.claude/skills/vibe-chat-history/SKILL.md
This skill should be used when the user asks about "vibe history", "chat history persistence", "vibe chat database", "ChatStore biz_type", "cc_sessions biz_type", "cc_chat_messages biz_type", "vibe MySQL", "vibe session save", "/api/vibe/sessions", "VibeHistory component", "handleVibeSessions", "handleVibeSessionMessages", "ListSessions", "GetMessages", "chat history sidebar", "load history session", "continue conversation from history", "vibe chatstore integration", "webuiSession chatStore", "chatStore is nil", "MySQL DSN format", "mysql driver log", "slogWriter", "chatstore log", "database operation log", "vite proxy /api/vibe", "404 api vibe sessions", "unified history", "IM history in vibe", "listAllSessionsSQL", "biz_type filter", "history includes IM", "history source tag", or needs to debug, extend, or understand how Vibe Coding chat messages are persisted to MySQL and loaded as browsable history in the frontend.
npx skillsauth add liuyu520/cc-connect-fork vibe-chat-historyInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Document how Vibe Coding chat messages are persisted to MySQL via the shared
ChatStore infrastructure and how the frontend provides browsable/resumable
chat history. This is a reference for extending chat persistence to other
business types or adding new query patterns.
不新建表。Vibe Coding 复用现有 cc_sessions + cc_chat_messages 表,
通过 biz_type 字段区分来源:
| biz_type | 来源 | 写入方 |
|----------|------|--------|
| im | IM 平台消息 (Feishu/Telegram/Discord 等) | engine_session.go / engine_events.go |
| vibe | Vibe Coding 浏览器对话 | webui.go (handleVibeWS) |
两张表各新增一列:
ALTER TABLE cc_sessions ADD COLUMN biz_type VARCHAR(32) NOT NULL DEFAULT 'im'
COMMENT '业务类型: im=IM平台, vibe=Vibe Coding';
ALTER TABLE cc_chat_messages ADD COLUMN biz_type VARCHAR(32) NOT NULL DEFAULT 'im'
COMMENT '业务类型: im=IM平台, vibe=Vibe Coding';
DEFAULT 'im' 确保旧数据自动标记为 IM,完全向后兼容NewMySQLChatStore() 中执行 ALTER(Duplicate column 错误静默忽略)biz_type 列和索引Browser WebSocket → webui.go handleVibeWS()
├─ "start" message → chatStore.EnsureSession(BizType:"vibe")
├─ "send" message → chatStore.SaveMessage(Role:"user", BizType:"vibe")
└─ parseEvent("result") → chatStore.SaveMessage(Role:"assistant", BizType:"vibe")
└─ 同时 EnsureSession 更新 agent_session_id
Frontend VibeHistory 面板
→ GET /api/vibe/sessions?limit=50
→ WebUIServer.handleVibeSessions()
→ chatStore.ListSessions("vibe", 50)
→ SELECT ... FROM cc_sessions WHERE biz_type='vibe' ORDER BY updated_at DESC
→ GET /api/vibe/sessions/{id}/messages?limit=200
→ WebUIServer.handleVibeSessionMessages()
→ chatStore.GetMessages(sessionID, 200)
→ SELECT ... FROM cc_chat_messages WHERE session_id=? ORDER BY created_at ASC
Frontend (Active Tab 或 History Panel)
→ POST /api/vibe/export (JSON: metadata + messages[])
→ WebUIServer.handleVibeExportMarkdown()
→ buildExportMarkdown() → Markdown string
→ Content-Disposition: attachment → browser downloads .md file
History Panel 导出时会先调用 getVibeMessages() 获取消息,再 POST 到导出端点。
Active Tab 导出时直接使用内存中的 tab.messages(含 tool_use 等富信息)。
详见 webui-export-markdown skill。
| File | Role |
|------|------|
| core/chatstore.go | ChatStore 接口 + ChatMessage/ChatSessionInfo 结构体(含 BizType 字段)+ 读取记录类型 |
| core/chatstore_mysql.go | MySQL 实现:DDL、ALTER 升级、INSERT/UPSERT(含 biz_type)、ListSessions/GetMessages 查询 |
| core/chatstore_test.go | stubChatStore 测试桩(实现 ListSessions/GetMessages) |
| core/webui.go | WebUIServer 注入 ChatStore + 写入调用 + REST API handlers |
| cmd/cc-connect/main.go | 将 chatStore 注入 WebUIServer |
| web/src/api/vibe.ts | 前端 Vibe 历史 API 客户端 |
| web/src/pages/VibeCoding/VibeHistory.tsx | 历史会话侧边面板组件(含每条会话的 Markdown 导出按钮) |
| web/src/pages/VibeCoding/VibeCoding.tsx | 容器中的历史面板入口 + 加载回调 + Tab 栏导出按钮 |
| web/src/i18n/locales/*.json | vibe.history/vibe.loading/vibe.noHistory 等翻译 |
type ChatStore interface {
// 写入(异步,非阻塞)
SaveMessage(ctx context.Context, msg ChatMessage)
EnsureSession(ctx context.Context, info ChatSessionInfo)
// 读取(同步,返回结果)
ListSessions(ctx context.Context, bizType string, limit int) ([]ChatSessionRecord, error)
GetMessages(ctx context.Context, sessionID string, limit int) ([]ChatMessageRecord, error)
Close() error
}
vibe-{UnixNano} (如 vibe-1711468800000000000)"start" 消息创建新 IDsession_key 格式:vibe:{workDir} (如 vibe:/Users/ywwl/project-a)┌─ VibeCoding 容器 ──────────────────────────────────┐
│ [Tab 栏] [历史记录 📋] │ ← 点击打开侧边面板
│ ┌─ VibeSession ─────────────────────┐ │
│ │ 聊天 UI │ │
│ └───────────────────────────────────┘ │
└────────────────────────────────────────────────────┘
点击"历史记录"后:
┌──────────────────────────────┬─── VibeHistory ──┐
│ 当前聊天界面 │ 📋 历史记录 │
│ │ ─────────────── │
│ │ [项目A] 2m ago │
│ │ 最后一条消息... │
│ │ [项目B] 1h ago │
│ │ 最后一条消息... │
│ │ [项目C] 3d ago │
└──────────────────────────────┴──────────────────┘
getVibeMessages(sessionId) 获取消息messages 设为历史消息,workDir 设为项目路径当需要为其他业务场景(如 API 调用、定时任务)添加聊天持久化时:
"api", "cron", "webhook"SaveMessage/EnsureSession 时传入对应值chatStore.ListSessions("api", limit)VibeHistory 组件模式无需修改表结构、无需新建表、无需改 ChatStore 接口。
当前 IM 消息的 Management API (GET /projects/{project}/sessions/{id}) 读取的是
JSON 文件/内存,不是 MySQL。如果想改为 MySQL 读取:
management.go 中注入 ChatStorehandleProjectSessions 调用 chatStore.ListSessions("im", limit) 替代 JSON 读取handleProjectSessionDetail 调用 chatStore.GetMessages(id, limit) 替代内存读取接口完全一致,只需切换数据源。
历史记录面板默认展示所有类型的会话(Vibe + IM),通过颜色标签区分来源。
biz_type 查询参数GET /api/vibe/sessions 支持可选的 biz_type 参数:
| 请求 | 行为 |
|------|------|
| /api/vibe/sessions?limit=50 | 返回所有类型(Vibe + IM),默认 |
| /api/vibe/sessions?biz_type=vibe | 仅 Vibe 会话 |
| /api/vibe/sessions?biz_type=im | 仅 IM 会话 |
实现方式:两条 SQL 常量
// 按 biz_type 过滤
listSessionsSQL = `SELECT ... WHERE s.biz_type = ? ORDER BY s.updated_at DESC LIMIT ?`
// 不过滤(查所有类型)
listAllSessionsSQL = `SELECT ... ORDER BY s.updated_at DESC LIMIT ?`
ListSessions 方法根据 bizType 是否为空选择 SQL:
func (s *MySQLChatStore) ListSessions(ctx, bizType, limit) {
if bizType == "" {
rows, err = s.db.QueryContext(ctx, listAllSessionsSQL, limit)
} else {
rows, err = s.db.QueryContext(ctx, listSessionsSQL, bizType, limit)
}
}
VibeHistory.tsx 每条记录显示颜色标签区分来源:
<span className={cn(
'text-[10px] px-1.5 py-0.5 rounded',
session.biz_type === 'vibe'
? 'text-emerald-600 bg-emerald-50' // 绿色 = Vibe
: 'text-blue-600 bg-blue-50' // 蓝色 = IM
)}>
{session.biz_type === 'vibe' ? 'Vibe' : 'IM'}
</span>
如果未来需要前端按来源筛选,只需在 VibeHistory 中添加 Tab 切换:
const [filter, setFilter] = useState<'' | 'vibe' | 'im'>('');
// 调用时传 biz_type 参数
listVibeSessions(50, filter);
API 层 listVibeSessions 添加 bizType 参数即可。
core/interfaces.go 的 AgentSystemPrompt() 包含 "Project management" 段,
告知 Claude Code agent 关于 /project 命令的存在:
### Project management
cc-connect manages multiple projects, each with its own work_dir.
The current project name is in the CC_PROJECT environment variable.
When the user asks about "projects", "switch project", "list projects",
"current project", or similar, tell them to use the /project command:
- /project — list all configured projects
- /project <name> — switch to a different project
Do NOT try to list projects by scanning the filesystem.
这避免了 Claude Code 在收到"展示当前项目"等自然语言时去执行 ls 扫描文件系统,
而是引导用户使用 /project 命令查看 cc-connect 配置中的项目列表。
webui-vibe-coding — Vibe Coding 完整架构(WebSocket 协议、Go 后端、配置)webui-export-markdown — 聊天记录导出 Markdown(POST /api/vibe/export、全栈数据流)frontend-multi-tab — 多 Tab 架构模式(状态管理、组件拆分)add-new-feature — 通用功能添加 checklist(含 Management API 模式)config-startup-validation — 启动配置校验(database.dsn 必填)所有数据库操作都有 slog.Info (成功) 和 slog.Error (失败) 日志:
| 操作 | 成功日志 | 失败日志 |
|------|---------|---------|
| MySQL 连接 | INFO chatstore: MySQL connected dsn=*** | ERROR chatstore: MySQL ping failed |
| 消息队列投递 | (静默) | ERROR chatstore: message queue full |
| INSERT 消息 | INFO chatstore: message saved session_id=... role=... biz_type=... | ERROR chatstore: save message failed |
| UPSERT 会话 | INFO chatstore: session ensured session_id=... project=... | ERROR chatstore: ensure session failed |
| 查询会话列表 | INFO chatstore: list sessions ok biz_type=... count=... | ERROR chatstore: list sessions query failed |
| 查询消息列表 | INFO chatstore: get messages ok session_id=... count=... | ERROR chatstore: get messages query failed |
go-sql-driver 的内部日志(如 packets.go:58 unexpected EOF)通过 slogWriter 桥接到 slog:
// chatstore_mysql.go
func init() {
_ = mysqldriver.SetLogger(log.New(slogWriter{}, "[mysql] ", 0))
}
type slogWriter struct{}
func (slogWriter) Write(p []byte) (int, error) {
slog.Error("chatstore: mysql driver", "detail", strings.TrimSpace(string(p)))
return len(p), nil
}
这确保底层 MySQL 协议错误也通过 cc-connect 的 slog 体系输出,不会因日志级别被过滤。
/api/vibe/* 的 REST 端点注册在 WebUIServer (9830),不是 Management API (9820)。
Vite 开发代理必须将 /api/vibe 转发到 9830,且规则要写在 /api 之前:
// web/vite.config.ts
proxy: {
'/api/vibe/ws': { target: 'http://localhost:9830', ws: true },
'/api/vibe': { target: 'http://localhost:9830' }, // ← REST API
'/api': { target: 'http://localhost:9820' }, // ← Management API
}
常见问题:GET /api/vibe/sessions 返回 404
原因:缺少 /api/vibe 代理规则,请求被 /api 规则转发到 9820
修复:在 vite.config.ts 中添加 /api/vibe 代理
chatStore_nil=true日志中 webui: creating vibe session chatStore_nil=true 表示 chatStore 未注入。
排查步骤:
chatstore: MySQL connected → 没有说明连接失败chatstore: MySQL ping failed → DSN 格式或网络问题chatstore: mysql driver detail=[mysql] unexpected EOF → MySQL 拒绝连接go-sql-driver/mysql 要求 tcp(host:port) 格式:
错误: hw3:[email protected]:3309/db
正确: hw3:pass@tcp(172.17.6.38:3309)/db?charset=utf8mb4&parseTime=true
parseTime=true 是必须的,否则 DATETIME 列扫描会失败。
unexpected EOF / invalid connection通常是 MySQL 服务端拒绝连接(IP 白名单、max_connections 已满、SSL 不匹配)。
用 mysql -h host -P port -u user -p 命令行测试确认。
context deadline exceeded连接超时(默认 10 秒)。可能是网络不通或 DNS 解析慢。
在 DSN 中添加 timeout=5s 可缩短超时时间以快速失败。
tools
This skill should be used when the user asks about "webui", "web ui", "vibe coding", "WebUIServer", "web interface", "browser Claude Code", "web frontend", "React admin dashboard", "web/src", "VibeCoding page", "WebSocket /api/vibe/ws", "webui config", "port 9830", "static file serving", "webuiSession", "claude code subprocess from web", "project dropdown", "work dir select", "listProjects", "Management API frontend", "multi tab vibe", "TabBar", "VibeSession component", "copy work dir", "clipboard copy", "disconnect confirm", "断开确认", "复制路径", "copyWorkDir", "AgentSystemPrompt", "project awareness", "/project command in agent", "attachment upload", "sendWithAttachments", "file upload vibe", "image upload vibe", "drag drop vibe", "paste image vibe", or needs to debug, extend, or understand the browser-based Vibe Coding interface and its Go backend.
tools
This skill should be used when the user asks about "permission request", "control_request", "control_response", "permission prompt tool", "permission-prompt-tool stdio", "permission popup not showing", "permission dialog missing", "authorize tool use", "allow deny button", "webuiSession permission", "respondPermission", "updatedInput", "control_cancel_request", "permission cancelled", "permission_cancelled", "pendingInputs", "permission flow webui", "vibe permission", "前端没有弹出授权", "权限请求不显示", "权限弹窗", "webuiSession vs claudeSession", "webui parity", or needs to debug, extend, or understand how tool permission requests flow between Claude Code CLI, the Go WebUI backend, and the React frontend.
tools
This skill should be used when the user asks about "export markdown", "export chat", "download markdown", "export conversation", "导出 Markdown", "导出聊天记录", "ExportRequest", "ExportMessage", "handleVibeExportMarkdown", "buildExportMarkdown", "POST /api/vibe/export", "exportVibeSession", "chat export", "markdown download", "sanitizeFilename", "Content-Disposition attachment", "export button vibe", "history export", "tool_use in export", "message type mapping export", or needs to debug, extend, or understand the chat history Markdown export feature including the full-stack data flow from frontend trigger to file download.
tools
This skill should be used when the user asks about "attachment upload", "file upload", "image upload", "paste image", "drag drop file", "vibe attachment", "pendingAttachments", "sendWithAttachments", "fileToAttachment", "AttachmentItem", "base64 attachment", "WebSocket attachment protocol", "multimodal content", "image content block", "file content block", "clipboard paste image", "drag and drop upload", "attachment preview", "file size limit", "10MB limit", "ExtFromMime", "附件上传", "图片上传", "拖拽上传", "粘贴图片", "附件预览", "文件大小限制", or needs to debug, extend, or understand the WebUI attachment upload feature including the full-stack data flow from browser to Claude Code CLI.