@a9i5k4/dsh-auto-memory 0.1.3 → 0.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/client.js +6 -0
- package/lib/index.js +46 -7
- package/package.json +1 -1
package/lib/client.js
CHANGED
|
@@ -130,6 +130,7 @@ window.__ModuleLoader__.load({
|
|
|
130
130
|
connectHint: '把其他 AI 工具(CodeBuddy / Claude Code / Codex / 项目约定文件等)积累的记忆接入当前 DSH 工作。接入后内容写入本地记忆并自动标注来源,后续会随会话自动注入。',
|
|
131
131
|
importAll: '一键接入全部', rescan: '重新扫描',
|
|
132
132
|
styleAuto: '由内容决定', styleLife: '生活化', styleProfessional: '专业性',
|
|
133
|
+
todayGreetingTitle: '今日问候',
|
|
133
134
|
saved: '已保存',
|
|
134
135
|
settingsHeader: '记忆存储与行为设置(保存到 DSH 主目录 dsh-auto-memory.json):',
|
|
135
136
|
fUserDir: '用户记忆目录', fUserDirHint: '跨项目规则存放处,支持 ~ 开头;需有文件写权限。',
|
|
@@ -181,6 +182,7 @@ window.__ModuleLoader__.load({
|
|
|
181
182
|
connectHint: 'Import memories accumulated by other AI tools (CodeBuddy / Claude Code / Codex / project convention files) into the current DSH workspace. Imported content is written to local memory with its source noted, and is auto-injected in future sessions.',
|
|
182
183
|
importAll: 'Import all', rescan: 'Rescan',
|
|
183
184
|
styleAuto: 'Auto', styleLife: 'Life-style', styleProfessional: 'Professional',
|
|
185
|
+
todayGreetingTitle: 'Today\'s Greeting',
|
|
184
186
|
saved: 'Saved',
|
|
185
187
|
settingsHeader: 'Memory storage & behavior (saved to ~/.dsh/dsh-auto-memory.json):',
|
|
186
188
|
fUserDir: 'User memory dir', fUserDirHint: 'Cross-project rules; supports ~ prefix; needs write permission.',
|
|
@@ -360,6 +362,10 @@ window.__ModuleLoader__.load({
|
|
|
360
362
|
}).catch(function (e) { setActMsg(t('failed') + e.message); setReflectBusy(false) })
|
|
361
363
|
}
|
|
362
364
|
return h('div', null,
|
|
365
|
+
// 今日拟人化问候(每天首次生成后常驻显示)
|
|
366
|
+
state.todayGreeting
|
|
367
|
+
? h(Card, { title: t('todayGreetingTitle') }, h('div', { 'data-dam-content': '' }, state.todayGreeting))
|
|
368
|
+
: null,
|
|
363
369
|
state.pendingReflection
|
|
364
370
|
? h(Banner, null, t('pendingReflection') + state.pendingReflection + t('pendingReflectionHint'))
|
|
365
371
|
: null,
|
package/lib/index.js
CHANGED
|
@@ -106,6 +106,7 @@ class MemoryEngine {
|
|
|
106
106
|
latestReflection: '', latestReflectionDate: '',
|
|
107
107
|
pendingReflection: undefined, // {date, text}
|
|
108
108
|
reflectionShownSession: undefined,
|
|
109
|
+
todayGreeting: '', greetingShownSession: undefined,
|
|
109
110
|
loadedAt: 0, loading: undefined, configLoaded: false,
|
|
110
111
|
}
|
|
111
112
|
this._configPath = path.join(dshHome(), 'dsh-auto-memory.json')
|
|
@@ -168,6 +169,8 @@ class MemoryEngine {
|
|
|
168
169
|
notesPath: path.join(projectDir, 'MEMORY.md'),
|
|
169
170
|
logPath: path.join(projectDir, `${todayStr()}.md`),
|
|
170
171
|
reflectDir: path.join(projectDir, 'reflections'),
|
|
172
|
+
greetDir: path.join(projectDir, 'greetings'),
|
|
173
|
+
greetPath: path.join(projectDir, 'greetings', `${todayStr()}.md`),
|
|
171
174
|
}
|
|
172
175
|
}
|
|
173
176
|
|
|
@@ -275,6 +278,8 @@ class MemoryEngine {
|
|
|
275
278
|
const pending = await this.detectPendingReflection(p.projectDir, p.reflectDir)
|
|
276
279
|
if (pending) this.state.pendingReflection = pending
|
|
277
280
|
}
|
|
281
|
+
// 今日拟人化问候(每天首会话展示一次)
|
|
282
|
+
this.state.todayGreeting = await this.readTextSafe(p.greetPath)
|
|
278
283
|
// 外部记忆探测(后台,结果进缓存)
|
|
279
284
|
if (this.config.externalSources) void this.external.discover(true)
|
|
280
285
|
this.state.loadedAt = Date.now()
|
|
@@ -324,10 +329,11 @@ class MemoryEngine {
|
|
|
324
329
|
}
|
|
325
330
|
lines.push('\n[记忆写入纪律 — 必须遵守]')
|
|
326
331
|
lines.push('- 会话开始:若任务与历史工作/历史决策相关,先回顾以上记忆;**遇到不熟悉的代码、领域或项目时,主动调用 memory_recall 检索本机所有 AI 工具的历史记忆(CodeBuddy/Claude Code/Codex 等会话),不要凭空猜测**。')
|
|
327
|
-
lines.push('- 新工作区(无历史日志/笔记):主动用 memory_recall 探索本机历史,判断该项目是否曾在其他 AI 工具中工作过;也可调用 memory_external
|
|
332
|
+
lines.push('- 新工作区(无历史日志/笔记):主动用 memory_recall 探索本机历史,判断该项目是否曾在其他 AI 工具中工作过;也可调用 memory_external 查看并接入外部记忆;检索时在正文中说明"我先查一下之前的记录"。')
|
|
328
333
|
lines.push('- 完成实质性工作后立即调用 memory_log 追加今日日志(append-only,绝不覆盖):建/改应用、修 bug、写文档、重构、技术选型、用户约定或偏好。')
|
|
329
334
|
lines.push('- progress 与 memory 一起写:写日志的同时,把有跨会话长期价值的内容一并写入记忆——跨项目规则 → memory_user,仅本项目 → memory_note;两者在同一轮完成,互不冲突、不遗漏。')
|
|
330
335
|
lines.push('- 只记录有跨会话长期价值的;不记临时信息(搜索结果、临时路径、工具报错)。')
|
|
336
|
+
lines.push('- **记忆操作对用户可见**:调用 memory_log/note/user/reflect 更新记忆时,在同一轮回复的正文中(非工具调用内部)用一句话向用户明文说明——"正在更新哪份文档、加入什么内容";调用 memory_recall/memory_external 检索时,也在正文中说明检索了什么、找到了什么,让用户直观看到记忆在工作。')
|
|
331
337
|
lines.push('- 用户明确要求长期记住:跨项目规则 → memory_user;仅本项目 → memory_note。')
|
|
332
338
|
lines.push('- 定期调用 memory_maintain 归档 30 天前日志;不存密钥,除非用户明确要求。')
|
|
333
339
|
lines.push('- 记忆仅作补充,不替代正常回复与交付物。')
|
|
@@ -357,6 +363,26 @@ class MemoryEngine {
|
|
|
357
363
|
].join('\n')
|
|
358
364
|
}
|
|
359
365
|
|
|
366
|
+
/** 拟人化问候请求块:每天首次会话注入一次(用户一打开就能看到)。 */
|
|
367
|
+
renderGreetingRequest() {
|
|
368
|
+
if (this.state.todayGreeting) return ''
|
|
369
|
+
if (this.state.greetingShownSession === todayStr()) return ''
|
|
370
|
+
this.state.greetingShownSession = todayStr()
|
|
371
|
+
const lines = this.state.recentLogs[0] ? this.state.recentLogs[0].text : ''
|
|
372
|
+
const hour = new Date().getHours()
|
|
373
|
+
const period = hour < 6 ? '凌晨' : hour < 9 ? '早上好' : hour < 12 ? '上午好' : hour < 14 ? '中午好' : hour < 18 ? '下午好' : hour < 22 ? '晚上好' : '夜深了'
|
|
374
|
+
return [
|
|
375
|
+
'\n\n[晨间问候 — 拟人化,请生成]',
|
|
376
|
+
'请以' + period + '的拟人化口吻,在本轮回复开头向用户说一段简短温暖的问候(2-4 句,像朋友聊天,不要列条框、不要用"反思"字样)。内容应自然融合:',
|
|
377
|
+
'- 昨天/最近的经历:根据以下工作回顾,自然提起"昨天你做了..."(挑 1-2 件最值得说的,轻描淡写即可)',
|
|
378
|
+
lines ? '昨天回顾:\n' + lines : '(暂无昨日日志)',
|
|
379
|
+
'- 善意提醒:如果从回顾里看出可能遗漏的事(未完成的计划、埋的坑、待办),轻轻提醒一句;没有就不提。',
|
|
380
|
+
'- 日常关心:可以自然地带一句时间/作息/状态相关的关心(如"记得吃早饭""别熬太晚"),如果有用户习惯(从记忆里看)就贴合习惯。',
|
|
381
|
+
'- 语气:温暖、自然、像朋友,不要官方、不要严肃、不要长篇大论。',
|
|
382
|
+
'生成后调用 memory_greet(date="' + todayStr() + '", text=完整问候内容)保存,之后今天不再提示。',
|
|
383
|
+
].join('\n')
|
|
384
|
+
}
|
|
385
|
+
|
|
360
386
|
// ---------- 写操作 ----------
|
|
361
387
|
async appendText(p, text) {
|
|
362
388
|
const existing = await this.readTextSafe(p)
|
|
@@ -432,8 +458,8 @@ class MemoryEngine {
|
|
|
432
458
|
}
|
|
433
459
|
}
|
|
434
460
|
} catch (e) {}
|
|
435
|
-
if (!out.length) return '
|
|
436
|
-
return out.join('\n')
|
|
461
|
+
if (!out.length) return '[记忆检索] 查询 "' + q + '" —— 未找到相关记忆。'
|
|
462
|
+
return '[记忆检索] "' + q + '":\n' + out.join('\n')
|
|
437
463
|
}
|
|
438
464
|
|
|
439
465
|
// ---------- 反思 ----------
|
|
@@ -533,6 +559,7 @@ class MemoryEngine {
|
|
|
533
559
|
todayEntries,
|
|
534
560
|
latestReflectionDate: this.state.latestReflectionDate,
|
|
535
561
|
pendingReflection: this.state.pendingReflection ? this.state.pendingReflection.date : undefined,
|
|
562
|
+
todayGreeting: this.state.todayGreeting,
|
|
536
563
|
refreshedAt: this.state.loadedAt,
|
|
537
564
|
configReadError: this._readError,
|
|
538
565
|
}
|
|
@@ -907,7 +934,7 @@ export function apply(ctx, config) {
|
|
|
907
934
|
if (!engine.state.loadedAt || Date.now() - engine.state.loadedAt > 60000) {
|
|
908
935
|
void engine.refresh(agent)
|
|
909
936
|
}
|
|
910
|
-
return engine.renderMemory(context) + engine.renderReflectionRequest()
|
|
937
|
+
return engine.renderMemory(context) + engine.renderReflectionRequest() + engine.renderGreetingRequest()
|
|
911
938
|
} catch (e) { return '' }
|
|
912
939
|
},
|
|
913
940
|
})
|
|
@@ -924,7 +951,7 @@ export function apply(ctx, config) {
|
|
|
924
951
|
const entry = '- ' + nowHm() + ' ' + String(args.note).trim()
|
|
925
952
|
const body = await engine.appendText(logPath, entry)
|
|
926
953
|
if (date === todayStr()) { engine.state.logText = body; engine.state.logPath = logPath; engine.state.loadedAt = Date.now() }
|
|
927
|
-
return '
|
|
954
|
+
return '已更新记忆文档: ' + logPath + '\n' + entry
|
|
928
955
|
}),
|
|
929
956
|
|
|
930
957
|
defineTool('memory_note', '更新当前项目长期笔记 .dsh-memory/MEMORY.md(本项目专属的约定、决策、架构要点)。action=append 追加一段(自动带日期标题);action=replace 整体替换(需先基于注入内容或 memory_recall 结果给出完整新内容)。', {
|
|
@@ -942,7 +969,7 @@ export function apply(ctx, config) {
|
|
|
942
969
|
body = await engine.appendText(p.notesPath, '\n## ' + todayStr() + '\n' + content)
|
|
943
970
|
}
|
|
944
971
|
engine.state.notesText = body; engine.state.loadedAt = Date.now()
|
|
945
|
-
return '
|
|
972
|
+
return '已更新项目笔记: ' + p.notesPath + '\n追加内容:\n' + content
|
|
946
973
|
}),
|
|
947
974
|
|
|
948
975
|
defineTool('memory_user', '更新用户级记忆 ~/.dsh/memory/MEMORY.md(跨所有项目的长期规则/偏好,用户明确要求记住时用)。action=append 追加;action=replace 整体替换。', {
|
|
@@ -960,7 +987,7 @@ export function apply(ctx, config) {
|
|
|
960
987
|
body = await engine.appendText(p.userFile, '\n## ' + todayStr() + '\n' + content)
|
|
961
988
|
}
|
|
962
989
|
engine.state.userText = body; engine.state.loadedAt = Date.now()
|
|
963
|
-
return '
|
|
990
|
+
return '已更新用户级记忆: ' + p.userFile + '\n追加内容:\n' + content
|
|
964
991
|
}),
|
|
965
992
|
|
|
966
993
|
defineTool('memory_recall', '检索记忆:本地记忆文件(每日日志、项目笔记、用户级记忆、反思)关键词匹配 + 历史 DSH 会话全文检索(如部署启用)。用户提到过去的做法/讨论/决定而当前上下文没有时调用,查询必须自包含。', {
|
|
@@ -989,6 +1016,18 @@ export function apply(ctx, config) {
|
|
|
989
1016
|
text: { type: 'string', required: true, description: '完整反思内容:成果回顾 / 教训改进 / 今日可延续要点。' },
|
|
990
1017
|
}, async (args, exec) => engine.saveReflection(args.date, args.text, exec.agent)),
|
|
991
1018
|
|
|
1019
|
+
defineTool('memory_greet', '保存今日拟人化晨间问候到 .dsh-memory/greetings/YYYY-MM-DD.md(每天首次会话收到「晨间问候」提示后调用)。问候内容为面向用户的拟人化短句(温暖自然、朋友口吻),不要写反思类结构化内容。', {
|
|
1020
|
+
date: { type: 'string', required: true, description: '问候日期 YYYY-MM-DD。' },
|
|
1021
|
+
text: { type: 'string', required: true, description: '完整问候内容。' },
|
|
1022
|
+
}, async (args, exec) => {
|
|
1023
|
+
const date = DATE_RE.test(args.date || '') ? args.date : todayStr()
|
|
1024
|
+
const p = await engine.resolvePaths(exec.agent)
|
|
1025
|
+
const file = path.join(p.greetDir, date + '.md')
|
|
1026
|
+
await engine.writeFull(file, args.text + '\n')
|
|
1027
|
+
if (date === todayStr()) { engine.state.todayGreeting = String(args.text).trim(); engine.state.loadedAt = Date.now() }
|
|
1028
|
+
return '已保存晨间问候 ' + file + '\n' + String(args.text).trim()
|
|
1029
|
+
}),
|
|
1030
|
+
|
|
992
1031
|
defineTool('memory_external', '查看/接入其他 AI 工具(CodeBuddy/Claude Code/Codex/项目约定文件等)的记忆。action=list 列出全部检测到的外部记忆源(路径/大小/预览/会话数);action=import 把某源内容整体接入本地记忆(source 为源 id,target=project 接进项目笔记 / user 接进用户级记忆,自动标注来源)。首次在新工作区工作、或用户提到其他软件里做过的事时调用。', {
|
|
993
1032
|
action: { type: 'string', enum: ['list', 'import'], required: true, description: 'list=列出外部记忆源; import=接入指定源。' },
|
|
994
1033
|
source: { type: 'string', description: '要接入的源 id(action=import 时必填,来自 list 结果)。' },
|