# bsh-scratch-plugin **Repository Path**: ling2/bsh-scratch-plugin ## Basic Information - **Project Name**: bsh-scratch-plugin - **Description**: No description available - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-08-26 - **Last Updated**: 2026-09-01 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # bsh-scratch-plugin dsh(DeepSeek Harness)Web GUI 外部插件集,通过 `--patch` overlay 挂载。目前含六个包: | 插件 | 用途 | |---|---| | `dsh-rdb` | 关系数据库公共层:`ctx.rdb` hub + 命名注册表 + 事务门面 + 迁移器(Service Definition) | | `dsh-rdb-mysql` | MySQL 提供者(mysql2 连接池;一源多行 = 多库) | | `dsh-session-persistence-mysql` | 会话持久化 JSONL → MySQL(经 rdb) | | `dsh-user-management` | 用户目录:完整 Ling Cloud `base_user` 表 + host 服务 + agent 工具 + `/api` Remote 面 | | `dsh-client-user-management` | 浏览器「用户管理」设置区(settings.section) | | `dsh-client-wenshu-skin` | 文枢十色皮肤配色与切换 | 组合关系:`dsh-rdb`(hub)← `dsh-rdb-mysql`(提供者,双行挂 sessions/users 两库)← 会话持久化与用户管理(消费者)。**cordis.yml 行序即依赖序**;消费者解析注册名失败会大声报错并列出现有名。 --- # dsh-session-persistence-mysql 使用说明 外部插件:把 dsh 的会话持久化后端从 JSONL 换成 MySQL。事件溯源模型不变(`SessionHeader` 元数据 + `SessionEvent` 行),只换存储原语;连接池与事务管道来自 `ctx.rdb`(先挂 `dsh-rdb` + `dsh-rdb-mysql` 行)。完整细节见插件目录下 `README.md` / `README.zh.md`。 ## 一键启动 ```sh pnpm dsh web --patch ./scratch-plugin/bsh-scratch-plugin/cordis.yml ``` `cordis.yml` 的 overlay 逻辑:禁用默认的 `session-persistence-jsonl`,插入 rdb hub、两个 MySQL 提供者行、会话持久化行、用户管理行与两个浏览器插件。 ## 前置条件 1. **MySQL ≥ 8.0.19**(行别名 `INSERT ... AS new_row` upsert 依赖此版本)。 2. **数据库必须预先建好**——提供者只验连,从不 `CREATE DATABASE`。当前用两个库:`dsh_sessions`(会话)与 `dsh_users`(用户目录)。最小权限建库见 README「Database initialization script」一节(`utf8mb4` + 仅授本库权限的专用账号)。 3. **驱动依赖装在提供者目录**(本目录均非 pnpm workspace 成员,`mysql2` 现归 `dsh-rdb-mysql` 所有): ```sh cd scratch-plugin/bsh-scratch-plugin/dsh-rdb-mysql pnpm install --ignore-workspace --config.auto-install-peers=false ``` ⚠️ **目录移动/换机器后必须重跑**:`node_modules` 不受 git 跟踪。漏装的症状是启动即报 `Cannot find package 'mysql2' imported from .../dsh-rdb-mysql/src/database.ts`。 ## 配置项(cordis.yml 里 plugin 的 config) | 配置 | 默认 | 说明 | |---|---|---| | `database`(必填) | — | rdb 注册名(指向某条 `rdb-mysql` 行) | | `preparedSessionCacheSize` | 插件默认 | 冷 Session 准备缓存,供 resume 复用 | | `writeBatchMaxDelayMs` | 协调器默认 | 实时事件合并写窗口 | 连接参数(`url`/`connectionLimit`/`connectTimeoutMs`)移至 `rdb-mysql` 提供者行,见 `dsh-rdb-mysql/README.md`。密码建议走环境变量而非明文 YAML(在提供者行): ```yaml url: !!js "`mysql://${process.env.DSH_MYSQL_USER}:${process.env.DSH_MYSQL_PASSWORD}@127.0.0.1:3306/dsh_sessions`" ``` ## 表结构(首次打开自动创建,共 4 张) | 表 | 角色 | |---|---| | `dsh_session_state` | 库的稳定 store 身份,单行 | | `dsh_sessions` | 每会话一行(header + `incarnation`/`revision`) | | `dsh_session_events` | 可回放事件账本(权威数据源);流式 chunk 会打包成物理行(3–1024 成员/行,≤1 MiB) | | `dsh_session_messages` | 会话投影:每条 user/assistant/tool 消息一行,与账本同事务写入 | 要点: - 事件账本是权威;resume/load/inspect 只读 `dsh_session_events`,投影只加速「取最新状态」类查询(如页面刷新直接 `SELECT ... ORDER BY seq`)。 - MySQL 写入是事务性的,**无 torn-tail 概念**:`loadStored` 不会报 torn 标记,`commitRepair` 只追加 closer。 - **无迁移机制**:未来版本若改 schema,打开时校验失败会大声报错而不是改表;升级 = 新库重积累或带外导出导入。 - 清理历史会话属带外维护(与其他后端一致),直接对库操作即可。 ## 行为特性 - **失败即停(fails loud)**:mount 时连不上服务器或建不了 schema 直接报错退出,不会静默回退到其他后端。 - **握手抗饥饿**:dsh 启动时 tsx 编译 ~136 个插件条目,可能拖慢 MySQL 首次握手。默认 60s `connectTimeoutMs` + 有界重试(1s、5s 各一次)已覆盖该场景,无需调服务端。只有「建池阶段」的瞬态握手失败会重试,已建立的连接不走这条重试。 ## 测试 / 冒烟 ```sh cd scratch-plugin/bsh-scratch-plugin/dsh-session-persistence-mysql pnpm install --ignore-workspace --config.auto-install-peers=false DSH_MYSQL_URL='mysql://user:pass@127.0.0.1:3306/dsh_sessions' npx vitest run ``` - codec 单测无需服务器;持久化契约套件(与 JSONL/SQLite 后端同一套)需 `DSH_MYSQL_URL`,未设置则跳过。 - 测试会先 truncate 三张表——**务必指向专用测试库**。 - `scripts/smoke-conversation.ts` 为端到端冒烟脚本。 ## Windows 注意 - 插件 `name` 必须写 `file:///C:/...` URL 形式;裸 `C:/` 路径不是合法 module specifier,启动时会**静默失败**。 --- # dsh-client-wenshu-skin 使用说明 外部浏览器插件:把 mateclaw 文枢的十色皮肤配色与切换机制搬进 dsh Web GUI。配色数据与 `@wenshu/shared` 的 `SKINS` 一一对应(壹·绛纱宫墙 …… 拾·靛蓝扎染,8 色字段),持久化 key 同 ling-web/ling-app(`localStorage['wenshu-skin']`,同浏览器互通)。 ![img.png](http://minio.ling2.cn:9090/api/v1/buckets/ling2/objects/download?preview=true&prefix=YnNoL2RzaC1jbGllbnQtd2Vuc2h1LXNraW4ucG5n&version_id=null) ## 一键启动 ```sh pnpm dsh web --patch ./scratch-plugin/bsh-scratch-plugin/cordis.yml ``` `cordis.yml` 同时插入两个插件;只想要皮肤的话把 mysql 那段 `- insert` 删掉即可。 ## 前置条件 浏览器 roster 行(`dsh.client` 包)必须能从 web profile 按包名解析,需一次性接线: 1. `$DSH_HOME/profiles/web/package.json` 的 `dependencies` 加: ```json "dsh-client-wenshu-skin": "link:C:/workspace/deepseek-harness/scratch-plugin/bsh-scratch-plugin/dsh-client-wenshu-skin" ``` 2. 在 `$DSH_HOME/profiles/web/node_modules/` 下建 junction 指向插件目录(管理员 PowerShell): ```powershell New-Item -ItemType Junction -Path "$env:DSH_HOME\profiles\web\node_modules\dsh-client-wenshu-skin" ` -Target "C:\workspace\deepseek-harness\scratch-plugin\bsh-scratch-plugin\dsh-client-wenshu-skin" ``` 3. **改插件代码后需重启 dsh 进程**:浏览器模块清单(boot graph)在启动时对 bundle 内容取哈希,无热更新(本插件不参与 `pnpm run dev:web` 的 HMR 链)。 ## 使用入口 | 入口 | 位置 | 交互 | |---|---|---| | 侧边栏按钮 | 侧边栏脚部,Settings 旁 | 显示当前皮肤色点+名称;点击弹出置底浮层(Esc/✕ 关闭),两列网格切换 | | 设置页 | 设置 → 通用 | 「文枢 · 十色皮肤」区块,宽网格切换,与外观/语言偏好并列 | 皮肤卡片:四个色点(底/主/点缀/墨)+ 中文序号 + 名称 + 出处,当前选中描边高亮。切换即全局生效并写入 localStorage;页面刷新/重开自动恢复上次皮肤。 ## 实现机制(排障背景) - **换肤通道**:皮肤 8 色映射到 dsh 的约 60 个 `--dsw-alias-*` / `--dsw-specific-*` 主题 token(背景层级/文字全级/边框/按钮填充/代码块/输入框/滚动条/状态色/Toast 等),经 ui-theme 服务的 `theme.overrideTokens('wenshu-skin', …)` 注入,light/dark 双模式同值——皮肤与 GUI 明暗偏好正交,任一模式下配色一致。 - **为什么全覆盖**:底层样式表(design-platform.css)有约 90 个 token 的调色板,只覆盖十来个基础 token 时输入框(`--dsw-specific-input-major`)、代码块(`--dsw-alias-markdown-code-block`)等会残留 light 白底。半透明遮罩/hover rgba 保持原生。 - **无构建步骤**:`client.js` 是浏览器模块系统直接加载的经典脚本(`window.__ModuleLoader__.load`),`react` 取自平台模块表;node 半 `index.js` 为空 `apply`。 - **停用即还原**:插件停用/移除 roster 行后,token 覆盖随插件生命周期自动撤销,GUI 回到原生 light/dark 主题;localStorage 记录保留,重新启用自动恢复。 ## 常见问题 - **入口没出现**:按「前置条件」检查 profile 依赖与 junction;重启 dsh 后刷新页面。 - **个别区域颜色不对**:多半还有未映射的 token 或组件字面色,在 `client.js` 的 `skinOverrides()` 里对号补一行即可。 - **想回原生主题**:侧边栏/设置里没有「关闭」开关——直接去掉 `cordis.yml` 里的 `wenshu-skin` 行重启,或清除 `localStorage['wenshu-skin']`(后者只重置为皮肤 0)。 --- # 关系数据库公共层(dsh-rdb + dsh-rdb-mysql) 把「连接池 + 事务 + 命名多库」从各插件抽成公共能力,供会话持久化、用户管理及后续插件共享。接口与约定详见 `dsh-rdb/README.md` 与 `dsh-rdb-mysql/README.md`。要点: - `ctx.rdb.database.register(name, db)` / `get(name)`——多库并存,重名/未知名 fails loud - `transaction(work)`——begin → work → commit,失败回滚重抛,回滚失败聚合 `AggregateError` - `migrateRdb`——版本表 + 有序 DDL 迁移器(用户管理在用;会话持久化刻意保持幂等建表) - 新增方言 = 新增提供者包(如 `dsh-rdb-postgres`):实现 `RdbDatabase` 接口并注册到 hub,消费者零改动 # 用户管理(dsh-user-management + dsh-client-user-management) 完整照搬 Ling Cloud `base_user`(60 列 + 复合主键),后续 RBAC 家族可直接沿用同名表结构甚至指向既有 Ling 库。三个暴露面:host 服务 `ctx.users`、agent 工具 `user_query` / `get_current_user`、浏览器设置页「用户管理」区(经 `/api` Remote)。密码沿用 Ling 的 `md5(md5(明文)+secretkey)` 以保数据互通。详见两个插件各自的 `README.md`。 ## 测试总入口 ```sh # 公共层(无需服务器) cd dsh-rdb && npx vitest run # MySQL 门控集成(务必指向专用测试库;users 套件会 DROP base_user) cd dsh-rdb-mysql && DSH_MYSQL_URL='mysql://…/testdb' npx vitest run cd dsh-session-persistence-mysql && DSH_MYSQL_URL='mysql://…/dsh_sessions' npx vitest run cd dsh-user-management && DSH_MYSQL_URL='mysql://…/dsh_users' npx vitest run ```