@kenz1117/dsh-engram 0.5.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -2
- package/lib/client.js +1 -1
- package/lib/client.js.map +1 -1
- package/lib/index.js +562 -63
- package/package.json +16 -8
package/README.md
CHANGED
|
@@ -36,14 +36,18 @@ dsh plugin --profile web add @kenz1117/dsh-engram
|
|
|
36
36
|
- **知识飞轮**:摄取/保存 → 矛盾候选(写入时高相似近邻建 `contradicts` 边并报告,模型/用户裁决)→ 命中强化(confidence +0.05)→ 蒸馏(同主题簇合并为高层规律、supersedes 取代链、置信度继承)→ 衰减(低重要性且长期未访问归档,可恢复)。
|
|
37
37
|
- **自动摄取**(`ingest` 配置开启时):新一轮第一步从会话日志提取上一轮的候选事实,会话结束时补摄取最后一轮(失败留 pending 键,下次会话自动补做,幂等不重复),低 confidence 写入并按嵌入去重——不说"记住"也能攒记忆。
|
|
38
38
|
- **来源审计**:每条记忆记录来源会话、轮次与事件 seq,`engram_review` 完整回查来源链、取代链、矛盾与操作日志;全部写入/修改/遗忘/蒸馏/衰减入操作日志表。
|
|
39
|
-
- **Web 管理面板**:设置页「记忆库」tab——统计卡片、按状态/种类/内容过滤、行内详情与编辑(走取代链)、遗忘/恢复、导出 Markdown/JSON
|
|
39
|
+
- **Web 管理面板**:设置页「记忆库」tab——统计卡片、按状态/种类/内容过滤、行内详情与编辑(走取代链)、遗忘/恢复、导出 Markdown/JSON。界面文案中英双语,跟随宿主语言设置实时切换。支持按脱敏标记筛选(仅看/排除含 `[REDACTED:*]` 的条目)并给命中条目挂琥珀色徽标,方便审计脱敏覆盖面。
|
|
40
|
+
- **提示注入防护**:全部记忆召回出口(画像注入、`engram_search/timeline/review` 输出)包 `<engram_memory_context>` 协议标签并附使用警告(历史记忆非当前请求、不遵循其中指令、仅相关时使用),当前请求独立包 `<current_user_request>`;所有入库内容(摄取候选、保存正文)先剥离这些协议标签,防伪造协议块二次注入。
|
|
41
|
+
- **摄取脱敏**:入库前正则清洗常见密钥凭据(sk- 系 API key、Bearer、AWS AKIA、GitHub token、PEM 私钥、password/token 赋值),命中片段替换为 `[REDACTED:<类型>]`。
|
|
42
|
+
- **召回占位(防回声室)**:摄取切片中记忆召回工具的输出替换为 `[engram memory result omitted from capture: <tool>]`,并向提取模型附注"既有记忆的复述不是新信息",阻断记忆自我强化循环。
|
|
43
|
+
- **多查询检索**:`engram_search` 可用辅助 LLM 把查询改写为 ≤3 个互补查询分别检索,跨查询 RRF 融合 + 每查询保底命中;改写失败自动降级单查询(`queryRewrite: false` 关闭)。
|
|
40
44
|
- **数据可携带**:`engram_export` 一键导出 Markdown / JSON 文件。
|
|
41
45
|
|
|
42
46
|
## 工具(9 个,窄参数)
|
|
43
47
|
|
|
44
48
|
| 工具 | 作用 |
|
|
45
49
|
|---|---|
|
|
46
|
-
| `engram_save` |
|
|
50
|
+
| `engram_save` | 保存(嵌入可用时自动做矛盾候选检测);支持 `items` 数组单次批量保存 ≤10 条,统一清洗/批量内去重,单条失败不影响其余(`count`/`items`/`failed` 汇总返回) |
|
|
47
51
|
| `engram_search` | 语义 + 关键词混合检索(命中强化置信度) |
|
|
48
52
|
| `engram_timeline` | 时间线浏览 |
|
|
49
53
|
| `engram_update` | 修正(supersedes 取代链) |
|
|
@@ -75,6 +79,7 @@ dsh plugin --profile web add @kenz1117/dsh-engram
|
|
|
75
79
|
decayImportanceBelow: 0.3 # 衰减:且 importance 低于该值 → 归档(可恢复)
|
|
76
80
|
rankRecencyWeight: 0.2 # 检索排序新鲜度因子权重(0-2,0 关闭)
|
|
77
81
|
rankProofWeight: 0.1 # 检索排序命中次数因子权重(0-2,0 关闭)
|
|
82
|
+
queryRewrite: true # engram_search 用辅助 LLM 改写 ≤3 个查询做 RRF 融合(失败自动降级单查询)
|
|
78
83
|
```
|
|
79
84
|
|
|
80
85
|
## 工作原理
|
package/lib/client.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
window.__ModuleLoader__.load({id:`@kenz1117/dsh-engram`,factory:e=>{var t={exports:{}},n=t.exports;Object.defineProperty(n,Symbol.toStringTag,{value:`Module`});let r=e("react"),i=e("react/jsx-runtime"),a=`@kenz1117/dsh-engram/panel.module.css`;if(typeof document<`u`&&document.querySelector(`style[data-plugin-css=`+JSON.stringify(a)+`]`)===null){let e=document.createElement(`style`);e.dataset.plugin=`@kenz1117/dsh-engram`,e.dataset.pluginCss=a,e.textContent=`.bWwFiW_panel{max-width:920px;animation:.24s both bWwFiW_rise}@keyframes bWwFiW_rise{0%{opacity:0;transform:translateY(6px)}to{opacity:1;transform:none}}.bWwFiW_toolbar{flex-wrap:wrap;align-items:center;gap:8px;margin-bottom:16px;display:flex}.bWwFiW_scopeTabs{border-bottom:1px solid var(--dsw-alias-border-l2);align-items:flex-end;gap:20px;margin-right:auto;display:flex}.bWwFiW_scopeOn,.bWwFiW_scopeOff{color:var(--dsw-alias-label-tertiary);cursor:pointer;background:0 0;border:0;padding:7px 1px 9px;font-size:13px;line-height:20px;transition:color .14s;position:relative}.bWwFiW_scopeOn,.bWwFiW_scopeOff:hover{color:var(--dsw-alias-label-primary)}.bWwFiW_scopeOn:after{background:var(--dsw-alias-brand-primary);content:"";border-radius:2px 2px 0 0;height:2px;position:absolute;bottom:-1px;left:0;right:0}.bWwFiW_button{color:var(--dsw-alias-label-secondary);border:1px solid var(--dsw-alias-border-l2);cursor:pointer;background:0 0;border-radius:8px;padding:5px 12px;font-size:13px;line-height:18px;transition:color .14s,border-color .14s,background .14s,transform .1s}.bWwFiW_button:hover{color:var(--dsw-alias-label-primary);border-color:var(--dsw-alias-brand-primary);background:color-mix(in srgb, var(--dsw-alias-brand-primary) 7%, transparent)}.bWwFiW_button:active{transform:scale(.97)}.bWwFiW_button:disabled{opacity:.4;cursor:default;border-color:var(--dsw-alias-border-l2);color:var(--dsw-alias-label-tertiary);background:0 0;transform:none}.bWwFiW_primary{background:var(--dsw-alias-button-primary-fill);border-color:var(--dsw-alias-button-primary-fill);color:var(--dsw-alias-label-primary-foreground)}.bWwFiW_primary:hover{background:var(--dsw-alias-button-primary-fill);color:var(--dsw-alias-label-primary-foreground);filter:brightness(1.08)}.bWwFiW_cards{grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:12px;margin-bottom:16px;display:grid}.bWwFiW_card{background:var(--dsw-alias-bg-layer-1);border:1px solid var(--dsw-alias-border-l2);text-align:left;cursor:pointer;color:var(--dsw-alias-label-primary);font:inherit;border-radius:12px;padding:14px 16px 12px;transition:border-color .16s,transform .16s,box-shadow .16s;position:relative;overflow:hidden}.bWwFiW_card:hover{border-color:var(--dsw-alias-border-l1,var(--dsw-alias-brand-primary));box-shadow:0 6px 18px -8px color-mix(in srgb, var(--dsw-alias-label-primary) 22%, transparent);transform:translateY(-1px)}.bWwFiW_card b{font-variant-numeric:tabular-nums;letter-spacing:-.01em;font-size:26px;line-height:1.15;display:block}.bWwFiW_card span{color:var(--dsw-alias-label-secondary);font-size:12px}.bWwFiW_cardOn{border-color:color-mix(in srgb, var(--dsw-alias-brand-primary) 55%, transparent);background:color-mix(in srgb, var(--dsw-alias-brand-primary) 5%, var(--dsw-alias-bg-layer-1))}.bWwFiW_cardOn:before{background:var(--dsw-alias-brand-primary);content:"";width:3px;position:absolute;top:0;bottom:0;left:0}.bWwFiW_cardMeter{background:color-mix(in srgb, var(--dsw-alias-label-tertiary) 18%, transparent);border-radius:2px;height:3px;margin-top:10px;display:block;overflow:hidden}.bWwFiW_cardMeter i{background:var(--dsw-alias-brand-primary);border-radius:2px;height:100%;transition:width .3s;display:block}.bWwFiW_filters{flex-wrap:wrap;gap:8px;margin-bottom:16px;display:flex}.bWwFiW_input{background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-primary);border:1px solid var(--dsw-alias-border-l2);border-radius:8px;padding:6px 10px;font-size:13px;transition:border-color .14s,box-shadow .14s}.bWwFiW_input:focus-visible{border-color:var(--dsw-alias-brand-primary);box-shadow:0 0 0 3px color-mix(in srgb, var(--dsw-alias-brand-primary) 18%, transparent);outline:none}.bWwFiW_filters .bWwFiW_input{flex:1;min-width:160px}.bWwFiW_filters select.bWwFiW_input{flex:0 auto;min-width:120px}.bWwFiW_item{background:var(--dsw-alias-bg-layer-1);border:1px solid var(--dsw-alias-border-l2);border-radius:12px;margin-bottom:10px;padding:13px 16px 11px;transition:border-color .16s,background .16s,box-shadow .16s;animation:.26s both bWwFiW_rise;position:relative}.bWwFiW_item:hover{border-color:color-mix(in srgb, var(--dsw-alias-brand-primary) 40%, var(--dsw-alias-border-l2));box-shadow:0 8px 22px -12px color-mix(in srgb, var(--dsw-alias-label-primary) 26%, transparent)}.bWwFiW_itemSelected{border-color:var(--dsw-alias-brand-primary);background:color-mix(in srgb, var(--dsw-alias-brand-primary) 4%, var(--dsw-alias-bg-layer-1))}.bWwFiW_row1{flex-wrap:wrap;align-items:center;gap:10px;margin-bottom:7px;display:flex}.bWwFiW_itemCheck{accent-color:var(--dsw-alias-brand-primary);cursor:pointer;flex:none;width:15px;height:15px}.bWwFiW_statusWrap{color:var(--dsw-alias-label-secondary);align-items:center;gap:6px;font-size:12px;display:inline-flex}.bWwFiW_statusWrap:before{background:var(--dsw-alias-label-tertiary);content:"";border-radius:50%;width:7px;height:7px}.bWwFiW_statusWrap.bWwFiW_active{color:var(--dsw-alias-state-success-primary)}.bWwFiW_statusWrap.bWwFiW_active:before{background:var(--dsw-alias-state-success-primary);box-shadow:0 0 0 3px color-mix(in srgb, var(--dsw-alias-state-success-primary) 16%, transparent)}.bWwFiW_statusWrap.bWwFiW_archived{color:var(--dsw-alias-state-warn-primary)}.bWwFiW_statusWrap.bWwFiW_archived:before{background:var(--dsw-alias-state-warn-primary)}.bWwFiW_statusWrap.bWwFiW_forgotten{color:var(--dsw-alias-state-error-primary)}.bWwFiW_statusWrap.bWwFiW_forgotten:before{background:var(--dsw-alias-state-error-primary)}.bWwFiW_chip{color:var(--dsw-alias-brand-primary);background:color-mix(in srgb, var(--dsw-alias-brand-primary) 10%, transparent);border-radius:6px;padding:0 8px;font-size:11px;line-height:18px}.bWwFiW_scopeTag{color:var(--dsw-alias-label-tertiary);font-size:11px}.bWwFiW_timeTag{color:var(--dsw-alias-label-tertiary);font-variant-numeric:tabular-nums;margin-left:auto;font-size:12px}.bWwFiW_content{white-space:pre-wrap;word-break:break-word;color:var(--dsw-alias-label-primary);-webkit-line-clamp:4;-webkit-box-orient:vertical;font-size:14px;line-height:1.7;display:-webkit-box;overflow:hidden}.bWwFiW_meta{color:var(--dsw-alias-label-secondary);flex-wrap:wrap;align-items:center;gap:16px;margin-top:8px;font-size:12px;display:flex}.bWwFiW_meterField{font-variant-numeric:tabular-nums;align-items:center;gap:7px;display:inline-flex}.bWwFiW_meter{background:color-mix(in srgb, var(--dsw-alias-label-tertiary) 18%, transparent);border-radius:2px;width:52px;height:4px;overflow:hidden}.bWwFiW_meter i{background:var(--dsw-alias-brand-primary);border-radius:2px;height:100%;display:block}.bWwFiW_meter.bWwFiW_conf i{background:var(--dsw-alias-state-success-primary)}.bWwFiW_ops{opacity:.55;gap:6px;margin-top:9px;transition:opacity .16s;display:flex}.bWwFiW_item:hover .bWwFiW_ops,.bWwFiW_item:focus-within .bWwFiW_ops{opacity:1}.bWwFiW_ops .bWwFiW_button{background:var(--dsw-alias-fill-tsp-secondary);border-color:#0000;padding:3px 10px;font-size:12px}.bWwFiW_ops .bWwFiW_button:hover{border-color:var(--dsw-alias-brand-primary);background:color-mix(in srgb, var(--dsw-alias-brand-primary) 8%, transparent)}.bWwFiW_batchBar{z-index:5;background:color-mix(in srgb, var(--dsw-alias-bg-layer-1) 82%, transparent);backdrop-filter:blur(10px);border:1px solid color-mix(in srgb, var(--dsw-alias-brand-primary) 45%, var(--dsw-alias-border-l2));box-shadow:0 10px 28px -12px color-mix(in srgb, var(--dsw-alias-label-primary) 30%, transparent);border-radius:12px;flex-wrap:wrap;align-items:center;gap:8px;margin-bottom:12px;padding:9px 14px;animation:.2s both bWwFiW_barUp;display:flex;position:sticky;bottom:12px}@keyframes bWwFiW_barUp{0%{opacity:0;transform:translateY(8px)}to{opacity:1;transform:none}}.bWwFiW_batchBar>span{color:var(--dsw-alias-label-primary);font-variant-numeric:tabular-nums;margin-right:auto;font-size:13px}.bWwFiW_danger{background:var(--dsw-alias-state-error-primary);border-color:var(--dsw-alias-state-error-primary);color:var(--dsw-alias-label-primary-foreground)}.bWwFiW_danger:hover{background:var(--dsw-alias-state-error-primary);color:var(--dsw-alias-label-primary-foreground);filter:brightness(1.08)}.bWwFiW_skeleton{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-1);border-radius:12px;margin-bottom:10px;padding:13px 16px}.bWwFiW_skeleton i{background:linear-gradient(90deg, color-mix(in srgb, var(--dsw-alias-label-tertiary) 12%, transparent) 25%, color-mix(in srgb, var(--dsw-alias-label-tertiary) 24%, transparent) 50%, color-mix(in srgb, var(--dsw-alias-label-tertiary) 12%, transparent) 75%);background-size:200% 100%;border-radius:6px;height:12px;margin:8px 0;animation:1.3s linear infinite bWwFiW_shimmer;display:block}.bWwFiW_skeleton i:first-child{width:34%;margin-top:2px}.bWwFiW_skeleton i:last-child{width:62%}@keyframes bWwFiW_shimmer{0%{background-position:200% 0}to{background-position:-200% 0}}.bWwFiW_empty{text-align:center;color:var(--dsw-alias-label-secondary);padding:48px 0 52px}.bWwFiW_empty:before{border:1px solid var(--dsw-alias-border-l2);background:linear-gradient(135deg, color-mix(in srgb, var(--dsw-alias-brand-primary) 14%, transparent), transparent 70%);content:"";border-radius:10px;width:34px;height:34px;margin:0 auto 12px;display:block;transform:rotate(45deg)scale(.8)}.bWwFiW_expand{border-top:1px dashed var(--dsw-alias-border-l2);margin-top:10px;padding-top:12px;animation:.18s both bWwFiW_rise}.bWwFiW_expandLoading{color:var(--dsw-alias-label-secondary);font-size:13px}.bWwFiW_attrGrid{grid-template-columns:max-content 1fr;align-items:center;gap:7px 16px;font-size:13px;display:grid}.bWwFiW_attrGrid>dt{color:var(--dsw-alias-label-tertiary);margin:0;font-size:12px}.bWwFiW_attrGrid>dd{color:var(--dsw-alias-label-primary);flex-wrap:wrap;align-items:center;gap:8px;margin:0;display:flex}.bWwFiW_relBlock{margin-top:12px}.bWwFiW_relBlock>h5{color:var(--dsw-alias-label-tertiary);margin:0 0 6px;font-size:12px;font-weight:500}.bWwFiW_relChips{flex-wrap:wrap;gap:6px;display:flex}.bWwFiW_relChip{border:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-secondary);background:var(--dsw-alias-bg-base);border-radius:6px;padding:2px 8px;font-family:ui-monospace,SF Mono,Menlo,monospace;font-size:11px}.bWwFiW_timeline{margin:12px 0 0;padding:0 0 0 14px;list-style:none;position:relative}.bWwFiW_timeline:before{background:var(--dsw-alias-border-l2);content:"";width:1px;position:absolute;top:6px;bottom:6px;left:3px}.bWwFiW_timeline li{color:var(--dsw-alias-label-secondary);padding:5px 0 5px 12px;font-size:12px;line-height:1.6;position:relative}.bWwFiW_timeline li:before{background:var(--dsw-alias-bg-layer-1);border:1px solid var(--dsw-alias-brand-primary);content:"";border-radius:50%;width:7px;height:7px;position:absolute;top:10px;left:-14px}.bWwFiW_timeline time{font-variant-numeric:tabular-nums;color:var(--dsw-alias-label-tertiary);margin-right:8px}.bWwFiW_timeline b{color:var(--dsw-alias-label-primary);font-weight:500}.bWwFiW_editForm{flex-direction:column;display:flex}.bWwFiW_editForm .bWwFiW_input{box-sizing:border-box;width:100%}.bWwFiW_fieldLabel{color:var(--dsw-alias-label-secondary);margin:12px 0 5px;font-size:12px;display:block}.bWwFiW_editForm input[type=range]{accent-color:var(--dsw-alias-brand-primary)}.bWwFiW_modalFoot{justify-content:flex-end;gap:8px;margin-top:14px;display:flex}.bWwFiW_pager{color:var(--dsw-alias-label-secondary);font-variant-numeric:tabular-nums;justify-content:center;align-items:center;gap:12px;margin-top:18px;font-size:13px;display:flex}`,document.head.appendChild(e)}var o={attrGrid:`bWwFiW_attrGrid`,relChips:`bWwFiW_relChips`,editForm:`bWwFiW_editForm`,modalFoot:`bWwFiW_modalFoot`,pager:`bWwFiW_pager`,item:`bWwFiW_item`,scopeTabs:`bWwFiW_scopeTabs`,toolbar:`bWwFiW_toolbar`,archived:`bWwFiW_archived`,empty:`bWwFiW_empty`,meta:`bWwFiW_meta`,skeleton:`bWwFiW_skeleton`,expand:`bWwFiW_expand`,rise:`bWwFiW_rise`,cardOn:`bWwFiW_cardOn`,forgotten:`bWwFiW_forgotten`,relBlock:`bWwFiW_relBlock`,timeline:`bWwFiW_timeline`,button:`bWwFiW_button`,card:`bWwFiW_card`,itemSelected:`bWwFiW_itemSelected`,cardMeter:`bWwFiW_cardMeter`,filters:`bWwFiW_filters`,active:`bWwFiW_active`,relChip:`bWwFiW_relChip`,cards:`bWwFiW_cards`,row1:`bWwFiW_row1`,scopeTag:`bWwFiW_scopeTag`,scopeOn:`bWwFiW_scopeOn`,itemCheck:`bWwFiW_itemCheck`,scopeOff:`bWwFiW_scopeOff`,timeTag:`bWwFiW_timeTag`,content:`bWwFiW_content`,meterField:`bWwFiW_meterField`,conf:`bWwFiW_conf`,batchBar:`bWwFiW_batchBar`,barUp:`bWwFiW_barUp`,chip:`bWwFiW_chip`,danger:`bWwFiW_danger`,shimmer:`bWwFiW_shimmer`,expandLoading:`bWwFiW_expandLoading`,fieldLabel:`bWwFiW_fieldLabel`,meter:`bWwFiW_meter`,input:`bWwFiW_input`,primary:`bWwFiW_primary`,ops:`bWwFiW_ops`,panel:`bWwFiW_panel`,statusWrap:`bWwFiW_statusWrap`};let s=[`fact`,`preference`,`decision`,`episode`,`skill`],c={active:`statusActive`,archived:`statusArchived`,forgotten:`statusForgotten`},l={fact:`kindFact`,preference:`kindPreference`,decision:`kindDecision`,episode:`kindEpisode`,skill:`kindSkill`},u={user:`scopeUser`,project:`scopeProject`},d={write:`opWrite`,update:`opUpdate`,forget:`opForget`,restore:`opRestore`,decay:`opDecay`,superseded:`opSuperseded`,"ingest-request":`opIngestRequest`,"distill-request":`opDistillRequest`},f={supersededBy:`relSupersededBy`,supersedes:`relSupersedes`,contradicts:`relContradicts`,related:`relRelated`},p={kind:`labelKind`,scope:`labelScope`,status:`labelStatus`};function m(e,t){let n=l[t];return n===void 0?t:e(n)}function h(e,t){let n=d[t];return n===void 0?t:e(n)}function g(e,t,n){if(n===null)return``;if(t!==`write`&&t!==`update`&&t!==`superseded`)return` ${n}`;try{let t=JSON.parse(n),r=Object.entries(t);return r.length===0?` ${n}`:` `+r.map(([t,n])=>{let r=p[t];return r===void 0?`${t}=${String(n)}`:t===`kind`&&typeof n==`string`?`${e(r)}=${m(e,n)}`:t===`scope`&&(n===`user`||n===`project`)?`${e(r)}=${e(u[n])}`:`${e(r)}=${String(n)}`}).join(` · `)}catch{return` ${n}`}}function _(e,t){if(t.sourceSessionId===null)return e(`sourceExplicit`);let n=`${t.sourceSessionId.slice(0,16)}…`;return e(`sourceSession`,{id:t.sourceRound===null?n:`${n} ${e(`round`,{n:t.sourceRound})}`})}async function v(e,t){let n=await fetch(`/api/engram/${e}`,t),r=await n.json();if(!n.ok)throw Error(r.error??`HTTP ${String(n.status)}`);return r}function y(e){return new Date(e).toLocaleString(navigator.language||`zh-CN`,{hour12:!1})}function b(e,t){let n=Math.max(0,Date.now()-t),r=Math.floor(n/6e4);if(r<1)return e(`timeJustNow`);if(r<60)return e(`timeMinutesAgo`,{n:r});let i=Math.floor(r/60);return i<48?e(`timeHoursAgo`,{n:i}):e(`timeDaysAgo`,{n:Math.floor(i/24)})}function x({value:e,conf:t}){return(0,i.jsx)(`span`,{className:t===!0?`${o.meter} ${o.conf}`:o.meter,children:(0,i.jsx)(`i`,{style:{width:`${String(Math.round(Math.min(1,Math.max(0,e))*100))}%`}})})}function S({ids:e}){return(0,i.jsx)(`div`,{className:o.relChips,children:e.map(e=>(0,i.jsx)(`span`,{className:o.relChip,title:e,children:e.slice(0,18)},e))})}function C({t:e,recordId:t,scope:n}){let[a,s]=(0,r.useState)(null),[l,u]=(0,r.useState)(null);if((0,r.useEffect)(()=>{let e=!1;return v(`review?scope=${n}&id=${encodeURIComponent(t)}`).then(t=>{e||s(t)}).catch(t=>{e||u(t.message)}),()=>{e=!0}},[t,n,e]),l!==null)return(0,i.jsx)(`div`,{className:o.expandLoading,children:e(`loadFailed`,{msg:l})});if(a===null)return(0,i.jsx)(`div`,{className:o.expandLoading,children:e(`loading`)});let{record:d}=a,p=[`supersededBy`,`supersedes`,`contradicts`,`related`].map(e=>({key:e,label:f[e],ids:a[e]??[]})).filter(e=>e.ids.length>0),b=a.operations??[];return(0,i.jsxs)(`div`,{children:[(0,i.jsxs)(`dl`,{className:o.attrGrid,children:[(0,i.jsx)(`dt`,{children:e(`labelContent`)}),(0,i.jsx)(`dd`,{children:d.content}),(0,i.jsx)(`dt`,{children:e(`labelKind`)}),(0,i.jsx)(`dd`,{children:(0,i.jsx)(`span`,{className:o.chip,children:m(e,d.kind)})}),(0,i.jsx)(`dt`,{children:e(`labelStatus`)}),(0,i.jsx)(`dd`,{children:(0,i.jsx)(`span`,{className:`${o.statusWrap} ${o[d.status]}`,children:e(c[d.status])})}),(0,i.jsx)(`dt`,{children:e(`importance`)}),(0,i.jsxs)(`dd`,{children:[d.importance.toFixed(2),(0,i.jsx)(x,{value:d.importance})]}),(0,i.jsx)(`dt`,{children:e(`confidence`)}),(0,i.jsxs)(`dd`,{children:[d.confidence.toFixed(2),(0,i.jsx)(x,{value:d.confidence,conf:!0})]}),(0,i.jsx)(`dt`,{children:e(`detailSource`)}),(0,i.jsx)(`dd`,{children:_(e,d)}),(0,i.jsx)(`dt`,{children:e(`labelCreated`)}),(0,i.jsx)(`dd`,{children:y(d.createdAt)})]}),p.map(({key:t,label:n,ids:r})=>(0,i.jsxs)(`div`,{className:o.relBlock,children:[(0,i.jsx)(`h5`,{children:n===void 0?t:e(n)}),(0,i.jsx)(S,{ids:r})]},t)),b.length>0&&(0,i.jsxs)(`div`,{className:o.relBlock,children:[(0,i.jsx)(`h5`,{children:e(`detailOperations`)}),(0,i.jsx)(`ul`,{className:o.timeline,children:b.map((t,n)=>(0,i.jsxs)(`li`,{children:[(0,i.jsx)(`time`,{children:y(t.at)}),(0,i.jsx)(`b`,{children:h(e,t.op)}),g(e,t.op,t.detail)]},n))})]})]})}function w({t:e,record:t,onClose:n,onSaved:a}){let[c,l]=(0,r.useState)(t.content),[u,d]=(0,r.useState)(t.kind),[f,p]=(0,r.useState)(t.importance);return(0,i.jsxs)(`div`,{className:o.editForm,children:[(0,i.jsx)(`label`,{className:o.fieldLabel,children:e(`labelContent`)}),(0,i.jsx)(`textarea`,{className:o.input,rows:3,value:c,onChange:e=>l(e.target.value)}),(0,i.jsx)(`label`,{className:o.fieldLabel,children:e(`labelKind`)}),(0,i.jsx)(`select`,{className:o.input,value:u,onChange:e=>d(e.target.value),children:s.map(t=>(0,i.jsx)(`option`,{value:t,children:m(e,t)},t))}),(0,i.jsx)(`label`,{className:o.fieldLabel,children:`${e(`importance`)} ${f.toFixed(2)}`}),(0,i.jsx)(`input`,{type:`range`,min:0,max:1,step:.05,value:f,onChange:e=>p(Number(e.target.value))}),(0,i.jsxs)(`div`,{className:o.modalFoot,children:[(0,i.jsx)(`button`,{type:`button`,className:o.button,onClick:n,children:e(`cancel`)}),(0,i.jsx)(`button`,{type:`button`,className:`${o.button} ${o.primary}`,onClick:()=>{v(`update`,{method:`POST`,headers:{"content-type":`application/json`},body:JSON.stringify({id:t.id,scope:t.scope,content:c,kind:u,importance:f})}).then(a).catch(e=>{alert(e.message)})},children:e(`saveWithHint`)})]})]})}function T({t:e}){let[t,n]=(0,r.useState)(`user`),[a,l]=(0,r.useState)(`all`),[d,f]=(0,r.useState)(`all`),[p,h]=(0,r.useState)(``),[g,S]=(0,r.useState)(0),[T,E]=(0,r.useState)(null),[D,O]=(0,r.useState)(null),[k,A]=(0,r.useState)(null),[j,M]=(0,r.useState)(null),[N,P]=(0,r.useState)(0),[F,I]=(0,r.useState)(new Set),[L,R]=(0,r.useState)(!1),z=(0,r.useCallback)(()=>{P(e=>e+1)},[]);(0,r.useEffect)(()=>{let e=!1,n=new URLSearchParams({scope:t,status:a,kind:d,limit:`20`,offset:String(g)});return p!==``&&n.set(`q`,p),v(`list?${n.toString()}`).then(t=>{e||(E(t),A(null))}).catch(t=>{e||A(t.message)}),v(`stats`).then(t=>{e||O(t.parts)}).catch(()=>{}),()=>{e=!0}},[t,a,d,p,g,N]);let B=(e,t)=>{v(e,{method:`POST`,headers:{"content-type":`application/json`},body:JSON.stringify({id:t.id,scope:t.scope})}).then(z).catch(e=>{alert(e.message)})},V=(e,t)=>{M(n=>n!==null&&n.kind===e&&n.record.id===t.id?null:{kind:e,record:t})},H=T?.records??[],U=H.filter(e=>F.has(e.id)),W=U.filter(e=>e.status===`active`).length,G=U.length-W,K=H.length>0&&H.every(e=>F.has(e.id)),q=e=>{I(t=>{let n=new Set(t);return n.has(e)?n.delete(e):n.add(e),n})},J=()=>{I(new Set),R(!1)},Y=()=>{I(e=>{let t=new Set(e);return K?H.forEach(e=>t.delete(e.id)):H.forEach(e=>t.add(e.id)),t})},X=e=>{let t=e===`forget`?U.filter(e=>e.status===`active`):U.filter(e=>e.status!==`active`);t.length!==0&&Promise.allSettled(t.map(t=>v(e,{method:`POST`,headers:{"content-type":`application/json`},body:JSON.stringify({id:t.id,scope:t.scope})}))).then(()=>{J(),z()})},Z=()=>{if(L){X(`forget`);return}R(!0)},Q=Math.floor(g/20)+1,$=T===null?1:Math.max(1,Math.ceil(T.total/20));return(0,i.jsxs)(`div`,{className:o.panel,children:[(0,i.jsxs)(`div`,{className:o.toolbar,children:[(0,i.jsx)(`div`,{className:o.scopeTabs,children:[`user`,`project`].map(r=>(0,i.jsx)(`button`,{type:`button`,className:t===r?o.scopeOn:o.scopeOff,onClick:()=>{n(r),S(0),M(null),J()},children:e(u[r])},r))}),(0,i.jsx)(`button`,{type:`button`,className:o.button,onClick:z,children:e(`refresh`)}),(0,i.jsx)(`button`,{type:`button`,className:o.button,onClick:()=>{location.href=`/api/engram/export?scope=${t}&format=markdown`},children:e(`exportMd`)}),(0,i.jsx)(`button`,{type:`button`,className:o.button,onClick:()=>{location.href=`/api/engram/export?scope=${t}&format=json`},children:e(`exportJson`)})]}),(0,i.jsx)(`div`,{className:o.cards,children:(D??[]).map(r=>(0,i.jsxs)(`button`,{type:`button`,className:r.scope===t?`${o.card} ${o.cardOn}`:o.card,onClick:()=>{n(r.scope),S(0),J()},children:[(0,i.jsx)(`b`,{children:r.stats.total}),(0,i.jsx)(`span`,{children:`${e(u[r.scope])} · ${e(`cardActive`,{n:r.stats.active})} · ${e(`signalRatio`,{n:Math.round(r.stats.signalRatio*100)})}`}),(0,i.jsx)(`span`,{className:o.cardMeter,children:(0,i.jsx)(`i`,{style:{width:`${String(Math.round(r.stats.signalRatio*100))}%`}})})]},r.scope))}),(0,i.jsxs)(`div`,{className:o.filters,children:[(0,i.jsxs)(`select`,{className:o.input,value:a,onChange:e=>{l(e.target.value),S(0),M(null),J()},children:[(0,i.jsx)(`option`,{value:`all`,children:e(`allStatuses`)}),(0,i.jsx)(`option`,{value:`active`,children:e(`statusActive`)}),(0,i.jsx)(`option`,{value:`archived`,children:e(`statusArchived`)}),(0,i.jsx)(`option`,{value:`forgotten`,children:e(`statusForgotten`)})]}),(0,i.jsxs)(`select`,{className:o.input,value:d,onChange:e=>{f(e.target.value),S(0),M(null),J()},children:[(0,i.jsx)(`option`,{value:`all`,children:e(`allKinds`)}),s.map(t=>(0,i.jsx)(`option`,{value:t,children:m(e,t)},t))]}),(0,i.jsx)(`input`,{className:o.input,placeholder:e(`searchPlaceholder`),value:p,onChange:e=>{h(e.target.value.trim()),S(0),M(null),J()}})]}),F.size>0&&(0,i.jsxs)(`div`,{className:o.batchBar,children:[(0,i.jsx)(`span`,{children:e(`selectedCount`,{n:F.size})}),(0,i.jsx)(`button`,{type:`button`,className:o.button,onClick:Y,children:e(K?`deselectAll`:`selectAll`)}),(0,i.jsx)(`button`,{type:`button`,className:o.button,disabled:G===0,onClick:()=>X(`restore`),children:e(`batchRestore`,{n:G})}),(0,i.jsx)(`button`,{type:`button`,className:L?`${o.button} ${o.danger}`:o.button,disabled:W===0,onClick:Z,children:e(L?`batchForgetConfirm`:`batchForget`,{n:W})}),(0,i.jsx)(`button`,{type:`button`,className:o.button,onClick:J,children:e(`clearSelection`)})]}),k!==null&&(0,i.jsx)(`div`,{className:o.empty,children:e(`loadFailed`,{msg:k})}),k===null&&T===null&&[0,1,2].map(e=>(0,i.jsxs)(`div`,{className:o.skeleton,children:[(0,i.jsx)(`i`,{}),(0,i.jsx)(`i`,{}),(0,i.jsx)(`i`,{})]},e)),k===null&&T!==null&&T.records.length===0&&(0,i.jsx)(`div`,{className:o.empty,children:e(`empty`)}),(T?.records??[]).map((t,n)=>(0,i.jsxs)(`div`,{className:F.has(t.id)?`${o.item} ${o.itemSelected}`:o.item,style:{animationDelay:`${String(Math.min(n,12)*28)}ms`},children:[(0,i.jsxs)(`div`,{className:o.row1,children:[(0,i.jsx)(`input`,{type:`checkbox`,className:o.itemCheck,checked:F.has(t.id),"aria-label":t.content.slice(0,24),onChange:()=>q(t.id)}),(0,i.jsx)(`span`,{className:`${o.statusWrap} ${o[t.status]}`,children:e(c[t.status])}),(0,i.jsx)(`span`,{className:o.chip,children:m(e,t.kind)}),(0,i.jsx)(`span`,{className:o.scopeTag,children:e(u[t.scope])}),(0,i.jsx)(`span`,{className:o.timeTag,title:y(t.createdAt),children:b(e,t.createdAt)})]}),(0,i.jsx)(`div`,{className:o.content,children:t.content}),(0,i.jsxs)(`div`,{className:o.meta,children:[(0,i.jsxs)(`span`,{className:o.meterField,children:[e(`importance`),(0,i.jsx)(x,{value:t.importance}),t.importance.toFixed(2)]}),(0,i.jsxs)(`span`,{className:o.meterField,children:[e(`confidence`),(0,i.jsx)(x,{value:t.confidence,conf:!0}),t.confidence.toFixed(2)]}),(0,i.jsx)(`span`,{children:e(`accessCount`,{n:t.accessCount})}),(0,i.jsx)(`span`,{children:_(e,t)})]}),(0,i.jsxs)(`div`,{className:o.ops,children:[(0,i.jsx)(`button`,{type:`button`,className:o.button,onClick:()=>{V(`review`,t)},children:e(`detail`)}),(0,i.jsx)(`button`,{type:`button`,className:o.button,onClick:()=>{V(`edit`,t)},children:e(`edit`)}),t.status===`active`?(0,i.jsx)(`button`,{type:`button`,className:o.button,onClick:()=>{B(`forget`,t)},children:e(`forget`)}):(0,i.jsx)(`button`,{type:`button`,className:o.button,onClick:()=>{B(`restore`,t)},children:e(`restore`)})]}),j!==null&&j.record.id===t.id&&(0,i.jsx)(`div`,{className:o.expand,children:j.kind===`review`?(0,i.jsx)(C,{t:e,recordId:t.id,scope:t.scope}):(0,i.jsx)(w,{t:e,record:t,onClose:()=>{M(null)},onSaved:()=>{M(null),z()}})})]},t.id)),(0,i.jsxs)(`div`,{className:o.pager,children:[(0,i.jsx)(`button`,{type:`button`,className:o.button,disabled:g===0,onClick:()=>{S(Math.max(0,g-20)),M(null),J()},children:e(`prevPage`)}),(0,i.jsx)(`span`,{children:e(`pagerInfo`,{page:Q,pages:$,total:T?.total??0})}),(0,i.jsx)(`button`,{type:`button`,className:o.button,disabled:T===null||g+20>=T.total,onClick:()=>{S(g+20),M(null),J()},children:e(`nextPage`)})]})]})}let E=`engram`,D={nav:`记忆库`,scopeUser:`用户级`,scopeProject:`项目级`,refresh:`刷新`,exportMd:`导出 MD`,exportJson:`导出 JSON`,allStatuses:`全部状态`,allKinds:`全部种类`,searchPlaceholder:`按内容搜索…`,statusActive:`生效中`,statusArchived:`已归档`,statusForgotten:`已遗忘`,kindFact:`事实`,kindPreference:`偏好`,kindDecision:`决策`,kindEpisode:`事件`,kindSkill:`技能`,labelContent:`内容`,labelKind:`种类`,labelStatus:`状态`,labelScope:`作用域`,importance:`重要性`,confidence:`置信`,accessCount:`访问 {n} 次`,labelCreated:`创建时间`,timeJustNow:`刚刚`,timeMinutesAgo:`{n} 分钟前`,timeHoursAgo:`{n} 小时前`,timeDaysAgo:`{n} 天前`,sourceExplicit:`显式保存`,sourceSession:`来源 {id}`,round:`第 {n} 轮`,cardActive:`生效 {n}`,signalRatio:`信噪比 {n}%`,detail:`详情`,edit:`编辑`,forget:`遗忘`,restore:`恢复`,empty:`没有符合条件的记忆`,loadFailed:`加载失败:{msg}`,loading:`加载中…`,pagerInfo:`第 {page} / {pages} 页 · 共 {total} 条`,prevPage:`上一页`,nextPage:`下一页`,cancel:`取消`,saveWithHint:`保存(旧条目归档)`,detailAttributes:`属性`,detailSource:`来源`,detailRelations:`关系`,detailOperations:`最近操作`,relSupersededBy:`被取代`,relSupersedes:`取代`,relContradicts:`矛盾`,relRelated:`关联`,opWrite:`写入`,opUpdate:`更新`,opForget:`遗忘`,opRestore:`恢复`,opDecay:`衰减归档`,opSuperseded:`被取代`,opIngestRequest:`摄取请求`,opDistillRequest:`蒸馏请求`,selectAll:`全选本页`,deselectAll:`取消全选`,selectedCount:`已选 {n} 条`,batchForget:`批量遗忘({n})`,batchForgetConfirm:`确认遗忘 {n} 条?`,batchRestore:`批量恢复({n})`,clearSelection:`取消选择`},O={nav:`Memory Library`,scopeUser:`User`,scopeProject:`Project`,refresh:`Refresh`,exportMd:`Export MD`,exportJson:`Export JSON`,allStatuses:`All statuses`,allKinds:`All kinds`,searchPlaceholder:`Search content…`,statusActive:`active`,statusArchived:`archived`,statusForgotten:`forgotten`,kindFact:`fact`,kindPreference:`preference`,kindDecision:`decision`,kindEpisode:`episode`,kindSkill:`skill`,labelContent:`Content`,labelKind:`Kind`,labelStatus:`Status`,labelScope:`Scope`,importance:`Importance`,confidence:`Confidence`,accessCount:`{n}× accessed`,labelCreated:`Created`,timeJustNow:`just now`,timeMinutesAgo:`{n} min ago`,timeHoursAgo:`{n} hr ago`,timeDaysAgo:`{n} d ago`,sourceExplicit:`Explicitly saved`,sourceSession:`Source {id}`,round:`round {n}`,cardActive:`{n} active`,signalRatio:`signal {n}%`,detail:`Details`,edit:`Edit`,forget:`Forget`,restore:`Restore`,empty:`No matching memories`,loadFailed:`Failed to load: {msg}`,loading:`Loading…`,pagerInfo:`Page {page} / {pages} · {total} records`,prevPage:`Prev`,nextPage:`Next`,cancel:`Cancel`,saveWithHint:`Save (archives old entry)`,detailAttributes:`Attributes`,detailSource:`Source`,detailRelations:`Relations`,detailOperations:`Recent operations`,relSupersededBy:`Superseded by`,relSupersedes:`Supersedes`,relContradicts:`Contradicts`,relRelated:`Related`,opWrite:`write`,opUpdate:`update`,opForget:`forget`,opRestore:`restore`,opDecay:`decay`,opSuperseded:`superseded`,opIngestRequest:`ingest-request`,opDistillRequest:`distill-request`,selectAll:`Select all on page`,deselectAll:`Deselect all`,selectedCount:`{n} selected`,batchForget:`Forget selected ({n})`,batchForgetConfirm:`Forget {n} entries?`,batchRestore:`Restore selected ({n})`,clearSelection:`Clear selection`},k=[`slots`,`locale`];function A(e){e.effect(()=>e.locale.register(E,{zh:D,en:O}),`dsh-engram: dictionaries`);let t=e.locale.bind(E);e.slots.inject(`settings.section`,()=>e.slots.register({name:`settings.section`,id:`engram`,order:20,label:()=>t(`nav`),locale:E},T))}return n.apply=A,n.inject=k,t.exports}});
|
|
1
|
+
window.__ModuleLoader__.load({id:`@kenz1117/dsh-engram`,factory:e=>{var t={exports:{}},n=t.exports;Object.defineProperty(n,Symbol.toStringTag,{value:`Module`});let r=e("react"),i=e("react/jsx-runtime"),a=`@kenz1117/dsh-engram/panel.module.css`;if(typeof document<`u`&&document.querySelector(`style[data-plugin-css=`+JSON.stringify(a)+`]`)===null){let e=document.createElement(`style`);e.dataset.plugin=`@kenz1117/dsh-engram`,e.dataset.pluginCss=a,e.textContent=`.bWwFiW_panel{max-width:920px;animation:.24s both bWwFiW_rise}@keyframes bWwFiW_rise{0%{opacity:0;transform:translateY(6px)}to{opacity:1;transform:none}}.bWwFiW_toolbar{flex-wrap:wrap;align-items:center;gap:8px;margin-bottom:16px;display:flex}.bWwFiW_scopeTabs{border-bottom:1px solid var(--dsw-alias-border-l2);align-items:flex-end;gap:20px;margin-right:auto;display:flex}.bWwFiW_scopeOn,.bWwFiW_scopeOff{color:var(--dsw-alias-label-tertiary);cursor:pointer;background:0 0;border:0;padding:7px 1px 9px;font-size:13px;line-height:20px;transition:color .14s;position:relative}.bWwFiW_scopeOn,.bWwFiW_scopeOff:hover{color:var(--dsw-alias-label-primary)}.bWwFiW_scopeOn:after{background:var(--dsw-alias-brand-primary);content:"";border-radius:2px 2px 0 0;height:2px;position:absolute;bottom:-1px;left:0;right:0}.bWwFiW_button{color:var(--dsw-alias-label-secondary);border:1px solid var(--dsw-alias-border-l2);cursor:pointer;background:0 0;border-radius:8px;padding:5px 12px;font-size:13px;line-height:18px;transition:color .14s,border-color .14s,background .14s,transform .1s}.bWwFiW_button:hover{color:var(--dsw-alias-label-primary);border-color:var(--dsw-alias-brand-primary);background:color-mix(in srgb, var(--dsw-alias-brand-primary) 7%, transparent)}.bWwFiW_button:active{transform:scale(.97)}.bWwFiW_button:disabled{opacity:.4;cursor:default;border-color:var(--dsw-alias-border-l2);color:var(--dsw-alias-label-tertiary);background:0 0;transform:none}.bWwFiW_primary{background:var(--dsw-alias-button-primary-fill);border-color:var(--dsw-alias-button-primary-fill);color:var(--dsw-alias-label-primary-foreground)}.bWwFiW_primary:hover{background:var(--dsw-alias-button-primary-fill);color:var(--dsw-alias-label-primary-foreground);filter:brightness(1.08)}.bWwFiW_cards{grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:12px;margin-bottom:16px;display:grid}.bWwFiW_card{background:var(--dsw-alias-bg-layer-1);border:1px solid var(--dsw-alias-border-l2);text-align:left;cursor:pointer;color:var(--dsw-alias-label-primary);font:inherit;border-radius:12px;padding:14px 16px 12px;transition:border-color .16s,transform .16s,box-shadow .16s;position:relative;overflow:hidden}.bWwFiW_card:hover{border-color:var(--dsw-alias-border-l1,var(--dsw-alias-brand-primary));box-shadow:0 6px 18px -8px color-mix(in srgb, var(--dsw-alias-label-primary) 22%, transparent);transform:translateY(-1px)}.bWwFiW_card b{font-variant-numeric:tabular-nums;letter-spacing:-.01em;font-size:26px;line-height:1.15;display:block}.bWwFiW_card span{color:var(--dsw-alias-label-secondary);font-size:12px}.bWwFiW_cardOn{border-color:color-mix(in srgb, var(--dsw-alias-brand-primary) 55%, transparent);background:color-mix(in srgb, var(--dsw-alias-brand-primary) 5%, var(--dsw-alias-bg-layer-1))}.bWwFiW_cardOn:before{background:var(--dsw-alias-brand-primary);content:"";width:3px;position:absolute;top:0;bottom:0;left:0}.bWwFiW_cardMeter{background:color-mix(in srgb, var(--dsw-alias-label-tertiary) 18%, transparent);border-radius:2px;height:3px;margin-top:10px;display:block;overflow:hidden}.bWwFiW_cardMeter i{background:var(--dsw-alias-brand-primary);border-radius:2px;height:100%;transition:width .3s;display:block}.bWwFiW_filters{flex-wrap:wrap;gap:8px;margin-bottom:16px;display:flex}.bWwFiW_input{background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-primary);border:1px solid var(--dsw-alias-border-l2);border-radius:8px;padding:6px 10px;font-size:13px;transition:border-color .14s,box-shadow .14s}.bWwFiW_input:focus-visible{border-color:var(--dsw-alias-brand-primary);box-shadow:0 0 0 3px color-mix(in srgb, var(--dsw-alias-brand-primary) 18%, transparent);outline:none}.bWwFiW_filters .bWwFiW_input{flex:1;min-width:160px}.bWwFiW_filters select.bWwFiW_input{flex:0 auto;min-width:120px}.bWwFiW_item{background:var(--dsw-alias-bg-layer-1);border:1px solid var(--dsw-alias-border-l2);border-radius:12px;margin-bottom:10px;padding:13px 16px 11px;transition:border-color .16s,background .16s,box-shadow .16s;animation:.26s both bWwFiW_rise;position:relative}.bWwFiW_item:hover{border-color:color-mix(in srgb, var(--dsw-alias-brand-primary) 40%, var(--dsw-alias-border-l2));box-shadow:0 8px 22px -12px color-mix(in srgb, var(--dsw-alias-label-primary) 26%, transparent)}.bWwFiW_itemSelected{border-color:var(--dsw-alias-brand-primary);background:color-mix(in srgb, var(--dsw-alias-brand-primary) 4%, var(--dsw-alias-bg-layer-1))}.bWwFiW_row1{flex-wrap:wrap;align-items:center;gap:10px;margin-bottom:7px;display:flex}.bWwFiW_itemCheck{accent-color:var(--dsw-alias-brand-primary);cursor:pointer;flex:none;width:15px;height:15px}.bWwFiW_statusWrap{color:var(--dsw-alias-label-secondary);align-items:center;gap:6px;font-size:12px;display:inline-flex}.bWwFiW_statusWrap:before{background:var(--dsw-alias-label-tertiary);content:"";border-radius:50%;width:7px;height:7px}.bWwFiW_statusWrap.bWwFiW_active{color:var(--dsw-alias-state-success-primary)}.bWwFiW_statusWrap.bWwFiW_active:before{background:var(--dsw-alias-state-success-primary);box-shadow:0 0 0 3px color-mix(in srgb, var(--dsw-alias-state-success-primary) 16%, transparent)}.bWwFiW_statusWrap.bWwFiW_archived{color:var(--dsw-alias-state-warn-primary)}.bWwFiW_statusWrap.bWwFiW_archived:before{background:var(--dsw-alias-state-warn-primary)}.bWwFiW_statusWrap.bWwFiW_forgotten{color:var(--dsw-alias-state-error-primary)}.bWwFiW_statusWrap.bWwFiW_forgotten:before{background:var(--dsw-alias-state-error-primary)}.bWwFiW_chip{color:var(--dsw-alias-brand-primary);background:color-mix(in srgb, var(--dsw-alias-brand-primary) 10%, transparent);border-radius:6px;padding:0 8px;font-size:11px;line-height:18px}.bWwFiW_redactedChip{color:var(--dsw-alias-state-warn-primary);background:color-mix(in srgb, var(--dsw-alias-state-warn-primary) 12%, transparent)}.bWwFiW_scopeTag{color:var(--dsw-alias-label-tertiary);font-size:11px}.bWwFiW_timeTag{color:var(--dsw-alias-label-tertiary);font-variant-numeric:tabular-nums;margin-left:auto;font-size:12px}.bWwFiW_content{white-space:pre-wrap;word-break:break-word;color:var(--dsw-alias-label-primary);-webkit-line-clamp:4;-webkit-box-orient:vertical;font-size:14px;line-height:1.7;display:-webkit-box;overflow:hidden}.bWwFiW_meta{color:var(--dsw-alias-label-secondary);flex-wrap:wrap;align-items:center;gap:16px;margin-top:8px;font-size:12px;display:flex}.bWwFiW_meterField{font-variant-numeric:tabular-nums;align-items:center;gap:7px;display:inline-flex}.bWwFiW_meter{background:color-mix(in srgb, var(--dsw-alias-label-tertiary) 18%, transparent);border-radius:2px;width:52px;height:4px;overflow:hidden}.bWwFiW_meter i{background:var(--dsw-alias-brand-primary);border-radius:2px;height:100%;display:block}.bWwFiW_meter.bWwFiW_conf i{background:var(--dsw-alias-state-success-primary)}.bWwFiW_ops{opacity:.55;gap:6px;margin-top:9px;transition:opacity .16s;display:flex}.bWwFiW_item:hover .bWwFiW_ops,.bWwFiW_item:focus-within .bWwFiW_ops{opacity:1}.bWwFiW_ops .bWwFiW_button{background:var(--dsw-alias-fill-tsp-secondary);border-color:#0000;padding:3px 10px;font-size:12px}.bWwFiW_ops .bWwFiW_button:hover{border-color:var(--dsw-alias-brand-primary);background:color-mix(in srgb, var(--dsw-alias-brand-primary) 8%, transparent)}.bWwFiW_batchBar{z-index:5;background:color-mix(in srgb, var(--dsw-alias-bg-layer-1) 82%, transparent);backdrop-filter:blur(10px);border:1px solid color-mix(in srgb, var(--dsw-alias-brand-primary) 45%, var(--dsw-alias-border-l2));box-shadow:0 10px 28px -12px color-mix(in srgb, var(--dsw-alias-label-primary) 30%, transparent);border-radius:12px;flex-wrap:wrap;align-items:center;gap:8px;margin-bottom:12px;padding:9px 14px;animation:.2s both bWwFiW_barUp;display:flex;position:sticky;bottom:12px}@keyframes bWwFiW_barUp{0%{opacity:0;transform:translateY(8px)}to{opacity:1;transform:none}}.bWwFiW_batchBar>span{color:var(--dsw-alias-label-primary);font-variant-numeric:tabular-nums;margin-right:auto;font-size:13px}.bWwFiW_danger{background:var(--dsw-alias-state-error-primary);border-color:var(--dsw-alias-state-error-primary);color:var(--dsw-alias-label-primary-foreground)}.bWwFiW_danger:hover{background:var(--dsw-alias-state-error-primary);color:var(--dsw-alias-label-primary-foreground);filter:brightness(1.08)}.bWwFiW_skeleton{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-1);border-radius:12px;margin-bottom:10px;padding:13px 16px}.bWwFiW_skeleton i{background:linear-gradient(90deg, color-mix(in srgb, var(--dsw-alias-label-tertiary) 12%, transparent) 25%, color-mix(in srgb, var(--dsw-alias-label-tertiary) 24%, transparent) 50%, color-mix(in srgb, var(--dsw-alias-label-tertiary) 12%, transparent) 75%);background-size:200% 100%;border-radius:6px;height:12px;margin:8px 0;animation:1.3s linear infinite bWwFiW_shimmer;display:block}.bWwFiW_skeleton i:first-child{width:34%;margin-top:2px}.bWwFiW_skeleton i:last-child{width:62%}@keyframes bWwFiW_shimmer{0%{background-position:200% 0}to{background-position:-200% 0}}.bWwFiW_empty{text-align:center;color:var(--dsw-alias-label-secondary);padding:48px 0 52px}.bWwFiW_empty:before{border:1px solid var(--dsw-alias-border-l2);background:linear-gradient(135deg, color-mix(in srgb, var(--dsw-alias-brand-primary) 14%, transparent), transparent 70%);content:"";border-radius:10px;width:34px;height:34px;margin:0 auto 12px;display:block;transform:rotate(45deg)scale(.8)}.bWwFiW_expand{border-top:1px dashed var(--dsw-alias-border-l2);margin-top:10px;padding-top:12px;animation:.18s both bWwFiW_rise}.bWwFiW_expandLoading{color:var(--dsw-alias-label-secondary);font-size:13px}.bWwFiW_attrGrid{grid-template-columns:max-content 1fr;align-items:center;gap:7px 16px;font-size:13px;display:grid}.bWwFiW_attrGrid>dt{color:var(--dsw-alias-label-tertiary);margin:0;font-size:12px}.bWwFiW_attrGrid>dd{color:var(--dsw-alias-label-primary);flex-wrap:wrap;align-items:center;gap:8px;margin:0;display:flex}.bWwFiW_relBlock{margin-top:12px}.bWwFiW_relBlock>h5{color:var(--dsw-alias-label-tertiary);margin:0 0 6px;font-size:12px;font-weight:500}.bWwFiW_relChips{flex-wrap:wrap;gap:6px;display:flex}.bWwFiW_relChip{border:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-secondary);background:var(--dsw-alias-bg-base);border-radius:6px;padding:2px 8px;font-family:ui-monospace,SF Mono,Menlo,monospace;font-size:11px}.bWwFiW_timeline{margin:12px 0 0;padding:0 0 0 14px;list-style:none;position:relative}.bWwFiW_timeline:before{background:var(--dsw-alias-border-l2);content:"";width:1px;position:absolute;top:6px;bottom:6px;left:3px}.bWwFiW_timeline li{color:var(--dsw-alias-label-secondary);padding:5px 0 5px 12px;font-size:12px;line-height:1.6;position:relative}.bWwFiW_timeline li:before{background:var(--dsw-alias-bg-layer-1);border:1px solid var(--dsw-alias-brand-primary);content:"";border-radius:50%;width:7px;height:7px;position:absolute;top:10px;left:-14px}.bWwFiW_timeline time{font-variant-numeric:tabular-nums;color:var(--dsw-alias-label-tertiary);margin-right:8px}.bWwFiW_timeline b{color:var(--dsw-alias-label-primary);font-weight:500}.bWwFiW_editForm{flex-direction:column;display:flex}.bWwFiW_editForm .bWwFiW_input{box-sizing:border-box;width:100%}.bWwFiW_fieldLabel{color:var(--dsw-alias-label-secondary);margin:12px 0 5px;font-size:12px;display:block}.bWwFiW_editForm input[type=range]{accent-color:var(--dsw-alias-brand-primary)}.bWwFiW_modalFoot{justify-content:flex-end;gap:8px;margin-top:14px;display:flex}.bWwFiW_pager{color:var(--dsw-alias-label-secondary);font-variant-numeric:tabular-nums;justify-content:center;align-items:center;gap:12px;margin-top:18px;font-size:13px;display:flex}`,document.head.appendChild(e)}var o={empty:`bWwFiW_empty`,scopeTabs:`bWwFiW_scopeTabs`,item:`bWwFiW_item`,cardMeter:`bWwFiW_cardMeter`,modalFoot:`bWwFiW_modalFoot`,itemCheck:`bWwFiW_itemCheck`,button:`bWwFiW_button`,shimmer:`bWwFiW_shimmer`,expand:`bWwFiW_expand`,relChip:`bWwFiW_relChip`,scopeOn:`bWwFiW_scopeOn`,active:`bWwFiW_active`,barUp:`bWwFiW_barUp`,relChips:`bWwFiW_relChips`,editForm:`bWwFiW_editForm`,attrGrid:`bWwFiW_attrGrid`,input:`bWwFiW_input`,expandLoading:`bWwFiW_expandLoading`,forgotten:`bWwFiW_forgotten`,danger:`bWwFiW_danger`,relBlock:`bWwFiW_relBlock`,content:`bWwFiW_content`,rise:`bWwFiW_rise`,primary:`bWwFiW_primary`,panel:`bWwFiW_panel`,ops:`bWwFiW_ops`,batchBar:`bWwFiW_batchBar`,statusWrap:`bWwFiW_statusWrap`,conf:`bWwFiW_conf`,cardOn:`bWwFiW_cardOn`,timeline:`bWwFiW_timeline`,fieldLabel:`bWwFiW_fieldLabel`,card:`bWwFiW_card`,scopeTag:`bWwFiW_scopeTag`,meta:`bWwFiW_meta`,cards:`bWwFiW_cards`,pager:`bWwFiW_pager`,filters:`bWwFiW_filters`,meter:`bWwFiW_meter`,scopeOff:`bWwFiW_scopeOff`,row1:`bWwFiW_row1`,timeTag:`bWwFiW_timeTag`,redactedChip:`bWwFiW_redactedChip`,toolbar:`bWwFiW_toolbar`,itemSelected:`bWwFiW_itemSelected`,meterField:`bWwFiW_meterField`,skeleton:`bWwFiW_skeleton`,chip:`bWwFiW_chip`,archived:`bWwFiW_archived`};let s=[`fact`,`preference`,`decision`,`episode`,`skill`],c={active:`statusActive`,archived:`statusArchived`,forgotten:`statusForgotten`},l={fact:`kindFact`,preference:`kindPreference`,decision:`kindDecision`,episode:`kindEpisode`,skill:`kindSkill`},u={user:`scopeUser`,project:`scopeProject`},d={write:`opWrite`,update:`opUpdate`,forget:`opForget`,restore:`opRestore`,decay:`opDecay`,superseded:`opSuperseded`,"ingest-request":`opIngestRequest`,"distill-request":`opDistillRequest`},f={supersededBy:`relSupersededBy`,supersedes:`relSupersedes`,contradicts:`relContradicts`,related:`relRelated`},p={kind:`labelKind`,scope:`labelScope`,status:`labelStatus`};function m(e,t){let n=l[t];return n===void 0?t:e(n)}function h(e,t){let n=d[t];return n===void 0?t:e(n)}function g(e,t,n){if(n===null)return``;if(t!==`write`&&t!==`update`&&t!==`superseded`)return` ${n}`;try{let t=JSON.parse(n),r=Object.entries(t);return r.length===0?` ${n}`:` `+r.map(([t,n])=>{let r=p[t];return r===void 0?`${t}=${String(n)}`:t===`kind`&&typeof n==`string`?`${e(r)}=${m(e,n)}`:t===`scope`&&(n===`user`||n===`project`)?`${e(r)}=${e(u[n])}`:`${e(r)}=${String(n)}`}).join(` · `)}catch{return` ${n}`}}function _(e,t){if(t.sourceSessionId===null)return e(`sourceExplicit`);let n=`${t.sourceSessionId.slice(0,16)}…`;return e(`sourceSession`,{id:t.sourceRound===null?n:`${n} ${e(`round`,{n:t.sourceRound})}`})}async function v(e,t){let n=await fetch(`/api/engram/${e}`,t),r=await n.json();if(!n.ok)throw Error(r.error??`HTTP ${String(n.status)}`);return r}function y(e){return new Date(e).toLocaleString(navigator.language||`zh-CN`,{hour12:!1})}function b(e,t){let n=Math.max(0,Date.now()-t),r=Math.floor(n/6e4);if(r<1)return e(`timeJustNow`);if(r<60)return e(`timeMinutesAgo`,{n:r});let i=Math.floor(r/60);return i<48?e(`timeHoursAgo`,{n:i}):e(`timeDaysAgo`,{n:Math.floor(i/24)})}function x({value:e,conf:t}){return(0,i.jsx)(`span`,{className:t===!0?`${o.meter} ${o.conf}`:o.meter,children:(0,i.jsx)(`i`,{style:{width:`${String(Math.round(Math.min(1,Math.max(0,e))*100))}%`}})})}function S({ids:e}){return(0,i.jsx)(`div`,{className:o.relChips,children:e.map(e=>(0,i.jsx)(`span`,{className:o.relChip,title:e,children:e.slice(0,18)},e))})}function C({t:e,recordId:t,scope:n}){let[a,s]=(0,r.useState)(null),[l,u]=(0,r.useState)(null);if((0,r.useEffect)(()=>{let e=!1;return v(`review?scope=${n}&id=${encodeURIComponent(t)}`).then(t=>{e||s(t)}).catch(t=>{e||u(t.message)}),()=>{e=!0}},[t,n,e]),l!==null)return(0,i.jsx)(`div`,{className:o.expandLoading,children:e(`loadFailed`,{msg:l})});if(a===null)return(0,i.jsx)(`div`,{className:o.expandLoading,children:e(`loading`)});let{record:d}=a,p=[`supersededBy`,`supersedes`,`contradicts`,`related`].map(e=>({key:e,label:f[e],ids:a[e]??[]})).filter(e=>e.ids.length>0),b=a.operations??[];return(0,i.jsxs)(`div`,{children:[(0,i.jsxs)(`dl`,{className:o.attrGrid,children:[(0,i.jsx)(`dt`,{children:e(`labelContent`)}),(0,i.jsx)(`dd`,{children:d.content}),(0,i.jsx)(`dt`,{children:e(`labelKind`)}),(0,i.jsx)(`dd`,{children:(0,i.jsx)(`span`,{className:o.chip,children:m(e,d.kind)})}),(0,i.jsx)(`dt`,{children:e(`labelStatus`)}),(0,i.jsx)(`dd`,{children:(0,i.jsx)(`span`,{className:`${o.statusWrap} ${o[d.status]}`,children:e(c[d.status])})}),(0,i.jsx)(`dt`,{children:e(`importance`)}),(0,i.jsxs)(`dd`,{children:[d.importance.toFixed(2),(0,i.jsx)(x,{value:d.importance})]}),(0,i.jsx)(`dt`,{children:e(`confidence`)}),(0,i.jsxs)(`dd`,{children:[d.confidence.toFixed(2),(0,i.jsx)(x,{value:d.confidence,conf:!0})]}),(0,i.jsx)(`dt`,{children:e(`detailSource`)}),(0,i.jsx)(`dd`,{children:_(e,d)}),(0,i.jsx)(`dt`,{children:e(`labelCreated`)}),(0,i.jsx)(`dd`,{children:y(d.createdAt)})]}),p.map(({key:t,label:n,ids:r})=>(0,i.jsxs)(`div`,{className:o.relBlock,children:[(0,i.jsx)(`h5`,{children:n===void 0?t:e(n)}),(0,i.jsx)(S,{ids:r})]},t)),b.length>0&&(0,i.jsxs)(`div`,{className:o.relBlock,children:[(0,i.jsx)(`h5`,{children:e(`detailOperations`)}),(0,i.jsx)(`ul`,{className:o.timeline,children:b.map((t,n)=>(0,i.jsxs)(`li`,{children:[(0,i.jsx)(`time`,{children:y(t.at)}),(0,i.jsx)(`b`,{children:h(e,t.op)}),g(e,t.op,t.detail)]},n))})]})]})}function w({t:e,record:t,onClose:n,onSaved:a}){let[c,l]=(0,r.useState)(t.content),[u,d]=(0,r.useState)(t.kind),[f,p]=(0,r.useState)(t.importance);return(0,i.jsxs)(`div`,{className:o.editForm,children:[(0,i.jsx)(`label`,{className:o.fieldLabel,children:e(`labelContent`)}),(0,i.jsx)(`textarea`,{className:o.input,rows:3,value:c,onChange:e=>l(e.target.value)}),(0,i.jsx)(`label`,{className:o.fieldLabel,children:e(`labelKind`)}),(0,i.jsx)(`select`,{className:o.input,value:u,onChange:e=>d(e.target.value),children:s.map(t=>(0,i.jsx)(`option`,{value:t,children:m(e,t)},t))}),(0,i.jsx)(`label`,{className:o.fieldLabel,children:`${e(`importance`)} ${f.toFixed(2)}`}),(0,i.jsx)(`input`,{type:`range`,min:0,max:1,step:.05,value:f,onChange:e=>p(Number(e.target.value))}),(0,i.jsxs)(`div`,{className:o.modalFoot,children:[(0,i.jsx)(`button`,{type:`button`,className:o.button,onClick:n,children:e(`cancel`)}),(0,i.jsx)(`button`,{type:`button`,className:`${o.button} ${o.primary}`,onClick:()=>{v(`update`,{method:`POST`,headers:{"content-type":`application/json`},body:JSON.stringify({id:t.id,scope:t.scope,content:c,kind:u,importance:f})}).then(a).catch(e=>{alert(e.message)})},children:e(`saveWithHint`)})]})]})}function T({t:e}){let[t,n]=(0,r.useState)(`user`),[a,l]=(0,r.useState)(`all`),[d,f]=(0,r.useState)(`all`),[p,h]=(0,r.useState)(`all`),[g,S]=(0,r.useState)(``),[T,E]=(0,r.useState)(0),[D,O]=(0,r.useState)(null),[k,A]=(0,r.useState)(null),[j,M]=(0,r.useState)(null),[N,P]=(0,r.useState)(null),[F,I]=(0,r.useState)(0),[L,R]=(0,r.useState)(new Set),[z,B]=(0,r.useState)(!1),V=(0,r.useCallback)(()=>{I(e=>e+1)},[]);(0,r.useEffect)(()=>{let e=!1,n=new URLSearchParams({scope:t,status:a,kind:d,redacted:p,limit:`20`,offset:String(T)});return g!==``&&n.set(`q`,g),v(`list?${n.toString()}`).then(t=>{e||(O(t),M(null))}).catch(t=>{e||M(t.message)}),v(`stats`).then(t=>{e||A(t.parts)}).catch(()=>{}),()=>{e=!0}},[t,a,d,p,g,T,F]);let H=(e,t)=>{v(e,{method:`POST`,headers:{"content-type":`application/json`},body:JSON.stringify({id:t.id,scope:t.scope})}).then(V).catch(e=>{alert(e.message)})},U=(e,t)=>{P(n=>n!==null&&n.kind===e&&n.record.id===t.id?null:{kind:e,record:t})},W=D?.records??[],G=W.filter(e=>L.has(e.id)),K=G.filter(e=>e.status===`active`).length,q=G.length-K,J=W.length>0&&W.every(e=>L.has(e.id)),Y=e=>{R(t=>{let n=new Set(t);return n.has(e)?n.delete(e):n.add(e),n})},X=()=>{R(new Set),B(!1)},Z=()=>{R(e=>{let t=new Set(e);return J?W.forEach(e=>t.delete(e.id)):W.forEach(e=>t.add(e.id)),t})},Q=e=>{let t=e===`forget`?G.filter(e=>e.status===`active`):G.filter(e=>e.status!==`active`);t.length!==0&&Promise.allSettled(t.map(t=>v(e,{method:`POST`,headers:{"content-type":`application/json`},body:JSON.stringify({id:t.id,scope:t.scope})}))).then(()=>{X(),V()})},$=()=>{if(z){Q(`forget`);return}B(!0)},ee=Math.floor(T/20)+1,te=D===null?1:Math.max(1,Math.ceil(D.total/20));return(0,i.jsxs)(`div`,{className:o.panel,children:[(0,i.jsxs)(`div`,{className:o.toolbar,children:[(0,i.jsx)(`div`,{className:o.scopeTabs,children:[`user`,`project`].map(r=>(0,i.jsx)(`button`,{type:`button`,className:t===r?o.scopeOn:o.scopeOff,onClick:()=>{n(r),E(0),P(null),X()},children:e(u[r])},r))}),(0,i.jsx)(`button`,{type:`button`,className:o.button,onClick:V,children:e(`refresh`)}),(0,i.jsx)(`button`,{type:`button`,className:o.button,onClick:()=>{location.href=`/api/engram/export?scope=${t}&format=markdown`},children:e(`exportMd`)}),(0,i.jsx)(`button`,{type:`button`,className:o.button,onClick:()=>{location.href=`/api/engram/export?scope=${t}&format=json`},children:e(`exportJson`)})]}),(0,i.jsx)(`div`,{className:o.cards,children:(k??[]).map(r=>(0,i.jsxs)(`button`,{type:`button`,className:r.scope===t?`${o.card} ${o.cardOn}`:o.card,onClick:()=>{n(r.scope),E(0),X()},children:[(0,i.jsx)(`b`,{children:r.stats.total}),(0,i.jsx)(`span`,{children:`${e(u[r.scope])} · ${e(`cardActive`,{n:r.stats.active})} · ${e(`signalRatio`,{n:Math.round(r.stats.signalRatio*100)})}`}),(0,i.jsx)(`span`,{className:o.cardMeter,children:(0,i.jsx)(`i`,{style:{width:`${String(Math.round(r.stats.signalRatio*100))}%`}})})]},r.scope))}),(0,i.jsxs)(`div`,{className:o.filters,children:[(0,i.jsxs)(`select`,{className:o.input,value:a,onChange:e=>{l(e.target.value),E(0),P(null),X()},children:[(0,i.jsx)(`option`,{value:`all`,children:e(`allStatuses`)}),(0,i.jsx)(`option`,{value:`active`,children:e(`statusActive`)}),(0,i.jsx)(`option`,{value:`archived`,children:e(`statusArchived`)}),(0,i.jsx)(`option`,{value:`forgotten`,children:e(`statusForgotten`)})]}),(0,i.jsxs)(`select`,{className:o.input,value:d,onChange:e=>{f(e.target.value),E(0),P(null),X()},children:[(0,i.jsx)(`option`,{value:`all`,children:e(`allKinds`)}),s.map(t=>(0,i.jsx)(`option`,{value:t,children:m(e,t)},t))]}),(0,i.jsxs)(`select`,{className:o.input,value:p,onChange:e=>{h(e.target.value),E(0),P(null),X()},children:[(0,i.jsx)(`option`,{value:`all`,children:e(`redactedAll`)}),(0,i.jsx)(`option`,{value:`true`,children:e(`redactedOnly`)}),(0,i.jsx)(`option`,{value:`false`,children:e(`redactedNone`)})]}),(0,i.jsx)(`input`,{className:o.input,placeholder:e(`searchPlaceholder`),value:g,onChange:e=>{S(e.target.value.trim()),E(0),P(null),X()}})]}),L.size>0&&(0,i.jsxs)(`div`,{className:o.batchBar,children:[(0,i.jsx)(`span`,{children:e(`selectedCount`,{n:L.size})}),(0,i.jsx)(`button`,{type:`button`,className:o.button,onClick:Z,children:e(J?`deselectAll`:`selectAll`)}),(0,i.jsx)(`button`,{type:`button`,className:o.button,disabled:q===0,onClick:()=>Q(`restore`),children:e(`batchRestore`,{n:q})}),(0,i.jsx)(`button`,{type:`button`,className:z?`${o.button} ${o.danger}`:o.button,disabled:K===0,onClick:$,children:e(z?`batchForgetConfirm`:`batchForget`,{n:K})}),(0,i.jsx)(`button`,{type:`button`,className:o.button,onClick:X,children:e(`clearSelection`)})]}),j!==null&&(0,i.jsx)(`div`,{className:o.empty,children:e(`loadFailed`,{msg:j})}),j===null&&D===null&&[0,1,2].map(e=>(0,i.jsxs)(`div`,{className:o.skeleton,children:[(0,i.jsx)(`i`,{}),(0,i.jsx)(`i`,{}),(0,i.jsx)(`i`,{})]},e)),j===null&&D!==null&&D.records.length===0&&(0,i.jsx)(`div`,{className:o.empty,children:e(`empty`)}),(D?.records??[]).map((t,n)=>(0,i.jsxs)(`div`,{className:L.has(t.id)?`${o.item} ${o.itemSelected}`:o.item,style:{animationDelay:`${String(Math.min(n,12)*28)}ms`},children:[(0,i.jsxs)(`div`,{className:o.row1,children:[(0,i.jsx)(`input`,{type:`checkbox`,className:o.itemCheck,checked:L.has(t.id),"aria-label":t.content.slice(0,24),onChange:()=>Y(t.id)}),(0,i.jsx)(`span`,{className:`${o.statusWrap} ${o[t.status]}`,children:e(c[t.status])}),(0,i.jsx)(`span`,{className:o.chip,children:m(e,t.kind)}),t.content.includes(`[REDACTED:`)&&(0,i.jsx)(`span`,{className:`${o.chip} ${o.redactedChip}`,children:e(`tagRedacted`)}),(0,i.jsx)(`span`,{className:o.scopeTag,children:e(u[t.scope])}),(0,i.jsx)(`span`,{className:o.timeTag,title:y(t.createdAt),children:b(e,t.createdAt)})]}),(0,i.jsx)(`div`,{className:o.content,children:t.content}),(0,i.jsxs)(`div`,{className:o.meta,children:[(0,i.jsxs)(`span`,{className:o.meterField,children:[e(`importance`),(0,i.jsx)(x,{value:t.importance}),t.importance.toFixed(2)]}),(0,i.jsxs)(`span`,{className:o.meterField,children:[e(`confidence`),(0,i.jsx)(x,{value:t.confidence,conf:!0}),t.confidence.toFixed(2)]}),(0,i.jsx)(`span`,{children:e(`accessCount`,{n:t.accessCount})}),(0,i.jsx)(`span`,{children:_(e,t)})]}),(0,i.jsxs)(`div`,{className:o.ops,children:[(0,i.jsx)(`button`,{type:`button`,className:o.button,onClick:()=>{U(`review`,t)},children:e(`detail`)}),(0,i.jsx)(`button`,{type:`button`,className:o.button,onClick:()=>{U(`edit`,t)},children:e(`edit`)}),t.status===`active`?(0,i.jsx)(`button`,{type:`button`,className:o.button,onClick:()=>{H(`forget`,t)},children:e(`forget`)}):(0,i.jsx)(`button`,{type:`button`,className:o.button,onClick:()=>{H(`restore`,t)},children:e(`restore`)})]}),N!==null&&N.record.id===t.id&&(0,i.jsx)(`div`,{className:o.expand,children:N.kind===`review`?(0,i.jsx)(C,{t:e,recordId:t.id,scope:t.scope}):(0,i.jsx)(w,{t:e,record:t,onClose:()=>{P(null)},onSaved:()=>{P(null),V()}})})]},t.id)),(0,i.jsxs)(`div`,{className:o.pager,children:[(0,i.jsx)(`button`,{type:`button`,className:o.button,disabled:T===0,onClick:()=>{E(Math.max(0,T-20)),P(null),X()},children:e(`prevPage`)}),(0,i.jsx)(`span`,{children:e(`pagerInfo`,{page:ee,pages:te,total:D?.total??0})}),(0,i.jsx)(`button`,{type:`button`,className:o.button,disabled:D===null||T+20>=D.total,onClick:()=>{E(T+20),P(null),X()},children:e(`nextPage`)})]})]})}let E=`engram`,D={nav:`记忆库`,scopeUser:`用户级`,scopeProject:`项目级`,refresh:`刷新`,exportMd:`导出 MD`,exportJson:`导出 JSON`,allStatuses:`全部状态`,allKinds:`全部种类`,redactedAll:`全部脱敏`,redactedOnly:`含脱敏标记`,redactedNone:`无脱敏标记`,tagRedacted:`已脱敏`,searchPlaceholder:`按内容搜索…`,statusActive:`生效中`,statusArchived:`已归档`,statusForgotten:`已遗忘`,kindFact:`事实`,kindPreference:`偏好`,kindDecision:`决策`,kindEpisode:`事件`,kindSkill:`技能`,labelContent:`内容`,labelKind:`种类`,labelStatus:`状态`,labelScope:`作用域`,importance:`重要性`,confidence:`置信`,accessCount:`访问 {n} 次`,labelCreated:`创建时间`,timeJustNow:`刚刚`,timeMinutesAgo:`{n} 分钟前`,timeHoursAgo:`{n} 小时前`,timeDaysAgo:`{n} 天前`,sourceExplicit:`显式保存`,sourceSession:`来源 {id}`,round:`第 {n} 轮`,cardActive:`生效 {n}`,signalRatio:`信噪比 {n}%`,detail:`详情`,edit:`编辑`,forget:`遗忘`,restore:`恢复`,empty:`没有符合条件的记忆`,loadFailed:`加载失败:{msg}`,loading:`加载中…`,pagerInfo:`第 {page} / {pages} 页 · 共 {total} 条`,prevPage:`上一页`,nextPage:`下一页`,cancel:`取消`,saveWithHint:`保存(旧条目归档)`,detailAttributes:`属性`,detailSource:`来源`,detailRelations:`关系`,detailOperations:`最近操作`,relSupersededBy:`被取代`,relSupersedes:`取代`,relContradicts:`矛盾`,relRelated:`关联`,opWrite:`写入`,opUpdate:`更新`,opForget:`遗忘`,opRestore:`恢复`,opDecay:`衰减归档`,opSuperseded:`被取代`,opIngestRequest:`摄取请求`,opDistillRequest:`蒸馏请求`,selectAll:`全选本页`,deselectAll:`取消全选`,selectedCount:`已选 {n} 条`,batchForget:`批量遗忘({n})`,batchForgetConfirm:`确认遗忘 {n} 条?`,batchRestore:`批量恢复({n})`,clearSelection:`取消选择`},O={nav:`Memory Library`,scopeUser:`User`,scopeProject:`Project`,refresh:`Refresh`,exportMd:`Export MD`,exportJson:`Export JSON`,allStatuses:`All statuses`,allKinds:`All kinds`,redactedAll:`All redaction`,redactedOnly:`Redacted only`,redactedNone:`Not redacted`,tagRedacted:`redacted`,searchPlaceholder:`Search content…`,statusActive:`active`,statusArchived:`archived`,statusForgotten:`forgotten`,kindFact:`fact`,kindPreference:`preference`,kindDecision:`decision`,kindEpisode:`episode`,kindSkill:`skill`,labelContent:`Content`,labelKind:`Kind`,labelStatus:`Status`,labelScope:`Scope`,importance:`Importance`,confidence:`Confidence`,accessCount:`{n}× accessed`,labelCreated:`Created`,timeJustNow:`just now`,timeMinutesAgo:`{n} min ago`,timeHoursAgo:`{n} hr ago`,timeDaysAgo:`{n} d ago`,sourceExplicit:`Explicitly saved`,sourceSession:`Source {id}`,round:`round {n}`,cardActive:`{n} active`,signalRatio:`signal {n}%`,detail:`Details`,edit:`Edit`,forget:`Forget`,restore:`Restore`,empty:`No matching memories`,loadFailed:`Failed to load: {msg}`,loading:`Loading…`,pagerInfo:`Page {page} / {pages} · {total} records`,prevPage:`Prev`,nextPage:`Next`,cancel:`Cancel`,saveWithHint:`Save (archives old entry)`,detailAttributes:`Attributes`,detailSource:`Source`,detailRelations:`Relations`,detailOperations:`Recent operations`,relSupersededBy:`Superseded by`,relSupersedes:`Supersedes`,relContradicts:`Contradicts`,relRelated:`Related`,opWrite:`write`,opUpdate:`update`,opForget:`forget`,opRestore:`restore`,opDecay:`decay`,opSuperseded:`superseded`,opIngestRequest:`ingest-request`,opDistillRequest:`distill-request`,selectAll:`Select all on page`,deselectAll:`Deselect all`,selectedCount:`{n} selected`,batchForget:`Forget selected ({n})`,batchForgetConfirm:`Forget {n} entries?`,batchRestore:`Restore selected ({n})`,clearSelection:`Clear selection`},k=[`slots`,`locale`];function A(e){e.effect(()=>e.locale.register(E,{zh:D,en:O}),`dsh-engram: dictionaries`);let t=e.locale.bind(E);e.slots.inject(`settings.section`,()=>e.slots.register({name:`settings.section`,id:`engram`,order:20,label:()=>t(`nav`),locale:E},T))}return n.apply=A,n.inject=k,t.exports}});
|
|
2
2
|
//# sourceMappingURL=client.js.map
|
package/lib/client.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.js","names":["styles","useState","useCallback"],"sources":["../src/client/EngramPanel.tsx","../src/client/locales.ts","../src/client/index.ts"],"sourcesContent":["/**\n * 记忆库设置面板:统计卡片、过滤列表、批量操作、编辑(取代链)、遗忘/恢复、导出。\n * 数据经回环 API(/api/engram/*)读写;详情与编辑为条目下方行内展开\n * (不嵌套弹窗);文案全部走宿主 locale 词典(zh/en),语言切换自动\n * 重渲染;数据层英文枚举(status/kind/op)只在显示层映射;内容节点\n * 一律 DOM/JSX 构建(防 XSS)。\n * @module @kenz1117/dsh-engram/client/EngramPanel\n */\n\nimport { useCallback, useEffect, useState } from 'react'\nimport type { PropsLocale } from '@deepseek-ai/dsh-client-ui-slots'\nimport styles from './panel.module.css'\nimport { NS, type EngramKey } from './locales.ts'\n\n/** 列表/详情用的记忆视图(宿主 /api/engram/list 的行结构)。 */\ninterface MemoryRow {\n readonly id: string\n readonly scope: 'user' | 'project'\n readonly kind: string\n readonly content: string\n readonly importance: number\n readonly confidence: number\n readonly status: 'active' | 'archived' | 'forgotten'\n readonly createdAt: number\n readonly accessCount: number\n readonly sourceSessionId: string | null\n readonly sourceRound: number | null\n}\n\ninterface ListResult {\n readonly records: MemoryRow[]\n readonly total: number\n}\n\ninterface StatsPart {\n readonly scope: 'user' | 'project'\n readonly stats: {\n readonly total: number\n readonly active: number\n readonly archived: number\n readonly forgotten: number\n readonly signalRatio: number\n }\n}\n\n/** review API 的返回结构(详情行内展开区的数据源)。 */\ninterface ReviewView {\n readonly record: MemoryRow\n readonly supersededBy?: readonly string[]\n readonly supersedes?: readonly string[]\n readonly contradicts?: readonly string[]\n readonly related?: readonly string[]\n readonly operations?: readonly { at: number; op: string; detail: string | null }[]\n}\n\n/** 面板内部传递的翻译函数(渲染器按注册的 locale 声明合成的 t 的窄化签名)。 */\ntype T = (key: EngramKey, params?: Record<string, unknown>) => string\n\n/** kind 数据值(存储层英文枚举,编辑表单下拉的 value 保持英文)。 */\nconst KINDS = ['fact', 'preference', 'decision', 'episode', 'skill'] as const\nconst PAGE_SIZE = 20\n\n/** 数据层枚举 → 词典键映射(显示层本地化,存储值不变)。 */\nconst STATUS_KEY: Record<MemoryRow['status'], EngramKey> = {\n active: 'statusActive',\n archived: 'statusArchived',\n forgotten: 'statusForgotten',\n}\nconst KIND_KEY: Record<string, EngramKey> = {\n fact: 'kindFact',\n preference: 'kindPreference',\n decision: 'kindDecision',\n episode: 'kindEpisode',\n skill: 'kindSkill',\n}\nconst SCOPE_KEY: Record<MemoryRow['scope'], EngramKey> = {\n user: 'scopeUser',\n project: 'scopeProject',\n}\nconst OP_KEY: Record<string, EngramKey> = {\n write: 'opWrite',\n update: 'opUpdate',\n forget: 'opForget',\n restore: 'opRestore',\n decay: 'opDecay',\n superseded: 'opSuperseded',\n 'ingest-request': 'opIngestRequest',\n 'distill-request': 'opDistillRequest',\n}\nconst REL_KEY: Record<string, EngramKey> = {\n supersededBy: 'relSupersededBy',\n supersedes: 'relSupersedes',\n contradicts: 'relContradicts',\n related: 'relRelated',\n}\n/** 操作日志 detail JSON 的已知键 → 词典键(write/update/superseded 的小对象)。 */\nconst DETAIL_KEY: Record<string, EngramKey> = {\n kind: 'labelKind',\n scope: 'labelScope',\n status: 'labelStatus',\n}\n\n/** kind 数据值 → 本地化标签(未知值回退原文)。 */\nfunction kindLabel(t: T, kind: string): string {\n const key = KIND_KEY[kind]\n return key === undefined ? kind : t(key)\n}\n\n/** op 数据值 → 本地化标签(未知值回退原文)。 */\nfunction opLabel(t: T, op: string): string {\n const key = OP_KEY[op]\n return key === undefined ? op : t(key)\n}\n\n/** 操作日志 detail 的本地化:write/update/superseded 的小对象转中文键值;摄取/蒸馏请求的完整 JSON 保持原样(审计诚实性优先)。 */\nfunction formatOpDetail(t: T, op: string, detail: string | null): string {\n if (detail === null) return ''\n if (op !== 'write' && op !== 'update' && op !== 'superseded') return ` ${detail}`\n try {\n const parsed = JSON.parse(detail) as Record<string, unknown>\n const entries = Object.entries(parsed)\n if (entries.length === 0) return ` ${detail}`\n return ' ' + entries.map(([key, value]) => {\n const label = DETAIL_KEY[key]\n if (label === undefined) return `${key}=${String(value)}`\n if (key === 'kind' && typeof value === 'string') return `${t(label)}=${kindLabel(t, value)}`\n if (key === 'scope' && (value === 'user' || value === 'project')) return `${t(label)}=${t(SCOPE_KEY[value])}`\n return `${t(label)}=${String(value)}`\n }).join(' · ')\n } catch {\n return ` ${detail}`\n }\n}\n\n/** 来源会话展示片段:截短的会话 id + 可选轮次。 */\nfunction sourceLabel(t: T, record: Pick<MemoryRow, 'sourceSessionId' | 'sourceRound'>): string {\n if (record.sourceSessionId === null) return t('sourceExplicit')\n const id = `${record.sourceSessionId.slice(0, 16)}…`\n const withRound = record.sourceRound === null\n ? id\n : `${id} ${t('round', { n: record.sourceRound })}`\n return t('sourceSession', { id: withRound })\n}\n\nasync function api<T>(path: string, init?: RequestInit): Promise<T> {\n const response = await fetch(`/api/engram/${path}`, init)\n const body = (await response.json()) as T & { error?: string }\n if (!response.ok) throw new Error(body.error ?? `HTTP ${String(response.status)}`)\n return body\n}\n\n/** 绝对时间(审计时间线等需要精确时刻的位置)。 */\nfunction fmtTime(ms: number): string {\n // 时间格式跟随浏览器环境语言(宿主界面语言通常与浏览器一致)。\n return new Date(ms).toLocaleString(navigator.language || 'zh-CN', { hour12: false })\n}\n\n/** 列表用的相对时间:1 分钟内「刚刚」,其后按分钟/小时/天取整。 */\nfunction relTime(t: T, ms: number): string {\n const diff = Math.max(0, Date.now() - ms)\n const minutes = Math.floor(diff / 60_000)\n if (minutes < 1) return t('timeJustNow')\n if (minutes < 60) return t('timeMinutesAgo', { n: minutes })\n const hours = Math.floor(minutes / 60)\n if (hours < 48) return t('timeHoursAgo', { n: hours })\n return t('timeDaysAgo', { n: Math.floor(hours / 24) })\n}\n\n/** 细仪表条:重要性(品牌色)与置信(成功色)共用,conf 变体换色。 */\nfunction Meter({ value, conf }: { value: number; conf?: boolean }): React.ReactElement {\n return (\n <span className={conf === true ? `${styles.meter} ${styles.conf}` : styles.meter}>\n <i style={{ width: `${String(Math.round(Math.min(1, Math.max(0, value)) * 100))}%` }} />\n </span>\n )\n}\n\n/** 关系 id 列表 → 等宽字体 chips(完整 id 放 title)。 */\nfunction RelChips({ ids }: { ids: readonly string[] }): React.ReactElement {\n return (\n <div className={styles.relChips}>\n {ids.map(id => <span key={id} className={styles.relChip} title={id}>{id.slice(0, 18)}</span>)}\n </div>\n )\n}\n\n/** 行内审计区:属性网格 + 关系 chips + 操作时间线(review API)。 */\nfunction ReviewBody({ t, recordId, scope }: {\n t: T\n recordId: string\n scope: 'user' | 'project'\n}): React.ReactElement {\n const [view, setView] = useState<ReviewView | null>(null)\n const [failed, setFailed] = useState<string | null>(null)\n useEffect(() => {\n let cancelled = false\n api<ReviewView>(`review?scope=${scope}&id=${encodeURIComponent(recordId)}`)\n .then((data) => { if (!cancelled) setView(data) })\n .catch((error: Error) => { if (!cancelled) setFailed(error.message) })\n return () => { cancelled = true }\n }, [recordId, scope, t])\n if (failed !== null) return <div className={styles.expandLoading}>{t('loadFailed', { msg: failed })}</div>\n if (view === null) return <div className={styles.expandLoading}>{t('loading')}</div>\n const { record } = view\n const relations = (['supersededBy', 'supersedes', 'contradicts', 'related'] as const)\n .map(key => ({ key, label: REL_KEY[key], ids: view[key] ?? [] }))\n .filter(entry => entry.ids.length > 0)\n const operations = view.operations ?? []\n return (\n <div>\n <dl className={styles.attrGrid}>\n <dt>{t('labelContent')}</dt>\n <dd>{record.content}</dd>\n <dt>{t('labelKind')}</dt>\n <dd><span className={styles.chip}>{kindLabel(t, record.kind)}</span></dd>\n <dt>{t('labelStatus')}</dt>\n <dd><span className={`${styles.statusWrap} ${styles[record.status]}`}>{t(STATUS_KEY[record.status])}</span></dd>\n <dt>{t('importance')}</dt>\n <dd>{record.importance.toFixed(2)}<Meter value={record.importance} /></dd>\n <dt>{t('confidence')}</dt>\n <dd>{record.confidence.toFixed(2)}<Meter value={record.confidence} conf /></dd>\n <dt>{t('detailSource')}</dt>\n <dd>{sourceLabel(t, record)}</dd>\n <dt>{t('labelCreated')}</dt>\n <dd>{fmtTime(record.createdAt)}</dd>\n </dl>\n {relations.map(({ key, label, ids }) => (\n <div key={key} className={styles.relBlock}>\n <h5>{label === undefined ? key : t(label)}</h5>\n <RelChips ids={ids} />\n </div>\n ))}\n {operations.length > 0 && (\n <div className={styles.relBlock}>\n <h5>{t('detailOperations')}</h5>\n <ul className={styles.timeline}>\n {operations.map((op, index) => (\n <li key={index}>\n <time>{fmtTime(op.at)}</time>\n <b>{opLabel(t, op.op)}</b>\n {formatOpDetail(t, op.op, op.detail)}\n </li>\n ))}\n </ul>\n </div>\n )}\n </div>\n )\n}\n\n/** 行内编辑表单:内容/种类/重要性 → POST update(旧条目归档,取代链保留)。 */\nfunction EditForm({ t, record, onClose, onSaved }: {\n t: T\n record: MemoryRow\n onClose: () => void\n onSaved: () => void\n}): React.ReactElement {\n const [content, setContent] = useState(record.content)\n const [kind, setKind] = useState(record.kind)\n const [importance, setImportance] = useState(record.importance)\n const save = (): void => {\n api('update', {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ id: record.id, scope: record.scope, content, kind, importance }),\n })\n .then(onSaved)\n .catch((error: Error) => { alert(error.message) })\n }\n return (\n <div className={styles.editForm}>\n <label className={styles.fieldLabel}>{t('labelContent')}</label>\n <textarea className={styles.input} rows={3} value={content} onChange={event => setContent(event.target.value)} />\n <label className={styles.fieldLabel}>{t('labelKind')}</label>\n {/* option 的 value 保持数据层英文枚举,仅显示文本本地化。 */}\n <select className={styles.input} value={kind} onChange={event => setKind(event.target.value)}>\n {KINDS.map(option => <option key={option} value={option}>{kindLabel(t, option)}</option>)}\n </select>\n <label className={styles.fieldLabel}>{`${t('importance')} ${importance.toFixed(2)}`}</label>\n <input type=\"range\" min={0} max={1} step={0.05} value={importance}\n onChange={event => setImportance(Number(event.target.value))} />\n <div className={styles.modalFoot}>\n <button type=\"button\" className={styles.button} onClick={onClose}>{t('cancel')}</button>\n <button type=\"button\" className={`${styles.button} ${styles.primary}`} onClick={save}>{t('saveWithHint')}</button>\n </div>\n </div>\n )\n}\n\n/** 设置页「记忆库」section 主组件(t 由渲染器按 locale: NS 声明合成)。 */\nexport function EngramSection({ t }: PropsLocale<typeof NS>): React.ReactElement {\n const [scope, setScope] = useState<'user' | 'project'>('user')\n const [status, setStatus] = useState('all')\n const [kind, setKind] = useState('all')\n const [q, setQ] = useState('')\n const [offset, setOffset] = useState(0)\n const [list, setList] = useState<ListResult | null>(null)\n const [stats, setStats] = useState<StatsPart[] | null>(null)\n const [error, setError] = useState<string | null>(null)\n /** 行内展开态:互斥的唯一展开条目(review 或 edit)。 */\n const [expanded, setExpanded] = useState<{ kind: 'review' | 'edit'; record: MemoryRow } | null>(null)\n const [reloadTick, setReloadTick] = useState(0)\n /** 批量选择:条目 id 集合(scope/过滤/翻页/搜索变更时清空)。 */\n const [selected, setSelected] = useState<ReadonlySet<string>>(new Set())\n /** 批量遗忘的两段式确认。 */\n const [confirmForget, setConfirmForget] = useState(false)\n\n const reload = useCallback((): void => { setReloadTick(tick => tick + 1) }, [])\n\n useEffect(() => {\n let cancelled = false\n const qs = new URLSearchParams({\n scope, status, kind, limit: String(PAGE_SIZE), offset: String(offset),\n })\n if (q !== '') qs.set('q', q)\n api<ListResult>(`list?${qs.toString()}`)\n .then((data) => { if (!cancelled) { setList(data); setError(null) } })\n .catch((loadError: Error) => { if (!cancelled) setError(loadError.message) })\n api<{ parts: StatsPart[] }>('stats')\n .then((data) => { if (!cancelled) setStats(data.parts) })\n .catch(() => { /* 统计失败不影响列表 */ })\n return () => { cancelled = true }\n }, [scope, status, kind, q, offset, reloadTick])\n\n const act = (route: string, record: MemoryRow): void => {\n api(route, {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ id: record.id, scope: record.scope }),\n })\n .then(reload)\n .catch((actError: Error) => { alert(actError.message) })\n }\n\n const toggle = (expandKind: 'review' | 'edit', record: MemoryRow): void => {\n setExpanded(current => (current !== null && current.kind === expandKind && current.record.id === record.id)\n ? null\n : { kind: expandKind, record })\n }\n\n const pageRecords = list?.records ?? []\n const selectedRecords = pageRecords.filter(record => selected.has(record.id))\n const forgetable = selectedRecords.filter(record => record.status === 'active').length\n const restorable = selectedRecords.length - forgetable\n const allSelected = pageRecords.length > 0 && pageRecords.every(record => selected.has(record.id))\n\n const toggleSelect = (id: string): void => {\n setSelected(current => {\n const next = new Set(current)\n if (next.has(id)) next.delete(id)\n else next.add(id)\n return next\n })\n }\n\n const clearSelection = (): void => { setSelected(new Set()); setConfirmForget(false) }\n\n const toggleAllPage = (): void => {\n setSelected(current => {\n const next = new Set(current)\n if (allSelected) pageRecords.forEach(record => next.delete(record.id))\n else pageRecords.forEach(record => next.add(record.id))\n return next\n })\n }\n\n /** 批量执行:逐条调单条 API(回环毫秒级),单条失败不阻塞其余;完成即刷新并清空选择。 */\n const runBatch = (mode: 'forget' | 'restore'): void => {\n const targets = mode === 'forget'\n ? selectedRecords.filter(record => record.status === 'active')\n : selectedRecords.filter(record => record.status !== 'active')\n if (targets.length === 0) return\n void Promise.allSettled(targets.map(target => api(mode, {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ id: target.id, scope: target.scope }),\n }))).then(() => { clearSelection(); reload() })\n }\n\n const armBatchForget = (): void => {\n // 确认态保持到用户点击确认执行或清空选择,不做自动复位(3 秒窗口曾导致执行落空)。\n if (confirmForget) { runBatch('forget'); return }\n setConfirmForget(true)\n }\n\n const page = Math.floor(offset / PAGE_SIZE) + 1\n const pages = list === null ? 1 : Math.max(1, Math.ceil(list.total / PAGE_SIZE))\n\n return (\n <div className={styles.panel}>\n <div className={styles.toolbar}>\n <div className={styles.scopeTabs}>\n {(['user', 'project'] as const).map(option => (\n <button key={option} type=\"button\"\n className={scope === option ? styles.scopeOn : styles.scopeOff}\n onClick={() => { setScope(option); setOffset(0); setExpanded(null); clearSelection() }}>\n {t(SCOPE_KEY[option])}\n </button>\n ))}\n </div>\n <button type=\"button\" className={styles.button} onClick={reload}>{t('refresh')}</button>\n <button type=\"button\" className={styles.button}\n onClick={() => { location.href = `/api/engram/export?scope=${scope}&format=markdown` }}>{t('exportMd')}</button>\n <button type=\"button\" className={styles.button}\n onClick={() => { location.href = `/api/engram/export?scope=${scope}&format=json` }}>{t('exportJson')}</button>\n </div>\n <div className={styles.cards}>\n {(stats ?? []).map(part => (\n <button key={part.scope} type=\"button\"\n className={part.scope === scope ? `${styles.card} ${styles.cardOn}` : styles.card}\n onClick={() => { setScope(part.scope); setOffset(0); clearSelection() }}>\n <b>{part.stats.total}</b>\n <span>{`${t(SCOPE_KEY[part.scope])} · ${t('cardActive', { n: part.stats.active })} · ${t('signalRatio', { n: Math.round(part.stats.signalRatio * 100) })}`}</span>\n <span className={styles.cardMeter}>\n <i style={{ width: `${String(Math.round(part.stats.signalRatio * 100))}%` }} />\n </span>\n </button>\n ))}\n </div>\n <div className={styles.filters}>\n <select className={styles.input} value={status}\n onChange={event => { setStatus(event.target.value); setOffset(0); setExpanded(null); clearSelection() }}>\n <option value=\"all\">{t('allStatuses')}</option>\n <option value=\"active\">{t('statusActive')}</option>\n <option value=\"archived\">{t('statusArchived')}</option>\n <option value=\"forgotten\">{t('statusForgotten')}</option>\n </select>\n <select className={styles.input} value={kind}\n onChange={event => { setKind(event.target.value); setOffset(0); setExpanded(null); clearSelection() }}>\n <option value=\"all\">{t('allKinds')}</option>\n {KINDS.map(option => <option key={option} value={option}>{kindLabel(t, option)}</option>)}\n </select>\n <input className={styles.input} placeholder={t('searchPlaceholder')} value={q}\n onChange={event => { setQ(event.target.value.trim()); setOffset(0); setExpanded(null); clearSelection() }} />\n </div>\n {selected.size > 0 && (\n <div className={styles.batchBar}>\n <span>{t('selectedCount', { n: selected.size })}</span>\n <button type=\"button\" className={styles.button} onClick={toggleAllPage}>\n {allSelected ? t('deselectAll') : t('selectAll')}\n </button>\n <button type=\"button\" className={styles.button} disabled={restorable === 0}\n onClick={() => runBatch('restore')}>{t('batchRestore', { n: restorable })}</button>\n <button type=\"button\"\n className={confirmForget ? `${styles.button} ${styles.danger}` : styles.button}\n disabled={forgetable === 0}\n onClick={armBatchForget}>\n {confirmForget ? t('batchForgetConfirm', { n: forgetable }) : t('batchForget', { n: forgetable })}\n </button>\n <button type=\"button\" className={styles.button} onClick={clearSelection}>{t('clearSelection')}</button>\n </div>\n )}\n {error !== null && <div className={styles.empty}>{t('loadFailed', { msg: error })}</div>}\n {error === null && list === null && [0, 1, 2].map(index => (\n <div key={index} className={styles.skeleton}><i /><i /><i /></div>\n ))}\n {error === null && list !== null && list.records.length === 0 && (\n <div className={styles.empty}>{t('empty')}</div>\n )}\n {(list?.records ?? []).map((record, index) => (\n <div key={record.id}\n className={selected.has(record.id) ? `${styles.item} ${styles.itemSelected}` : styles.item}\n style={{ animationDelay: `${String(Math.min(index, 12) * 28)}ms` }}>\n <div className={styles.row1}>\n <input type=\"checkbox\" className={styles.itemCheck} checked={selected.has(record.id)}\n aria-label={record.content.slice(0, 24)} onChange={() => toggleSelect(record.id)} />\n <span className={`${styles.statusWrap} ${styles[record.status]}`}>{t(STATUS_KEY[record.status])}</span>\n <span className={styles.chip}>{kindLabel(t, record.kind)}</span>\n <span className={styles.scopeTag}>{t(SCOPE_KEY[record.scope])}</span>\n <span className={styles.timeTag} title={fmtTime(record.createdAt)}>{relTime(t, record.createdAt)}</span>\n </div>\n <div className={styles.content}>{record.content}</div>\n <div className={styles.meta}>\n <span className={styles.meterField}>{t('importance')}<Meter value={record.importance} />{record.importance.toFixed(2)}</span>\n <span className={styles.meterField}>{t('confidence')}<Meter value={record.confidence} conf />{record.confidence.toFixed(2)}</span>\n <span>{t('accessCount', { n: record.accessCount })}</span>\n <span>{sourceLabel(t, record)}</span>\n </div>\n <div className={styles.ops}>\n <button type=\"button\" className={styles.button}\n onClick={() => { toggle('review', record) }}>{t('detail')}</button>\n <button type=\"button\" className={styles.button}\n onClick={() => { toggle('edit', record) }}>{t('edit')}</button>\n {record.status === 'active'\n ? <button type=\"button\" className={styles.button}\n onClick={() => { act('forget', record) }}>{t('forget')}</button>\n : <button type=\"button\" className={styles.button}\n onClick={() => { act('restore', record) }}>{t('restore')}</button>}\n </div>\n {expanded !== null && expanded.record.id === record.id && (\n <div className={styles.expand}>\n {expanded.kind === 'review'\n ? <ReviewBody t={t} recordId={record.id} scope={record.scope} />\n : <EditForm t={t} record={record} onClose={() => { setExpanded(null) }}\n onSaved={() => { setExpanded(null); reload() }} />}\n </div>\n )}\n </div>\n ))}\n <div className={styles.pager}>\n <button type=\"button\" className={styles.button} disabled={offset === 0}\n onClick={() => { setOffset(Math.max(0, offset - PAGE_SIZE)); setExpanded(null); clearSelection() }}>{t('prevPage')}</button>\n <span>{t('pagerInfo', { page, pages, total: list?.total ?? 0 })}</span>\n <button type=\"button\" className={styles.button}\n disabled={list === null || offset + PAGE_SIZE >= list.total}\n onClick={() => { setOffset(offset + PAGE_SIZE); setExpanded(null); clearSelection() }}>{t('nextPage')}</button>\n </div>\n </div>\n )\n}\n","/**\n * 「记忆库」client 词典:zh/en 键并集必须完全一致(类型化注册的编译约束)。\n * 数据层英文枚举(status/kind/op 等)只在显示层映射,存储值保持英文不变。\n * @module @kenz1117/dsh-engram/client/locales\n */\n\n/** 词典命名空间(同时用作 LocaleNamespaceMap 的声明合并键)。 */\nexport const NS = 'engram'\n\n/** 「记忆库」全部界面文案键。 */\nexport type EngramKey =\n | 'nav'\n | 'scopeUser'\n | 'scopeProject'\n | 'refresh'\n | 'exportMd'\n | 'exportJson'\n | 'allStatuses'\n | 'allKinds'\n | 'searchPlaceholder'\n | 'statusActive'\n | 'statusArchived'\n | 'statusForgotten'\n | 'kindFact'\n | 'kindPreference'\n | 'kindDecision'\n | 'kindEpisode'\n | 'kindSkill'\n | 'labelContent'\n | 'labelKind'\n | 'labelStatus'\n | 'labelScope'\n | 'importance'\n | 'confidence'\n | 'accessCount'\n | 'labelCreated'\n | 'timeJustNow'\n | 'timeMinutesAgo'\n | 'timeHoursAgo'\n | 'timeDaysAgo'\n | 'sourceExplicit'\n | 'sourceSession'\n | 'round'\n | 'cardActive'\n | 'signalRatio'\n | 'detail'\n | 'edit'\n | 'forget'\n | 'restore'\n | 'empty'\n | 'loadFailed'\n | 'loading'\n | 'pagerInfo'\n | 'prevPage'\n | 'nextPage'\n | 'cancel'\n | 'saveWithHint'\n | 'detailAttributes'\n | 'detailSource'\n | 'detailRelations'\n | 'detailOperations'\n | 'relSupersededBy'\n | 'relSupersedes'\n | 'relContradicts'\n | 'relRelated'\n | 'opWrite'\n | 'opUpdate'\n | 'opForget'\n | 'opRestore'\n | 'opDecay'\n | 'opSuperseded'\n | 'opIngestRequest'\n | 'opDistillRequest'\n | 'selectAll'\n | 'deselectAll'\n | 'selectedCount'\n | 'batchForget'\n | 'batchForgetConfirm'\n | 'batchRestore'\n | 'clearSelection'\n\n/** 中文词典(宿主默认语言)。 */\nexport const zh: Record<EngramKey, string> = {\n nav: '记忆库',\n scopeUser: '用户级',\n scopeProject: '项目级',\n refresh: '刷新',\n exportMd: '导出 MD',\n exportJson: '导出 JSON',\n allStatuses: '全部状态',\n allKinds: '全部种类',\n searchPlaceholder: '按内容搜索…',\n statusActive: '生效中',\n statusArchived: '已归档',\n statusForgotten: '已遗忘',\n kindFact: '事实',\n kindPreference: '偏好',\n kindDecision: '决策',\n kindEpisode: '事件',\n kindSkill: '技能',\n labelContent: '内容',\n labelKind: '种类',\n labelStatus: '状态',\n labelScope: '作用域',\n importance: '重要性',\n confidence: '置信',\n accessCount: '访问 {n} 次',\n labelCreated: '创建时间',\n timeJustNow: '刚刚',\n timeMinutesAgo: '{n} 分钟前',\n timeHoursAgo: '{n} 小时前',\n timeDaysAgo: '{n} 天前',\n sourceExplicit: '显式保存',\n sourceSession: '来源 {id}',\n round: '第 {n} 轮',\n cardActive: '生效 {n}',\n signalRatio: '信噪比 {n}%',\n detail: '详情',\n edit: '编辑',\n forget: '遗忘',\n restore: '恢复',\n empty: '没有符合条件的记忆',\n loadFailed: '加载失败:{msg}',\n loading: '加载中…',\n pagerInfo: '第 {page} / {pages} 页 · 共 {total} 条',\n prevPage: '上一页',\n nextPage: '下一页',\n cancel: '取消',\n saveWithHint: '保存(旧条目归档)',\n detailAttributes: '属性',\n detailSource: '来源',\n detailRelations: '关系',\n detailOperations: '最近操作',\n relSupersededBy: '被取代',\n relSupersedes: '取代',\n relContradicts: '矛盾',\n relRelated: '关联',\n opWrite: '写入',\n opUpdate: '更新',\n opForget: '遗忘',\n opRestore: '恢复',\n opDecay: '衰减归档',\n opSuperseded: '被取代',\n opIngestRequest: '摄取请求',\n opDistillRequest: '蒸馏请求',\n selectAll: '全选本页',\n deselectAll: '取消全选',\n selectedCount: '已选 {n} 条',\n batchForget: '批量遗忘({n})',\n batchForgetConfirm: '确认遗忘 {n} 条?',\n batchRestore: '批量恢复({n})',\n clearSelection: '取消选择',\n}\n\n/** 英文词典。 */\nexport const en: Record<EngramKey, string> = {\n nav: 'Memory Library',\n scopeUser: 'User',\n scopeProject: 'Project',\n refresh: 'Refresh',\n exportMd: 'Export MD',\n exportJson: 'Export JSON',\n allStatuses: 'All statuses',\n allKinds: 'All kinds',\n searchPlaceholder: 'Search content…',\n statusActive: 'active',\n statusArchived: 'archived',\n statusForgotten: 'forgotten',\n kindFact: 'fact',\n kindPreference: 'preference',\n kindDecision: 'decision',\n kindEpisode: 'episode',\n kindSkill: 'skill',\n labelContent: 'Content',\n labelKind: 'Kind',\n labelStatus: 'Status',\n labelScope: 'Scope',\n importance: 'Importance',\n confidence: 'Confidence',\n accessCount: '{n}× accessed',\n labelCreated: 'Created',\n timeJustNow: 'just now',\n timeMinutesAgo: '{n} min ago',\n timeHoursAgo: '{n} hr ago',\n timeDaysAgo: '{n} d ago',\n sourceExplicit: 'Explicitly saved',\n sourceSession: 'Source {id}',\n round: 'round {n}',\n cardActive: '{n} active',\n signalRatio: 'signal {n}%',\n detail: 'Details',\n edit: 'Edit',\n forget: 'Forget',\n restore: 'Restore',\n empty: 'No matching memories',\n loadFailed: 'Failed to load: {msg}',\n loading: 'Loading…',\n pagerInfo: 'Page {page} / {pages} · {total} records',\n prevPage: 'Prev',\n nextPage: 'Next',\n cancel: 'Cancel',\n saveWithHint: 'Save (archives old entry)',\n detailAttributes: 'Attributes',\n detailSource: 'Source',\n detailRelations: 'Relations',\n detailOperations: 'Recent operations',\n relSupersededBy: 'Superseded by',\n relSupersedes: 'Supersedes',\n relContradicts: 'Contradicts',\n relRelated: 'Related',\n opWrite: 'write',\n opUpdate: 'update',\n opForget: 'forget',\n opRestore: 'restore',\n opDecay: 'decay',\n opSuperseded: 'superseded',\n opIngestRequest: 'ingest-request',\n opDistillRequest: 'distill-request',\n selectAll: 'Select all on page',\n deselectAll: 'Deselect all',\n selectedCount: '{n} selected',\n batchForget: 'Forget selected ({n})',\n batchForgetConfirm: 'Forget {n} entries?',\n batchRestore: 'Restore selected ({n})',\n clearSelection: 'Clear selection',\n}\n","/**\n * dsh-engram client half: 注册设置页「记忆库」section。\n * 数据经回环 API(/api/engram/*)读取与操作,与 host 半的路由对齐。\n * 文案经宿主 locale 服务(zh/en 词典,语言切换由渲染器自动重渲染)。\n * @module @kenz1117/dsh-engram/client\n */\n\nimport type { Context } from '@deepseek-ai/cordis'\n// Type-only: ctx.locale 服务声明(宿主 locale 插件的 Context merge)。\nimport type {} from '@deepseek-ai/dsh-client-locale/client'\n// Type-only: ctx.slots(renderer 的 SlotMap 渲染接线)。\nimport type {} from '@deepseek-ai/dsh-client-ui-renderer/client'\n// Type-only: settings.section 槽位的 SlotMap merge(ui-settings 契约)。\nimport type {} from '@deepseek-ai/dsh-client-ui-settings/client'\n// Type-only: LocaleNamespaceMap 声明合并目标(t 席位的键类型检查)。\nimport type {} from '@deepseek-ai/dsh-client-ui-slots'\nimport { EngramSection } from './EngramPanel.tsx'\nimport { NS, en, zh, type EngramKey } from './locales.ts'\n\ndeclare module '@deepseek-ai/dsh-client-ui-slots' {\n interface LocaleNamespaceMap {\n [NS]: EngramKey\n }\n}\n\n/** 必需服务:slots 渲染接线 + locale 词典注册。 */\nexport const inject = ['slots', 'locale']\n\n/**\n * Client plugin body: 注册 zh/en 词典与设置页「记忆库」section(order 20,\n * 排在 general/models/plugins 之后)。\n * @param ctx - client root context.\n */\nexport function apply(ctx: Context): void {\n ctx.effect(() => ctx.locale.register(NS, { zh, en }), 'dsh-engram: dictionaries')\n const t = ctx.locale.bind(NS)\n ctx.slots.inject('settings.section', () => ctx.slots.register({\n name: 'settings.section',\n id: 'engram',\n order: 20,\n label: () => t('nav'),\n locale: NS,\n }, EngramSection))\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"client.js","names":["styles","useState","useCallback"],"sources":["../src/client/EngramPanel.tsx","../src/client/locales.ts","../src/client/index.ts"],"sourcesContent":["/**\n * 记忆库设置面板:统计卡片、过滤列表、批量操作、编辑(取代链)、遗忘/恢复、导出。\n * 数据经回环 API(/api/engram/*)读写;详情与编辑为条目下方行内展开\n * (不嵌套弹窗);文案全部走宿主 locale 词典(zh/en),语言切换自动\n * 重渲染;数据层英文枚举(status/kind/op)只在显示层映射;内容节点\n * 一律 DOM/JSX 构建(防 XSS)。\n * @module @kenz1117/dsh-engram/client/EngramPanel\n */\n\nimport { useCallback, useEffect, useState } from 'react'\nimport type { PropsLocale } from '@deepseek-ai/dsh-client-ui-slots'\nimport styles from './panel.module.css'\nimport { NS, type EngramKey } from './locales.ts'\n\n/** 列表/详情用的记忆视图(宿主 /api/engram/list 的行结构)。 */\ninterface MemoryRow {\n readonly id: string\n readonly scope: 'user' | 'project'\n readonly kind: string\n readonly content: string\n readonly importance: number\n readonly confidence: number\n readonly status: 'active' | 'archived' | 'forgotten'\n readonly createdAt: number\n readonly accessCount: number\n readonly sourceSessionId: string | null\n readonly sourceRound: number | null\n}\n\ninterface ListResult {\n readonly records: MemoryRow[]\n readonly total: number\n}\n\ninterface StatsPart {\n readonly scope: 'user' | 'project'\n readonly stats: {\n readonly total: number\n readonly active: number\n readonly archived: number\n readonly forgotten: number\n readonly signalRatio: number\n }\n}\n\n/** review API 的返回结构(详情行内展开区的数据源)。 */\ninterface ReviewView {\n readonly record: MemoryRow\n readonly supersededBy?: readonly string[]\n readonly supersedes?: readonly string[]\n readonly contradicts?: readonly string[]\n readonly related?: readonly string[]\n readonly operations?: readonly { at: number; op: string; detail: string | null }[]\n}\n\n/** 面板内部传递的翻译函数(渲染器按注册的 locale 声明合成的 t 的窄化签名)。 */\ntype T = (key: EngramKey, params?: Record<string, unknown>) => string\n\n/** kind 数据值(存储层英文枚举,编辑表单下拉的 value 保持英文)。 */\nconst KINDS = ['fact', 'preference', 'decision', 'episode', 'skill'] as const\nconst PAGE_SIZE = 20\n\n/** 数据层枚举 → 词典键映射(显示层本地化,存储值不变)。 */\nconst STATUS_KEY: Record<MemoryRow['status'], EngramKey> = {\n active: 'statusActive',\n archived: 'statusArchived',\n forgotten: 'statusForgotten',\n}\nconst KIND_KEY: Record<string, EngramKey> = {\n fact: 'kindFact',\n preference: 'kindPreference',\n decision: 'kindDecision',\n episode: 'kindEpisode',\n skill: 'kindSkill',\n}\nconst SCOPE_KEY: Record<MemoryRow['scope'], EngramKey> = {\n user: 'scopeUser',\n project: 'scopeProject',\n}\nconst OP_KEY: Record<string, EngramKey> = {\n write: 'opWrite',\n update: 'opUpdate',\n forget: 'opForget',\n restore: 'opRestore',\n decay: 'opDecay',\n superseded: 'opSuperseded',\n 'ingest-request': 'opIngestRequest',\n 'distill-request': 'opDistillRequest',\n}\nconst REL_KEY: Record<string, EngramKey> = {\n supersededBy: 'relSupersededBy',\n supersedes: 'relSupersedes',\n contradicts: 'relContradicts',\n related: 'relRelated',\n}\n/** 操作日志 detail JSON 的已知键 → 词典键(write/update/superseded 的小对象)。 */\nconst DETAIL_KEY: Record<string, EngramKey> = {\n kind: 'labelKind',\n scope: 'labelScope',\n status: 'labelStatus',\n}\n\n/** kind 数据值 → 本地化标签(未知值回退原文)。 */\nfunction kindLabel(t: T, kind: string): string {\n const key = KIND_KEY[kind]\n return key === undefined ? kind : t(key)\n}\n\n/** op 数据值 → 本地化标签(未知值回退原文)。 */\nfunction opLabel(t: T, op: string): string {\n const key = OP_KEY[op]\n return key === undefined ? op : t(key)\n}\n\n/** 操作日志 detail 的本地化:write/update/superseded 的小对象转中文键值;摄取/蒸馏请求的完整 JSON 保持原样(审计诚实性优先)。 */\nfunction formatOpDetail(t: T, op: string, detail: string | null): string {\n if (detail === null) return ''\n if (op !== 'write' && op !== 'update' && op !== 'superseded') return ` ${detail}`\n try {\n const parsed = JSON.parse(detail) as Record<string, unknown>\n const entries = Object.entries(parsed)\n if (entries.length === 0) return ` ${detail}`\n return ' ' + entries.map(([key, value]) => {\n const label = DETAIL_KEY[key]\n if (label === undefined) return `${key}=${String(value)}`\n if (key === 'kind' && typeof value === 'string') return `${t(label)}=${kindLabel(t, value)}`\n if (key === 'scope' && (value === 'user' || value === 'project')) return `${t(label)}=${t(SCOPE_KEY[value])}`\n return `${t(label)}=${String(value)}`\n }).join(' · ')\n } catch {\n return ` ${detail}`\n }\n}\n\n/** 来源会话展示片段:截短的会话 id + 可选轮次。 */\nfunction sourceLabel(t: T, record: Pick<MemoryRow, 'sourceSessionId' | 'sourceRound'>): string {\n if (record.sourceSessionId === null) return t('sourceExplicit')\n const id = `${record.sourceSessionId.slice(0, 16)}…`\n const withRound = record.sourceRound === null\n ? id\n : `${id} ${t('round', { n: record.sourceRound })}`\n return t('sourceSession', { id: withRound })\n}\n\nasync function api<T>(path: string, init?: RequestInit): Promise<T> {\n const response = await fetch(`/api/engram/${path}`, init)\n const body = (await response.json()) as T & { error?: string }\n if (!response.ok) throw new Error(body.error ?? `HTTP ${String(response.status)}`)\n return body\n}\n\n/** 绝对时间(审计时间线等需要精确时刻的位置)。 */\nfunction fmtTime(ms: number): string {\n // 时间格式跟随浏览器环境语言(宿主界面语言通常与浏览器一致)。\n return new Date(ms).toLocaleString(navigator.language || 'zh-CN', { hour12: false })\n}\n\n/** 列表用的相对时间:1 分钟内「刚刚」,其后按分钟/小时/天取整。 */\nfunction relTime(t: T, ms: number): string {\n const diff = Math.max(0, Date.now() - ms)\n const minutes = Math.floor(diff / 60_000)\n if (minutes < 1) return t('timeJustNow')\n if (minutes < 60) return t('timeMinutesAgo', { n: minutes })\n const hours = Math.floor(minutes / 60)\n if (hours < 48) return t('timeHoursAgo', { n: hours })\n return t('timeDaysAgo', { n: Math.floor(hours / 24) })\n}\n\n/** 细仪表条:重要性(品牌色)与置信(成功色)共用,conf 变体换色。 */\nfunction Meter({ value, conf }: { value: number; conf?: boolean }): React.ReactElement {\n return (\n <span className={conf === true ? `${styles.meter} ${styles.conf}` : styles.meter}>\n <i style={{ width: `${String(Math.round(Math.min(1, Math.max(0, value)) * 100))}%` }} />\n </span>\n )\n}\n\n/** 关系 id 列表 → 等宽字体 chips(完整 id 放 title)。 */\nfunction RelChips({ ids }: { ids: readonly string[] }): React.ReactElement {\n return (\n <div className={styles.relChips}>\n {ids.map(id => <span key={id} className={styles.relChip} title={id}>{id.slice(0, 18)}</span>)}\n </div>\n )\n}\n\n/** 行内审计区:属性网格 + 关系 chips + 操作时间线(review API)。 */\nfunction ReviewBody({ t, recordId, scope }: {\n t: T\n recordId: string\n scope: 'user' | 'project'\n}): React.ReactElement {\n const [view, setView] = useState<ReviewView | null>(null)\n const [failed, setFailed] = useState<string | null>(null)\n useEffect(() => {\n let cancelled = false\n api<ReviewView>(`review?scope=${scope}&id=${encodeURIComponent(recordId)}`)\n .then((data) => { if (!cancelled) setView(data) })\n .catch((error: Error) => { if (!cancelled) setFailed(error.message) })\n return () => { cancelled = true }\n }, [recordId, scope, t])\n if (failed !== null) return <div className={styles.expandLoading}>{t('loadFailed', { msg: failed })}</div>\n if (view === null) return <div className={styles.expandLoading}>{t('loading')}</div>\n const { record } = view\n const relations = (['supersededBy', 'supersedes', 'contradicts', 'related'] as const)\n .map(key => ({ key, label: REL_KEY[key], ids: view[key] ?? [] }))\n .filter(entry => entry.ids.length > 0)\n const operations = view.operations ?? []\n return (\n <div>\n <dl className={styles.attrGrid}>\n <dt>{t('labelContent')}</dt>\n <dd>{record.content}</dd>\n <dt>{t('labelKind')}</dt>\n <dd><span className={styles.chip}>{kindLabel(t, record.kind)}</span></dd>\n <dt>{t('labelStatus')}</dt>\n <dd><span className={`${styles.statusWrap} ${styles[record.status]}`}>{t(STATUS_KEY[record.status])}</span></dd>\n <dt>{t('importance')}</dt>\n <dd>{record.importance.toFixed(2)}<Meter value={record.importance} /></dd>\n <dt>{t('confidence')}</dt>\n <dd>{record.confidence.toFixed(2)}<Meter value={record.confidence} conf /></dd>\n <dt>{t('detailSource')}</dt>\n <dd>{sourceLabel(t, record)}</dd>\n <dt>{t('labelCreated')}</dt>\n <dd>{fmtTime(record.createdAt)}</dd>\n </dl>\n {relations.map(({ key, label, ids }) => (\n <div key={key} className={styles.relBlock}>\n <h5>{label === undefined ? key : t(label)}</h5>\n <RelChips ids={ids} />\n </div>\n ))}\n {operations.length > 0 && (\n <div className={styles.relBlock}>\n <h5>{t('detailOperations')}</h5>\n <ul className={styles.timeline}>\n {operations.map((op, index) => (\n <li key={index}>\n <time>{fmtTime(op.at)}</time>\n <b>{opLabel(t, op.op)}</b>\n {formatOpDetail(t, op.op, op.detail)}\n </li>\n ))}\n </ul>\n </div>\n )}\n </div>\n )\n}\n\n/** 行内编辑表单:内容/种类/重要性 → POST update(旧条目归档,取代链保留)。 */\nfunction EditForm({ t, record, onClose, onSaved }: {\n t: T\n record: MemoryRow\n onClose: () => void\n onSaved: () => void\n}): React.ReactElement {\n const [content, setContent] = useState(record.content)\n const [kind, setKind] = useState(record.kind)\n const [importance, setImportance] = useState(record.importance)\n const save = (): void => {\n api('update', {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ id: record.id, scope: record.scope, content, kind, importance }),\n })\n .then(onSaved)\n .catch((error: Error) => { alert(error.message) })\n }\n return (\n <div className={styles.editForm}>\n <label className={styles.fieldLabel}>{t('labelContent')}</label>\n <textarea className={styles.input} rows={3} value={content} onChange={event => setContent(event.target.value)} />\n <label className={styles.fieldLabel}>{t('labelKind')}</label>\n {/* option 的 value 保持数据层英文枚举,仅显示文本本地化。 */}\n <select className={styles.input} value={kind} onChange={event => setKind(event.target.value)}>\n {KINDS.map(option => <option key={option} value={option}>{kindLabel(t, option)}</option>)}\n </select>\n <label className={styles.fieldLabel}>{`${t('importance')} ${importance.toFixed(2)}`}</label>\n <input type=\"range\" min={0} max={1} step={0.05} value={importance}\n onChange={event => setImportance(Number(event.target.value))} />\n <div className={styles.modalFoot}>\n <button type=\"button\" className={styles.button} onClick={onClose}>{t('cancel')}</button>\n <button type=\"button\" className={`${styles.button} ${styles.primary}`} onClick={save}>{t('saveWithHint')}</button>\n </div>\n </div>\n )\n}\n\n/** 设置页「记忆库」section 主组件(t 由渲染器按 locale: NS 声明合成)。 */\nexport function EngramSection({ t }: PropsLocale<typeof NS>): React.ReactElement {\n const [scope, setScope] = useState<'user' | 'project'>('user')\n const [status, setStatus] = useState('all')\n const [kind, setKind] = useState('all')\n /** 脱敏筛选:all 全部 / true 仅含 [REDACTED: 标记 / false 仅不含(审计脱敏命中)。 */\n const [redacted, setRedacted] = useState('all')\n const [q, setQ] = useState('')\n const [offset, setOffset] = useState(0)\n const [list, setList] = useState<ListResult | null>(null)\n const [stats, setStats] = useState<StatsPart[] | null>(null)\n const [error, setError] = useState<string | null>(null)\n /** 行内展开态:互斥的唯一展开条目(review 或 edit)。 */\n const [expanded, setExpanded] = useState<{ kind: 'review' | 'edit'; record: MemoryRow } | null>(null)\n const [reloadTick, setReloadTick] = useState(0)\n /** 批量选择:条目 id 集合(scope/过滤/翻页/搜索变更时清空)。 */\n const [selected, setSelected] = useState<ReadonlySet<string>>(new Set())\n /** 批量遗忘的两段式确认。 */\n const [confirmForget, setConfirmForget] = useState(false)\n\n const reload = useCallback((): void => { setReloadTick(tick => tick + 1) }, [])\n\n useEffect(() => {\n let cancelled = false\n const qs = new URLSearchParams({\n scope, status, kind, redacted, limit: String(PAGE_SIZE), offset: String(offset),\n })\n if (q !== '') qs.set('q', q)\n api<ListResult>(`list?${qs.toString()}`)\n .then((data) => { if (!cancelled) { setList(data); setError(null) } })\n .catch((loadError: Error) => { if (!cancelled) setError(loadError.message) })\n api<{ parts: StatsPart[] }>('stats')\n .then((data) => { if (!cancelled) setStats(data.parts) })\n .catch(() => { /* 统计失败不影响列表 */ })\n return () => { cancelled = true }\n }, [scope, status, kind, redacted, q, offset, reloadTick])\n\n const act = (route: string, record: MemoryRow): void => {\n api(route, {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ id: record.id, scope: record.scope }),\n })\n .then(reload)\n .catch((actError: Error) => { alert(actError.message) })\n }\n\n const toggle = (expandKind: 'review' | 'edit', record: MemoryRow): void => {\n setExpanded(current => (current !== null && current.kind === expandKind && current.record.id === record.id)\n ? null\n : { kind: expandKind, record })\n }\n\n const pageRecords = list?.records ?? []\n const selectedRecords = pageRecords.filter(record => selected.has(record.id))\n const forgetable = selectedRecords.filter(record => record.status === 'active').length\n const restorable = selectedRecords.length - forgetable\n const allSelected = pageRecords.length > 0 && pageRecords.every(record => selected.has(record.id))\n\n const toggleSelect = (id: string): void => {\n setSelected(current => {\n const next = new Set(current)\n if (next.has(id)) next.delete(id)\n else next.add(id)\n return next\n })\n }\n\n const clearSelection = (): void => { setSelected(new Set()); setConfirmForget(false) }\n\n const toggleAllPage = (): void => {\n setSelected(current => {\n const next = new Set(current)\n if (allSelected) pageRecords.forEach(record => next.delete(record.id))\n else pageRecords.forEach(record => next.add(record.id))\n return next\n })\n }\n\n /** 批量执行:逐条调单条 API(回环毫秒级),单条失败不阻塞其余;完成即刷新并清空选择。 */\n const runBatch = (mode: 'forget' | 'restore'): void => {\n const targets = mode === 'forget'\n ? selectedRecords.filter(record => record.status === 'active')\n : selectedRecords.filter(record => record.status !== 'active')\n if (targets.length === 0) return\n void Promise.allSettled(targets.map(target => api(mode, {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ id: target.id, scope: target.scope }),\n }))).then(() => { clearSelection(); reload() })\n }\n\n const armBatchForget = (): void => {\n // 确认态保持到用户点击确认执行或清空选择,不做自动复位(3 秒窗口曾导致执行落空)。\n if (confirmForget) { runBatch('forget'); return }\n setConfirmForget(true)\n }\n\n const page = Math.floor(offset / PAGE_SIZE) + 1\n const pages = list === null ? 1 : Math.max(1, Math.ceil(list.total / PAGE_SIZE))\n\n return (\n <div className={styles.panel}>\n <div className={styles.toolbar}>\n <div className={styles.scopeTabs}>\n {(['user', 'project'] as const).map(option => (\n <button key={option} type=\"button\"\n className={scope === option ? styles.scopeOn : styles.scopeOff}\n onClick={() => { setScope(option); setOffset(0); setExpanded(null); clearSelection() }}>\n {t(SCOPE_KEY[option])}\n </button>\n ))}\n </div>\n <button type=\"button\" className={styles.button} onClick={reload}>{t('refresh')}</button>\n <button type=\"button\" className={styles.button}\n onClick={() => { location.href = `/api/engram/export?scope=${scope}&format=markdown` }}>{t('exportMd')}</button>\n <button type=\"button\" className={styles.button}\n onClick={() => { location.href = `/api/engram/export?scope=${scope}&format=json` }}>{t('exportJson')}</button>\n </div>\n <div className={styles.cards}>\n {(stats ?? []).map(part => (\n <button key={part.scope} type=\"button\"\n className={part.scope === scope ? `${styles.card} ${styles.cardOn}` : styles.card}\n onClick={() => { setScope(part.scope); setOffset(0); clearSelection() }}>\n <b>{part.stats.total}</b>\n <span>{`${t(SCOPE_KEY[part.scope])} · ${t('cardActive', { n: part.stats.active })} · ${t('signalRatio', { n: Math.round(part.stats.signalRatio * 100) })}`}</span>\n <span className={styles.cardMeter}>\n <i style={{ width: `${String(Math.round(part.stats.signalRatio * 100))}%` }} />\n </span>\n </button>\n ))}\n </div>\n <div className={styles.filters}>\n <select className={styles.input} value={status}\n onChange={event => { setStatus(event.target.value); setOffset(0); setExpanded(null); clearSelection() }}>\n <option value=\"all\">{t('allStatuses')}</option>\n <option value=\"active\">{t('statusActive')}</option>\n <option value=\"archived\">{t('statusArchived')}</option>\n <option value=\"forgotten\">{t('statusForgotten')}</option>\n </select>\n <select className={styles.input} value={kind}\n onChange={event => { setKind(event.target.value); setOffset(0); setExpanded(null); clearSelection() }}>\n <option value=\"all\">{t('allKinds')}</option>\n {KINDS.map(option => <option key={option} value={option}>{kindLabel(t, option)}</option>)}\n </select>\n <select className={styles.input} value={redacted}\n onChange={event => { setRedacted(event.target.value); setOffset(0); setExpanded(null); clearSelection() }}>\n <option value=\"all\">{t('redactedAll')}</option>\n <option value=\"true\">{t('redactedOnly')}</option>\n <option value=\"false\">{t('redactedNone')}</option>\n </select>\n <input className={styles.input} placeholder={t('searchPlaceholder')} value={q}\n onChange={event => { setQ(event.target.value.trim()); setOffset(0); setExpanded(null); clearSelection() }} />\n </div>\n {selected.size > 0 && (\n <div className={styles.batchBar}>\n <span>{t('selectedCount', { n: selected.size })}</span>\n <button type=\"button\" className={styles.button} onClick={toggleAllPage}>\n {allSelected ? t('deselectAll') : t('selectAll')}\n </button>\n <button type=\"button\" className={styles.button} disabled={restorable === 0}\n onClick={() => runBatch('restore')}>{t('batchRestore', { n: restorable })}</button>\n <button type=\"button\"\n className={confirmForget ? `${styles.button} ${styles.danger}` : styles.button}\n disabled={forgetable === 0}\n onClick={armBatchForget}>\n {confirmForget ? t('batchForgetConfirm', { n: forgetable }) : t('batchForget', { n: forgetable })}\n </button>\n <button type=\"button\" className={styles.button} onClick={clearSelection}>{t('clearSelection')}</button>\n </div>\n )}\n {error !== null && <div className={styles.empty}>{t('loadFailed', { msg: error })}</div>}\n {error === null && list === null && [0, 1, 2].map(index => (\n <div key={index} className={styles.skeleton}><i /><i /><i /></div>\n ))}\n {error === null && list !== null && list.records.length === 0 && (\n <div className={styles.empty}>{t('empty')}</div>\n )}\n {(list?.records ?? []).map((record, index) => (\n <div key={record.id}\n className={selected.has(record.id) ? `${styles.item} ${styles.itemSelected}` : styles.item}\n style={{ animationDelay: `${String(Math.min(index, 12) * 28)}ms` }}>\n <div className={styles.row1}>\n <input type=\"checkbox\" className={styles.itemCheck} checked={selected.has(record.id)}\n aria-label={record.content.slice(0, 24)} onChange={() => toggleSelect(record.id)} />\n <span className={`${styles.statusWrap} ${styles[record.status]}`}>{t(STATUS_KEY[record.status])}</span>\n <span className={styles.chip}>{kindLabel(t, record.kind)}</span>\n {record.content.includes('[REDACTED:') && (\n <span className={`${styles.chip} ${styles.redactedChip}`}>{t('tagRedacted')}</span>\n )}\n <span className={styles.scopeTag}>{t(SCOPE_KEY[record.scope])}</span>\n <span className={styles.timeTag} title={fmtTime(record.createdAt)}>{relTime(t, record.createdAt)}</span>\n </div>\n <div className={styles.content}>{record.content}</div>\n <div className={styles.meta}>\n <span className={styles.meterField}>{t('importance')}<Meter value={record.importance} />{record.importance.toFixed(2)}</span>\n <span className={styles.meterField}>{t('confidence')}<Meter value={record.confidence} conf />{record.confidence.toFixed(2)}</span>\n <span>{t('accessCount', { n: record.accessCount })}</span>\n <span>{sourceLabel(t, record)}</span>\n </div>\n <div className={styles.ops}>\n <button type=\"button\" className={styles.button}\n onClick={() => { toggle('review', record) }}>{t('detail')}</button>\n <button type=\"button\" className={styles.button}\n onClick={() => { toggle('edit', record) }}>{t('edit')}</button>\n {record.status === 'active'\n ? <button type=\"button\" className={styles.button}\n onClick={() => { act('forget', record) }}>{t('forget')}</button>\n : <button type=\"button\" className={styles.button}\n onClick={() => { act('restore', record) }}>{t('restore')}</button>}\n </div>\n {expanded !== null && expanded.record.id === record.id && (\n <div className={styles.expand}>\n {expanded.kind === 'review'\n ? <ReviewBody t={t} recordId={record.id} scope={record.scope} />\n : <EditForm t={t} record={record} onClose={() => { setExpanded(null) }}\n onSaved={() => { setExpanded(null); reload() }} />}\n </div>\n )}\n </div>\n ))}\n <div className={styles.pager}>\n <button type=\"button\" className={styles.button} disabled={offset === 0}\n onClick={() => { setOffset(Math.max(0, offset - PAGE_SIZE)); setExpanded(null); clearSelection() }}>{t('prevPage')}</button>\n <span>{t('pagerInfo', { page, pages, total: list?.total ?? 0 })}</span>\n <button type=\"button\" className={styles.button}\n disabled={list === null || offset + PAGE_SIZE >= list.total}\n onClick={() => { setOffset(offset + PAGE_SIZE); setExpanded(null); clearSelection() }}>{t('nextPage')}</button>\n </div>\n </div>\n )\n}\n","/**\n * 「记忆库」client 词典:zh/en 键并集必须完全一致(类型化注册的编译约束)。\n * 数据层英文枚举(status/kind/op 等)只在显示层映射,存储值保持英文不变。\n * @module @kenz1117/dsh-engram/client/locales\n */\n\n/** 词典命名空间(同时用作 LocaleNamespaceMap 的声明合并键)。 */\nexport const NS = 'engram'\n\n/** 「记忆库」全部界面文案键。 */\nexport type EngramKey =\n | 'nav'\n | 'scopeUser'\n | 'scopeProject'\n | 'refresh'\n | 'exportMd'\n | 'exportJson'\n | 'allStatuses'\n | 'allKinds'\n | 'redactedAll'\n | 'redactedOnly'\n | 'redactedNone'\n | 'tagRedacted'\n | 'searchPlaceholder'\n | 'statusActive'\n | 'statusArchived'\n | 'statusForgotten'\n | 'kindFact'\n | 'kindPreference'\n | 'kindDecision'\n | 'kindEpisode'\n | 'kindSkill'\n | 'labelContent'\n | 'labelKind'\n | 'labelStatus'\n | 'labelScope'\n | 'importance'\n | 'confidence'\n | 'accessCount'\n | 'labelCreated'\n | 'timeJustNow'\n | 'timeMinutesAgo'\n | 'timeHoursAgo'\n | 'timeDaysAgo'\n | 'sourceExplicit'\n | 'sourceSession'\n | 'round'\n | 'cardActive'\n | 'signalRatio'\n | 'detail'\n | 'edit'\n | 'forget'\n | 'restore'\n | 'empty'\n | 'loadFailed'\n | 'loading'\n | 'pagerInfo'\n | 'prevPage'\n | 'nextPage'\n | 'cancel'\n | 'saveWithHint'\n | 'detailAttributes'\n | 'detailSource'\n | 'detailRelations'\n | 'detailOperations'\n | 'relSupersededBy'\n | 'relSupersedes'\n | 'relContradicts'\n | 'relRelated'\n | 'opWrite'\n | 'opUpdate'\n | 'opForget'\n | 'opRestore'\n | 'opDecay'\n | 'opSuperseded'\n | 'opIngestRequest'\n | 'opDistillRequest'\n | 'selectAll'\n | 'deselectAll'\n | 'selectedCount'\n | 'batchForget'\n | 'batchForgetConfirm'\n | 'batchRestore'\n | 'clearSelection'\n\n/** 中文词典(宿主默认语言)。 */\nexport const zh: Record<EngramKey, string> = {\n nav: '记忆库',\n scopeUser: '用户级',\n scopeProject: '项目级',\n refresh: '刷新',\n exportMd: '导出 MD',\n exportJson: '导出 JSON',\n allStatuses: '全部状态',\n allKinds: '全部种类',\n redactedAll: '全部脱敏',\n redactedOnly: '含脱敏标记',\n redactedNone: '无脱敏标记',\n tagRedacted: '已脱敏',\n searchPlaceholder: '按内容搜索…',\n statusActive: '生效中',\n statusArchived: '已归档',\n statusForgotten: '已遗忘',\n kindFact: '事实',\n kindPreference: '偏好',\n kindDecision: '决策',\n kindEpisode: '事件',\n kindSkill: '技能',\n labelContent: '内容',\n labelKind: '种类',\n labelStatus: '状态',\n labelScope: '作用域',\n importance: '重要性',\n confidence: '置信',\n accessCount: '访问 {n} 次',\n labelCreated: '创建时间',\n timeJustNow: '刚刚',\n timeMinutesAgo: '{n} 分钟前',\n timeHoursAgo: '{n} 小时前',\n timeDaysAgo: '{n} 天前',\n sourceExplicit: '显式保存',\n sourceSession: '来源 {id}',\n round: '第 {n} 轮',\n cardActive: '生效 {n}',\n signalRatio: '信噪比 {n}%',\n detail: '详情',\n edit: '编辑',\n forget: '遗忘',\n restore: '恢复',\n empty: '没有符合条件的记忆',\n loadFailed: '加载失败:{msg}',\n loading: '加载中…',\n pagerInfo: '第 {page} / {pages} 页 · 共 {total} 条',\n prevPage: '上一页',\n nextPage: '下一页',\n cancel: '取消',\n saveWithHint: '保存(旧条目归档)',\n detailAttributes: '属性',\n detailSource: '来源',\n detailRelations: '关系',\n detailOperations: '最近操作',\n relSupersededBy: '被取代',\n relSupersedes: '取代',\n relContradicts: '矛盾',\n relRelated: '关联',\n opWrite: '写入',\n opUpdate: '更新',\n opForget: '遗忘',\n opRestore: '恢复',\n opDecay: '衰减归档',\n opSuperseded: '被取代',\n opIngestRequest: '摄取请求',\n opDistillRequest: '蒸馏请求',\n selectAll: '全选本页',\n deselectAll: '取消全选',\n selectedCount: '已选 {n} 条',\n batchForget: '批量遗忘({n})',\n batchForgetConfirm: '确认遗忘 {n} 条?',\n batchRestore: '批量恢复({n})',\n clearSelection: '取消选择',\n}\n\n/** 英文词典。 */\nexport const en: Record<EngramKey, string> = {\n nav: 'Memory Library',\n scopeUser: 'User',\n scopeProject: 'Project',\n refresh: 'Refresh',\n exportMd: 'Export MD',\n exportJson: 'Export JSON',\n allStatuses: 'All statuses',\n allKinds: 'All kinds',\n redactedAll: 'All redaction',\n redactedOnly: 'Redacted only',\n redactedNone: 'Not redacted',\n tagRedacted: 'redacted',\n searchPlaceholder: 'Search content…',\n statusActive: 'active',\n statusArchived: 'archived',\n statusForgotten: 'forgotten',\n kindFact: 'fact',\n kindPreference: 'preference',\n kindDecision: 'decision',\n kindEpisode: 'episode',\n kindSkill: 'skill',\n labelContent: 'Content',\n labelKind: 'Kind',\n labelStatus: 'Status',\n labelScope: 'Scope',\n importance: 'Importance',\n confidence: 'Confidence',\n accessCount: '{n}× accessed',\n labelCreated: 'Created',\n timeJustNow: 'just now',\n timeMinutesAgo: '{n} min ago',\n timeHoursAgo: '{n} hr ago',\n timeDaysAgo: '{n} d ago',\n sourceExplicit: 'Explicitly saved',\n sourceSession: 'Source {id}',\n round: 'round {n}',\n cardActive: '{n} active',\n signalRatio: 'signal {n}%',\n detail: 'Details',\n edit: 'Edit',\n forget: 'Forget',\n restore: 'Restore',\n empty: 'No matching memories',\n loadFailed: 'Failed to load: {msg}',\n loading: 'Loading…',\n pagerInfo: 'Page {page} / {pages} · {total} records',\n prevPage: 'Prev',\n nextPage: 'Next',\n cancel: 'Cancel',\n saveWithHint: 'Save (archives old entry)',\n detailAttributes: 'Attributes',\n detailSource: 'Source',\n detailRelations: 'Relations',\n detailOperations: 'Recent operations',\n relSupersededBy: 'Superseded by',\n relSupersedes: 'Supersedes',\n relContradicts: 'Contradicts',\n relRelated: 'Related',\n opWrite: 'write',\n opUpdate: 'update',\n opForget: 'forget',\n opRestore: 'restore',\n opDecay: 'decay',\n opSuperseded: 'superseded',\n opIngestRequest: 'ingest-request',\n opDistillRequest: 'distill-request',\n selectAll: 'Select all on page',\n deselectAll: 'Deselect all',\n selectedCount: '{n} selected',\n batchForget: 'Forget selected ({n})',\n batchForgetConfirm: 'Forget {n} entries?',\n batchRestore: 'Restore selected ({n})',\n clearSelection: 'Clear selection',\n}\n","/**\n * dsh-engram client half: 注册设置页「记忆库」section。\n * 数据经回环 API(/api/engram/*)读取与操作,与 host 半的路由对齐。\n * 文案经宿主 locale 服务(zh/en 词典,语言切换由渲染器自动重渲染)。\n * @module @kenz1117/dsh-engram/client\n */\n\nimport type { Context } from '@deepseek-ai/cordis'\n// Type-only: ctx.locale 服务声明(宿主 locale 插件的 Context merge)。\nimport type {} from '@deepseek-ai/dsh-client-locale/client'\n// Type-only: ctx.slots(renderer 的 SlotMap 渲染接线)。\nimport type {} from '@deepseek-ai/dsh-client-ui-renderer/client'\n// Type-only: settings.section 槽位的 SlotMap merge(ui-settings 契约)。\nimport type {} from '@deepseek-ai/dsh-client-ui-settings/client'\n// Type-only: LocaleNamespaceMap 声明合并目标(t 席位的键类型检查)。\nimport type {} from '@deepseek-ai/dsh-client-ui-slots'\nimport { EngramSection } from './EngramPanel.tsx'\nimport { NS, en, zh, type EngramKey } from './locales.ts'\n\ndeclare module '@deepseek-ai/dsh-client-ui-slots' {\n interface LocaleNamespaceMap {\n [NS]: EngramKey\n }\n}\n\n/** 必需服务:slots 渲染接线 + locale 词典注册。 */\nexport const inject = ['slots', 'locale']\n\n/**\n * Client plugin body: 注册 zh/en 词典与设置页「记忆库」section(order 20,\n * 排在 general/models/plugins 之后)。\n * @param ctx - client root context.\n */\nexport function apply(ctx: Context): void {\n ctx.effect(() => ctx.locale.register(NS, { zh, en }), 'dsh-engram: dictionaries')\n const t = ctx.locale.bind(NS)\n ctx.slots.inject('settings.section', () => ctx.slots.register({\n name: 'settings.section',\n id: 'engram',\n order: 20,\n label: () => t('nav'),\n locale: NS,\n }, EngramSection))\n}\n"],"mappings":"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"}
|