@a9i5k4/dsh-auto-memory 0.1.6 → 0.1.7

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 CHANGED
@@ -1,8 +1,8 @@
1
1
  # dsh-auto-memory — DSH Auto Memory Plugin / DSH 自动记忆插件
2
2
 
3
- An auto-memory plugin for the DeepSeek Harness Web GUI: three-layer memory (user-level / project notes / daily logs) with automatic injection and retrieval, daily reflections, a visual panel and settings page, and inheritance of memories from other AI tools.
3
+ An auto-memory plugin for the DeepSeek Harness Web GUI: three-layer memory (user-level / project notes / daily logs) with automatic injection and retrieval, daily reflections, smart period greetings, a calendar view and settings page, and inheritance of memories from other AI tools.
4
4
 
5
- DSH Web GUI 的记忆插件:三层记忆(用户级 / 项目笔记 / 每日日志)自动注入与检索、每日反思、可视化面板与设置页,支持继承其他 AI 工具的历史记忆。
5
+ DSH Web GUI 的记忆插件:三层记忆自动注入与检索、每日反思、智能时段问候、日历视图与设置页,支持继承其他 AI 工具的历史记忆。
6
6
 
7
7
  [**English**](README.md) | [中文版](README.zh-CN.md)
8
8
 
@@ -10,18 +10,45 @@ DSH Web GUI 的记忆插件:三层记忆(用户级 / 项目笔记 / 每日
10
10
 
11
11
  ## Features
12
12
 
13
+ ### Three-layer Memory
14
+
13
15
  | Layer | Location | Description |
14
16
  |---|---|---|
15
17
  | User-level memory | `~/.dsh/memory/MEMORY.md` | Cross-project rules & preferences |
16
18
  | Project notes | `{workspace}/.dsh-memory/MEMORY.md` | Project conventions & decisions |
17
19
  | Daily logs | `{workspace}/.dsh-memory/YYYY-MM-DD.md` | Append-only work log |
18
- | Reflections | `{workspace}/.dsh-memory/reflections/YYYY-MM-DD.md` | Daily reflection, auto-prompted |
20
+ | Reflections | `{workspace}/.dsh-memory/reflections/YYYY-MM-DD.md` | Daily reflection (structured, kept in background) |
21
+
22
+ - **Auto injection**: injects a `<memory_system>` block into every system prompt (user rules + project notes + recent reflections + recent N days of log tails + pending calendar items + writing discipline)
23
+ - **Visible memory ops**: when the AI updates or searches memory, it says so in plain text in the chat reply (e.g. "Logged X to today's journal", "I checked memory and found..."), not hidden inside tool calls
24
+
25
+ ### Smart Period Greetings (Overview page)
26
+
27
+ The first thing you see when opening the memory panel is a friendly period greeting, not technical info:
28
+
29
+ - **Multiple times a day**: morning shows "yesterday summary + early morning", forenoon shows the morning's work, noon/afternoon/evening follow suit
30
+ - **Smart timing**: if you were away for more than 1 hour (off work / stepped away) and come back, it automatically shows "Welcome back" with what was finished meanwhile
31
+ - **Drawer layout**: the outer layer stays casual and greeting-like; each period is a drawer — tap to expand the professional details
32
+ - **Daily reflection stays in background**: structured reflections (results / lessons / next steps) are kept, while the front page only shows a light greeting
33
+
34
+ ### Calendar View (Four Quadrants)
35
+
36
+ New 「Calendar」tab (liquid-glass monthly view):
37
+
38
+ - Monthly grid, today highlighted, click any date to add an item
39
+ - **Four-quadrant colors**: Urgent & Important (red) / Important (blue) / Urgent (orange) / Neither (gray)
40
+ - Click an item to toggle done, click again to delete; legend + weekday header
41
+ - **Cross-conversation persistence**: data lives at user level `~/.dsh/memory/CALENDAR.md`, shared across workspaces, survives DSH reinstall
42
+ - **AI-maintained**: the AI extracts deadlines and appointments from conversations and writes them to the calendar automatically (`calendar_add` / `calendar_list` / `calendar_done` / `calendar_remove`), restating it in plain text; pending items are injected into every session's system prompt
43
+
44
+ ### Agent Tools
45
+
46
+ `memory_log` / `memory_note` / `memory_user` / `memory_recall` / `memory_external` / `memory_maintain` / `memory_status` / `memory_reflect` / `calendar_add` / `calendar_list` / `calendar_done` / `calendar_remove`
47
+
48
+ ### UI
19
49
 
20
- - **Auto injection**: injects a `<memory_system>` block into every system prompt (user rules + project notes + recent reflections + recent N days of log tails + writing discipline)
21
- - **Daily reflection**: when yesterday has logs but no reflection, the agent presents one at session start
22
- - **Agent tools**: `memory_log` / `memory_note` / `memory_user` / `memory_recall` / `memory_external` / `memory_maintain` / `memory_status` / `memory_reflect`
23
- - **GUI**: sidebar 「Memory」entry → floating panel (Overview / Logs / Notes / Reflections / Connect / Search); Settings page (Settings → Auto Memory)
24
- - **UI language**: switch between 中文 / English in Settings → Auto Memory → UI language
50
+ - Sidebar 「Memory」entry floating panel (Overview / Logs / Notes / Reflections / Connect / Calendar / Search)
51
+ - Settings page (Settings Auto Memory): storage paths, injection budget, reflection style, **UI language (中文 / English)**
25
52
  - **External memory inheritance**: import memories accumulated by other AI tools (CodeBuddy / Claude Code / Codex / project convention files)
26
53
 
27
54
  ---
@@ -86,7 +113,7 @@ Adjustable in the GUI (Settings → Auto Memory), including the UI language (zh
86
113
  ## Structure
87
114
 
88
115
  - `lib/index.js` — Host half: engine, injection, tools, routes (zero runtime deps, Node built-ins only)
89
- - `lib/client.js` — Browser half: memory panel + settings page (built-in zh/en i18n)
116
+ - `lib/client.js` — Browser half: memory panel (with calendar view) + settings page (built-in zh/en i18n)
90
117
  - `cordis.patch.yml` — Plugin row (`auto-memory`)
91
118
 
92
119
  ---
package/README.zh-CN.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # dsh-auto-memory — DSH 自动记忆插件
2
2
 
3
- DSH Web GUI 的记忆插件:三层记忆(用户级 / 项目笔记 / 每日日志)自动注入与检索、每日反思、可视化面板与设置页,支持继承其他 AI 工具的历史记忆。
3
+ DSH Web GUI 的记忆插件:三层记忆(用户级 / 项目笔记 / 每日日志)自动注入与检索、每日反思、智能时段问候、日历视图与设置页,支持继承其他 AI 工具的历史记忆。
4
4
 
5
5
  [English](README.md) | [中文版](README.zh-CN.md)
6
6
 
@@ -8,18 +8,45 @@ DSH Web GUI 的记忆插件:三层记忆(用户级 / 项目笔记 / 每日
8
8
 
9
9
  ## 功能
10
10
 
11
+ ### 三层记忆
12
+
11
13
  | 层 | 位置 | 说明 |
12
14
  |---|---|---|
13
15
  | 用户级记忆 | `~/.dsh/memory/MEMORY.md` | 跨项目规则/偏好(用户明确要求时写) |
14
16
  | 项目笔记 | `{工作区}/.dsh-memory/MEMORY.md` | 项目长期约定、决策、架构要点 |
15
17
  | 每日日志 | `{工作区}/.dsh-memory/YYYY-MM-DD.md` | append-only 工作日志 |
16
- | 反思 | `{工作区}/.dsh-memory/reflections/YYYY-MM-DD.md` | 每日反思(自动提示生成) |
18
+ | 反思 | `{工作区}/.dsh-memory/reflections/YYYY-MM-DD.md` | 每日反思(后台结构化积累) |
19
+
20
+ - **自动注入**:每次组装系统提示词时注入 `<memory_system>` 块(用户规则 + 项目笔记 + 最近反思 + 最近 N 天日志尾部 + 未完成日历事项 + 写入纪律)
21
+ - **记忆操作可见**:更新/检索记忆时,AI 会在对话正文中明文说明(如"已把 X 记入今日日志""我查了记忆,发现…"),不藏在工具调用里
22
+
23
+ ### 智能时段问候(概览页)
24
+
25
+ 打开记忆面板第一眼看到的是生活化的时段问候,而不是严肃的技术信息:
26
+
27
+ - **一天多次**:早晨显示"昨天摘要 + 今天早晨"、上午显示上午的工作、中午/下午/晚上依次类推
28
+ - **智能时机**:离开超过 1 小时(下班/暂离)再打开,自动显示"欢迎回来"并列出期间的完成事项
29
+ - **抽屉式展开**:外层保持生活化问候风格;每个时段做成抽屉,点开才显示专业的工作明细
30
+ - **每日反思**:后台保留结构化反思(成果/教训/要点),前台只有轻松问候
31
+
32
+ ### 日历视图(四象限)
33
+
34
+ 新增「日历」页签(液态玻璃风格月视图):
35
+
36
+ - 月视图网格,今日高亮,点击任意日期添加事项
37
+ - **四象限色标**:重要紧急(红)/ 重要不紧急(蓝)/ 紧急不重要(橙)/ 不重要不紧急(灰)
38
+ - 点条目切换完成状态,再点删除;图例 + 星期头
39
+ - **跨对话持久**:数据存用户级 `~/.dsh/memory/CALENDAR.md`,所有工作区共享,重装 DSH 不丢
40
+ - **AI 主动维护**:AI 会从对话中提取 deadline、约定时间等自动写入日历(`calendar_add` / `calendar_list` / `calendar_done` / `calendar_remove`),并在正文转述;未完成事项注入每次会话的系统提示词
41
+
42
+ ### Agent 工具
43
+
44
+ `memory_log` / `memory_note` / `memory_user` / `memory_recall` / `memory_external` / `memory_maintain` / `memory_status` / `memory_reflect` / `calendar_add` / `calendar_list` / `calendar_done` / `calendar_remove`
45
+
46
+ ### 界面
17
47
 
18
- - **自动注入**:每次组装系统提示词时注入 `<memory_system>` 块(用户规则 + 项目笔记 + 最近反思 + 最近 N 天日志尾部 + 写入纪律)
19
- - **每日反思**:检测到"昨天有日志但未生成反思"时,会话首轮自动请求 agent 生成昨日反思
20
- - **Agent 工具**:`memory_log` / `memory_note` / `memory_user` / `memory_recall` / `memory_external` / `memory_maintain` / `memory_status` / `memory_reflect`
21
- - **GUI**:侧边栏「记忆」入口 → 浮层面板(概览/日志/笔记/反思/接续/检索);设置页(设置 → 自动记忆)
22
- - **界面语言**:中文 / English 可切换(设置 → 自动记忆 → 界面语言)
48
+ - 侧边栏「记忆」入口 浮层面板(概览/日志/笔记/反思/接续/日历/检索)
49
+ - 设置页(设置 自动记忆):存储位置、注入预算、反思风格、**界面语言(中文 / English)**
23
50
  - **外部记忆继承**:接入其他 AI 工具(CodeBuddy / Claude Code / Codex / 项目约定文件)积累的记忆
24
51
 
25
52
  ---
@@ -84,7 +111,7 @@ pnpm add @a9i5k4/dsh-auto-memory
84
111
  ## 结构
85
112
 
86
113
  - `lib/index.js` — Host 半:引擎、注入、工具、路由(零运行时依赖,仅 node 内置模块)
87
- - `lib/client.js` — 浏览器半:记忆面板 + 设置页(内置中英双语)
114
+ - `lib/client.js` — 浏览器半:记忆面板(含日历视图)+ 设置页(内置中英双语)
88
115
  - `cordis.patch.yml` — 插件行(`auto-memory`)
89
116
 
90
117
  ---
package/lib/client.js CHANGED
@@ -148,6 +148,9 @@ window.__ModuleLoader__.load({
148
148
  segMorning: '早晨', segForenoon: '上午', segNoon: '中午', segAfternoon: '下午', segEvening: '晚上',
149
149
  segPrefix: '今日', segMorningHint: '(昨日摘要)',
150
150
  welcomeBack: '欢迎回来!这段时间你完成了这些工作:',
151
+ yesterdayDrawer: '昨天',
152
+ greetMorning: '新的一天开始啦,先看看昨天做了什么。', greetForenoon: '上午好,今天也在稳步推进。', greetNoon: '中午好,歇口气再继续。', greetAfternoon: '下午好,下午也要元气满满。', greetEvening: '晚上好,辛苦一天了。',
153
+ greetSummary: '今天已经完成了 ', greetThings: ' 件工作,点开看看:',
151
154
  qUrgentImportant: '重要紧急', qImportant: '重要不紧急', qUrgent: '紧急不重要', qNone: '不重要不紧急', qUncategorized: '未分类',
152
155
  },
153
156
  en: {
@@ -206,6 +209,9 @@ window.__ModuleLoader__.load({
206
209
  segMorning: 'Morning', segForenoon: 'Forenoon', segNoon: 'Noon', segAfternoon: 'Afternoon', segEvening: 'Evening',
207
210
  segPrefix: 'Today ', segMorningHint: ' (yesterday summary)',
208
211
  welcomeBack: 'Welcome back! While you were away, you finished:',
212
+ yesterdayDrawer: 'Yesterday',
213
+ greetMorning: 'A fresh day! Let us look back at yesterday first.', greetForenoon: 'Good morning, steady progress today.', greetNoon: 'Good noon, take a break and keep going.', greetAfternoon: 'Good afternoon, keep up the good energy.', greetEvening: 'Good evening, well done today.',
214
+ greetSummary: 'You have completed ', greetThings: ' things today. Tap to expand:',
209
215
  qUrgentImportant: 'Urgent & Important', qImportant: 'Important', qUrgent: 'Urgent', qNone: 'Neither', qUncategorized: 'Uncategorized',
210
216
  }
211
217
  }
@@ -350,59 +356,74 @@ window.__ModuleLoader__.load({
350
356
  var g = props.greeting
351
357
  var ps = props.periodSummary
352
358
  if (!g) return null
359
+ var openPair = useState({})
360
+ var openMap = openPair[0]
361
+ var setOpenMap = openPair[1]
353
362
  // 智能时段判定
354
363
  var hour = new Date().getHours()
355
364
  var seg = hour < 9 ? 'morning' : hour < 12 ? 'forenoon' : hour < 14 ? 'noon' : hour < 18 ? 'afternoon' : 'evening'
356
365
  var segLabel = { morning: t('segMorning'), forenoon: t('segForenoon'), noon: t('segNoon'), afternoon: t('segAfternoon'), evening: t('segEvening') }[seg]
357
- var title = (g.period || '') + ' · ' + segLabel
358
- var rows = []
359
- // 离开>1小时后回来 欢迎回来提示
360
- var lastSeen = 0
361
- try { lastSeen = Number(localStorage.getItem('dsh-auto-memory.lastActive') || 0) } catch (e) {}
362
- var now = Date.now()
363
- var away = lastSeen > 0 && (now - lastSeen) > 3600000
364
- if (away) {
365
- rows.push(h('div', { 'data-dam-content': '' }, t('welcomeBack')))
366
+ // 收集抽屉: {key, label, hint, items, withTime}
367
+ var drawers = []
368
+ var curSegName = { morning: '早晨', forenoon: '上午', noon: '中午', afternoon: '下午', evening: '晚上' }[seg]
369
+ // 昨天抽屉(早晨显示)
370
+ if (seg === 'morning' && g.entries.length) {
371
+ drawers.push({ key: 'yesterday', label: t('yesterdayDrawer') + (g.yesterdayDate || ''), hint: '', items: g.entries, withTime: true, defaultOpen: true })
366
372
  }
367
- // 时段摘要(今天该时段之前的工作)
368
- if (ps && ps.entries && ps.entries.length) {
369
- var seen = { '凌晨': true, '早晨': seg === 'morning' ? false : true, '上午': (seg === 'forenoon' || seg === 'noon' || seg === 'afternoon' || seg === 'evening'), '中午': (seg === 'noon' || seg === 'afternoon' || seg === 'evening'), '下午': (seg === 'afternoon' || seg === 'evening'), '晚上': seg === 'evening' }
370
- var segRows = []
371
- var segOrder = ['早晨', '上午', '中午', '下午', '晚上']
372
- for (var si = 0; si < segOrder.length; si++) {
373
- var sname = segOrder[si]
374
- if (!seen[sname]) continue
375
- var items = (ps.groups && ps.groups[sname]) || []
376
- if (!items.length) continue
377
- if (segRows.length) segRows.push(h('div', { 'data-dam-hint': '' }, ''))
378
- segRows.push(h('div', { 'data-dam-hint': '' }, t('segPrefix') + sname + (sname === '早晨' ? t('segMorningHint') : '') + ':'))
379
- for (var ii = 0; ii < items.length; ii++) {
380
- (function (txt) {
381
- segRows.push(h('div', { 'data-dam-row': '', style: { marginBottom: '3px', alignItems: 'flex-start' } },
382
- h('span', { 'data-dam-muted': '', style: { flex: '0 0 10px', marginTop: '2px' } }, '·'),
383
- h('span', { style: { flex: '1', wordBreak: 'break-word' } }, txt)))
384
- })(items[ii])
385
- }
386
- }
387
- if (segRows.length) rows.push(h('div', null, segRows))
373
+ // 今天各时段抽屉(已过的时段)
374
+ var seenSeg = { '早晨': seg !== 'morning', '上午': (seg === 'forenoon' || seg === 'noon' || seg === 'afternoon' || seg === 'evening'), '中午': (seg === 'noon' || seg === 'afternoon' || seg === 'evening'), '下午': (seg === 'afternoon' || seg === 'evening'), '晚上': seg === 'evening' }
375
+ var segOrder = ['早晨', '上午', '中午', '下午', '晚上']
376
+ for (var si = 0; si < segOrder.length; si++) {
377
+ var sname = segOrder[si]
378
+ if (!seenSeg[sname]) continue
379
+ var items = (ps && ps.groups && ps.groups[sname]) || []
380
+ if (!items.length) continue
381
+ drawers.push({ key: 'seg-' + sname, label: t('segPrefix') + sname, hint: '', items: items.map(function (x) { return { time: '', text: x } }), withTime: false, defaultOpen: sname === curSegName })
388
382
  }
389
- // 昨天时间轴(早晨时段显示昨天摘要)
390
- if (seg === 'morning' && g.entries.length) {
391
- rows.push(h('div', { 'data-dam-hint': '' }, t('yesterdayTimeline') + (g.yesterdayDate || '') + ')'))
392
- for (var i = 0; i < g.entries.length; i++) {
393
- (function (en) {
394
- rows.push(h('div', { 'data-dam-row': '', style: { marginBottom: '4px', alignItems: 'flex-start' } },
395
- h('span', { 'data-dam-muted': '', style: { flex: '0 0 44px', fontFamily: 'monospace', fontSize: '11.5px', marginTop: '2px' } }, en.time),
396
- h('span', { style: { flex: '1', wordBreak: 'break-word' } }, en.text)))
397
- })(g.entries[i])
398
- }
383
+ // 外层:生活化问候
384
+ var totalCount = 0
385
+ for (var d0 = 0; d0 < drawers.length; d0++) totalCount += drawers[d0].items.length
386
+ var greetLine = g.greeting && String(g.greeting).trim()
387
+ ? String(g.greeting).trim()
388
+ : (function () {
389
+ if (away()) return t('welcomeBack')
390
+ var base = { morning: t('greetMorning'), forenoon: t('greetForenoon'), noon: t('greetNoon'), afternoon: t('greetAfternoon'), evening: t('greetEvening') }[seg]
391
+ if (totalCount > 0) base += t('greetSummary') + totalCount + t('greetThings')
392
+ return base
393
+ })()
394
+ // 离开>1小时后回来
395
+ function away() {
396
+ var lastSeen = 0
397
+ try { lastSeen = Number(localStorage.getItem('dsh-auto-memory.lastActive') || 0) } catch (e) {}
398
+ return lastSeen > 0 && (Date.now() - lastSeen) > 3600000
399
+ }
400
+ var rows = []
401
+ rows.push(h('div', { 'data-dam-content': '' }, greetLine))
402
+ // 抽屉列表
403
+ for (var d = 0; d < drawers.length; d++) {
404
+ (function (dr) {
405
+ var isOpen = openMap[dr.key] !== undefined ? openMap[dr.key] : dr.defaultOpen
406
+ rows.push(h('div', { key: dr.key, style: { marginTop: '8px' } },
407
+ h('button', {
408
+ 'data-dam-btn': '',
409
+ onClick: function () { var n = Object.assign({}, openMap); n[dr.key] = !isOpen; setOpenMap(n) },
410
+ style: { width: '100%', display: 'flex', justifyContent: 'space-between', alignItems: 'center', padding: '5px 8px', borderRadius: '7px', background: 'color-mix(in srgb, var(--dsw-alias-bg-layer-1, rgba(128,128,128,.08)) 45%, transparent)', border: '1px solid color-mix(in srgb, var(--dsw-alias-border-l1, rgba(128,128,128,.3)) 50%, transparent)' },
411
+ },
412
+ h('span', { style: { fontWeight: 600, fontSize: '12.5px' } }, (isOpen ? '▼ ' : '▶ ') + dr.label),
413
+ h('span', { 'data-dam-muted': '', style: { fontSize: '11.5px' } }, dr.items.length + t('logEntries'))),
414
+ isOpen ? h('div', { style: { padding: '6px 4px 2px 10px' } },
415
+ dr.items.map(function (en) {
416
+ return h('div', { key: (en.time || '') + en.text, style: { marginBottom: '3px', fontSize: '12.5px', lineHeight: 1.5 } },
417
+ dr.withTime && en.time ? h('span', { 'data-dam-muted': '', style: { fontFamily: 'monospace', fontSize: '11px', marginRight: '6px' } }, en.time) : null,
418
+ h('span', { style: { wordBreak: 'break-word' } }, en.text))
419
+ })) : null))
420
+ })(drawers[d])
399
421
  }
400
422
  // 待反思提醒
401
423
  if (g.pendingReflectionDate) {
402
- rows.push(h('div', { 'data-dam-hint': '' }, t('pendingReflectionShort') + g.pendingReflectionDate))
424
+ rows.push(h('div', { 'data-dam-hint': '', style: { marginTop: '8px' } }, t('pendingReflectionShort') + g.pendingReflectionDate))
403
425
  }
404
- if (!rows.length) return null
405
- return h(Card, { title: title }, rows)
426
+ return h(Card, { title: (g.period || '') + ' · ' + segLabel }, rows)
406
427
  }
407
428
 
408
429
  function OverviewTab() {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@a9i5k4/dsh-auto-memory",
3
3
  "description": "DSH 自动记忆插件:三层记忆(用户级/项目笔记/每日日志)自动注入与检索、每日反思、可视化面板与设置页,支持继承其他 AI 工具的记忆。",
4
- "version": "0.1.6",
4
+ "version": "0.1.7",
5
5
  "type": "module",
6
6
  "main": "lib/index.js",
7
7
  "exports": {