dsh-semantic-drift

toolstested: passnpmMIT

One versioned vocabulary of a project's business concepts, a read-only drift scan, and the same naming rules in every agent prompt.

下载量 / Downloads
1,455
依赖体积 / node_modules
1.21 MB
测试时间 / Tested
2026-11-06
DSH 版本 / Version
0.2.2-rc.1

Install

dsh plugin --profile web add dsh-semantic-drift

Sandbox test results

StageResult
1 install✓
2 list✓
3 mount✓
4 boot—

Four stages run in an isolated sandbox: install (network on) → list → mount → boot (last three with no network).

README

dsh-semantic-drift · 语义漂移词表

[English](README.md) · 简体中文

一个 DSH 插件:用一份可版本化的词表记录项目的业务概念,只读扫描出代码里把它们写得不一样的地方,并给人和 Agent 一个地方去决定"哪种写法才算数"。

DSH 中显示的名字是 语义漂移词表(英文 Semantic Drift Vocabulary)。

目录

  • [这个想法从哪来](#这个想法从哪来)
  • [它做什么](#它做什么)
  • [它不做什么](#它不做什么)
  • [安装](#安装)
  • [开始使用](#开始使用)
  • [各模块信息](#各模块信息)
  • [词表文件](#词表文件)
  • [检测器](#检测器)
  • [Agent 工具与提示注入](#agent-工具与提示注入)
  • [面板](#面板)
  • [配置](#配置)
  • [工作详细信息](#工作详细信息)
  • [Token 成本](#token-成本)
  • [保证](#保证)
  • [限制](#限制)
  • [开发](#开发)
  • [许可](#许可)

这个想法从哪来

思路来自 kurapica/schema-node-csharp,它主张的三件事是本插件的前提:

1. 语义应当是可版本化的独立实体,而不是每次从代码里重新推导;

2. 有限可枚举的词汇表比无限类型系统更容易保持正确;

3. 漂移必须可观测、可裁决,而不是指望团队靠记忆维持。

但不借实现:没有 Meta/Property/Relation 建模,没有语义编译,没有代码生成。只有一份 YAML、一个只读扫描器、一个面板、五个 Agent 工具。

它做什么

它记住"东西叫什么"。 每个概念一条记录:点分 id、人怎么称呼它(术语)、种类、规范写法(必要时还有类型与单位)、一句说明。这份文件跟着项目走版本,所以一次改名就是一次可 review 的 diff。

它找出代码里不一致的地方。 只读扫描把代码树与词表对照,报告:

  • 同一个类型被定义了两遍——比较成员名,也比较成员取值;
  • 两份拷贝已经分叉:少了成员、多了成员、枚举值被互换;
  • 看起来是拷贝、其实是参数化派生,不能合并;
  • 规范名的拼写变体,包括"词表里的写法在代码里根本不存在";
  • 术语出现在注释或资源里,但代码里没有对应符号。

词表为空时也能用:结构性检测器拿代码和代码比较,所以新项目在登记第一个概念之前就有结果。

它给"决定"一个落点。 接受一条例外要写理由、选最小范围;之后可以改范围、改理由、移除、撤销,每条都显示它当前真正静音了多少条发现。这个决定是词表里的一行,而不是某个人脑子里的记忆。

它把词表放到 Agent 面前。 每个会话收到一节系统提示:所在工作区的概念,以及配套规则——改名前先查、名字与规范符号逐字一致、缺概念先登记、刻意偏离要写理由记录。五个工具让 Agent 读取、登记、扫描、裁决。

它会消耗 token,而且可以关掉。 提示小节是持续性的成本;面板设置里的开关可按 profile 关闭它,扫描本身在没有请求时不产生任何开销。实测数字见 [Token 成本](#token-成本)。

它不做什么

  • 它是词法级工具,不懂语义。 比较的是标识符、成员名与注释文本;两个同名但无关的类型仍可能被报出来。
  • 它不强制任何事。 提示里的规则是建议;Agent 可以偏离,唯一的防线是偏离必须记录。
  • 它不改代码。 没有自动重命名、自动合并或补丁;扫描之所以能被信任,正因为它从不写源码。
  • 结构性检测只覆盖三种语言的声明:C#、TypeScript、Python。其它文件只贡献注释/字符串证据。
  • 单位只存不查。 canonical.unit 会被展示并做字符串校验,但没有量纲漂移检测器。
  • 一个工作区一份词表。 没有跨仓库视图。
  • 它不替你决定词表是否提交。 那是项目自己的选择:提交则可以团队共享与 review,不提交则只在本机生效。

安装

以下任一方式都可安装到某个 profile:

# 从 npm
dsh plugin --profile desktop add dsh-semantic-drift

# 从 GitHub
dsh plugin --profile desktop add github:Yubickari/dsh-semantic-drift

# 从本地目录
dsh plugin --profile desktop add link:/path/to/dsh-semantic-drift

Web GUI 里对应「设置 → 插件 → 从源安装」。安装后刷新一次页面让浏览器半边加载,侧边栏会出现「语义漂移词表」。

lib/ 已随仓库提交,从 git 安装不需要构建。插件要求 DSH >=0.2.1-rc.3。

更新

插件里没有自动更新器:DSH 在重新安装时替换已安装的 bundle。

# npm,指定版本
dsh plugin --profile desktop add dsh-semantic-drift@0.2.0

# GitHub,锁定到某个 tag
dsh plugin --profile desktop add github:Yubickari/dsh-semantic-drift#v0.2.0

之后重启 DSH,版本号看面板右下角的底栏(vX.Y.Z)或 GET /semantic-drift/health;设置弹窗里不再显示版本。更新不会改动你的词表文件与已接受例外。

开始使用

1. 在某个工作区打开「语义漂移词表」。

2. 点「创建词表」——写入 .dsh/semantics.yaml(含默认排除项,暂无概念)。

3. 点「重新扫描」。还没有概念时就有发现:结构性检测器会指出"同名类型被定义了两遍",这是冷启动的价值。

4. 用「新建概念」(或 semantic_upsert)登记概念,再扫一次。依赖词表的检测器这才有比较基准。

5. 对打算保留的写法点「接受」:选范围(仅此文件 / 同文件名的所有目录 / 整个符号 / 自定义 glob),看清会静音多少条,再写理由。

各模块信息

词表文件

version: 1
meta:
  project: demo
  updated: 2026-10-25
exclude: ["**/node_modules/**", "**/bin/**", "**/obj/**"]
concepts:
  - id: device.target_temperature      # group.name,全局唯一
    terms: ["目标温度", "设定温度"]        # 人怎么称呼它
    kind: quantity                     # entity | quantity | enum | status | reference
    canonical:
      symbol: TargetTemperature        # 代码里必须这么写
      type: double
      unit: "°C"
    note: 设备被要求达到的温度。
    accepted:                          # 已裁决的例外,必须带理由
      - symbol: TargetTemp
        path: src/Legacy/**            # glob;省略表示该符号全局接受
        reason: 公开字段保留一个版本

terms 可以写任何语言:扫描器把它们当纯文本在注释、字符串与资源文件里匹配。

写入前一定先校验;不通过就不会写入,并给出行号或文档路径:

  • id 唯一且形如 group.name;
  • canonical.symbol 是合法标识符且全局唯一;
  • terms 非空,且不能被两个概念共用;
  • 每条 accepted 必须有 reason;
  • 每个 glob 必须能解析;
  • YAML 语法错误给出行列号,文件保持原样。

保存是规范化、幂等的;用原文编辑器手改时保留你自己的格式。

检测器

检测器 · 置信度 · 信号

duplicate-type · 高 · 成员名与取值都相同:真正的复制,建议合并是站得住的

· 高 · 派生副本:成员名相同、取值不同、共享同一基类——参数化派生,不作为合并候选

· 高 · 同名不同值:没有共同基类,两侧对这些名字的含义已不一致

contract-drift · 高 · 同名类型的成员不同,或同名成员的取值不同。若一方是另一方的同名子类,或两方都是私有嵌套助手类,则不报

symbol-variant · 中 · canonical.symbol 的拼写变体(大小写/分隔符、已知错拼、编辑距离 ≤ 2),或同一契约另一种命名:同基类、同成员、同稳定常量

· 中 · 词表拼写不在代码里:canonical.symbol 作为代码 token 全仓不出现,而另一种大小写写法有声明或作为声明词头

term-unmapped · 低 · 术语出现在注释或资源里,但规范符号从未在代码中出现

每条发现还带一个稳定的规则 id(detail.rule),面板就是按它本地化的:

规则 · 检测器 · 含义

identical-members · duplicate-type · 成员名与取值都相同

derived-copy · duplicate-type · 成员相同、取值不同、共享同一基类

literal-variant · duplicate-type · 成员相同、取值不同、无共享基类

diverged-members · contract-drift · 成员或成员取值不同

normalized · symbol-variant · 去掉大小写与分隔符后拼写相同

confusable · symbol-variant · 符号中某个词的已知错拼

edit-distance · symbol-variant · 与规范写法相差 ≤ 2 次编辑

contract-alias · symbol-variant · 同一契约、另一个名字

canonical-case · symbol-variant · 规范写法不存在,只有另一种大小写

canonical-missing · term-unmapped · 术语被使用,规范符号未出现

成员的取值也参与比较(仅限单行简单字面量):两个枚举成员值互换,过去因为只比名字而看起来"完全一致"。一侧是 struct、另一侧是 class 的拷贝会在消息里点明。

两条过滤避免刷屏:变体必须同文件还提到该概念的术语,或与规范符号共享首个词元;"契约漂移"的两份声明必须至少共享一个成员。

刻意排除:入口类(带 Main 的 Program/Startup)、partial 声明、生成文件(.Designer.cs、.g.cs、auto-generated 头)、成员少于两个的声明、同名子类遮蔽基类、私有嵌套助手类。

Agent 工具与提示注入

工具 · 用途

semantic_list · 列出概念;hasDrift 跑一次扫描并只保留有发现的概念

semantic_get · 按 id 或符号读一个概念与它的已接受例外;includeDrift 追加扫描

semantic_upsert · 新建或更新概念(merge 保留未提供字段,replace 重建)

drift_scan · 结构化发现,带检测器名、置信度与引用

semantic_accept · add(默认)、update 改范围或理由、remove 移除一条、clear 清空一个概念;新增与修改必须带 reason;定位已有条目用 previousPath

announceToAgent 开启时(默认),每个会话收到一节提示:所在工作区的概念与配套规则。整节最多 200 行,超过 120 个概念折叠为计数。面板顶部、工作区开关右边的「注入提示」按工作区记忆,关掉即停止该工作区的持续成本,工具不受影响。

拒绝一律是返回值({ ok: false, code, message, issues }),不抛异常。词表无法解析时返回 valid: false 与前几条问题。

它设计的循环:

1. Agent 接到任务,先 semantic_get 查要动的概念;

2. 缺失的概念先 semantic_upsert 登记,再写代码;

3. 改完 drift_scan,看有没有引入变体或分叉;

4. 确属刻意的发现,用 semantic_accept 带理由、带最小范围接受;

5. 词表 diff 和其它改动一样走 review。

面板

  • 左侧树:概念按 id 前缀分组,组内有发现计数、组头有加号,顶部有搜索与快速新建。
  • 概念详情:字段、归属

…(truncated)

Rendered from the README published on npm. Formatted only, not edited.

Versions

Published on npm::3,最后更新 2026-10-31

Links

GitHub · Homepage · npm

Same category