@a9i5k4/dsh-auto-memory 0.1.17 → 0.1.18
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/cordis.patch.yml +9 -9
- package/lib/client.js +17 -2
- package/lib/client.js.bak-20260814 +568 -0
- package/package.json +46 -46
package/cordis.patch.yml
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
# dsh-auto-memory bundle patch: inserts the dual-face plugin row into the web
|
|
2
|
-
# profile roster. Applied as a profile bundle layer (the `dsh.bundle.patch`
|
|
3
|
-
# manifest field). The node half (exports ".") runs in the host process
|
|
4
|
-
# (memory engine, /api/dsh-auto-memory routes, agent tools, prompt injection);
|
|
5
|
-
# the `dsh.client` declaration in package.json makes the browser half
|
|
6
|
-
# (exports "./client", served at /plugins/<id>/client.js) load in the web GUI.
|
|
7
|
-
- insert:
|
|
8
|
-
- id: auto-memory
|
|
9
|
-
name: '@
|
|
1
|
+
# dsh-auto-memory bundle patch: inserts the dual-face plugin row into the web
|
|
2
|
+
# profile roster. Applied as a profile bundle layer (the `dsh.bundle.patch`
|
|
3
|
+
# manifest field). The node half (exports ".") runs in the host process
|
|
4
|
+
# (memory engine, /api/dsh-auto-memory routes, agent tools, prompt injection);
|
|
5
|
+
# the `dsh.client` declaration in package.json makes the browser half
|
|
6
|
+
# (exports "./client", served at /plugins/<id>/client.js) load in the web GUI.
|
|
7
|
+
- insert:
|
|
8
|
+
- id: auto-memory-dev
|
|
9
|
+
name: '@deepseek-ai/dsh-auto-memory'
|
package/lib/client.js
CHANGED
|
@@ -115,7 +115,7 @@ window.__ModuleLoader__.load({
|
|
|
115
115
|
kvAvail: '可用', kvUnavail: '不可用', kvDup: '项目笔记重复标题', kvDupCount: ' 个',
|
|
116
116
|
kvMem: '记忆文件', kvMemUser: '用户', kvMemNotes: '笔记', kvMemLog: '日志', kvMemMissing: '缺失',
|
|
117
117
|
kvWs: '当前工作区', kvWsUnknown: '(未取到)', kvApi: 'API 连通', unknown: '(未知)',
|
|
118
|
-
guideTitle: '欢迎使用 dsh-auto-memory', guideSub: '这个插件能干什么:',
|
|
118
|
+
guideTitle: '欢迎使用 dsh-auto-memory(开发版)', guideSub: '这个插件能干什么:',
|
|
119
119
|
gFeat1: '三层记忆自动注入与检索:用户级 / 项目笔记 / 每日日志,每轮对话自动读、自动写',
|
|
120
120
|
gFeat2: '每轮对话结束自动沉淀:修了什么 bug、做了哪些决策,自动按主题写进今日日志',
|
|
121
121
|
gFeat3: 'AI 时段问候与三级抽屉:打开「记忆」面板,AI 按时段向你汇报当天进展',
|
|
@@ -205,7 +205,7 @@ window.__ModuleLoader__.load({
|
|
|
205
205
|
kvAvail: 'available', kvUnavail: 'unavailable', kvDup: 'Duplicate note headings', kvDupCount: '',
|
|
206
206
|
kvMem: 'Memory files', kvMemUser: 'user', kvMemNotes: 'notes', kvMemLog: 'log', kvMemMissing: 'missing',
|
|
207
207
|
kvWs: 'Current workspace', kvWsUnknown: '(unknown)', kvApi: 'API probes', unknown: '(unknown)',
|
|
208
|
-
guideTitle: 'Welcome to dsh-auto-memory', guideSub: 'What this plugin does:',
|
|
208
|
+
guideTitle: 'Welcome to dsh-auto-memory (dev)', guideSub: 'What this plugin does:',
|
|
209
209
|
gFeat1: 'Three-layer memory with automatic injection & retrieval: user / project notes / daily logs',
|
|
210
210
|
gFeat2: 'Auto-consolidation after every turn: bugs fixed and decisions made are written into today\'s log automatically',
|
|
211
211
|
gFeat3: 'AI period greetings with three-level drawers: open the Memory panel for a period-by-period digest',
|
|
@@ -313,6 +313,21 @@ window.__ModuleLoader__.load({
|
|
|
313
313
|
|
|
314
314
|
// ───────────────────────── 更新弹窗 / 首次指导 ─────────────────────────
|
|
315
315
|
var CHANGELOG = {
|
|
316
|
+
'0.1.18': { zh: [
|
|
317
|
+
'稳定版:整合 0.1.13~0.1.17 全部修复与优化',
|
|
318
|
+
'核心:上下文缓存策略重写——记忆注入迁至运行时上下文快照,系统提示词保持稳定,DeepSeek 前缀缓存全程命中,不再白白消耗 token(命中率恢复 95%+)',
|
|
319
|
+
'修复:秒级时间戳击穿前缀缓存(改日期级)',
|
|
320
|
+
'修复:npm 安装后客户端面板无法加载(bundle 注册名)',
|
|
321
|
+
'新增:更新说明弹窗/首次安装指导/暂离回归自动打开记忆窗口/动态通知中心',
|
|
322
|
+
'提示:pnpm v11 默认限制安装发布不足 1 天的版本,想立即获取新版请在 pnpm-workspace.yaml 设 minimumReleaseAge: 0 或使用显式版本号',
|
|
323
|
+
], en: [
|
|
324
|
+
'Stable release: consolidates 0.1.13~0.1.17 fixes and polish',
|
|
325
|
+
'Core: context-cache strategy rewrite — memory injection moved to runtime-context snapshot, system prompt stays byte-stable, DeepSeek prefix cache hits throughout, no more wasted tokens (hit rate back to 95%+)',
|
|
326
|
+
'Fix: second-level timestamp breaking prefix cache (now date-level)',
|
|
327
|
+
'Fix: client panel not loading after npm install (bundle registration id)',
|
|
328
|
+
'New: update dialog / first-run guide / memory panel auto-opens after >1h away / dynamic notice center',
|
|
329
|
+
'Note: pnpm v11 blocks packages published <1 day ago by default; set minimumReleaseAge: 0 in pnpm-workspace.yaml or use an explicit version for the latest immediately',
|
|
330
|
+
] },
|
|
316
331
|
'0.1.17': { zh: [
|
|
317
332
|
'新增:动态通知中心——插件自动拉取发布者的重要提醒(重大 bug/升级建议),特定时间窗口内显示,无需等待发版即可收到推送',
|
|
318
333
|
'优化:0.1.14 及以下旧版本已全部弃用(缓存击穿浪费 token),升级到 0.1.16+ 彻底解决',
|
|
@@ -0,0 +1,568 @@
|
|
|
1
|
+
/* dsh-auto-memory — browser half (hand-written __ModuleLoader__ bundle).
|
|
2
|
+
* Registers three additive surfaces:
|
|
3
|
+
* 1. sidebar.footer.action — 「记忆」入口按钮(开关左下角浮层面板)
|
|
4
|
+
* 2. shell.overlay — 记忆面板:概览 / 日志 / 笔记 / 反思 / 检索
|
|
5
|
+
* 液态玻璃视觉(backdrop-filter + --dsw-alias-* 主题令牌),
|
|
6
|
+
* 可拖动 / 右下角缩放 / 开关缩放动画 / 位置大小持久化。
|
|
7
|
+
* 3. settings.section — 自动记忆设置页(存储位置、注入、反思风格)
|
|
8
|
+
* Data flows over /api/dsh-auto-memory/* (loopback-only host routes).
|
|
9
|
+
*/
|
|
10
|
+
window.__ModuleLoader__.load({
|
|
11
|
+
id: '@deepseek-ai/dsh-auto-memory',
|
|
12
|
+
factory: (require) => {
|
|
13
|
+
var module = { exports: {} }
|
|
14
|
+
var exports = module.exports
|
|
15
|
+
var React = require('react')
|
|
16
|
+
var h = React.createElement
|
|
17
|
+
var useState = React.useState
|
|
18
|
+
var useEffect = React.useEffect
|
|
19
|
+
var useReducer = React.useReducer
|
|
20
|
+
|
|
21
|
+
// ───────────────────────── 控制器 ─────────────────────────
|
|
22
|
+
var listeners = new Set()
|
|
23
|
+
var panelOpen = false
|
|
24
|
+
var panelClosing = false
|
|
25
|
+
var closeTimer = null
|
|
26
|
+
// 几何状态:left/top/width/height,持久化到 localStorage(用户可拖动/缩放)
|
|
27
|
+
var GEOM_KEY = 'dsh-auto-memory.panel.geom'
|
|
28
|
+
var DEFAULT_W = 440
|
|
29
|
+
var DEFAULT_H = 560
|
|
30
|
+
var DEFAULT_GAP = 16
|
|
31
|
+
function defaultGeom() {
|
|
32
|
+
var vh = window.innerHeight || 800
|
|
33
|
+
return {
|
|
34
|
+
left: DEFAULT_GAP,
|
|
35
|
+
top: Math.max(DEFAULT_GAP, vh - DEFAULT_H - DEFAULT_GAP),
|
|
36
|
+
width: DEFAULT_W,
|
|
37
|
+
height: DEFAULT_H,
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
var geom = null
|
|
41
|
+
function clampGeom(g) {
|
|
42
|
+
var vw = window.innerWidth || 1280
|
|
43
|
+
var vh = window.innerHeight || 800
|
|
44
|
+
var w = Math.max(300, Math.min(g.width || DEFAULT_W, vw - DEFAULT_GAP * 2))
|
|
45
|
+
var h = Math.max(240, Math.min(g.height || DEFAULT_H, vh - DEFAULT_GAP * 2))
|
|
46
|
+
return {
|
|
47
|
+
left: Math.max(DEFAULT_GAP, Math.min(g.left !== undefined ? g.left : DEFAULT_GAP, vw - w - DEFAULT_GAP)),
|
|
48
|
+
top: Math.max(DEFAULT_GAP, Math.min(g.top !== undefined ? g.top : DEFAULT_GAP, vh - h - DEFAULT_GAP)),
|
|
49
|
+
width: w,
|
|
50
|
+
height: h,
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
function loadGeom() {
|
|
54
|
+
try {
|
|
55
|
+
var raw = localStorage.getItem(GEOM_KEY)
|
|
56
|
+
if (raw) return clampGeom(JSON.parse(raw))
|
|
57
|
+
} catch (e) {}
|
|
58
|
+
return clampGeom(defaultGeom())
|
|
59
|
+
}
|
|
60
|
+
function persistGeom() { if (geom) { try { localStorage.setItem(GEOM_KEY, JSON.stringify(geom)) } catch (e) {} } }
|
|
61
|
+
function emit() { listeners.forEach(function (fn) { try { fn() } catch (e) {} }) }
|
|
62
|
+
var controller = {
|
|
63
|
+
isOpen: function () { return panelOpen },
|
|
64
|
+
isClosing: function () { return panelClosing },
|
|
65
|
+
geom: function () { if (!geom) geom = loadGeom(); return geom },
|
|
66
|
+
setGeom: function (partial) {
|
|
67
|
+
var cur = controller.geom()
|
|
68
|
+
geom = clampGeom({
|
|
69
|
+
left: partial.left !== undefined ? partial.left : cur.left,
|
|
70
|
+
top: partial.top !== undefined ? partial.top : cur.top,
|
|
71
|
+
width: partial.width !== undefined ? partial.width : cur.width,
|
|
72
|
+
height: partial.height !== undefined ? partial.height : cur.height,
|
|
73
|
+
})
|
|
74
|
+
emit()
|
|
75
|
+
},
|
|
76
|
+
flushGeom: function () { persistGeom() },
|
|
77
|
+
resetGeom: function () { geom = clampGeom(defaultGeom()); persistGeom(); emit() },
|
|
78
|
+
toggle: function () { if (panelOpen) controller.close(); else controller.open() },
|
|
79
|
+
open: function () {
|
|
80
|
+
if (closeTimer) { clearTimeout(closeTimer); closeTimer = null }
|
|
81
|
+
panelOpen = true; panelClosing = false; emit()
|
|
82
|
+
},
|
|
83
|
+
close: function () {
|
|
84
|
+
if (!panelOpen || panelClosing) return
|
|
85
|
+
panelClosing = true; emit()
|
|
86
|
+
closeTimer = setTimeout(function () {
|
|
87
|
+
panelOpen = false; panelClosing = false; closeTimer = null; emit()
|
|
88
|
+
}, 170)
|
|
89
|
+
},
|
|
90
|
+
subscribe: function (fn) { listeners.add(fn); return function () { listeners.delete(fn) } },
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// ───────────────────────── API ─────────────────────────
|
|
94
|
+
var API = {
|
|
95
|
+
state: '/api/dsh-auto-memory/state',
|
|
96
|
+
list: '/api/dsh-auto-memory/list',
|
|
97
|
+
file: '/api/dsh-auto-memory/file',
|
|
98
|
+
recall: '/api/dsh-auto-memory/recall',
|
|
99
|
+
config: '/api/dsh-auto-memory/config',
|
|
100
|
+
reflect: '/api/dsh-auto-memory/reflect',
|
|
101
|
+
note: '/api/dsh-auto-memory/note',
|
|
102
|
+
external: '/api/dsh-auto-memory/external',
|
|
103
|
+
externalImport: '/api/dsh-auto-memory/external-import',
|
|
104
|
+
}
|
|
105
|
+
function query(params) {
|
|
106
|
+
var search = new URLSearchParams()
|
|
107
|
+
for (var key in params) if (params[key] !== undefined && params[key] !== '') search.set(key, String(params[key]))
|
|
108
|
+
var text = search.toString()
|
|
109
|
+
return text ? '?' + text : ''
|
|
110
|
+
}
|
|
111
|
+
async function apiGet(path, params) {
|
|
112
|
+
var res = await fetch(path + query(params))
|
|
113
|
+
var body = await res.json().catch(function () { return {} })
|
|
114
|
+
if (!res.ok) throw new Error(body.error || ('HTTP ' + res.status))
|
|
115
|
+
return body
|
|
116
|
+
}
|
|
117
|
+
async function apiPost(path, payload) {
|
|
118
|
+
var res = await fetch(path, { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify(payload) })
|
|
119
|
+
var body = await res.json().catch(function () { return {} })
|
|
120
|
+
if (!res.ok) throw new Error(body.error || ('HTTP ' + res.status))
|
|
121
|
+
return body
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// ───────────────────────── 样式 ─────────────────────────
|
|
125
|
+
// 视觉:液态玻璃(毛玻璃)—— backdrop-filter + DSH 主题令牌(--dsw-alias-*),
|
|
126
|
+
// 跟随亮/暗主题与页面背景自适应;位置/尺寸由 JS 几何状态驱动(可拖动、可缩放)。
|
|
127
|
+
var CSS = [
|
|
128
|
+
'[data-dam-panel] { position: fixed; left: 16px; width: 440px; height: 560px;',
|
|
129
|
+
' max-width: calc(100vw - 32px); max-height: calc(100vh - 32px);',
|
|
130
|
+
' display: flex; flex-direction: column; overflow: hidden; z-index: 3000; pointer-events: auto;',
|
|
131
|
+
' border-radius: 16px; font: 13px/1.55 system-ui, "Segoe UI", sans-serif;',
|
|
132
|
+
' background: color-mix(in srgb, var(--dsw-alias-bg-overlay, rgba(255,255,255,.86)) 58%, transparent);',
|
|
133
|
+
' -webkit-backdrop-filter: blur(28px) saturate(1.55); backdrop-filter: blur(28px) saturate(1.55);',
|
|
134
|
+
' border: 1px solid color-mix(in srgb, var(--dsw-alias-border-l1, rgba(128,128,128,.35)) 65%, transparent);',
|
|
135
|
+
' box-shadow: 0 24px 64px rgba(0,0,0,.22), 0 4px 16px rgba(0,0,0,.10), inset 0 1px 0 rgba(255,255,255,.22);',
|
|
136
|
+
' color: var(--dsw-alias-label-primary, #1f2328);',
|
|
137
|
+
' animation: dam-in .2s cubic-bezier(.2,.9,.3,1.15) both; transform-origin: left bottom; }',
|
|
138
|
+
'@keyframes dam-in { from { opacity: 0; transform: scale(.92) translateY(10px); } to { opacity: 1; transform: none; } }',
|
|
139
|
+
'@keyframes dam-out { from { opacity: 1; transform: none; } to { opacity: 0; transform: scale(.95) translateY(6px); } }',
|
|
140
|
+
'[data-dam-panel][data-closing="true"] { animation: dam-out .16s ease-in both; }',
|
|
141
|
+
'[data-dam-panel]::before { content: ""; position: absolute; inset: 0 0 auto 0; height: 64%; pointer-events: none;',
|
|
142
|
+
' background: linear-gradient(180deg, rgba(255,255,255,.13), rgba(255,255,255,0) 70%); border-radius: 16px 16px 0 0; }',
|
|
143
|
+
'[data-dam-panel][data-dragging="true"] { user-select: none; }',
|
|
144
|
+
'[data-dam-panel] header { display: flex; align-items: center; gap: 8px; padding: 10px 14px; cursor: grab;',
|
|
145
|
+
' border-bottom: 1px solid color-mix(in srgb, var(--dsw-alias-border-l1, rgba(128,128,128,.25)) 55%, transparent); }',
|
|
146
|
+
'[data-dam-panel][data-dragging="true"] header { cursor: grabbing; }',
|
|
147
|
+
'[data-dam-panel] header strong { font-size: 14px; }',
|
|
148
|
+
'[data-dam-panel] header .dam-spacer { flex: 1; }',
|
|
149
|
+
'[data-dam-resize] { position: absolute; right: 0; bottom: 0; width: 22px; height: 22px; cursor: nwse-resize;',
|
|
150
|
+
' opacity: .55; z-index: 2; border-radius: 0 0 16px 0;',
|
|
151
|
+
' background: linear-gradient(135deg, transparent 50%, color-mix(in srgb, var(--dsw-alias-label-secondary, #666) 45%, transparent) 50%); }',
|
|
152
|
+
'[data-dam-resize]:hover { opacity: 1; }',
|
|
153
|
+
'[data-dam-btn] { border: none; background: transparent; cursor: pointer; color: inherit; opacity: .75; font-size: 13px; padding: 4px 8px; border-radius: 6px; }',
|
|
154
|
+
'[data-dam-btn]:hover { opacity: 1; background: color-mix(in srgb, var(--dsw-alias-label-secondary, #666) 16%, transparent); }',
|
|
155
|
+
'[data-dam-tabs] { display: flex; gap: 2px; padding: 6px 10px; border-bottom: 1px solid color-mix(in srgb, var(--dsw-alias-border-l1, rgba(128,128,128,.2)) 55%, transparent); }',
|
|
156
|
+
'[data-dam-tab] { border: none; background: transparent; cursor: pointer; color: inherit; opacity: .6; padding: 5px 10px; border-radius: 7px; font-size: 12.5px; }',
|
|
157
|
+
'[data-dam-tab][data-active="true"] { opacity: 1; background: color-mix(in srgb, var(--dsw-alias-label-secondary, #666) 18%, transparent); font-weight: 600; }',
|
|
158
|
+
'[data-dam-body] { flex: 1; overflow: auto; padding: 12px 14px; }',
|
|
159
|
+
'[data-dam-kv] { display: grid; grid-template-columns: auto 1fr; gap: 4px 12px; font-size: 12.5px; }',
|
|
160
|
+
'[data-dam-kv] b { opacity: .55; font-weight: 500; }',
|
|
161
|
+
'[data-dam-card] { border: 1px solid color-mix(in srgb, var(--dsw-alias-border-l1, rgba(128,128,128,.22)) 60%, transparent); border-radius: 9px; padding: 8px 10px; margin-bottom: 8px; font-size: 12.5px;',
|
|
162
|
+
' background: color-mix(in srgb, var(--dsw-alias-bg-layer-1, rgba(128,128,128,.06)) 40%, transparent); }',
|
|
163
|
+
'[data-dam-card] .dam-date { font-weight: 600; margin-bottom: 4px; }',
|
|
164
|
+
'[data-dam-card] .dam-content { white-space: pre-wrap; word-break: break-word; max-height: 220px; overflow: auto; }',
|
|
165
|
+
'[data-dam-banner] { border: 1px solid color-mix(in srgb, var(--dsw-alias-state-warn-primary, #e6a23c) 55%, transparent);',
|
|
166
|
+
' background: color-mix(in srgb, var(--dsw-alias-state-warn-primary, #e6a23c) 13%, transparent); border-radius: 9px; padding: 8px 10px; margin-bottom: 10px; font-size: 12.5px; }',
|
|
167
|
+
'[data-dam-input], [data-dam-select] { width: 100%; box-sizing: border-box; background: color-mix(in srgb, var(--dsw-alias-bg-layer-1, rgba(128,128,128,.08)) 45%, transparent); color: inherit; border: 1px solid color-mix(in srgb, var(--dsw-alias-border-l1, rgba(128,128,128,.3)) 60%, transparent); border-radius: 7px; padding: 6px 8px; font: inherit; }',
|
|
168
|
+
'[data-dam-row] { display: flex; align-items: center; gap: 8px; margin-bottom: 10px; }',
|
|
169
|
+
'[data-dam-row] label { flex: 0 0 110px; opacity: .8; font-size: 12.5px; }',
|
|
170
|
+
'[data-dam-hint] { opacity: .5; font-size: 11.5px; margin-top: 2px; }',
|
|
171
|
+
'[data-dam-sidebar-btn] { display: flex; align-items: center; gap: 6px; width: 100%; border: none; background: transparent; color: inherit; cursor: pointer; padding: 6px 10px; border-radius: 8px; font: inherit; font-size: 13px; opacity: .8; }',
|
|
172
|
+
'[data-dam-sidebar-btn]:hover { background: color-mix(in srgb, var(--dsw-alias-label-secondary, #666) 14%, transparent); opacity: 1; }',
|
|
173
|
+
'[data-dam-sidebar-btn][data-active="true"] { opacity: 1; background: color-mix(in srgb, var(--dsw-alias-brand-primary, #4f7cff) 16%, transparent); color: var(--dsw-alias-brand-primary, #4f7cff); }',
|
|
174
|
+
'[data-dam-error] { color: var(--dsw-alias-state-error-primary, #d64545); font-size: 12px; margin-top: 6px; white-space: pre-wrap; }',
|
|
175
|
+
'[data-dam-muted] { opacity: .55; }',
|
|
176
|
+
'@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {',
|
|
177
|
+
' [data-dam-panel] { background: var(--dsw-alias-bg-overlay, #ffffff); } }',
|
|
178
|
+
].join('\n')
|
|
179
|
+
var STYLE_ID = 'dsh-auto-memory-css'
|
|
180
|
+
function ensureStyle() {
|
|
181
|
+
if (document.getElementById(STYLE_ID)) return
|
|
182
|
+
var tag = document.createElement('style')
|
|
183
|
+
tag.id = STYLE_ID
|
|
184
|
+
tag.dataset.plugin = '@deepseek-ai/dsh-auto-memory'
|
|
185
|
+
tag.textContent = CSS
|
|
186
|
+
document.head.appendChild(tag)
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
// ───────────────────────── 通用小组件 ─────────────────────────
|
|
190
|
+
function useTick() { return useReducer(function (x) { return x + 1 }, 0) }
|
|
191
|
+
|
|
192
|
+
function Banner(props) {
|
|
193
|
+
return h('div', { 'data-dam-banner': '' }, props.children)
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
function Card(props) {
|
|
197
|
+
return h('div', { 'data-dam-card': '' },
|
|
198
|
+
h('div', { className: 'dam-date' }, props.title),
|
|
199
|
+
h('div', { className: 'dam-content' }, props.children))
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
function Loading() { return h('div', { 'data-dam-muted': '' }, '加载中…') }
|
|
203
|
+
|
|
204
|
+
// ───────────────────────── 侧边栏入口 ─────────────────────────
|
|
205
|
+
function SidebarButton() {
|
|
206
|
+
var tick = useTick()
|
|
207
|
+
useEffect(function () { return controller.subscribe(tick[1]) }, [])
|
|
208
|
+
return h('button', {
|
|
209
|
+
'data-dam-sidebar-btn': '',
|
|
210
|
+
title: '记忆面板',
|
|
211
|
+
'data-active': (panelOpen || panelClosing) ? 'true' : undefined,
|
|
212
|
+
onClick: function () { controller.toggle() },
|
|
213
|
+
}, h('span', null, '记忆'))
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
// ───────────────────────── 记忆面板 ─────────────────────────
|
|
217
|
+
function fmtSize(n) {
|
|
218
|
+
if (n >= 1024 * 1024) return (n / 1024 / 1024).toFixed(1) + ' MB'
|
|
219
|
+
if (n >= 1024) return (n / 1024).toFixed(1) + ' KB'
|
|
220
|
+
return n + ' B'
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
function OverviewTab() {
|
|
224
|
+
var tick = useTick()
|
|
225
|
+
var state = null
|
|
226
|
+
useEffect(function () {
|
|
227
|
+
var alive = true
|
|
228
|
+
apiGet(API.state).then(function (s) { if (alive) { state = s; tick[1]() } }).catch(function () {})
|
|
229
|
+
return function () { alive = false }
|
|
230
|
+
}, [])
|
|
231
|
+
if (!state) return h(Loading)
|
|
232
|
+
return h('div', null,
|
|
233
|
+
state.pendingReflection
|
|
234
|
+
? h(Banner, null, '待生成反思: ' + state.pendingReflection + ' —— 打开/继续会话,agent 会在会话开始时主动呈现昨日反思。')
|
|
235
|
+
: null,
|
|
236
|
+
h('div', { 'data-dam-kv': '' },
|
|
237
|
+
h('b', null, '工作区'), h('span', null, state.ws),
|
|
238
|
+
h('b', null, '用户级记忆'), h('span', null, state.userFile + ' (' + fmtSize(state.sizes.user) + ')'),
|
|
239
|
+
h('b', null, '项目笔记'), h('span', null, state.notesPath + ' (' + fmtSize(state.sizes.notes) + ')'),
|
|
240
|
+
h('b', null, '今日日志'), h('span', null, state.logPath + ' · ' + state.todayEntries + ' 条 (' + fmtSize(state.sizes.log) + ')'),
|
|
241
|
+
h('b', null, '最近反思'), h('span', null, state.latestReflectionDate || '(无)'),
|
|
242
|
+
h('b', null, '配置文件'), h('span', null, state.configReadError ? ('读取失败: ' + state.configReadError) : '正常')),
|
|
243
|
+
h('div', { 'data-dam-hint': '' }, '上次刷新: ' + (state.refreshedAt ? new Date(state.refreshedAt).toLocaleString() : '尚未')))
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
function LogsTab() {
|
|
247
|
+
var tick = useTick()
|
|
248
|
+
var data = null
|
|
249
|
+
var open = null
|
|
250
|
+
var content = ''
|
|
251
|
+
useEffect(function () {
|
|
252
|
+
var alive = true
|
|
253
|
+
apiGet(API.list).then(function (d) { if (alive) { data = d; tick[1]() } }).catch(function () {})
|
|
254
|
+
return function () { alive = false }
|
|
255
|
+
}, [])
|
|
256
|
+
useEffect(function () {
|
|
257
|
+
if (!open) return
|
|
258
|
+
var alive = true
|
|
259
|
+
apiGet(API.file, { path: open }).then(function (d) { if (alive) { content = d.content; tick[1]() } }).catch(function () {})
|
|
260
|
+
return function () { alive = false }
|
|
261
|
+
}, [open])
|
|
262
|
+
if (!data) return h(Loading)
|
|
263
|
+
var rows = []
|
|
264
|
+
if (open) {
|
|
265
|
+
rows.push(h(Card, { title: pathName(open) },
|
|
266
|
+
h('div', { 'data-dam-content': '' }, content || '(空)'),
|
|
267
|
+
h('button', { 'data-dam-btn': '', onClick: function () { open = null; content = ''; tick[1]() } }, '← 返回')))
|
|
268
|
+
} else {
|
|
269
|
+
rows.push(h('div', { 'data-dam-hint': '' }, '点击日期查看当日日志(append-only):'))
|
|
270
|
+
for (var i = 0; i < data.logs.length; i++) {
|
|
271
|
+
(function (log) {
|
|
272
|
+
rows.push(h(Card, { title: log.date + ' · ' + fmtSize(log.size) },
|
|
273
|
+
h('button', { 'data-dam-btn': '', onClick: function () { open = log.date + '.md'; tick[1]() } }, '查看')))
|
|
274
|
+
})(data.logs[i])
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
return h('div', null, rows)
|
|
278
|
+
}
|
|
279
|
+
function pathName(p) { var parts = String(p).split(/[\\/]/); return parts[parts.length - 1] }
|
|
280
|
+
|
|
281
|
+
function NotesTab() {
|
|
282
|
+
var tick = useTick()
|
|
283
|
+
var data = null
|
|
284
|
+
var draft = ''
|
|
285
|
+
var saving = false
|
|
286
|
+
var msg = ''
|
|
287
|
+
var err = ''
|
|
288
|
+
if (!data) {
|
|
289
|
+
apiGet(API.state).then(function (s) { data = s; tick[1]() }).catch(function () {})
|
|
290
|
+
return h(Loading)
|
|
291
|
+
}
|
|
292
|
+
function save() {
|
|
293
|
+
if (!draft.trim() || saving) return
|
|
294
|
+
saving = true; msg = ''; err = ''
|
|
295
|
+
apiPost(API.note, { content: draft.trim() }).then(function (d) {
|
|
296
|
+
msg = d.result || '已追加 ✓'; draft = ''; saving = false; tick[1]()
|
|
297
|
+
}).catch(function (e) { err = e.message; saving = false; tick[1]() })
|
|
298
|
+
}
|
|
299
|
+
return h('div', null,
|
|
300
|
+
h('div', { 'data-dam-hint': '' }, '项目笔记: ' + data.notesPath),
|
|
301
|
+
h('textarea', { 'data-dam-input': '', rows: 6, placeholder: '想追加到项目笔记的内容…(保存时自动带日期标题)', value: draft, onChange: function (e) { draft = e.target.value; tick[1]() } }),
|
|
302
|
+
h('div', { 'data-dam-row': '' },
|
|
303
|
+
h('button', { 'data-dam-btn': '', onClick: save, disabled: saving }, saving ? '保存中…' : '追加'),
|
|
304
|
+
h('span', { 'data-dam-hint': '' }, '建议直接用对话让 agent 调 memory_note;此处为手动追加。')),
|
|
305
|
+
msg ? h('div', null, msg) : null,
|
|
306
|
+
err ? h('div', { 'data-dam-error': '' }, err) : null)
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
function ReflectionsTab() {
|
|
310
|
+
var tick = useTick()
|
|
311
|
+
var data = null
|
|
312
|
+
var open = null
|
|
313
|
+
var content = ''
|
|
314
|
+
useEffect(function () {
|
|
315
|
+
var alive = true
|
|
316
|
+
apiGet(API.list).then(function (d) { if (alive) { data = d; tick[1]() } }).catch(function () {})
|
|
317
|
+
return function () { alive = false }
|
|
318
|
+
}, [])
|
|
319
|
+
useEffect(function () {
|
|
320
|
+
if (!open) return
|
|
321
|
+
var alive = true
|
|
322
|
+
apiGet(API.file, { path: open }).then(function (d) { if (alive) { content = d.content; tick[1]() } }).catch(function () {})
|
|
323
|
+
return function () { alive = false }
|
|
324
|
+
}, [open])
|
|
325
|
+
if (!data) return h(Loading)
|
|
326
|
+
var rows = []
|
|
327
|
+
if (open) {
|
|
328
|
+
rows.push(h(Card, { title: '反思 ' + pathName(open) }, h('div', { 'data-dam-content': '' }, content || '(空)')))
|
|
329
|
+
rows.push(h('button', { 'data-dam-btn': '', onClick: function () { open = null; content = ''; tick[1]() } }, '← 返回'))
|
|
330
|
+
} else {
|
|
331
|
+
if (!data.reflections.length) rows.push(h('div', { 'data-dam-muted': '' }, '还没有反思。每天第一次会话时,agent 会主动呈现前一天的工作反思。'))
|
|
332
|
+
for (var i = 0; i < data.reflections.length; i++) {
|
|
333
|
+
(function (r) {
|
|
334
|
+
rows.push(h(Card, { title: r.date + ' · ' + fmtSize(r.size) },
|
|
335
|
+
h('button', { 'data-dam-btn': '', onClick: function () { open = 'reflections/' + r.name; tick[1]() } }, '查看')))
|
|
336
|
+
})(data.reflections[i])
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
return h('div', null, rows)
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
function SearchTab() {
|
|
343
|
+
var tick = useTick()
|
|
344
|
+
var q = ''
|
|
345
|
+
var result = null
|
|
346
|
+
var busy = false
|
|
347
|
+
function search() {
|
|
348
|
+
if (!q.trim() || busy) return
|
|
349
|
+
busy = true; result = null; tick[1]()
|
|
350
|
+
apiPost(API.recall, { query: q.trim() }).then(function (d) { result = d.result; busy = false; tick[1]() })
|
|
351
|
+
.catch(function (e) { result = '检索失败: ' + e.message; busy = false; tick[1]() })
|
|
352
|
+
}
|
|
353
|
+
return h('div', null,
|
|
354
|
+
h('div', { 'data-dam-row': '' },
|
|
355
|
+
h('input', { 'data-dam-input': '', placeholder: '搜记忆:关键词或自包含描述…', value: q, onChange: function (e) { q = e.target.value; tick[1]() }, onKeyDown: function (e) { if (e.key === 'Enter') search() } }),
|
|
356
|
+
h('button', { 'data-dam-btn': '', onClick: search, disabled: busy }, '检索')),
|
|
357
|
+
result ? h(Card, { title: '结果' }, h('div', { 'data-dam-content': '' }, result)) : null)
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
var TOOL_LABEL = { workbuddy: 'WorkBuddy', codebuddy: 'CodeBuddy', claude: 'Claude Code', codex: 'Codex', 'project-files': '项目文件' }
|
|
361
|
+
function ConnectTab() {
|
|
362
|
+
var tick = useTick()
|
|
363
|
+
var sources = null
|
|
364
|
+
var busy = {}
|
|
365
|
+
var msg = ''
|
|
366
|
+
var err = ''
|
|
367
|
+
function load() {
|
|
368
|
+
apiGet(API.external).then(function (d) { sources = d.sources || []; tick[1]() }).catch(function (e) { err = e.message; tick[1]() })
|
|
369
|
+
}
|
|
370
|
+
useEffect(function () { load(); var t = setInterval(load, 60000); return function () { clearInterval(t) } }, [])
|
|
371
|
+
if (!sources) return err ? h('div', { 'data-dam-error': '' }, err) : h(Loading)
|
|
372
|
+
function doImport(source, target) {
|
|
373
|
+
busy[source] = true; msg = ''; err = ''
|
|
374
|
+
apiPost(API.externalImport, { source: source, target: target }).then(function (d) {
|
|
375
|
+
msg = d.result || '接入完成'; busy[source] = false; tick[1]()
|
|
376
|
+
}).catch(function (e) { err = e.message; busy[source] = false; tick[1]() })
|
|
377
|
+
}
|
|
378
|
+
function importAll() {
|
|
379
|
+
var md = sources.filter(function (s) { return s.kind !== 'sessions' && s.enabled !== false })
|
|
380
|
+
msg = '正在接入 ' + md.length + ' 个源…'; err = ''
|
|
381
|
+
var chain = Promise.resolve()
|
|
382
|
+
md.forEach(function (s) { chain = chain.then(function () { return apiPost(API.externalImport, { source: s.id, target: 'project' }) }) })
|
|
383
|
+
chain.then(function () { msg = '全部接入完成 ✓'; tick[1]() }).catch(function (e) { err = e.message; tick[1]() })
|
|
384
|
+
}
|
|
385
|
+
var cards = []
|
|
386
|
+
if (!sources.length) {
|
|
387
|
+
cards.push(h('div', { 'data-dam-muted': '' }, '未检测到其他 AI 工具的记忆文件(WorkBuddy/CodeBuddy/Claude Code/Codex)。'))
|
|
388
|
+
}
|
|
389
|
+
for (var i = 0; i < sources.length; i++) {
|
|
390
|
+
(function (s) {
|
|
391
|
+
var actions = []
|
|
392
|
+
if (s.kind === 'sessions') {
|
|
393
|
+
actions.push(h('span', { 'data-dam-hint': '' }, '会话源:共 ' + s.fileCount + ' 个会话文件,用 memory_recall 按需检索'))
|
|
394
|
+
} else {
|
|
395
|
+
actions.push(h('button', { 'data-dam-btn': '', disabled: !!busy[s.id], onClick: function () { doImport(s.id, 'project') } }, busy[s.id] ? '接入中…' : '接入项目笔记'))
|
|
396
|
+
actions.push(h('button', { 'data-dam-btn': '', disabled: !!busy[s.id], onClick: function () { doImport(s.id, 'user') } }, '接入用户记忆'))
|
|
397
|
+
}
|
|
398
|
+
cards.push(h(Card, { title: s.name + ' · ' + s.tool + (s.enabled === false ? ' · 已停用' : '') },
|
|
399
|
+
h('div', { 'data-dam-hint': '' }, s.kind + ' · ' + s.fileCount + ' 个文件 · ' + fmtSize(s.size)),
|
|
400
|
+
s.preview ? h('div', { 'data-dam-content': '' }, s.preview) : null,
|
|
401
|
+
h('div', { 'data-dam-row': '' }, actions)))
|
|
402
|
+
})(sources[i])
|
|
403
|
+
}
|
|
404
|
+
return h('div', null,
|
|
405
|
+
h('div', { 'data-dam-hint': '' }, '把其他 AI 工具(WorkBuddy / CodeBuddy / Claude Code / Codex / 项目约定文件)积累的记忆接入当前 DSH 工作。接入后内容写入本地记忆并自动标注来源,后续会随会话自动注入。'),
|
|
406
|
+
h('div', { 'data-dam-row': '' },
|
|
407
|
+
h('button', { 'data-dam-btn': '', onClick: importAll }, '一键接入全部'),
|
|
408
|
+
h('button', { 'data-dam-btn': '', onClick: load }, '重新扫描')),
|
|
409
|
+
msg ? h('div', null, msg) : null,
|
|
410
|
+
err ? h('div', { 'data-dam-error': '' }, err) : null,
|
|
411
|
+
cards)
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
// ───────────────────────── 拖动/缩放辅助 ─────────────────────────
|
|
415
|
+
var dragActive = false
|
|
416
|
+
function startPointerDrag(onMove, interactiveSel) {
|
|
417
|
+
return function (e) {
|
|
418
|
+
// 命中交互控件(按钮/输入框等)时不启动拖动
|
|
419
|
+
if (interactiveSel && e.target && e.target.closest && e.target.closest(interactiveSel)) return
|
|
420
|
+
e.preventDefault()
|
|
421
|
+
e.stopPropagation()
|
|
422
|
+
var startX = e.clientX
|
|
423
|
+
var startY = e.clientY
|
|
424
|
+
var moved = false
|
|
425
|
+
function move(ev) {
|
|
426
|
+
var dx = ev.clientX - startX
|
|
427
|
+
var dy = ev.clientY - startY
|
|
428
|
+
if (!moved && Math.abs(dx) < 2 && Math.abs(dy) < 2) return
|
|
429
|
+
moved = true
|
|
430
|
+
if (!dragActive) { dragActive = true; emit() }
|
|
431
|
+
onMove(dx, dy)
|
|
432
|
+
}
|
|
433
|
+
function up() {
|
|
434
|
+
window.removeEventListener('pointermove', move)
|
|
435
|
+
window.removeEventListener('pointerup', up)
|
|
436
|
+
if (dragActive) { dragActive = false; emit() }
|
|
437
|
+
controller.flushGeom()
|
|
438
|
+
}
|
|
439
|
+
window.addEventListener('pointermove', move)
|
|
440
|
+
window.addEventListener('pointerup', up)
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
function MemoryPanel() {
|
|
445
|
+
var tick = useTick()
|
|
446
|
+
var tab = 'overview'
|
|
447
|
+
var g = controller.geom()
|
|
448
|
+
useEffect(function () { return controller.subscribe(tick[1]) }, [])
|
|
449
|
+
if (!panelOpen && !panelClosing) return null
|
|
450
|
+
var body
|
|
451
|
+
if (tab === 'overview') body = h(OverviewTab)
|
|
452
|
+
else if (tab === 'logs') body = h(LogsTab)
|
|
453
|
+
else if (tab === 'notes') body = h(NotesTab)
|
|
454
|
+
else if (tab === 'reflections') body = h(ReflectionsTab)
|
|
455
|
+
else if (tab === 'connect') body = h(ConnectTab)
|
|
456
|
+
else body = h(SearchTab)
|
|
457
|
+
var tabs = [['overview', '概览'], ['logs', '日志'], ['notes', '笔记'], ['reflections', '反思'], ['connect', '接续'], ['search', '检索']]
|
|
458
|
+
var style = {
|
|
459
|
+
left: g.left + 'px',
|
|
460
|
+
top: g.top + 'px',
|
|
461
|
+
width: g.width + 'px',
|
|
462
|
+
height: g.height + 'px',
|
|
463
|
+
}
|
|
464
|
+
var dragMove = startPointerDrag(function (dx, dy) {
|
|
465
|
+
controller.setGeom({ left: g.left + dx, top: g.top + dy })
|
|
466
|
+
}, '[data-dam-btn], [data-dam-tab], [data-dam-input], [data-dam-select], textarea')
|
|
467
|
+
var resizeMove = startPointerDrag(function (dx, dy) {
|
|
468
|
+
controller.setGeom({ width: g.width + dx, height: g.height + dy })
|
|
469
|
+
})
|
|
470
|
+
return h('div', {
|
|
471
|
+
'data-dam-panel': '',
|
|
472
|
+
style: style,
|
|
473
|
+
'data-closing': panelClosing ? 'true' : undefined,
|
|
474
|
+
'data-dragging': dragActive ? 'true' : undefined,
|
|
475
|
+
},
|
|
476
|
+
h('header', {
|
|
477
|
+
title: '拖动移动',
|
|
478
|
+
onPointerDown: dragMove,
|
|
479
|
+
},
|
|
480
|
+
h('strong', null, '自动记忆'),
|
|
481
|
+
h('span', { className: 'dam-spacer' }),
|
|
482
|
+
h('button', { 'data-dam-btn': '', title: '恢复默认位置', onClick: function () { controller.resetGeom() } }, '⤾'),
|
|
483
|
+
h('button', { 'data-dam-btn': '', title: '刷新', onClick: function () { tick[1]() } }, '⟳'),
|
|
484
|
+
h('button', { 'data-dam-btn': '', title: '关闭', onClick: function () { controller.close() } }, '✕')),
|
|
485
|
+
h('div', { 'data-dam-tabs': '' }, tabs.map(function (t) {
|
|
486
|
+
return h('button', { key: t[0], 'data-dam-tab': '', 'data-active': tab === t[0] ? 'true' : undefined, onClick: function () { tab = t[0]; tick[1]() } }, t[1])
|
|
487
|
+
})),
|
|
488
|
+
h('div', { 'data-dam-body': '' }, body),
|
|
489
|
+
h('div', { 'data-dam-resize': '', title: '拖动调整大小', onPointerDown: resizeMove }))
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
// ───────────────────────── 设置页 ─────────────────────────
|
|
493
|
+
var STYLE_OPTIONS = [['auto', '由内容决定'], ['life', '生活化'], ['professional', '专业性']]
|
|
494
|
+
function SettingsPage() {
|
|
495
|
+
var tick = useTick()
|
|
496
|
+
var cfg = null
|
|
497
|
+
var busy = false
|
|
498
|
+
var msg = ''
|
|
499
|
+
var err = ''
|
|
500
|
+
useEffect(function () {
|
|
501
|
+
var alive = true
|
|
502
|
+
apiGet(API.config).then(function (d) { if (alive) { cfg = d.config; tick[1]() } }).catch(function (e) { err = e.message; tick[1]() })
|
|
503
|
+
return function () { alive = false }
|
|
504
|
+
}, [])
|
|
505
|
+
if (!cfg) return err ? h('div', { 'data-dam-error': '' }, err) : h(Loading)
|
|
506
|
+
function set(key, value) { cfg[key] = value; tick[1]() }
|
|
507
|
+
function save() {
|
|
508
|
+
if (busy) return
|
|
509
|
+
busy = true; msg = ''; err = ''
|
|
510
|
+
apiPost(API.config, cfg).then(function (d) { cfg = d.config; msg = '已保存 ✓'; busy = false; tick[1]() })
|
|
511
|
+
.catch(function (e) { err = e.message; busy = false; tick[1]() })
|
|
512
|
+
}
|
|
513
|
+
function field(label, control, hint) {
|
|
514
|
+
return h('div', null,
|
|
515
|
+
h('div', { 'data-dam-row': '' }, h('label', null, label), control),
|
|
516
|
+
hint ? h('div', { 'data-dam-hint': '' }, hint) : null)
|
|
517
|
+
}
|
|
518
|
+
return h('div', null,
|
|
519
|
+
h('div', { 'data-dam-hint': '' }, '记忆存储与行为设置(保存到 DSH 主目录 dsh-auto-memory.json):'),
|
|
520
|
+
field('用户记忆目录', h('input', { 'data-dam-input': '', value: cfg.userMemoryDir, onChange: function (e) { set('userMemoryDir', e.target.value) } }), '跨项目规则存放处,支持 ~ 开头;需有文件写权限。'),
|
|
521
|
+
field('项目记忆目录', h('input', { 'data-dam-input': '', value: cfg.projectMemoryDir, onChange: function (e) { set('projectMemoryDir', e.target.value) } }), '相对各工作区的目录名(默认 .dsh-memory)。'),
|
|
522
|
+
field('注入记忆上下文', h('input', { type: 'checkbox', checked: !!cfg.injectEnabled, onChange: function (e) { set('injectEnabled', e.target.checked) } }), '每次组装提示词时自动注入 <memory_system> 块。'),
|
|
523
|
+
field('注入预算(字符)', h('input', { 'data-dam-input': '', type: 'number', min: 400, value: cfg.injectBudgetChars, onChange: function (e) { set('injectBudgetChars', Number(e.target.value) || 2400) } }), '记忆块总预算,超出部分截断。'),
|
|
524
|
+
field('注入最近日志天数', h('input', { 'data-dam-input': '', type: 'number', min: 1, max: 14, value: cfg.recentDaysInjected, onChange: function (e) { set('recentDaysInjected', Number(e.target.value) || 3) } }), '会话开始时注入最近 N 天的工作日志尾部。'),
|
|
525
|
+
field('每日反思', h('input', { type: 'checkbox', checked: !!cfg.reflectEnabled, onChange: function (e) { set('reflectEnabled', e.target.checked) } }), '昨天有工作日志时,会话首轮主动呈现昨日反思。'),
|
|
526
|
+
field('反思风格', h('select', { 'data-dam-select': '', value: cfg.reflectStyle, onChange: function (e) { set('reflectStyle', e.target.value) } },
|
|
527
|
+
STYLE_OPTIONS.map(function (o) { return h('option', { key: o[0], value: o[0] }, o[1]) })), '生活化 / 专业性 / 由内容决定。'),
|
|
528
|
+
h('div', { 'data-dam-row': '' },
|
|
529
|
+
h('button', { 'data-dam-btn': '', onClick: save, disabled: busy }, busy ? '保存中…' : '保存设置'),
|
|
530
|
+
msg ? h('span', null, msg) : null),
|
|
531
|
+
err ? h('div', { 'data-dam-error': '' }, err) : null)
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
// ───────────────────────── 插件挂载 ─────────────────────────
|
|
535
|
+
function apply(ctx) {
|
|
536
|
+
try { ensureStyle() } catch (e) { console.warn('[dsh-auto-memory] style inject failed', e) }
|
|
537
|
+
ctx.effect(function () {
|
|
538
|
+
return function () {
|
|
539
|
+
var tag = document.getElementById(STYLE_ID)
|
|
540
|
+
if (tag) tag.remove()
|
|
541
|
+
if (closeTimer) { clearTimeout(closeTimer); closeTimer = null }
|
|
542
|
+
}
|
|
543
|
+
}, 'dsh-auto-memory: styles')
|
|
544
|
+
|
|
545
|
+
var slots = ctx.slots
|
|
546
|
+
if (!slots) { console.warn('[dsh-auto-memory] slots service unavailable'); return }
|
|
547
|
+
|
|
548
|
+
try {
|
|
549
|
+
slots.inject('sidebar.footer.action', function () {
|
|
550
|
+
return slots.register({ name: 'sidebar.footer.action', id: 'auto-memory', order: 5, label: '记忆' }, function () { return h(SidebarButton) })
|
|
551
|
+
})
|
|
552
|
+
slots.inject('shell.overlay', function () {
|
|
553
|
+
return slots.register({ name: 'shell.overlay', id: 'auto-memory', order: 5 }, function () { return h(MemoryPanel) })
|
|
554
|
+
})
|
|
555
|
+
slots.inject('settings.section', function () {
|
|
556
|
+
return slots.register({ name: 'settings.section', id: 'auto-memory', order: 25, label: '自动记忆' }, function (props) { return h(SettingsPage, { close: props && props.close }) })
|
|
557
|
+
})
|
|
558
|
+
} catch (e) {
|
|
559
|
+
console.warn('[dsh-auto-memory] slot registration failed', e)
|
|
560
|
+
}
|
|
561
|
+
console.log('[dsh-auto-memory] client ready: sidebar entry + panel + settings page')
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
exports.inject = ['slots']
|
|
565
|
+
exports.apply = apply
|
|
566
|
+
return module.exports
|
|
567
|
+
},
|
|
568
|
+
})
|
package/package.json
CHANGED
|
@@ -1,46 +1,46 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@a9i5k4/dsh-auto-memory",
|
|
3
|
-
"description": "DSH 自动记忆插件:三层记忆(用户级/项目笔记/每日日志)自动注入与检索、每轮对话自动沉淀、每日反思、可视化面板与设置页,支持继承其他 AI 工具的记忆。",
|
|
4
|
-
"version": "0.1.
|
|
5
|
-
"type": "module",
|
|
6
|
-
"main": "lib/index.js",
|
|
7
|
-
"exports": {
|
|
8
|
-
".": "./lib/index.js",
|
|
9
|
-
"./client": "./lib/client.js",
|
|
10
|
-
"./package.json": "./package.json"
|
|
11
|
-
},
|
|
12
|
-
"files": [
|
|
13
|
-
"lib",
|
|
14
|
-
"cordis.patch.yml"
|
|
15
|
-
],
|
|
16
|
-
"dsh": {
|
|
17
|
-
"bundle": {
|
|
18
|
-
"patch": "./cordis.patch.yml"
|
|
19
|
-
},
|
|
20
|
-
"client": {
|
|
21
|
-
"inject": [
|
|
22
|
-
"@deepseek-ai/dsh-client-runtime",
|
|
23
|
-
"@deepseek-ai/dsh-client-connection",
|
|
24
|
-
"@deepseek-ai/dsh-client-ui-slots",
|
|
25
|
-
"@deepseek-ai/dsh-client-ui-settings",
|
|
26
|
-
"@deepseek-ai/dsh-client-ui-sidebar"
|
|
27
|
-
],
|
|
28
|
-
"platform": "web"
|
|
29
|
-
}
|
|
30
|
-
},
|
|
31
|
-
"keywords": [
|
|
32
|
-
"dsh",
|
|
33
|
-
"deepseek-harness",
|
|
34
|
-
"memory",
|
|
35
|
-
"plugin",
|
|
36
|
-
"auto-memory"
|
|
37
|
-
],
|
|
38
|
-
"repository": {
|
|
39
|
-
"type": "git",
|
|
40
|
-
"url": "git+https://github.com/Aik358/dsh-auto-memory.git"
|
|
41
|
-
},
|
|
42
|
-
"peerDependencies": {
|
|
43
|
-
"@deepseek-ai/cordis": "^4.0.1"
|
|
44
|
-
},
|
|
45
|
-
"license": "BSD-3-Clause"
|
|
46
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "@a9i5k4/dsh-auto-memory",
|
|
3
|
+
"description": "DSH 自动记忆插件:三层记忆(用户级/项目笔记/每日日志)自动注入与检索、每轮对话自动沉淀、每日反思、可视化面板与设置页,支持继承其他 AI 工具的记忆。",
|
|
4
|
+
"version": "0.1.18",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "lib/index.js",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": "./lib/index.js",
|
|
9
|
+
"./client": "./lib/client.js",
|
|
10
|
+
"./package.json": "./package.json"
|
|
11
|
+
},
|
|
12
|
+
"files": [
|
|
13
|
+
"lib",
|
|
14
|
+
"cordis.patch.yml"
|
|
15
|
+
],
|
|
16
|
+
"dsh": {
|
|
17
|
+
"bundle": {
|
|
18
|
+
"patch": "./cordis.patch.yml"
|
|
19
|
+
},
|
|
20
|
+
"client": {
|
|
21
|
+
"inject": [
|
|
22
|
+
"@deepseek-ai/dsh-client-runtime",
|
|
23
|
+
"@deepseek-ai/dsh-client-connection",
|
|
24
|
+
"@deepseek-ai/dsh-client-ui-slots",
|
|
25
|
+
"@deepseek-ai/dsh-client-ui-settings",
|
|
26
|
+
"@deepseek-ai/dsh-client-ui-sidebar"
|
|
27
|
+
],
|
|
28
|
+
"platform": "web"
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
"keywords": [
|
|
32
|
+
"dsh",
|
|
33
|
+
"deepseek-harness",
|
|
34
|
+
"memory",
|
|
35
|
+
"plugin",
|
|
36
|
+
"auto-memory"
|
|
37
|
+
],
|
|
38
|
+
"repository": {
|
|
39
|
+
"type": "git",
|
|
40
|
+
"url": "git+https://github.com/Aik358/dsh-auto-memory.git"
|
|
41
|
+
},
|
|
42
|
+
"peerDependencies": {
|
|
43
|
+
"@deepseek-ai/cordis": "^4.0.1"
|
|
44
|
+
},
|
|
45
|
+
"license": "BSD-3-Clause"
|
|
46
|
+
}
|