@kenz1117/dsh-engram 0.4.3 → 0.4.4
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 +1 -2
- package/lib/client.js +2 -2
- package/lib/client.js.map +1 -1
- package/package.json +4 -2
- package/scripts/link-peers.mjs +2 -0
package/README.md
CHANGED
|
@@ -45,7 +45,7 @@ dsh plugin --profile web add @kenz1117/dsh-engram
|
|
|
45
45
|
|
|
46
46
|
## Web 管理面板(设置页「记忆库」tab)
|
|
47
47
|
|
|
48
|
-
宿主带 webServer 的 profile(web 等)会在**设置页**自动出现「记忆库」tab(经 `settings.section` 槽位注册,client 半为 React 组件、随 `lib/client.js`
|
|
48
|
+
宿主带 webServer 的 profile(web 等)会在**设置页**自动出现「记忆库」tab(经 `settings.section` 槽位注册,client 半为 React 组件、随 `lib/client.js` 由宿主模块表装载):统计卡片、按状态/种类/内容过滤、行内详情与编辑(走取代链)、遗忘/恢复、导出 Markdown/JSON 下载。数据经回环 API `/api/engram/*`(写操作校验回环 Origin)。界面文案经宿主 locale 服务注册 zh/en 词典,跟随宿主语言设置实时切换;状态/种类等数据枚举仅在显示层映射为中文/英文,存储值保持英文。headless 等无 webServer 的组合不挂载,其余能力不受影响。
|
|
49
49
|
|
|
50
50
|
## 理解实现
|
|
51
51
|
|
|
@@ -86,4 +86,3 @@ pnpm bundle
|
|
|
86
86
|
- **自动摄取的最后一轮盲区** —— 摄取由下一轮的第一步触发,会话最后一轮不摄取;会话结束事件钩子是后续工作。
|
|
87
87
|
- **矛盾候选无 LLM 判定** —— 写入时仅按向量相似度(≥0.88)报告候选并建边,语义矛盾的确认留给模型/用户裁决与蒸馏。
|
|
88
88
|
- **嵌入器降级期间的记忆无向量** —— 模型未就绪时写入的记忆不参与语义道;语义上线后跑一次 `pnpm backfill` 补算存量向量(`pnpm build` 的模型缓存就绪后执行,可经 `HF_ENDPOINT` 配镜像)。
|
|
89
|
-
- **Web 管理面板未实现** —— 浏览、搜索、编辑、导出记忆库的 client 半在三期。
|
package/lib/client.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
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:980px}.bWwFiW_toolbar{flex-wrap:wrap;align-items:center;gap:10px;margin-bottom:14px;display:flex}.bWwFiW_scopeTabs{border-bottom:1px solid var(--dsw-alias-border-l2);align-items:flex-end;gap:18px;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;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{background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-primary);border:1px solid var(--dsw-alias-border-l2);cursor:pointer;border-radius:8px;padding:5px 12px;font-size:13px}.bWwFiW_button:hover{border-color:var(--dsw-alias-brand-primary)}.bWwFiW_button:disabled{opacity:.45;cursor:default}.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_cards{grid-template-columns:repeat(auto-fit,minmax(180px,1fr));gap:10px;margin-bottom:14px;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:10px;padding:10px 14px}.bWwFiW_card b{font-size:20px;display:block}.bWwFiW_card span{color:var(--dsw-alias-label-secondary);font-size:12px}.bWwFiW_filters{flex-wrap:wrap;gap:8px;margin-bottom:14px;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}.bWwFiW_filters .bWwFiW_input{flex:1;min-width:160px}.bWwFiW_item{background:var(--dsw-alias-bg-layer-1);border:1px solid var(--dsw-alias-border-l2);border-radius:10px;margin-bottom:10px;padding:12px 14px}.bWwFiW_row1{flex-wrap:wrap;align-items:center;gap:8px;margin-bottom:6px;display:flex}.bWwFiW_badge{border:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-secondary);background:var(--dsw-alias-fill-tsp-secondary);border-radius:99px;padding:1px 8px;font-size:11px}.bWwFiW_active{color:var(--dsw-alias-state-success-primary);border-color:var(--dsw-alias-state-success-primary)}.bWwFiW_archived{color:var(--dsw-alias-state-warn-primary);border-color:var(--dsw-alias-state-warn-primary)}.bWwFiW_forgotten{color:var(--dsw-alias-state-error-primary);border-color:var(--dsw-alias-state-error-primary)}.bWwFiW_content{white-space:pre-wrap;word-break:break-word;color:var(--dsw-alias-label-primary)}.bWwFiW_meta{color:var(--dsw-alias-label-secondary);flex-wrap:wrap;gap:14px;margin-top:6px;font-size:12px;display:flex}.bWwFiW_ops{gap:8px;margin-top:8px;display:flex}.bWwFiW_pager{color:var(--dsw-alias-label-secondary);justify-content:center;align-items:center;gap:10px;margin-top:14px;display:flex}.bWwFiW_empty{text-align:center;color:var(--dsw-alias-label-secondary);padding:40px 0}.bWwFiW_expand{border-top:1px dashed var(--dsw-alias-border-l2);margin-top:10px;padding-top:10px}.bWwFiW_expandLoading{color:var(--dsw-alias-label-secondary);font-size:13px}.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:10px 0 4px;font-size:12px;display:block}.bWwFiW_modalFoot{justify-content:flex-end;gap:8px;margin-top:12px;display:flex}.bWwFiW_review{background:var(--dsw-alias-bg-base);border:1px solid var(--dsw-alias-border-l2);white-space:pre-wrap;max-height:320px;color:var(--dsw-alias-label-primary);border-radius:8px;margin:0;padding:10px;font-size:12px;overflow:auto}`,document.head.appendChild(e)}var o={
|
|
2
|
-
`))}).catch(
|
|
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:980px}.bWwFiW_toolbar{flex-wrap:wrap;align-items:center;gap:10px;margin-bottom:14px;display:flex}.bWwFiW_scopeTabs{border-bottom:1px solid var(--dsw-alias-border-l2);align-items:flex-end;gap:18px;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;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{background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-primary);border:1px solid var(--dsw-alias-border-l2);cursor:pointer;border-radius:8px;padding:5px 12px;font-size:13px}.bWwFiW_button:hover{border-color:var(--dsw-alias-brand-primary)}.bWwFiW_button:disabled{opacity:.45;cursor:default}.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_cards{grid-template-columns:repeat(auto-fit,minmax(180px,1fr));gap:10px;margin-bottom:14px;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:10px;padding:10px 14px}.bWwFiW_card b{font-size:20px;display:block}.bWwFiW_card span{color:var(--dsw-alias-label-secondary);font-size:12px}.bWwFiW_filters{flex-wrap:wrap;gap:8px;margin-bottom:14px;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}.bWwFiW_filters .bWwFiW_input{flex:1;min-width:160px}.bWwFiW_item{background:var(--dsw-alias-bg-layer-1);border:1px solid var(--dsw-alias-border-l2);border-radius:10px;margin-bottom:10px;padding:12px 14px}.bWwFiW_row1{flex-wrap:wrap;align-items:center;gap:8px;margin-bottom:6px;display:flex}.bWwFiW_badge{border:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-secondary);background:var(--dsw-alias-fill-tsp-secondary);border-radius:99px;padding:1px 8px;font-size:11px}.bWwFiW_active{color:var(--dsw-alias-state-success-primary);border-color:var(--dsw-alias-state-success-primary)}.bWwFiW_archived{color:var(--dsw-alias-state-warn-primary);border-color:var(--dsw-alias-state-warn-primary)}.bWwFiW_forgotten{color:var(--dsw-alias-state-error-primary);border-color:var(--dsw-alias-state-error-primary)}.bWwFiW_content{white-space:pre-wrap;word-break:break-word;color:var(--dsw-alias-label-primary)}.bWwFiW_meta{color:var(--dsw-alias-label-secondary);flex-wrap:wrap;gap:14px;margin-top:6px;font-size:12px;display:flex}.bWwFiW_ops{gap:8px;margin-top:8px;display:flex}.bWwFiW_pager{color:var(--dsw-alias-label-secondary);justify-content:center;align-items:center;gap:10px;margin-top:14px;display:flex}.bWwFiW_empty{text-align:center;color:var(--dsw-alias-label-secondary);padding:40px 0}.bWwFiW_expand{border-top:1px dashed var(--dsw-alias-border-l2);margin-top:10px;padding-top:10px}.bWwFiW_expandLoading{color:var(--dsw-alias-label-secondary);font-size:13px}.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:10px 0 4px;font-size:12px;display:block}.bWwFiW_modalFoot{justify-content:flex-end;gap:8px;margin-top:12px;display:flex}.bWwFiW_review{background:var(--dsw-alias-bg-base);border:1px solid var(--dsw-alias-border-l2);white-space:pre-wrap;max-height:320px;color:var(--dsw-alias-label-primary);border-radius:8px;margin:0;padding:10px;font-size:12px;overflow:auto}`,document.head.appendChild(e)}var o={forgotten:`bWwFiW_forgotten`,expand:`bWwFiW_expand`,editForm:`bWwFiW_editForm`,review:`bWwFiW_review`,item:`bWwFiW_item`,ops:`bWwFiW_ops`,fieldLabel:`bWwFiW_fieldLabel`,filters:`bWwFiW_filters`,card:`bWwFiW_card`,scopeOff:`bWwFiW_scopeOff`,input:`bWwFiW_input`,cards:`bWwFiW_cards`,badge:`bWwFiW_badge`,primary:`bWwFiW_primary`,button:`bWwFiW_button`,active:`bWwFiW_active`,content:`bWwFiW_content`,row1:`bWwFiW_row1`,scopeOn:`bWwFiW_scopeOn`,meta:`bWwFiW_meta`,pager:`bWwFiW_pager`,empty:`bWwFiW_empty`,archived:`bWwFiW_archived`,expandLoading:`bWwFiW_expandLoading`,modalFoot:`bWwFiW_modalFoot`,toolbar:`bWwFiW_toolbar`,panel:`bWwFiW_panel`,scopeTabs:`bWwFiW_scopeTabs`};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`,"ingest-request":`opIngestRequest`,"distill-request":`opDistillRequest`},f={supersededBy:`relSupersededBy`,supersedes:`relSupersedes`,contradicts:`relContradicts`,related:`relRelated`};function p(e,t){let n=l[t];return n===void 0?t:e(n)}function m(e,t){let n=d[t];return n===void 0?t:e(n)}function h(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 g(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 _(e){return new Date(e).toLocaleString(navigator.language||`zh-CN`,{hour12:!1})}function v({t:e,recordId:t,scope:n}){let[a,s]=(0,r.useState)(null);return(0,r.useEffect)(()=>{let r=!1;return g(`review?scope=${n}&id=${encodeURIComponent(t)}`).then(t=>{if(r)return;let n=t.record,i=[`${e(`labelContent`)}: ${n.content}`,`${e(`detailAttributes`)}: ${e(`labelKind`)}=${p(e,n.kind)}, ${e(`labelStatus`)}=${e(c[n.status])}, ${e(`importance`)}=${n.importance.toFixed(2)}, ${e(`confidence`)}=${n.confidence.toFixed(2)}, ${e(`accessCount`,{n:n.accessCount})}`,`${e(`detailSource`)}: ${h(e,n)}`];for(let n of[`supersededBy`,`supersedes`,`contradicts`,`related`]){let r=t[n],a=f[n];r!==void 0&&r.length>0&&i.push(`${a===void 0?n:e(a)}: ${r.join(`, `)}`)}let a=t.operations;a!==void 0&&a.length>0&&(i.push(`${e(`detailOperations`)}:`),a.forEach(t=>i.push(` ${_(t.at)} ${m(e,t.op)}${t.detail?` ${t.detail}`:``}`))),s(i.join(`
|
|
2
|
+
`))}).catch(t=>{r||s(e(`loadFailed`,{msg:t.message}))}),()=>{r=!0}},[t,n,e]),a===null?(0,i.jsx)(`div`,{className:o.expandLoading,children:e(`loading`)}):(0,i.jsx)(`pre`,{className:o.review,children:a})}function y({t:e,record:t,onClose:n,onSaved:a}){let[c,l]=(0,r.useState)(t.content),[u,d]=(0,r.useState)(t.kind),[f,m]=(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:p(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=>m(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:()=>{g(`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 b({t:e}){let[t,n]=(0,r.useState)(`user`),[a,l]=(0,r.useState)(`all`),[d,f]=(0,r.useState)(`all`),[m,b]=(0,r.useState)(``),[x,S]=(0,r.useState)(0),[C,w]=(0,r.useState)(null),[T,E]=(0,r.useState)(null),[D,O]=(0,r.useState)(null),[k,A]=(0,r.useState)(null),[j,M]=(0,r.useState)(0),N=(0,r.useCallback)(()=>{M(e=>e+1)},[]);(0,r.useEffect)(()=>{let e=!1,n=new URLSearchParams({scope:t,status:a,kind:d,limit:`20`,offset:String(x)});return m!==``&&n.set(`q`,m),g(`list?${n.toString()}`).then(t=>{e||(w(t),O(null))}).catch(t=>{e||O(t.message)}),g(`stats`).then(t=>{e||E(t.parts)}).catch(()=>{}),()=>{e=!0}},[t,a,d,m,x,j]);let P=(e,t)=>{g(e,{method:`POST`,headers:{"content-type":`application/json`},body:JSON.stringify({id:t.id,scope:t.scope})}).then(N).catch(e=>{alert(e.message)})},F=(e,t)=>{A(n=>n!==null&&n.kind===e&&n.record.id===t.id?null:{kind:e,record:t})},I=Math.floor(x/20)+1,L=C===null?1:Math.max(1,Math.ceil(C.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),A(null)},children:e(u[r])},r))}),(0,i.jsx)(`button`,{type:`button`,className:o.button,onClick:N,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:(T??[]).map(r=>(0,i.jsxs)(`button`,{type:`button`,className:o.card,style:r.scope===t?{borderColor:`var(--dsw-alias-brand-primary)`}:void 0,onClick:()=>{n(r.scope),S(0)},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)})}`})]},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),A(null)},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),A(null)},children:[(0,i.jsx)(`option`,{value:`all`,children:e(`allKinds`)}),s.map(t=>(0,i.jsx)(`option`,{value:t,children:p(e,t)},t))]}),(0,i.jsx)(`input`,{className:o.input,placeholder:e(`searchPlaceholder`),value:m,onChange:e=>{b(e.target.value.trim()),S(0),A(null)}})]}),D!==null&&(0,i.jsx)(`div`,{className:o.empty,children:e(`loadFailed`,{msg:D})}),D===null&&C!==null&&C.records.length===0&&(0,i.jsx)(`div`,{className:o.empty,children:e(`empty`)}),(C?.records??[]).map(t=>(0,i.jsxs)(`div`,{className:o.item,children:[(0,i.jsxs)(`div`,{className:o.row1,children:[(0,i.jsx)(`span`,{className:`${o.badge} ${o[t.status]}`,children:e(c[t.status])}),(0,i.jsx)(`span`,{className:o.badge,children:p(e,t.kind)}),(0,i.jsx)(`span`,{className:o.badge,children:e(u[t.scope])})]}),(0,i.jsx)(`div`,{className:o.content,children:t.content}),(0,i.jsxs)(`div`,{className:o.meta,children:[(0,i.jsx)(`span`,{children:`${e(`importance`)} ${t.importance.toFixed(2)}`}),(0,i.jsx)(`span`,{children:`${e(`confidence`)} ${t.confidence.toFixed(2)}`}),(0,i.jsx)(`span`,{children:e(`accessCount`,{n:t.accessCount})}),(0,i.jsx)(`span`,{children:h(e,t)}),(0,i.jsx)(`span`,{children:_(t.createdAt)})]}),(0,i.jsxs)(`div`,{className:o.ops,children:[(0,i.jsx)(`button`,{type:`button`,className:o.button,onClick:()=>{F(`review`,t)},children:e(`detail`)}),(0,i.jsx)(`button`,{type:`button`,className:o.button,onClick:()=>{F(`edit`,t)},children:e(`edit`)}),t.status===`active`?(0,i.jsx)(`button`,{type:`button`,className:o.button,onClick:()=>{P(`forget`,t)},children:e(`forget`)}):(0,i.jsx)(`button`,{type:`button`,className:o.button,onClick:()=>{P(`restore`,t)},children:e(`restore`)})]}),k!==null&&k.record.id===t.id&&(0,i.jsx)(`div`,{className:o.expand,children:k.kind===`review`?(0,i.jsx)(v,{t:e,recordId:t.id,scope:t.scope}):(0,i.jsx)(y,{t:e,record:t,onClose:()=>{A(null)},onSaved:()=>{A(null),N()}})})]},t.id)),(0,i.jsxs)(`div`,{className:o.pager,children:[(0,i.jsx)(`button`,{type:`button`,className:o.button,disabled:x===0,onClick:()=>{S(Math.max(0,x-20))},children:e(`prevPage`)}),(0,i.jsx)(`span`,{children:e(`pagerInfo`,{page:I,pages:L,total:C?.total??0})}),(0,i.jsx)(`button`,{type:`button`,className:o.button,disabled:C===null||x+20>=C.total,onClick:()=>{S(x+20)},children:e(`nextPage`)})]})]})}let x=`engram`,S={nav:`记忆库`,scopeUser:`用户级`,scopeProject:`项目级`,refresh:`刷新`,exportMd:`导出 MD`,exportJson:`导出 JSON`,allStatuses:`全部状态`,allKinds:`全部种类`,searchPlaceholder:`按内容搜索…`,statusActive:`生效中`,statusArchived:`已归档`,statusForgotten:`已遗忘`,kindFact:`事实`,kindPreference:`偏好`,kindDecision:`决策`,kindEpisode:`事件`,kindSkill:`技能`,labelContent:`内容`,labelKind:`种类`,labelStatus:`状态`,importance:`重要性`,confidence:`置信`,accessCount:`访问 {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:`衰减归档`,opIngestRequest:`摄取请求`,opDistillRequest:`蒸馏请求`},C={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`,importance:`Importance`,confidence:`Confidence`,accessCount:`{n} accesses`,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`,opIngestRequest:`ingest-request`,opDistillRequest:`distill-request`},w=[`slots`,`locale`];function T(e){e.effect(()=>e.locale.register(x,{zh:S,en:C}),`dsh-engram: dictionaries`);let t=e.locale.bind(x);e.slots.inject(`settings.section`,()=>e.slots.register({name:`settings.section`,id:`engram`,order:20,label:()=>t(`nav`),locale:x},b))}return n.apply=T,n.inject=w,t.exports}});
|
|
3
3
|
//# sourceMappingURL=client.js.map
|
package/lib/client.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.js","names":["useState","styles","useCallback"],"sources":["../src/client/EngramPanel.tsx","../src/client/index.ts"],"sourcesContent":["/**\n * 记忆库设置面板:统计卡片、过滤列表、编辑(取代链)、遗忘/恢复、导出。\n * 数据经回环 API(/api/engram/*)读写;详情与编辑为条目下方行内展开\n * (不嵌套弹窗);内容节点一律 DOM/JSX 构建(防 XSS)。\n * @module @kenz1117/dsh-engram/client/EngramPanel\n */\n\nimport { useCallback, useEffect, useState } from 'react'\nimport styles from './panel.module.css'\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\nconst KINDS = ['fact', 'preference', 'decision', 'episode', 'skill'] as const\nconst PAGE_SIZE = 20\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\nfunction fmtTime(ms: number): string {\n return new Date(ms).toLocaleString('zh-CN', { hour12: false })\n}\n\n/** 行内审计区:来源链、关系与最近操作日志(review API)。 */\nfunction ReviewBody({ recordId, scope }: { recordId: string; scope: 'user' | 'project' }): React.ReactElement {\n const [text, setText] = useState<string | null>(null)\n useEffect(() => {\n let cancelled = false\n api<Record<string, unknown>>(`review?scope=${scope}&id=${encodeURIComponent(recordId)}`)\n .then((view) => {\n if (cancelled) return\n const record = view.record as MemoryRow\n const lines = [\n `内容: ${record.content}`,\n `属性: kind=${record.kind}, status=${record.status}, importance=${record.importance.toFixed(2)}, confidence=${record.confidence.toFixed(2)}, 访问 ${record.accessCount} 次`,\n `来源: ${record.sourceSessionId ?? '显式保存'}${record.sourceRound === null ? '' : ` 第${String(record.sourceRound)}轮`}`,\n ]\n for (const key of ['supersededBy', 'supersedes', 'contradicts', 'related'] as const) {\n const ids = view[key] as string[] | undefined\n if (ids !== undefined && ids.length > 0) lines.push(`${key}: ${ids.join(', ')}`)\n }\n const operations = view.operations as { at: number; op: string; detail: string | null }[] | undefined\n if (operations !== undefined && operations.length > 0) {\n lines.push('最近操作:')\n operations.forEach(op => lines.push(` ${fmtTime(op.at)} ${op.op}${op.detail ? ` ${op.detail}` : ''}`))\n }\n setText(lines.join('\\n'))\n })\n .catch((error: Error) => { if (!cancelled) setText(`加载失败:${error.message}`) })\n return () => { cancelled = true }\n }, [recordId, scope])\n if (text === null) return <div className={styles.expandLoading}>加载中…</div>\n return <pre className={styles.review}>{text}</pre>\n}\n\n/** 行内编辑表单:内容/种类/重要性 → POST update(旧条目归档,取代链保留)。 */\nfunction EditForm({ record, onClose, onSaved }: {\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}>内容</label>\n <textarea className={styles.input} rows={3} value={content} onChange={event => setContent(event.target.value)} />\n <label className={styles.fieldLabel}>种类</label>\n <select className={styles.input} value={kind} onChange={event => setKind(event.target.value)}>\n {KINDS.map(option => <option key={option} value={option}>{option}</option>)}\n </select>\n <label className={styles.fieldLabel}>重要性 {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}>取消</button>\n <button type=\"button\" className={`${styles.button} ${styles.primary}`} onClick={save}>保存(旧条目归档)</button>\n </div>\n </div>\n )\n}\n\n/** 设置页「记忆库」section 主组件。 */\nexport function EngramSection(): 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\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 = (kind: 'review' | 'edit', record: MemoryRow): void => {\n setExpanded(current => (current !== null && current.kind === kind && current.record.id === record.id)\n ? null\n : { kind, record })\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) }}>\n {option === 'user' ? '用户级' : '项目级'}\n </button>\n ))}\n </div>\n <button type=\"button\" className={styles.button} onClick={reload}>刷新</button>\n <button type=\"button\" className={styles.button}\n onClick={() => { location.href = `/api/engram/export?scope=${scope}&format=markdown` }}>导出 MD</button>\n <button type=\"button\" className={styles.button}\n onClick={() => { location.href = `/api/engram/export?scope=${scope}&format=json` }}>导出 JSON</button>\n </div>\n <div className={styles.cards}>\n {(stats ?? []).map(part => (\n <button key={part.scope} type=\"button\" className={styles.card}\n style={part.scope === scope ? { borderColor: 'var(--dsw-alias-brand-primary)' } : undefined}\n onClick={() => { setScope(part.scope); setOffset(0) }}>\n <b>{part.stats.total}</b>\n <span>{part.scope} · active {part.stats.active} · 信噪比 {Math.round(part.stats.signalRatio * 100)}%</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) }}>\n <option value=\"all\">全部状态</option>\n <option value=\"active\">active</option>\n <option value=\"archived\">archived</option>\n <option value=\"forgotten\">forgotten</option>\n </select>\n <select className={styles.input} value={kind}\n onChange={event => { setKind(event.target.value); setOffset(0); setExpanded(null) }}>\n <option value=\"all\">全部种类</option>\n {KINDS.map(option => <option key={option} value={option}>{option}</option>)}\n </select>\n <input className={styles.input} placeholder=\"按内容搜索…\" value={q}\n onChange={event => { setQ(event.target.value.trim()); setOffset(0); setExpanded(null) }} />\n </div>\n {error !== null && <div className={styles.empty}>{`加载失败:${error}`}</div>}\n {error === null && list !== null && list.records.length === 0 && (\n <div className={styles.empty}>没有符合条件的记忆</div>\n )}\n {(list?.records ?? []).map(record => (\n <div key={record.id} className={styles.item}>\n <div className={styles.row1}>\n <span className={`${styles.badge} ${styles[record.status]}`}>{record.status}</span>\n <span className={styles.badge}>{record.kind}</span>\n <span className={styles.badge}>{record.scope}</span>\n </div>\n <div className={styles.content}>{record.content}</div>\n <div className={styles.meta}>\n <span>重要性 {record.importance.toFixed(2)}</span>\n <span>置信 {record.confidence.toFixed(2)}</span>\n <span>访问 {record.accessCount} 次</span>\n <span>{record.sourceSessionId === null\n ? '显式保存'\n : `来源 ${record.sourceSessionId.slice(0, 16)}…${record.sourceRound === null ? '' : ` 第${String(record.sourceRound)}轮`}`}</span>\n <span>{fmtTime(record.createdAt)}</span>\n </div>\n <div className={styles.ops}>\n <button type=\"button\" className={styles.button}\n onClick={() => { toggle('review', record) }}>详情</button>\n <button type=\"button\" className={styles.button}\n onClick={() => { toggle('edit', record) }}>编辑</button>\n {record.status === 'active'\n ? <button type=\"button\" className={styles.button}\n onClick={() => { act('forget', record) }}>遗忘</button>\n : <button type=\"button\" className={styles.button}\n onClick={() => { act('restore', record) }}>恢复</button>}\n </div>\n {expanded !== null && expanded.record.id === record.id && (\n <div className={styles.expand}>\n {expanded.kind === 'review'\n ? <ReviewBody recordId={record.id} scope={record.scope} />\n : <EditForm 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)) }}>上一页</button>\n <span>第 {page} / {pages} 页 · 共 {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) }}>下一页</button>\n </div>\n </div>\n )\n}\n","/**\n * dsh-engram client half: 注册设置页「记忆库」section。\n * 数据经回环 API(/api/engram/*)读取与操作,与 host 半的路由对齐。\n * @module @kenz1117/dsh-engram/client\n */\n\nimport type { Context } from '@deepseek-ai/cordis'\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'\nimport { EngramSection } from './EngramPanel.tsx'\n\n/** 必需服务:slots 渲染接线。 */\nexport const inject = ['slots']\n\n/**\n * Client plugin body: 设置页注册「记忆库」section(order 20,排在\n * general/models/plugins 之后)。\n * @param ctx - client root context.\n */\nexport function apply(ctx: Context): void {\n ctx.slots.inject('settings.section', () => ctx.slots.register({\n name: 'settings.section',\n id: 'engram',\n order: 20,\n label: () => '记忆库',\n }, EngramSection))\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"client.js","names":["useState","styles","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/** 面板内部传递的翻译函数(渲染器按注册的 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 '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\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/** 来源会话展示片段:截短的会话 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\nfunction fmtTime(ms: number): string {\n // 时间格式跟随浏览器环境语言(宿主界面语言通常与浏览器一致)。\n return new Date(ms).toLocaleString(navigator.language || 'zh-CN', { hour12: false })\n}\n\n/** 行内审计区:来源链、关系与最近操作日志(review API)。 */\nfunction ReviewBody({ t, recordId, scope }: {\n t: T\n recordId: string\n scope: 'user' | 'project'\n}): React.ReactElement {\n const [text, setText] = useState<string | null>(null)\n useEffect(() => {\n let cancelled = false\n api<Record<string, unknown>>(`review?scope=${scope}&id=${encodeURIComponent(recordId)}`)\n .then((view) => {\n if (cancelled) return\n const record = view.record as MemoryRow\n const lines = [\n `${t('labelContent')}: ${record.content}`,\n `${t('detailAttributes')}: ${t('labelKind')}=${kindLabel(t, record.kind)}, ${t('labelStatus')}=${t(STATUS_KEY[record.status])}, ${t('importance')}=${record.importance.toFixed(2)}, ${t('confidence')}=${record.confidence.toFixed(2)}, ${t('accessCount', { n: record.accessCount })}`,\n `${t('detailSource')}: ${sourceLabel(t, record)}`,\n ]\n for (const key of ['supersededBy', 'supersedes', 'contradicts', 'related'] as const) {\n const ids = view[key] as string[] | undefined\n const relKey = REL_KEY[key]\n if (ids !== undefined && ids.length > 0) lines.push(`${relKey === undefined ? key : t(relKey)}: ${ids.join(', ')}`)\n }\n const operations = view.operations as { at: number; op: string; detail: string | null }[] | undefined\n if (operations !== undefined && operations.length > 0) {\n lines.push(`${t('detailOperations')}:`)\n operations.forEach(op => lines.push(` ${fmtTime(op.at)} ${opLabel(t, op.op)}${op.detail ? ` ${op.detail}` : ''}`))\n }\n setText(lines.join('\\n'))\n })\n .catch((error: Error) => { if (!cancelled) setText(t('loadFailed', { msg: error.message })) })\n return () => { cancelled = true }\n }, [recordId, scope, t])\n if (text === null) return <div className={styles.expandLoading}>{t('loading')}</div>\n return <pre className={styles.review}>{text}</pre>\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\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 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) }}>\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\" className={styles.card}\n style={part.scope === scope ? { borderColor: 'var(--dsw-alias-brand-primary)' } : undefined}\n onClick={() => { setScope(part.scope); setOffset(0) }}>\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 </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) }}>\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) }}>\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) }} />\n </div>\n {error !== null && <div className={styles.empty}>{t('loadFailed', { msg: error })}</div>}\n {error === null && list !== null && list.records.length === 0 && (\n <div className={styles.empty}>{t('empty')}</div>\n )}\n {(list?.records ?? []).map(record => (\n <div key={record.id} className={styles.item}>\n <div className={styles.row1}>\n <span className={`${styles.badge} ${styles[record.status]}`}>{t(STATUS_KEY[record.status])}</span>\n <span className={styles.badge}>{kindLabel(t, record.kind)}</span>\n <span className={styles.badge}>{t(SCOPE_KEY[record.scope])}</span>\n </div>\n <div className={styles.content}>{record.content}</div>\n <div className={styles.meta}>\n <span>{`${t('importance')} ${record.importance.toFixed(2)}`}</span>\n <span>{`${t('confidence')} ${record.confidence.toFixed(2)}`}</span>\n <span>{t('accessCount', { n: record.accessCount })}</span>\n <span>{sourceLabel(t, record)}</span>\n <span>{fmtTime(record.createdAt)}</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)) }}>{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) }}>{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 | 'importance'\n | 'confidence'\n | 'accessCount'\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 | 'opIngestRequest'\n | 'opDistillRequest'\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 importance: '重要性',\n confidence: '置信',\n accessCount: '访问 {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 opIngestRequest: '摄取请求',\n opDistillRequest: '蒸馏请求',\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 importance: 'Importance',\n confidence: 'Confidence',\n accessCount: '{n} accesses',\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 opIngestRequest: 'ingest-request',\n opDistillRequest: 'distill-request',\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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"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kenz1117/dsh-engram",
|
|
3
3
|
"description": "Cross-session long-term memory for DeepSeek Harness: dual-scope SQLite memory graph, hybrid retrieval, provenance audit, and a knowledge flywheel.",
|
|
4
|
-
"version": "0.4.
|
|
4
|
+
"version": "0.4.4",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
7
7
|
},
|
|
@@ -31,7 +31,9 @@
|
|
|
31
31
|
"patch": "./cordis.patch.yml"
|
|
32
32
|
},
|
|
33
33
|
"client": {
|
|
34
|
-
"inject": [
|
|
34
|
+
"inject": [
|
|
35
|
+
"@deepseek-ai/dsh-client-locale"
|
|
36
|
+
],
|
|
35
37
|
"platform": "web"
|
|
36
38
|
}
|
|
37
39
|
},
|
package/scripts/link-peers.mjs
CHANGED
|
@@ -29,8 +29,10 @@ const LINKED_PACKAGES = [
|
|
|
29
29
|
['@deepseek-ai/dsh-system-prompt', 'packages/core/system-prompt'],
|
|
30
30
|
['@deepseek-ai/dsh-session', 'packages/core/session'],
|
|
31
31
|
['@deepseek-ai/dsh-host-webserver', 'packages/host/webserver'],
|
|
32
|
+
['@deepseek-ai/dsh-client-locale', 'packages/client/locale'],
|
|
32
33
|
['@deepseek-ai/dsh-client-ui-settings', 'packages/client/ui-settings'],
|
|
33
34
|
['@deepseek-ai/dsh-client-ui-renderer', 'packages/client/ui-renderer'],
|
|
35
|
+
['@deepseek-ai/dsh-client-ui-slots', 'packages/client/ui-slots'],
|
|
34
36
|
['@deepseek-ai/dsh-llm', 'packages/llm/llm'],
|
|
35
37
|
['@deepseek-ai/dsh-agent', 'packages/core/agent'],
|
|
36
38
|
['@deepseek-ai/dsh-scope', 'packages/core/scope'],
|