bowenliang123/dsh-context
bowenliang123/dsh-contextDSH 上下文洞察面板:Context 仪表盘 + /context命令 + Context 浏览器,查看 Context的分类组成、内容详情、演进趋势、压缩/注入事件、统计等一站式 Context 全生命周期管理。
按工作目录浏览 Claude Code、DSH 和 Codex 会话日志,查看每轮上下文构成、token 用量、压缩点和费用估算。
English | 简体中文
DSH Web GUI 的「会话洞察」面板:解析 Claude Code / DSH / Codex 三个来源的会话日志,把模型每一轮实际收到的上下文拆开给人看——系统提示、工具定义、记忆与指令、历史、工具结果、图片各占多少,以及每个数字是精确的 usage 还是按字符折算的估算。

洞察读取不改写源日志;会话行支持右键「删除会话」,确认后永久删除该会话原始日志。
当前范围:只读洞察 + 摘要交接 + 确认删除。交接把生成好的简报投递进 DSH 新会话,只调官方
session.create/session.prompt,不手写会话事件、不改写原会话(docs/HANDOFF.md、docs/adr/0003-never-handwrite-session-events.md、docs/adr/0007-accepted-is-not-success.md)。
精确 / 估算 徽标与口径。
工作目录是唯一主轴,来源只是徽标。 工作目录 → 会话 → 轮次
精确 / 估算 徽标)、压缩点、工具调用(默认折叠成一行摘要,报错的自动展开)、子代理会话。⌘K(Windows/Linux 上 Ctrl+K)打开全库搜索,命中后直接跳到那一轮。
打开 Claude Code 或 Codex 会话,点击「交接给 DSH」,预览并编辑自动生成的交接简报、确认工作目录,再点击「投递到 DSH」。简报包含背景与目标、已改动文件、已定决策、未决与风险、下一步和验证命令六段。

| 来源 | 默认根目录 | 覆盖用的环境变量 |
|---|---|---|
| Claude Code | ~/.claude/projects | DSH_CONTEXT_INSIGHT_CLAUDE_ROOT |
| DSH | ~/.dsh/sessions | DSH_CONTEXT_INSIGHT_DSH_ROOT |
| Codex | ~/.codex/sessions | DSH_CONTEXT_INSIGHT_CODEX_ROOT |
某个来源缺失或不可读不影响其余来源:顶部只把该源标为「不可用」,并给出原因(根目录不存在 / 不可读 / 适配器异常)。
需要 DSH 0.2.1-rc.2 或更高(插件按运行版 app.asar 内的行为对齐,见 docs/adr/0002-asar-021-is-the-contract.md)。
第 0 步:先确认装进哪个 profile
装错 profile 不会报错,只是面板不会出现。两者是不同的 profile,不是同一份配置:
| 你怎么启动 | 实际 profile | 命令 |
|---|---|---|
双击 DeepSeek Harness.app(桌面端) | desktop | --profile desktop |
dsh web(命令行 / 远程) | web | --profile web |
不确定时看进程参数或 ~/.dsh/profiles/ 下哪个目录在更新。
第 1 步:把包装进 profile
单独安装本插件:
dsh plugin --profile desktop add @cyrus/dsh-sessions-insight # 桌面端
dsh plugin --profile web add @cyrus/dsh-sessions-insight # dsh web
# 本地开发时换成目录或打包产物:
# dsh plugin --profile <name> add link:$PWD
# dsh plugin --profile <name> add /abs/path/cyrus-dsh-sessions-insight-<版本>.tgz
也可以装组合包 @cyrus/dsh-plugins,它会把合集里的插件一起装上(见仓库根 README)。
两种方式只能选一种。 组合包和本插件都会往加载树里插
id: sessions-insight,两个都在dsh.profile.bundles里时,DSH 启动会报duplicate loader entry id: sessions-insight并退出。
第 2 步:确认包名在 dsh.profile.bundles 里
实测 dsh plugin ... add 会顺带把包名追加到 ~/.dsh/profiles/<name>/package.json 的 dsh.profile.bundles 末尾。没自动加上时(link: 安装、手改过 package.json、或从旧版本升级)手工补齐——顺序有意义,后面的层覆盖前面的层:
{
"dsh": {
"profile": {
"bundles": ["@deepseek-ai/dsh-base", "@deepseek-ai/dsh-web-app", "@cyrus/dsh-sessions-insight"]
}
}
}
第 3 步:重启
dsh web
侧边栏出现「会话洞察」一行即挂载成功。(市场里另有一个 dsh-context 插件叫「上下文洞察」,两者无关。)宿主侧自检(不带 Origin 头视为同源):
curl -sS http://127.0.0.1:<port>/api/dsh-sessions-insight/health
# {"ok":true,"value":{"version":"<版本号>","sources":["claude","dsh","codex"]}}
# value.version 是宿主侧常量 PLUGIN_VERSION,构建时从 package.json 注入
loader 行只在 boot 时组合,改完必须重启;浏览器热重载只覆盖「客户端 bundle 被重建」这一种情况。
source + id + mtime + size 失效。realpath 校验,必须仍落在三个白名单根目录之内——挡掉 .. 与符号链接逃逸。kind:'exact',先过 Origin/Host 门:Sec-Fetch-Site: cross-site 直接 403,Origin 与 Host 不一致 403;不带 Origin 的同源 GET 放行。health / sources / workdirs / sessions / session / search / cost);唯一的写动作是 handoff/apply,它只调官方 session.create + session.prompt——不写源目录,也不往活会话里塞事件。read-limit,不会把宿主拖死。搜索有 2.5 秒预算。 全库搜索是流式的,达到 SEARCH_DEADLINE_MS = 2500 就停:响应里 truncated: true、remaining 是没轮到的会话数,界面显示「预算内未扫完,还剩 N 个会话」。语料特别大时请缩窄来源,或按工作目录逐层点开。
Claude 会话没有 prompt_snapshot 时,面板会显示一大块「未知」。 这类会话(本机语料 121 个文件里 56 个)看不到工具定义与系统提示的原文,那一份只能留在 residual 里显式画成「未知」切片,不会等比摊进其他类别。这是有意为之,见 docs/adr/0005-honest-attribution-residual.md。
Codex 的思维链拿不到。 response_item.reasoning.encrypted_content 是密文,只能计数、无法测量,因此 Codex 轮次不显示「思考」分块。
分块数字是估算,总量才是精确值。 分块按 2.6 chars/token 折算,对指令体偏高约 23%;做过等比对账的轮次会显示 reconciled.factor(见 docs/adr/0006-projection-not-differencing.md)。不要拿分块数字做计费。
DSH 正文必须解日志。 projcache 只有元数据、没有正文投影,看内容时仍要逐帧解压会话日志,几 MB 的会话首开有明显停顿。
交接的 delivered 是投递瞬间的状态,不是可持续观察的状态。 宿主接受 prompt 后约 30ms 内就会发出 turn/start,所以轮询能看到的稳定状态只有 running / succeeded / failed。成功判定以 turn/end reason=completed 为准,见 docs/adr/0007-accepted-is-not-success.md。
成本是「多张价目表」并存的,不做汇率换算。 共两张表,各自带 version/asOf/source:
official(USD):DeepSeek 官方定价页,取 peak 价作为保守上界(cacheWrite 记 0——官方只按 cache hit/miss 计价);openrouter(USD):公开参考价,从 /api/v1/models 抽取,只作「参考」列。主金额只取 official:DeepSeek 模型有主价,Claude/GPT 没有主价(null,不估算),只显示 openrouter 参考列。同一会话里出现不同币种时,合计按 (表, 币种) 分组并列,绝不跨表或跨币种相加、也没有汇率换算。价目里某通道未列价 ≠ 免费:该通道按 0 计入,金额前加 ≥ 并标 partial。这些数字用于理解用量结构,不要拿去对账。
本包只有两个半边,能力在它依赖的 workspace 包里。依赖方向是 plugins/sessions-insight → packages/*,由包边界维持:包名到源码的映射在 tooling/aliases.ts,tsconfig.json 的 paths 与之对应。
本包 plugins/sessions-insight/src/:
src/
├── index.ts 宿主入口:装配三源、注册路由(唯一碰 cordis 的文件)
├── protocol.ts 本包的线上契约出口:路由路径 + 转出契约包的 IR / 类型 / 守卫
├── version.ts 版本常量(构建时从 package.json 注入)
├── host/ 宿主半边
│ ├── http/ 同源门、信封、路由表(routes.ts + routes/)
│ ├── sources/ 三源装配、工作目录归并、快照索引、路径白名单
│ ├── views/ search / cost / pricing / brief
│ └── handoff/ 交接状态机(accepted ≠ 成功)
└── client/ 浏览器半边
├── index.tsx 入口:注册 sidebar/main 槽位与词典
├── api.ts 同源 fetch + 响应解码
├── format.ts / labels.ts / locale.ts 格式化、标签回落、zh/en 词典
├── styles.ts 注入编译好的 CSS(一次)
├── state/ 纯状态逻辑:树展平、轮次行、堆叠条算术
├── theme/ app.css、components.css、构建产物 generated.css.ts
└── ui/ 组件:面板、工具栏、项目树、会话头部、轮次列表与详情、工具明细、交接、搜索面板…
它依赖的包(packages/,构建时内联进 lib/,不单独发布):
packages/
├── plugin-kit/ 零依赖底座:JSON 信封、URL 拼法
├── session-contract/ 统一 IR、线上类型、guards → plugin-kit
├── session-readers/ Claude / Codex / DSH 三源适配与计量 → session-contract
├── plugin-kit-host/ 路由表、同源门、信封、LRU → plugin-kit
└── plugin-kit-client/ 解码 fetch、样式注入、槽位注册 → plugin-kit
这些命令都在仓库根执行(本包不是独立仓库):
pnpm install
npx tsc --noEmit # 类型门禁:各包与宿主半边
npx tsc --noEmit -p tsconfig.client.json # 类型门禁:浏览器半边(types: [],摘掉 node 类型)
npx vitest run # 单测
node scripts/build-css.mjs plugins/sessions-insight
npx tsdown --config plugins/sessions-insight/tsdown.config.ts --minify
node scripts/check-bundle.mjs plugins/sessions-insight # 宿主加载契约
在包内也可以只构建自己:pnpm --filter @cyrus/dsh-sessions-insight build(等价于 css + tsdown)。
lib/ 产物随源码提交到 GitHub,让 Git 安装直接使用预构建入口,无需用户授权构建脚本。修改源码后,提交前必须重新构建并一并提交产物;保留 prepack,供打包时重新构建和校验。
产物两个入口:
lib/index.js — 宿主半边(ESM,在 Host 的 node:vm realm 里跑)lib/client.js — 浏览器半边,必须是 window.__ModuleLoader__.load({ id, factory }) 包装,react 外置不打包想验证挂载而不污染生产 profile,用隔离 DSH_HOME:
export DSH_HOME=/tmp/dsh-try
dsh try --from-default-profile web --dump-config # 从内置模板建 profile,只打印组合树
dsh plugin --profile try add "$PWD"
# 再把包名追加进 profiles/try/package.json 的 dsh.profile.bundles
dsh try --dump-config | grep -A2 sessions-insight # 确认 patch 行已插入
dsh try --host 127.0.0.1 --port 49744 --no-open # 独立端口 boot
这些文档都在仓库根,不在本包目录内(npm tarball 只带 docs/images):
docs/RELEASE.md — npm 发布步骤docs/PLAN.md — 决策与里程碑docs/IR.md — 三源统一的轮次 IR(adapter 契约)docs/API.md — 宿主路由契约docs/HANDOFF.md — 交接链路契约docs/adr — 架构决策记录GLOSSARY.md — 词表