@senguoyun/dsh-arkme 0.1.70 → 0.1.71

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.
Files changed (77) hide show
  1. package/docs/calendar-tooltip-regression-2026-09-20.md +25 -0
  2. package/docs/calls-retention-contacts-responsive-regression-2026-09-20.md +40 -0
  3. package/docs/composer-focus-regression-2026-09-20.md +38 -0
  4. package/docs/conversation-header-regression-2026-09-20.md +22 -0
  5. package/docs/desktop-regression-2026-09-19.md +10 -0
  6. package/docs/harness-activity.md +8 -0
  7. package/docs/harness-quick-create.md +18 -0
  8. package/docs/harness-session-dropdown.md +12 -0
  9. package/docs/my-day-calendar.md +42 -1
  10. package/docs/private-chat-actions.md +10 -0
  11. package/docs/private-interaction-directory-regression-2026-09-20.md +38 -0
  12. package/lib/arko-native-client.js +40 -0
  13. package/lib/client.js +2104 -1208
  14. package/lib/client.js.map +1 -1
  15. package/lib/harness-model-client.js +9 -0
  16. package/lib/harness-native-selection-client.js +40 -0
  17. package/lib/harness-sidebar-client.js +121 -11
  18. package/lib/index.js +60 -1
  19. package/lib/persistent-extension.js +1 -1
  20. package/lib/{persistent-runtime-DxKHwHTw.js → persistent-runtime-Cb8xQ4w0.js} +210 -8
  21. package/lib/types/arkme-service.d.ts +18 -2
  22. package/lib/types/arkme-service.d.ts.map +1 -1
  23. package/lib/types/client/ArkmeCalendarDateTooltip.d.ts +8 -0
  24. package/lib/types/client/ArkmeCalendarDateTooltip.d.ts.map +1 -0
  25. package/lib/types/client/ArkmeCalendarSurface.d.ts.map +1 -1
  26. package/lib/types/client/ArkmeCallDetailContent.d.ts +2 -1
  27. package/lib/types/client/ArkmeCallDetailContent.d.ts.map +1 -1
  28. package/lib/types/client/ArkmeCallSurface.d.ts +2 -1
  29. package/lib/types/client/ArkmeCallSurface.d.ts.map +1 -1
  30. package/lib/types/client/ArkmeDayTimeline.d.ts.map +1 -1
  31. package/lib/types/client/ArkmeDshMenu.d.ts.map +1 -1
  32. package/lib/types/client/ArkmeNoteDetails.d.ts +10 -2
  33. package/lib/types/client/ArkmeNoteDetails.d.ts.map +1 -1
  34. package/lib/types/client/ArkmePersonalDayCalendar.d.ts.map +1 -1
  35. package/lib/types/client/ArkmeQuickAdd.d.ts +3 -1
  36. package/lib/types/client/ArkmeQuickAdd.d.ts.map +1 -1
  37. package/lib/types/client/ArkmeRetainedCallPage.d.ts +5 -0
  38. package/lib/types/client/ArkmeRetainedCallPage.d.ts.map +1 -0
  39. package/lib/types/client/ArkmeSidebar.d.ts.map +1 -1
  40. package/lib/types/client/ArkmeSourceBreadcrumb.d.ts +3 -1
  41. package/lib/types/client/ArkmeSourceBreadcrumb.d.ts.map +1 -1
  42. package/lib/types/client/ArkmeVirtualWorkspace.d.ts +4 -0
  43. package/lib/types/client/ArkmeVirtualWorkspace.d.ts.map +1 -1
  44. package/lib/types/client/api.d.ts +1 -1
  45. package/lib/types/client/api.d.ts.map +1 -1
  46. package/lib/types/client/calendar-activity-model.d.ts +25 -1
  47. package/lib/types/client/calendar-activity-model.d.ts.map +1 -1
  48. package/lib/types/client/call-history-refresh.d.ts +5 -0
  49. package/lib/types/client/call-history-refresh.d.ts.map +1 -0
  50. package/lib/types/client/conversation-header-layout.d.ts +4 -0
  51. package/lib/types/client/conversation-header-layout.d.ts.map +1 -0
  52. package/lib/types/client/day-activity-presentation.d.ts +6 -0
  53. package/lib/types/client/day-activity-presentation.d.ts.map +1 -0
  54. package/lib/types/client/documented-day-activity-reader.d.ts +21 -0
  55. package/lib/types/client/documented-day-activity-reader.d.ts.map +1 -0
  56. package/lib/types/client/harness-session-dropdown.d.ts.map +1 -1
  57. package/lib/types/client/locales/dynamic-en.d.ts.map +1 -1
  58. package/lib/types/client/multisource-day-activity-reader.d.ts +10 -0
  59. package/lib/types/client/multisource-day-activity-reader.d.ts.map +1 -1
  60. package/lib/types/client/private-interaction-directory.d.ts +18 -0
  61. package/lib/types/client/private-interaction-directory.d.ts.map +1 -0
  62. package/lib/types/client/realtime-client-events.d.ts.map +1 -1
  63. package/lib/types/client/use-documented-day-month.d.ts +13 -0
  64. package/lib/types/client/use-documented-day-month.d.ts.map +1 -0
  65. package/lib/types/client/use-private-interaction-directory.d.ts +16 -0
  66. package/lib/types/client/use-private-interaction-directory.d.ts.map +1 -0
  67. package/lib/types/host-api.d.ts.map +1 -1
  68. package/lib/types/services/calendar-service.d.ts +15 -1
  69. package/lib/types/services/calendar-service.d.ts.map +1 -1
  70. package/lib/types/services/call-history-service.d.ts +4 -1
  71. package/lib/types/services/call-history-service.d.ts.map +1 -1
  72. package/lib/types/services/chat-service.d.ts.map +1 -1
  73. package/lib/types/services/interwoven-service.d.ts +2 -1
  74. package/lib/types/services/interwoven-service.d.ts.map +1 -1
  75. package/lib/types/types.d.ts +38 -1
  76. package/lib/types/types.d.ts.map +1 -1
  77. package/package.json +5 -5
@@ -0,0 +1,25 @@
1
+ # 日历日期悬浮提示即时显示
2
+
3
+ ## 原因与范围
4
+
5
+ 日期格原先通过原生 HTML `title` 显示「私聊 × 条 · 群聊互动 × 条」。等待时间由浏览器控制,不是统计请求导致。用户确认后,替换为即时自定义提示;没有修改日历尺寸、条数口径、数据加载或日期点击定位逻辑。
6
+
7
+ ## 交互
8
+
9
+ - 鼠标移入立即显示,移出立即关闭,没有延迟定时器;相邻日期切换不残留旧提示。
10
+ - 键盘聚焦可显示,失焦、Escape、滚动、窗口缩放或失焦时关闭。
11
+ - 提示挂载在当前页面的浮层中,避免日历滚动容器裁切;根据窗口边缘调整位置,不拦截鼠标点击。
12
+ - 使用现有浅色/深色主题,并关联日期按钮的无障碍描述。空白、未知、不可用日期不制造统计内容。
13
+ - 移除原生 `title`,避免再次出现一份延迟提示。
14
+
15
+ ## 验证(2026-09-20 19:44–19:48 CST)
16
+
17
+ - 9 个相关测试文件共 100 项通过,包括新增的即时显示/关闭、键盘、滚动、切换、边缘避让、卸载清理与原有会话日历回归。
18
+ - 类型检查、构建、差异空白检查通过。
19
+ - 固定预览 `http://127.0.0.1:3098/` 已更新;安装包与本地构建的 client/index 哈希一致。未修改已安装 Arkme 客户端,未提交或推送代码。
20
+ - 独立 Chromium 对已登录预览实测:私聊日历显示真实私聊及群互动条数;移出、滚动关闭;1440 宽及 420 宽窗口提示正常,窄窗口未超出边界。暗色提示实测背景 `rgb(53, 54, 56)`、文字 `rgb(249, 250, 251)`。
21
+ - 无页面脚本异常。验证设置了发送、已读、创建、AI 生成及开始录音请求拦截,实测未触发这些写入。
22
+ - 缩放后先将鼠标移离日期再移入进行验证;缩放本身会关闭提示,同一指针位置不应被当作一次新的移入事件。
23
+
24
+ 修改前已完整备份当前已修改及未跟踪文件:
25
+ `/var/folders/qd/3ysmrl0n1bg9rm_bpq2bfd480000gn/T/arkme-calendar-tooltip-before-EDtzRb/changes.tar.gz`。
@@ -0,0 +1,40 @@
1
+ # 通话页保留与窄屏联系人回归(2026-09-20)
2
+
3
+ ## 已确认的需求
4
+
5
+ - 当前登录期间,通话列表、已加载历史分页、选中详情、搜索条件与阅读位置在板块切换后保留。返回时后台检查更新,不清空重载;退出登录或切换账号清空。
6
+ - 联系人窄屏不再缩成不可见目录:先显示列表,选中后显示详情与返回入口;左侧功能导航始终保留。放宽恢复目录与详情双栏。
7
+ - 本轮仅调整插件与独立 3098 Web 预览,不更新已安装的 Arkme 客户端,不发布、不合并代码。
8
+
9
+ ## 根因
10
+
11
+ 1. `ArkmeSidebar` 的通话模式分支切换会卸载 `ArkmeCallSurface`;工作区进入非活动状态时另有提前返回分支,也会卸载整棵通话界面。
12
+ 2. 通话页重新挂载后从空状态请求首屏;原刷新直接替换整页,丢失此前加载的历史分页。
13
+ 3. 后端每次封装通话会重新生成 `callRef`,原选中状态及详情节点依赖此临时标识,刷新后可能失选、重挂载。
14
+ 4. 联系人旧窄屏样式只覆盖 820px 以下,而宿主在更宽时已折叠侧栏。实测 900px、821px 下目录仅约 1px,剩下空白详情占位。
15
+
16
+ ## 实现
17
+
18
+ - 通话页首次访问才挂载,离开时隐藏并传入活动状态。活动/挂起分支的外层容器和通话节点使用稳定键值;账号、环境或登录状态改变会销毁保留内容。
19
+ - 返回后通过现有 `calls.history.list` 拉取最新页,并以 `stableId` 合并。新数据超过一页时继续补齐到已缓存记录,保留旧分页游标与去重逻辑;完整响应按服务器结果收敛。
20
+ - 选中与行节点、详情容器使用稳定记录标识,接口调用仍使用最新 `callRef`。只在刷新后检查当前选中详情,不因加载旧分页重复请求详情。
21
+ - 列表刷新前后按可见行锚点保持阅读位置;后台失败保留旧内容,后续访问重试。
22
+ - 隐藏时不自动填满分页、停止已加载页的后台补页,关闭临时选择弹窗并停止详情音视频播放;不会停止全局正在进行的真实通话。
23
+ - 联系人跟随宿主实际折叠状态,而非另设不一致断点;窄屏仅隐藏目录或详情之一,不卸载目录,不隐藏第一栏导航。
24
+
25
+ ## 验证
26
+
27
+ - 15 个相关测试文件、482 项测试通过,包含真实 `ArkmeSurface` 工作区挂起/恢复、账号切换/退出、旧分页保留、访问标识轮换、刷新失败、多页补齐、无效游标、迟到响应、音视频暂停及原有发送交互。
28
+ - 类型检查与完整构建通过。
29
+ - 3098 生产组件浏览器验证:1440、1100、1099、1024、1000、900、821、820、720、420px 下联系人目录均可见;窄屏选择/返回、搜索保留、放宽恢复双栏通过。
30
+ - 通话浏览器受控响应验证:已加载 60 条,离开/返回后列表、详情仍是同一 DOM 节点,列表滚动 2600px、详情 480px 保留;新增一条后共 61 条,列表补偿至 2695px 保持原阅读锚点;模拟后台失败不清空。
31
+ - 真实账号只读验证:30 条通话记录,离开/返回后同一列表及详情节点、240px 列表位置保留,不出现“正在读取通话记录”。没有发起通话或修改数据。
32
+ - 原“发给自己”输入框回归:1440/720px、底部/历史位置各三轮聚焦与失焦,消息位移为 0,未出现页面异常。
33
+
34
+ 浏览器脚本保存在独立预览目录:`check-contacts-calls-retained.mjs`、`check-calls-live-retained.mjs`、`check-composer-focus.mjs`。
35
+
36
+ ## 边界
37
+
38
+ - 保留范围是当前页面运行期间;刷新整个浏览器或重启后仍需要首次加载,不把通话详情长期写入磁盘。
39
+ - 使用现有分页接口实现后台检查,没有新增后端增量接口。未返回范围内的历史记录全量变更/删除不等于已完整同步;当前选中详情会再次读取。
40
+ - 多页新增、网络错误和取消场景使用受控测试响应验证,不是通过真实制造通话验证。
@@ -0,0 +1,38 @@
1
+ # 发给自己输入框聚焦稳定性回归
2
+
3
+ ## 原因与修复
4
+
5
+ - 聚焦前后,输入卡片本身均为 103px;变化来自卡片上方统计栏:空草稿失焦时为 0px,聚焦时为 20px。
6
+ - 消息视口因此从 809px 缩为 789px,底部锚定使最后一条消息上移 20px。
7
+ - 经用户确认,非私聊输入区固定预留 20px 统计栏;私聊维持原有 30px。字数、时长和快捷键仍按原规则显隐,不改变发送、采集或编辑行为。
8
+ - 修改前备份:`/tmp/arkme-composer-focus-before-Rkuihn/changes.tar.gz`,含本次涉及的源码和测试原文件。
9
+
10
+ ## 自动化回归
11
+
12
+ 10 个测试文件、417 项测试通过:
13
+
14
+ ```sh
15
+ ./node_modules/.bin/vitest run \
16
+ tests/conversation-send-directory.test.tsx \
17
+ tests/conversation-composer-presentation.test.tsx \
18
+ tests/conversation-resize-anchor.test.ts \
19
+ tests/resizable-composer-dom.test.tsx \
20
+ tests/resizable-composer.test.tsx \
21
+ tests/conversation-composer-border.test.tsx \
22
+ tests/conversation-composer-visual.test.ts \
23
+ tests/composer-focus.test.ts \
24
+ tests/composer-click-focus.test.tsx \
25
+ tests/composer-paste-focus.test.tsx --maxWorkers=2
26
+ ```
27
+
28
+ 渲染测试覆盖私聊、群聊、发给自己、主题、未分类的聚焦、失焦、输入、清空以及时长显示切换。
29
+ `pnpm run build`(含 TypeScript 声明检查、打包及可执行入口校验)和 `git diff --check` 通过。
30
+
31
+ ## 3098 实际页面回归
32
+
33
+ - 独立 Chromium 测试,1440px、720px 两种宽度,各覆盖最新消息底部与历史阅读位置,每种场景连续聚焦/失焦 3 次。
34
+ - 四种场景的消息位置、滚动位置、消息视口、输入卡片几何均保持不变;消息位移为 0px。
35
+ - 统计栏始终 20px,输入区整体始终 143px;统计文字、快捷键在聚焦时显示,空草稿失焦时隐藏。
36
+ - 无页面异常。测试未发送消息、修改记录或开启录音;未出现被拦截的业务写请求。
37
+ - 已更新 3098 独立 Web 预览,核对安装的 20 个 JavaScript 包与本地构建一致。未改动已安装桌面客户端,未提交或推送。
38
+ - 复现脚本:`/Users/tison/arkme/.codex-artifacts/web-preview-3098/check-composer-focus.mjs`。
@@ -0,0 +1,22 @@
1
+ # 对话标题与中央选择器统一
2
+
3
+ 用户确认后实施:左侧显示固定对话名,中央显示任务/主题选择器,右侧保留现有操作。
4
+
5
+ ## 改动
6
+
7
+ - 第二栏 DSH 卡片与 DSH 对话左上角共用 `DeepSeek Harness` 名称。当前任务名称不再覆盖第二栏名称;进行中、待处理及待查看提示保留。
8
+ - DSH 当前任务及状态仍在中央选择器显示。保留原生任务列表、菜单、状态图标、模式说明和右侧全部操作,不移动上游 React 节点。
9
+ - 发给自己:名称固定在左侧,全部/主题选择器独立居中;日历和更多操作仍在右侧。切换主题只改变中央选择项,不改变对话名。
10
+ - 居中以整个对话区域为准,左右预留相同宽度;DSH 计算全部右侧原生操作组所需空间,防止新增标题后操作按钮换行。模式说明保持一行,窄窗口不额外增高。
11
+ - 中央主题菜单在窗口右边缘向左避让,保留正常菜单宽度;第二栏悬浮菜单、主题归类窗口等入口不改。
12
+ - 适配器卸载恢复原生样式;遇到无法识别的上游顶栏不覆盖其导航。
13
+
14
+ ## 验证(2026-09-20 20:41–20:42 CST)
15
+
16
+ - 12 个相关测试文件,133 项测试通过;类型检查、构建及 `git diff --check` 通过。
17
+ - 固定 3098 安装包与本地 20 个 JS 产物逐一校验一致。
18
+ - 独立 Chromium 已登录预览:打开现有 DSH 任务、展开和关闭任务菜单、打开主题菜单并切换到未分类,均无页面脚本异常;第二栏名称与 DSH 顶栏一致,发给自己名称不随主题改变。
19
+ - 1440、1000、720 宽度检查 DSH/发给自己选择器相对于对话区域的中心误差小于 0.1 像素;发给自己另检查了 420 宽度。DSH 顶栏实测 73 像素、发给自己顶栏 68 像素,各窗口宽度不额外增高;右侧原生操作组与标题同一行。
20
+ - 发送、已读、创建、AI 生成、开始录音等接口配置了拦截;本轮实测未触发这些写入。不修改已安装 Arkme 客户端,不提交或推送代码。
21
+
22
+ 工作区修改前备份:`/var/folders/qd/3ysmrl0n1bg9rm_bpq2bfd480000gn/T/arkme-conversation-header-before-5TMwl8/changes.tar.gz`。
@@ -75,3 +75,13 @@
75
75
  - 最终全量:671 文件,663 通过、0 失败、8 跳过;**7,938 项通过、0 失败、12 跳过**(18:52:20 开始,151.72 秒)。原有跳过数量未增加,未删除失败用例。
76
76
  - 本节没有更新或重启固定 3098 预览,未更换端口、迁移登录、访问钥匙串或修改已安装 Arkme 客户端。此时预览仍是之前部署版本。
77
77
  - 既有 DSH 页面卸载生命周期问题未在本节修复,真实截屏授权、麦克风、多小时录音、真实发送及跨端状态等验收限制也仍有效。
78
+
79
+ ## 第二栏「添加」按钮的悬停反馈回归
80
+
81
+ 2026-09-20 修复:Arkme 的统一悬停反馈(`redesign/interaction-feedback.css`)是**叠一层 `background-image` 渐变**,不是改 `background-color`。第二栏工具栏的 `.arkme-directory-search-toolbar button[title="添加"]` 用了 `background` **简写**并带 `!important`,简写会把 `background-image` 重置为 `none`,且该选择器优先级高于 `[data-arkme-feedback]`,于是这个按钮的悬停与按下反馈被静默清掉。
82
+
83
+ 该规则最初只命中未登录时的联系人工具栏按钮,`#576` 把选择器改成按 `title="添加"` 命中后,才开始作用于带 `data-arkme-feedback` 的加号按钮。修复为只设置 `background-color`,保留输入框式底色,同时让共享悬停渐变层继续生效。
84
+
85
+ 验证:`tests/interaction-feedback.test.tsx` 用 jsdom 计算样式直接断言该按钮的 `background-image` 仍是共享渐变,并断言规则只使用 `background-color`;把简写改回去该用例会失败。类型检查、完整测试与打包通过。
86
+
87
+ 后续(2026-09-20):该按钮已按会话输入框的统一控件改为 28×28 圆形加号(官方 `IconPlusOutline16`),底色改由组件内联 `backgroundColor` 声明,`.arkme-directory-search-toolbar button[title="添加"]` 这条本地覆盖规则不再需要并已移除,避免第二处可能重置悬停层的简写。悬停反馈依赖的仍是 `[data-arkme-feedback]` 那层 `background-image` 渐变。
@@ -16,3 +16,11 @@
16
16
  本地存储仅保存按环境与账户隔离的待查看会话 ID,不保存会话正文、执行状态或凭据。活动状态仍由官方数据实时提供。刷新时保留已观察到的待查看提醒;页面完全关闭期间未观察到的运行变化依赖宿主的完成状态,不保证补报。
17
17
 
18
18
  退出登录时移除摘要;未登录入口保持原有行为。测试覆盖状态优先级、子任务合并、已读、刷新、归档与删除、账户隔离,以及公开槽位订阅和可见性桥接。浏览器中的模拟状态只用于视觉验收,不向真实会话发送消息。
19
+
20
+ ## 会话入口显示当前对话名
21
+
22
+ 2026-09-20 调整:第二栏的 DeepSeek Harness 卡片与其它会话行(`ArkmeDirectoryRow`)共用同一个两行结构,但第一行此前写死为「DeepSeek Harness」,真正的当前对话名被放在第二行——而只要有任务在跑,第二行又会被状态摘要整条顶掉,用户就看不到自己正在哪个对话里。
23
+
24
+ 现在第一行改为显示当前对话名(沿用该行已有的 `activity.current.title`,空白会话显示「新会话」),口径与其它会话行一致;产品名只在 Harness 尚未上报会话时作为兜底。第二行沿用本文档已确认的口径不变:有进行中任务时显示状态计数,否则显示空闲提示;只有待处理/待查看而没有进行中任务时仍是头像角标,不占用第二行。行内 `aria-label` 同步改为「对话名,状态摘要」。
25
+
26
+ 验证:`tests/harness-directory-row.test.tsx` 覆盖当前对话名、运行中仍保留对话名、无运行任务但有未读时第二行仍显示状态、未上报会话时回退产品名、空白会话显示「新会话」;并确认把第一行改回写死、把第二行重新当作对话名载体、或去掉产品名兜底时,对应用例都会失败。类型检查、完整测试与打包通过。
@@ -11,3 +11,21 @@
11
11
  ## 外部点击收起
12
12
 
13
13
  原菜单只监听外层 document,DSH iframe 内点击和 Esc 不会冒泡到外层,导致菜单不收起。菜单打开期间额外监听可访问的嵌入文档及其同源子页面,随 iframe 插入、加载、刷新和移除更新绑定;菜单关闭时完整释放。外部点击不阻止默认行为或传播,仍能聚焦原输入框、点击原按钮。Esc 由当前菜单先处理并把焦点还给「+」,避免触发下层快捷操作。外观不变,未新增遮罩,也不读取或绕过跨域页面。
14
+
15
+ ## 外部点击收起的兜底
16
+
17
+ 2026-09-20 的后续修复:原生 DSH 菜单只在**冒泡阶段**监听 `document` 的 `pointerdown`,因此从点击目标到 `document` 之间只要有任意一层调用了 `stopPropagation()`(自定义滚动条把手、拖拽层、卡片包装层都可能在列),事件就永远到不了 `document`,整个菜单的外部点击收起会被静默禁用,而外观和键盘交互都没有任何异常迹象。
18
+
19
+ `ArkmeActionMenu` 因此在菜单打开期间额外挂一个**捕获阶段**的 `pointerdown` 监听:捕获阶段先于所有其他处理器运行,无法被下层阻断。为避免和原生路径重复关闭,同一个 `document` 上还挂一个冒泡阶段监听,只要事件正常冒泡到 `document` 就取消捕获阶段排下的兜底,所以正常路径仍然**只关闭一次**(`tests/native-action-menu.test.tsx` 断言的单次契约保持不变);只有在传播确实被阻断时,兜底才在下一个任务里执行收起。菜单本身和外层锚点的判断沿用原生口径(`rootRef` 与菜单列表都不包含目标才关闭),点击触发按钮仍走原有开合逻辑。
20
+
21
+ 验证:`tests/quick-add-dismissal.test.tsx` 覆盖宿主文档外部点击、同源嵌入文档内点击、以及目标阻断传播三种情况;确认移除捕获监听时阻断用例会失败。类型检查、完整测试与打包通过。
22
+
23
+ ## 悬浮展开与统一控件
24
+
25
+ 2026-09-20 的后续调整:第二栏的「添加」入口此前是点击才展开,曝光率低;同时它自成一个方形按钮并使用文字 `+` 字形,和会话输入框不是同一套控件。现在改为**鼠标悬浮即展开**,并把它统一成 DSH 会话输入框左下角那颗圆形加号。
26
+
27
+ 交互:指针移入触发按钮即展开,指针离开「触发按钮 + 浮层菜单」这一整块区域才收起,两者之间的窄缝也算同一悬停目标,因此从按钮移向菜单不会误关。触屏不因 `pointerenter` 展开,仍沿用点击;键盘激活(`detail === 0`)继续切换开合,而鼠标点击只会展开、不会把已展开的菜单点掉。外部点击、Esc 与之前的传播兜底收起逻辑不变。
28
+
29
+ 控件:改用官方 primitives 的 `IconPlusOutline16`(`size={14}`)与 28×28 圆形底板,底面色沿用官方 `--dsw-specific-selector`,不再引入第二套图形或文字字形,也不再需要本地覆盖规则。悬停反馈继续走共享的 `[data-arkme-feedback]`,内联样式只用 `backgroundColor` 声明底色——`background` 简写会重置悬停渐变层,这一点在实现中已固化。
30
+
31
+ 验证:`tests/quick-add-menu.test.tsx` 覆盖悬浮展开、触屏不展开、鼠标点击不误关、键盘切换、指针离开后收起,以及原有的三种外部点击收起;`tests/quick-add-ui.test.tsx` 断言新尺寸、圆角与官方加号路径;并确认去掉悬浮处理、去掉触屏判断、改回点击切换或把内联底色改回 `background` 简写时,对应用例都会失败。类型检查、完整测试与打包通过。
@@ -63,3 +63,15 @@
63
63
  次数作为独立条目注册到公开的 `conversation.session.header.actions` 会话级列表插槽,使用框架 `useProjection('sessionStats')` 读取官方整段会话的 `turns`。不统计当前屏幕消息,不复制官方计算逻辑、不缓存第二份次数;分页、折叠、历史压缩及实时推送继续由官方负责。失败、取消及轮次何时增长也沿用宿主统计口径,与官方底部“n 轮”保持一致。数据缺失或格式不兼容时不显示次数,不用 0 代替未知值。文案通过官方 locale 接口提供中英文。
64
64
 
65
65
  验证:8 个相关文件、59 项检查通过,包含次数更新、工具步骤不重复计数、会话数据切换、缺失值、卸载清理以及原生节点身份保留。类型检查和完整打包通过。真实页面对比顶部次数与官方底部轮次,验证宽/窄窗口、超长标题、会话切换、新会话和轨迹往返。当前两行标题区高度 77px;第二行是实际信息,并非原 tab 留白。测试用长标题仅在浏览器临时 DOM 中模拟,没有修改服务端会话标题。
66
+
67
+ ## 固定标题的任务状态同步
68
+
69
+ 后续调整:下拉列表里每个会话行左侧由官方渲染任务状态(`pendingInteraction` 警告点、运行中的像素跑马灯、运行中的子任务,以及完成/空闲态),但上方固定的标题按钮此前只有文字,用户聚焦标题时看不到当前会话是否还在跑。现在把选中行自己的状态节点镜像到标题按钮里。
70
+
71
+ 镜像而不是重算:只识别 `[role="treeitem"][aria-selected="true"]` 行的第一个子节点槽,取其直接子级的 `[data-state]` 节点整棵克隆。状态集合、颜色、尺寸和跑马灯动画继续由官方 `StateDot` 与其 CSS Module 提供,这里不复制状态判定,也不新增第二份本地化文案。官方对「完成且未标记完成」的行本来就不渲染状态槽,此处同样不显示,标题保持原宽度。
72
+
73
+ 只在签名(克隆节点的 `outerHTML` 加官方读屏文案)变化时替换克隆节点,避免每次无关重渲染都重建节点、把进行中的跑马灯动画打断。读屏文案取官方状态槽内已有的隐藏文本,拼进标题按钮的 `aria-label`,形如「切换会话:标题(进行中)」;克隆节点本身不带文字,`textContent` 仍是纯标题,读屏不会重复播报。
74
+
75
+ 状态可能只改 `data-state` 而不增删节点(例如「已完成」转为「等待批准」),因此观察器的 `attributeFilter` 增加 `data-state`。适配层卸载或结构不匹配时移除克隆节点并复位签名。标题、箭头与状态三者的排布继续由既有 `[data-arkme-conversation-selector] > span:first-child` 规则承载:状态槽放在标题文字所在的第一个 span 内,不改变官方按钮的两个分区结构。
76
+
77
+ 验证:`tests/harness-session-dropdown.test.ts` 覆盖状态镜像、无状态时隐藏且标题保持原文本、仅 `data-state` 变化、状态不变时节点身份保持(动画不重启)、切换选中行后丢弃过期状态、以及卸载清理;并确认去掉 `data-state` 观察项或有条件替换判断时对应用例会失败。类型检查、完整测试与打包通过。
@@ -1,6 +1,47 @@
1
1
  # 「我的一天」日历:分阶段实现与接口边界
2
2
 
3
- 更新:2026-09-20。**已接入多来源有限分页:个人记录、私聊/群聊中我发送的内容、通话、Arko、可只读的 Bot、DSH 已同步输入、录音与地点。仍不是完整的全天全来源索引。**
3
+ 更新:2026-09-20 18:39。**已接入文档化的按日来源:个人记录、私聊/群聊收发与 @/回复关系、通话、Arko、Bot、DSH 已同步输入、录音覆盖与地点。分页和接口历史覆盖边界仍然存在;当前 Arko 新接口实测返回服务器繁忙。**
4
+
5
+ ## 本轮最终回归与实际边界
6
+
7
+ ### 紧凑活动片段(2026-09-20,用户确认后实施)
8
+
9
+ - 标题优先显示联系人备注名或真实群名,并复用现有账号范围内的头像读取;无头像的来源使用类型图标。
10
+ - 同一来源片段从已加载正文中选择最多两条原文摘录,优先有内容的交流而不是最后一句“好的/继续”,并标明我、对方或已知群成员。选文不请求 AI、不改写正文、不推测消息回复关系;仅有简短回复时仍保留该回复。
11
+ - 选文不改变片段身份、时间排序、原始条数和展开内容;同来源 15 分钟相邻规则保持不变,原始明细模式仍逐条展示。
12
+ - 去掉重复来源文案,缩小片段间距,明确展示展开入口。录音显示实际覆盖时长,不再显示“0 条原始记录”;同一分钟内不重复显示相同起止时间。
13
+ - DSH 尚无可靠任务名关联的输入仍标明 DSH 输入,不把记录所属主题名冒充任务名。Arko 等来源的接口错误和未覆盖范围仍独立显示。
14
+ - 原有自主确认的 AI 小结入口保留;本轮选文、头像与详情检查不调用它,也不改变会话已读状态。
15
+ - 验证:10 个直接相关测试文件 118 项、6 个来源/通话/地点/群互动回归文件 151 项通过;类型检查、构建及差异检查通过。固定 3098 已更新,安装产物与本地构建一致。
16
+ - 18:54–18:56 使用独立 Chromium 连接已登录 3098 实测:今天与 9 月 18 日显示真实名称、原文摘录和通话;头像补读后实际图片可见;群片段展开保留 5 条消息,原始明细/活动片段、录音筛选可切换;1440/800/420 宽度无横向溢出、无页面脚本异常。测试监听了发送/已读/创建/AI 生成入口,没有触发这些写入。内嵌浏览器控制连接超时,未声称已替用户刷新其现有标签页;深色主题未单独验收。
17
+
18
+ - 使用与浏览器相同的适配器跑测试,移除了此前 `NODE_ENV=test` 时切回旧适配器的分支;避免测试通过而实际浏览器走另一套逻辑。
19
+ - Chat 正文读取实际 `record.payload.text_content`,Host 批量复用会话目录的备注名与账号绑定的来源引用;不把原始 `chat_session_uid` 作为可直接导航的引用。同一会话的相邻片段展开包含所有已加载成员消息,不只显示第一条的 240 字预览。
20
+ - 个人记录复用既有权限、隐私锁、富媒体及临时地点引用投影。只有地点摘要而没有坐标时不会崩溃;展开地点按响应真实 access/recordUid 校验。相同本人记录只在公开记录身份和会话身份均一致时与 Chat 去重,并保留图文与位置,不按文本/昵称/时间猜测。
21
+ - 通话按所选日期范围读取既有聚合接口,并复用备注名、已有摘要、签名引用及按需通话详情;范围进入缓存键。录音覆盖分页累积,某段展开时才按 `recording_id` 查询转写;没有读取全日人声不能宣称没有人声。当前新入口不自动拉取旧 `recordings.day` 的录音 AI 回顾,下面旧阶段的该项说明不代表本轮已完成同等接入。
22
+ - 独立游标循环会明确失败,未选择的来源不发请求,后端 `coverage=partial` 不被误报为完整;月历刷新与日期切换也重置对应请求。
23
+ - 2026-09-20 18:38–18:39,已登录 3098 真实浏览器确认:9 月 20 日显示联系人备注名、群名、消息正文及 DSH 输入;9 月 18 日显示 7 次通话,展开周鹏的通话可查看已有摘要和转写。
24
+ - 21 个相关测试文件共 256 项通过,最后地点去重补丁另复跑 30 项通过;类型检查、构建和安装产物哈希一致性通过。这不是全库、所有日期或两端真实收发验收。
25
+ - Arko `/api/v1/arko/activities/query` 在只读联调时返回 502 / `arkme-code-1002`(服务器繁忙);前端保留其它来源并显示重试。请后端排查新接口部署、migration 21、MySQL 时区表及日志,不能从此响应断言具体是哪项失败。
26
+ - 没有发送消息、生成 AI 小结、发起通话/录音或主动写会话已读;原有 TRTC 音量工作线程加载警告仍存在,未纳入本轮修复。
27
+
28
+ 以下较早阶段的说明用于保留演进背景;与本节不一致时以本节及文档化接口回接为准。
29
+
30
+ ## 文档接口回接升级(2026-09-20)
31
+
32
+ 本轮已把同事返回的「我的一天」接口契约接入桌面端时间线。前端不把多个来源拼成一个假接口,而是通过 Host 的 `calendar.activity` 只读入口分别读取并在浏览器内合成:每个来源保留自己的游标、失败状态和是否还有下一页。
33
+
34
+ | 来源 | 桶/明细读取 | 桌面端呈现 |
35
+ | --- | --- | --- |
36
+ | 个人记录 | `/api/v1/calendar/buckets/query`、`/api/v1/calendar/records/query` | 快记、DSH 输入、备注名优先、位置摘要与按需位置详情 |
37
+ | 私聊/群聊 | `/api/v1/chats/activities/buckets/query`、`/api/v1/chats/activities/query` | 发送、收到、@我、回复我的互动;私聊/群聊按来源身份展示 |
38
+ | 通话 | `/api/v1/call/history-buckets/query`、`/api/v1/call/history-aggregate` | 时间、对象、语音/视频、结果与已有摘要 |
39
+ | 录音 | `/api/v1/audio/get-calender-summary`、`/api/v1/audio/coverage/query`、`/api/v1/audio/transcripts/query` | 物理录音覆盖与有人声/转写分层,录音不是只有转写才算存在 |
40
+ | Arko / Bot | 各自的 `activities/buckets`、`activities` | 对话活动来源标识、分页与失败提示 |
41
+
42
+ 月历会合并没有个人快记、但有聊天/通话/录音/Arko/Bot 活动的日期;日期格用来源圆点区分,数字仍只代表个人记录数,不把不同口径相加。时间线支持「活动片段 / 原始明细」、按日历时区计算日界线,单一来源失败时保留其它来源并明确显示部分状态。
43
+
44
+ 该入口只允许文档列出的来源、模式和请求体,不能传任意 URL;浏览器不执行写操作、不触发已读、不自动启动录音或通话。记录的位置摘要只显示后端明确返回的标签和采集时间,不伪造坐标;有临时位置引用时仍通过既有 `calendar.record-location` 做权限复核。
4
45
 
5
46
  ## 轻量回顾与展示优化(2026-09-20)
6
47
 
@@ -56,3 +56,13 @@
56
56
  - 本次不修改服务端业务合同、插件版本或根 README。按后续明确授权提交并推送任务分支;不合并、发布或替换常驻插件。
57
57
 
58
58
  后续合并前审核、修复循环及分层验证记录位于仓库 `docs/changes/private-chat-actions-premerge-review.md`(审核资料不随运行制品发布)。
59
+
60
+ ## 转发快记弹窗里的发起私聊
61
+
62
+ 2026-09-20 新增:点击聊天记录(无论是转发过来的还是通过分享链接打开的)会打开转发快记弹窗,弹窗里每条记录的发送人头像此前没有入口。现在把指针移到**他人**的头像上会出现操作卡片,里面是「发起私聊」,选择后直接打开与该发送人的私聊会话。键盘聚焦头像同样能打开卡片;触屏不因悬浮触发,卡片本身沿用既有菜单的定位、外部点击与 Escape 收起。
63
+
64
+ 身份来源:转发快照此前只有发送人昵称和不透明的 `avatarRef`,无法定位账号。`ArkmeForwardRecordPreviewItem` 因此新增 `senderUserId`,由 Provider 在已有解析结果上补齐——该字段**只在解析到真实账号且不是查看者本人时**下发,查看者自己的 id 和未解析的发送人都不上链路;发送人的头像封印仍照旧独立生成,两者互不替代。弹窗侧只消费这个字段,不按昵称反查账号。
65
+
66
+ 边界:转写说话人标签从来不是账号身份(快照可能复用发送人的昵称与头像),因此说话人行永远不出现入口,即使调用方误传了 id 也会被 `arkmeForwardSenderChatPeerId` 拦掉;无法导航到会话的宿主(未传 `onPrivateChatOpened`)同样不显示入口。打开失败时保留卡片并显示原因,不伪造成功。所有入口路径(会话内详情、客户端日历、发给自己日历)共用同一个组件与同一套判定。
67
+
68
+ 验证:`tests/forward-sender-identity.test.ts` 断言只有他人的已解析账号会出现在投影里,本人和未解析发送人都不下发;`tests/forward-sender-private-chat.test.tsx` 覆盖悬浮出现卡片、点击调用私聊接口并回调导航、失败保留卡片、无身份与不可导航时不出现入口、说话人行永不出现入口;并确认分别去掉身份判断、说话人判断、导航判断和本人排除后,对应用例都会失败。类型检查、完整测试与打包通过。
@@ -0,0 +1,38 @@
1
+ # 群 @ 联动私聊目录:桌面回接与回归
2
+
3
+ ## 需求与本轮范围
4
+
5
+ 群内我 @ 对方或对方 @ 我后,已有的对应私聊入口按最新互动更新预览和活动排序;仍遵守置顶和隐藏规则。收到的互动提醒以 Chat 权威计数为准,自己发出的 @ 不产生自己的未读。读原群消息后刷新对应互动计数,保留其他群互动和直接私聊未读。
6
+
7
+ 仅修改桌面插件和固定端口 3098 的 Web 预览;没有修改或部署手机、Chat 后端,没有发送真实测试消息,没有自动创建私聊或恢复主动隐藏的入口。
8
+
9
+ ## 修复的根因
10
+
11
+ 1. 旧目录按完整 `sourceRef` 匹配互动。普通目录引用带备注名和目录元数据,互动引用带昵称;同一联系人因此变成两行,真实浏览器可见“狗才”的群互动卡片与“周鹏”的旧私聊卡片并存。现按账号绑定的 `sourceKey` 合并,标题保留备注名,选中态也用同一稳定身份。
12
+ 2. 旧实现从 occurrence 明细最多读取 500 条,全部读完才更新;普通目录 revision 变化又会取消整个读取。现接入 `/api/v1/chats/interwoven/directory/query`,每位联系人的最新预览、排序和完整互动计数由 Chat 返回,不再累计首批明细猜未读。
13
+ 3. 收发、群已读及权限失效没有完整接入侧栏互动刷新。现订阅既有失效通道,覆盖成功发送群 @、会话增量、消息变化、已读 ACK、成员/权限变化、重连及回到前台;单路请求合并密集事件,账号切换丢弃迟到结果。
14
+
15
+ ## 接口与安全边界
16
+
17
+ - Host 内部只读入口:`private-interaction.directory`,页大小不超过 100;不接受浏览器指定用户身份或任意上游路径。
18
+ - 复用普通目录 bundle 解析、联系人头像引用和会话入口可见性校验。互动计数与普通私聊未读分开;不增加全局徽标重复计数、不修改原群/私聊已读游标。
19
+ - 范围仍为 `chat_group_mentions`,未覆盖旧 World 历史。没有现成私聊入口的联系人是否创建入口,仍由已有业务规则决定。
20
+ - 权限/读取失败不伪装为零未读;旧请求不能覆盖新事件、账号或阅读结果。
21
+
22
+ ## 实际联调发现:版本稳定性仍需后端检查
23
+
24
+ 2026-09-20 18:21–18:24,使用现有账号做只读查询:
25
+
26
+ - 最新一页能返回“周鹏”、17:46 的群 @ 预览与正确的零未读事实,页面可以正确去重和排序。
27
+ - 50 条分页时,首个成功请求耗时约 4996 ms;带返回的游标和版本读下一页,约 3133 ms 后得到 HTTP 409 `version_changed`。
28
+ - 随后的不带游标首屏请求也曾在约 4669 ms 后返回同样错误;再次首屏请求约 4771 ms 成功。不能据此断言没有真实业务状态变化,需后端核对快照日志。
29
+ - Chat 当前实现对全账号目录、关系、成员、策略和读游标做版本哈希,读取/装饰前后重验。请排查版本是否受无关更新或非确定性排序影响,检查 `facts/recheck/hydration` 阶段耗时,以及正常活跃账号能否稳定续页;不能取消权限复核来消除 409。
30
+
31
+ 桌面处理:按合同使用 100 条页,先展示已成功的近期页;版本变化时有界重读第一页。持续续页冲突时,**再独立核验最新一页**,丢弃旧分页内容,并明确显示“较早群互动暂未加载,点击重试”。再次核验也失败则清除互动投影、保留普通目录并显示失败提示。不声称此时全目录已完整加载,也不把缓存当作新的权限事实。
32
+
33
+ ## 验证
34
+
35
+ - 最终 3098 页面也读取到用户新发出的 18:32 “@狗才 测试再次”,在同一个“周鹏”备注名卡片显示“群名 · 我:…”;保留固定置顶排序,没有另建昵称卡片。
36
+ - 针对稳定身份、备注名、完整计数、自己发送不新增未读、直接消息优先、排除隐藏入口、分批发布、版本变化、重试、取消、跨账号迟到结果及实时失效补充自动回归。
37
+ - 同时回归“我的一天”新接口读取;编译/打包单独验证。
38
+ - 浏览器只读取现有业务消息验证卡片,没有通过真实发送或真实修改读游标制造测试数据。两端实时往返仍需双方安装同一修复版本后验收;其他端不会因更新本地 Web 预览而自动升级。
@@ -1458,6 +1458,14 @@ Arkme 账号|Arkme account
1458
1458
  return [line.slice(0, index), line.slice(index + 1)];
1459
1459
  }));
1460
1460
  Object.fromEntries(`
1461
+ {v0} 条相关消息|{v0} related messages
1462
+ 录音 {v0}|Recorded {v0}
1463
+ 始于前一天|Started the previous day
1464
+ 延续至下一天|Continues into the next day
1465
+ 暂无内容预览,展开查看详情|No preview available. Expand for details
1466
+ 已有摘要:|Existing summary:
1467
+ 群互动同步暂未完成,点击重试|Group interactions could not sync. Click to retry
1468
+ 较早群互动暂未加载,点击重试|Earlier group interactions are not loaded. Click to retry
1461
1469
  {v0}的头像|Avatar of {v0}
1462
1470
  {v0} 的头像|Avatar of {v0}
1463
1471
  {v0}头像|Avatar of {v0}
@@ -1504,6 +1512,7 @@ Arkme 账号|Arkme account
1504
1512
  {v0} 像素|{v0} px
1505
1513
  来源:{v0}|Source: {v0}
1506
1514
  私聊 {v0} 条|{v0} direct messages
1515
+ 多来源活动|Activity from multiple sources
1507
1516
  群聊互动 {v0} 条|{v0} group interactions
1508
1517
  查看地点:{v0}|View location: {v0}
1509
1518
  查看小结来源:{v0}|View recap source: {v0}
@@ -2004,6 +2013,37 @@ Arkme 用户 {v0}|Arkme user {v0}
2004
2013
  document.removeEventListener("keydown", onKey);
2005
2014
  };
2006
2015
  }, [open]);
2016
+ (0, react.useEffect)(() => {
2017
+ if (!open || typeof document === "undefined") return;
2018
+ const own = root.current?.ownerDocument ?? document;
2019
+ if (typeof own?.addEventListener !== "function") return;
2020
+ let pending;
2021
+ const cancel = () => {
2022
+ if (pending !== void 0) {
2023
+ clearTimeout(pending);
2024
+ pending = void 0;
2025
+ }
2026
+ };
2027
+ const outside = (event) => {
2028
+ const target = event.target;
2029
+ if (!(target instanceof Node)) return;
2030
+ if (root.current?.contains(target) === true) return;
2031
+ if (menu.current?.contains(target) === true) return;
2032
+ cancel();
2033
+ pending = setTimeout(() => {
2034
+ pending = void 0;
2035
+ closeRef.current();
2036
+ }, 0);
2037
+ };
2038
+ const arrived = () => cancel();
2039
+ own.addEventListener("pointerdown", outside, true);
2040
+ own.addEventListener("pointerdown", arrived);
2041
+ return () => {
2042
+ cancel();
2043
+ own.removeEventListener("pointerdown", outside, true);
2044
+ own.removeEventListener("pointerdown", arrived);
2045
+ };
2046
+ }, [open]);
2007
2047
  (0, react.useEffect)(() => {
2008
2048
  if (!open || !props.point || typeof document === "undefined" || typeof document.createElement !== "function") return;
2009
2049
  const doc = props.pointDocument ?? document;