Skip to content

Releases: dpkg-s/ai-memory-web

v1.11.3 — 本版无代码变更(源码包与安装器随 Release 提供)

Choose a tag to compare

@github-actions github-actions released this 22 Oct 13:25

本版没有代码变更 —— serve_web.py、web_console.py、web/ 与 v1.11.2 完全相同。v1.11.1 修的启动守卫与 MCP 报错可读性,本版原样有效。

现在能直接下载到什么

附件 用途
web-console-v1.11.3.tgz 控制台源码包,解压即用(不含测试与 CI 配置)
ai-memory-setup.exe Windows 快捷安装器,与核心仓提供的是同一个文件

此前这两个附件要手工挂,v1.11.2 及更早的几个版本在下载页上干脆没有。

升级方式

代码没变,正在用 v1.11.2 的不需要升级。Docker 部署请跟随 ai-memory-docker 的镜像 tag。

破坏性变更

无。

校验

744414078fa6de1eae7255fb8e51e9c12b7c9a4ed014e9448fd86b72bf43df4c  web-console-v1.11.3.tgz
a52ca45373f8bfe21bfdbebc9b21afe91f40d7fe3f9c14f4961e8d2a7a3e3b1f  ai-memory-setup.exe

本版尚未提供 .sha256 文件,下一版起自动附带。

v1.11.2 — 本版无功能变更(Docker 构建定义迁往 ai-memory-docker)

Choose a tag to compare

@github-actions github-actions released this 22 Oct 13:00

本版控制台源码一行未改,变化只在「怎么跑容器」这件事由谁负责。

用 Docker 部署的:构建入口变了

Dockerfile / docker-compose.yml / .dockerignore 已移出,改由 ai-memory-docker 的 Dockerfile.web 构建:

git clone --recurse-submodules https://github.com/dpkg-s/ai-memory-docker.git
cd ai-memory-docker
docker compose up -d --build     # ai-memory(8700) + ai-memory-web(8811)

镜像内容不变,原来跑着的容器不用动。

不用 Docker 的:什么都不用做

README 现在讲什么

不再教 docker build,改为列控制台对镜像的运行时契约 —— 入口 serve_web.py、端口 AI_MEMORY_WEB_PORT、状态目录 AI_MEMORY_WEB_CONFIG_DIR、上游 MCP AI_MEMORY_WEB_MCP。怎么构建归容器仓,控制台只承诺这几个接口,两边不再各写一半。

不受影响

serve_web.py / web_console.py / web/ 的资源与行为一字未改,v1.11.1 的守卫修复与 _mcp_error_text() 依旧有效。

破坏性变更

无。唯一需要动作的是自建镜像的人,改一下构建入口即可。

校验

附件 用途
web-console-v1.11.2.tgz 控制台源码包,解压即用
ai-memory-setup.exe Windows 快捷安装器,与核心仓同一个文件
4a578040377fe50fa8ca144ae3f02255d350461b95f053358ad66d56ec0850ab  web-console-v1.11.2.tgz
a52ca45373f8bfe21bfdbebc9b21afe91f40d7fe3f9c14f4961e8d2a7a3e3b1f  ai-memory-setup.exe

v1.11.1 — 非回环守卫不再打回自己人,MCP 报错能看见真正原因

Choose a tag to compare

@dpkg-s dpkg-s released this 22 Oct 10:52

这一版全部是控制台自身的修复:一个把容器挡在门外的认证守卫,一个只会显示
ExceptionGroup: unhandled errors in a TaskGroup (1 sub-exception) 的错误包装。

Fixed

非回环监听 + 账号登录,被自家守卫打回 exit 2

非回环地址的认证守卫只看 AI_MEMORY_WEB_TOKEN,而且写在登录配置解析之前。
可服务的标准形态恰恰是「HOST=0.0.0.0 + 账号登录、不给 token」(令牌是给脚本用的,
不该塞给浏览器用户)—— 于是进程一起来就被自己打回:

[web] 配置错误:监听非回环地址 '0.0.0.0' 时必须设置 AI_MEMORY_WEB_TOKEN …   → exit 2

改法:守卫移到登录配置解析之后,判据变成「token 或账号登录至少一道」。

守卫要防的是「裸奔:局域网内谁都能打开调试台写记忆库」,两道认证任一成立都不算裸奔;
只配半截(给了 USER 没给口令)依旧 rc=2,不放水。

启动提示语与事实相反

serve_web.py 只判 auth_enabled(token),在「0.0.0.0 + 账号登录」下会打印
「未设 token:仅回环可访问」,恰好说反。改为按两道认证分别措辞。

Added

_mcp_error_text() —— 把多层异常下钻到叶子

streamablehttp_client 抛的常是 ExceptionGroup: unhandled errors in a TaskGroup (1 sub-exception),
真正原因藏在子异常里,界面显示这句等于没提示。现在逐层下钻到叶子异常再显示;
碰到 421 时追加一句「把 host:port 写进 MCP 侧的 AI_MEMORY_HTTP_ALLOWED_HOSTS,
该变量是替换语义」。已接入 health / tools / overview / 阈值 / 调用共 9 处。

回归 4 条(tests/test_web.py A3b~A3e)

用例 断言
A3b 非回环 + 账号登录 ⇒ 放行
A3c 首次启动把初始 admin 落盘,且磁盘上没有明文口令
A3d 二次启动不重建账号(改过的口令不被环境变量打回)
A3e 非回环 + 只给 USER ⇒ 仍拒绝

测试里把 config / users / tokens 全钉到临时目录,不碰宿主机 ~/.ai-memory-web。

Note

  • 421 Invalid Host header 的成因在 MCP 侧 —— MCP 的 streamable HTTP transport 默认只放行
    127.0.0.1 / localhost / [::1] 作为 Host(防 DNS rebinding)。实测同一 IP:端口只换
    Host 头:127.0.0.1:8700 → 200,host.docker.internal:8700 → 421。放行方式在 MCP 侧,
    完整说明见 docker 仓 README。
  • 源码侧接口未变:AI_MEMORY_WEB_HOST/PORT/TOKEN/USER/PASSWORD、AI_MEMORY_WEB_MCP、
    AI_MEMORY_WEB_CONFIG_DIR 语义一字未动,升级无迁移成本。

v1.11.0 — 容器定义进仓库:Dockerfile + compose + 开箱即可登录

Choose a tag to compare

@dpkg-s dpkg-s released this 22 Oct 12:41

主题:把「跑起来」这件事收进仓库。此前容器镜像是在设备上手工 docker build -f Dockerfile.offline 拼出来的,仓库里没有任何容器定义 —— 换台机器就得重新摸一遍。这一版补上 Dockerfile / docker-compose.yml / .dockerignore,并把默认账号定成 admin / password,开箱即可登录。

Added

  • Dockerfile —— python:3.13-slim 基座,pip install -r requirements.txt 单独成层(改源码不重装 mcp);非 root 运行(uid 10001);/config 为唯一可写目录并声明为卷;EXPOSE 8811。
    • 默认账号:AI_MEMORY_WEB_USER=admin / AI_MEMORY_WEB_PASSWORD=password 写进镜像 ENV。它只是首次启动的种子 —— web_console 只在 /config/users.json 为空时用它建初始管理员,落盘为 scrypt 哈希;一旦改过口令,环境变量即失效(否则每次重启都会把口令打回默认值)。
    • 探活打 /api/session,不是 /api/health:开启登录后后者要 401,拿它做 healthcheck 会让容器被反复判死。
  • docker-compose.yml —— docker compose up -d --build 即起;/config 落命名卷,/vault 只读挂载留成注释(按需打开);上游 MCP 用 AI_MEMORY_WEB_MCP 指到容器外(容器内的 127.0.0.1 是它自己)。
  • .dockerignore —— 排除 .git / tests / __pycache__ / *.tgz,镜像里不放测试与发布件。
  • README「容器运行(Docker)」一节 —— 构建/运行命令、默认账号表、两个挂载点的作用、默认口令的失效语义,以及「口令以 ENV 形式进镜像层,docker inspect 能看到」这条风险提示。

Note

  • 离线设备(h29k)仍用设备侧 Dockerfile.offline(基座镜像已装好 mcp):本文件的 pip install 需要网络,离线构建会在那一步失败。

完整变更:CHANGELOG.md

v1.10.0 — 圆形扩散回来了:自研「底片挖孔」

Choose a tag to compare

@dpkg-s dpkg-s released this 22 Oct 12:41

主题:圆形扩散回来了,而且和开关真正同时。上一轮把扩散撤掉是因为浏览器 View Transition 会冻结整页快照;这一轮不再用它 —— 自己造一张「旧主题底片」盖在页面上,在底片中央挖一个不断扩大的圆孔,底片下面是实时页面。于是扩散扫到哪里,那里的开关就在演。

Added

  • 自研圆形揭示(底片挖孔)(core/theme.js + 6-anim.css 末段)—— 点击瞬间:
    1. 克隆 body 子树成一张底片,把旧主题的 token 逐个写进行内样式(html.theming 那条降级路径不再参与主流程);
    2. 底片 position:fixed 盖满视口,mask: radial-gradient(...) 在开关圆心留半径 --vt-r 的透明孔;
    3. 提交新主题 → 底层是活页面,开关的 GSAP timeline 从第 0 帧起跑;
    4. 圆孔 0 → 视口外接圆,0.45s。
    • 开孔与滑块同一帧:startReveal() 挂在 timeline 的 onStart 上 —— 那一 tick 正是滑块被画到第一帧的时刻。theme.js 里另留 150ms 兜底(拿不到 gsap / 组件没挂时自己开孔)。
    • 为什么不再用 document.startViewTransition:VT 的快照是位图且冻结,页面内元素在那段时间不可见也不可动 —— 「同时」它在物理上做不到(2.x 跳过帧、2.1 试过错后 671ms、4.0 试过顺序化)。

Fixed

  • 底片取不到 token(本轮实测抓到的坑)—— 用 getComputedStyle(documentElement) 遍历自定义属性一个都拿不到(实现上不在枚举列表里),克隆体于是继承到刚提交的新值,底片变成新主题,圆孔挖开等于什么都没变。改法:遍历 document.styleSheets,把 html[data-theme=...] 规则声明过的 --* 名字抠出来再逐个取计算值(实测拿到 58 个,底片 --bg = #0b0c0d、卡片 rgb(16,17,18),与旧主题一致)。
  • 滚动位置与 canvas:克隆体默认回到顶部,逐节点同步 scrollTop/scrollLeft;canvas 用 drawImage 补像素(跨域污染的跳过)。

完整变更:CHANGELOG.md

v1.9.1 — 同一帧起跑,并给连点上锁

Choose a tag to compare

@dpkg-s dpkg-s released this 22 Oct 12:41

主题:把「同一帧起跑」写死,并给连点上锁。三条要求来自主人:页面换色与开关动画必须同帧开始、这期间不可再点、开关演完后等 0.3s 才收窄。

Changed

  • 门控点 0.45s → 0.95s、摘锁延迟 150ms → 300ms(ThemeSwitch.js)—— 0.95s 是滑块回弹段结束(0→66 用 0.45s、66→63 用 0.5s),也就是肉眼上「开关演完了」的时刻;再等 300ms 才摘 data-anim,胶囊开始收窄。点击到可收纳 0.6s → 1.25s。
    • 不等星星闪烁的尾巴(到 2.55s):星星在画面上方、滑块在右侧,收窄后窗口覆盖 59~101,月亮始终在窗内,等它只是白让开关「大着不动」。

Added

  • 动画期间互斥(ThemeSwitch.js)—— _busy 在 timeline 建立时置位、在主段结束(0.95s)清位;toggle() 与 followSystem() 先判 _busy 早返回。连点不再「kill 旧 timeline → 门控重新加锁 → 滑块抖一下重来」,右键恢复跟随系统同样被拦。

完整变更:CHANGELOG.md

v1.9.0 — 撤掉圆形扩散,改回单时钟

Choose a tag to compare

@dpkg-s dpkg-s released this 22 Oct 12:40

主题:撤掉圆形扩散,回到单时钟。1.8.0 的扩散本身好看,但它与开关动画在物理上无法同步 —— View Transition 期间整页是一张静态快照,开关被冻在快照里,扩散期间不存在任何可见的活体动画。于是只剩两条路:跳帧(1.8.0 之前)或错后(1.8.0)。实测错后 671ms,比跳帧更像不同步。这一次把页面换色和开关放回同一条时钟:同帧起跑、同帧收尾。

Changed

  • 主题切换改回单时钟渐变(core/theme.js 重写 + 6-anim.css 末段重写)—— 页面换色 0.45s、缓动 --ease-in-out,与开关 timeline 的滑块首段(0.45s、power2.inOut)完全一致,两者同一帧起跑。没有快照 ⇒ 没有冻结 ⇒ 既无跳帧也无滞后。
    • 为什么放弃 View Transitions:VT 期间原 DOM 不可见。让 timeline 照常跑 ⇒ 揭示完成瞬间画面从第 0 帧跳到第 0.55s 帧(滑块像被抽了一下);让 timeline 暂停等 ⇒ 页面先换完、开关 0.55s 后才补演。探针实测(真实时钟):页面 t≈108ms 已换、滑块 t≈779ms 才起跑,错位 671ms。整页快照下「有扩散」与「有同步」不可兼得。
    • html.theming * 而非容器白名单:只过渡容器的话,文字色会先在旧底色上跳到新色,那 0.2s 里白底白字。代价是 0.51s 内全站元素的 transition 属性列表被改写 —— 因此门控 .tsw[data-anim="1"](特异性 0,2,0 > 0,1,1)必须压住本规则,否则开关收窄的 width 过渡被顶掉、变成瞬跳。
    • 一切延迟归零:1.8.0 降级路径的三层错峰(0/60/80/140ms)已删除 —— 错峰本身就是「不同步」。
  • 门控点 0.65s → 0.45s(ThemeSwitch.js)—— 0.65s 里的 0.2s 余量是留给 VT 的,VT 撤掉后一并去掉。点击到可收纳 1.35s → 0.6s。

Removed

  • core/theme.js 的 vtBusy() / whenVtDone() / setOrigin() / resolveOrigin() 与 --vt-x/--vt-y/--vt-r 三个 CSS 变量、::view-transition-* 与 @keyframes theme-reveal —— 一并删除,不留死代码。
  • applyTheme(pref, origin, silent) 的 origin 参数(圆形扩散的圆心,已无用途);ThemeSwitch.toggle() / followSystem() 不再计算按钮矩形。

完整变更:CHANGELOG.md

v1.8.0 — 主题开关与切换串行 + 从开关圆心扩散揭示

Choose a tag to compare

@dpkg-s dpkg-s released this 22 Oct 12:40

这一版解决什么

主题开关上有两个独立动效:悬停收窄(收纳)和点击切换。它们各跑各的时钟 ——
收窄是 CSS 过渡(width / left,0.5s),切换是 GSAP timeline。更麻烦的是
.tsw.night .tsw-box { left: -59px } 是类切换即生效的终态值,不看 timeline
播到第几帧。

于是点击后稍一移开鼠标:窗口先左移 42.48px,滑块还在半路,收窄后那 30.24px
窗口里只剩空天空 —— 月亮被切成一半再滑出来,连点两次还会错位叠加。

v1.8.0 把两条时钟串成一条(门控),把主题切换改成从开关圆心扩散,并让扩散与
开关动画串行而不是各演各的。

变化

门控串行

  • timeline 播放期间锁 data-anim="1":窗口锁定为全展开、禁用过渡;
  • 滑块第一段落定(0.65s)后解禁,再延 150ms 摘锁;
  • 为什么不等第二段(0.45→0.95 的 66→63 微调):门控要防的是「窗口按终态左移
    42.48px 而滑块还在半路」,0.45s 后滑块已在 66、占 66102,收窄窗口覆盖
    59
    101,月亮完整在窗内,3px 微调不会跑出窗口;
  • 收窄 0.5s → 0.62s、ease-in-out → ease-expo。

主题圆形扩散

  • View Transitions:clip-path: circle() 以开关中心为圆心扩张揭示,0.55s;
  • 与开关动画串行:VT 期间整页是静态快照,原 DOM 不可见。timeline 若照常起跑,
    观众看到的是「定格 → 揭示完成瞬间跳到第 0.55s 帧」,滑块像被抽了一下 —— 这是
    「两段动画不融洽」的真正来源。现在扩散在跑时 timeline 以 paused 创建,扩散
    结束(含 rejected / 超时兜底)后由 whenVtDone() 放行;
  • 0.55s 与滑块首段 0.45s 同频、缓动同族(power2.inOut ≈
    cubic-bezier(.65,0,.35,1))—— 一快一慢会让「页面已换完、开关还在爬」;
  • 不支持 VT(或 prefers-reduced-motion)时回落三层错峰:顶栏 0ms /
    侧栏 60ms / 状态栏 80ms / 主区 140ms 颜色过渡;两套互斥、绝不并行;
  • 首屏不演,系统主题自动跟随也不演。

时间轴整体压缩

滑块 0.6+0.9 → 0.45+0.5,天空 0.6→0.5,云/星/月同步收紧,光晕 0.6+0.7 → 0.5+0.5。
原时序是 WPF 原文 1:1 移植,本次按需求加快;首段/回弹段的比例关系不变。

点击后可开始收纳:约 1.35s(0.55 扩散 + 0.65 门控 + 0.15 摘锁),改前是 2.05s
且带跳帧。

修掉一个 Vue 反模式

lock() 加的类会被 Vue 抹掉。原因:模板是 class="tsw" :class="{night: night}",
Vue 3 的 options watch 默认 flush:'pre' —— watch 先跑(加类成功),紧接着本组件
的 patch 重算 :class,把整个 class 属性覆写回去。探针证据:classList.add("animating")
调用过 1 次,60ms 后 classList 里没有它,MutationObserver 只看到 tsw > tsw > tsw。
改用 data-anim 属性(不在 diff 目标里)后,同一探针读到 w=72px / left=0px。

Breaking Change

网关鉴权从「比对单枚 env token」改为 auth_request 回调控制台
/api/internal/token/verify,两侧需同时设置 AI_MEMORY_WEB_INTERNAL_KEY。
容器部署必须重建容器 —— docker restart 不会应用新的 -e。

升级

# 源码部署
git pull && 重启服务(后端改动需重启进程;web/ 静态资源保存即生效)

# 容器部署
docker build -t web-console:1.8.0 .
docker rm -f ai-memory-web && docker run …(按旧容器 inspect 复原,替换镜像 tag)

校验

  • 本地回归:tests/test_web.py 87 passed / 0 failed;
  • 设备实测:镜像 fafa1c007f8a(186MB),启动日志 [web] ai-memory 控制台 v1.8.0,
    /api/config 返回 version: 1.8.0,/api/health 200,四容器全 Up;
  • 静态资源 sha256:theme.js / ThemeSwitch.js / 6-anim.css / 3-components.css
    4/4 与本地一致;
  • 动效探针(mock 后端 + 无头 Chrome):timeline 以 paused 创建、扩散结束后
    play() 被调用 1 次、门控期间宽度锁在 72px 且窗口 left=0。

v1.2.0 — 进控制台自动检查更新,有新版会提示

Choose a tag to compare

@github-actions github-actions released this 19 Oct 03:23

新增

  • 进控制台自动检查更新 —— 后台跑一次,不阻塞首屏,失败静默;一次页面会话最多联网一次。有新版时弹一条提示(带版本号),并在侧栏「配置」右上角留一个圆点,直到更新完成或再检测已是最新。
  • 同时检查两个目标 —— 控制台本身与核心程序各查各的、各更各的,两块卡片分开显示;某个目标定位不到时也留一张卡说明原因,不静默少一块。

修复

  • 刚联网查到的版本会瞬间退回「未检查」 —— 进「关于」页或点「只读本地」时,本地状态的更新覆盖了刚拿到的远端结论。现在远端结论会保留,本地字段照常更新。
  • 「远端版本」分不清「没联网」和「联网失败」 —— 原来两者都显示「(未检查)」。现在分三态:(未检查) / 检查失败(原因见下方) / 已检查,未取到提交号;拿到提交号时正常显示 vX.Y.Z <短提交号>。

升级方式

覆盖安装或替换源码后重启控制台。已在界面上配过的记忆库路径不受影响。

破坏性变更

无。

v1.1.0 — 阈值改由 MCP 读写;连核心程序不再靠猜路径

Choose a tag to compare

@dpkg-s dpkg-s released this 19 Oct 03:26

变化

  • 阈值读写改走 MCP 工具 —— 控制台不再自己读改 memory.toml,改为调用核心程序的 memory_config 工具。校验、写前备份(同目录 memory.toml.bak.<时间戳>,保留最近 10 份)、原子替换都交给服务端统一完成,界面契约没变。
    • 需要核心程序为 v3.0.0 或更高。
  • --with-mcp 必须显式指定核心程序目录 —— 不再自动猜路径(猜错时的症状是连上一个空库、还一切正常)。用 --core-dir <路径> 或环境变量 AI_MEMORY_CORE_DIR;不给会直接报错并打印可照抄的命令。
  • 只读开关语义明确 —— AI_MEMORY_WEB_CONFIG_WRITE=0 时界面仍能看阈值,但不能保存。

升级方式

serve_web.py --with-mcp --core-dir <核心程序目录>

从安装器装的,重新跑一遍安装器即可,它会写对路径。

破坏性变更

--with-mcp 不再自动定位核心程序,需要补 --core-dir 或 AI_MEMORY_CORE_DIR。