dsh-plugin-term-dictionary 0.0.0-stage → 1.1.0
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/CHANGELOG.md +189 -0
- package/LICENSE +21 -0
- package/README.md +776 -2
- package/cordis.patch.yml +14 -0
- package/icon.svg +13 -0
- package/lib/ROADMAP-lexicon.md +52 -0
- package/lib/client.js +13354 -0
- package/lib/core/api.js +278 -0
- package/lib/core/bus.js +98 -0
- package/lib/core/copy.js +614 -0
- package/lib/core/core.js +309 -0
- package/lib/core/dictionary.js +1187 -0
- package/lib/core/entries.js +454 -0
- package/lib/core/highlight.js +282 -0
- package/lib/core/hover.js +470 -0
- package/lib/core/hovercard.js +173 -0
- package/lib/core/interact.js +1802 -0
- package/lib/core/lexicon.en.js +872 -0
- package/lib/core/lexicon.zh.js +249 -0
- package/lib/core/overlay.js +239 -0
- package/lib/core/pack.js +372 -0
- package/lib/core/package.json +4 -0
- package/lib/core/selection.js +83 -0
- package/lib/core/settings.js +366 -0
- package/lib/core/shell.js +1003 -0
- package/lib/core/stopwords.js +147 -0
- package/lib/core/store.js +397 -0
- package/lib/core/styles.js +574 -0
- package/lib/core/terms.js +398 -0
- package/lib/core/transfer.js +382 -0
- package/lib/core/views.js +2428 -0
- package/lib/index.js +1110 -0
- package/lib/pack-code.js +84 -0
- package/locale/en.json +6 -0
- package/locale/zh.json +6 -0
- package/package.json +71 -3
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
# 更新日志
|
|
2
|
+
|
|
3
|
+
本文件记录**发布出去**的版本。每一项都是可验证的行为,不写计划。
|
|
4
|
+
|
|
5
|
+
## 1.1.0 — 未发布
|
|
6
|
+
|
|
7
|
+
### 词条组(目录)
|
|
8
|
+
|
|
9
|
+
- **组是列表里的一行**,和词条同一块地方、同一层滚动、同一行尺寸——因为组和词条是同一类东西:**点开它**。
|
|
10
|
+
行里给出组名、里面有多少条(含所有下级)、以及一个 `›`。
|
|
11
|
+
- **一次只看一层**:顶层显示"就在顶层"的词条与下级组;进去之后显示该层的词条与它自己的下级组,上层的
|
|
12
|
+
词条不再出现(组是目录,里面的东西是进去之后看到的)。
|
|
13
|
+
- **面包屑是回去的路**:`全部 › backend › net`,每段都能点,当前层不可点(它不是动作)。只能进不能出的
|
|
14
|
+
目录是陷阱。
|
|
15
|
+
- **站在哪一层,新建的词条就落在哪一层**(编辑器里的「分组」字段也可手改,用 `/` 分层)。
|
|
16
|
+
- 分组是**决定**而不是内容:按 `groupAt` 时间戳合并(第三次用 `pinnedAt` 那套),所以移动、移回顶层、
|
|
17
|
+
同毫秒再移动都有确定结果,不会因合并顺序被翻案。
|
|
18
|
+
- 「导入文件夹」按文件夹路径建组(选中的文件夹名就是第一级),可用开关关掉。
|
|
19
|
+
|
|
20
|
+
### 恢复删除是一个有名字的动作
|
|
21
|
+
|
|
22
|
+
- `restoreEntry`:记录 `restoredAt` 作为合并真正去读的证据,并**重新封存文档**——墓碑与它的 key 直接消失,
|
|
23
|
+
而不是"在一次比较里被否决"。导入时**新词条走写入、被删词条走恢复**(`planImport` 用 `revived` 单独列出
|
|
24
|
+
被恢复的那些)。
|
|
25
|
+
- 这是被报上来的形状问题:**"被投票否决"不等于"撤回"**,此后任何一次读到墓碑的合并都能把删除放回去。
|
|
26
|
+
|
|
27
|
+
### 词条行:钉选在前、操作在第二行,而且操作不再让列表跳动
|
|
28
|
+
|
|
29
|
+
- **列表不再重排**:以前排序是"钉选优先 → 待补充优先 → 最近见过优先",于是钉选会把词条顶到首位、补上解释会让它掉下去、正文里再提一次都会打乱顺序——**操作移动了正在看的那一行**。现在只按**创建时间倒序**:这是唯一不会被任何操作改变的东西。钉选状态就在行首显示,「已钉选」标签负责汇集它们,顺序不必再承担这件事。
|
|
30
|
+
- **钉选移到标题前面**:它是词条的**状态**而不是对它的操作,所以和标题同一行、且在标题之前。
|
|
31
|
+
- **操作统一到第二行**:复制 / 反馈 / 编辑 / 删除,每一行都在同样的位置。以前它们跟在标题行末尾,位置随术语长度、徽标数量、有没有分类而变——控件在行与行之间游走。
|
|
32
|
+
- **单行输入框统一宽度**(22em;地址类字段显式放宽到 30em)。上一版按内容给了 18/12/14/20em 不等,结果是一列长短不齐的框,读起来像失误而不是决定。多行字段(Area)仍占满宽度。
|
|
33
|
+
|
|
34
|
+
### 导入:文件夹,以及"导入之后看得见"
|
|
35
|
+
|
|
36
|
+
- **导入文件夹**:用系统自己的目录选择器(`webkitdirectory`)选一个文件夹,把里面的 `*.json` 全部读一遍
|
|
37
|
+
——导出的词典、下载的包文件都认。不是 JSON 的文件直接忽略,读不了的**点名列出**(一个二十文件的文件夹
|
|
38
|
+
里有个坏文件,只说"失败"等于没说);可选「用文件夹名作为分类」,只补**没有分类**的词条。用
|
|
39
|
+
`webkitdirectory` 而不是宿主服务,是因为那需要一个可能缺席的服务依赖,而缺席会把整个插件挂起。
|
|
40
|
+
- **导入之后看得见**:以前写入后仍停在原来的标签与搜索里——在「已删除」下导入,界面看起来就是"什么都没
|
|
41
|
+
发生"(这正是它被报上来的样子)。现在导入页请面板切到「全部」并清空搜索,且报告里明说何时动过视图。
|
|
42
|
+
- **数据那条路本来就是好的**:新增的宿主往返用例证明"导入撤回的词条"在宿主那边活着、带着文件里的文本、
|
|
43
|
+
且墓碑消失——报告里的"看不到"发生在显示层,不是写入层。
|
|
44
|
+
|
|
45
|
+
### 三处界面
|
|
46
|
+
|
|
47
|
+
- **词条列表可以多列排版**:新偏好「词条排列」= 自动 / 1 / 2 / 3 列。自动按面板宽度铺,窄了回到一列;
|
|
48
|
+
一列排下去是"很长一条",多列才看得动。列表容器带 `data-term-columns`,排版规则是一个可断言的纯函数。
|
|
49
|
+
已删除 / 已标记视图与批量选择模式**不**参与分列(那是"决定的列表"和"带勾选框的行")。
|
|
50
|
+
- **导入要确认**:选文件不再立刻写入——先给一份**预演**(将导入几条 / 已有几条 / 你删过几条会被跳过 /
|
|
51
|
+
重复或无效几条),按「确认导入」才真的写。勾选「导入我删除过的词条」会**重新预演**,因为要确认的
|
|
52
|
+
数字必须是这个勾选产生的数字。预演用的是同一个纯函数 `planImport`,写入那一刻再算一次——所以预演
|
|
53
|
+
即使过期(另一个窗口删了东西),写进去的也不是过期的答案。读文件时上一份报告同时清掉:它描述的是
|
|
54
|
+
已经发生的事,留在新的确认框下面会读成在描述这一次。
|
|
55
|
+
- **输入框不再一律撑满**:`Field` 多了一个 `width`(上限)——包名 18em、署名 / 许可 12em、源地址 26em、
|
|
56
|
+
编辑器里的术语 20em / 中文名 12em / 分类 14em。一个两字字段不该横跨整个面板。
|
|
57
|
+
|
|
58
|
+
### 自带一个源
|
|
59
|
+
|
|
60
|
+
- **新装即有源**:`settings.packSources` 的默认值是本仓库自己的 `packs/index.json`
|
|
61
|
+
(`@main`,所以仓库里新增的包不必发新版就能被看到)。它不是硬编码的特例:在「源」列表里显示
|
|
62
|
+
**内置**、一键可移除,取回只在你打开词条包页或按刷新时发生。
|
|
63
|
+
- **打开页面就取一次**:没有这一步,新装用户看到的是一个源加一片空白,而「刷新」是一个没人猜得出
|
|
64
|
+
目的的按钮。取的是**你自己配置的那些源**,宿主负责取并缓存一小时。
|
|
65
|
+
- **"从没设过"与"我全删了"是两件事**:设置里缺这个键 → 用内置默认;存着空数组 → 就是空
|
|
66
|
+
(不把默认塞回来)。少了这个区分,清空源列表的人每次都会被内置源"复活"一次。
|
|
67
|
+
|
|
68
|
+
## 1.0.0 — 2026-10-10
|
|
69
|
+
|
|
70
|
+
首个正式版(已发布到 npm)。功能面:自动收录、标注、悬停解释、点击进词条、面板五个视图与三个二级页、
|
|
71
|
+
设置页、导入 / 导出、反馈、词条包与分享码。
|
|
72
|
+
|
|
73
|
+
### 反馈
|
|
74
|
+
|
|
75
|
+
- **词条上可以留言**:编辑器里的「反馈」块记录问题类型(解释不对 / 术语不对 / 不该收录 / 其他)
|
|
76
|
+
与一句自己的说明;面板多了一个「已标记」视图,每行一个「撤回标记」。
|
|
77
|
+
- **「解释不可信」是一条会给机器看的判断**:标上之后,自动解释**不会再覆盖**这条词条
|
|
78
|
+
(规则在数据层 `recordSighting`,所以页面的队列、将来的后台刷新、宿主自己的 `record` 动作都受它约束),
|
|
79
|
+
列表与已标记视图里都带徽标。
|
|
80
|
+
- **重新生成会告诉模型上一次被否掉了**:页面发 `retry: true`,宿主在提示词末尾追加一句固定的话。
|
|
81
|
+
用户自己的备注永远不会发给模型——那是把备注变成指令。
|
|
82
|
+
- **反馈报告**:导入 / 导出页可以把标记导出成一个文件(下载或复制)。报告里**永远没有会话原文**
|
|
83
|
+
(构造上就没有这个字段),当前解释要另外勾选才附上。
|
|
84
|
+
- **也可以记进宿主自己的反馈日志**:宿主半边用 `ctx.inject(["sessionFeedback"], …)` 接这条可选服务
|
|
85
|
+
(和 `llm` 同一个模式),页面 POST 到自己的 `/feedback` 路由。**没有**把它写成客户端的
|
|
86
|
+
`remote.sessionFeedback`:实测这个桌面端没有 `remote` 服务,写进客户端 `inject` 会让整个包
|
|
87
|
+
永远等待、插件整体不加载。没有这条通道的组合会如实回答 `unavailable`,报告照样能导出。
|
|
88
|
+
|
|
89
|
+
### 词条包与分享码
|
|
90
|
+
|
|
91
|
+
- `tools/make-pack-index.mjs`:把 `packs/` 里的包扫成 `packs/index.json`(各自的 sha256、条数、分类、
|
|
92
|
+
可取的 https 地址),`--check` 不写文件、不一致即非零退出。索引是**确定性**的(`updatedAt` 取目录里
|
|
93
|
+
最新那个包的时间),所以 `--check` 才可能通过——第一版不是,这个 bug 被端到端用例逼出来。
|
|
94
|
+
- 宿主:缓存里的包**对不上索引承诺的摘要**时会**重新取一次**再判定。摘要是权威、缓存不是;
|
|
95
|
+
否则重发包之后读者会在大约一天里看到 `checksum-mismatch`,看起来就像包坏了。
|
|
96
|
+
- `packs/README.md`:发一个源的完整步骤与两条硬规则。
|
|
97
|
+
- 端到端用例:真跑生成器 → 把生成出来的索引与包喂给真实路由 → 摘要必须通过;篡改一个字节必须被拒;
|
|
98
|
+
同 URL 新字节新摘要必须通过(证明会重取而不是拿缓存判死)。
|
|
99
|
+
- `lib/core/pack.js`:包形状、按分类切片、允许字段的精确白名单(`context`/`notes`/`feedback`/
|
|
100
|
+
`untrusted`/`pinned`/`source`/历史计数/墓碑都进不去)、索引形状与 `refuseUrl`(只允许 https)。
|
|
101
|
+
- `lib/pack-code.js`(宿主):`dshpack1:` + base64url(raw-deflate) 分享码,解码时剥空白、
|
|
102
|
+
区分 `not-a-code`/`corrupt`/`too-large`,**解压上限 4 MiB**(防解压炸弹)。
|
|
103
|
+
- 宿主路由:`POST /pack`(build / decode)、`GET /source/index`、`GET /source/pack`。
|
|
104
|
+
索引 1 小时、包 24 小时的磁盘缓存;源不可达而缓存还在 → 返回上次内容并标 `stale`;
|
|
105
|
+
索引里不可用的行丢掉并计数;包的 `sha256` 与索引承诺不符则拒绝。
|
|
106
|
+
- 界面:面板第三个二级页「词条包」——生成分享码 / 下载包文件、粘贴分享码**先预览再导入**、
|
|
107
|
+
源的增删与刷新(列表显示名称/作者/许可/条数/分类/校验和,点预览才取回)。
|
|
108
|
+
- 导入路径收成一条:`importEntries()` 由导入 / 导出页与词条包页共用(重复项报告、已删除词条的
|
|
109
|
+
勾选、"精心构造的复活"因此只有一份实现);分类勾选行提成共享组件 `CategoryChecklist`
|
|
110
|
+
——**变异 harness 先发现它有两份**。
|
|
111
|
+
- 源地址规则三处共用(设置存储 / 页面添加源 / 宿主发起请求前),页面不可能接受传输层会拒绝的地址。
|
|
112
|
+
- 用例的 vm 沙箱补上 `URL`(真实页面有):缺它时页面把每个地址都判成 `bad-url`,
|
|
113
|
+
"拒绝 http" 的检查因此看到的是错的理由。
|
|
114
|
+
- 打包修复:`files` 白名单漏了 `lib/pack-code.js`(装出来的包 import 会失败)——
|
|
115
|
+
这是发布闸门"装进干净目录再 import"这一步第一次抓到真问题。
|
|
116
|
+
|
|
117
|
+
### 复制词条
|
|
118
|
+
|
|
119
|
+
- 每行一个**复制**图标、编辑器里一个**复制词条**按钮:一次点击把词条写成可读文本
|
|
120
|
+
(`术语(中文名)` / 解释 / `例:…`),**不需要先选中**。
|
|
121
|
+
- 修掉"选中想复制却被切走"这一类:结束选中的那一下点击不再被当作选择手势。
|
|
122
|
+
以前面板里双击词条中的词会打开编辑器、正文里拖选句子(选区结束在标记词上)会切进词典,
|
|
123
|
+
现在两条路都不动,规则统一在 `lib/core/selection.js`。
|
|
124
|
+
|
|
125
|
+
首个正式版的功能面:自动收录、标注、悬停解释、点击进词条、面板视图与二级页、
|
|
126
|
+
设置页、导入 / 导出。
|
|
127
|
+
|
|
128
|
+
### 收录与标注
|
|
129
|
+
|
|
130
|
+
- **自动收录**:agent 回复渲染完成后扫描英文技术词、缩写、`camelCase` / `snake_case` 命名与内置词库里的
|
|
131
|
+
中文术语,每条消息最多新建 3 条、每分钟有独立预算;代码块与输入框不参与。
|
|
132
|
+
- **标注**走 CSS Custom Highlight API:不写宿主的 DOM,因此正文的文本节点与偏移不会被改动;
|
|
133
|
+
行内代码与正文遵守**同一条**匹配规则。
|
|
134
|
+
- **收录门槛可调**:最短词长、是否收代码风格命名、是否收中文术语。
|
|
135
|
+
- **删除是黑名单**:删掉的词不会被自动重新收录,导入默认也跳过它;「已删除」视图里可以**撤回**。
|
|
136
|
+
|
|
137
|
+
### 鼠标手势
|
|
138
|
+
|
|
139
|
+
- **悬停**在指针停稳 `hoverInMs`(默认 110ms,设置页可调 0–200ms)后浮出简短解释;
|
|
140
|
+
读出延迟默认 **0**(给"离开"加延迟读起来像卡顿)。
|
|
141
|
+
- **点击**已标注的词进入词典对应词条并滚动到视野;词典里没有的词弹卡片提供「创建词条 /
|
|
142
|
+
用模型生成解释」;选中词句出现「添加词条」按钮。
|
|
143
|
+
- 命中是**一次文本走查的查表**:caret 给出 `(节点, 偏移)`,标注层记下每段标记的区间,
|
|
144
|
+
命中即查表——不读包围盒、不按比例估算字符位置。这一条是本版与早期实现最大的区别,
|
|
145
|
+
也是"有下划线但悬停/点击没反应"那一类问题的根因。
|
|
146
|
+
- 指针层只此一份:早期由第二个插件(`dsh-plugin-term-wikilink`)承担的那半边已合并进来并退役,
|
|
147
|
+
两层各算一次、结论不一致的结构性问题因此消失。
|
|
148
|
+
|
|
149
|
+
### 面板
|
|
150
|
+
|
|
151
|
+
- **四个视图**:全部 / 待补充 / 已钉选 / **已删除**(墓碑列表 + 逐行撤回)。
|
|
152
|
+
- **两个二级页**:**设置**(11 项偏好:两态用开关、多值用选项条、范围内的数用滑杆 + 数字框)与
|
|
153
|
+
**导入 / 导出**。
|
|
154
|
+
- 词条行整块可点(行内按钮保留各自语义);批量选择一次写入,每条各留一个墓碑。
|
|
155
|
+
- **钉选**的词条不会被「清空词典」带走,确认框里写明「删几条、留几条」。
|
|
156
|
+
|
|
157
|
+
### 导入 / 导出
|
|
158
|
+
|
|
159
|
+
- 导出可按**全部**或**按分类**(分类就是词条的「领域」,清单由数据统计得出);一个分类都不选 =
|
|
160
|
+
导出空文件,而不是"那就全导"。
|
|
161
|
+
- 导出文件**不带**本机的看到历史(`seen` / `lastSeenAt` / `createdAt`),带 `pinned`——那是用户的判断。
|
|
162
|
+
- 导入逐条判定归宿并**报告各自条数**:新建、已存在(原样保留)、被你删过(默认跳过,可显式勾选
|
|
163
|
+
「导入我删除过的词条」,勾选后这些词条会被导入并从已删除列表撤回)、重复或无效。
|
|
164
|
+
- 导入**不读**文件里的 `source`:所有导入的词条都由保存路径记成 `user`,那是唯一被合并当作
|
|
165
|
+
「用户意图」的来源。
|
|
166
|
+
|
|
167
|
+
### 模型解释
|
|
168
|
+
|
|
169
|
+
- 生成解释走 profile 里挂载的 `llm` 服务:优先用**配置里指定的路由**,其次用 profile 自己的选择,
|
|
170
|
+
最后才回退到注册表里的第一条——并且只对**凭据缺失**这一类失败继续换线路,模型侧的失败如实报告。
|
|
171
|
+
- 解释语言(跟随界面 / 中文 / 英文)与详细程度(一句话 / 标准 / 详细)是设置页里的偏好,
|
|
172
|
+
`zh` 字段始终是中文。
|
|
173
|
+
|
|
174
|
+
### 同步与存储
|
|
175
|
+
|
|
176
|
+
- 文档形状:活词条在 `entries`,墓碑在 `backing` 且键列在 `deletedKeys`;本机文件写在
|
|
177
|
+
`~/.dsh/dsh-plugin-term-dictionary/dictionary.json`,宿主路由 `/dsh-term-dictionary/{state,entries,explain}`。
|
|
178
|
+
- 合并是并集 + **墓碑裁决**:删除只在 `mergeRecords` 一处决定,复活需要"用户要过的记录、且严格
|
|
179
|
+
晚于那次删除"。一台时钟落后的机器不会因为"现在比删除新"而把删除撤销掉。
|
|
180
|
+
|
|
181
|
+
### 已知限制
|
|
182
|
+
|
|
183
|
+
见 README 的「已知限制」一节。其中一条要特别说明:**点击"词典里没有的词"仍走几何命中**
|
|
184
|
+
(`blockAtPoint` → `elementFromPoint` 复核 → 偏移换算),那条路上的快照老化问题没有做过对照实验;
|
|
185
|
+
悬停已经不依赖它。
|
|
186
|
+
|
|
187
|
+
## 0.1.0 — 2026-10-08
|
|
188
|
+
|
|
189
|
+
内部版本:面板、收录、标注、模型解释的最初实现。未发布。
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 lakerian
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|