dsh-memory-eternal 0.2.3 → 0.2.5
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/README.md +15 -9
- package/lib/capture.js +3 -3
- package/lib/client.js +2 -2
- package/lib/vault.js +5 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -42,7 +42,7 @@
|
|
|
42
42
|
| 🕸 **知识图谱** | 卡片间的 `[[wikilink]]` 与共享标签自动连线,SVG 图谱左键凸显关联、右键打开卡片阅读 |
|
|
43
43
|
| 🧠 **自动召回** | 注入 system prompt 告知 Agent 它拥有记忆核心,并注册 `memory_recall` 工具——需要项目背景/历史决策/领域知识时自动检索 |
|
|
44
44
|
| 🔒 **本地优先** | 所有内容留在你的本机 Vault;不设遥测、不传云端。模型请求仍走你已配置好的 provider |
|
|
45
|
-
| ⚙️ **一键安装** | 与 `dsh-ui-three-body` 同款插件机制,`
|
|
45
|
+
| ⚙️ **一键安装** | 与 `dsh-ui-three-body` 同款插件机制,`dsh plugin --profile web add dsh-memory-eternal` 即可 |
|
|
46
46
|
|
|
47
47
|
**适合**:想要让 DSH 记住项目背景与历史决策的人 / 想给对话沉淀可检索知识库的人 / Obsidian 式 Markdown Vault 爱好者 / 在意数据归属(本地文件 > 云端数据库)的人。
|
|
48
48
|
|
|
@@ -52,15 +52,17 @@
|
|
|
52
52
|
|
|
53
53
|
```bash
|
|
54
54
|
# 已发布后(npm)
|
|
55
|
-
|
|
55
|
+
dsh plugin --profile web add dsh-memory-eternal
|
|
56
56
|
|
|
57
57
|
# 从 GitHub
|
|
58
|
-
|
|
58
|
+
dsh plugin --profile web add github:EternalNight996/dsh-memory-eternal
|
|
59
59
|
|
|
60
60
|
# 本地联调(link 本地目录,改代码即时生效)
|
|
61
|
-
|
|
61
|
+
dsh plugin --profile web add F:/MyApp/eternal/dsh-memory-eternal
|
|
62
62
|
```
|
|
63
63
|
|
|
64
|
+
> 未全局安装 `dsh` 时,可改用 `npx @deepseek-ai/dsh plugin --profile web add dsh-memory-eternal`。
|
|
65
|
+
|
|
64
66
|
装完**重启 dsh web**:设置 → 记忆 出现知识库页面;侧边栏底部也会出现「记忆」按钮,一键打开完整记忆库弹窗。此后每轮对话自动沉淀知识卡。
|
|
65
67
|
|
|
66
68
|
---
|
|
@@ -81,7 +83,7 @@ LLM 判定(值得保存?)──否──► 丢弃
|
|
|
81
83
|
▼
|
|
82
84
|
语义去重(喂给模型已有卡片索引)
|
|
83
85
|
├─ 同一主题 ──► append_to:追加「更新记录」到已有卡(不建重复卡)
|
|
84
|
-
└─ 新主题 ────► 写新知识卡到 02-
|
|
86
|
+
└─ 新主题 ────► 写新知识卡到 02-08 对应目录
|
|
85
87
|
```
|
|
86
88
|
|
|
87
89
|
知识卡格式(frontmatter + markdown 正文):
|
|
@@ -110,7 +112,9 @@ Vault 目录结构:
|
|
|
110
112
|
├── 03-Knowledge/ # 通用知识 / 技术方案 / 设计决策(默认)
|
|
111
113
|
├── 04-Content/ # 内容素材 / 资料
|
|
112
114
|
├── 05-Prompts/ # 提示词 / 工作流
|
|
113
|
-
|
|
115
|
+
├── 06-Business/ # 业务 / 商业
|
|
116
|
+
├── 07-Tools/ # 工具链 / CLI / 配置 / 环境坑
|
|
117
|
+
└── 08-Mistakes/ # 教训:错误 / 反模式 / 踩坑 /「别这么做」
|
|
114
118
|
```
|
|
115
119
|
|
|
116
120
|
## 🕸 图形化知识库(设置 → 记忆 + 侧边栏「记忆」入口)
|
|
@@ -118,7 +122,7 @@ Vault 目录结构:
|
|
|
118
122
|
- **双入口**:设置 → 记忆 页 + 侧边栏底部「记忆」按钮(一键打开完整记忆库弹窗)
|
|
119
123
|
- **统计概览**:总卡数、近 7 天新增、标签数、知识卡数
|
|
120
124
|
- **检索**:中文片段即时搜索(280ms 防抖)
|
|
121
|
-
- **知识卡网格**:kind
|
|
125
|
+
- **知识卡网格**:kind 筛选(全部/项目/知识/内容/提示词/业务/工具/教训),点击卡片阅读全文(frontmatter 一并展示)
|
|
122
126
|
- **知识图谱(增强版)**:力导向有机布局(大规模自动切**径向布局** + 节点/连线上限 + 标签节流,**几千节点不卡**);节点 = 知识卡(按 kind 渐变+发光着色、按连接数自动放大);连线 = `[[wikilink]]` 或共享标签(曲线渐变 + 流动动画);**滚轮缩放、按住左键拖动画布**、**左键凸显关联节点并淡化无关节点**、**右键打开卡片**、悬停高亮
|
|
123
127
|
|
|
124
128
|
## 🔧 设置
|
|
@@ -158,7 +162,7 @@ dsh-memory-eternal/
|
|
|
158
162
|
## 🗺 Roadmap / 待办
|
|
159
163
|
|
|
160
164
|
- [x] 对话自动沉淀(turn-stopping 钩子 + LLM 压缩 + 双层去重)
|
|
161
|
-
- [x] CJK 感知检索 + 本地 Markdown Vault(02-
|
|
165
|
+
- [x] CJK 感知检索 + 本地 Markdown Vault(02-08 分类 + frontmatter)
|
|
162
166
|
- [x] `memory_recall` 自动召回工具 + system prompt 分段
|
|
163
167
|
- [x] 图形化知识库:统计 / 检索 / 知识卡网格
|
|
164
168
|
- [x] 侧边栏「记忆」按钮 + 完整记忆库弹窗
|
|
@@ -169,11 +173,13 @@ dsh-memory-eternal/
|
|
|
169
173
|
|
|
170
174
|
## 📦 发布记录
|
|
171
175
|
|
|
176
|
+
- **v0.2.5**:安装方式统一为 `dsh plugin --profile web add`(README 标注 npx 备选写法)。
|
|
177
|
+
- **v0.2.4**:知识库分类扩展——新增「工具 Tools」(07) 与「教训 Mistakes」(08) 两类(错误/反模式/踩坑/debug 教训),前端筛选、图谱着色、自动捕获提示词同步更新。
|
|
172
178
|
- **v0.2.3**:放宽兼容性——`@deepseek-ai/dsh-tools` / `dsh-llm` peer 依赖改为 `>=0.1.0-rc.2 <0.2.0`,跨整个 `0.1.x` 系列均兼容(大多数 DSH 版本可直接安装)。
|
|
173
179
|
- **v0.2.2**:放宽 `@deepseek-ai/dsh-tools` / `dsh-llm` peer 依赖至 `^0.1.0-rc.7`,同时兼容旧版与新版 DSH。
|
|
174
180
|
- **v0.2.1**:更新 `@deepseek-ai/dsh-tools` / `dsh-llm` peer 依赖至 `^0.1.1-rc.2`(对齐当前 DSH 运行时)。
|
|
175
181
|
- **v0.2.0**:新增侧边栏「记忆」入口 + 完整记忆库弹窗;增强知识图谱(力导向/径向布局、滚轮缩放、左键拖拽平移、左键凸显关联/右键打开卡片、大规模抗压:节点/连线上限 + 标签节流 + O(n) 径向布局);README 头部动态演示 GIF。
|
|
176
|
-
- **v0.1.0**:首个可用版本。对话自动沉淀(turn-stopping 钩子 + LLM 压缩 + 双层去重)、`memory_recall` 工具、system prompt 召回段、Markdown Vault(02-
|
|
182
|
+
- **v0.1.0**:首个可用版本。对话自动沉淀(turn-stopping 钩子 + LLM 压缩 + 双层去重)、`memory_recall` 工具、system prompt 召回段、Markdown Vault(02-08 分类 + frontmatter)、CJK 检索、自研知识图谱、设置页图形化知识库。
|
|
177
183
|
|
|
178
184
|
## 📄 License
|
|
179
185
|
|
package/lib/capture.js
CHANGED
|
@@ -46,8 +46,8 @@ export async function summarizeTurn(llm, route, conversation, opts = {}) {
|
|
|
46
46
|
'输出严格 JSON(不要 markdown 代码块、不要多余文字):',
|
|
47
47
|
'{"save": false} 表示不值得保存;',
|
|
48
48
|
'否则输出:',
|
|
49
|
-
'{"save": true, "title": "简短标题", "kind": "knowledge|project|content|prompt|business", "tags": ["标签"], "body": "300-800字的压缩正文,markdown,含要点列表,首行是# 标题"}',
|
|
50
|
-
'kind 含义:project=项目背景/进度;knowledge=通用知识/技术方案/设计决策;content=内容素材/资料;prompt=提示词/工作流;business
|
|
49
|
+
'{"save": true, "title": "简短标题", "kind": "knowledge|project|content|prompt|business|tool|mistake", "tags": ["标签"], "body": "300-800字的压缩正文,markdown,含要点列表,首行是# 标题"}',
|
|
50
|
+
'kind 含义:project=项目背景/进度;knowledge=通用知识/技术方案/设计决策;content=内容素材/资料;prompt=提示词/工作流;business=业务/商业;tool=工具链/CLI/配置/环境坑;mistake=错误/反模式/踩坑/“别这么做”/debug 教训。',
|
|
51
51
|
'正文要求:去掉对话口水,只留可复用的结论、参数、步骤、原因。语言与对话一致。',
|
|
52
52
|
'已有卡片规则:若新知识与某张已有卡片是同一主题(同一技术、同一项目、同一决策),不要新建——输出',
|
|
53
53
|
'{"append_to": "已有卡片的 path 字段原样", "update": "追加/修正的短文本(一段话)"}',
|
|
@@ -151,7 +151,7 @@ export function parseCaptureJson(text) {
|
|
|
151
151
|
const title = String(parsed.title || '').trim().slice(0, 80)
|
|
152
152
|
const body = String(parsed.body || '').trim()
|
|
153
153
|
if (!title || body.length < 20) return null
|
|
154
|
-
const kind = ['project', 'knowledge', 'content', 'prompt', 'business'].includes(parsed.kind) ? parsed.kind : 'knowledge'
|
|
154
|
+
const kind = ['project', 'knowledge', 'content', 'prompt', 'business', 'tool', 'mistake'].includes(parsed.kind) ? parsed.kind : 'knowledge'
|
|
155
155
|
const tags = Array.isArray(parsed.tags)
|
|
156
156
|
? parsed.tags.map((t) => String(t).trim().slice(0, 30)).filter(Boolean).slice(0, 8)
|
|
157
157
|
: []
|
package/lib/client.js
CHANGED
|
@@ -3,7 +3,7 @@ window.__ModuleLoader__.load({
|
|
|
3
3
|
factory: (require) => {
|
|
4
4
|
var module = { exports: {} };
|
|
5
5
|
var exports = module.exports;
|
|
6
|
-
var te=Object.create;var q=Object.defineProperty;var ae=Object.getOwnPropertyDescriptor;var re=Object.getOwnPropertyNames;var ne=Object.getPrototypeOf,oe=Object.prototype.hasOwnProperty;var se=(t,r)=>{for(var n in r)q(t,n,{get:r[n],enumerable:!0})},V=(t,r,n,o)=>{if(r&&typeof r=="object"||typeof r=="function")for(let d of re(r))!oe.call(t,d)&&d!==n&&q(t,d,{get:()=>r[d],enumerable:!(o=ae(r,d))||o.enumerable});return t};var ie=(t,r,n)=>(n=t!=null?te(ne(t)):{},V(r||!t||!t.__esModule?q(n,"default",{value:t,enumerable:!0}):n,t)),le=t=>V(q({},"__esModule",{value:!0}),t);var ze={};se(ze,{apply:()=>ge,inject:()=>ce});module.exports=le(ze);var c=ie(require("react"),1),e=require("react/jsx-runtime"),H="memory-eternal",U="/memory-eternal/api",ce=["settingsScope","slots","locale","connection","remote"],de={nav:"\u8BB0\u5FC6",loading:"\u52A0\u8F7D\u4E2D\u2026",refresh:"\u5237\u65B0",overview:"\u8BB0\u5FC6\u5E93\u6982\u89C8",total:"\u77E5\u8BC6\u5361",recent:"\u8FD1 7 \u5929\u65B0\u589E",tags:"\u6807\u7B7E",searchPlaceholder:"\u641C\u7D22\u8BB0\u5FC6\uFF08\u652F\u6301\u4E2D\u6587\u7247\u6BB5\uFF09\u2026",search:"\u641C\u7D22",all:"\u5168\u90E8",kindProject:"\u9879\u76EE",kindKnowledge:"\u77E5\u8BC6",kindContent:"\u5185\u5BB9",kindPrompt:"\u63D0\u793A\u8BCD",kindBusiness:"\u4E1A\u52A1",cardsTab:"\u77E5\u8BC6\u5361",graphTab:"\u77E5\u8BC6\u56FE\u8C31",graph:"\u77E5\u8BC6\u56FE\u8C31",graphHint:"\u8282\u70B9=\u77E5\u8BC6\u5361\uFF1B\u8FDE\u7EBF=[[\u94FE\u63A5]] \u6216\u5171\u4EAB\u6807\u7B7E\u3002\u70B9\u51FB\u8282\u70B9\u9605\u8BFB\u5361\u7247\u3002",graphTip:"\u5DE6\u952E\u51F8\u663E\u5173\u8054\u8282\u70B9 \xB7 \u53F3\u952E\u6253\u5F00\u5361\u7247 \xB7 \u6EDA\u8F6E\u7F29\u653E \xB7 \u6309\u4F4F\u5DE6\u952E\u62D6\u52A8\u753B\u5E03",capped:"\u5DF2\u5C55\u793A\u6700\u6838\u5FC3\u7684",clearFocus:"\u53D6\u6D88\u9AD8\u4EAE",empty:"\u8BB0\u5FC6\u5E93\u8FD8\u662F\u7A7A\u7684\u3002\u591A\u804A\u51E0\u8F6E\u540E\uFF0C\u503C\u5F97\u4FDD\u5B58\u7684\u5185\u5BB9\u4F1A\u81EA\u52A8\u6C89\u6DC0\u6210\u77E5\u8BC6\u5361\u3002",emptyGraph:"\u56FE\u8C31\u6682\u65E0\u6570\u636E\u3002",open:"\u9605\u8BFB",updated:"\u66F4\u65B0\u4E8E",created:"\u521B\u5EFA\u4E8E",source:"\u6765\u6E90",close:"\u5173\u95ED",vaultDir:"\u8BB0\u5FC6\u5E93\u76EE\u5F55",capture:"\u81EA\u52A8\u6C89\u6DC0",recall:"\u81EA\u52A8\u53EC\u56DE",enabled:"\u5DF2\u542F\u7528",disabled:"\u5DF2\u7981\u7528",error:"\u52A0\u8F7D\u5931\u8D25",back:"\u8FD4\u56DE\u5217\u8868",cardCount:"\u5F20\u5361",nodes:"\u8282\u70B9",edges:"\u8FDE\u7EBF",memoryTitle:"\u8BB0\u5FC6\u5E93",memoryHint:"\u4F60\u7684\u672C\u5730\u7B2C\u4E8C\u5927\u8111",zoomIn:"\u653E\u5927",zoomOut:"\u7F29\u5C0F",fit:"\u9002\u5E94"},pe={nav:"Memory",loading:"Loading\u2026",refresh:"Refresh",overview:"Memory Overview",total:"Cards",recent:"Added (7d)",tags:"Tags",searchPlaceholder:"Search memory\u2026",search:"Search",all:"All",kindProject:"Projects",kindKnowledge:"Knowledge",kindContent:"Content",kindPrompt:"Prompts",kindBusiness:"Business",cardsTab:"Cards",graphTab:"Graph",graph:"Knowledge Graph",graphHint:"Nodes = cards; edges = [[links]] or shared tags. Click a node to read.",graphTip:"Left-click focuses neighbors \xB7 right-click opens card \xB7 scroll to zoom \xB7 hold left to pan",capped:"Showing the",clearFocus:"Clear highlight",empty:"Memory is empty. After a few conversations, valuable content is auto-captured.",emptyGraph:"No graph data yet.",open:"Read",updated:"Updated",created:"Created",source:"Source",close:"Close",vaultDir:"Vault directory",capture:"Auto capture",recall:"Auto recall",enabled:"on",disabled:"off",error:"Load failed",back:"Back to list",cardCount:"cards",nodes:"nodes",edges:"edges",memoryTitle:"Memory Library",memoryHint:"Your local second brain",zoomIn:"Zoom in",zoomOut:"Zoom out",fit:"Fit"},me=["all","project","knowledge","content","prompt","business"],
|
|
6
|
+
var te=Object.create;var q=Object.defineProperty;var ae=Object.getOwnPropertyDescriptor;var re=Object.getOwnPropertyNames;var ne=Object.getPrototypeOf,oe=Object.prototype.hasOwnProperty;var se=(t,r)=>{for(var n in r)q(t,n,{get:r[n],enumerable:!0})},V=(t,r,n,o)=>{if(r&&typeof r=="object"||typeof r=="function")for(let d of re(r))!oe.call(t,d)&&d!==n&&q(t,d,{get:()=>r[d],enumerable:!(o=ae(r,d))||o.enumerable});return t};var ie=(t,r,n)=>(n=t!=null?te(ne(t)):{},V(r||!t||!t.__esModule?q(n,"default",{value:t,enumerable:!0}):n,t)),le=t=>V(q({},"__esModule",{value:!0}),t);var ze={};se(ze,{apply:()=>ge,inject:()=>ce});module.exports=le(ze);var c=ie(require("react"),1),e=require("react/jsx-runtime"),H="memory-eternal",U="/memory-eternal/api",ce=["settingsScope","slots","locale","connection","remote"],de={nav:"\u8BB0\u5FC6",loading:"\u52A0\u8F7D\u4E2D\u2026",refresh:"\u5237\u65B0",overview:"\u8BB0\u5FC6\u5E93\u6982\u89C8",total:"\u77E5\u8BC6\u5361",recent:"\u8FD1 7 \u5929\u65B0\u589E",tags:"\u6807\u7B7E",searchPlaceholder:"\u641C\u7D22\u8BB0\u5FC6\uFF08\u652F\u6301\u4E2D\u6587\u7247\u6BB5\uFF09\u2026",search:"\u641C\u7D22",all:"\u5168\u90E8",kindProject:"\u9879\u76EE",kindKnowledge:"\u77E5\u8BC6",kindContent:"\u5185\u5BB9",kindPrompt:"\u63D0\u793A\u8BCD",kindBusiness:"\u4E1A\u52A1",kindTool:"\u5DE5\u5177",kindMistake:"\u6559\u8BAD",cardsTab:"\u77E5\u8BC6\u5361",graphTab:"\u77E5\u8BC6\u56FE\u8C31",graph:"\u77E5\u8BC6\u56FE\u8C31",graphHint:"\u8282\u70B9=\u77E5\u8BC6\u5361\uFF1B\u8FDE\u7EBF=[[\u94FE\u63A5]] \u6216\u5171\u4EAB\u6807\u7B7E\u3002\u70B9\u51FB\u8282\u70B9\u9605\u8BFB\u5361\u7247\u3002",graphTip:"\u5DE6\u952E\u51F8\u663E\u5173\u8054\u8282\u70B9 \xB7 \u53F3\u952E\u6253\u5F00\u5361\u7247 \xB7 \u6EDA\u8F6E\u7F29\u653E \xB7 \u6309\u4F4F\u5DE6\u952E\u62D6\u52A8\u753B\u5E03",capped:"\u5DF2\u5C55\u793A\u6700\u6838\u5FC3\u7684",clearFocus:"\u53D6\u6D88\u9AD8\u4EAE",empty:"\u8BB0\u5FC6\u5E93\u8FD8\u662F\u7A7A\u7684\u3002\u591A\u804A\u51E0\u8F6E\u540E\uFF0C\u503C\u5F97\u4FDD\u5B58\u7684\u5185\u5BB9\u4F1A\u81EA\u52A8\u6C89\u6DC0\u6210\u77E5\u8BC6\u5361\u3002",emptyGraph:"\u56FE\u8C31\u6682\u65E0\u6570\u636E\u3002",open:"\u9605\u8BFB",updated:"\u66F4\u65B0\u4E8E",created:"\u521B\u5EFA\u4E8E",source:"\u6765\u6E90",close:"\u5173\u95ED",vaultDir:"\u8BB0\u5FC6\u5E93\u76EE\u5F55",capture:"\u81EA\u52A8\u6C89\u6DC0",recall:"\u81EA\u52A8\u53EC\u56DE",enabled:"\u5DF2\u542F\u7528",disabled:"\u5DF2\u7981\u7528",error:"\u52A0\u8F7D\u5931\u8D25",back:"\u8FD4\u56DE\u5217\u8868",cardCount:"\u5F20\u5361",nodes:"\u8282\u70B9",edges:"\u8FDE\u7EBF",memoryTitle:"\u8BB0\u5FC6\u5E93",memoryHint:"\u4F60\u7684\u672C\u5730\u7B2C\u4E8C\u5927\u8111",zoomIn:"\u653E\u5927",zoomOut:"\u7F29\u5C0F",fit:"\u9002\u5E94"},pe={nav:"Memory",loading:"Loading\u2026",refresh:"Refresh",overview:"Memory Overview",total:"Cards",recent:"Added (7d)",tags:"Tags",searchPlaceholder:"Search memory\u2026",search:"Search",all:"All",kindProject:"Projects",kindKnowledge:"Knowledge",kindContent:"Content",kindPrompt:"Prompts",kindBusiness:"Business",kindTool:"Tools",kindMistake:"Mistakes",cardsTab:"Cards",graphTab:"Graph",graph:"Knowledge Graph",graphHint:"Nodes = cards; edges = [[links]] or shared tags. Click a node to read.",graphTip:"Left-click focuses neighbors \xB7 right-click opens card \xB7 scroll to zoom \xB7 hold left to pan",capped:"Showing the",clearFocus:"Clear highlight",empty:"Memory is empty. After a few conversations, valuable content is auto-captured.",emptyGraph:"No graph data yet.",open:"Read",updated:"Updated",created:"Created",source:"Source",close:"Close",vaultDir:"Vault directory",capture:"Auto capture",recall:"Auto recall",enabled:"on",disabled:"off",error:"Load failed",back:"Back to list",cardCount:"cards",nodes:"nodes",edges:"edges",memoryTitle:"Memory Library",memoryHint:"Your local second brain",zoomIn:"Zoom in",zoomOut:"Zoom out",fit:"Fit"},me=["all","project","knowledge","content","prompt","business","tool","mistake"],I={project:"#3b82f6",knowledge:"#22c55e",content:"#f43f5e",prompt:"#06b6d4",business:"#eab308",tool:"#f97316",mistake:"#a855f7",other:"#64748b"},_={project:"kindProject",knowledge:"kindKnowledge",content:"kindContent",prompt:"kindPrompt",business:"kindBusiness",tool:"kindTool",mistake:"kindMistake",other:"kindKnowledge"},Y=`
|
|
7
7
|
.memory-eternal-root { font-family: inherit; color: var(--dsw-alias-label-primary, #1f2937); }
|
|
8
8
|
.mc-card { background: var(--dsw-alias-bg-layer-1, #fff); border: 1px solid var(--dsw-alias-border-l1, #e5e7eb); border-radius: 12px; padding: 14px 16px; }
|
|
9
9
|
.mc-stats { display: grid; grid-template-columns: repeat(auto-fit, minmax(110px, 1fr)); gap: 10px; margin-bottom: 14px; }
|
|
@@ -88,7 +88,7 @@ var te=Object.create;var q=Object.defineProperty;var ae=Object.getOwnPropertyDes
|
|
|
88
88
|
.me-graph-legend { display: flex; gap: 12px; flex-wrap: wrap; padding: 2px 2px 0; font-size: 11px; opacity: 0.85; }
|
|
89
89
|
.me-graph-legend .lg { display: inline-flex; align-items: center; gap: 5px; }
|
|
90
90
|
.me-graph-hint { font-size: 11px; opacity: 0.6; margin-left: auto; }
|
|
91
|
-
`;function ge(t){t.effect(()=>t.locale.register(H,{zh:de,en:pe}),"memory-eternal: locale");let r=t.locale.bind(H);t.effect(()=>t.slots.inject("settings.section",()=>t.slots.register({name:"settings.section",id:H,order:25,label:()=>r("nav"),locale:H,inject:()=>({})},()=>c.default.createElement(W,{t:r,inModal:!1}))),"memory-eternal: settings section"),t.effect(()=>t.slots.inject("sidebar.footer.action",()=>t.slots.register({name:"sidebar.footer.action",id:`${H}:footer`,order:100,label:()=>r("nav"),locale:H,inject:()=>({})},n=>c.default.createElement(fe,{t:r,wide:!(n&&n.wide===!1)}))),"memory-eternal: sidebar footer action")}function fe({t,wide:r}){let[n,o]=(0,c.useState)(!1);return(0,e.jsxs)("div",{className:`me-footer${r?"":" rail"}`,children:[(0,e.jsx)("style",{children:Y}),(0,e.jsxs)("button",{type:"button",className:"me-footer-btn",onClick:()=>o(!0),"aria-label":t("nav"),title:t("nav"),children:[(0,e.jsx)("span",{className:"me-footer-ico","aria-hidden":"true",children:(0,e.jsx)(Z,{})}),(0,e.jsx)("span",{className:"me-footer-label",children:t("nav")})]}),n&&(0,e.jsx)(ue,{t,onClose:()=>o(!1)})]})}function Z(){return(0,e.jsxs)("svg",{viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"1.8",strokeLinecap:"round",strokeLinejoin:"round","aria-hidden":"true",children:[(0,e.jsx)("ellipse",{cx:"12",cy:"5.5",rx:"8",ry:"3"}),(0,e.jsx)("path",{d:"M4 5.5v6c0 1.66 3.58 3 8 3s8-1.34 8-3v-6"}),(0,e.jsx)("path",{d:"M4 11.5v6c0 1.66 3.58 3 8 3s8-1.34 8-3v-6"})]})}function ue({t,onClose:r}){return(0,c.useEffect)(()=>{let n=o=>{o.key==="Escape"&&r()};return window.addEventListener("keydown",n),()=>window.removeEventListener("keydown",n)},[r]),(0,e.jsxs)("div",{className:"me-overlay-top",onClick:r,children:[(0,e.jsx)("style",{children:Y}),(0,e.jsx)("div",{className:"me-modal",onClick:n=>n.stopPropagation(),children:(0,e.jsx)(W,{t,inModal:!0,onClose:r})})]})}function W({t,inModal:r,onClose:n}){let[o,d]=(0,c.useState)(null),[N,g]=(0,c.useState)([]),[l,z]=(0,c.useState)(!0),[D,j]=(0,c.useState)(""),[k,C]=(0,c.useState)("all"),[y,u]=(0,c.useState)(""),[M,f]=(0,c.useState)("cards"),[P,A]=(0,c.useState)(null),E=(0,c.useRef)(null),T=(0,c.useCallback)(async(p=k,$=y)=>{try{z(!0),j("");let v=new URLSearchParams;p&&p!=="all"&&v.set("kind",p),$.trim()&&v.set("q",$.trim());let a=await(await fetch(`${U}/cards?${v.toString()}`)).json();a.ok&&g(a.cards||[])}catch(v){j(String(v&&v.message?v.message:v))}finally{z(!1)}},[k,y]),h=(0,c.useCallback)(async()=>{try{let[p,$]=await Promise.all([fetch(`${U}/overview`).then(v=>v.json()),fetch(`${U}/cards`).then(v=>v.json())]);p.ok&&d(p),$.ok&&g($.cards||[])}catch(p){j(String(p&&p.message?p.message:p))}finally{z(!1)}},[]);(0,c.useEffect)(()=>(h(),()=>{E.current&&clearTimeout(E.current)}),[h]);let i=p=>{u(p),E.current&&clearTimeout(E.current),E.current=setTimeout(()=>T(k,p),280)},x=p=>{C(p),T(p,y)},I=async p=>{try{let v=await(await fetch(`${U}/card?path=${encodeURIComponent(p.path||p.id)}`)).json();v.ok&&A({path:v.path,title:p.title,text:v.text})}catch($){j(String($&&$.message?$.message:$))}};return(0,e.jsxs)("div",{className:"memory-eternal-root",style:{height:"100%",display:"flex",flexDirection:"column"},children:[(0,e.jsx)("style",{children:Y}),r&&(0,e.jsxs)("div",{className:"me-modal-head",children:[(0,e.jsxs)("div",{className:"me-modal-title",children:[(0,e.jsx)(Z,{}),(0,e.jsx)("h2",{children:t("memoryTitle")}),(0,e.jsx)("span",{children:t("memoryHint")})]}),(0,e.jsx)("div",{className:"spacer"}),(0,e.jsx)("button",{type:"button",className:"me-modal-close",onClick:n,"aria-label":t("close"),children:"\u2715"})]}),(0,e.jsxs)("div",{className:"me-modal-body",children:[(0,e.jsxs)("div",{className:"mc-stats",children:[(0,e.jsx)(X,{label:t("total"),value:o?o.total:"\u2014"}),(0,e.jsx)(X,{label:t("recent"),value:o?o.recent:"\u2014"}),(0,e.jsx)(X,{label:t("tags"),value:o?o.tags:"\u2014"}),(0,e.jsx)(X,{label:t("cardCount"),value:o?o.byKind?.knowledge??0:"\u2014"})]}),(0,e.jsxs)("div",{className:"mc-toolbar",children:[(0,e.jsx)("input",{type:"text",placeholder:t("searchPlaceholder"),value:y,onChange:p=>i(p.target.value)}),(0,e.jsxs)("div",{className:"mc-tabs",children:[(0,e.jsx)("button",{type:"button",className:`mc-tab${M==="cards"?" active":""}`,onClick:()=>f("cards"),children:t("cardsTab")}),(0,e.jsx)("button",{type:"button",className:`mc-tab${M==="graph"?" active":""}`,onClick:()=>f("graph"),children:t("graphTab")})]}),(0,e.jsx)("button",{type:"button",className:"mc-btn",onClick:()=>h(),children:t("refresh")})]}),M==="cards"&&(0,e.jsx)("div",{className:"mc-chips",children:me.map(p=>(0,e.jsx)("button",{type:"button",className:`mc-chip${k===p?" active":""}`,onClick:()=>x(p),children:t(p==="all"?"all":_[p])},p))}),D&&(0,e.jsxs)("div",{className:"mc-empty",children:[t("error"),"\uFF1A",D]}),M==="cards"?l&&!N.length?(0,e.jsx)("div",{className:"mc-empty",children:t("loading")}):N.length===0?(0,e.jsx)("div",{className:"mc-empty",children:t("empty")}):(0,e.jsx)("div",{className:"mc-grid",children:N.map(p=>(0,e.jsx)(he,{card:p,t,onOpen:I},p.path))}):(0,e.jsx)(ye,{t,onOpen:I}),P&&(0,e.jsx)(be,{t,card:P,onClose:()=>A(null)})]})]})}var X=({label:t,value:r})=>(0,e.jsxs)("div",{className:"mc-stat mc-card",children:[(0,e.jsx)("b",{children:r}),(0,e.jsx)("span",{children:t})]}),he=({card:t,t:r,onOpen:n})=>(0,e.jsxs)("article",{className:"mc-cardrow mc-card",onClick:()=>n(t),children:[(0,e.jsxs)("h4",{children:[(0,e.jsx)("span",{className:"mc-kind",style:{background:L[t.kind]||L.other}}),t.title]}),(0,e.jsx)("p",{children:t.summary||""}),t.tags.length>0&&(0,e.jsx)("div",{className:"mc-tags",children:t.tags.slice(0,4).map(o=>(0,e.jsx)("span",{className:"mc-tag",children:o},o))}),(0,e.jsxs)("footer",{children:[(0,e.jsx)("span",{children:r(_[t.kind])}),(0,e.jsx)("span",{children:Ce(t.updated)})]})]});function be({t,card:r,onClose:n}){return(0,c.useEffect)(()=>{let o=d=>{d.key==="Escape"&&n()};return window.addEventListener("keydown",o),()=>window.removeEventListener("keydown",o)},[n]),(0,e.jsxs)("div",{className:"me-overlay",onClick:n,children:[(0,e.jsx)("style",{children:Y}),(0,e.jsxs)("div",{className:"me-dialog",onClick:o=>o.stopPropagation(),children:[(0,e.jsxs)("div",{className:"me-dialog-head",children:[(0,e.jsx)("h3",{children:r.title}),(0,e.jsx)("button",{type:"button",className:"mc-btn",onClick:n,children:t("close")})]}),(0,e.jsx)("div",{className:"me-dialog-body",children:r.text})]})]})}function ye({t,onOpen:r}){let[n,o]=(0,c.useState)(null),[d,N]=(0,c.useState)("");return(0,c.useEffect)(()=>{let g=!0;return fetch(`${U}/graph`).then(l=>l.json()).then(l=>{g&&o(l.ok?l:null)}).catch(l=>{g&&N(String(l&&l.message?l.message:l))}),()=>{g=!1}},[]),(0,e.jsxs)("div",{className:"me-graph",children:[(0,e.jsx)("style",{children:Y}),d&&(0,e.jsxs)("div",{className:"mc-empty",children:[t("error"),"\uFF1A",d]}),!n&&!d&&(0,e.jsx)("div",{className:"mc-empty",children:t("loading")}),n&&n.nodes.length===0&&(0,e.jsx)("div",{className:"mc-empty",children:t("emptyGraph")}),n&&n.nodes.length>0&&(0,e.jsx)(ve,{nodes:n.nodes,edges:n.edges,onOpen:r,t,countLabel:`${n.nodes.length} ${t("nodes")} \xB7 ${xe(n.edges)} ${t("edges")}`})]})}function xe(t){let r=new Set;for(let n of t||[])r.add([n.source,n.target].sort().join("|"));return r.size}function ve({nodes:t,edges:r,onOpen:n,t:o,countLabel:d}){let l=(0,c.useRef)(null),z=(0,c.useRef)(null),D=(0,c.useRef)(null),j=(0,c.useRef)(null),k=(0,c.useRef)({x:0,y:0,k:1}),C=(0,c.useRef)(null),y=(0,c.useRef)(!1),[u,M]=(0,c.useState)(null),f=(0,c.useMemo)(()=>{let a={};r.forEach(w=>{a[w.source]=(a[w.source]||0)+1,a[w.target]=(a[w.target]||0)+1});let s=420,m=900,b=t,S=!1;t.length>s&&(b=[...t].sort((w,K)=>(a[K.id]||0)-(a[w.id]||0)).slice(0,s),S=!0);let R=new Set(b.map(w=>w.id)),B=new Set,O=[];r.forEach(w=>{if(!R.has(w.source)||!R.has(w.target))return;let K=[w.source,w.target].sort().join("|");B.has(K)||(B.add(K),O.push(w))}),O.sort((w,K)=>(a[w.source]||0)+(a[w.target]||0)-((a[K.source]||0)+(a[K.target]||0)));let F=Math.min(b.length,28),J=b.map(w=>a[w.id]||0).sort((w,K)=>K-w),ee=F>0?J[F-1]:1/0;return{list:b,es:O.slice(0,m),capped:S,maxDeg:Math.max(1,...Object.values(a)),deg:a,hubMin:ee}},[t,r]),P=(0,c.useMemo)(()=>we(f.list,f.es,980,620),[f.list,f.es,980,620]),A=(0,c.useMemo)(()=>f.list.reduce((a,s,m)=>(a[s.id]=m,a),{}),[f.list]),E=(0,c.useMemo)(()=>{let a={};return f.list.forEach(s=>{a[s.id]=new Set}),f.es.forEach(s=>{a[s.source]&&a[s.source].add(s.target),a[s.target]&&a[s.target].add(s.source)}),a},[f.list,f.es]),T=(0,c.useCallback)(()=>{let a=D.current;if(!a)return;let{x:s,y:m,k:b}=k.current;a.setAttribute("transform",`translate(${s} ${m}) scale(${b})`),j.current&&j.current.classList.toggle("all",b>=1.4)},[]);(0,c.useEffect)(()=>{T()},[T,P]);let h=(0,c.useCallback)((a,s)=>{let m=z.current;if(!m||typeof m.getScreenCTM!="function")return{x:a,y:s};let b=m.getScreenCTM();if(!b)return{x:a,y:s};let S=new DOMPoint(a,s).matrixTransform(b.inverse());return{x:S.x,y:S.y}},[]),i=(0,c.useCallback)((a,s)=>{let m=k.current,b=Math.min(5,Math.max(.25,m.k*s));k.current={k:b,x:a.x-b/m.k*(a.x-m.x),y:a.y-b/m.k*(a.y-m.y)},T()},[T]);(0,c.useEffect)(()=>{let a=l.current;if(!a)return;let s=m=>{m.preventDefault(),i(h(m.clientX,m.clientY),m.deltaY<0?1.12:1/1.12)};return a.addEventListener("wheel",s,{passive:!1}),()=>a.removeEventListener("wheel",s)},[h,i]);let x=a=>{if(a.button!==0)return;let s=h(a.clientX,a.clientY);C.current={px:s.x,py:s.y,tx:k.current.x,ty:k.current.y,started:!1,id:a.pointerId},y.current=!1},I=a=>{let s=C.current;if(!s)return;let m=h(a.clientX,a.clientY);Math.abs(m.x-s.px)+Math.abs(m.y-s.py)>1.5&&(y.current=!0,!s.started&&l.current&&l.current.setPointerCapture&&(l.current.setPointerCapture(a.pointerId),s.started=!0),l.current&&l.current.classList.add("dragging"),k.current={...k.current,x:s.tx+(m.x-s.px),y:s.ty+(m.y-s.py)},T())},p=()=>{C.current=null,l.current&&l.current.classList.remove("dragging")},$=a=>{n({path:a.id,title:a.title})},v=a=>{y.current||M(a.id)},G=a=>7+Math.min(9,(f.deg[a.id]||0)/f.maxDeg*9);return(0,e.jsxs)("div",{className:"me-graph",children:[(0,e.jsxs)("div",{className:"me-graph-toolbar",children:[(0,e.jsx)("span",{className:"me-graph-count",children:d}),u&&(0,e.jsx)("button",{type:"button",className:"mc-btn",onClick:()=>M(null),children:o("clearFocus")}),(0,e.jsx)("span",{className:"spacer",style:{flex:1}}),(0,e.jsx)("button",{type:"button",className:"mc-btn",onClick:()=>i({x:980/2,y:620/2},1/1.25),"aria-label":o("zoomOut"),children:"\u2212"}),(0,e.jsx)("button",{type:"button",className:"mc-btn",onClick:()=>{k.current={x:0,y:0,k:1},T()},"aria-label":o("fit"),children:o("fit")}),(0,e.jsx)("button",{type:"button",className:"mc-btn",onClick:()=>i({x:980/2,y:620/2},1.25),"aria-label":o("zoomIn"),children:"+"})]}),(0,e.jsxs)("div",{className:"me-graph-canvas",ref:l,onPointerDown:x,onPointerMove:I,onPointerUp:p,onPointerLeave:p,onContextMenu:a=>{a.preventDefault(),M(null)},onClick:a=>{y.current||M(null)},children:[(0,e.jsxs)("svg",{ref:z,viewBox:"0 0 980 620",role:"img",children:[(0,e.jsxs)("defs",{children:[Object.keys(L).map(a=>(0,e.jsxs)("radialGradient",{id:`me-grad-${a}`,cx:"35%",cy:"30%",r:"75%",children:[(0,e.jsx)("stop",{offset:"0%",stopColor:Me(L[a],.55)}),(0,e.jsx)("stop",{offset:"60%",stopColor:L[a]}),(0,e.jsx)("stop",{offset:"100%",stopColor:$e(L[a],.25)})]},a)),Object.keys(L).map(a=>(0,e.jsxs)("linearGradient",{id:`me-edge-${a}`,gradientUnits:"userSpaceOnUse",children:[(0,e.jsx)("stop",{offset:"0%",stopColor:L[a],stopOpacity:"0.4"}),(0,e.jsx)("stop",{offset:"100%",stopColor:L[a],stopOpacity:"0.85"})]},`e-${a}`)),(0,e.jsxs)("filter",{id:"me-glow",x:"-60%",y:"-60%",width:"220%",height:"220%",children:[(0,e.jsx)("feGaussianBlur",{stdDeviation:"3.2",result:"b"}),(0,e.jsxs)("feMerge",{children:[(0,e.jsx)("feMergeNode",{in:"b"}),(0,e.jsx)("feMergeNode",{in:"SourceGraphic"})]})]})]}),(0,e.jsxs)("g",{ref:D,transform:"translate(0 0) scale(1)",children:[f.es.map((a,s)=>{let m=A[a.source],b=A[a.target];if(m===void 0||b===void 0)return null;let S=P[m],R=P[b];if(!S||!R)return null;let B=f.list[m].kind||"other",O=u&&a.source!==u&&a.target!==u,F=u&&(a.source===u||a.target===u);return(0,e.jsx)("path",{d:Ne(S,R),className:`me-graph-edge${O?" dim":""}${F?" focus":""}`,style:{stroke:`url(#me-edge-${B})`,animationDelay:`${s%8*.12}s`}},`e${s}`)}),f.list.map((a,s)=>{let m=P[s];if(!m)return null;let b=a.kind||"other",S=G(a),R=u&&a.id!==u&&!E[a.id].has(u),B=u&&(a.id===u||E[a.id].has(u));return(0,e.jsxs)("g",{className:`me-graph-node in${B?" focus":""}${R?" dim":""}`,style:{animationDelay:`${s*.02}s`},transform:`translate(${m.x} ${m.y})`,onClick:O=>{O.stopPropagation(),v(a)},onContextMenu:O=>{O.preventDefault(),O.stopPropagation(),$(a)},children:[(0,e.jsx)("circle",{className:"inner",r:S,fill:`url(#me-grad-${b})`,stroke:L[b],strokeOpacity:"0.9",filter:"url(#me-glow)"}),(0,e.jsx)("circle",{r:Math.max(2.4,S*.2),fill:"rgba(255,255,255,0.85)"})]},a.id)}),(0,e.jsx)("g",{ref:j,className:"me-labels",children:f.list.map((a,s)=>{let m=P[s];if(!m)return null;let b=G(a),S=(f.deg[a.id]||0)>=f.hubMin,R=u&&a.id!==u&&!E[a.id].has(u);return(0,e.jsx)("text",{className:`${S?"me-nodelabel":"me-nodelabel minor"}${R?" dim":""}`,x:m.x+b+7,y:m.y+4,children:String(a.title||"").slice(0,16)},`l${a.id}`)})})]})]}),(0,e.jsxs)("div",{className:"me-graph-legend",children:[Object.keys(L).map(a=>(0,e.jsxs)("span",{className:"lg",children:[(0,e.jsx)("span",{className:"mc-kind",style:{background:L[a]}}),o(_[a])]},a)),(0,e.jsx)("span",{className:"me-graph-hint",children:o("graphHint")})]})]}),(0,e.jsxs)("div",{className:"me-graph-tip",children:[f.capped?`${o("capped")} ${f.list.length} / ${t.length} ${o("nodes")} \xB7 `:"",o("graphTip")]})]})}function we(t,r,n,o){let d=t.length;if(d===0)return[];if(d>160)return ke(t,n,o);let N=d<60?260:d<120?180:120,g=t.map((h,i)=>{let x=i/d*Math.PI*2-Math.PI/2;return{x:Math.cos(x),y:Math.sin(x)}}),l=g.map(()=>({x:0,y:0})),z=t.map(()=>[]);r.forEach(h=>{let i=t.findIndex(I=>I.id===h.source),x=t.findIndex(I=>I.id===h.target);i>=0&&x>=0&&i!==x&&(z[i].push(x),z[x].push(i))});let D=1.35,j=.035,k=.03,C=.84;for(let h=0;h<N;h++){for(let i=0;i<d;i++)for(let x=i+1;x<d;x++){let I=g[i].x-g[x].x,p=g[i].y-g[x].y,$=I*I+p*p||.01,v=Math.sqrt($),G=D/$,a=I/v*G,s=p/v*G;l[i].x+=a,l[i].y+=s,l[x].x-=a,l[x].y-=s}for(let i=0;i<d;i++)for(let x of z[i])l[i].x+=(g[x].x-g[i].x)*j,l[i].y+=(g[x].y-g[i].y)*j;for(let i=0;i<d;i++)l[i].x-=g[i].x*k,l[i].y-=g[i].y*k;for(let i=0;i<d;i++)l[i].x=Math.max(-.5,Math.min(.5,l[i].x*C)),l[i].y=Math.max(-.5,Math.min(.5,l[i].y*C)),g[i].x+=l[i].x,g[i].y+=l[i].y}let y=1/0,u=-1/0,M=1/0,f=-1/0;g.forEach(h=>{y=Math.min(y,h.x),u=Math.max(u,h.x),M=Math.min(M,h.y),f=Math.max(f,h.y)});let P=70,A=Math.min((n-2*P)/(u-y||1),(o-2*P)/(f-M||1)),E=(y+u)/2,T=(M+f)/2;return g.map(h=>({x:n/2+(h.x-E)*A,y:o/2+(h.y-T)*A}))}function ke(t,r,n){let o=t.length,d=r/2,N=n/2,g=Math.min(r,n)/2-80,l={};t.forEach((k,C)=>{let y=k.kind||"other";(l[y]=l[y]||[]).push(C)});let z=Object.keys(l),D=new Array(o),j=-Math.PI/2;for(let k of z){let C=l[k],y=C.length/o*Math.PI*2,u=j;C.forEach((M,f)=>{let P=C.length===1?u+y/2:u+y*(f+.5)/C.length;D[M]={x:d+g*Math.cos(P),y:N+g*Math.sin(P)}}),j+=y}return D}function Ne(t,r){let n=(t.x+r.x)/2,o=(t.y+r.y)/2,d=r.x-t.x,N=r.y-t.y,g=Math.sqrt(d*d+N*N)||1,l=Math.min(38,g*.18),z=n-N/g*l,D=o+d/g*l;return`M ${t.x} ${t.y} Q ${z} ${D} ${r.x} ${r.y}`}function Q(t){let r=t.replace("#",""),n=r.length===3?r.split("").map(o=>o+o).join(""):r;return[parseInt(n.slice(0,2),16),parseInt(n.slice(2,4),16),parseInt(n.slice(4,6),16)]}function Me(t,r){let[n,o,d]=Q(t);return`rgb(${Math.round(n+(255-n)*r)}, ${Math.round(o+(255-o)*r)}, ${Math.round(d+(255-d)*r)})`}function $e(t,r){let[n,o,d]=Q(t);return`rgb(${Math.round(n*(1-r))}, ${Math.round(o*(1-r))}, ${Math.round(d*(1-r))})`}function Ce(t){if(!t)return"";let r=new Date(t);if(Number.isNaN(r.getTime()))return"";let n=new Date,o=r.toDateString()===n.toDateString(),d=g=>String(g).padStart(2,"0"),N=`${d(r.getHours())}:${d(r.getMinutes())}`;return o?N:`${r.getMonth()+1}-${r.getDate()} ${N}`}
|
|
91
|
+
`;function ge(t){t.effect(()=>t.locale.register(H,{zh:de,en:pe}),"memory-eternal: locale");let r=t.locale.bind(H);t.effect(()=>t.slots.inject("settings.section",()=>t.slots.register({name:"settings.section",id:H,order:25,label:()=>r("nav"),locale:H,inject:()=>({})},()=>c.default.createElement(W,{t:r,inModal:!1}))),"memory-eternal: settings section"),t.effect(()=>t.slots.inject("sidebar.footer.action",()=>t.slots.register({name:"sidebar.footer.action",id:`${H}:footer`,order:100,label:()=>r("nav"),locale:H,inject:()=>({})},n=>c.default.createElement(fe,{t:r,wide:!(n&&n.wide===!1)}))),"memory-eternal: sidebar footer action")}function fe({t,wide:r}){let[n,o]=(0,c.useState)(!1);return(0,e.jsxs)("div",{className:`me-footer${r?"":" rail"}`,children:[(0,e.jsx)("style",{children:Y}),(0,e.jsxs)("button",{type:"button",className:"me-footer-btn",onClick:()=>o(!0),"aria-label":t("nav"),title:t("nav"),children:[(0,e.jsx)("span",{className:"me-footer-ico","aria-hidden":"true",children:(0,e.jsx)(Z,{})}),(0,e.jsx)("span",{className:"me-footer-label",children:t("nav")})]}),n&&(0,e.jsx)(ue,{t,onClose:()=>o(!1)})]})}function Z(){return(0,e.jsxs)("svg",{viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"1.8",strokeLinecap:"round",strokeLinejoin:"round","aria-hidden":"true",children:[(0,e.jsx)("ellipse",{cx:"12",cy:"5.5",rx:"8",ry:"3"}),(0,e.jsx)("path",{d:"M4 5.5v6c0 1.66 3.58 3 8 3s8-1.34 8-3v-6"}),(0,e.jsx)("path",{d:"M4 11.5v6c0 1.66 3.58 3 8 3s8-1.34 8-3v-6"})]})}function ue({t,onClose:r}){return(0,c.useEffect)(()=>{let n=o=>{o.key==="Escape"&&r()};return window.addEventListener("keydown",n),()=>window.removeEventListener("keydown",n)},[r]),(0,e.jsxs)("div",{className:"me-overlay-top",onClick:r,children:[(0,e.jsx)("style",{children:Y}),(0,e.jsx)("div",{className:"me-modal",onClick:n=>n.stopPropagation(),children:(0,e.jsx)(W,{t,inModal:!0,onClose:r})})]})}function W({t,inModal:r,onClose:n}){let[o,d]=(0,c.useState)(null),[N,g]=(0,c.useState)([]),[l,z]=(0,c.useState)(!0),[D,j]=(0,c.useState)(""),[k,C]=(0,c.useState)("all"),[y,u]=(0,c.useState)(""),[M,f]=(0,c.useState)("cards"),[P,A]=(0,c.useState)(null),L=(0,c.useRef)(null),E=(0,c.useCallback)(async(p=k,$=y)=>{try{z(!0),j("");let v=new URLSearchParams;p&&p!=="all"&&v.set("kind",p),$.trim()&&v.set("q",$.trim());let a=await(await fetch(`${U}/cards?${v.toString()}`)).json();a.ok&&g(a.cards||[])}catch(v){j(String(v&&v.message?v.message:v))}finally{z(!1)}},[k,y]),h=(0,c.useCallback)(async()=>{try{let[p,$]=await Promise.all([fetch(`${U}/overview`).then(v=>v.json()),fetch(`${U}/cards`).then(v=>v.json())]);p.ok&&d(p),$.ok&&g($.cards||[])}catch(p){j(String(p&&p.message?p.message:p))}finally{z(!1)}},[]);(0,c.useEffect)(()=>(h(),()=>{L.current&&clearTimeout(L.current)}),[h]);let i=p=>{u(p),L.current&&clearTimeout(L.current),L.current=setTimeout(()=>E(k,p),280)},x=p=>{C(p),E(p,y)},T=async p=>{try{let v=await(await fetch(`${U}/card?path=${encodeURIComponent(p.path||p.id)}`)).json();v.ok&&A({path:v.path,title:p.title,text:v.text})}catch($){j(String($&&$.message?$.message:$))}};return(0,e.jsxs)("div",{className:"memory-eternal-root",style:{height:"100%",display:"flex",flexDirection:"column"},children:[(0,e.jsx)("style",{children:Y}),r&&(0,e.jsxs)("div",{className:"me-modal-head",children:[(0,e.jsxs)("div",{className:"me-modal-title",children:[(0,e.jsx)(Z,{}),(0,e.jsx)("h2",{children:t("memoryTitle")}),(0,e.jsx)("span",{children:t("memoryHint")})]}),(0,e.jsx)("div",{className:"spacer"}),(0,e.jsx)("button",{type:"button",className:"me-modal-close",onClick:n,"aria-label":t("close"),children:"\u2715"})]}),(0,e.jsxs)("div",{className:"me-modal-body",children:[(0,e.jsxs)("div",{className:"mc-stats",children:[(0,e.jsx)(X,{label:t("total"),value:o?o.total:"\u2014"}),(0,e.jsx)(X,{label:t("recent"),value:o?o.recent:"\u2014"}),(0,e.jsx)(X,{label:t("tags"),value:o?o.tags:"\u2014"}),(0,e.jsx)(X,{label:t("cardCount"),value:o?o.byKind?.knowledge??0:"\u2014"})]}),(0,e.jsxs)("div",{className:"mc-toolbar",children:[(0,e.jsx)("input",{type:"text",placeholder:t("searchPlaceholder"),value:y,onChange:p=>i(p.target.value)}),(0,e.jsxs)("div",{className:"mc-tabs",children:[(0,e.jsx)("button",{type:"button",className:`mc-tab${M==="cards"?" active":""}`,onClick:()=>f("cards"),children:t("cardsTab")}),(0,e.jsx)("button",{type:"button",className:`mc-tab${M==="graph"?" active":""}`,onClick:()=>f("graph"),children:t("graphTab")})]}),(0,e.jsx)("button",{type:"button",className:"mc-btn",onClick:()=>h(),children:t("refresh")})]}),M==="cards"&&(0,e.jsx)("div",{className:"mc-chips",children:me.map(p=>(0,e.jsx)("button",{type:"button",className:`mc-chip${k===p?" active":""}`,onClick:()=>x(p),children:t(p==="all"?"all":_[p])},p))}),D&&(0,e.jsxs)("div",{className:"mc-empty",children:[t("error"),"\uFF1A",D]}),M==="cards"?l&&!N.length?(0,e.jsx)("div",{className:"mc-empty",children:t("loading")}):N.length===0?(0,e.jsx)("div",{className:"mc-empty",children:t("empty")}):(0,e.jsx)("div",{className:"mc-grid",children:N.map(p=>(0,e.jsx)(he,{card:p,t,onOpen:T},p.path))}):(0,e.jsx)(ye,{t,onOpen:T}),P&&(0,e.jsx)(be,{t,card:P,onClose:()=>A(null)})]})]})}var X=({label:t,value:r})=>(0,e.jsxs)("div",{className:"mc-stat mc-card",children:[(0,e.jsx)("b",{children:r}),(0,e.jsx)("span",{children:t})]}),he=({card:t,t:r,onOpen:n})=>(0,e.jsxs)("article",{className:"mc-cardrow mc-card",onClick:()=>n(t),children:[(0,e.jsxs)("h4",{children:[(0,e.jsx)("span",{className:"mc-kind",style:{background:I[t.kind]||I.other}}),t.title]}),(0,e.jsx)("p",{children:t.summary||""}),t.tags.length>0&&(0,e.jsx)("div",{className:"mc-tags",children:t.tags.slice(0,4).map(o=>(0,e.jsx)("span",{className:"mc-tag",children:o},o))}),(0,e.jsxs)("footer",{children:[(0,e.jsx)("span",{children:r(_[t.kind])}),(0,e.jsx)("span",{children:Ce(t.updated)})]})]});function be({t,card:r,onClose:n}){return(0,c.useEffect)(()=>{let o=d=>{d.key==="Escape"&&n()};return window.addEventListener("keydown",o),()=>window.removeEventListener("keydown",o)},[n]),(0,e.jsxs)("div",{className:"me-overlay",onClick:n,children:[(0,e.jsx)("style",{children:Y}),(0,e.jsxs)("div",{className:"me-dialog",onClick:o=>o.stopPropagation(),children:[(0,e.jsxs)("div",{className:"me-dialog-head",children:[(0,e.jsx)("h3",{children:r.title}),(0,e.jsx)("button",{type:"button",className:"mc-btn",onClick:n,children:t("close")})]}),(0,e.jsx)("div",{className:"me-dialog-body",children:r.text})]})]})}function ye({t,onOpen:r}){let[n,o]=(0,c.useState)(null),[d,N]=(0,c.useState)("");return(0,c.useEffect)(()=>{let g=!0;return fetch(`${U}/graph`).then(l=>l.json()).then(l=>{g&&o(l.ok?l:null)}).catch(l=>{g&&N(String(l&&l.message?l.message:l))}),()=>{g=!1}},[]),(0,e.jsxs)("div",{className:"me-graph",children:[(0,e.jsx)("style",{children:Y}),d&&(0,e.jsxs)("div",{className:"mc-empty",children:[t("error"),"\uFF1A",d]}),!n&&!d&&(0,e.jsx)("div",{className:"mc-empty",children:t("loading")}),n&&n.nodes.length===0&&(0,e.jsx)("div",{className:"mc-empty",children:t("emptyGraph")}),n&&n.nodes.length>0&&(0,e.jsx)(ve,{nodes:n.nodes,edges:n.edges,onOpen:r,t,countLabel:`${n.nodes.length} ${t("nodes")} \xB7 ${xe(n.edges)} ${t("edges")}`})]})}function xe(t){let r=new Set;for(let n of t||[])r.add([n.source,n.target].sort().join("|"));return r.size}function ve({nodes:t,edges:r,onOpen:n,t:o,countLabel:d}){let l=(0,c.useRef)(null),z=(0,c.useRef)(null),D=(0,c.useRef)(null),j=(0,c.useRef)(null),k=(0,c.useRef)({x:0,y:0,k:1}),C=(0,c.useRef)(null),y=(0,c.useRef)(!1),[u,M]=(0,c.useState)(null),f=(0,c.useMemo)(()=>{let a={};r.forEach(w=>{a[w.source]=(a[w.source]||0)+1,a[w.target]=(a[w.target]||0)+1});let s=420,m=900,b=t,S=!1;t.length>s&&(b=[...t].sort((w,K)=>(a[K.id]||0)-(a[w.id]||0)).slice(0,s),S=!0);let R=new Set(b.map(w=>w.id)),B=new Set,O=[];r.forEach(w=>{if(!R.has(w.source)||!R.has(w.target))return;let K=[w.source,w.target].sort().join("|");B.has(K)||(B.add(K),O.push(w))}),O.sort((w,K)=>(a[w.source]||0)+(a[w.target]||0)-((a[K.source]||0)+(a[K.target]||0)));let F=Math.min(b.length,28),J=b.map(w=>a[w.id]||0).sort((w,K)=>K-w),ee=F>0?J[F-1]:1/0;return{list:b,es:O.slice(0,m),capped:S,maxDeg:Math.max(1,...Object.values(a)),deg:a,hubMin:ee}},[t,r]),P=(0,c.useMemo)(()=>we(f.list,f.es,980,620),[f.list,f.es,980,620]),A=(0,c.useMemo)(()=>f.list.reduce((a,s,m)=>(a[s.id]=m,a),{}),[f.list]),L=(0,c.useMemo)(()=>{let a={};return f.list.forEach(s=>{a[s.id]=new Set}),f.es.forEach(s=>{a[s.source]&&a[s.source].add(s.target),a[s.target]&&a[s.target].add(s.source)}),a},[f.list,f.es]),E=(0,c.useCallback)(()=>{let a=D.current;if(!a)return;let{x:s,y:m,k:b}=k.current;a.setAttribute("transform",`translate(${s} ${m}) scale(${b})`),j.current&&j.current.classList.toggle("all",b>=1.4)},[]);(0,c.useEffect)(()=>{E()},[E,P]);let h=(0,c.useCallback)((a,s)=>{let m=z.current;if(!m||typeof m.getScreenCTM!="function")return{x:a,y:s};let b=m.getScreenCTM();if(!b)return{x:a,y:s};let S=new DOMPoint(a,s).matrixTransform(b.inverse());return{x:S.x,y:S.y}},[]),i=(0,c.useCallback)((a,s)=>{let m=k.current,b=Math.min(5,Math.max(.25,m.k*s));k.current={k:b,x:a.x-b/m.k*(a.x-m.x),y:a.y-b/m.k*(a.y-m.y)},E()},[E]);(0,c.useEffect)(()=>{let a=l.current;if(!a)return;let s=m=>{m.preventDefault(),i(h(m.clientX,m.clientY),m.deltaY<0?1.12:1/1.12)};return a.addEventListener("wheel",s,{passive:!1}),()=>a.removeEventListener("wheel",s)},[h,i]);let x=a=>{if(a.button!==0)return;let s=h(a.clientX,a.clientY);C.current={px:s.x,py:s.y,tx:k.current.x,ty:k.current.y,started:!1,id:a.pointerId},y.current=!1},T=a=>{let s=C.current;if(!s)return;let m=h(a.clientX,a.clientY);Math.abs(m.x-s.px)+Math.abs(m.y-s.py)>1.5&&(y.current=!0,!s.started&&l.current&&l.current.setPointerCapture&&(l.current.setPointerCapture(a.pointerId),s.started=!0),l.current&&l.current.classList.add("dragging"),k.current={...k.current,x:s.tx+(m.x-s.px),y:s.ty+(m.y-s.py)},E())},p=()=>{C.current=null,l.current&&l.current.classList.remove("dragging")},$=a=>{n({path:a.id,title:a.title})},v=a=>{y.current||M(a.id)},G=a=>7+Math.min(9,(f.deg[a.id]||0)/f.maxDeg*9);return(0,e.jsxs)("div",{className:"me-graph",children:[(0,e.jsxs)("div",{className:"me-graph-toolbar",children:[(0,e.jsx)("span",{className:"me-graph-count",children:d}),u&&(0,e.jsx)("button",{type:"button",className:"mc-btn",onClick:()=>M(null),children:o("clearFocus")}),(0,e.jsx)("span",{className:"spacer",style:{flex:1}}),(0,e.jsx)("button",{type:"button",className:"mc-btn",onClick:()=>i({x:980/2,y:620/2},1/1.25),"aria-label":o("zoomOut"),children:"\u2212"}),(0,e.jsx)("button",{type:"button",className:"mc-btn",onClick:()=>{k.current={x:0,y:0,k:1},E()},"aria-label":o("fit"),children:o("fit")}),(0,e.jsx)("button",{type:"button",className:"mc-btn",onClick:()=>i({x:980/2,y:620/2},1.25),"aria-label":o("zoomIn"),children:"+"})]}),(0,e.jsxs)("div",{className:"me-graph-canvas",ref:l,onPointerDown:x,onPointerMove:T,onPointerUp:p,onPointerLeave:p,onContextMenu:a=>{a.preventDefault(),M(null)},onClick:a=>{y.current||M(null)},children:[(0,e.jsxs)("svg",{ref:z,viewBox:"0 0 980 620",role:"img",children:[(0,e.jsxs)("defs",{children:[Object.keys(I).map(a=>(0,e.jsxs)("radialGradient",{id:`me-grad-${a}`,cx:"35%",cy:"30%",r:"75%",children:[(0,e.jsx)("stop",{offset:"0%",stopColor:Me(I[a],.55)}),(0,e.jsx)("stop",{offset:"60%",stopColor:I[a]}),(0,e.jsx)("stop",{offset:"100%",stopColor:$e(I[a],.25)})]},a)),Object.keys(I).map(a=>(0,e.jsxs)("linearGradient",{id:`me-edge-${a}`,gradientUnits:"userSpaceOnUse",children:[(0,e.jsx)("stop",{offset:"0%",stopColor:I[a],stopOpacity:"0.4"}),(0,e.jsx)("stop",{offset:"100%",stopColor:I[a],stopOpacity:"0.85"})]},`e-${a}`)),(0,e.jsxs)("filter",{id:"me-glow",x:"-60%",y:"-60%",width:"220%",height:"220%",children:[(0,e.jsx)("feGaussianBlur",{stdDeviation:"3.2",result:"b"}),(0,e.jsxs)("feMerge",{children:[(0,e.jsx)("feMergeNode",{in:"b"}),(0,e.jsx)("feMergeNode",{in:"SourceGraphic"})]})]})]}),(0,e.jsxs)("g",{ref:D,transform:"translate(0 0) scale(1)",children:[f.es.map((a,s)=>{let m=A[a.source],b=A[a.target];if(m===void 0||b===void 0)return null;let S=P[m],R=P[b];if(!S||!R)return null;let B=f.list[m].kind||"other",O=u&&a.source!==u&&a.target!==u,F=u&&(a.source===u||a.target===u);return(0,e.jsx)("path",{d:Ne(S,R),className:`me-graph-edge${O?" dim":""}${F?" focus":""}`,style:{stroke:`url(#me-edge-${B})`,animationDelay:`${s%8*.12}s`}},`e${s}`)}),f.list.map((a,s)=>{let m=P[s];if(!m)return null;let b=a.kind||"other",S=G(a),R=u&&a.id!==u&&!L[a.id].has(u),B=u&&(a.id===u||L[a.id].has(u));return(0,e.jsxs)("g",{className:`me-graph-node in${B?" focus":""}${R?" dim":""}`,style:{animationDelay:`${s*.02}s`},transform:`translate(${m.x} ${m.y})`,onClick:O=>{O.stopPropagation(),v(a)},onContextMenu:O=>{O.preventDefault(),O.stopPropagation(),$(a)},children:[(0,e.jsx)("circle",{className:"inner",r:S,fill:`url(#me-grad-${b})`,stroke:I[b],strokeOpacity:"0.9",filter:"url(#me-glow)"}),(0,e.jsx)("circle",{r:Math.max(2.4,S*.2),fill:"rgba(255,255,255,0.85)"})]},a.id)}),(0,e.jsx)("g",{ref:j,className:"me-labels",children:f.list.map((a,s)=>{let m=P[s];if(!m)return null;let b=G(a),S=(f.deg[a.id]||0)>=f.hubMin,R=u&&a.id!==u&&!L[a.id].has(u);return(0,e.jsx)("text",{className:`${S?"me-nodelabel":"me-nodelabel minor"}${R?" dim":""}`,x:m.x+b+7,y:m.y+4,children:String(a.title||"").slice(0,16)},`l${a.id}`)})})]})]}),(0,e.jsxs)("div",{className:"me-graph-legend",children:[Object.keys(I).map(a=>(0,e.jsxs)("span",{className:"lg",children:[(0,e.jsx)("span",{className:"mc-kind",style:{background:I[a]}}),o(_[a])]},a)),(0,e.jsx)("span",{className:"me-graph-hint",children:o("graphHint")})]})]}),(0,e.jsxs)("div",{className:"me-graph-tip",children:[f.capped?`${o("capped")} ${f.list.length} / ${t.length} ${o("nodes")} \xB7 `:"",o("graphTip")]})]})}function we(t,r,n,o){let d=t.length;if(d===0)return[];if(d>160)return ke(t,n,o);let N=d<60?260:d<120?180:120,g=t.map((h,i)=>{let x=i/d*Math.PI*2-Math.PI/2;return{x:Math.cos(x),y:Math.sin(x)}}),l=g.map(()=>({x:0,y:0})),z=t.map(()=>[]);r.forEach(h=>{let i=t.findIndex(T=>T.id===h.source),x=t.findIndex(T=>T.id===h.target);i>=0&&x>=0&&i!==x&&(z[i].push(x),z[x].push(i))});let D=1.35,j=.035,k=.03,C=.84;for(let h=0;h<N;h++){for(let i=0;i<d;i++)for(let x=i+1;x<d;x++){let T=g[i].x-g[x].x,p=g[i].y-g[x].y,$=T*T+p*p||.01,v=Math.sqrt($),G=D/$,a=T/v*G,s=p/v*G;l[i].x+=a,l[i].y+=s,l[x].x-=a,l[x].y-=s}for(let i=0;i<d;i++)for(let x of z[i])l[i].x+=(g[x].x-g[i].x)*j,l[i].y+=(g[x].y-g[i].y)*j;for(let i=0;i<d;i++)l[i].x-=g[i].x*k,l[i].y-=g[i].y*k;for(let i=0;i<d;i++)l[i].x=Math.max(-.5,Math.min(.5,l[i].x*C)),l[i].y=Math.max(-.5,Math.min(.5,l[i].y*C)),g[i].x+=l[i].x,g[i].y+=l[i].y}let y=1/0,u=-1/0,M=1/0,f=-1/0;g.forEach(h=>{y=Math.min(y,h.x),u=Math.max(u,h.x),M=Math.min(M,h.y),f=Math.max(f,h.y)});let P=70,A=Math.min((n-2*P)/(u-y||1),(o-2*P)/(f-M||1)),L=(y+u)/2,E=(M+f)/2;return g.map(h=>({x:n/2+(h.x-L)*A,y:o/2+(h.y-E)*A}))}function ke(t,r,n){let o=t.length,d=r/2,N=n/2,g=Math.min(r,n)/2-80,l={};t.forEach((k,C)=>{let y=k.kind||"other";(l[y]=l[y]||[]).push(C)});let z=Object.keys(l),D=new Array(o),j=-Math.PI/2;for(let k of z){let C=l[k],y=C.length/o*Math.PI*2,u=j;C.forEach((M,f)=>{let P=C.length===1?u+y/2:u+y*(f+.5)/C.length;D[M]={x:d+g*Math.cos(P),y:N+g*Math.sin(P)}}),j+=y}return D}function Ne(t,r){let n=(t.x+r.x)/2,o=(t.y+r.y)/2,d=r.x-t.x,N=r.y-t.y,g=Math.sqrt(d*d+N*N)||1,l=Math.min(38,g*.18),z=n-N/g*l,D=o+d/g*l;return`M ${t.x} ${t.y} Q ${z} ${D} ${r.x} ${r.y}`}function Q(t){let r=t.replace("#",""),n=r.length===3?r.split("").map(o=>o+o).join(""):r;return[parseInt(n.slice(0,2),16),parseInt(n.slice(2,4),16),parseInt(n.slice(4,6),16)]}function Me(t,r){let[n,o,d]=Q(t);return`rgb(${Math.round(n+(255-n)*r)}, ${Math.round(o+(255-o)*r)}, ${Math.round(d+(255-d)*r)})`}function $e(t,r){let[n,o,d]=Q(t);return`rgb(${Math.round(n*(1-r))}, ${Math.round(o*(1-r))}, ${Math.round(d*(1-r))})`}function Ce(t){if(!t)return"";let r=new Date(t);if(Number.isNaN(r.getTime()))return"";let n=new Date,o=r.toDateString()===n.toDateString(),d=g=>String(g).padStart(2,"0"),N=`${d(r.getHours())}:${d(r.getMinutes())}`;return o?N:`${r.getMonth()+1}-${r.getDate()} ${N}`}
|
|
92
92
|
|
|
93
93
|
return module.exports;
|
|
94
94
|
},
|
package/lib/vault.js
CHANGED
|
@@ -11,16 +11,18 @@
|
|
|
11
11
|
import { promises as fs } from 'node:fs'
|
|
12
12
|
import path from 'node:path'
|
|
13
13
|
|
|
14
|
-
/**
|
|
14
|
+
/** 主题目录根。 */
|
|
15
15
|
export const KIND_ROOTS = {
|
|
16
16
|
project: '02-Projects',
|
|
17
17
|
knowledge: '03-Knowledge',
|
|
18
18
|
content: '04-Content',
|
|
19
19
|
prompt: '05-Prompts',
|
|
20
20
|
business: '06-Business',
|
|
21
|
+
tool: '07-Tools',
|
|
22
|
+
mistake: '08-Mistakes',
|
|
21
23
|
}
|
|
22
24
|
|
|
23
|
-
export const CAPTURE_KINDS = ['project', 'knowledge', 'content', 'prompt', 'business']
|
|
25
|
+
export const CAPTURE_KINDS = ['project', 'knowledge', 'content', 'prompt', 'business', 'tool', 'mistake']
|
|
24
26
|
|
|
25
27
|
/** 从 Markdown 文本提取 frontmatter 与正文。 */
|
|
26
28
|
export function parseCard(text) {
|
|
@@ -174,7 +176,7 @@ async function walkMd(dir) {
|
|
|
174
176
|
return out
|
|
175
177
|
}
|
|
176
178
|
|
|
177
|
-
/** 确保 vault 目录结构存在(00-System + 02-
|
|
179
|
+
/** 确保 vault 目录结构存在(00-System + 02-08)。 */
|
|
178
180
|
export async function ensureVault(root) {
|
|
179
181
|
await fs.mkdir(path.join(root, '00-System'), { recursive: true })
|
|
180
182
|
for (const dir of Object.values(KIND_ROOTS)) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-memory-eternal",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.5",
|
|
4
4
|
"description": "记忆核心(Memory Eternal):自研的 DeepSeek Harness 记忆插件,不移植任何既有记忆框架——对话结束后自动沉淀知识卡到本地 Markdown Vault(自研去重、自研 CJK 检索、可 git 管理),设置页提供图形化知识库(统计 / 搜索 / 知识图谱 + 侧边栏一键弹窗),Agent 通过 memory_recall 工具按需召回历史上下文。零人工干预。",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|