memory-eternal 0.14.2 → 0.14.3

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.
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://anthropic.com/claude-code/plugin.schema.json",
3
3
  "name": "memory-eternal",
4
- "version": "0.14.2",
4
+ "version": "0.14.3",
5
5
  "description": "记忆核心(Memory Eternal):对话结束后自动沉淀知识卡到本地记忆库(~/.dsh/memory-vault),支持检索 / 召回 / 审核中心。",
6
6
  "author": {
7
7
  "name": "EternalNight996",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "memory-eternal",
3
- "version": "0.14.2",
3
+ "version": "0.14.3",
4
4
  "description": "记忆核心(Memory Eternal):对话结束后自动沉淀知识卡到本地记忆库(~/.dsh/memory-vault),支持检索 / 召回 / 审核中心。",
5
5
  "author": {
6
6
  "name": "EternalNight996",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "memory-eternal",
3
- "version": "0.14.2",
3
+ "version": "0.14.3",
4
4
  "description": "记忆核心(Memory Eternal):对话结束后自动沉淀知识卡到本地记忆库(~/.dsh/memory-vault),支持检索 / 召回 / 审核中心。",
5
5
  "author": {
6
6
  "name": "EternalNight996",
package/README.en.md CHANGED
@@ -20,7 +20,7 @@
20
20
  <p align="center">
21
21
  <img src="https://img.shields.io/badge/DeepSeek%20Harness-plugin-3B82F6" alt="DSH plugin" />
22
22
  <img src="https://img.shields.io/npm/v/memory-eternal" alt="npm version" />
23
- <img src="https://img.shields.io/badge/release-v0.14.2-FF7A45" alt="v0.14.2" />
23
+ <img src="https://img.shields.io/badge/release-v0.14.3-FF7A45" alt="v0.14.3" />
24
24
  <a href="https://eternalnight996.github.io/memory-eternal/"><img src="https://img.shields.io/badge/Live%20Demo-online-FF7A45" alt="Live demo" /></a>
25
25
  <img src="https://img.shields.io/github/stars/EternalNight996/memory-eternal?style=flat" alt="GitHub stars" />
26
26
  <img src="https://img.shields.io/github/license/EternalNight996/memory-eternal" alt="license" />
@@ -95,7 +95,7 @@ dsh-memory tui --live --write # write: real approve / reject
95
95
 
96
96
  If `dsh-memory` is not on PATH, use the `npx` command above; it downloads and runs the current npm version.
97
97
 
98
- > The `tui` subcommand ships in **0.14.1+**. An older CLI prints help; upgrade with `npm i -g --force memory-eternal@0.14.2`.
98
+ > The `tui` subcommand ships in **0.14.1+**. An older CLI prints help; upgrade with `npm i -g --force memory-eternal@0.14.3`.
99
99
 
100
100
  ### What is inside
101
101
 
@@ -176,7 +176,7 @@ cd ~/.dsh/profiles/web && pnpm add memory-eternal@latest
176
176
  # right after a release, @latest can be held back by pnpm's minimum-release-age gate or a cached
177
177
  # packument (it silently stays on the old version): pin the version instead — pnpm adds it to the
178
178
  # workspace's minimumReleaseAgeExclude automatically
179
- cd ~/.dsh/profiles/web && pnpm add memory-eternal@0.14.2
179
+ cd ~/.dsh/profiles/web && pnpm add memory-eternal@0.14.3
180
180
 
181
181
  # verify the version, then restart the host
182
182
  node -e "console.log(require('memory-eternal/package.json').version)"
@@ -485,14 +485,15 @@ curl http://127.0.0.1:7999/memory-eternal/api/web-info # is the standalone we
485
485
 
486
486
  | Version | Date | Highlights |
487
487
  |---|---|---|
488
+ | **v0.14.3** | 2026-10-23 | **Live data across the whole TUI**: `--live` now loads the real library (paginated), graph nodes/edges, runtime totals/backups/version and recycle bin; the library/graph/status pages no longer show fake 999 nodes, 0.12.0 or demo logs. Review stays on the real queue, and cards are fetched with their real status. |
488
489
  | **v0.14.2** | 2026-10-23 | **Live empty-queue fix**: `dsh-memory tui --live` no longer falls back to sample data when the real pending queue is empty; it stays in LIVE mode and shows the empty state. The path-free npx entry and the 0.14.1 old-global-CLI upgrade note remain. |
489
- | **v0.14.1** | 2026-10-23 | **Portable terminal entry**: new `dsh-memory tui --live` lets any installed user launch the full terminal client without `cd`-ing into the repo or hard-coding a local path; the Web terminal page now shows the same read-only/write commands. |
490
490
 
491
491
  <details>
492
492
  <summary>Older release notes (v0.10.52 and earlier · 79 releases, click to expand)</summary>
493
493
 
494
494
  | Version | Date | Highlights |
495
495
  |---|---|---|
496
+ | **v0.14.1** | 2026-10-23 | **Portable terminal entry**: new `dsh-memory tui --live` lets any installed user launch the full terminal client without `cd`-ing into the repo or hard-coding a local path; the Web terminal page now shows the same read-only/write commands. |
496
497
  | **v0.14.0** | 2026-10-23 | **Web terminal entry + fresh screenshots**: the library rail gains a Terminal page with copy-ready commands, the dsh-tui `/audit` guide and a terminal preview, so terminal-only features are discoverable from the Web UI; README adds real screenshots for the terminal audit, long-form reader and Web terminal page; the native dsh-tui `/audit` scene ships. |
497
498
  | **v0.13.0** | 2026-10-23 | **Full TUI + native dsh-tui audit**: the terminal client now covers library, audit, graph, status, recycle, settings, long-form reader and search; audit gains select-all and batch approve/reject; `--live` talks to the local API (read-only by default, `--write` to mutate); a native dsh-tui `/audit` scene replaces the browser-only entry. |
498
499
  | **v0.12.0** | 2026-10-22 | **Cross-host launchers**: Orca right-sidebar Memory panel, dsh-tui `/memory`, Codex / Claude `memory-open` skill, and a Cursor / VS Code Webview extension; README gains a platform support table; one Web UI stays the single source of truth — Webview where it works, a thin launcher everywhere else, with no new agent permissions. |
package/README.md CHANGED
@@ -20,7 +20,7 @@
20
20
  <p align="center">
21
21
  <img src="https://img.shields.io/badge/DeepSeek%20Harness-plugin-3B82F6" alt="DSH plugin" />
22
22
  <img src="https://img.shields.io/npm/v/memory-eternal" alt="npm version" />
23
- <img src="https://img.shields.io/badge/release-v0.14.2-FF7A45" alt="v0.14.2" />
23
+ <img src="https://img.shields.io/badge/release-v0.14.3-FF7A45" alt="v0.14.3" />
24
24
  <a href="https://eternalnight996.github.io/memory-eternal/"><img src="https://img.shields.io/badge/Live%20Demo-online-FF7A45" alt="Live demo" /></a>
25
25
  <img src="https://img.shields.io/github/stars/EternalNight996/memory-eternal?style=flat" alt="GitHub stars" />
26
26
  <img src="https://img.shields.io/github/license/EternalNight996/memory-eternal" alt="license" />
@@ -95,7 +95,7 @@ dsh-memory tui --live --write # 写入:允许真实批准/驳回
95
95
 
96
96
  `dsh-memory` 不在 PATH 时,直接用上面的 `npx` 命令;它会临时下载并运行当前 npm 版本。
97
97
 
98
- > `tui` 子命令从 **0.14.1** 开始提供。旧版 `dsh-memory` 会显示帮助;升级:`npm i -g --force memory-eternal@0.14.2`。
98
+ > `tui` 子命令从 **0.14.1** 开始提供。旧版 `dsh-memory` 会显示帮助;升级:`npm i -g --force memory-eternal@0.14.3`。
99
99
 
100
100
  ### 终端版包含
101
101
 
@@ -176,7 +176,7 @@ cd ~/.dsh/profiles/web && pnpm add memory-eternal@latest
176
176
 
177
177
  # 刚发新版时 @latest 可能被 pnpm 的最小发布年龄门槛/元数据缓存挡住(静默停在旧版):
178
178
  # 直接指定版本号最快,pnpm 会自动把它加进 workspace 的 minimumReleaseAgeExclude
179
- cd ~/.dsh/profiles/web && pnpm add memory-eternal@0.14.2
179
+ cd ~/.dsh/profiles/web && pnpm add memory-eternal@0.14.3
180
180
 
181
181
  # 验版本(应等于上面装的号),然后重启对应宿主生效
182
182
  node -e "console.log(require('memory-eternal/package.json').version)"
@@ -518,14 +518,15 @@ curl http://127.0.0.1:7999/memory-eternal/api/web-info # 独立 web 是否活
518
518
 
519
519
  | 版本 | 日期 | 关键改动 |
520
520
  |---|---|---|
521
+ | **v0.14.3** | 2026-10-23 | **终端实时数据全页打通**:`--live` 现在同时加载真实记忆库(全量分页)、知识星图节点/连线、运行状态总数/备份/版本、回收站;不再在记忆库/星图/状态页显示 999 节点、0.12.0、示例日志等假数据;待审仍为真实队列,读卡按卡状态请求正文。 |
521
522
  | **v0.14.2** | 2026-10-23 | **实时空队列修复**:`dsh-memory tui --live` 在真实待审为 0 时不再回退示例数据,显示 LIVE 空队列;同时保留 `npx -p memory-eternal dsh-memory tui --live` 的免路径入口与 0.14.1 的旧全局 CLI 升级提示。 |
522
- | **v0.14.1** | 2026-10-23 | **终端入口免绝对路径**:新增 `dsh-memory tui --live`,任意用户安装插件后可直接运行完整终端客户端,无需 `cd` 到仓库或填写本机绝对路径;Web 终端页同步改为只读/写入两条通用命令。 |
523
523
 
524
524
  <details>
525
525
  <summary>更早的更新日志(v0.10.52 及以前 · 共 79 版,点开查看)</summary>
526
526
 
527
527
  | 版本 | 日期 | 关键改动 |
528
528
  |---|---|---|
529
+ | **v0.14.1** | 2026-10-23 | **终端入口免绝对路径**:新增 `dsh-memory tui --live`,任意用户安装插件后可直接运行完整终端客户端,无需 `cd` 到仓库或填写本机绝对路径;Web 终端页同步改为只读/写入两条通用命令。 |
529
530
  | **v0.14.0** | 2026-10-23 | **Web 终端入口 + 新功能截图**:记忆库左栏新增「终端版」,内置运行命令、dsh-tui `/audit` 引导与终端预览,解决 Web 无法展示 TUI 的问题;README 新增终端审核、长文读卡器和 Web 终端页真实截图;dsh-tui 原生 `/audit` 正式接入。 |
530
531
  | **v0.13.0** | 2026-10-23 | **完整 TUI + dsh-tui 原生审核**:终端客户端补齐记忆库、待审、星图、运行状态、回收站、设置、长文读卡器与搜索;待审支持全选/批量批驳;`--live` 直连本地 API(默认只读,`--write` 才写);新增 dsh-tui 原生 `/audit` 场景,不再只是打开浏览器。 |
531
532
  | **v0.12.0** | 2026-10-22 | **跨宿主入口**:Orca 右侧栏「记忆」启动器、dsh-tui `/memory` 命令、Codex / Claude `memory-open` skill、Cursor / VS Code Webview 扩展;README 新增平台支持表;坚持一套 Web UI 唯一真源,能内嵌的用 Webview,不能内嵌的只做启动器;不新增 agent 权限。 |
@@ -2,7 +2,7 @@
2
2
  "name": "memory-eternal",
3
3
  "displayName": "Memory Atlas",
4
4
  "description": "Memory-eternal: open the local Memory Atlas library, review queue and knowledge graph in a Cursor/VS Code webview.",
5
- "version": "0.14.2",
5
+ "version": "0.14.3",
6
6
  "publisher": "EternalNight996",
7
7
  "license": "MIT",
8
8
  "repository": {
@@ -237,7 +237,8 @@ function panel(title, lines, w, h, accent = C.border) {
237
237
  const kindOf = (c) => KIND[c.kind] || KIND.project
238
238
  const filtered = (state) => {
239
239
  const q = state.query.trim().toLowerCase()
240
- return state.cards.filter((c) => {
240
+ const base = state.screen === 'library' ? (state.libraryCards || state.cards) : state.cards
241
+ return base.filter((c) => {
241
242
  if (state.kind !== 'all' && c.kind !== state.kind) return false
242
243
  if (!q) return true
243
244
  return (c.title + ' ' + c.summary + ' ' + c.tags.join(' ')).toLowerCase().includes(q)
@@ -246,9 +247,10 @@ const filtered = (state) => {
246
247
 
247
248
  function typeRow(state, w) {
248
249
  const labels = [['全部', 'all'], ['项目', 'project'], ['知识', 'knowledge'], ['教训', 'mistake'], ['内容', 'content'], ['工具', 'tool'], ['提示词', 'prompt']]
250
+ const base = state.screen === 'library' ? (state.libraryCards || state.cards) : state.cards
249
251
  const line = sgr(C.faint, '类型 ') + labels.map(([label, key]) => {
250
252
  const active = state.kind === key
251
- const count = key === 'all' ? state.cards.length : state.cards.filter((c) => c.kind === key).length
253
+ const count = key === 'all' ? base.length : base.filter((c) => c.kind === key).length
252
254
  return tone(` ${active ? '●' : '○'} ${label} ${count} `, active ? C.text : C.dim, active ? C.chipBg : '')
253
255
  }).join(' ')
254
256
  return ' ' + clip(line + ' ' + sgr(C.faint, '←→ 类型'), w - 1)
@@ -392,24 +394,49 @@ function readerView(state, w, h) {
392
394
  }
393
395
 
394
396
  function graphView(state, w, h) {
395
- const cluster = [['项目', 417, C.blue], ['知识', 219, C.violet], ['内容', 112, C.pink], ['教训', 185, C.red], ['工具', 51, C.cyan], ['提示词', 12, C.amber]]
396
- const card = filtered(state)[state.index] || CARDS[0]
397
- const lines = [sgr(C.ember, '知识星图'), `${sgr(C.dim, '999 节点 · 4713 连线')}`, '', sgr(C.dim, '连接簇')]
398
- cluster.forEach(([label, n, color]) => lines.push(` ${sgr(color, '●')} ${sgr(C.text, label).padEnd(8)} ${sgr(C.dim, String(n))}`))
399
- lines.push('', sgr(C.border, '─'.repeat(Math.max(1, w - 2))), '', `${sgr(C.dim, '选中')} ${sgr(C.text, card.title)}`, ` ${sgr(C.dim, '↔ 12 张相连')} ${card.tags.map((t) => sgr(C.ember, '#' + t)).join(' ')}`, '', sgr(C.dim, '相关卡片'))
400
- CARDS.filter((c) => c.id !== card.id).slice(0, 4).forEach((r) => lines.push(`${sgr(kindOf(r).color, '→')} ${sgr(C.dim, r.title)}`))
397
+ const data = state.graphData
398
+ const nodes = Array.isArray(data?.nodes) ? data.nodes : []
399
+ const edges = Array.isArray(data?.edges) ? data.edges : []
400
+ const node = nodes[state.graphIndex] || nodes[0]
401
+ const counts = {}
402
+ for (const n of nodes) counts[n.kind] = (counts[n.kind] || 0) + 1
403
+ const labels = [['项目', 'project', C.blue], ['知识', 'knowledge', C.violet], ['内容', 'content', C.pink], ['教训', 'mistake', C.red], ['工具', 'tool', C.cyan], ['提示词', 'prompt', C.amber]]
404
+ const lines = [sgr(C.ember, '知识星图'), `${sgr(C.dim, `${nodes.length} 节点 · ${edges.length} 连线`)}`, '', sgr(C.dim, '连接簇')]
405
+ labels.forEach(([label, key, color]) => lines.push(` ${sgr(color, '●')} ${sgr(C.text, label).padEnd(8)} ${sgr(C.dim, String(counts[key] || 0))}`))
406
+ lines.push('', sgr(C.border, '─'.repeat(Math.max(1, w - 2))), '', `${sgr(C.dim, '选中')} ${sgr(C.text, node?.title || '暂无节点')}`)
407
+ if (node) {
408
+ const rel = []
409
+ for (const e of edges) {
410
+ if (e.source === node.id) rel.push(e.target)
411
+ else if (e.target === node.id) rel.push(e.source)
412
+ }
413
+ const byId = new Map(nodes.map((n) => [n.id, n]))
414
+ lines.push(` ${sgr(C.dim, `↔ ${rel.length} 张相连`)} ${(node.tags || []).slice(0, 4).map((t) => sgr(C.ember, '#' + t)).join(' ')}`, '', sgr(C.dim, '相关卡片'))
415
+ rel.slice(0, 4).forEach((id) => {
416
+ const r = byId.get(id)
417
+ if (r) lines.push(`${sgr(kindOf(r).color, '→')} ${sgr(C.dim, r.title)}`)
418
+ })
419
+ }
401
420
  return [panel('知识星图', lines, w, h, C.violet)]
402
421
  }
403
422
 
404
423
  function statusView(state, w, h) {
424
+ const o = state.overview
425
+ const total = o?.total ?? state.libraryCards?.length ?? 0
426
+ const backups = o?.backups?.count ?? 0
427
+ const version = o?.version || '—'
428
+ const pending = o?.quarantine?.pending ?? state.cards.length
429
+ const rejected = o?.quarantine?.rejected ?? 0
430
+ const deleted = o?.quarantine?.deleted ?? state.recycle.length
431
+ const recent = o?.recent ?? 0
432
+ const dbOk = o?.db?.writable !== false
405
433
  const lines = [
406
- `${sgr(C.ember, '●')} ${sgr(C.text, '记忆库')} ${sgr(C.amber, '999')} ${sgr(C.dim, '备份')} ${sgr(C.text, '7')} ${sgr(C.dim, '版本')} ${sgr(C.text, '0.12.0')}`,
407
- `${sgr(C.green, '●')} ${sgr(C.text, '自动沉淀')} ${sgr(C.green, '正常')} ${sgr(C.dim, '上次')} ${sgr(C.text, '18:20')} ${sgr(C.dim, '队列')} ${sgr(C.text, '0')}`,
408
- '', sgr(C.border, '─'.repeat(Math.max(1, w - 2))), '', sgr(C.dim, '沉淀日志'),
409
- `${sgr(C.faint, '18:20')} ${sgr(C.green, 'created')} 新卡:Orca 右侧栏启动器`,
410
- `${sgr(C.faint, '18:18')} ${sgr(C.blue, 'listen')} 会话事件 32 条 → 有效 1199 字`,
411
- `${sgr(C.faint, '18:16')} ${sgr(C.faint, 'skip')} 低信号会话,未生成卡片`,
412
- '', sgr(C.dim, '审核'), `${sgr(C.amber, '6')} 张待审 ${sgr(C.dim, '回收站')} 3 张 ${sgr(C.dim, '常驻')} 7999`,
434
+ `${sgr(C.ember, '●')} ${sgr(C.text, '记忆库')} ${sgr(C.amber, String(total))} ${sgr(C.dim, '备份')} ${sgr(C.text, String(backups))} ${sgr(C.dim, '版本')} ${sgr(C.text, version)}`,
435
+ `${sgr(dbOk ? C.green : C.red, '●')} ${sgr(C.text, '数据库')} ${sgr(dbOk ? C.green : C.red, dbOk ? '可写' : '不可写')} ${sgr(C.dim, '近 7 天')} ${sgr(C.text, String(recent))} ${sgr(C.dim, '待审')} ${sgr(C.text, String(pending))}`,
436
+ '', sgr(C.border, '─'.repeat(Math.max(1, w - 2))), '', sgr(C.dim, '队列'),
437
+ `${sgr(C.amber, String(pending))} 张待审 ${sgr(C.red, String(rejected))} 张已驳回 ${sgr(C.dim, String(deleted))} 张回收站`,
438
+ '', sgr(C.dim, '库根目录'), `${sgr(C.text, o?.vaultDir || '示例数据')}`,
439
+ '', sgr(C.faint, '数据来自实时 /overview;没有日志接口时不伪造日志。'),
413
440
  ]
414
441
  return [panel('运行状态', lines, w, h, C.green)]
415
442
  }
@@ -486,7 +513,8 @@ function frame(state) {
486
513
  const rows = Math.max(24, process.stdout.rows || 36)
487
514
  const screen = state.help ? 'help' : state.screen
488
515
  const label = screen === 'help' ? '帮助' : SCREENS[screen]?.label || '记忆库'
489
- const counts = `${sgr(C.amber, String(state.cards.length))} ${sgr(C.dim, '待审')}` + (state.marked.size ? ` ${sgr(C.amber, '已选 ' + state.marked.size)}` : '')
516
+ const totalNow = state.screen === 'library' ? (state.libraryCards || state.cards).length : state.cards.length
517
+ const counts = `${sgr(C.amber, String(totalNow))} ${sgr(C.dim, state.screen === 'library' ? '记忆' : '待审')}` + (state.marked.size ? ` ${sgr(C.amber, '已选 ' + state.marked.size)}` : '')
490
518
  const mode = state.live ? (writeMode ? 'LIVE / WRITE' : 'LIVE / READONLY') : 'LOCAL MEMORY'
491
519
  const title = `${sgr(C.ember, '●')} ${sgr(C.ember, 'MEMORY ATLAS')} ${sgr(C.faint, mode)} ${sgr(C.faint, '/')} ${sgr(C.text, label)}`
492
520
  const right = `${counts} ${keycap('?', '帮助')} ${keycap('q', '退出')}`
@@ -544,6 +572,7 @@ function toLiveCard(c) {
544
572
  time: fmtTime(c.updated || c.created),
545
573
  tags: Array.isArray(c.tags) ? c.tags.slice(0, 5) : [],
546
574
  summary: cleanSummary(c.summary || ''),
575
+ status: c.status || 'pending',
547
576
  body: [],
548
577
  }
549
578
  }
@@ -553,18 +582,44 @@ function parseCardBody(text) {
553
582
  return clean.split(/\r?\n/).map((line) => line.replace(/^#{1,6}\s*/, '').replace(/^\s*[-*]\s+/, '· ').trimEnd())
554
583
  }
555
584
 
585
+ async function loadAllCards(status) {
586
+ const out = []
587
+ let offset = 0
588
+ for (;;) {
589
+ const page = await apiJson(`/cards?status=${status}&limit=500&offset=${offset}`)
590
+ out.push(...(page.cards || []))
591
+ if (!page.cards?.length || out.length >= (page.total || 0)) break
592
+ offset += page.cards.length
593
+ }
594
+ return { cards: out, total: out.length }
595
+ }
596
+
556
597
  async function loadLive(state) {
557
598
  try {
558
- const [cardsData, overview] = await Promise.all([
559
- apiJson('/cards?status=pending&limit=300'),
599
+ const [cardsData, libraryData, overview, graphData, recycleData] = await Promise.all([
600
+ loadAllCards('pending'),
601
+ loadAllCards('approved').catch(() => ({ cards: [] })),
560
602
  apiJson('/overview').catch(() => null),
603
+ apiJson('/graph').catch(() => null),
604
+ apiJson('/recycle/list').catch(() => ({ items: [] })),
561
605
  ])
562
606
  state.cards = cardsData.cards.map(toLiveCard)
607
+ state.libraryCards = libraryData.cards.map(toLiveCard)
563
608
  state.overview = overview
609
+ state.graphData = graphData
610
+ state.recycle = (recycleData.items || []).map((c) => ({
611
+ title: c.title || c.path,
612
+ kind: c.kind || 'knowledge',
613
+ time: fmtTime(c.deletedAt || c.updated || c.created),
614
+ reason: c.reason || '已删除',
615
+ path: c.path,
616
+ }))
564
617
  state.index = 0
565
- if (!state.cards.length) state.toast = { text: '实时队列为空(0 张待审)', ok: true }
566
618
  state.marked.clear()
567
619
  if (selectAllAtStart) state.cards.forEach((c) => state.marked.add(c.id))
620
+ if (!state.cards.length) {
621
+ state.toast = { text: `0 张待审 · 已加载 ${state.libraryCards.length} 张记忆`, ok: true }
622
+ }
568
623
  state.live = true
569
624
  state.liveError = ''
570
625
  } catch (err) {
@@ -582,7 +637,7 @@ async function main() {
582
637
  readerCard: screenArg === 'reader' ? CARDS.find((c) => c.id === 'longform') || CARDS[0] : null,
583
638
  readerBack: 'audit', readerScroll: scrollArg > 0 ? scrollArg : 0, readerMax: 0, recycle: RECYCLE.slice(), recycleIndex: 0,
584
639
  settings: SETTINGS.map((s) => ({ ...s })), settingsIndex: 0, help: screenArg === 'help', toast: null,
585
- live: false, liveError: '', overview: null,
640
+ live: false, liveError: '', overview: null, libraryCards: CARDS.slice(), graphData: null, graphIndex: 0,
586
641
  }
587
642
  if (liveMode) await loadLive(state)
588
643
  if (once) { draw(state); return }
@@ -601,6 +656,22 @@ async function main() {
601
656
  const visible = () => filtered(state)
602
657
  const selectedCard = () => visible()[state.index]
603
658
 
659
+ const recycleAction = async (purge) => {
660
+ const item = state.recycle[state.recycleIndex]
661
+ if (!item) return
662
+ if (state.live && item.path) {
663
+ try {
664
+ await apiJson('/recycle/' + (purge ? 'purge' : 'restore') + '?path=' + encodeURIComponent(item.path))
665
+ } catch (err) {
666
+ toast('操作失败:' + err.message, false)
667
+ return
668
+ }
669
+ }
670
+ state.recycle.splice(state.recycleIndex, 1)
671
+ state.recycleIndex = Math.max(0, state.recycleIndex - 1)
672
+ toast((purge ? '✕ 已彻底删除:' : '✓ 已恢复:') + item.title, !purge)
673
+ }
674
+
604
675
  const removeSelected = async (decision) => {
605
676
  const cards = visible()
606
677
  const targets = state.marked.size ? cards.filter((c) => state.marked.has(c.id)) : (cards[state.index] ? [cards[state.index]] : [])
@@ -628,8 +699,8 @@ async function main() {
628
699
  toast(`${decision === 'a' ? '✓ 已批准' : '✕ 已驳回'} ${targets.length} 张:${targets[0].title}`, decision === 'a')
629
700
  }
630
701
 
631
- const openReader = async () => {
632
- const card = selectedCard()
702
+ const openReader = async (override) => {
703
+ const card = override || selectedCard()
633
704
  if (!card) return
634
705
  state.readerCard = card
635
706
  state.readerBack = state.screen
@@ -638,8 +709,9 @@ async function main() {
638
709
  if (state.live && !card.body.length) {
639
710
  card.body = ['加载正文…']
640
711
  draw(state)
712
+ const status = card.status || (state.readerBack === 'audit' ? 'pending' : 'approved')
641
713
  try {
642
- const data = await apiJson('/card?path=' + encodeURIComponent(card.id) + '&status=pending')
714
+ const data = await apiJson('/card?path=' + encodeURIComponent(card.id) + '&status=' + status)
643
715
  card.body = parseCardBody(data.text)
644
716
  } catch (err) {
645
717
  card.body = ['正文加载失败:' + err.message]
@@ -698,15 +770,19 @@ async function main() {
698
770
  if (state.screen === 'recycle') {
699
771
  if (key.name === 'up' || str === 'k') { state.recycleIndex = Math.max(0, state.recycleIndex - 1); draw(state); return }
700
772
  if (key.name === 'down' || str === 'j') { state.recycleIndex = Math.min(state.recycle.length - 1, state.recycleIndex + 1); draw(state); return }
701
- if (str === 'r' && state.recycle.length) { const [x] = state.recycle.splice(state.recycleIndex, 1); state.recycleIndex = Math.max(0, state.recycleIndex - 1); toast('✓ 已恢复:' + x.title); return }
702
- if (str === 'd' && state.recycle.length) { const [x] = state.recycle.splice(state.recycleIndex, 1); state.recycleIndex = Math.max(0, state.recycleIndex - 1); toast('✕ 已彻底删除:' + x.title, false); return }
773
+ if (str === 'r' && state.recycle.length) { void recycleAction(false); return }
774
+ if (str === 'd' && state.recycle.length) { void recycleAction(true); return }
703
775
  return
704
776
  }
705
777
  if (state.screen === 'graph') {
706
- const cards = visible()
707
- if (key.name === 'up' || str === 'k') { state.index = Math.max(0, state.index - 1); draw(state); return }
708
- if (key.name === 'down' || str === 'j') { state.index = Math.min(Math.max(0, cards.length - 1), state.index + 1); draw(state); return }
709
- if (key.name === 'return' || key.name === 'enter') { openReader(); return }
778
+ const nodes = Array.isArray(state.graphData?.nodes) ? state.graphData.nodes : []
779
+ if (key.name === 'up' || str === 'k') { state.graphIndex = Math.max(0, state.graphIndex - 1); draw(state); return }
780
+ if (key.name === 'down' || str === 'j') { state.graphIndex = Math.min(Math.max(0, nodes.length - 1), state.graphIndex + 1); draw(state); return }
781
+ if (key.name === 'return' || key.name === 'enter') {
782
+ const node = nodes[state.graphIndex]
783
+ if (node) void openReader({ ...node, id: node.id, status: 'approved', body: [] })
784
+ return
785
+ }
710
786
  return
711
787
  }
712
788
  if (state.screen === 'status') return
@@ -2,7 +2,7 @@
2
2
  "$schema": "urn:dsh-std:community-draft:dsh-plugin:0.15",
3
3
  "id": "memory-eternal-tui",
4
4
  "name": "memory-eternal-tui",
5
- "version": "0.14.2",
5
+ "version": "0.14.3",
6
6
  "manifestVersion": "0.15",
7
7
  "description": "Open Memory Atlas from dsh-TUI: native /audit scene plus browser launcher.",
8
8
  "facets": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "memory-eternal-tui",
3
- "version": "0.14.2",
3
+ "version": "0.14.3",
4
4
  "description": "Open Memory Atlas from dsh-TUI with /memory.",
5
5
  "type": "module",
6
6
  "main": "main.js",
package/lib/client.js CHANGED
@@ -701,7 +701,7 @@ Option A, because:
701
701
  .mc-audit-batchcard > .mc-btn { width: 100%; }
702
702
  .mc-audit-batchcard > div[style*="flex: 1"] { display: none; }
703
703
  }
704
- `;function Ea(t){t.effect(()=>t.locale.register(kt,{zh:da,en:ca}),"memory-eternal: locale");let a=t.locale.bind(kt);t.effect(()=>t.slots.inject("settings.section",()=>t.slots.register({name:"settings.section",id:kt,order:25,label:()=>a("nav"),locale:kt,inject:()=>({})},()=>o.default.createElement(Wa,{t:a}))),"memory-eternal: settings section"),t.effect(()=>t.slots.inject("sidebar.footer.action",()=>t.slots.register({name:"sidebar.footer.action",id:`${kt}:footer`,order:100,label:()=>a("nav"),locale:kt,inject:()=>({})},i=>o.default.createElement($a,{t:a,locale:t.locale,wide:!(i&&i.wide===!1)}))),"memory-eternal: sidebar footer action")}function Oa(){let[t,a]=(0,o.useState)($+"/ui/app");return(0,o.useEffect)(()=>{let i=!0,m=()=>fetch("/memory-eternal/api/web-info").then(c=>c.json()).then(c=>{i&&c&&c.ok&&c.alive!==!1&&c.url&&a(c.url.endsWith("/")?c.url:c.url+"/")}).catch(()=>{});return fetch($+"/ui/app",{method:"HEAD"}).then(c=>{if(i&&!c.ok)return m()}).catch(()=>i?m():void 0),()=>{i=!1}},[]),t}function Wa({t}){return(0,e.jsxs)("div",{style:{display:"flex",flexDirection:"column",height:"100%",minHeight:0},children:[(0,e.jsx)("style",{children:Ue}),(0,e.jsx)(ua,{t,onReload:()=>{},version:0})]})}function $a({t,locale:a,wide:i}){let[m,c]=(0,o.useState)(!1);return(0,e.jsxs)("div",{className:`me-footer${i?"":" rail"}`,children:[(0,e.jsx)("style",{children:Ue}),(0,e.jsxs)("button",{type:"button",className:"me-footer-btn",onClick:()=>c(!0),"aria-label":t("nav"),title:t("nav"),children:[(0,e.jsx)("span",{className:"me-footer-ico","aria-hidden":"true",children:(0,e.jsx)(Ua,{})}),(0,e.jsx)("span",{className:"me-footer-label",children:t("nav")})]}),m&&(0,e.jsx)(_a,{t,locale:a,onClose:()=>c(!1)})]})}function _a({t,locale:a,onClose:i,tab:m}){let[c,r]=(0,o.useState)(!1),h=(0,o.useRef)(null),w=Oa(),S=(0,o.useCallback)(T=>a&&typeof a.subscribe=="function"?a.subscribe(T):()=>{},[a]),L=(0,o.useCallback)(()=>a&&typeof a.getSnapshot=="function"?a.getSnapshot():null,[a]),N=(0,o.useSyncExternalStore)(S,L),x=N&&(N.active==="zh"||N.active==="en")?N.active:null,u=(0,o.useRef)(null);u.current===null&&x&&(u.current=x);let z=(0,o.useMemo)(()=>{let T=u.current?`lang=${u.current}`:"";if(m==="config")return`${$}/ui/config?tab=config${T?`&${T}`:""}`;let P=w.replace(/\/$/,""),M=P.endsWith("/ui/app")?"?":"/?";return m?`${P}${M}tab=${m}${T?`&${T}`:""}`:T?`${P}${M}${T}`:w},[w,m]);return(0,o.useEffect)(()=>{let T=h.current&&h.current.contentWindow;T&&x&&T.postMessage({source:"memory-eternal",type:"locale",lang:x},"*")},[x]),(0,o.useEffect)(()=>{let T=P=>{P.key==="Escape"&&i()};return window.addEventListener("keydown",T),()=>window.removeEventListener("keydown",T)},[i]),(0,e.jsxs)("div",{className:"me-overlay-top",onClick:i,children:[(0,e.jsx)("style",{children:Ue}),(0,e.jsx)("div",{className:"me-modal"+(c?" me-modal-full":""),onClick:T=>T.stopPropagation(),children:(0,e.jsxs)("div",{style:{display:"flex",flexDirection:"column",height:"100%",minHeight:0,position:"relative"},children:[(0,e.jsxs)("div",{style:{position:"absolute",top:8,right:8,zIndex:10,display:"flex",gap:4,padding:"4px 6px",background:"var(--dsw-alias-bg-overlay, rgba(17,24,39,0.45))",borderRadius:8,backdropFilter:"blur(4px)"},children:[(0,e.jsx)("button",{type:"button",onClick:()=>r(T=>!T),"aria-label":t(c?"exitFullscreen":"enterFullscreen"),title:t(c?"exitFullscreen":"enterFullscreen"),style:{width:26,height:26,borderRadius:6,border:"1px solid rgba(255,255,255,0.18)",background:"rgba(255,255,255,0.08)",color:"#fff",cursor:"pointer",fontSize:14,lineHeight:1,display:"flex",alignItems:"center",justifyContent:"center"},children:c?"\u2921":"\u2922"}),(0,e.jsx)("button",{type:"button",onClick:i,"aria-label":t("close"),title:t("close"),style:{width:26,height:26,borderRadius:6,border:"1px solid rgba(255,255,255,0.18)",background:"rgba(255,255,255,0.08)",color:"#fff",cursor:"pointer",fontSize:16,lineHeight:1,display:"flex",alignItems:"center",justifyContent:"center"},children:"\xD7"})]}),(0,e.jsx)("iframe",{ref:h,src:z,title:"memory-eternal",allow:"clipboard-write; clipboard-read",style:{width:"100%",flex:1,border:0,borderRadius:"inherit",background:"var(--dsw-alias-bg-base, #fff)"}})]})})]})}function Ua(){return(0,e.jsxs)("svg",{viewBox:"0 0 24 24","aria-hidden":"true",children:[(0,e.jsx)("defs",{children:(0,e.jsxs)("linearGradient",{id:"mg-brain",x1:"0",y1:"0",x2:"1",y2:"1",children:[(0,e.jsx)("stop",{offset:"0%",stopColor:"#FFC46B"}),(0,e.jsx)("stop",{offset:"50%",stopColor:"#F97316"}),(0,e.jsx)("stop",{offset:"100%",stopColor:"#EA580C"})]})}),(0,e.jsx)("path",{fill:"url(#mg-brain)",d:"M12 4.5a3.2 3.2 0 0 0-6.4.1 4.1 4.1 0 0 0-2.7 5.9 4.1 4.1 0 0 0 .6 6.7A4.2 4.2 0 0 0 12 18.2Z"}),(0,e.jsx)("path",{fill:"url(#mg-brain)",d:"M12 4.5a3.2 3.2 0 0 1 6.4.1 4.1 4.1 0 0 1 2.7 5.9 4.1 4.1 0 0 1-.6 6.7A4.2 4.2 0 0 1 12 18.2Z"}),(0,e.jsx)("path",{d:"M12 9.2c-.8-1.4-1.7-2-3.1-2.2M12 9.2c.8-1.4 1.7-2 3.1-2.2M12 12.4c-1.2 1-3.2 1.6-5 1.4M12 12.4c1.2 1 3.2 1.6 5 1.4M12 13.2v4",fill:"none",stroke:"rgba(255,255,255,0.62)",strokeWidth:"1",strokeLinecap:"round"}),(0,e.jsx)("circle",{cx:"12",cy:"8.6",r:"1.1",fill:"rgba(255,255,255,0.85)"})]})}var St="0.14.2";function Ga({t}){let[a,i]=(0,o.useState)(""),m="dsh-memory tui --live",c="dsh-memory tui --live --write",r=async(L,N)=>{try{await navigator.clipboard.writeText(L),i(N),setTimeout(()=>i(""),1600)}catch{}},h={border:"1px solid #3a404a",borderRadius:14,background:"#22262d",padding:"16px 18px"},w={margin:"10px 0 0",padding:"12px 14px",borderRadius:10,background:"#171a1f",border:"1px solid #333943",color:"#f3f5f8",fontSize:12.5,lineHeight:1.7,overflowX:"auto",fontFamily:"ui-monospace, Consolas, monospace"},S={marginTop:10,border:"1px solid #4a515c",background:"transparent",color:"#ffb08a",borderRadius:9,padding:"7px 12px",fontSize:12,cursor:"pointer"};return(0,e.jsxs)("div",{style:{padding:"22px 26px 34px",maxWidth:1040,color:"#f3f5f8"},children:[(0,e.jsxs)("div",{style:{display:"flex",alignItems:"baseline",gap:12,flexWrap:"wrap"},children:[(0,e.jsx)("h2",{style:{margin:0,fontSize:24,letterSpacing:"-.02em"},children:t("terminalTitle")}),(0,e.jsx)("span",{style:{color:"#99a1ac",fontSize:12},children:"TUI \xB7 LIVE \xB7 dsh-tui"})]}),(0,e.jsx)("p",{style:{margin:"9px 0 20px",color:"#aeb5bf",fontSize:13.5,lineHeight:1.8},children:t("terminalIntro")}),(0,e.jsxs)("div",{style:{display:"grid",gridTemplateColumns:"minmax(0, 1.1fr) minmax(0, .9fr)",gap:14},children:[(0,e.jsxs)("div",{style:h,children:[(0,e.jsxs)("div",{style:{fontSize:13,fontWeight:700},children:["\u25B8 ",t("terminalRun")]}),(0,e.jsx)("pre",{style:w,children:m}),(0,e.jsx)("button",{type:"button",style:S,onClick:()=>r(m,"run"),children:a==="run"?"\u2713 "+t("terminalCopied"):"\u29C9 "+t("terminalCopy")}),(0,e.jsxs)("div",{style:{marginTop:12,color:"#99a1ac",fontSize:12,lineHeight:1.7},children:["`--live` \u8BFB\u53D6\u771F\u5B9E\u5F85\u5BA1\u961F\u5217\uFF1B\u9ED8\u8BA4\u53EA\u8BFB\uFF0C\u786E\u8BA4\u540E\u624D\u7528 `--write`\u3002",(0,e.jsx)("br",{}),"\u6CA1\u6709 `dsh-memory` \u547D\u4EE4\u65F6\uFF1A`npx -p memory-eternal dsh-memory tui --live`"]})]}),(0,e.jsxs)("div",{style:h,children:[(0,e.jsxs)("div",{style:{fontSize:13,fontWeight:700},children:["\u25B8 ",t("terminalTui")]}),(0,e.jsx)("pre",{style:w,children:c}),(0,e.jsx)("button",{type:"button",style:S,onClick:()=>r(c,"tui"),children:a==="tui"?"\u2713 "+t("terminalCopied"):"\u29C9 "+t("terminalCopy")}),(0,e.jsx)("div",{style:{marginTop:12,color:"#99a1ac",fontSize:12,lineHeight:1.7},children:"\u771F\u5B9E\u6279\u51C6/\u9A73\u56DE\uFF1B\u4E0D\u786E\u5B9A\u65F6\u5148\u7528\u53EA\u8BFB\u6A21\u5F0F\u3002"})]})]}),(0,e.jsxs)("div",{style:{...h,marginTop:14},children:[(0,e.jsxs)("div",{style:{fontSize:13,fontWeight:700},children:["\u25B8 ",t("terminalPreview")]}),(0,e.jsx)("pre",{style:{...w,marginTop:10,color:"#d7dce3",fontSize:12,lineHeight:1.5},children:`\u256D\u2500 MEMORY ATLAS / \u5F85\u5BA1 \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256E
704
+ `;function Ea(t){t.effect(()=>t.locale.register(kt,{zh:da,en:ca}),"memory-eternal: locale");let a=t.locale.bind(kt);t.effect(()=>t.slots.inject("settings.section",()=>t.slots.register({name:"settings.section",id:kt,order:25,label:()=>a("nav"),locale:kt,inject:()=>({})},()=>o.default.createElement(Wa,{t:a}))),"memory-eternal: settings section"),t.effect(()=>t.slots.inject("sidebar.footer.action",()=>t.slots.register({name:"sidebar.footer.action",id:`${kt}:footer`,order:100,label:()=>a("nav"),locale:kt,inject:()=>({})},i=>o.default.createElement($a,{t:a,locale:t.locale,wide:!(i&&i.wide===!1)}))),"memory-eternal: sidebar footer action")}function Oa(){let[t,a]=(0,o.useState)($+"/ui/app");return(0,o.useEffect)(()=>{let i=!0,m=()=>fetch("/memory-eternal/api/web-info").then(c=>c.json()).then(c=>{i&&c&&c.ok&&c.alive!==!1&&c.url&&a(c.url.endsWith("/")?c.url:c.url+"/")}).catch(()=>{});return fetch($+"/ui/app",{method:"HEAD"}).then(c=>{if(i&&!c.ok)return m()}).catch(()=>i?m():void 0),()=>{i=!1}},[]),t}function Wa({t}){return(0,e.jsxs)("div",{style:{display:"flex",flexDirection:"column",height:"100%",minHeight:0},children:[(0,e.jsx)("style",{children:Ue}),(0,e.jsx)(ua,{t,onReload:()=>{},version:0})]})}function $a({t,locale:a,wide:i}){let[m,c]=(0,o.useState)(!1);return(0,e.jsxs)("div",{className:`me-footer${i?"":" rail"}`,children:[(0,e.jsx)("style",{children:Ue}),(0,e.jsxs)("button",{type:"button",className:"me-footer-btn",onClick:()=>c(!0),"aria-label":t("nav"),title:t("nav"),children:[(0,e.jsx)("span",{className:"me-footer-ico","aria-hidden":"true",children:(0,e.jsx)(Ua,{})}),(0,e.jsx)("span",{className:"me-footer-label",children:t("nav")})]}),m&&(0,e.jsx)(_a,{t,locale:a,onClose:()=>c(!1)})]})}function _a({t,locale:a,onClose:i,tab:m}){let[c,r]=(0,o.useState)(!1),h=(0,o.useRef)(null),w=Oa(),S=(0,o.useCallback)(T=>a&&typeof a.subscribe=="function"?a.subscribe(T):()=>{},[a]),L=(0,o.useCallback)(()=>a&&typeof a.getSnapshot=="function"?a.getSnapshot():null,[a]),N=(0,o.useSyncExternalStore)(S,L),x=N&&(N.active==="zh"||N.active==="en")?N.active:null,u=(0,o.useRef)(null);u.current===null&&x&&(u.current=x);let z=(0,o.useMemo)(()=>{let T=u.current?`lang=${u.current}`:"";if(m==="config")return`${$}/ui/config?tab=config${T?`&${T}`:""}`;let P=w.replace(/\/$/,""),M=P.endsWith("/ui/app")?"?":"/?";return m?`${P}${M}tab=${m}${T?`&${T}`:""}`:T?`${P}${M}${T}`:w},[w,m]);return(0,o.useEffect)(()=>{let T=h.current&&h.current.contentWindow;T&&x&&T.postMessage({source:"memory-eternal",type:"locale",lang:x},"*")},[x]),(0,o.useEffect)(()=>{let T=P=>{P.key==="Escape"&&i()};return window.addEventListener("keydown",T),()=>window.removeEventListener("keydown",T)},[i]),(0,e.jsxs)("div",{className:"me-overlay-top",onClick:i,children:[(0,e.jsx)("style",{children:Ue}),(0,e.jsx)("div",{className:"me-modal"+(c?" me-modal-full":""),onClick:T=>T.stopPropagation(),children:(0,e.jsxs)("div",{style:{display:"flex",flexDirection:"column",height:"100%",minHeight:0,position:"relative"},children:[(0,e.jsxs)("div",{style:{position:"absolute",top:8,right:8,zIndex:10,display:"flex",gap:4,padding:"4px 6px",background:"var(--dsw-alias-bg-overlay, rgba(17,24,39,0.45))",borderRadius:8,backdropFilter:"blur(4px)"},children:[(0,e.jsx)("button",{type:"button",onClick:()=>r(T=>!T),"aria-label":t(c?"exitFullscreen":"enterFullscreen"),title:t(c?"exitFullscreen":"enterFullscreen"),style:{width:26,height:26,borderRadius:6,border:"1px solid rgba(255,255,255,0.18)",background:"rgba(255,255,255,0.08)",color:"#fff",cursor:"pointer",fontSize:14,lineHeight:1,display:"flex",alignItems:"center",justifyContent:"center"},children:c?"\u2921":"\u2922"}),(0,e.jsx)("button",{type:"button",onClick:i,"aria-label":t("close"),title:t("close"),style:{width:26,height:26,borderRadius:6,border:"1px solid rgba(255,255,255,0.18)",background:"rgba(255,255,255,0.08)",color:"#fff",cursor:"pointer",fontSize:16,lineHeight:1,display:"flex",alignItems:"center",justifyContent:"center"},children:"\xD7"})]}),(0,e.jsx)("iframe",{ref:h,src:z,title:"memory-eternal",allow:"clipboard-write; clipboard-read",style:{width:"100%",flex:1,border:0,borderRadius:"inherit",background:"var(--dsw-alias-bg-base, #fff)"}})]})})]})}function Ua(){return(0,e.jsxs)("svg",{viewBox:"0 0 24 24","aria-hidden":"true",children:[(0,e.jsx)("defs",{children:(0,e.jsxs)("linearGradient",{id:"mg-brain",x1:"0",y1:"0",x2:"1",y2:"1",children:[(0,e.jsx)("stop",{offset:"0%",stopColor:"#FFC46B"}),(0,e.jsx)("stop",{offset:"50%",stopColor:"#F97316"}),(0,e.jsx)("stop",{offset:"100%",stopColor:"#EA580C"})]})}),(0,e.jsx)("path",{fill:"url(#mg-brain)",d:"M12 4.5a3.2 3.2 0 0 0-6.4.1 4.1 4.1 0 0 0-2.7 5.9 4.1 4.1 0 0 0 .6 6.7A4.2 4.2 0 0 0 12 18.2Z"}),(0,e.jsx)("path",{fill:"url(#mg-brain)",d:"M12 4.5a3.2 3.2 0 0 1 6.4.1 4.1 4.1 0 0 1 2.7 5.9 4.1 4.1 0 0 1-.6 6.7A4.2 4.2 0 0 1 12 18.2Z"}),(0,e.jsx)("path",{d:"M12 9.2c-.8-1.4-1.7-2-3.1-2.2M12 9.2c.8-1.4 1.7-2 3.1-2.2M12 12.4c-1.2 1-3.2 1.6-5 1.4M12 12.4c1.2 1 3.2 1.6 5 1.4M12 13.2v4",fill:"none",stroke:"rgba(255,255,255,0.62)",strokeWidth:"1",strokeLinecap:"round"}),(0,e.jsx)("circle",{cx:"12",cy:"8.6",r:"1.1",fill:"rgba(255,255,255,0.85)"})]})}var St="0.14.3";function Ga({t}){let[a,i]=(0,o.useState)(""),m="dsh-memory tui --live",c="dsh-memory tui --live --write",r=async(L,N)=>{try{await navigator.clipboard.writeText(L),i(N),setTimeout(()=>i(""),1600)}catch{}},h={border:"1px solid #3a404a",borderRadius:14,background:"#22262d",padding:"16px 18px"},w={margin:"10px 0 0",padding:"12px 14px",borderRadius:10,background:"#171a1f",border:"1px solid #333943",color:"#f3f5f8",fontSize:12.5,lineHeight:1.7,overflowX:"auto",fontFamily:"ui-monospace, Consolas, monospace"},S={marginTop:10,border:"1px solid #4a515c",background:"transparent",color:"#ffb08a",borderRadius:9,padding:"7px 12px",fontSize:12,cursor:"pointer"};return(0,e.jsxs)("div",{style:{padding:"22px 26px 34px",maxWidth:1040,color:"#f3f5f8"},children:[(0,e.jsxs)("div",{style:{display:"flex",alignItems:"baseline",gap:12,flexWrap:"wrap"},children:[(0,e.jsx)("h2",{style:{margin:0,fontSize:24,letterSpacing:"-.02em"},children:t("terminalTitle")}),(0,e.jsx)("span",{style:{color:"#99a1ac",fontSize:12},children:"TUI \xB7 LIVE \xB7 dsh-tui"})]}),(0,e.jsx)("p",{style:{margin:"9px 0 20px",color:"#aeb5bf",fontSize:13.5,lineHeight:1.8},children:t("terminalIntro")}),(0,e.jsxs)("div",{style:{display:"grid",gridTemplateColumns:"minmax(0, 1.1fr) minmax(0, .9fr)",gap:14},children:[(0,e.jsxs)("div",{style:h,children:[(0,e.jsxs)("div",{style:{fontSize:13,fontWeight:700},children:["\u25B8 ",t("terminalRun")]}),(0,e.jsx)("pre",{style:w,children:m}),(0,e.jsx)("button",{type:"button",style:S,onClick:()=>r(m,"run"),children:a==="run"?"\u2713 "+t("terminalCopied"):"\u29C9 "+t("terminalCopy")}),(0,e.jsxs)("div",{style:{marginTop:12,color:"#99a1ac",fontSize:12,lineHeight:1.7},children:["`--live` \u8BFB\u53D6\u771F\u5B9E\u5F85\u5BA1\u961F\u5217\uFF1B\u9ED8\u8BA4\u53EA\u8BFB\uFF0C\u786E\u8BA4\u540E\u624D\u7528 `--write`\u3002",(0,e.jsx)("br",{}),"\u6CA1\u6709 `dsh-memory` \u547D\u4EE4\u65F6\uFF1A`npx -p memory-eternal dsh-memory tui --live`"]})]}),(0,e.jsxs)("div",{style:h,children:[(0,e.jsxs)("div",{style:{fontSize:13,fontWeight:700},children:["\u25B8 ",t("terminalTui")]}),(0,e.jsx)("pre",{style:w,children:c}),(0,e.jsx)("button",{type:"button",style:S,onClick:()=>r(c,"tui"),children:a==="tui"?"\u2713 "+t("terminalCopied"):"\u29C9 "+t("terminalCopy")}),(0,e.jsx)("div",{style:{marginTop:12,color:"#99a1ac",fontSize:12,lineHeight:1.7},children:"\u771F\u5B9E\u6279\u51C6/\u9A73\u56DE\uFF1B\u4E0D\u786E\u5B9A\u65F6\u5148\u7528\u53EA\u8BFB\u6A21\u5F0F\u3002"})]})]}),(0,e.jsxs)("div",{style:{...h,marginTop:14},children:[(0,e.jsxs)("div",{style:{fontSize:13,fontWeight:700},children:["\u25B8 ",t("terminalPreview")]}),(0,e.jsx)("pre",{style:{...w,marginTop:10,color:"#d7dce3",fontSize:12,lineHeight:1.5},children:`\u256D\u2500 MEMORY ATLAS / \u5F85\u5BA1 \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256E
705
705
  \u2502 \u7C7B\u578B \u25CF \u5168\u90E8 7 \u25CB \u9879\u76EE 3 \u25CB \u77E5\u8BC6 1 \u25CB \u6559\u8BAD 1 \u2502
706
706
  \u2502 \u2502
707
707
  \u2502 \u25A3 \u5168\u9009 7 \u5DF2\u9009 3 s \u5168\u9009 \u2502
@@ -3,7 +3,7 @@
3
3
  "id": "memory-eternal",
4
4
  "publisher": "eternalnight996",
5
5
  "name": "memory-eternal",
6
- "version": "0.14.2",
6
+ "version": "0.14.3",
7
7
  "description": "Memory Atlas for Orca: open the local memory vault, pending review and knowledge graph from a sandboxed Orca panel.",
8
8
  "author": {
9
9
  "name": "EternalNight996",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "memory-eternal",
3
- "version": "0.14.2",
3
+ "version": "0.14.3",
4
4
  "description": "记忆核心(Memory Eternal):自研的 DeepSeek Harness 记忆插件,不移植任何既有记忆框架——对话结束后自动沉淀知识卡到本地 Markdown Vault(自研去重、自研 CJK 检索、可 git 管理),设置页提供图形化知识库(统计 / 搜索 / 知识图谱 + 侧边栏一键弹窗),Agent 通过 memory_recall 工具按需召回历史上下文。零人工干预。",
5
5
  "icon": "assets/icon.png",
6
6
  "license": "MIT",
package/web/app.js CHANGED
@@ -703,7 +703,7 @@ Option A, because:
703
703
  .mc-audit-batchcard > .mc-btn { width: 100%; }
704
704
  .mc-audit-batchcard > div[style*="flex: 1"] { display: none; }
705
705
  }
706
- `;var ro="0.14.2";function sh({t:e}){let[t,n]=(0,g.useState)(""),r="dsh-memory tui --live",a="dsh-memory tui --live --write",i=async(p,y)=>{try{await navigator.clipboard.writeText(p),n(y),setTimeout(()=>n(""),1600)}catch{}},l={border:"1px solid #3a404a",borderRadius:14,background:"#22262d",padding:"16px 18px"},s={margin:"10px 0 0",padding:"12px 14px",borderRadius:10,background:"#171a1f",border:"1px solid #333943",color:"#f3f5f8",fontSize:12.5,lineHeight:1.7,overflowX:"auto",fontFamily:"ui-monospace, Consolas, monospace"},d={marginTop:10,border:"1px solid #4a515c",background:"transparent",color:"#ffb08a",borderRadius:9,padding:"7px 12px",fontSize:12,cursor:"pointer"};return(0,o.jsxs)("div",{style:{padding:"22px 26px 34px",maxWidth:1040,color:"#f3f5f8"},children:[(0,o.jsxs)("div",{style:{display:"flex",alignItems:"baseline",gap:12,flexWrap:"wrap"},children:[(0,o.jsx)("h2",{style:{margin:0,fontSize:24,letterSpacing:"-.02em"},children:e("terminalTitle")}),(0,o.jsx)("span",{style:{color:"#99a1ac",fontSize:12},children:"TUI \xB7 LIVE \xB7 dsh-tui"})]}),(0,o.jsx)("p",{style:{margin:"9px 0 20px",color:"#aeb5bf",fontSize:13.5,lineHeight:1.8},children:e("terminalIntro")}),(0,o.jsxs)("div",{style:{display:"grid",gridTemplateColumns:"minmax(0, 1.1fr) minmax(0, .9fr)",gap:14},children:[(0,o.jsxs)("div",{style:l,children:[(0,o.jsxs)("div",{style:{fontSize:13,fontWeight:700},children:["\u25B8 ",e("terminalRun")]}),(0,o.jsx)("pre",{style:s,children:r}),(0,o.jsx)("button",{type:"button",style:d,onClick:()=>i(r,"run"),children:t==="run"?"\u2713 "+e("terminalCopied"):"\u29C9 "+e("terminalCopy")}),(0,o.jsxs)("div",{style:{marginTop:12,color:"#99a1ac",fontSize:12,lineHeight:1.7},children:["`--live` \u8BFB\u53D6\u771F\u5B9E\u5F85\u5BA1\u961F\u5217\uFF1B\u9ED8\u8BA4\u53EA\u8BFB\uFF0C\u786E\u8BA4\u540E\u624D\u7528 `--write`\u3002",(0,o.jsx)("br",{}),"\u6CA1\u6709 `dsh-memory` \u547D\u4EE4\u65F6\uFF1A`npx -p memory-eternal dsh-memory tui --live`"]})]}),(0,o.jsxs)("div",{style:l,children:[(0,o.jsxs)("div",{style:{fontSize:13,fontWeight:700},children:["\u25B8 ",e("terminalTui")]}),(0,o.jsx)("pre",{style:s,children:a}),(0,o.jsx)("button",{type:"button",style:d,onClick:()=>i(a,"tui"),children:t==="tui"?"\u2713 "+e("terminalCopied"):"\u29C9 "+e("terminalCopy")}),(0,o.jsx)("div",{style:{marginTop:12,color:"#99a1ac",fontSize:12,lineHeight:1.7},children:"\u771F\u5B9E\u6279\u51C6/\u9A73\u56DE\uFF1B\u4E0D\u786E\u5B9A\u65F6\u5148\u7528\u53EA\u8BFB\u6A21\u5F0F\u3002"})]})]}),(0,o.jsxs)("div",{style:{...l,marginTop:14},children:[(0,o.jsxs)("div",{style:{fontSize:13,fontWeight:700},children:["\u25B8 ",e("terminalPreview")]}),(0,o.jsx)("pre",{style:{...s,marginTop:10,color:"#d7dce3",fontSize:12,lineHeight:1.5},children:`\u256D\u2500 MEMORY ATLAS / \u5F85\u5BA1 \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256E
706
+ `;var ro="0.14.3";function sh({t:e}){let[t,n]=(0,g.useState)(""),r="dsh-memory tui --live",a="dsh-memory tui --live --write",i=async(p,y)=>{try{await navigator.clipboard.writeText(p),n(y),setTimeout(()=>n(""),1600)}catch{}},l={border:"1px solid #3a404a",borderRadius:14,background:"#22262d",padding:"16px 18px"},s={margin:"10px 0 0",padding:"12px 14px",borderRadius:10,background:"#171a1f",border:"1px solid #333943",color:"#f3f5f8",fontSize:12.5,lineHeight:1.7,overflowX:"auto",fontFamily:"ui-monospace, Consolas, monospace"},d={marginTop:10,border:"1px solid #4a515c",background:"transparent",color:"#ffb08a",borderRadius:9,padding:"7px 12px",fontSize:12,cursor:"pointer"};return(0,o.jsxs)("div",{style:{padding:"22px 26px 34px",maxWidth:1040,color:"#f3f5f8"},children:[(0,o.jsxs)("div",{style:{display:"flex",alignItems:"baseline",gap:12,flexWrap:"wrap"},children:[(0,o.jsx)("h2",{style:{margin:0,fontSize:24,letterSpacing:"-.02em"},children:e("terminalTitle")}),(0,o.jsx)("span",{style:{color:"#99a1ac",fontSize:12},children:"TUI \xB7 LIVE \xB7 dsh-tui"})]}),(0,o.jsx)("p",{style:{margin:"9px 0 20px",color:"#aeb5bf",fontSize:13.5,lineHeight:1.8},children:e("terminalIntro")}),(0,o.jsxs)("div",{style:{display:"grid",gridTemplateColumns:"minmax(0, 1.1fr) minmax(0, .9fr)",gap:14},children:[(0,o.jsxs)("div",{style:l,children:[(0,o.jsxs)("div",{style:{fontSize:13,fontWeight:700},children:["\u25B8 ",e("terminalRun")]}),(0,o.jsx)("pre",{style:s,children:r}),(0,o.jsx)("button",{type:"button",style:d,onClick:()=>i(r,"run"),children:t==="run"?"\u2713 "+e("terminalCopied"):"\u29C9 "+e("terminalCopy")}),(0,o.jsxs)("div",{style:{marginTop:12,color:"#99a1ac",fontSize:12,lineHeight:1.7},children:["`--live` \u8BFB\u53D6\u771F\u5B9E\u5F85\u5BA1\u961F\u5217\uFF1B\u9ED8\u8BA4\u53EA\u8BFB\uFF0C\u786E\u8BA4\u540E\u624D\u7528 `--write`\u3002",(0,o.jsx)("br",{}),"\u6CA1\u6709 `dsh-memory` \u547D\u4EE4\u65F6\uFF1A`npx -p memory-eternal dsh-memory tui --live`"]})]}),(0,o.jsxs)("div",{style:l,children:[(0,o.jsxs)("div",{style:{fontSize:13,fontWeight:700},children:["\u25B8 ",e("terminalTui")]}),(0,o.jsx)("pre",{style:s,children:a}),(0,o.jsx)("button",{type:"button",style:d,onClick:()=>i(a,"tui"),children:t==="tui"?"\u2713 "+e("terminalCopied"):"\u29C9 "+e("terminalCopy")}),(0,o.jsx)("div",{style:{marginTop:12,color:"#99a1ac",fontSize:12,lineHeight:1.7},children:"\u771F\u5B9E\u6279\u51C6/\u9A73\u56DE\uFF1B\u4E0D\u786E\u5B9A\u65F6\u5148\u7528\u53EA\u8BFB\u6A21\u5F0F\u3002"})]})]}),(0,o.jsxs)("div",{style:{...l,marginTop:14},children:[(0,o.jsxs)("div",{style:{fontSize:13,fontWeight:700},children:["\u25B8 ",e("terminalPreview")]}),(0,o.jsx)("pre",{style:{...s,marginTop:10,color:"#d7dce3",fontSize:12,lineHeight:1.5},children:`\u256D\u2500 MEMORY ATLAS / \u5F85\u5BA1 \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256E
707
707
  \u2502 \u7C7B\u578B \u25CF \u5168\u90E8 7 \u25CB \u9879\u76EE 3 \u25CB \u77E5\u8BC6 1 \u25CB \u6559\u8BAD 1 \u2502
708
708
  \u2502 \u2502
709
709
  \u2502 \u25A3 \u5168\u9009 7 \u5DF2\u9009 3 s \u5168\u9009 \u2502