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 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` 同款插件机制,`npx @deepseek-ai/dsh plugin add dsh-memory-eternal` 即可 |
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
- npx @deepseek-ai/dsh plugin --profile web add dsh-memory-eternal
55
+ dsh plugin --profile web add dsh-memory-eternal
56
56
 
57
57
  # 从 GitHub
58
- npx @deepseek-ai/dsh plugin --profile web add github:EternalNight996/dsh-memory-eternal
58
+ dsh plugin --profile web add github:EternalNight996/dsh-memory-eternal
59
59
 
60
60
  # 本地联调(link 本地目录,改代码即时生效)
61
- npx @deepseek-ai/dsh plugin --profile web add F:/MyApp/eternal/dsh-memory-eternal
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-06 对应目录
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
- └── 06-Business/ # 业务 / 商业
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 筛选(全部/项目/知识/内容/提示词/业务),点击卡片阅读全文(frontmatter 一并展示)
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-06 分类 + frontmatter)
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-06 分类 + frontmatter)、CJK 检索、自研知识图谱、设置页图形化知识库。
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"],L={project:"#3b82f6",knowledge:"#22c55e",content:"#f43f5e",prompt:"#06b6d4",business:"#eab308",other:"#8b5cf6"},_={project:"kindProject",knowledge:"kindKnowledge",content:"kindContent",prompt:"kindPrompt",business:"kindBusiness",other:"kindKnowledge"},Y=`
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
- /** boujoy 一致的主题目录根。 */
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-06)。 */
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",
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": {