weflow-cli 1.9.0 → 1.10.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/ARCHITECTURE.md +62 -26
- package/CHANGELOG.md +948 -0
- package/OPERATIONS.md +65 -11
- package/README.en.md +14 -5
- package/README.md +21 -6
- package/bin/weflow-cli.ts +348 -39
- package/dist/bin/weflow-cli.js +363 -68
- package/dist/bin/weflow-cli.js.map +1 -1
- package/dist/mcp-server/index.d.ts.map +1 -1
- package/dist/mcp-server/index.js +19 -1
- package/dist/mcp-server/index.js.map +1 -1
- package/dist/src/core/dbPathService.d.ts +12 -0
- package/dist/src/core/dbPathService.d.ts.map +1 -1
- package/dist/src/core/dbPathService.js +20 -3
- package/dist/src/core/dbPathService.js.map +1 -1
- package/dist/src/panel/server.d.ts.map +1 -1
- package/dist/src/panel/server.js +35 -0
- package/dist/src/panel/server.js.map +1 -1
- package/dist/src/services/assistantService.d.ts +19 -0
- package/dist/src/services/assistantService.d.ts.map +1 -1
- package/dist/src/services/assistantService.js +20 -0
- package/dist/src/services/assistantService.js.map +1 -1
- package/dist/src/services/assistantTools.d.ts +27 -1
- package/dist/src/services/assistantTools.d.ts.map +1 -1
- package/dist/src/services/assistantTools.js +169 -35
- package/dist/src/services/assistantTools.js.map +1 -1
- package/dist/src/services/configService.d.ts +2 -0
- package/dist/src/services/configService.d.ts.map +1 -1
- package/dist/src/services/configService.js +3 -2
- package/dist/src/services/configService.js.map +1 -1
- package/dist/src/services/messageQuery.d.ts +18 -0
- package/dist/src/services/messageQuery.d.ts.map +1 -1
- package/dist/src/services/messageQuery.js +29 -0
- package/dist/src/services/messageQuery.js.map +1 -1
- package/dist/src/services/wechatClient.d.ts +125 -0
- package/dist/src/services/wechatClient.d.ts.map +1 -0
- package/dist/src/services/wechatClient.js +344 -0
- package/dist/src/services/wechatClient.js.map +1 -0
- package/dist/src/services/wechatMedia.d.ts +44 -0
- package/dist/src/services/wechatMedia.d.ts.map +1 -0
- package/dist/src/services/wechatMedia.js +155 -0
- package/dist/src/services/wechatMedia.js.map +1 -0
- package/dist/src/services/wechatMessageService.d.ts +11 -0
- package/dist/src/services/wechatMessageService.d.ts.map +1 -1
- package/dist/src/services/wechatMessageService.js +55 -11
- package/dist/src/services/wechatMessageService.js.map +1 -1
- package/dist/src/types.d.ts +4 -0
- package/dist/src/types.d.ts.map +1 -1
- package/docs/CONTACT_DB_SCHEMA.md +1085 -0
- package/docs/DECISIONS.md +1274 -0
- package/docs/EXTENDING.md +69 -7
- package/docs/FUNCTIONAL-IMPROVEMENT-SPEC.md +6 -0
- package/docs/HEALTH-CHECK.md +12 -7
- package/docs/JEV/345/272/224/347/224/250/346/226/275/345/267/245/346/226/207/346/241/243.md +2 -2
- package/docs/MCP.md +2 -2
- package/docs/PROJECT_STATE.md +62 -5
- package/docs/RELEASING.md +115 -1
- package/docs/images/weflow-architecture-gpt-image-2.png +0 -0
- package/logo.png +0 -0
- package/mcp-server/index.ts +18 -3
- package/package.json +5 -3
- package/resources/js/graph3d/NOTICE.txt +35 -0
- package/resources/js/graph3d/d3-binarytree.min.js +2 -0
- package/resources/js/graph3d/d3-dispatch.min.js +2 -0
- package/resources/js/graph3d/d3-force-3d.min.js +2 -0
- package/resources/js/graph3d/d3-octree.min.js +2 -0
- package/resources/js/graph3d/d3-quadtree.min.js +2 -0
- package/resources/js/graph3d/d3-timer.min.js +2 -0
- package/resources/js/graph3d/layout.mjs +63 -0
- package/resources/js/graph3d/three.min.js +6 -0
- package/resources/js/graph3d/viewer2d.js +448 -0
- package/resources/panel/index.html +12 -0
- package/resources/panel/mascot-blink-1.png +0 -0
- package/resources/panel/mascot-blink-2.png +0 -0
- package/resources/panel/mascot-lift-down-1.png +0 -0
- package/resources/panel/mascot-lift-down-2.png +0 -0
- package/resources/panel/mascot-lift-down-3.png +0 -0
- package/resources/panel/mascot-lift-down-4.png +0 -0
- package/resources/panel/mascot-lift-down-5.png +0 -0
- package/resources/panel/mascot-lift-down-6.png +0 -0
- package/resources/panel/mascot-lift-up-1.png +0 -0
- package/resources/panel/mascot-lift-up-2.png +0 -0
- package/resources/panel/mascot-lift-up-3.png +0 -0
- package/resources/panel/mascot-lift-up-4.png +0 -0
- package/resources/panel/mascot-lift-up-5.png +0 -0
- package/resources/panel/mascot-lift-up-6.png +0 -0
- package/resources/panel/mascot-tickle-1.png +0 -0
- package/resources/panel/mascot-tickle-2.png +0 -0
- package/resources/panel/mascot-tickle-3.png +0 -0
- package/resources/panel/mascot-tickle-4.png +0 -0
- package/resources/panel/panel.css +111 -0
- package/resources/panel/renderer.js +480 -8
- package/scripts/_utils.py +1203 -977
- package/scripts/biz_daily.py +25 -10
- package/scripts/chat_notes.py +15 -5
- package/scripts/check_readme_commands.py +426 -0
- package/scripts/compile_wiki.py +163 -57
- package/scripts/contact_schema.py +339 -0
- package/scripts/data/wechat_emoji.json +225 -0
- package/scripts/fav_notes.py +4 -1
- package/scripts/graph_2d.py +151 -0
- package/scripts/graph_3d.py +646 -0
- package/scripts/health_check.py +163 -26
- package/scripts/nt_decrypt.py +3 -3
- package/scripts/panel_frames.py +683 -0
- package/scripts/pipeline.py +21 -10
- package/scripts/quality_eval.py +5 -0
- package/scripts/rag_chat.py +33 -16
- package/scripts/reply_debt.py +26 -6
- package/scripts/semantic_search.py +130 -22
- package/scripts/vault_rag.py +42 -16
- package/scripts/vault_search.py +44 -8
- package/scripts/wechat_emoticon.py +6 -0
- package/scripts/wiki_lint.py +94 -17
- package/src/core/dbPathService.ts +22 -4
- package/src/panel/server.ts +33 -0
- package/src/services/assistantService.ts +26 -0
- package/src/services/assistantTools.ts +2452 -2319
- package/src/services/configService.ts +5 -2
- package/src/services/messageQuery.ts +29 -0
- package/src/services/wechatClient.ts +380 -0
- package/src/services/wechatMedia.ts +166 -0
- package/src/services/wechatMessageService.ts +62 -11
- package/src/types.ts +4 -0
- package/dist/src/utils/wechatEmoji.d.ts +0 -5
- package/dist/src/utils/wechatEmoji.d.ts.map +0 -1
- package/dist/src/utils/wechatEmoji.js +0 -35
- package/dist/src/utils/wechatEmoji.js.map +0 -1
package/docs/RELEASING.md
CHANGED
|
@@ -32,8 +32,25 @@ npm 包与 GitHub 分开发布,中间隔多久都不奇怪——`1.5.0` 与主
|
|
|
32
32
|
```powershell
|
|
33
33
|
npm run build
|
|
34
34
|
npm test
|
|
35
|
+
py scripts/check_readme_commands.py # 文档/脚本调用/capabilities 里写的命令必须真的存在
|
|
35
36
|
```
|
|
36
37
|
|
|
38
|
+
最后那条盯的是**用户先发现的那一类漂移**:`1.5.0` 与主线拉开 128 个提交时,用户照着 README 敲
|
|
39
|
+
`init --path` 得到 `unknown option`。它逐级问 CLI 的 `--help`(不复刻命令表),扫**三个手写的命令面**:
|
|
40
|
+
**用户文档**的围栏代码块(两份 README + 仓库根那几份 + `docs/*.md`,排除按性质记录过去的
|
|
41
|
+
`CHANGELOG.md` 与 `docs/DECISIONS.md` —— 它们会成段引用当时的命令;同一批代码块里
|
|
42
|
+
`node …/cli.cjs <命令>`、`npx tsx bin/weflow-cli.ts <命令>` 也算这一面 —— 那是同一套命令换个写法)、
|
|
43
|
+
同一批代码块里的
|
|
44
|
+
`python|py scripts/x.py --flag` 调用(**不跑脚本**,按 AST 读它们的 `add_argument` 声明表 —— 仓库对
|
|
45
|
+
Python 脚本的既定纪律就是不 import 也不运行),以及 `capabilities --json` 里手写的 `cli:` **与 `preview:`**
|
|
46
|
+
串(`preview:` 是两阶段约定的第一步 —— 用户与 agent 都按它来,所以它和 `cli:` 一样会被手写漂移;
|
|
47
|
+
那个输出的 MCP 那半是从真实注册表派生的,不用管。串里有这个输出自己的记法:`<a|b>` 是"或"、
|
|
48
|
+
括号外的 `|` 是"两种写法"、`…` 之后截断 —— 判据会按这个归一化后再验)。`--self-test` 是十三条正对照;
|
|
49
|
+
文档命令那一面还有反空扫(缺省语料一定有命令,扫到 0 条就不报通过)。CI 的 `node` job 每次推送都会跑这两步。
|
|
50
|
+
|
|
51
|
+
> 2026-10-11 它就是这么抓到东西的:`OPERATIONS.md` 教用户敲 `search --no-rerank`,而 CLI 从来没有
|
|
52
|
+
> 这个旗标(Python 侧一直有)。只扫两份 README 时它一条也扫不到 —— 所以缺省集合就是"用户文档"。
|
|
53
|
+
|
|
37
54
|
## 4. 打包检查(**不能跳过**)
|
|
38
55
|
|
|
39
56
|
```powershell
|
|
@@ -57,6 +74,46 @@ grep -E "^output/|^models/|node_modules|\.env|\.db$|\.dat$|secret|credential" /t
|
|
|
57
74
|
grep -E "新文件名" /tmp/list.txt
|
|
58
75
|
```
|
|
59
76
|
|
|
77
|
+
这后半句("**该有的在不在**")现在有自动判据:`test/pack-contents.test.ts` 跑一次
|
|
78
|
+
`npm pack --dry-run --json`,断言 `scripts/` 下每个跟踪文件(`.ts` 开发入口除外)与两份 README 引用的
|
|
79
|
+
本地图片都在包里。它防的故障 2026-10-11 在**真实发布物**上量到过:registry 上 `weflow-cli@1.9.0`
|
|
80
|
+
的 501 个文件里同时缺 `scripts/data/wechat_emoji.json` 与 `logo.png` —— 前者让 npm 用户导出的
|
|
81
|
+
聊天记录里一批表情码原样显示成 `[名字]`,后者让包页面挂着一张裂图。这条测试跟着 `npm test` 跑,
|
|
82
|
+
CI 的 `node` job 也在跑;上面那条人工命令留着,用来核对本次**新加**的文件名。
|
|
83
|
+
|
|
84
|
+
想验到"**装出来真的能跑**"(最强的一道,代价是多装一次依赖):把包打进临时目录、再装进一个空
|
|
85
|
+
prefix,然后从**装好的那一份**里问版本。它盯的是白名单之外的另一半 —— 清单对、运行时不成立的情况。
|
|
86
|
+
|
|
87
|
+
```powershell
|
|
88
|
+
npm pack --pack-destination $env:TEMP
|
|
89
|
+
mkdir $env:TEMP\wf-smoke ; cd $env:TEMP\wf-smoke # 空目录
|
|
90
|
+
npm install --no-save --no-audit --no-fund "$env:TEMP\weflow-cli-<版本>.tgz"
|
|
91
|
+
node node_modules\weflow-cli\cli.cjs --version
|
|
92
|
+
node node_modules\weflow-cli\cli.cjs --help
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
2026-10-11 拿 1.10.0 跑过一遍:`ALL_NAMES = 222`(不是只有原图的 118 —— 那正是上一版缺
|
|
96
|
+
`scripts/data/wechat_emoji.json` 时的值)、`[乒乓]`/`[冷汗]`/`[开红包]` 都渲染成对应表情、
|
|
97
|
+
`--version` 答 `1.10.0`。
|
|
98
|
+
|
|
99
|
+
**两个数字口径,免得下一次又花半小时**(2026-10-11 实测):`npm publish` 的 notice 报
|
|
100
|
+
`package size: 12.5 MB` 用的是**十进制 MB**,而 `npm pack --json` 的 `size` 是**字节**(你按习惯除以
|
|
101
|
+
`1MB` 得到 11.88 是 MiB)—— **同一份 tarball**:12,460,202 字节 = 12.46 MB = 11.88 MiB。
|
|
102
|
+
`unpacked size` 同理(publish 27.9 MB = pack 26.62 MiB,解压实测 27,915,402 字节)。不是
|
|
103
|
+
"publish 比 pack 大",是两套单位。
|
|
104
|
+
|
|
105
|
+
**发布时那两条 `npm warn publish … errors corrected` 是修饰性的,不是故障。**
|
|
106
|
+
`bin[weflow-cli]` 那句「cli.cjs was invalid and removed」措辞很吓人,实际只是把 `./cli.cjs` 规范成
|
|
107
|
+
`cli.cjs`;`repository.url` 被改写成 `git+https://…`。**实测证据**:registry 上 `weflow-cli@1.9.0`
|
|
108
|
+
的元数据里 `bin = { 'weflow-cli': 'cli.cjs' }` 完好无损(`npm view weflow-cli@1.9.0 bin repository.url`)
|
|
109
|
+
⇒ `npm i -g` 装出来的命令入口一直都在,**别据此以为发布物少了 bin**。
|
|
110
|
+
(那两条规范化 2026-10-11 已经直接落到仓库里了:`package.json` 的 `bin` 与 `repository.url` 现在就是
|
|
111
|
+
规范形式,发布时不再报这两条 warning,仓库也与 registry 上的一致。)
|
|
112
|
+
|
|
113
|
+
> ⚠️ **`npm pkg fix` 没有 `--dry-run`**:`npm pkg fix --dry-run` 会把 `--dry-run` 当成不认识的参数**忽略掉**,
|
|
114
|
+
> 然后**直接改你的 `package.json`**(2026-10-11 就是这么被改的 —— 我原以为只是"看看会改什么")。
|
|
115
|
+
> 想先看结果就用 `git diff package.json` 兜底,别指望它自己停手。
|
|
116
|
+
|
|
60
117
|
## 5. 发布
|
|
61
118
|
|
|
62
119
|
需要 npm 凭据。`ribiaosu` 账号开了 2FA,所以两条路:
|
|
@@ -68,7 +125,7 @@ grep -E "新文件名" /tmp/list.txt
|
|
|
68
125
|
| 现象 | 原因 |
|
|
69
126
|
| --- | --- |
|
|
70
127
|
| `403 ... two-factor authentication ... required` | token 没勾 Bypass 2FA,或没用 OTP |
|
|
71
|
-
| `
|
|
128
|
+
| `ENEEDAUTH` | 没登录 / 没配 token |
|
|
72
129
|
|
|
73
130
|
**验证 token 是否可用**(`bypass_2fa` 必须是 `true`):
|
|
74
131
|
|
|
@@ -111,6 +168,22 @@ npm publish # 再发一次
|
|
|
111
168
|
|
|
112
169
|
报 `409 Conflict - Cannot publish over previously staged version` → **已经发布成功**。
|
|
113
170
|
|
|
171
|
+
但 409 只说明**版本槽位已被占**,不等于 registry 已经能查到它。发布后 npm 要先扫描再让版本可读,
|
|
172
|
+
**官方不承诺上限**:常见 5 分钟,实测出现过 14、16、25、55 分钟。这个窗口里的表现是:
|
|
173
|
+
|
|
174
|
+
- `npm view weflow-cli version` 还是旧版本号
|
|
175
|
+
- tarball 直链仍然 404
|
|
176
|
+
- 再发一次仍然是 409 —— 所以 409 **区分不了**「还在传播」和「已经好了」
|
|
177
|
+
|
|
178
|
+
窗口期内只做一件事:等 + 轮询,**不要改版本号重发**。想确认不是卡在人工审批:
|
|
179
|
+
|
|
180
|
+
```powershell
|
|
181
|
+
npx --yes npm@11.17.0 stage list weflow-cli --json # 返回 [] 即无待审批版本,属传播中
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
(`npm stage` 需要 npm ≥ 11.15;本机装的是 11.6.2,直接跑会报 `Unknown command: "stage"`,
|
|
185
|
+
所以用 npx 临时拉一个高版本。`npm@11.17.0` 是在本机 Node 24.11.1 上验证过能用的。)
|
|
186
|
+
|
|
114
187
|
## 8. 兜底:告诉用户怎么绕开镜像
|
|
115
188
|
|
|
116
189
|
```powershell
|
|
@@ -121,6 +194,30 @@ npm view weflow-cli version --registry=https://registry.npmjs.org # 用官方
|
|
|
121
194
|
两个源结果不一致 → 是镜像同步问题,不是包的问题:
|
|
122
195
|
`npm install -g weflow-cli@<版本> --registry=https://registry.npmjs.org` 立刻可用。
|
|
123
196
|
|
|
197
|
+
## 建 GitHub Release 时的两个坑(2026-10-02 补 1.8.0/1.8.1/1.8.2 时实测)
|
|
198
|
+
|
|
199
|
+
- **正文上限 125,000 字符。** 1.8.0 那段 CHANGELOG 是 140,154 字符,直接贴会被 API 拒:
|
|
200
|
+
`HTTP 422 ... body is too long (maximum is 125000 characters)`。处理方式是**按 `### ` 小节边界
|
|
201
|
+
机械截断**(放到装不下为止),末尾补一句"完整条目在 `CHANGELOG.md`"。**不要凭"哪几段更重要"去挑**:
|
|
202
|
+
那既不可复现,也不是发布这件事该做的判断。
|
|
203
|
+
- **补历史的 Release 要显式 `--latest=false`。** `gh release create` 默认会把新页面标成 Latest ——
|
|
204
|
+
给 1.8.x 补账时会把 1.9.0 从 Latest 上挤下去。补完用 `gh release list` 确认 Latest 还是最新的那个。
|
|
205
|
+
- **发布前先确认工作区干净**(`git status` 为空,HEAD 就是你打算打 tag 的那次提交)。
|
|
206
|
+
理由不是形式主义,是实测出来的:2026-10-02 给 1.8.0/1.8.1/1.8.2 补 tag 时做了逐文件溯源
|
|
207
|
+
(拿 registry 上的 tarball 与 `git archive <tag>` 比,行尾差异不算),结果是 1.8.1 与 1.8.2 的
|
|
208
|
+
发布源码与 tag 树**一致**,而 **1.8.0 的包里有两个文档文件在 git 里找不到对应状态**:
|
|
209
|
+
`docs/DECISIONS.md` 与更晚的一次提交一致,`README.en.md` 则**与任何提交都不一致**(比 tag 那份
|
|
210
|
+
长约 7,000 字符)。代码部分没问题(逐字节相同),但**那次发布出去的文档再也回不来** ——
|
|
211
|
+
这正是"不把 npm 发布包当作 GitHub 源码的实时镜像;先确认版本和提交"这条规矩要防的事。
|
|
212
|
+
- **1.9.0 的出处核过了(2026-10-11,用上面同一套办法)**:把 registry 上的 tarball 与
|
|
213
|
+
`git archive v1.9.0` 逐文件比(行尾归一后比内容):两边都有的 **289 个文件全部逐字节一致、0 处不同**;
|
|
214
|
+
包里多出的 212 个是 `dist/`(构建产物、不在 git 里);tag 里有而包里没有的 124 个是白名单外的
|
|
215
|
+
东西(`.github/`、`AGENTS.md`、`package-lock.json`、`scripts/*.ts` 等)。
|
|
216
|
+
⚠️ 其中 **`logo.png` 与 `scripts/data/wechat_emoji.json` 两个文件当时确实没进包** —— 那正是
|
|
217
|
+
1.10.0 修掉的缺口(同一件事,两条独立的路都指到它)。
|
|
218
|
+
**结论:1.8.0 那个"发出去的文档再也回不来"没有在 1.9.0 重演** ✅
|
|
219
|
+
|
|
220
|
+
|
|
124
221
|
## 发布后
|
|
125
222
|
|
|
126
223
|
- 回到相关 issue 回复「已发布 + 升级方式」
|
|
@@ -162,6 +259,23 @@ npm view weflow-cli version --registry=https://registry.npmjs.org # 用官方
|
|
|
162
259
|
- 手动跑一次:`py scripts/watch_issues.py`
|
|
163
260
|
- 查看/改频率:`Get-ScheduledTask -TaskName 'WeFlow Issue Watch'`
|
|
164
261
|
|
|
262
|
+
**两个任务怎么建**(这一节此前只写"交给计划任务",**命令本身没记下来过** —— 而 `scripts/health_check.py`
|
|
263
|
+
正是按这两个**名字**判红的,所以缺的从来不是判断,是这三行):
|
|
264
|
+
|
|
265
|
+
```powershell
|
|
266
|
+
schtasks /create /tn "WeFlow Issue Watch" /sc minute /mo 30 ^
|
|
267
|
+
/tr "py \"<仓库路径>\scripts\watch_issues.py\""
|
|
268
|
+
schtasks /create /tn "WeFlow Mail Watch" /sc minute /mo 30 ^
|
|
269
|
+
/tr "py \"<仓库路径>\scripts\watch_mail.py\""
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
- 查看:`Get-ScheduledTask -TaskName 'WeFlow *'` / 撤销:`schtasks /delete /tn "<任务名>" /f`
|
|
273
|
+
- **PATH 不用操心**(计划任务的 PATH 与交互式会话不同,这是这类任务常见的翻车点):`watch_issues.py`
|
|
274
|
+
自己带兜底 —— `GH_CANDIDATES = ['gh', r'C:\Program Files\GitHub CLI\gh.exe']`;`py` 是系统启动器
|
|
275
|
+
(`C:\Windows\py.exe`)。两者都不依赖任务继承的 PATH。
|
|
276
|
+
- `watch_mail.py` 做的是**另一件事**:把白名单来信追加进本地队列 `~/.weflow-mail-queue.jsonl`
|
|
277
|
+
(不读别人的信、不发信;真正按指令做事要等一个会话在跑)。
|
|
278
|
+
|
|
165
279
|
### 发布后自检
|
|
166
280
|
|
|
167
281
|
```powershell
|
|
Binary file
|
package/logo.png
ADDED
|
Binary file
|
package/mcp-server/index.ts
CHANGED
|
@@ -267,13 +267,28 @@ export function buildServer(): Server {
|
|
|
267
267
|
if (!name || name.includes('/') || name.includes('\\') || name.includes('..')) {
|
|
268
268
|
return { content: [{ type: 'text', text: '概念名无效' }] }
|
|
269
269
|
}
|
|
270
|
+
// **两条线各留一张同名页是设计**(用户要求两个概念命名空间分开)。只回第一条
|
|
271
|
+
// 会让人以为另一条没有这个概念 —— 所以同名的都要说出来,并指明回的是哪一张。
|
|
272
|
+
const found: string[] = []
|
|
270
273
|
for (const dir of VAULT_WIKI_DIRS) {
|
|
271
274
|
for (const ext of ['', '.md']) {
|
|
272
275
|
const path = safeChildPath(dir, name + ext)
|
|
273
|
-
if (path && existsSync(path)) {
|
|
274
|
-
|
|
275
|
-
|
|
276
|
+
if (path && existsSync(path)) { found.push(path); break }
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
if (found.length) {
|
|
280
|
+
const text = readFileSync(found[0], 'utf-8')
|
|
281
|
+
if (found.length === 1) return { content: [{ type: 'text', text }] }
|
|
282
|
+
// 用**目录名**说清是哪条线(`Wiki/Concepts` / `Chat/Concepts`):这里不再自己
|
|
283
|
+
// 写一份"文章线/聊天线"的名单 —— 那份在 `_utils.LINE_LABELS` 与助手里各有一份,
|
|
284
|
+
// 已经有测试钉着两边一致,再来第三份就是三处要一起改。
|
|
285
|
+
const rel = (p: string): string => {
|
|
286
|
+
const dir = VAULT_WIKI_DIRS.find(d => p.startsWith(d))
|
|
287
|
+
return dir ? dir.split(/[\\/]/).slice(-2).join('/') : p
|
|
276
288
|
}
|
|
289
|
+
const where = found.map(rel)
|
|
290
|
+
return { content: [{ type: 'text', text:
|
|
291
|
+
`(这个概念两条线都有:${where.join('、')};下面是第一条 ${where[0]})\n\n${text}` }] }
|
|
277
292
|
}
|
|
278
293
|
// Fuzzy search
|
|
279
294
|
for (const dir of VAULT_WIKI_DIRS) {
|
package/package.json
CHANGED
|
@@ -1,21 +1,23 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "weflow-cli",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.10.0",
|
|
4
4
|
"description": "让 AI 读懂你的微信 — 公众号日报·聊天导出·知识库搜索·MCP Server",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
|
-
"weflow-cli": "
|
|
7
|
+
"weflow-cli": "cli.cjs"
|
|
8
8
|
},
|
|
9
9
|
"files": [
|
|
10
10
|
"cli.cjs",
|
|
11
11
|
"dist/",
|
|
12
12
|
"scripts/**/*.py",
|
|
13
|
+
"scripts/data/",
|
|
13
14
|
"mcp-server/",
|
|
14
15
|
"bin/",
|
|
15
16
|
"src/",
|
|
16
17
|
"resources/",
|
|
17
18
|
"docs/images/",
|
|
18
19
|
"docs/*.md",
|
|
20
|
+
"logo.png",
|
|
19
21
|
"README.md",
|
|
20
22
|
"OPERATIONS.md",
|
|
21
23
|
"ARCHITECTURE.md",
|
|
@@ -39,7 +41,7 @@
|
|
|
39
41
|
],
|
|
40
42
|
"repository": {
|
|
41
43
|
"type": "git",
|
|
42
|
-
"url": "https://github.com/zhuobichen/weflow-cli"
|
|
44
|
+
"url": "git+https://github.com/zhuobichen/weflow-cli.git"
|
|
43
45
|
},
|
|
44
46
|
"scripts": {
|
|
45
47
|
"build": "tsc",
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
随包发出去的第三方 JS(3D 图谱页面用)
|
|
2
|
+
=====================================
|
|
3
|
+
|
|
4
|
+
这些文件**不是本仓库写的**,是原样收进来的上游产物。放进仓库的原因只有一个:
|
|
5
|
+
`weflow-cli wiki graph` 要把页面做成**自包含**的(库内联进 HTML,`file://` 双击就能开、
|
|
6
|
+
不联网、不依赖 CDN)。所以它们随 npm 包一起发,各自的许可证照旧约束各自的使用。
|
|
7
|
+
|
|
8
|
+
three.min.js three.js r147 MIT
|
|
9
|
+
Copyright 2010-2022 Three.js Authors(许可头在该文件里)
|
|
10
|
+
https://github.com/mrdoob/three.js
|
|
11
|
+
d3-dispatch.min.js d3-dispatch ISC
|
|
12
|
+
d3-quadtree.min.js d3-quadtree ISC
|
|
13
|
+
d3-timer.min.js d3-timer ISC
|
|
14
|
+
https://d3js.org(Mike Bostock 等)
|
|
15
|
+
d3-force-3d.min.js d3-force-3d v3.0.6 MIT
|
|
16
|
+
d3-octree.min.js d3-octree MIT
|
|
17
|
+
d3-binarytree.min.js d3-binarytree MIT
|
|
18
|
+
https://github.com/vasturiano(来源写在每个文件第一行)
|
|
19
|
+
|
|
20
|
+
d3-force-3d 的 UMD **不带依赖**:它从全局 `d3` 命名空间取 dispatch / timer / quadtree /
|
|
21
|
+
octree / binarytree,所以上面五个必须按这个顺序先引(`layout.mjs` 与 `graph_3d.py` 里
|
|
22
|
+
都按这个顺序读)。少一个的报错是 "u.timer is not a function",看着像库坏了,其实只是缺件。
|
|
23
|
+
|
|
24
|
+
本目录里另外两个文件是**本项目自己的**,不是第三方:`layout.mjs`(构建期算布局的 Node 助手)与
|
|
25
|
+
`viewer2d.js`(2D 版的 canvas 渲染器,会被 `graph_2d.py` 内联进页面)。它们与上面这些库放在一起,
|
|
26
|
+
是因为布局助手 `new Function` 跑的就是这套 UMD —— 一个在包外、一个在包里最容易漏。2D 页面本身
|
|
27
|
+
**不需要任何库**(布局在构建期做完,渲染是裸 canvas),所以 `graph_2d.py` 只检查 d3 那几个 + 这两个文件。
|
|
28
|
+
|
|
29
|
+
注意事项:
|
|
30
|
+
- **升级这些文件要一起改两处**:`scripts/graph_3d.py` 的 `LIB_D3` 与
|
|
31
|
+
`resources/js/graph3d/layout.mjs` 的 `LIBS`。两处都要有,因为页面与布局用的是同一套 UMD。
|
|
32
|
+
- `test/graph-3d-cli.test.ts` 会断言这些文件都在、且页面里**没有外部 http 引用** ——
|
|
33
|
+
换库时别把 CDN 引回来。
|
|
34
|
+
- 3d-force-graph 曾经用过(第一版,2.2 fps),后来换成自己拼 three + d3-force-3d
|
|
35
|
+
(每帧 3~4 次 draw call)。那个 692KB 的捆绑包**没有**收进仓库。
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
// https://github.com/vasturiano/d3-binarytree v1.0.2
|
|
2
|
+
!function(t,r){"object"==typeof exports&&"undefined"!=typeof module?r(exports):"function"==typeof define&&define.amd?define(["exports"],r):r((t="undefined"!=typeof globalThis?globalThis:t||self).d3=t.d3||{})}(this,(function(t){"use strict";function r(t,r,e){if(isNaN(r))return t;var n,i,o,s,h,a,u=t._root,f={data:e},l=t._x0,x=t._x1;if(!u)return t._root=f,t;for(;u.length;)if((s=r>=(i=(l+x)/2))?l=i:x=i,n=u,!(u=u[h=+s]))return n[h]=f,t;if(r===(o=+t._x.call(null,u.data)))return f.next=u,n?n[h]=f:t._root=f,t;do{n=n?n[h]=new Array(2):t._root=new Array(2),(s=r>=(i=(l+x)/2))?l=i:x=i}while((h=+s)==(a=+(o>=i)));return n[a]=u,n[h]=f,t}function e(t,r,e){this.node=t,this.x0=r,this.x1=e}function n(t){return t[0]}function i(t,r){var e=new o(null==r?n:r,NaN,NaN);return null==t?e:e.addAll(t)}function o(t,r,e){this._x=t,this._x0=r,this._x1=e,this._root=void 0}function s(t){for(var r={data:t.data},e=r;t=t.next;)e=e.next={data:t.data};return r}var h=i.prototype=o.prototype;h.copy=function(){var t,r,e=new o(this._x,this._x0,this._x1),n=this._root;if(!n)return e;if(!n.length)return e._root=s(n),e;for(t=[{source:n,target:e._root=new Array(2)}];n=t.pop();)for(var i=0;i<2;++i)(r=n.source[i])&&(r.length?t.push({source:r,target:n.target[i]=new Array(2)}):n.target[i]=s(r));return e},h.add=function(t){const e=+this._x.call(null,t);return r(this.cover(e),e,t)},h.addAll=function(t){Array.isArray(t)||(t=Array.from(t));const e=t.length,n=new Float64Array(e);let i=1/0,o=-1/0;for(let r,s=0;s<e;++s)isNaN(r=+this._x.call(null,t[s]))||(n[s]=r,r<i&&(i=r),r>o&&(o=r));if(i>o)return this;this.cover(i).cover(o);for(let i=0;i<e;++i)r(this,n[i],t[i]);return this},h.cover=function(t){if(isNaN(t=+t))return this;var r=this._x0,e=this._x1;if(isNaN(r))e=(r=Math.floor(t))+1;else{for(var n,i,o=e-r||1,s=this._root;r>t||t>=e;)switch(i=+(t<r),(n=new Array(2))[i]=s,s=n,o*=2,i){case 0:e=r+o;break;case 1:r=e-o}this._root&&this._root.length&&(this._root=s)}return this._x0=r,this._x1=e,this},h.data=function(){var t=[];return this.visit((function(r){if(!r.length)do{t.push(r.data)}while(r=r.next)})),t},h.extent=function(t){return arguments.length?this.cover(+t[0][0]).cover(+t[1][0]):isNaN(this._x0)?void 0:[[this._x0],[this._x1]]},h.find=function(t,r){var n,i,o,s,h,a=this._x0,u=this._x1,f=[],l=this._root;for(l&&f.push(new e(l,a,u)),null==r?r=1/0:(a=t-r,u=t+r);s=f.pop();)if(!(!(l=s.node)||(i=s.x0)>u||(o=s.x1)<a))if(l.length){var x=(i+o)/2;f.push(new e(l[1],x,o),new e(l[0],i,x)),(h=+(t>=x))&&(s=f[f.length-1],f[f.length-1]=f[f.length-1-h],f[f.length-1-h]=s)}else{var _=Math.abs(t-+this._x.call(null,l.data));_<r&&(r=_,a=t-_,u=t+_,n=l.data)}return n},h.remove=function(t){if(isNaN(o=+this._x.call(null,t)))return this;var r,e,n,i,o,s,h,a,u,f=this._root,l=this._x0,x=this._x1;if(!f)return this;if(f.length)for(;;){if((h=o>=(s=(l+x)/2))?l=s:x=s,r=f,!(f=f[a=+h]))return this;if(!f.length)break;r[a+1&1]&&(e=r,u=a)}for(;f.data!==t;)if(n=f,!(f=f.next))return this;return(i=f.next)&&delete f.next,n?(i?n.next=i:delete n.next,this):r?(i?r[a]=i:delete r[a],(f=r[0]||r[1])&&f===(r[1]||r[0])&&!f.length&&(e?e[u]=f:this._root=f),this):(this._root=i,this)},h.removeAll=function(t){for(var r=0,e=t.length;r<e;++r)this.remove(t[r]);return this},h.root=function(){return this._root},h.size=function(){var t=0;return this.visit((function(r){if(!r.length)do{++t}while(r=r.next)})),t},h.visit=function(t){var r,n,i,o,s=[],h=this._root;for(h&&s.push(new e(h,this._x0,this._x1));r=s.pop();)if(!t(h=r.node,i=r.x0,o=r.x1)&&h.length){var a=(i+o)/2;(n=h[1])&&s.push(new e(n,a,o)),(n=h[0])&&s.push(new e(n,i,a))}return this},h.visitAfter=function(t){var r,n=[],i=[];for(this._root&&n.push(new e(this._root,this._x0,this._x1));r=n.pop();){var o=r.node;if(o.length){var s,h=r.x0,a=r.x1,u=(h+a)/2;(s=o[0])&&n.push(new e(s,h,u)),(s=o[1])&&n.push(new e(s,u,a))}i.push(r)}for(;r=i.pop();)t(r.node,r.x0,r.x1);return this},h.x=function(t){return arguments.length?(this._x=t,this):this._x},t.binarytree=i}));
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
// https://d3js.org/d3-dispatch/ v3.0.1 Copyright 2010-2021 Mike Bostock
|
|
2
|
+
!function(n,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports):"function"==typeof define&&define.amd?define(["exports"],e):e((n="undefined"!=typeof globalThis?globalThis:n||self).d3=n.d3||{})}(this,(function(n){"use strict";var e={value:()=>{}};function t(){for(var n,e=0,t=arguments.length,o={};e<t;++e){if(!(n=arguments[e]+"")||n in o||/[\s.]/.test(n))throw new Error("illegal type: "+n);o[n]=[]}return new r(o)}function r(n){this._=n}function o(n,e){return n.trim().split(/^|\s+/).map((function(n){var t="",r=n.indexOf(".");if(r>=0&&(t=n.slice(r+1),n=n.slice(0,r)),n&&!e.hasOwnProperty(n))throw new Error("unknown type: "+n);return{type:n,name:t}}))}function i(n,e){for(var t,r=0,o=n.length;r<o;++r)if((t=n[r]).name===e)return t.value}function f(n,t,r){for(var o=0,i=n.length;o<i;++o)if(n[o].name===t){n[o]=e,n=n.slice(0,o).concat(n.slice(o+1));break}return null!=r&&n.push({name:t,value:r}),n}r.prototype=t.prototype={constructor:r,on:function(n,e){var t,r=this._,l=o(n+"",r),a=-1,u=l.length;if(!(arguments.length<2)){if(null!=e&&"function"!=typeof e)throw new Error("invalid callback: "+e);for(;++a<u;)if(t=(n=l[a]).type)r[t]=f(r[t],n.name,e);else if(null==e)for(t in r)r[t]=f(r[t],n.name,null);return this}for(;++a<u;)if((t=(n=l[a]).type)&&(t=i(r[t],n.name)))return t},copy:function(){var n={},e=this._;for(var t in e)n[t]=e[t].slice();return new r(n)},call:function(n,e){if((t=arguments.length-2)>0)for(var t,r,o=new Array(t),i=0;i<t;++i)o[i]=arguments[i+2];if(!this._.hasOwnProperty(n))throw new Error("unknown type: "+n);for(i=0,t=(r=this._[n]).length;i<t;++i)r[i].value.apply(e,o)},apply:function(n,e,t){if(!this._.hasOwnProperty(n))throw new Error("unknown type: "+n);for(var r=this._[n],o=0,i=r.length;o<i;++o)r[o].value.apply(e,t)}},n.dispatch=t,Object.defineProperty(n,"__esModule",{value:!0})}));
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
// https://github.com/vasturiano/d3-force-3d v3.0.6
|
|
2
|
+
!function(n,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports,require("d3-binarytree"),require("d3-quadtree"),require("d3-octree"),require("d3-dispatch"),require("d3-timer")):"function"==typeof define&&define.amd?define(["exports","d3-binarytree","d3-quadtree","d3-octree","d3-dispatch","d3-timer"],t):t((n="undefined"!=typeof globalThis?globalThis:n||self).d3=n.d3||{},n.d3,n.d3,n.d3,n.d3,n.d3)}(this,(function(n,t,r,e,i,u){"use strict";function o(n){return function(){return n}}function f(n){return 1e-6*(n()-.5)}function a(n){return n.x+n.vx}function c(n){return n.y+n.vy}function l(n){return n.z+n.vz}function h(n){return n.index}function v(n,t){var r=n.get(t);if(!r)throw new Error("node not found: "+t);return r}const d=1664525,y=1013904223,s=4294967296;var g=3;function x(n){return n.x}function z(n){return n.y}function p(n){return n.z}var M=10,w=Math.PI*(3-Math.sqrt(5)),q=20*Math.PI/(9+Math.sqrt(221));n.forceCenter=function(n,t,r){var e,i=1;function u(){var u,o,f=e.length,a=0,c=0,l=0;for(u=0;u<f;++u)a+=(o=e[u]).x||0,c+=o.y||0,l+=o.z||0;for(a=(a/f-n)*i,c=(c/f-t)*i,l=(l/f-r)*i,u=0;u<f;++u)o=e[u],a&&(o.x-=a),c&&(o.y-=c),l&&(o.z-=l)}return null==n&&(n=0),null==t&&(t=0),null==r&&(r=0),u.initialize=function(n){e=n},u.x=function(t){return arguments.length?(n=+t,u):n},u.y=function(n){return arguments.length?(t=+n,u):t},u.z=function(n){return arguments.length?(r=+n,u):r},u.strength=function(n){return arguments.length?(i=+n,u):i},u},n.forceCollide=function(n){var i,u,h,v,d=1,y=1;function s(){for(var n,o,s,x,z,p,M,w,q=i.length,N=0;N<y;++N)for(o=(1===u?t.binarytree(i,a):2===u?r.quadtree(i,a,c):3===u?e.octree(i,a,c,l):null).visitAfter(g),n=0;n<q;++n)s=i[n],M=h[s.index],w=M*M,x=s.x+s.vx,u>1&&(z=s.y+s.vy),u>2&&(p=s.z+s.vz),o.visit(m);function m(n,t,r,e,i,o,a){var c=[t,r,e,i,o,a],l=c[0],h=c[1],y=c[2],g=c[u],q=c[u+1],N=c[u+2],m=n.data,A=n.r,b=M+A;if(!m)return l>x+b||g<x-b||u>1&&(h>z+b||q<z-b)||u>2&&(y>p+b||N<p-b);if(m.index>s.index){var k=x-m.x-m.vx,E=u>1?z-m.y-m.vy:0,j=u>2?p-m.z-m.vz:0,D=k*k+E*E+j*j;D<b*b&&(0===k&&(D+=(k=f(v))*k),u>1&&0===E&&(D+=(E=f(v))*E),u>2&&0===j&&(D+=(j=f(v))*j),D=(b-(D=Math.sqrt(D)))/D*d,s.vx+=(k*=D)*(b=(A*=A)/(w+A)),u>1&&(s.vy+=(E*=D)*b),u>2&&(s.vz+=(j*=D)*b),m.vx-=k*(b=1-b),u>1&&(m.vy-=E*b),u>2&&(m.vz-=j*b))}}}function g(n){if(n.data)return n.r=h[n.data.index];for(var t=n.r=0;t<Math.pow(2,u);++t)n[t]&&n[t].r>n.r&&(n.r=n[t].r)}function x(){if(i){var t,r,e=i.length;for(h=new Array(e),t=0;t<e;++t)r=i[t],h[r.index]=+n(r,t,i)}}return"function"!=typeof n&&(n=o(null==n?1:+n)),s.initialize=function(n,...t){i=n,v=t.find((n=>"function"==typeof n))||Math.random,u=t.find((n=>[1,2,3].includes(n)))||2,x()},s.iterations=function(n){return arguments.length?(y=+n,s):y},s.strength=function(n){return arguments.length?(d=+n,s):d},s.radius=function(t){return arguments.length?(n="function"==typeof t?t:o(+t),x(),s):n},s},n.forceLink=function(n){var t,r,e,i,u,a,c,l=h,d=function(n){return 1/Math.min(u[n.source.index],u[n.target.index])},y=o(30),s=1;function g(e){for(var u=0,o=n.length;u<s;++u)for(var l,h,v,d,y,g=0,x=0,z=0,p=0;g<o;++g)h=(l=n[g]).source,x=(v=l.target).x+v.vx-h.x-h.vx||f(c),i>1&&(z=v.y+v.vy-h.y-h.vy||f(c)),i>2&&(p=v.z+v.vz-h.z-h.vz||f(c)),x*=d=((d=Math.sqrt(x*x+z*z+p*p))-r[g])/d*e*t[g],z*=d,p*=d,v.vx-=x*(y=a[g]),i>1&&(v.vy-=z*y),i>2&&(v.vz-=p*y),h.vx+=x*(y=1-y),i>1&&(h.vy+=z*y),i>2&&(h.vz+=p*y)}function x(){if(e){var i,o,f=e.length,c=n.length,h=new Map(e.map(((n,t)=>[l(n,t,e),n])));for(i=0,u=new Array(f);i<c;++i)(o=n[i]).index=i,"object"!=typeof o.source&&(o.source=v(h,o.source)),"object"!=typeof o.target&&(o.target=v(h,o.target)),u[o.source.index]=(u[o.source.index]||0)+1,u[o.target.index]=(u[o.target.index]||0)+1;for(i=0,a=new Array(c);i<c;++i)o=n[i],a[i]=u[o.source.index]/(u[o.source.index]+u[o.target.index]);t=new Array(c),z(),r=new Array(c),p()}}function z(){if(e)for(var r=0,i=n.length;r<i;++r)t[r]=+d(n[r],r,n)}function p(){if(e)for(var t=0,i=n.length;t<i;++t)r[t]=+y(n[t],t,n)}return null==n&&(n=[]),g.initialize=function(n,...t){e=n,c=t.find((n=>"function"==typeof n))||Math.random,i=t.find((n=>[1,2,3].includes(n)))||2,x()},g.links=function(t){return arguments.length?(n=t,x(),g):n},g.id=function(n){return arguments.length?(l=n,g):l},g.iterations=function(n){return arguments.length?(s=+n,g):s},g.strength=function(n){return arguments.length?(d="function"==typeof n?n:o(+n),z(),g):d},g.distance=function(n){return arguments.length?(y="function"==typeof n?n:o(+n),p(),g):y},g},n.forceManyBody=function(){var n,i,u,a,c,l,h=o(-30),v=1,d=1/0,y=.81;function s(o){var f,a=n.length,l=(1===i?t.binarytree(n,x):2===i?r.quadtree(n,x,z):3===i?e.octree(n,x,z,p):null).visitAfter(M);for(c=o,f=0;f<a;++f)u=n[f],l.visit(w)}function g(){if(n){var t,r,e=n.length;for(l=new Array(e),t=0;t<e;++t)r=n[t],l[r.index]=+h(r,t,n)}}function M(n){var t,r,e,u,o,f,a=0,c=0,h=n.length;if(h){for(e=u=o=f=0;f<h;++f)(t=n[f])&&(r=Math.abs(t.value))&&(a+=t.value,c+=r,e+=r*(t.x||0),u+=r*(t.y||0),o+=r*(t.z||0));a*=Math.sqrt(4/h),n.x=e/c,i>1&&(n.y=u/c),i>2&&(n.z=o/c)}else{(t=n).x=t.data.x,i>1&&(t.y=t.data.y),i>2&&(t.z=t.data.z);do{a+=l[t.data.index]}while(t=t.next)}n.value=a}function w(n,t,r,e,o){if(!n.value)return!0;var h=[r,e,o][i-1],s=n.x-u.x,g=i>1?n.y-u.y:0,x=i>2?n.z-u.z:0,z=h-t,p=s*s+g*g+x*x;if(z*z/y<p)return p<d&&(0===s&&(p+=(s=f(a))*s),i>1&&0===g&&(p+=(g=f(a))*g),i>2&&0===x&&(p+=(x=f(a))*x),p<v&&(p=Math.sqrt(v*p)),u.vx+=s*n.value*c/p,i>1&&(u.vy+=g*n.value*c/p),i>2&&(u.vz+=x*n.value*c/p)),!0;if(!(n.length||p>=d)){(n.data!==u||n.next)&&(0===s&&(p+=(s=f(a))*s),i>1&&0===g&&(p+=(g=f(a))*g),i>2&&0===x&&(p+=(x=f(a))*x),p<v&&(p=Math.sqrt(v*p)));do{n.data!==u&&(z=l[n.data.index]*c/p,u.vx+=s*z,i>1&&(u.vy+=g*z),i>2&&(u.vz+=x*z))}while(n=n.next)}}return s.initialize=function(t,...r){n=t,a=r.find((n=>"function"==typeof n))||Math.random,i=r.find((n=>[1,2,3].includes(n)))||2,g()},s.strength=function(n){return arguments.length?(h="function"==typeof n?n:o(+n),g(),s):h},s.distanceMin=function(n){return arguments.length?(v=n*n,s):Math.sqrt(v)},s.distanceMax=function(n){return arguments.length?(d=n*n,s):Math.sqrt(d)},s.theta=function(n){return arguments.length?(y=n*n,s):Math.sqrt(y)},s},n.forceRadial=function(n,t,r,e){var i,u,f,a,c=o(.1);function l(n){for(var o=0,c=i.length;o<c;++o){var l=i[o],h=l.x-t||1e-6,v=(l.y||0)-r||1e-6,d=(l.z||0)-e||1e-6,y=Math.sqrt(h*h+v*v+d*d),s=(a[o]-y)*f[o]*n/y;l.vx+=h*s,u>1&&(l.vy+=v*s),u>2&&(l.vz+=d*s)}}function h(){if(i){var t,r=i.length;for(f=new Array(r),a=new Array(r),t=0;t<r;++t)a[t]=+n(i[t],t,i),f[t]=isNaN(a[t])?0:+c(i[t],t,i)}}return"function"!=typeof n&&(n=o(+n)),null==t&&(t=0),null==r&&(r=0),null==e&&(e=0),l.initialize=function(n,...t){i=n,u=t.find((n=>[1,2,3].includes(n)))||2,h()},l.strength=function(n){return arguments.length?(c="function"==typeof n?n:o(+n),h(),l):c},l.radius=function(t){return arguments.length?(n="function"==typeof t?t:o(+t),h(),l):n},l.x=function(n){return arguments.length?(t=+n,l):t},l.y=function(n){return arguments.length?(r=+n,l):r},l.z=function(n){return arguments.length?(e=+n,l):e},l},n.forceSimulation=function(n,t){t=t||2;var r,e=Math.min(g,Math.max(1,Math.round(t))),o=1,f=.001,a=1-Math.pow(f,1/300),c=0,l=.6,h=new Map,v=u.timer(p),x=i.dispatch("tick","end"),z=function(){let n=1;return()=>(n=(d*n+y)%s)/s}();function p(){N(),x.call("tick",r),o<f&&(v.stop(),x.call("end",r))}function N(t){var i,u,f=n.length;void 0===t&&(t=1);for(var v=0;v<t;++v)for(o+=(c-o)*a,h.forEach((function(n){n(o)})),i=0;i<f;++i)null==(u=n[i]).fx?u.x+=u.vx*=l:(u.x=u.fx,u.vx=0),e>1&&(null==u.fy?u.y+=u.vy*=l:(u.y=u.fy,u.vy=0)),e>2&&(null==u.fz?u.z+=u.vz*=l:(u.z=u.fz,u.vz=0));return r}function m(){for(var t,r=0,i=n.length;r<i;++r){if((t=n[r]).index=r,null!=t.fx&&(t.x=t.fx),null!=t.fy&&(t.y=t.fy),null!=t.fz&&(t.z=t.fz),isNaN(t.x)||e>1&&isNaN(t.y)||e>2&&isNaN(t.z)){var u=M*(e>2?Math.cbrt(.5+r):e>1?Math.sqrt(.5+r):r),o=r*w,f=r*q;1===e?t.x=u:2===e?(t.x=u*Math.cos(o),t.y=u*Math.sin(o)):(t.x=u*Math.sin(o)*Math.cos(f),t.y=u*Math.cos(o),t.z=u*Math.sin(o)*Math.sin(f))}(isNaN(t.vx)||e>1&&isNaN(t.vy)||e>2&&isNaN(t.vz))&&(t.vx=0,e>1&&(t.vy=0),e>2&&(t.vz=0))}}function A(t){return t.initialize&&t.initialize(n,z,e),t}return null==n&&(n=[]),m(),r={tick:N,restart:function(){return v.restart(p),r},stop:function(){return v.stop(),r},numDimensions:function(n){return arguments.length?(e=Math.min(g,Math.max(1,Math.round(n))),h.forEach(A),r):e},nodes:function(t){return arguments.length?(n=t,m(),h.forEach(A),r):n},alpha:function(n){return arguments.length?(o=+n,r):o},alphaMin:function(n){return arguments.length?(f=+n,r):f},alphaDecay:function(n){return arguments.length?(a=+n,r):+a},alphaTarget:function(n){return arguments.length?(c=+n,r):c},velocityDecay:function(n){return arguments.length?(l=1-n,r):1-l},randomSource:function(n){return arguments.length?(z=n,h.forEach(A),r):z},force:function(n,t){return arguments.length>1?(null==t?h.delete(n):h.set(n,A(t)),r):h.get(n)},find:function(){var t,r,i,u,o,f,a=Array.prototype.slice.call(arguments),c=a.shift()||0,l=(e>1?a.shift():null)||0,h=(e>2?a.shift():null)||0,v=a.shift()||1/0,d=0,y=n.length;for(v*=v,d=0;d<y;++d)(u=(t=c-(o=n[d]).x)*t+(r=l-(o.y||0))*r+(i=h-(o.z||0))*i)<v&&(f=o,v=u);return f},on:function(n,t){return arguments.length>1?(x.on(n,t),r):x.on(n)}}},n.forceX=function(n){var t,r,e,i=o(.1);function u(n){for(var i,u=0,o=t.length;u<o;++u)(i=t[u]).vx+=(e[u]-i.x)*r[u]*n}function f(){if(t){var u,o=t.length;for(r=new Array(o),e=new Array(o),u=0;u<o;++u)r[u]=isNaN(e[u]=+n(t[u],u,t))?0:+i(t[u],u,t)}}return"function"!=typeof n&&(n=o(null==n?0:+n)),u.initialize=function(n){t=n,f()},u.strength=function(n){return arguments.length?(i="function"==typeof n?n:o(+n),f(),u):i},u.x=function(t){return arguments.length?(n="function"==typeof t?t:o(+t),f(),u):n},u},n.forceY=function(n){var t,r,e,i=o(.1);function u(n){for(var i,u=0,o=t.length;u<o;++u)(i=t[u]).vy+=(e[u]-i.y)*r[u]*n}function f(){if(t){var u,o=t.length;for(r=new Array(o),e=new Array(o),u=0;u<o;++u)r[u]=isNaN(e[u]=+n(t[u],u,t))?0:+i(t[u],u,t)}}return"function"!=typeof n&&(n=o(null==n?0:+n)),u.initialize=function(n){t=n,f()},u.strength=function(n){return arguments.length?(i="function"==typeof n?n:o(+n),f(),u):i},u.y=function(t){return arguments.length?(n="function"==typeof t?t:o(+t),f(),u):n},u},n.forceZ=function(n){var t,r,e,i=o(.1);function u(n){for(var i,u=0,o=t.length;u<o;++u)(i=t[u]).vz+=(e[u]-i.z)*r[u]*n}function f(){if(t){var u,o=t.length;for(r=new Array(o),e=new Array(o),u=0;u<o;++u)r[u]=isNaN(e[u]=+n(t[u],u,t))?0:+i(t[u],u,t)}}return"function"!=typeof n&&(n=o(null==n?0:+n)),u.initialize=function(n){t=n,f()},u.strength=function(n){return arguments.length?(i="function"==typeof n?n:o(+n),f(),u):i},u.z=function(t){return arguments.length?(n="function"==typeof t?t:o(+t),f(),u):n},u}}));
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
// https://github.com/vasturiano/d3-octree v1.1.0
|
|
2
|
+
!function(t,i){"object"==typeof exports&&"undefined"!=typeof module?i(exports):"function"==typeof define&&define.amd?define(["exports"],i):i((t="undefined"!=typeof globalThis?globalThis:t||self).d3=t.d3||{})}(this,(function(t){"use strict";function i(t,i,n,s,e){if(isNaN(i)||isNaN(n)||isNaN(s))return t;var h,r,o,a,l,u,_,f,c,y,x,d,p=t._root,w={data:e},z=t._x0,N=t._y0,v=t._z0,g=t._x1,A=t._y1,b=t._z1;if(!p)return t._root=w,t;for(;p.length;)if((f=i>=(r=(z+g)/2))?z=r:g=r,(c=n>=(o=(N+A)/2))?N=o:A=o,(y=s>=(a=(v+b)/2))?v=a:b=a,h=p,!(p=p[x=y<<2|c<<1|f]))return h[x]=w,t;if(l=+t._x.call(null,p.data),u=+t._y.call(null,p.data),_=+t._z.call(null,p.data),i===l&&n===u&&s===_)return w.next=p,h?h[x]=w:t._root=w,t;do{h=h?h[x]=new Array(8):t._root=new Array(8),(f=i>=(r=(z+g)/2))?z=r:g=r,(c=n>=(o=(N+A)/2))?N=o:A=o,(y=s>=(a=(v+b)/2))?v=a:b=a}while((x=y<<2|c<<1|f)==(d=(_>=a)<<2|(u>=o)<<1|l>=r));return h[d]=p,h[x]=w,t}function n(t,i,n,s,e,h,r){this.node=t,this.x0=i,this.y0=n,this.z0=s,this.x1=e,this.y1=h,this.z1=r}const s=(t,i,n,s,e,h)=>Math.sqrt((t-s)**2+(i-e)**2+(n-h)**2);function e(t){return t[0]}function h(t){return t[1]}function r(t){return t[2]}function o(t,i,n,s){var o=new a(null==i?e:i,null==n?h:n,null==s?r:s,NaN,NaN,NaN,NaN,NaN,NaN);return null==t?o:o.addAll(t)}function a(t,i,n,s,e,h,r,o,a){this._x=t,this._y=i,this._z=n,this._x0=s,this._y0=e,this._z0=h,this._x1=r,this._y1=o,this._z1=a,this._root=void 0}function l(t){for(var i={data:t.data},n=i;t=t.next;)n=n.next={data:t.data};return i}var u=o.prototype=a.prototype;u.copy=function(){var t,i,n=new a(this._x,this._y,this._z,this._x0,this._y0,this._z0,this._x1,this._y1,this._z1),s=this._root;if(!s)return n;if(!s.length)return n._root=l(s),n;for(t=[{source:s,target:n._root=new Array(8)}];s=t.pop();)for(var e=0;e<8;++e)(i=s.source[e])&&(i.length?t.push({source:i,target:s.target[e]=new Array(8)}):s.target[e]=l(i));return n},u.add=function(t){const n=+this._x.call(null,t),s=+this._y.call(null,t),e=+this._z.call(null,t);return i(this.cover(n,s,e),n,s,e,t)},u.addAll=function(t){Array.isArray(t)||(t=Array.from(t));const n=t.length,s=new Float64Array(n),e=new Float64Array(n),h=new Float64Array(n);let r=1/0,o=1/0,a=1/0,l=-1/0,u=-1/0,_=-1/0;for(let i,f,c,y,x=0;x<n;++x)isNaN(f=+this._x.call(null,i=t[x]))||isNaN(c=+this._y.call(null,i))||isNaN(y=+this._z.call(null,i))||(s[x]=f,e[x]=c,h[x]=y,f<r&&(r=f),f>l&&(l=f),c<o&&(o=c),c>u&&(u=c),y<a&&(a=y),y>_&&(_=y));if(r>l||o>u||a>_)return this;this.cover(r,o,a).cover(l,u,_);for(let r=0;r<n;++r)i(this,s[r],e[r],h[r],t[r]);return this},u.cover=function(t,i,n){if(isNaN(t=+t)||isNaN(i=+i)||isNaN(n=+n))return this;var s=this._x0,e=this._y0,h=this._z0,r=this._x1,o=this._y1,a=this._z1;if(isNaN(s))r=(s=Math.floor(t))+1,o=(e=Math.floor(i))+1,a=(h=Math.floor(n))+1;else{for(var l,u,_=r-s||1,f=this._root;s>t||t>=r||e>i||i>=o||h>n||n>=a;)switch(u=(n<h)<<2|(i<e)<<1|t<s,(l=new Array(8))[u]=f,f=l,_*=2,u){case 0:r=s+_,o=e+_,a=h+_;break;case 1:s=r-_,o=e+_,a=h+_;break;case 2:r=s+_,e=o-_,a=h+_;break;case 3:s=r-_,e=o-_,a=h+_;break;case 4:r=s+_,o=e+_,h=a-_;break;case 5:s=r-_,o=e+_,h=a-_;break;case 6:r=s+_,e=o-_,h=a-_;break;case 7:s=r-_,e=o-_,h=a-_}this._root&&this._root.length&&(this._root=f)}return this._x0=s,this._y0=e,this._z0=h,this._x1=r,this._y1=o,this._z1=a,this},u.data=function(){var t=[];return this.visit((function(i){if(!i.length)do{t.push(i.data)}while(i=i.next)})),t},u.extent=function(t){return arguments.length?this.cover(+t[0][0],+t[0][1],+t[0][2]).cover(+t[1][0],+t[1][1],+t[1][2]):isNaN(this._x0)?void 0:[[this._x0,this._y0,this._z0],[this._x1,this._y1,this._z1]]},u.find=function(t,i,s,e){var h,r,o,a,l,u,_,f,c,y=this._x0,x=this._y0,d=this._z0,p=this._x1,w=this._y1,z=this._z1,N=[],v=this._root;for(v&&N.push(new n(v,y,x,d,p,w,z)),null==e?e=1/0:(y=t-e,x=i-e,d=s-e,p=t+e,w=i+e,z=s+e,e*=e);f=N.pop();)if(!(!(v=f.node)||(r=f.x0)>p||(o=f.y0)>w||(a=f.z0)>z||(l=f.x1)<y||(u=f.y1)<x||(_=f.z1)<d))if(v.length){var g=(r+l)/2,A=(o+u)/2,b=(a+_)/2;N.push(new n(v[7],g,A,b,l,u,_),new n(v[6],r,A,b,g,u,_),new n(v[5],g,o,b,l,A,_),new n(v[4],r,o,b,g,A,_),new n(v[3],g,A,a,l,u,b),new n(v[2],r,A,a,g,u,b),new n(v[1],g,o,a,l,A,b),new n(v[0],r,o,a,g,A,b)),(c=(s>=b)<<2|(i>=A)<<1|t>=g)&&(f=N[N.length-1],N[N.length-1]=N[N.length-1-c],N[N.length-1-c]=f)}else{var k=t-+this._x.call(null,v.data),m=i-+this._y.call(null,v.data),M=s-+this._z.call(null,v.data),F=k*k+m*m+M*M;if(F<e){var q=Math.sqrt(e=F);y=t-q,x=i-q,d=s-q,p=t+q,w=i+q,z=s+q,h=v.data}}return h},u.findAllWithinRadius=function(t,i,n,e){const h=[],r=t-e,o=i-e,a=n-e,l=t+e,u=i+e,_=n+e;return this.visit(((f,c,y,x,d,p,w)=>{if(!f.length)do{const r=f.data;s(t,i,n,this._x(r),this._y(r),this._z(r))<=e&&h.push(r)}while(f=f.next);return c>l||y>u||x>_||d<r||p<o||w<a})),h},u.remove=function(t){if(isNaN(h=+this._x.call(null,t))||isNaN(r=+this._y.call(null,t))||isNaN(o=+this._z.call(null,t)))return this;var i,n,s,e,h,r,o,a,l,u,_,f,c,y,x,d=this._root,p=this._x0,w=this._y0,z=this._z0,N=this._x1,v=this._y1,g=this._z1;if(!d)return this;if(d.length)for(;;){if((_=h>=(a=(p+N)/2))?p=a:N=a,(f=r>=(l=(w+v)/2))?w=l:v=l,(c=o>=(u=(z+g)/2))?z=u:g=u,i=d,!(d=d[y=c<<2|f<<1|_]))return this;if(!d.length)break;(i[y+1&7]||i[y+2&7]||i[y+3&7]||i[y+4&7]||i[y+5&7]||i[y+6&7]||i[y+7&7])&&(n=i,x=y)}for(;d.data!==t;)if(s=d,!(d=d.next))return this;return(e=d.next)&&delete d.next,s?(e?s.next=e:delete s.next,this):i?(e?i[y]=e:delete i[y],(d=i[0]||i[1]||i[2]||i[3]||i[4]||i[5]||i[6]||i[7])&&d===(i[7]||i[6]||i[5]||i[4]||i[3]||i[2]||i[1]||i[0])&&!d.length&&(n?n[x]=d:this._root=d),this):(this._root=e,this)},u.removeAll=function(t){for(var i=0,n=t.length;i<n;++i)this.remove(t[i]);return this},u.root=function(){return this._root},u.size=function(){var t=0;return this.visit((function(i){if(!i.length)do{++t}while(i=i.next)})),t},u.visit=function(t){var i,s,e,h,r,o,a,l,u=[],_=this._root;for(_&&u.push(new n(_,this._x0,this._y0,this._z0,this._x1,this._y1,this._z1));i=u.pop();)if(!t(_=i.node,e=i.x0,h=i.y0,r=i.z0,o=i.x1,a=i.y1,l=i.z1)&&_.length){var f=(e+o)/2,c=(h+a)/2,y=(r+l)/2;(s=_[7])&&u.push(new n(s,f,c,y,o,a,l)),(s=_[6])&&u.push(new n(s,e,c,y,f,a,l)),(s=_[5])&&u.push(new n(s,f,h,y,o,c,l)),(s=_[4])&&u.push(new n(s,e,h,y,f,c,l)),(s=_[3])&&u.push(new n(s,f,c,r,o,a,y)),(s=_[2])&&u.push(new n(s,e,c,r,f,a,y)),(s=_[1])&&u.push(new n(s,f,h,r,o,c,y)),(s=_[0])&&u.push(new n(s,e,h,r,f,c,y))}return this},u.visitAfter=function(t){var i,s=[],e=[];for(this._root&&s.push(new n(this._root,this._x0,this._y0,this._z0,this._x1,this._y1,this._z1));i=s.pop();){var h=i.node;if(h.length){var r,o=i.x0,a=i.y0,l=i.z0,u=i.x1,_=i.y1,f=i.z1,c=(o+u)/2,y=(a+_)/2,x=(l+f)/2;(r=h[0])&&s.push(new n(r,o,a,l,c,y,x)),(r=h[1])&&s.push(new n(r,c,a,l,u,y,x)),(r=h[2])&&s.push(new n(r,o,y,l,c,_,x)),(r=h[3])&&s.push(new n(r,c,y,l,u,_,x)),(r=h[4])&&s.push(new n(r,o,a,x,c,y,f)),(r=h[5])&&s.push(new n(r,c,a,x,u,y,f)),(r=h[6])&&s.push(new n(r,o,y,x,c,_,f)),(r=h[7])&&s.push(new n(r,c,y,x,u,_,f))}e.push(i)}for(;i=e.pop();)t(i.node,i.x0,i.y0,i.z0,i.x1,i.y1,i.z1);return this},u.x=function(t){return arguments.length?(this._x=t,this):this._x},u.y=function(t){return arguments.length?(this._y=t,this):this._y},u.z=function(t){return arguments.length?(this._z=t,this):this._z},t.octree=o}));
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
// https://d3js.org/d3-quadtree/ v3.0.1 Copyright 2010-2021 Mike Bostock
|
|
2
|
+
!function(t,i){"object"==typeof exports&&"undefined"!=typeof module?i(exports):"function"==typeof define&&define.amd?define(["exports"],i):i((t="undefined"!=typeof globalThis?globalThis:t||self).d3=t.d3||{})}(this,(function(t){"use strict";function i(t,i,e,n){if(isNaN(i)||isNaN(e))return t;var r,s,h,o,a,u,l,_,f,c=t._root,x={data:n},y=t._x0,d=t._y0,p=t._x1,v=t._y1;if(!c)return t._root=x,t;for(;c.length;)if((u=i>=(s=(y+p)/2))?y=s:p=s,(l=e>=(h=(d+v)/2))?d=h:v=h,r=c,!(c=c[_=l<<1|u]))return r[_]=x,t;if(o=+t._x.call(null,c.data),a=+t._y.call(null,c.data),i===o&&e===a)return x.next=c,r?r[_]=x:t._root=x,t;do{r=r?r[_]=new Array(4):t._root=new Array(4),(u=i>=(s=(y+p)/2))?y=s:p=s,(l=e>=(h=(d+v)/2))?d=h:v=h}while((_=l<<1|u)==(f=(a>=h)<<1|o>=s));return r[f]=c,r[_]=x,t}function e(t,i,e,n,r){this.node=t,this.x0=i,this.y0=e,this.x1=n,this.y1=r}function n(t){return t[0]}function r(t){return t[1]}function s(t,i,e){var s=new h(null==i?n:i,null==e?r:e,NaN,NaN,NaN,NaN);return null==t?s:s.addAll(t)}function h(t,i,e,n,r,s){this._x=t,this._y=i,this._x0=e,this._y0=n,this._x1=r,this._y1=s,this._root=void 0}function o(t){for(var i={data:t.data},e=i;t=t.next;)e=e.next={data:t.data};return i}var a=s.prototype=h.prototype;a.copy=function(){var t,i,e=new h(this._x,this._y,this._x0,this._y0,this._x1,this._y1),n=this._root;if(!n)return e;if(!n.length)return e._root=o(n),e;for(t=[{source:n,target:e._root=new Array(4)}];n=t.pop();)for(var r=0;r<4;++r)(i=n.source[r])&&(i.length?t.push({source:i,target:n.target[r]=new Array(4)}):n.target[r]=o(i));return e},a.add=function(t){const e=+this._x.call(null,t),n=+this._y.call(null,t);return i(this.cover(e,n),e,n,t)},a.addAll=function(t){var e,n,r,s,h=t.length,o=new Array(h),a=new Array(h),u=1/0,l=1/0,_=-1/0,f=-1/0;for(n=0;n<h;++n)isNaN(r=+this._x.call(null,e=t[n]))||isNaN(s=+this._y.call(null,e))||(o[n]=r,a[n]=s,r<u&&(u=r),r>_&&(_=r),s<l&&(l=s),s>f&&(f=s));if(u>_||l>f)return this;for(this.cover(u,l).cover(_,f),n=0;n<h;++n)i(this,o[n],a[n],t[n]);return this},a.cover=function(t,i){if(isNaN(t=+t)||isNaN(i=+i))return this;var e=this._x0,n=this._y0,r=this._x1,s=this._y1;if(isNaN(e))r=(e=Math.floor(t))+1,s=(n=Math.floor(i))+1;else{for(var h,o,a=r-e||1,u=this._root;e>t||t>=r||n>i||i>=s;)switch(o=(i<n)<<1|t<e,(h=new Array(4))[o]=u,u=h,a*=2,o){case 0:r=e+a,s=n+a;break;case 1:e=r-a,s=n+a;break;case 2:r=e+a,n=s-a;break;case 3:e=r-a,n=s-a}this._root&&this._root.length&&(this._root=u)}return this._x0=e,this._y0=n,this._x1=r,this._y1=s,this},a.data=function(){var t=[];return this.visit((function(i){if(!i.length)do{t.push(i.data)}while(i=i.next)})),t},a.extent=function(t){return arguments.length?this.cover(+t[0][0],+t[0][1]).cover(+t[1][0],+t[1][1]):isNaN(this._x0)?void 0:[[this._x0,this._y0],[this._x1,this._y1]]},a.find=function(t,i,n){var r,s,h,o,a,u,l,_=this._x0,f=this._y0,c=this._x1,x=this._y1,y=[],d=this._root;for(d&&y.push(new e(d,_,f,c,x)),null==n?n=1/0:(_=t-n,f=i-n,c=t+n,x=i+n,n*=n);u=y.pop();)if(!(!(d=u.node)||(s=u.x0)>c||(h=u.y0)>x||(o=u.x1)<_||(a=u.y1)<f))if(d.length){var p=(s+o)/2,v=(h+a)/2;y.push(new e(d[3],p,v,o,a),new e(d[2],s,v,p,a),new e(d[1],p,h,o,v),new e(d[0],s,h,p,v)),(l=(i>=v)<<1|t>=p)&&(u=y[y.length-1],y[y.length-1]=y[y.length-1-l],y[y.length-1-l]=u)}else{var w=t-+this._x.call(null,d.data),N=i-+this._y.call(null,d.data),g=w*w+N*N;if(g<n){var A=Math.sqrt(n=g);_=t-A,f=i-A,c=t+A,x=i+A,r=d.data}}return r},a.remove=function(t){if(isNaN(s=+this._x.call(null,t))||isNaN(h=+this._y.call(null,t)))return this;var i,e,n,r,s,h,o,a,u,l,_,f,c=this._root,x=this._x0,y=this._y0,d=this._x1,p=this._y1;if(!c)return this;if(c.length)for(;;){if((u=s>=(o=(x+d)/2))?x=o:d=o,(l=h>=(a=(y+p)/2))?y=a:p=a,i=c,!(c=c[_=l<<1|u]))return this;if(!c.length)break;(i[_+1&3]||i[_+2&3]||i[_+3&3])&&(e=i,f=_)}for(;c.data!==t;)if(n=c,!(c=c.next))return this;return(r=c.next)&&delete c.next,n?(r?n.next=r:delete n.next,this):i?(r?i[_]=r:delete i[_],(c=i[0]||i[1]||i[2]||i[3])&&c===(i[3]||i[2]||i[1]||i[0])&&!c.length&&(e?e[f]=c:this._root=c),this):(this._root=r,this)},a.removeAll=function(t){for(var i=0,e=t.length;i<e;++i)this.remove(t[i]);return this},a.root=function(){return this._root},a.size=function(){var t=0;return this.visit((function(i){if(!i.length)do{++t}while(i=i.next)})),t},a.visit=function(t){var i,n,r,s,h,o,a=[],u=this._root;for(u&&a.push(new e(u,this._x0,this._y0,this._x1,this._y1));i=a.pop();)if(!t(u=i.node,r=i.x0,s=i.y0,h=i.x1,o=i.y1)&&u.length){var l=(r+h)/2,_=(s+o)/2;(n=u[3])&&a.push(new e(n,l,_,h,o)),(n=u[2])&&a.push(new e(n,r,_,l,o)),(n=u[1])&&a.push(new e(n,l,s,h,_)),(n=u[0])&&a.push(new e(n,r,s,l,_))}return this},a.visitAfter=function(t){var i,n=[],r=[];for(this._root&&n.push(new e(this._root,this._x0,this._y0,this._x1,this._y1));i=n.pop();){var s=i.node;if(s.length){var h,o=i.x0,a=i.y0,u=i.x1,l=i.y1,_=(o+u)/2,f=(a+l)/2;(h=s[0])&&n.push(new e(h,o,a,_,f)),(h=s[1])&&n.push(new e(h,_,a,u,f)),(h=s[2])&&n.push(new e(h,o,f,_,l)),(h=s[3])&&n.push(new e(h,_,f,u,l))}r.push(i)}for(;i=r.pop();)t(i.node,i.x0,i.y0,i.x1,i.y1);return this},a.x=function(t){return arguments.length?(this._x=t,this):this._x},a.y=function(t){return arguments.length?(this._y=t,this):this._y},t.quadtree=s,Object.defineProperty(t,"__esModule",{value:!0})}));
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
// https://d3js.org/d3-timer/ v3.0.1 Copyright 2010-2021 Mike Bostock
|
|
2
|
+
!function(t,n){"object"==typeof exports&&"undefined"!=typeof module?n(exports):"function"==typeof define&&define.amd?define(["exports"],n):n((t="undefined"!=typeof globalThis?globalThis:t||self).d3=t.d3||{})}(this,(function(t){"use strict";var n,e,o=0,i=0,r=0,l=0,u=0,a=0,s="object"==typeof performance&&performance.now?performance:Date,c="object"==typeof window&&window.requestAnimationFrame?window.requestAnimationFrame.bind(window):function(t){setTimeout(t,17)};function f(){return u||(c(_),u=s.now()+a)}function _(){u=0}function m(){this._call=this._time=this._next=null}function p(t,n,e){var o=new m;return o.restart(t,n,e),o}function w(){f(),++o;for(var t,e=n;e;)(t=u-e._time)>=0&&e._call.call(void 0,t),e=e._next;--o}function d(){u=(l=s.now())+a,o=i=0;try{w()}finally{o=0,function(){var t,o,i=n,r=1/0;for(;i;)i._call?(r>i._time&&(r=i._time),t=i,i=i._next):(o=i._next,i._next=null,i=t?t._next=o:n=o);e=t,y(r)}(),u=0}}function h(){var t=s.now(),n=t-l;n>1e3&&(a-=n,l=t)}function y(t){o||(i&&(i=clearTimeout(i)),t-u>24?(t<1/0&&(i=setTimeout(d,t-s.now()-a)),r&&(r=clearInterval(r))):(r||(l=s.now(),r=setInterval(h,1e3)),o=1,c(d)))}m.prototype=p.prototype={constructor:m,restart:function(t,o,i){if("function"!=typeof t)throw new TypeError("callback is not a function");i=(null==i?f():+i)+(null==o?0:+o),this._next||e===this||(e?e._next=this:n=this,e=this),this._call=t,this._time=i,y()},stop:function(){this._call&&(this._call=null,this._time=1/0,y())}},t.interval=function(t,n,e){var o=new m,i=n;return null==n?(o.restart(t,n,e),o):(o._restart=o.restart,o.restart=function(t,n,e){n=+n,e=null==e?f():+e,o._restart((function r(l){l+=i,o._restart(r,i+=n,e),t(l)}),n,e)},o.restart(t,n,e),o)},t.now=f,t.timeout=function(t,n,e){var o=new m;return n=null==n?0:+n,o.restart((e=>{o.stop(),t(e+n)}),n,e),o},t.timer=p,t.timerFlush=w,Object.defineProperty(t,"__esModule",{value:!0})}));
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
// 在 Node 里把 3D 布局算好,坐标交给 scripts/graph_3d.py 内联进页面。
|
|
2
|
+
//
|
|
3
|
+
// 为什么不在浏览器里算:25,431 个点跑 90 tick 实测要 **15.9 秒**,每次打开页面都要等一遍。
|
|
4
|
+
// 布局只跟图有关、跟窗口无关,所以算一次存下来最合适 —— 打开即用。
|
|
5
|
+
//
|
|
6
|
+
// 这里不装 npm 包:d3-force-3d 的 UMD 就是浏览器分支(挂 globalThis.d3),
|
|
7
|
+
// 用 new Function 跑一遍就得到同一个 d3,省掉 node_modules。
|
|
8
|
+
//
|
|
9
|
+
// 用法:node layout.mjs <缓存目录> <库目录> [tick] [digest] [dims]
|
|
10
|
+
//
|
|
11
|
+
// `dims=2` 走 2D 力导向(`forceCenter(0,0)`):**不是把 3D 的 x/y 拍扁** —— 那一维也承载结构,
|
|
12
|
+
// 拍扁会把两团本不相干的点叠在一起。2D 的解也更省(快的不是一个量级),所以同一张图重算得起。
|
|
13
|
+
//
|
|
14
|
+
// **路径一律走参数**:这个文件原来住在 output/_3d/ 里,并且写死了某台机器的绝对路径。
|
|
15
|
+
// 搬进仓库时一并改掉 —— 仓库里的代码不许出现用户的真实路径。
|
|
16
|
+
import { readFileSync, writeFileSync } from 'node:fs'
|
|
17
|
+
|
|
18
|
+
const [cacheDir, libDir, ticksArg, digest, dimsArg, paramsArg] = process.argv.slice(2)
|
|
19
|
+
if (!cacheDir || !libDir) {
|
|
20
|
+
console.error('用法:node layout.mjs <缓存目录> <库目录> [tick] [digest] [dims] [params-json]')
|
|
21
|
+
process.exit(2)
|
|
22
|
+
}
|
|
23
|
+
const DIMS = Number(dimsArg || 3) === 2 ? 2 : 3
|
|
24
|
+
// digest 是图内容的哈希(含维度):核心图与全量图、2D 与 3D 各存一份坐标
|
|
25
|
+
// (见 graph_3d.py / graph_2d.py 里那段注释)
|
|
26
|
+
const suffix = digest ? `-${digest}` : ''
|
|
27
|
+
const IN = `${cacheDir}/graph${suffix}.json`
|
|
28
|
+
const OUT = `${cacheDir}/positions${suffix}.json`
|
|
29
|
+
const TICKS = Number(ticksArg || 250)
|
|
30
|
+
|
|
31
|
+
const LIBS = ['d3-dispatch.min.js', 'd3-timer.min.js', 'd3-quadtree.min.js',
|
|
32
|
+
'd3-binarytree.min.js', 'd3-octree.min.js', 'd3-force-3d.min.js']
|
|
33
|
+
const code = LIBS.map((f) => readFileSync(`${libDir}/${f}`, 'utf8')).join('\n')
|
|
34
|
+
new Function(code)()
|
|
35
|
+
const d3 = globalThis.d3
|
|
36
|
+
if (!d3?.forceSimulation) {
|
|
37
|
+
console.error('d3 没挂上 globalThis,检查 UMD 列表')
|
|
38
|
+
process.exit(1)
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const { nodes, links } = JSON.parse(readFileSync(IN, 'utf8'))
|
|
42
|
+
const L = links.map(([source, target]) => ({ source, target }))
|
|
43
|
+
// 力参数**由调用方给**(graph_3d.py 的 LAYOUT_PARAMS),这里只照做:参数放两处迟早会分叉,
|
|
44
|
+
// 而它们还得计入缓存 key(改了参数却读到旧坐标,这个坑踩过一次)。
|
|
45
|
+
const P = paramsArg ? JSON.parse(paramsArg) : { charge: -22, chargeMax: 600, linkDist: 22, linkStrength: 0.6 }
|
|
46
|
+
const sim = d3.forceSimulation(nodes, DIMS)
|
|
47
|
+
.force('charge', d3.forceManyBody().strength(P.charge).distanceMax(P.chargeMax).theta(1.1))
|
|
48
|
+
.force('link', d3.forceLink(L).id((d) => d.id).distance(P.linkDist).strength(P.linkStrength))
|
|
49
|
+
.force('center', DIMS === 2 ? d3.forceCenter(0, 0) : d3.forceCenter(0, 0, 0))
|
|
50
|
+
.stop()
|
|
51
|
+
|
|
52
|
+
const t0 = Date.now()
|
|
53
|
+
for (let i = 0; i < TICKS; i += 1) sim.tick()
|
|
54
|
+
const ms = Date.now() - t0
|
|
55
|
+
|
|
56
|
+
// 整数就够:整团云上千单位宽,1 个单位的误差在屏幕上肉眼不可见,但能省一半体积
|
|
57
|
+
const coords = (n) => (DIMS === 2
|
|
58
|
+
? `${Math.round(n.x)},${Math.round(n.y)}`
|
|
59
|
+
: `${Math.round(n.x)},${Math.round(n.y)},${Math.round(n.z)}`)
|
|
60
|
+
const flat = nodes.map(coords).join(',')
|
|
61
|
+
writeFileSync(OUT, flat)
|
|
62
|
+
console.log(`布局 ${nodes.length} 点 / ${L.length} 边,${TICKS} tick 用时 ${(ms / 1000).toFixed(1)} s`)
|
|
63
|
+
console.log(`${OUT} ${(flat.length / 1048576).toFixed(2)} MB`)
|