sillyspec 3.7.10 → 3.7.12
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/.sillyspec/docs/sillyspec/brainstorm/2026-04-05-dashboard-design.md +206 -0
- package/.sillyspec/docs/sillyspec/brainstorm/2026-04-05-unified-docs-design.md +199 -0
- package/.sillyspec/specs/2026-04-05-unified-docs-design.md +199 -0
- package/package.json +1 -1
- package/packages/dashboard/dist/assets/index-5Rrvs0Rl.css +1 -0
- package/packages/dashboard/dist/assets/index-ZNToqi9V.js +17 -0
- package/packages/dashboard/dist/index.html +2 -2
- package/packages/dashboard/server/index.js +166 -105
- package/packages/dashboard/server/parser.js +83 -3
- package/packages/dashboard/server/watcher.js +203 -131
- package/packages/dashboard/src/App.vue +45 -4
- package/packages/dashboard/src/components/ActionBar.vue +6 -6
- package/packages/dashboard/src/components/CommandPalette.vue +5 -5
- package/packages/dashboard/src/components/DetailPanel.vue +10 -10
- package/packages/dashboard/src/components/DocPreview.vue +43 -0
- package/packages/dashboard/src/components/DocTree.vue +36 -0
- package/packages/dashboard/src/components/LogStream.vue +5 -5
- package/packages/dashboard/src/components/PipelineView.vue +76 -33
- package/packages/dashboard/src/components/ProjectList.vue +94 -11
- package/packages/dashboard/src/composables/useDashboard.js +20 -6
- package/packages/dashboard/src/style.css +11 -11
- package/src/index.js +12 -1
- package/src/init.js +26 -10
- package/src/migrate.js +134 -0
- package/templates/archive.md +5 -5
- package/templates/brainstorm.md +15 -9
- package/templates/execute.md +6 -6
- package/templates/plan.md +3 -3
- package/templates/propose.md +3 -3
- package/templates/quick.md +8 -8
- package/templates/scan.md +14 -8
- package/packages/dashboard/dist/assets/index-Bh-GPjKY.css +0 -1
- package/packages/dashboard/dist/assets/index-CrCn5Gg6.js +0 -17
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
# SillySpec Dashboard 设计
|
|
2
|
+
|
|
3
|
+
## 概述
|
|
4
|
+
|
|
5
|
+
为 SillySpec CLI 工具添加可视化仪表盘(`sillyspec dashboard`),用户通过浏览器直观查看和管理项目进度、阶段流程、任务详情和实时日志。
|
|
6
|
+
|
|
7
|
+
## 目标用户
|
|
8
|
+
|
|
9
|
+
SillySpec 全部用户(官方功能,随 npm 包发布)。
|
|
10
|
+
|
|
11
|
+
## 分期计划
|
|
12
|
+
|
|
13
|
+
### 一期(MVP)
|
|
14
|
+
|
|
15
|
+
可视化仪表盘 + CLI 命令执行 + 实时日志流。
|
|
16
|
+
|
|
17
|
+
### 二期(进阶)
|
|
18
|
+
|
|
19
|
+
Web Terminal(xterm.js)+ 自定义命令 + AI 交互(视需求而定)。
|
|
20
|
+
|
|
21
|
+
## 架构
|
|
22
|
+
|
|
23
|
+
```
|
|
24
|
+
sillyspec dashboard
|
|
25
|
+
│
|
|
26
|
+
▼
|
|
27
|
+
Node.js HTTP Server (localhost:3456)
|
|
28
|
+
│
|
|
29
|
+
├─ chokidar: watch .sillyspec/ 目录
|
|
30
|
+
├─ WebSocket: 实时推送状态变更
|
|
31
|
+
└─ REST API: 项目列表、状态、日志、CLI 执行
|
|
32
|
+
│
|
|
33
|
+
▼
|
|
34
|
+
Vue 3 SPA (浏览器)
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
### 文件结构
|
|
38
|
+
|
|
39
|
+
```
|
|
40
|
+
sillyspec/packages/dashboard/
|
|
41
|
+
├── server/
|
|
42
|
+
│ ├── index.js # HTTP + WebSocket 服务启动
|
|
43
|
+
│ ├── watcher.js # chokidar 文件监听 + 增量解析
|
|
44
|
+
│ └── api.js # REST 路由
|
|
45
|
+
├── src/
|
|
46
|
+
│ ├── App.vue
|
|
47
|
+
│ ├── components/
|
|
48
|
+
│ │ ├── ProjectList.vue # 左栏:项目列表
|
|
49
|
+
│ │ ├── PipelineView.vue # 中栏:阶段 pipeline
|
|
50
|
+
│ │ ├── StepCard.vue # 步骤卡片(可展开折叠)
|
|
51
|
+
│ │ ├── DetailPanel.vue # 右栏:详情 + 日志
|
|
52
|
+
│ │ ├── LogStream.vue # 终端风格日志流
|
|
53
|
+
│ │ ├── CommandPalette.vue # Cmd+K 命令面板
|
|
54
|
+
│ │ └── StageBadge.vue # 阶段状态标签
|
|
55
|
+
│ ├── composables/
|
|
56
|
+
│ │ ├── useWebSocket.js # WebSocket 连接管理
|
|
57
|
+
│ │ └── useKeyboard.js # 键盘快捷键
|
|
58
|
+
│ └── styles/
|
|
59
|
+
│ └── theme.css # 深色主题变量
|
|
60
|
+
├── package.json
|
|
61
|
+
└── vite.config.js
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## 核心页面设计
|
|
65
|
+
|
|
66
|
+
### 三栏布局
|
|
67
|
+
|
|
68
|
+
```
|
|
69
|
+
┌──────────┬─────────────────────────┬──────────────────┐
|
|
70
|
+
│ 项目列表 │ Pipeline 视图(中) │ 详情+日志(右) │
|
|
71
|
+
│ (200px) │ (flex-1) │ (320px,可收起) │
|
|
72
|
+
│ │ │ │
|
|
73
|
+
│ 📁 proj1 │ ✅ brainstorm │ Step 3 详情 │
|
|
74
|
+
│ 📁 proj2 │ ⏳ plan ← 当前 │ 结论:选择React │
|
|
75
|
+
│ 📁 proj3 │ ⬜ execute │ 决策:... │
|
|
76
|
+
│ │ ⬜ verify │ 📋 实时日志 │
|
|
77
|
+
└──────────┴─────────────────────────┴──────────────────┘
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### 信息分层(三级密度)
|
|
81
|
+
|
|
82
|
+
1. **低密度(默认)**:阶段名 + 状态图标
|
|
83
|
+
2. **中密度(hover)**:步骤摘要(1-2 句话)
|
|
84
|
+
3. **高密度(点击)**:右侧面板展开完整详情 + 日志
|
|
85
|
+
|
|
86
|
+
### 异常高亮
|
|
87
|
+
|
|
88
|
+
失败/阻塞/超时步骤自动标红,视觉上突出,不需用户手动查找。
|
|
89
|
+
|
|
90
|
+
## 数据源与同步
|
|
91
|
+
|
|
92
|
+
### 数据文件
|
|
93
|
+
|
|
94
|
+
| 文件 | 用途 |
|
|
95
|
+
|---|---|
|
|
96
|
+
| `STATE.md` | 当前阶段、状态、下一步命令 |
|
|
97
|
+
| `.runtime/progress.json` | 步骤进度、摘要、时间戳 |
|
|
98
|
+
| `.runtime/user-inputs.md` | 用户输入记录 |
|
|
99
|
+
| `specs/*.md` | 设计文档 |
|
|
100
|
+
| `changes/*/design.md` | 技术方案 |
|
|
101
|
+
|
|
102
|
+
### 同步方案
|
|
103
|
+
|
|
104
|
+
- **启动时**:全量读取 `.sillyspec/` 目录,构建初始状态
|
|
105
|
+
- **运行时**:chokidar watch 文件变化 → 解析 → WebSocket 增量推送
|
|
106
|
+
- **不轮询,不做 diff**,文件变化直接读取推送
|
|
107
|
+
|
|
108
|
+
### CLI 命令执行(一期)
|
|
109
|
+
|
|
110
|
+
后端通过 `child_process.spawn` 执行 CLI 命令:
|
|
111
|
+
- "下一步"按钮 → `sillyspec next`
|
|
112
|
+
- 阶段切换按钮 → `sillyspec plan` / `sillyspec execute` 等
|
|
113
|
+
- 执行结果通过 WebSocket 实时推送到前端日志面板
|
|
114
|
+
|
|
115
|
+
## 交互设计
|
|
116
|
+
|
|
117
|
+
### 键盘快捷键
|
|
118
|
+
|
|
119
|
+
| 快捷键 | 功能 |
|
|
120
|
+
|---|---|
|
|
121
|
+
| `j/k` | 上下切换步骤 |
|
|
122
|
+
| `Enter` | 展开详情 |
|
|
123
|
+
| `Escape` | 收起面板 |
|
|
124
|
+
| `/` | 搜索日志 |
|
|
125
|
+
| `Cmd/Ctrl+K` | 命令面板 |
|
|
126
|
+
|
|
127
|
+
### 命令面板功能
|
|
128
|
+
|
|
129
|
+
- 搜索项目名
|
|
130
|
+
- 跳转到指定阶段
|
|
131
|
+
- 切换深色/浅色主题
|
|
132
|
+
|
|
133
|
+
### CLI 命令
|
|
134
|
+
|
|
135
|
+
```bash
|
|
136
|
+
sillyspec dashboard # 启动 + 自动开浏览器
|
|
137
|
+
sillyspec dashboard --port 8080 # 自定义端口
|
|
138
|
+
sillyspec dashboard --no-open # 不自动打开浏览器
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
## 视觉设计
|
|
142
|
+
|
|
143
|
+
### 配色
|
|
144
|
+
|
|
145
|
+
| 用途 | 色值 |
|
|
146
|
+
|---|---|
|
|
147
|
+
| 背景 | `#0D1117` |
|
|
148
|
+
| 主色(进行中) | `#00D4AA` |
|
|
149
|
+
| 阻塞 | `#F59E0B` |
|
|
150
|
+
| 失败 | `#F87171` |
|
|
151
|
+
| 未开始 | `#6B7280` |
|
|
152
|
+
|
|
153
|
+
### 动效
|
|
154
|
+
|
|
155
|
+
- 阶段完成:脉冲光效(CSS animation,200ms)
|
|
156
|
+
- 日志新行:淡入
|
|
157
|
+
- hover 过渡:100ms
|
|
158
|
+
- 进度条:弹性缓动
|
|
159
|
+
|
|
160
|
+
## 技术选型
|
|
161
|
+
|
|
162
|
+
| 层 | 技术 |
|
|
163
|
+
|---|---|
|
|
164
|
+
| 前端框架 | Vue 3 |
|
|
165
|
+
| 构建工具 | Vite |
|
|
166
|
+
| CSS | Tailwind CSS |
|
|
167
|
+
| 后端 | Node.js 原生 http + ws |
|
|
168
|
+
| 文件监听 | chokidar |
|
|
169
|
+
| 数据库 | 无,纯文件系统 |
|
|
170
|
+
|
|
171
|
+
## 约束和假设
|
|
172
|
+
|
|
173
|
+
- 用户本地已有 Node.js(SillySpec 前置依赖)
|
|
174
|
+
- 仪表盘为本地工具,不考虑多用户并发
|
|
175
|
+
- 前端构建产物嵌入 npm 包,无需额外 build
|
|
176
|
+
- 不引入 Express、数据库等重依赖
|
|
177
|
+
|
|
178
|
+
## 状态历史时间线
|
|
179
|
+
|
|
180
|
+
Pipeline 视图下方展示时间线,记录每个步骤的:
|
|
181
|
+
- 开始时间 / 结束时间 / 耗时
|
|
182
|
+
- 状态变化(进行中 → 完成/阻塞/失败)
|
|
183
|
+
- 可按时间排序,快速定位耗时最长或异常步骤
|
|
184
|
+
|
|
185
|
+
数据来源:`progress.json` 中的 `summaries` 和时间戳。
|
|
186
|
+
|
|
187
|
+
## 不在范围内(一期)
|
|
188
|
+
|
|
189
|
+
- 用户认证/权限
|
|
190
|
+
- 多人协作
|
|
191
|
+
- 数据持久化(纯文件系统)
|
|
192
|
+
- AI 对话交互(二期)
|
|
193
|
+
- Web Terminal(二期)
|
|
194
|
+
|
|
195
|
+
## 验收标准
|
|
196
|
+
|
|
197
|
+
- [ ] `sillyspec dashboard` 一键启动,自动打开浏览器
|
|
198
|
+
- [ ] 三栏布局正确渲染,响应式适配
|
|
199
|
+
- [ ] 文件变化后前端实时更新(<1s 延迟)
|
|
200
|
+
- [ ] 步骤卡片三级信息分层(默认/hover/点击)
|
|
201
|
+
- [ ] 实时日志流正常显示,可搜索可过滤
|
|
202
|
+
- [ ] 键盘快捷键可用(j/k/Enter/Escape/Cmd+K)
|
|
203
|
+
- [ ] 命令面板可搜索项目名和阶段
|
|
204
|
+
- [ ] CLI 命令执行按钮可用,结果实时显示
|
|
205
|
+
- [ ] 异常步骤自动高亮
|
|
206
|
+
- [ ] 深色/浅色主题切换
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
# 统一文档管理 + Dashboard 文档浏览
|
|
2
|
+
|
|
3
|
+
## 动机
|
|
4
|
+
|
|
5
|
+
### 现状问题
|
|
6
|
+
1. 文档散落在各子项目的 `.sillyspec/` 里,没有统一视角
|
|
7
|
+
2. Dashboard 只能发现项目,看不到文档内容
|
|
8
|
+
3. 扫描的 `codebase/` 文档只在子项目里,主项目看不到
|
|
9
|
+
4. 归档后文档沉入 `knowledge/`,跨项目复用不方便
|
|
10
|
+
5. 单项目模式和工作区模式两套逻辑,维护成本高
|
|
11
|
+
|
|
12
|
+
### 目标
|
|
13
|
+
- 文档只写一份,集中管理
|
|
14
|
+
- 默认工作区模式,去掉模式切换
|
|
15
|
+
- Dashboard 支持文档浏览
|
|
16
|
+
- 子项目保持干净(只有源代码)
|
|
17
|
+
|
|
18
|
+
## 方案
|
|
19
|
+
|
|
20
|
+
### 核心原则
|
|
21
|
+
- **文档只写一份**,在哪执行就写在哪
|
|
22
|
+
- **默认工作区模式**,每个项目天生就是"主项目"
|
|
23
|
+
- **子项目不生成文档**,文档全部在主项目的 `.sillyspec/docs/<project>/` 下
|
|
24
|
+
|
|
25
|
+
### 目录结构
|
|
26
|
+
|
|
27
|
+
```
|
|
28
|
+
my-project/.sillyspec/
|
|
29
|
+
├── STATE.md # 主项目状态(含当前操作的项目)
|
|
30
|
+
├── projects/ # 子项目注册表
|
|
31
|
+
│ ├── my-project.yaml # 默认注册自己
|
|
32
|
+
│ ├── frontend.yaml # { name, path, status }
|
|
33
|
+
│ └── backend.yaml
|
|
34
|
+
│
|
|
35
|
+
├── docs/ # 统一文档中心
|
|
36
|
+
│ └── my-project/ # 按子项目分目录
|
|
37
|
+
│ ├── scan/ # scan 产出
|
|
38
|
+
│ │ ├── ARCHITECTURE.md
|
|
39
|
+
│ │ └── CONVENTIONS.md
|
|
40
|
+
│ ├── brainstorm/ # brainstorm 设计文档
|
|
41
|
+
│ │ └── 2026-04-05-user-auth.md
|
|
42
|
+
│ ├── plan/ # plan 产出
|
|
43
|
+
│ │ └── 2026-04-05-user-auth.md
|
|
44
|
+
│ ├── changes/ # 当前变更(WIP)
|
|
45
|
+
│ │ └── user-auth/
|
|
46
|
+
│ │ ├── design.md
|
|
47
|
+
│ │ └── tasks.md
|
|
48
|
+
│ ├── archive/ # 归档
|
|
49
|
+
│ │ └── 2026-03-20-db-redesign.md
|
|
50
|
+
│ └── quicklog/ # quick 操作记录
|
|
51
|
+
│ └── 2026-04-05-fix-login.md
|
|
52
|
+
│
|
|
53
|
+
├── knowledge/ # 跨项目共享知识库(不变)
|
|
54
|
+
└── .runtime/
|
|
55
|
+
└── progress.json # 运行时数据(含子项目维度)
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### 子项目保持干净
|
|
59
|
+
|
|
60
|
+
```
|
|
61
|
+
frontend/ # 只有源代码
|
|
62
|
+
├── src/
|
|
63
|
+
├── package.json
|
|
64
|
+
└── .gitignore
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
子项目不再有 `.sillyspec/` 目录。
|
|
68
|
+
|
|
69
|
+
## 命令变更
|
|
70
|
+
|
|
71
|
+
### --project 参数
|
|
72
|
+
|
|
73
|
+
所有产生文档的命令支持 `--project <name>` 参数:
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
/sillyspec:scan --project frontend
|
|
77
|
+
/sillyspec:brainstorm "用户认证" --project frontend
|
|
78
|
+
/sillyspec:plan --project frontend
|
|
79
|
+
/sillyspec:execute --project frontend
|
|
80
|
+
/sillyspec:archive --project frontend
|
|
81
|
+
/sillyspec:quick --project frontend --change "修复登录bug"
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
不指定 `--project` 时,默认使用 `STATE.md` 中记录的当前项目。
|
|
85
|
+
|
|
86
|
+
### 文档输出路径映射
|
|
87
|
+
|
|
88
|
+
| 命令 | 输出路径 |
|
|
89
|
+
|------|---------|
|
|
90
|
+
| scan | `.sillyspec/docs/<project>/scan/` |
|
|
91
|
+
| brainstorm | `.sillyspec/docs/<project>/brainstorm/<name>.md` |
|
|
92
|
+
| propose | `.sillyspec/docs/<project>/brainstorm/<name>.md` |
|
|
93
|
+
| plan | `.sillyspec/docs/<project>/plan/<name>.md` |
|
|
94
|
+
| execute | `.sillyspec/docs/<project>/changes/<name>/` (WIP) |
|
|
95
|
+
| archive | `.sillyspec/docs/<project>/archive/<name>.md` |
|
|
96
|
+
| quick | `.sillyspec/docs/<project>/quicklog/<name>.md` |
|
|
97
|
+
|
|
98
|
+
### init 变更
|
|
99
|
+
|
|
100
|
+
- `sillyspec init` 初始化时,`projects/` 默认注册当前目录自己
|
|
101
|
+
- 去掉 `--workspace` 参数(默认就是工作区模式)
|
|
102
|
+
- 去掉 `--interactive` 参数(默认零交互)
|
|
103
|
+
|
|
104
|
+
### STATE.md 变更
|
|
105
|
+
|
|
106
|
+
```markdown
|
|
107
|
+
# 项目状态
|
|
108
|
+
|
|
109
|
+
## 当前项目
|
|
110
|
+
- 名称:frontend
|
|
111
|
+
- 路径:./frontend
|
|
112
|
+
|
|
113
|
+
## 当前变更
|
|
114
|
+
- 名称:user-auth
|
|
115
|
+
- 当前阶段:execute ⏳
|
|
116
|
+
- 下一步:执行任务 3/8
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
### progress.json 变更
|
|
120
|
+
|
|
121
|
+
增加子项目维度:
|
|
122
|
+
|
|
123
|
+
```json
|
|
124
|
+
{
|
|
125
|
+
"_version": 1,
|
|
126
|
+
"schemaVersion": "1.0",
|
|
127
|
+
"currentProject": "frontend",
|
|
128
|
+
"currentStage": "execute",
|
|
129
|
+
"stages": {
|
|
130
|
+
"brainstorm": { "status": "completed", "steps": [...] },
|
|
131
|
+
"plan": { "status": "completed", "steps": [...] },
|
|
132
|
+
"execute": { "status": "in-progress", "steps": [...] },
|
|
133
|
+
"verify": { "status": "pending", "steps": [] }
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
## Dashboard 文档浏览
|
|
139
|
+
|
|
140
|
+
### 新增文档 Tab
|
|
141
|
+
|
|
142
|
+
选中项目后,中间区域顶部增加 Tab 切换:
|
|
143
|
+
|
|
144
|
+
```
|
|
145
|
+
[ 流水线 ] [ 文档 ]
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
### 文档 Tab 内容
|
|
149
|
+
|
|
150
|
+
左侧:文档树(按类型分组)
|
|
151
|
+
|
|
152
|
+
```
|
|
153
|
+
📋 设计文档
|
|
154
|
+
📄 用户认证功能设计
|
|
155
|
+
|
|
156
|
+
📐 实现计划
|
|
157
|
+
📄 用户认证功能计划
|
|
158
|
+
|
|
159
|
+
⚙️ 当前变更
|
|
160
|
+
📄 design.md
|
|
161
|
+
📄 tasks.md
|
|
162
|
+
|
|
163
|
+
📦 已归档
|
|
164
|
+
📄 数据库重设计
|
|
165
|
+
|
|
166
|
+
🔍 架构文档
|
|
167
|
+
📄 ARCHITECTURE.md
|
|
168
|
+
📄 CONVENTIONS.md
|
|
169
|
+
|
|
170
|
+
⚡ 快速修复
|
|
171
|
+
📄 修复登录bug
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
右侧:文档预览(Markdown 渲染)
|
|
175
|
+
|
|
176
|
+
点击左侧文档,右侧显示内容。
|
|
177
|
+
|
|
178
|
+
### 后端新增 API
|
|
179
|
+
|
|
180
|
+
```
|
|
181
|
+
GET /api/projects/:path/docs # 获取项目文档树
|
|
182
|
+
GET /api/projects/:path/docs/:filePath # 获取文档内容
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
## 兼容性
|
|
186
|
+
|
|
187
|
+
- 旧项目 `.sillyspec/codebase/`、`.sillyspec/specs/` 不受影响,只是新文档不再往那写
|
|
188
|
+
- 可加 `sillyspec docs migrate` 命令把旧文档迁移到新结构
|
|
189
|
+
- Dashboard 的项目发现逻辑不变(扫描 `.sillyspec` 目录)
|
|
190
|
+
|
|
191
|
+
## 验收标准
|
|
192
|
+
|
|
193
|
+
1. `sillyspec init` 生成 `projects/` 和 `docs/` 结构
|
|
194
|
+
2. `--project` 参数在所有命令中生效
|
|
195
|
+
3. 文档输出到 `.sillyspec/docs/<project>/` 对应子目录
|
|
196
|
+
4. 子项目目录不生成任何 `.sillyspec` 文件
|
|
197
|
+
5. Dashboard 文档 Tab 能展示文档树和预览内容
|
|
198
|
+
6. 旧项目不受影响
|
|
199
|
+
7. `sillyspec docs migrate` 能迁移旧文档
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
# 统一文档管理 + Dashboard 文档浏览
|
|
2
|
+
|
|
3
|
+
## 动机
|
|
4
|
+
|
|
5
|
+
### 现状问题
|
|
6
|
+
1. 文档散落在各子项目的 `.sillyspec/` 里,没有统一视角
|
|
7
|
+
2. Dashboard 只能发现项目,看不到文档内容
|
|
8
|
+
3. 扫描的 `codebase/` 文档只在子项目里,主项目看不到
|
|
9
|
+
4. 归档后文档沉入 `knowledge/`,跨项目复用不方便
|
|
10
|
+
5. 单项目模式和工作区模式两套逻辑,维护成本高
|
|
11
|
+
|
|
12
|
+
### 目标
|
|
13
|
+
- 文档只写一份,集中管理
|
|
14
|
+
- 默认工作区模式,去掉模式切换
|
|
15
|
+
- Dashboard 支持文档浏览
|
|
16
|
+
- 子项目保持干净(只有源代码)
|
|
17
|
+
|
|
18
|
+
## 方案
|
|
19
|
+
|
|
20
|
+
### 核心原则
|
|
21
|
+
- **文档只写一份**,在哪执行就写在哪
|
|
22
|
+
- **默认工作区模式**,每个项目天生就是"主项目"
|
|
23
|
+
- **子项目不生成文档**,文档全部在主项目的 `.sillyspec/docs/<project>/` 下
|
|
24
|
+
|
|
25
|
+
### 目录结构
|
|
26
|
+
|
|
27
|
+
```
|
|
28
|
+
my-project/.sillyspec/
|
|
29
|
+
├── STATE.md # 主项目状态(含当前操作的项目)
|
|
30
|
+
├── projects/ # 子项目注册表
|
|
31
|
+
│ ├── my-project.yaml # 默认注册自己
|
|
32
|
+
│ ├── frontend.yaml # { name, path, status }
|
|
33
|
+
│ └── backend.yaml
|
|
34
|
+
│
|
|
35
|
+
├── docs/ # 统一文档中心
|
|
36
|
+
│ └── my-project/ # 按子项目分目录
|
|
37
|
+
│ ├── scan/ # scan 产出
|
|
38
|
+
│ │ ├── ARCHITECTURE.md
|
|
39
|
+
│ │ └── CONVENTIONS.md
|
|
40
|
+
│ ├── brainstorm/ # brainstorm 设计文档
|
|
41
|
+
│ │ └── 2026-04-05-user-auth.md
|
|
42
|
+
│ ├── plan/ # plan 产出
|
|
43
|
+
│ │ └── 2026-04-05-user-auth.md
|
|
44
|
+
│ ├── changes/ # 当前变更(WIP)
|
|
45
|
+
│ │ └── user-auth/
|
|
46
|
+
│ │ ├── design.md
|
|
47
|
+
│ │ └── tasks.md
|
|
48
|
+
│ ├── archive/ # 归档
|
|
49
|
+
│ │ └── 2026-03-20-db-redesign.md
|
|
50
|
+
│ └── quicklog/ # quick 操作记录
|
|
51
|
+
│ └── 2026-04-05-fix-login.md
|
|
52
|
+
│
|
|
53
|
+
├── knowledge/ # 跨项目共享知识库(不变)
|
|
54
|
+
└── .runtime/
|
|
55
|
+
└── progress.json # 运行时数据(含子项目维度)
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### 子项目保持干净
|
|
59
|
+
|
|
60
|
+
```
|
|
61
|
+
frontend/ # 只有源代码
|
|
62
|
+
├── src/
|
|
63
|
+
├── package.json
|
|
64
|
+
└── .gitignore
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
子项目不再有 `.sillyspec/` 目录。
|
|
68
|
+
|
|
69
|
+
## 命令变更
|
|
70
|
+
|
|
71
|
+
### --project 参数
|
|
72
|
+
|
|
73
|
+
所有产生文档的命令支持 `--project <name>` 参数:
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
/sillyspec:scan --project frontend
|
|
77
|
+
/sillyspec:brainstorm "用户认证" --project frontend
|
|
78
|
+
/sillyspec:plan --project frontend
|
|
79
|
+
/sillyspec:execute --project frontend
|
|
80
|
+
/sillyspec:archive --project frontend
|
|
81
|
+
/sillyspec:quick --project frontend --change "修复登录bug"
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
不指定 `--project` 时,默认使用 `STATE.md` 中记录的当前项目。
|
|
85
|
+
|
|
86
|
+
### 文档输出路径映射
|
|
87
|
+
|
|
88
|
+
| 命令 | 输出路径 |
|
|
89
|
+
|------|---------|
|
|
90
|
+
| scan | `.sillyspec/docs/<project>/scan/` |
|
|
91
|
+
| brainstorm | `.sillyspec/docs/<project>/brainstorm/<name>.md` |
|
|
92
|
+
| propose | `.sillyspec/docs/<project>/brainstorm/<name>.md` |
|
|
93
|
+
| plan | `.sillyspec/docs/<project>/plan/<name>.md` |
|
|
94
|
+
| execute | `.sillyspec/docs/<project>/changes/<name>/` (WIP) |
|
|
95
|
+
| archive | `.sillyspec/docs/<project>/archive/<name>.md` |
|
|
96
|
+
| quick | `.sillyspec/docs/<project>/quicklog/<name>.md` |
|
|
97
|
+
|
|
98
|
+
### init 变更
|
|
99
|
+
|
|
100
|
+
- `sillyspec init` 初始化时,`projects/` 默认注册当前目录自己
|
|
101
|
+
- 去掉 `--workspace` 参数(默认就是工作区模式)
|
|
102
|
+
- 去掉 `--interactive` 参数(默认零交互)
|
|
103
|
+
|
|
104
|
+
### STATE.md 变更
|
|
105
|
+
|
|
106
|
+
```markdown
|
|
107
|
+
# 项目状态
|
|
108
|
+
|
|
109
|
+
## 当前项目
|
|
110
|
+
- 名称:frontend
|
|
111
|
+
- 路径:./frontend
|
|
112
|
+
|
|
113
|
+
## 当前变更
|
|
114
|
+
- 名称:user-auth
|
|
115
|
+
- 当前阶段:execute ⏳
|
|
116
|
+
- 下一步:执行任务 3/8
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
### progress.json 变更
|
|
120
|
+
|
|
121
|
+
增加子项目维度:
|
|
122
|
+
|
|
123
|
+
```json
|
|
124
|
+
{
|
|
125
|
+
"_version": 1,
|
|
126
|
+
"schemaVersion": "1.0",
|
|
127
|
+
"currentProject": "frontend",
|
|
128
|
+
"currentStage": "execute",
|
|
129
|
+
"stages": {
|
|
130
|
+
"brainstorm": { "status": "completed", "steps": [...] },
|
|
131
|
+
"plan": { "status": "completed", "steps": [...] },
|
|
132
|
+
"execute": { "status": "in-progress", "steps": [...] },
|
|
133
|
+
"verify": { "status": "pending", "steps": [] }
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
## Dashboard 文档浏览
|
|
139
|
+
|
|
140
|
+
### 新增文档 Tab
|
|
141
|
+
|
|
142
|
+
选中项目后,中间区域顶部增加 Tab 切换:
|
|
143
|
+
|
|
144
|
+
```
|
|
145
|
+
[ 流水线 ] [ 文档 ]
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
### 文档 Tab 内容
|
|
149
|
+
|
|
150
|
+
左侧:文档树(按类型分组)
|
|
151
|
+
|
|
152
|
+
```
|
|
153
|
+
📋 设计文档
|
|
154
|
+
📄 用户认证功能设计
|
|
155
|
+
|
|
156
|
+
📐 实现计划
|
|
157
|
+
📄 用户认证功能计划
|
|
158
|
+
|
|
159
|
+
⚙️ 当前变更
|
|
160
|
+
📄 design.md
|
|
161
|
+
📄 tasks.md
|
|
162
|
+
|
|
163
|
+
📦 已归档
|
|
164
|
+
📄 数据库重设计
|
|
165
|
+
|
|
166
|
+
🔍 架构文档
|
|
167
|
+
📄 ARCHITECTURE.md
|
|
168
|
+
📄 CONVENTIONS.md
|
|
169
|
+
|
|
170
|
+
⚡ 快速修复
|
|
171
|
+
📄 修复登录bug
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
右侧:文档预览(Markdown 渲染)
|
|
175
|
+
|
|
176
|
+
点击左侧文档,右侧显示内容。
|
|
177
|
+
|
|
178
|
+
### 后端新增 API
|
|
179
|
+
|
|
180
|
+
```
|
|
181
|
+
GET /api/projects/:path/docs # 获取项目文档树
|
|
182
|
+
GET /api/projects/:path/docs/:filePath # 获取文档内容
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
## 兼容性
|
|
186
|
+
|
|
187
|
+
- 旧项目 `.sillyspec/codebase/`、`.sillyspec/specs/` 不受影响,只是新文档不再往那写
|
|
188
|
+
- 可加 `sillyspec docs migrate` 命令把旧文档迁移到新结构
|
|
189
|
+
- Dashboard 的项目发现逻辑不变(扫描 `.sillyspec` 目录)
|
|
190
|
+
|
|
191
|
+
## 验收标准
|
|
192
|
+
|
|
193
|
+
1. `sillyspec init` 生成 `projects/` 和 `docs/` 结构
|
|
194
|
+
2. `--project` 参数在所有命令中生效
|
|
195
|
+
3. 文档输出到 `.sillyspec/docs/<project>/` 对应子目录
|
|
196
|
+
4. 子项目目录不生成任何 `.sillyspec` 文件
|
|
197
|
+
5. Dashboard 文档 Tab 能展示文档树和预览内容
|
|
198
|
+
6. 旧项目不受影响
|
|
199
|
+
7. `sillyspec docs migrate` 能迁移旧文档
|
package/package.json
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
.slide-enter-active[data-v-ce467cd5],.slide-leave-active[data-v-ce467cd5]{transition:all .2s ease}.slide-enter-from[data-v-ce467cd5],.slide-leave-to[data-v-ce467cd5]{opacity:0;max-height:0;overflow:hidden}.slide-enter-to[data-v-ce467cd5],.slide-leave-from[data-v-ce467cd5]{max-height:300px}.line-clamp-2[data-v-20b76823]{display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}.backdrop-enter-active[data-v-fbb5ff82],.backdrop-leave-active[data-v-fbb5ff82]{transition:opacity .15s ease}.backdrop-enter-from[data-v-fbb5ff82],.backdrop-leave-to[data-v-fbb5ff82]{opacity:0}.palette-enter-active[data-v-fbb5ff82],.palette-leave-active[data-v-fbb5ff82]{transition:all .2s cubic-bezier(.16,1,.3,1)}.palette-enter-from[data-v-fbb5ff82],.palette-leave-to[data-v-fbb5ff82]{opacity:0;transform:translate(-50%,-8px) scale(.98)}*{margin:0;padding:0;box-sizing:border-box}body{font-family:DM Sans,-apple-system,BlinkMacSystemFont,sans-serif;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}#app{width:100vw;height:100vh;overflow:hidden}/*! tailwindcss v4.2.2 | MIT License | https://tailwindcss.com */@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-translate-x:0;--tw-translate-y:0;--tw-translate-z:0;--tw-rotate-x:initial;--tw-rotate-y:initial;--tw-rotate-z:initial;--tw-skew-x:initial;--tw-skew-y:initial;--tw-space-y-reverse:0;--tw-border-style:solid;--tw-leading:initial;--tw-font-weight:initial;--tw-tracking:initial;--tw-backdrop-blur:initial;--tw-backdrop-brightness:initial;--tw-backdrop-contrast:initial;--tw-backdrop-grayscale:initial;--tw-backdrop-hue-rotate:initial;--tw-backdrop-invert:initial;--tw-backdrop-opacity:initial;--tw-backdrop-saturate:initial;--tw-backdrop-sepia:initial;--tw-duration:initial}}}@layer theme{:root,:host{--font-sans:ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";--font-mono:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;--color-black:#000;--color-white:#fff;--spacing:.25rem;--container-md:28rem;--font-weight-medium:500;--font-weight-semibold:600;--font-weight-bold:700;--tracking-tight:-.025em;--tracking-wider:.05em;--tracking-widest:.1em;--leading-relaxed:1.625;--radius-sm:.25rem;--radius-md:.375rem;--radius-lg:.5rem;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4, 0, .2, 1);--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono);--animate-pulse-dot:pulse-dot 1.5s ease-in-out infinite}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;-moz-tab-size:4;tab-size:4;line-height:1.5;font-family:var(--default-font-family,ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring{outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab,red,red)){::placeholder{color:color-mix(in oklab,currentcolor 50%,transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){-webkit-appearance:button;-moz-appearance:button;appearance:button}::file-selector-button{-webkit-appearance:button;-moz-appearance:button;appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}}@layer components;@layer utilities{.pointer-events-none{pointer-events:none}.absolute{position:absolute}.fixed{position:fixed}.relative{position:relative}.static{position:static}.inset-0{inset:calc(var(--spacing) * 0)}.inset-x-0{inset-inline:calc(var(--spacing) * 0)}.start{inset-inline-start:var(--spacing)}.top-0{top:calc(var(--spacing) * 0)}.top-\[18\%\]{top:18%}.bottom-0{bottom:calc(var(--spacing) * 0)}.left-0{left:calc(var(--spacing) * 0)}.left-1\/2{left:50%}.z-10{z-index:10}.z-40{z-index:40}.z-50{z-index:50}.mx-4{margin-inline:calc(var(--spacing) * 4)}.mx-auto{margin-inline:auto}.-mt-0\.5{margin-top:calc(var(--spacing) * -.5)}.mt-0\.5{margin-top:calc(var(--spacing) * .5)}.mt-1{margin-top:calc(var(--spacing) * 1)}.mt-1\.5{margin-top:calc(var(--spacing) * 1.5)}.mt-2{margin-top:calc(var(--spacing) * 2)}.mt-3{margin-top:calc(var(--spacing) * 3)}.mt-4{margin-top:calc(var(--spacing) * 4)}.mb-1\.5{margin-bottom:calc(var(--spacing) * 1.5)}.mb-2{margin-bottom:calc(var(--spacing) * 2)}.mb-3{margin-bottom:calc(var(--spacing) * 3)}.mb-4{margin-bottom:calc(var(--spacing) * 4)}.line-clamp-2{-webkit-line-clamp:2;-webkit-box-orient:vertical;display:-webkit-box;overflow:hidden}.flex{display:flex}.hidden{display:none}.inline-flex{display:inline-flex}.h-1{height:calc(var(--spacing) * 1)}.h-2{height:calc(var(--spacing) * 2)}.h-3{height:calc(var(--spacing) * 3)}.h-3\.5{height:calc(var(--spacing) * 3.5)}.h-4{height:calc(var(--spacing) * 4)}.h-5{height:calc(var(--spacing) * 5)}.h-6{height:calc(var(--spacing) * 6)}.h-8{height:calc(var(--spacing) * 8)}.h-10{height:calc(var(--spacing) * 10)}.h-12{height:calc(var(--spacing) * 12)}.h-14{height:calc(var(--spacing) * 14)}.h-\[2px\]{height:2px}.h-full{height:100%}.h-px{height:1px}.h-screen{height:100vh}.max-h-32{max-height:calc(var(--spacing) * 32)}.max-h-40{max-height:calc(var(--spacing) * 40)}.max-h-72{max-height:calc(var(--spacing) * 72)}.w-0{width:calc(var(--spacing) * 0)}.w-1{width:calc(var(--spacing) * 1)}.w-2{width:calc(var(--spacing) * 2)}.w-3{width:calc(var(--spacing) * 3)}.w-3\.5{width:calc(var(--spacing) * 3.5)}.w-4{width:calc(var(--spacing) * 4)}.w-5{width:calc(var(--spacing) * 5)}.w-6{width:calc(var(--spacing) * 6)}.w-8{width:calc(var(--spacing) * 8)}.w-10{width:calc(var(--spacing) * 10)}.w-14{width:calc(var(--spacing) * 14)}.w-20{width:calc(var(--spacing) * 20)}.w-32{width:calc(var(--spacing) * 32)}.w-\[2px\]{width:2px}.w-\[200px\]{width:200px}.w-\[240px\]{width:240px}.w-\[340px\]{width:340px}.w-full{width:100%}.w-px{width:1px}.w-screen{width:100vw}.max-w-md{max-width:var(--container-md)}.min-w-0{min-width:calc(var(--spacing) * 0)}.flex-1{flex:1}.flex-shrink-0{flex-shrink:0}.-translate-x-1\/2{--tw-translate-x: -50% ;translate:var(--tw-translate-x) var(--tw-translate-y)}.rotate-180{rotate:180deg}.transform{transform:var(--tw-rotate-x,) var(--tw-rotate-y,) var(--tw-rotate-z,) var(--tw-skew-x,) var(--tw-skew-y,)}.animate-pulse-dot{animation:var(--animate-pulse-dot)}.cursor-pointer{cursor:pointer}.flex-col{flex-direction:column}.items-center{align-items:center}.items-start{align-items:flex-start}.justify-between{justify-content:space-between}.justify-center{justify-content:center}.gap-1{gap:calc(var(--spacing) * 1)}.gap-1\.5{gap:calc(var(--spacing) * 1.5)}.gap-2{gap:calc(var(--spacing) * 2)}.gap-2\.5{gap:calc(var(--spacing) * 2.5)}.gap-3{gap:calc(var(--spacing) * 3)}.gap-4{gap:calc(var(--spacing) * 4)}.gap-6{gap:calc(var(--spacing) * 6)}:where(.space-y-0\.5>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * .5) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * .5) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-1>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 1) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 1) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-2>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 2) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 2) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-4>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 4) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 4) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-5>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 5) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 5) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-px>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(1px * var(--tw-space-y-reverse));margin-block-end:calc(1px * calc(1 - var(--tw-space-y-reverse)))}.truncate{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.overflow-hidden{overflow:hidden}.overflow-y-auto{overflow-y:auto}.rounded{border-radius:.25rem}.rounded-full{border-radius:3.40282e38px}.rounded-lg{border-radius:var(--radius-lg)}.rounded-md{border-radius:var(--radius-md)}.rounded-sm{border-radius:var(--radius-sm)}.border{border-style:var(--tw-border-style);border-width:1px}.border-none{--tw-border-style:none;border-style:none}.bg-transparent{background-color:#0000}.p-1{padding:calc(var(--spacing) * 1)}.p-1\.5{padding:calc(var(--spacing) * 1.5)}.p-3{padding:calc(var(--spacing) * 3)}.px-1{padding-inline:calc(var(--spacing) * 1)}.px-1\.5{padding-inline:calc(var(--spacing) * 1.5)}.px-2{padding-inline:calc(var(--spacing) * 2)}.px-2\.5{padding-inline:calc(var(--spacing) * 2.5)}.px-3{padding-inline:calc(var(--spacing) * 3)}.px-4{padding-inline:calc(var(--spacing) * 4)}.px-5{padding-inline:calc(var(--spacing) * 5)}.px-6{padding-inline:calc(var(--spacing) * 6)}.py-0\.5{padding-block:calc(var(--spacing) * .5)}.py-1{padding-block:calc(var(--spacing) * 1)}.py-1\.5{padding-block:calc(var(--spacing) * 1.5)}.py-2{padding-block:calc(var(--spacing) * 2)}.py-2\.5{padding-block:calc(var(--spacing) * 2.5)}.py-3{padding-block:calc(var(--spacing) * 3)}.py-4{padding-block:calc(var(--spacing) * 4)}.py-10{padding-block:calc(var(--spacing) * 10)}.py-12{padding-block:calc(var(--spacing) * 12)}.py-px{padding-block:1px}.pt-1\.5{padding-top:calc(var(--spacing) * 1.5)}.pt-4{padding-top:calc(var(--spacing) * 4)}.pt-5{padding-top:calc(var(--spacing) * 5)}.pr-3{padding-right:calc(var(--spacing) * 3)}.pb-0{padding-bottom:calc(var(--spacing) * 0)}.pb-2{padding-bottom:calc(var(--spacing) * 2)}.pb-3{padding-bottom:calc(var(--spacing) * 3)}.pb-4{padding-bottom:calc(var(--spacing) * 4)}.pb-5{padding-bottom:calc(var(--spacing) * 5)}.pl-3\.5{padding-left:calc(var(--spacing) * 3.5)}.pl-\[3px\]{padding-left:3px}.text-center{text-align:center}.text-left{text-align:left}.font-\[DM_Sans\,sans-serif\]{font-family:DM Sans,sans-serif}.font-\[JetBrains_Mono\,monospace\]{font-family:JetBrains Mono,monospace}.text-\[9px\]{font-size:9px}.text-\[10px\]{font-size:10px}.text-\[11px\]{font-size:11px}.text-\[12px\]{font-size:12px}.text-\[13px\]{font-size:13px}.leading-relaxed{--tw-leading:var(--leading-relaxed);line-height:var(--leading-relaxed)}.font-bold{--tw-font-weight:var(--font-weight-bold);font-weight:var(--font-weight-bold)}.font-medium{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.font-semibold{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.tracking-\[0\.2em\]{--tw-tracking:.2em;letter-spacing:.2em}.tracking-\[0\.15em\]{--tw-tracking:.15em;letter-spacing:.15em}.tracking-\[0\.25em\]{--tw-tracking:.25em;letter-spacing:.25em}.tracking-tight{--tw-tracking:var(--tracking-tight);letter-spacing:var(--tracking-tight)}.tracking-wider{--tw-tracking:var(--tracking-wider);letter-spacing:var(--tracking-wider)}.tracking-widest{--tw-tracking:var(--tracking-widest);letter-spacing:var(--tracking-widest)}.whitespace-pre-wrap{white-space:pre-wrap}.text-black{color:var(--color-black)}.uppercase{text-transform:uppercase}.italic{font-style:italic}.opacity-0{opacity:0}.backdrop-filter{-webkit-backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,)}.transition{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to,opacity,box-shadow,transform,translate,scale,rotate,filter,-webkit-backdrop-filter,backdrop-filter,display,content-visibility,overlay,pointer-events;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-all{transition-property:all;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-colors{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-opacity{transition-property:opacity;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-transform{transition-property:transform,translate,scale,rotate;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.duration-100{--tw-duration:.1s;transition-duration:.1s}.duration-150{--tw-duration:.15s;transition-duration:.15s}.duration-200{--tw-duration:.2s;transition-duration:.2s}.duration-300{--tw-duration:.3s;transition-duration:.3s}.duration-500{--tw-duration:.5s;transition-duration:.5s}.outline-none{--tw-outline-style:none;outline-style:none}.select-none{-webkit-user-select:none;user-select:none}@media(hover:hover){.group-hover\:opacity-100:is(:where(.group):hover *){opacity:1}.hover\:bg-white\/5:hover{background-color:#ffffff0d}@supports (color:color-mix(in lab,red,red)){.hover\:bg-white\/5:hover{background-color:color-mix(in oklab,var(--color-white) 5%,transparent)}}}}@keyframes pulse-glow{0%,to{box-shadow:0 0 #fbbf2466}50%{box-shadow:0 0 12px 2px #fbbf2426}}@keyframes pulse-dot{0%,to{opacity:1;transform:scale(1)}50%{opacity:.4;transform:scale(1.5)}}@keyframes breathe{0%,to{opacity:.5}50%{opacity:1}}@keyframes shimmer{0%{background-position:-200% 0}to{background-position:200% 0}}@keyframes slide-in{0%{opacity:0;transform:translateY(6px)}to{opacity:1;transform:translateY(0)}}@keyframes glow-border{0%,to{border-color:#fbbf2426}50%{border-color:#fbbf2480}}@keyframes float{0%,to{transform:translateY(0)}50%{transform:translateY(-3px)}}.font-mono-log{font-family:JetBrains Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace}.noise-bg{position:relative}.noise-bg:before{content:"";pointer-events:none;z-index:0;background-image:url("data:image/svg+xml,%3Csvg viewBox='0 0 256 256' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)' opacity='0.03'/%3E%3C/svg%3E");position:absolute;top:0;right:0;bottom:0;left:0}.accent-stripe{background:repeating-linear-gradient(-45deg,#0000,#0000 8px,#fbbf2408 8px,#fbbf2408 9px)}.progress-gradient{background:linear-gradient(90deg,#fbbf24,#f59e0b,#fb923c)}.skeleton-shimmer{background:linear-gradient(90deg,#1a1e28 25%,#2a3040,#1a1e28 75%) 0 0/200% 100%;animation:1.5s ease-in-out infinite shimmer}::-webkit-scrollbar{width:5px;height:5px}::-webkit-scrollbar-track{background:0 0}::-webkit-scrollbar-thumb{background:#2a3040;border-radius:10px}::-webkit-scrollbar-thumb:hover{background:#3a4555}*{scrollbar-width:thin;scrollbar-color:#2a2a2d transparent}::selection{color:#fbbf24;background:#fbbf2433}@property --tw-translate-x{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-y{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-z{syntax:"*";inherits:false;initial-value:0}@property --tw-rotate-x{syntax:"*";inherits:false}@property --tw-rotate-y{syntax:"*";inherits:false}@property --tw-rotate-z{syntax:"*";inherits:false}@property --tw-skew-x{syntax:"*";inherits:false}@property --tw-skew-y{syntax:"*";inherits:false}@property --tw-space-y-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-leading{syntax:"*";inherits:false}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-tracking{syntax:"*";inherits:false}@property --tw-backdrop-blur{syntax:"*";inherits:false}@property --tw-backdrop-brightness{syntax:"*";inherits:false}@property --tw-backdrop-contrast{syntax:"*";inherits:false}@property --tw-backdrop-grayscale{syntax:"*";inherits:false}@property --tw-backdrop-hue-rotate{syntax:"*";inherits:false}@property --tw-backdrop-invert{syntax:"*";inherits:false}@property --tw-backdrop-opacity{syntax:"*";inherits:false}@property --tw-backdrop-saturate{syntax:"*";inherits:false}@property --tw-backdrop-sepia{syntax:"*";inherits:false}@property --tw-duration{syntax:"*";inherits:false}
|