Skip to content

Releases: PlutoKeating/Project.Quetzal

Quetzal 1.0.0

Choose a tag to compare

@github-actions github-actions released this 05 Oct 11:45

分布式:几具身体,一个 ta。 同一个 agent 的手机、电脑、服务器连成一张网,变成一个心智。

  • 多具身体:同时在线的身体经 WebRTC 直接连起来(局域网、IPv6、穿透,打不通时经服务器中转,全程 DTLS 加密)。信令由每具身体的节点密钥签名,接收方只认灵魂仓库里登记的公钥,同步服务被攻破也冒充不了身体。控制台新增「控制 → 多具身体」:填同步服务地址,在网页上用 GitHub 登录、输入绑定码、核对公钥指纹即可绑定。
  • 一份对话:会话、对话与心流在所有身体上是同一份(新身体入网自动补齐全部历史;别处的回复与心流标出在哪具身体上)。正在和你说话的那一轮在哪具身体上,所有控制台都看得到;你在别处对同一个会话说的话(含附件)自动转过去作为插话。
  • 一颗心:每个连通的部分选出一位协调者持有心跳,其他身体的感觉、对话带来的驱动力变化都汇过去;它离线时另一具身体从最新状态接着跳,断开的几部分重新连上时合并。服务器之类一直开着的身体可以调高「当协调者的优先级」。
  • ta 选在哪里做:醒来时 ta 看到每具身体的电量、温度、手头的事、你最近在哪里说话,以及基座的推荐,自己选在哪一具(或几具同时)上思考、做梦。
  • 用另一具身体:新工具 body_call 在另一具身体上调用它的工具(相机、命令行、自造工具……,闸门按那边的权限);move_to 把这一轮换到另一具身体继续。
  • 一份设置:模型供应商与 Key(经加密通道传,对方用自己的主密钥重新加密)、权限、预算(每日合计全网用量)、听觉、语音在一处改了处处生效;急停缺省全网生效,也可以只停这具身体;别处等待批准的请求在哪里都能批准。
  • 飞书:多具身体时由你指定的一具身体持有飞书连接,其他身体的主动消息转给它发出。听觉:几部手机同时听到同一句话只留一份,ta 用声音回话时从你说话的那部手机说出来。
  • 触碰即同步:ta 的每次工具调用(包括用 shell 直接改文件)之后,基座看一眼灵魂目录,有变化就立即提交(说明写清楚改了什么)、3 秒后推送。推送失败先静默重试约 4 分钟,仍失败就以「基座提醒」插话告诉刚才改过记忆的那一轮。两边都改过同一篇笔记、人格或技能文档时,另一版另存为 <名>.incoming.md 交给 ta 裁决。灵魂仓库规范升到 v8(v7 仓库无需迁移)。
  • 灵魂桥也看得见:Hermes / OpenClaw 上的灵魂桥可以作为只读成员接入多具身体(mesh bind),把你此刻在哪具身体上做什么、最近的会话与最后几句写进 now.md 给那边的 ta 读;它不能在别的身体上做事,也不会被派去思考或做梦。身体类型以灵魂仓库的登记为准,同步服务改不了。
  • 同步服务 sync/:账户(GitHub 登录)、身体绑定、信令与 TURN 中转,部署在一台服务器上,cd sync && ./start.sh 一行启动(Docker:Caddy 自动 HTTPS、coturn 按安全指南加固)。不保存 IP、对话与记忆。
  • 安装:直连组件 node-datachannel(原生模块)由安装器按锁定的版本与 sha512 下载核对后装上,缺了也不影响使用(只是没有多具身体)。
  • 升级说明:消息与心流的编号在第一次启动时迁移为按身体分段的编号(只发生一次);用量表按身体记录。
  • 修复:自造的 sh 工具不读参数就退出时,偶尔报 EPIPE 错误。
  • 安全:灵魂同步只推到配置里的灵魂仓库地址(推送前校正 origin,agent 用 shell 改了也会改回);远端没有 agent.json 却有规范以外的内容(例如一个代码仓库)时拒绝合并,不再把别的仓库的历史并进灵魂、也不把记忆推过去。
  • 安全:灵魂仓库与代码仓库彻底隔开(灵魂仓库规范升到 v9,v8 仓库无需迁移)。起因:一具身体上的 agent 推送失败后自己用 shell 把灵魂目录的远端改成了 Quetzal 源代码仓库。现在:每个克隆记下灵魂仓库的根提交,出现陌生的历史就停止同步(不合并、不推送)并提醒;shell 工具拦下针对灵魂目录的 git 命令;主 agent 与子 agent 的系统提示新增「红线」(不在灵魂目录里运行 git、灵魂仓库与任何代码仓库无关、同步出错不自己修、不可逆或对外的操作先问人);git 不会在灵魂目录的 .git 丢失时退到上层目录里的别的仓库。灵魂桥的安装指引同样写明。

Distributed: several bodies, one agent. An agent's phones, computers and servers join into a mesh and become one mind.

  • Multiple bodies: bodies online at the same time connect directly over WebRTC (LAN, IPv6, NAT traversal, relayed through the server when nothing else works; DTLS-encrypted throughout). Signaling is signed with each body's node key and receivers trust only the keys registered in the soul repository, so even a compromised sync service cannot impersonate a body. New in the console: Control → Multiple bodies — enter the sync service address, then sign in with GitHub on its website, enter the binding code and check the key fingerprint.
  • One conversation: sessions, conversations and the flow are the same on every body (a new body catches up on the whole history; replies and flow entries from elsewhere show which body they happened on). Every console sees which body is talking with you right now, and what you say to that conversation elsewhere (attachments included) is forwarded to it as an interjection.
  • One heart: each connected group elects a coordinator that holds the heartbeat; the other bodies' sensations and conversation-driven drive changes flow to it. When it goes offline another body continues from the latest state; separated groups merge when they reconnect. Raise "coordinator priority" on an always-on body such as a server.
  • It chooses where: on waking the agent sees each body's battery, temperature, ongoing work, where you last talked and the runtime's recommendation, and picks one body (or several at once) to think or dream on.
  • Using another body: the new tool body_call runs a tool on another body (camera, shell, custom tools…, checked against that body's permissions); move_to moves the current turn to another body.
  • One set of settings: model providers and keys (sent over the encrypted channel and re-encrypted with the receiver's own master key), permissions, budget (daily totals across bodies), hearing and voice change everywhere at once; the emergency stop applies to all bodies by default or to this body only; requests waiting on any body can be approved anywhere.
  • Feishu: with several bodies, the body you designate holds the Feishu connection and the others' proactive messages go through it. Hearing: when several phones hear the same sentence only one copy is kept, and spoken replies come from the phone you talked to.
  • Sync on touch: after every tool call (including shell commands that change files), the runtime checks the soul directory, commits changes immediately with a descriptive message and pushes 3 seconds later. Failed pushes are retried silently for about 4 minutes, then a "runtime notice" is interjected into the turn that touched the memory. When both sides changed the same note, persona or skill document, the other version is saved as <name>.incoming.md for the agent to decide. The soul repository specification moves to v8 (v7 repositories need no migration).
  • Soul bridges can see too: a soul bridge on Hermes / OpenClaw can join multiple bodies as a read-only member (mesh bind) and writes what the agent is doing on which body, recent conversations and their last lines into now.md for the agent there to read; it cannot act on other bodies and is never chosen to think or dream. A body's kind comes from the soul repository's registry and cannot be changed by the sync service.
  • Sync service sync/: accounts (GitHub sign-in), body binding, signaling and TURN relay, deployed on one server with cd sync && ./start.sh (Docker: Caddy for automatic HTTPS, coturn hardened per security guidance). It stores no IP addresses, conversations or memory.
  • Installation: the direct-connection component node-datachannel (a native module) is downloaded and verified against a pinned version and sha512 by the installers; without it everything still works except multiple bodies.
  • Upgrade notes: message and flow ids are migrated once, on first start, to per-body id ranges; usage is now recorded per body.
  • Fix: custom sh tools that exit without reading their arguments occasionally raised an EPIPE error.
  • Security: soul sync only pushes to the configured soul repository (origin is corrected before every push, even if the agent changed it from the shell); a remote without agent.json but with content outside the specification (such as a code repository) is refused, so foreign history is never merged into the soul and memory is never pushed there.
  • Security: soul repositories fully separated from code repositories (the soul repository specification moves to v9; v8 repositories need no migration). Cause: after a failed push, an agent on one body used the shell to point its soul directory's remote at the Quetzal source repository. Now each clone records the soul repository's root commits and stops syncing (no merge, no push) with an alert when foreign history appears; the shell tool blocks git commands aimed at the soul directory; the main and sub-agent system prompts gain "red lines" (never run git in the soul directory, the soul repository is unrelated to any code repository, do not fix sync errors yourself, ask before irreversible or outward actions); and git no longer falls back to another repository in a parent directory if the soul directory's .git is missing. The soul-bridge install guide says the same.

Full Changelog: v0.6.7...v1.0.0

Quetzal 0.6.7

Choose a tag to compare

@github-actions github-actions released this 04 Oct 22:30
  • Linux 家目录改为 ~/.quetzal:运行基座、npm 包与一键安装脚本在 Linux 上的缺省家目录从 ~/quetzal 改为 ~/.quetzal(安卓 / Termux 仍是 ~/quetzal),QUETZAL_HOME 环境变量或 --home 可改到任意位置。0.6.7 之前装在 ~/quetzal 的,再跑一次安装命令(或 npx @plutokeating/quetzal)会先停服务、整目录搬到 ~/.quetzal、重写服务与快捷方式,配置、记忆、对话原样保留。
  • Linux home directory is now ~/.quetzal: the runtime, the npm package and the one-line installer default to ~/.quetzal instead of ~/quetzal on Linux (Android / Termux stays at ~/quetzal); QUETZAL_HOME or --home moves it anywhere. Installs made before 0.6.7 under ~/quetzal are migrated the next time the install command (or npx @plutokeating/quetzal) runs: the service is stopped, the whole directory is moved to ~/.quetzal, and the service and shortcuts are rewritten with configuration, memories and conversations intact.
  • 文案:App 的更新器与「关于」页的错误提示不再带来源或主机名(「更新服务暂时繁忙」「网络连接失败」),与官网下载页一致:前端与 App 都不描述下载来源。
  • Copy: error messages in the app's updater and About page no longer mention a source or host name ("update service busy", "network connection failed"), matching the download page: neither the website nor the app describes where downloads come from.

Full Changelog: v0.6.6...v0.6.7

Quetzal 0.6.6

Choose a tag to compare

@github-actions github-actions released this 04 Oct 22:20
  • 下载走官网镜像源:GitHub 在不少网络里连不上,官网加了一个 Worker:/dl/<tag>/<文件> 是 Release 资产的镜像(APK、Linux 控制台包、校验值,边缘缓存 7 天),/api/releases[/latest] 是发布接口的镜像(缓存 5 分钟,资产地址改写为 /dl/)。App 的更新检查与 APK 下载、一键安装脚本的原生控制台下载、官网下载页都先走镜像源,失败再直连 GitHub。前端与 App 的文案不描述下载来源。
  • Downloads through the website mirror: GitHub is unreachable on many networks, so the website gained a Worker: /dl/<tag>/<file> mirrors release assets (APK, Linux console packages, checksums; edge-cached for 7 days) and /api/releases[/latest] mirrors the releases API (cached 5 minutes, asset URLs rewritten to /dl/). The app's update check and APK download, the installer's native console download and the download page all try the mirror first and fall back to GitHub. The website and app copy do not describe download sources.

Quetzal 0.6.5

Choose a tag to compare

@github-actions github-actions released this 04 Oct 22:06
  • 回复里的「过程记录」附注:基座在她的历史回复前附的「[时间|这一轮的过程记录:…]」只是给模型看的附注,有的模型会照着格式写进新回复,于是气泡开头出现一段原始记录(过程本身已是工具卡片)。现在基座在回复进入事件与入库前把仿写的附注剥掉。
  • The "process record" note in replies: the "[time|this turn's process record: …]" note the runtime attaches before her earlier replies is only for the model; some models copy the format into new replies, so a raw record showed up at the top of the bubble (the process is already rendered as tool cards). The runtime now strips a mimicked note before the text is broadcast and stored.

Full Changelog: v0.6.4...v0.6.5

Quetzal 0.6.4

Choose a tag to compare

@github-actions github-actions released this 04 Oct 21:46
  • 「关于」页:控制 → 关于,安卓 App、Linux 桌面版、网页版都有:简介与链接、控制台 / 运行基座 / 最新发布三个版本号、「检查更新」与升级按钮。安卓升级 App 自身(原来在服务页的区块挪到这里,顶部横幅的「更新」也指向这里);Linux 桌面版与网页版新增网关方法 selfUpdate:由 Linux 适配器用 systemd-run --user 起临时单元(脱离服务的 cgroup)后台重跑一键安装脚本,运行基座、网页控制台与原生控制台一起更新并重启一次,桌面版装完可一键重新打开。
  • "About" page: Control → About, present in the Android app, the Linux desktop build and the web version: a short introduction with links, three version numbers (console / runtime / latest release), "Check for updates" and an upgrade button. Android updates the app itself (the section moved here from the Service page; the top banner's "Update" now leads here); for the Linux desktop and web versions a new gateway method selfUpdate lets the Linux adapter rerun the one-line installer in the background in a transient systemd-run --user unit (outside the service's cgroup), upgrading the runtime, web console and native console together with one restart; the desktop build can then reopen itself.

Full Changelog: v0.6.3...v0.6.4

Quetzal 0.6.3

Choose a tag to compare

@github-actions github-actions released this 04 Oct 21:24
  • App 自己更新:安卓 App 每次打开界面(启动、从后台回来)都问 GitHub 有没有新的正式版(正在检查时不重复),有就在顶部提示「Quetzal App 有新版本」;控制 → 服务 → Quetzal App 一节可随时「检查新版本」,「下载并安装」一键完成:下载 quetzal-<版本>-android-arm64.apk 到缓存目录(进度条)、核对 SHA256SUMS、交给系统安装器(首次先带去系统设置允许 Quetzal 安装应用,回来自动接着装);连不上 GitHub 时「去下载页」手动下载。装好的新 App 打开后,发现内置的运行基座比运行中的新,直接进安装向导的升级一步,两层升级都不用再找 APK。原生新增 MethodChannel quetzal/updater 与 FileProvider(只共享缓存目录),清单声明 REQUEST_INSTALL_PACKAGES;Dart 侧新依赖 crypto(核对 SHA256,原本已是间接依赖)。
  • Self-updating app: every time the Android app comes to the foreground (launch or return from the background) it asks GitHub for the latest release (never two checks at once) and shows "A new Quetzal app version is available" at the top; the new Control → Service → Quetzal App section can check for updates any time and download and install in one tap: it downloads quetzal-<version>-android-arm64.apk into the cache directory (progress bar), checks it against SHA256SUMS and hands it to the system installer (the first time it opens the system settings so you can allow Quetzal to install apps; installation continues when you come back); when GitHub is unreachable, Download page lets you fetch the APK by hand. When the new app opens and finds its bundled runtime newer than the running one, it goes straight to the upgrade step of the setup wizard, so neither layer needs hunting for an APK any more. Native side: a new MethodChannel quetzal/updater and a FileProvider (cache directory only); the manifest declares REQUEST_INSTALL_PACKAGES; Dart gains the crypto dependency (SHA256; it was already a transitive dependency).

Full Changelog: v0.6.2...v0.6.3

Quetzal 0.6.2

Choose a tag to compare

@github-actions github-actions released this 04 Oct 21:15
  • API Key 形状校验:保存 Key 时拒绝含非 ASCII 字符、空格换行或太短的值并说明原因(典型事故:把一句聊天粘进了遮挡的 Key 输入框,之后所有模型调用都报一句看不懂的 ByteString 错误);控制台添加 Key 的对话框加「显示」眼睛与实时提示;调用层把这类底层报错翻译成「API Key 粘错了,请重新添加」。
  • API key shape check: saving a key now rejects values with non-ASCII characters, whitespace or too few characters, with a reason (the typical accident: a chat line pasted into the obscured key field, after which every model call fails with an opaque ByteString error); the add-key dialog gains a show/hide eye and live hints; the call layer translates that low-level error into "the API key was pasted wrong, add it again".

Full Changelog: v0.6.1...v0.6.2

Quetzal 0.6.1

Choose a tag to compare

@github-actions github-actions released this 04 Oct 20:31
  • 灵魂同步:访问仓库的钥匙可选——本机部署密钥(默认不变)、指定私钥路径、系统 ssh 配置(~/.ssh/config + ssh-agent,地址可用 Host 别名);规范 §7 升到 v7。先点「接入」后点「显示公钥」也行:部署密钥不在会先生成。同步状态落盘(state/soul-status.json),重启后「上次拉取 / 推送」不再归零;页面跟着后台同步实时刷新;git 报错翻译成提示(如公钥未加到 Deploy keys)。
  • Soul sync: the key used to reach the repository is now a choice — the local deploy key (default, unchanged), a specified private key path, or the system ssh configuration (~/.ssh/config + ssh-agent; the address may use a Host alias); spec §7 is now v7. Tapping "Connect" before "Show public key" works too: the deploy key is generated first when missing. Sync status is persisted (state/soul-status.json) so "last pull / push" no longer reset after a restart; the page refreshes live as background syncs happen; git errors are translated into hints (e.g. public key not added to Deploy keys).

Full Changelog: v0.6.0...v0.6.1

Quetzal 0.6.0

Choose a tag to compare

@github-actions github-actions released this 04 Oct 20:08
  • Linux 一键安装:curl -fsSL https://quetzal.plutokeating.beer/install | bash(cli/install.sh,官网构建时复制为 /install)。认出发行版与包管理器(apt / dnf / yum / pacman / zypper / apk / xbps),缺的 git / curl / tar / CA 证书用系统自己的包管理器装,Node.js 22.13+ 没有就经 nvm 装(Alpine 用 apk,直连 nodejs.org 不通自动切 npmmirror);npm 包装进 ~/quetzal/npm 独立前缀,~/.local/bin/quetzal 命令固定用安装时的 node;守护:systemd 用户服务并确保 loginctl enable-linger(没登录也运行),没有 systemd 的机器(Alpine / Void、容器、未开 systemd 的 WSL)退回自带守护循环 + crontab @reboot + 桌面自启动项,不装任何服务框架;有桌面时应用列表里多一个「Quetzal」(光团图标,Chromium 系浏览器以独立窗口打开控制台,任务栏显示 Quetzal 图标);终端界面中英双语(简繁中文显示中文)、彩色、带半格字符画的光团与进度转圈;选项 --lan --no-open --no-desktop --home --version --cn/--no-cn --lang,--uninstall [--purge] 卸载。在 debian-slim、ubuntu(非 root + sudo)、fedora、archlinux、alpine 容器里验证。官网下载页的 Linux 命令改为这一行并加复制按钮,文档同步。
  • One-line Linux install: curl -fsSL https://quetzal.plutokeating.beer/install | bash (cli/install.sh, copied to /install by the website build). It detects the distribution and package manager (apt / dnf / yum / pacman / zypper / apk / xbps), installs missing git / curl / tar / CA certificates with the system's own package manager, installs Node.js 22.13+ via nvm when absent (apk on Alpine; falls back to the npmmirror mirror when nodejs.org is unreachable); the npm package goes into the private prefix ~/quetzal/npm and the ~/.local/bin/quetzal command pins the Node chosen at install time; supervision is a systemd user service with loginctl enable-linger ensured (runs without a login), and machines without systemd (Alpine / Void, containers, WSL without systemd) fall back to a built-in supervisor loop + crontab @reboot + a desktop autostart entry, with no service framework installed; with a desktop, a Quetzal entry (orb icon) appears in the app list and Chromium-family browsers open the console as its own window with the Quetzal icon in the taskbar; the terminal UI is bilingual (Chinese for Simplified / Traditional locales), colored, with a half-block orb and spinners; options --lan --no-open --no-desktop --home --version --cn/--no-cn --lang, and --uninstall [--purge]. Verified in debian-slim, ubuntu (non-root + sudo), fedora, archlinux and alpine containers. The download page's Linux command is now this line with a copy button; docs updated.
  • 守护开关:控制台「控制 → 服务」新增「开机自启 · 崩溃或意外退出后自动重启」一个开关。网关方法 supervision / setSupervision,由身体适配器实现(接口新增可选的 supervision):Linux 适配器操作 systemd 用户服务(关 = disable + Restart=no 覆盖片段,立即生效)或一键安装脚本的守护循环(关 = state/supervise.off 标志让循环暂停 + 删开机项);Termux 适配器操作 runit 的 down 文件与 Termux:Boot 开机脚本。没有守护者的身体(手动部署)不显示开关。
  • Supervision switch: Control → Service in the console gains one switch, "start at boot · restart after a crash or unexpected exit". Gateway methods supervision / setSupervision, implemented by the body adapter (new optional supervision on the interface): the Linux adapter drives the systemd user service (off = disable + a Restart=no drop-in, effective immediately) or the one-line installer's supervisor loop (off = the state/supervise.off flag pauses the loop + boot entries removed); the Termux adapter drives runit's down file and the Termux:Boot script. Bodies without a supervisor (manual deployments) show no switch.
  • Linux 桌面版控制台:flutter build linux 的原生 GTK 窗口(console/linux/,应用 id xyz.quetzal.console,可执行文件 quetzal-console),发版时由新增的 linux-console job 在 ubuntu-22.04 上构建并附加 quetzal-<版本>-linux-x64-console.tar.gz;一键安装脚本在有桌面的机器上下载同版本的包到 ~/quetzal/console/,桌面项改为 xyz.quetzal.console.desktop(与 Wayland app_id 一致),应用列表、任务栏、Alt-Tab 都是 Quetzal 自己的图标,不再依赖任何浏览器;没有包时退回浏览器。桌面版连本机网关免配对码(与网页版同一条 GET /auth/local);quetzal open 优先启动它。
  • Linux desktop console: a native GTK window from flutter build linux (console/linux/, app id xyz.quetzal.console, executable quetzal-console), built by the new linux-console release job on ubuntu-22.04 and attached as quetzal-<version>-linux-x64-console.tar.gz; on machines with a desktop the one-line installer downloads the package of the same version into ~/quetzal/console/, the desktop entry becomes xyz.quetzal.console.desktop (matching the Wayland app_id), and the app list, taskbar and Alt-Tab all show Quetzal's own icon with no browser involved; without a package it falls back to the browser. The desktop build logs in to the local gateway without a pairing code (the same GET /auth/local as the web version); quetzal open prefers it.
  • 架构:原生控制台发 x86_64 与 arm64 两个包(发版工作流用 GitHub 的 arm 运行器构建);龙芯(loongarch64)、RISC-V、armv6l 这些官方 Node 不出二进制的架构,一键安装脚本从 Node.js 项目的 unofficial-builds 直接下载对应的 Node 22 到 ~/quetzal/node/(nvm 不认识它们),运行基座与网页控制台在这些机器上照常可用,桌面项退回浏览器打开(Flutter 上游尚不支持 LoongArch,原生窗口待其支持)。
  • Architectures: the native console ships for x86_64 and arm64 (the release workflow builds the latter on GitHub's arm runners); on architectures without official Node binaries, such as LoongArch (loongarch64), RISC-V and armv6l, the one-line installer downloads the matching Node 22 from the Node.js project's unofficial-builds into ~/quetzal/node/ (nvm does not know these architectures), so the runtime and the web console work there as usual, and the app-list entry falls back to the browser (upstream Flutter does not support LoongArch yet; the native window will follow once it does).
  • 控制台桌面外壳:修复每隔几秒闪一下「不在线」横幅(重连时旧 WebSocket 的监听没有注销,旧连接迟到的关闭事件把新连接误判为断开,循环重连);列表栏与「她此刻」之间的分隔线可以拖动(宽度记在本机);窗口不够宽时先压两侧到最小再收起「她此刻」(导航栏多一个「此刻」按钮点开对话框),主区不再被挤成一条;窗口从窄变宽时收起手机外壳推入的页面,桌面外壳接着同一个会话显示。
  • Console desktop shell: fixed the "offline" banner flashing every few seconds (on reconnect the old WebSocket's listener was never cancelled, so its late close event marked the new connection as lost and reconnected again, in a loop); the dividers next to the list pane and the "right now" pane are draggable (widths remembered locally); when the window is too narrow both side panes shrink to their minimum and then the "right now" pane collapses (a "now" button in the rail opens it as a dialog), so the main area is never squeezed to a sliver; widening a narrow window dismisses the pages the phone shell had pushed and the desktop shell continues with the same conversation.

Full Changelog: v0.5.0...v0.6.0

Quetzal 0.5.0

Choose a tag to compare

@github-actions github-actions released this 04 Oct 14:58
  • 网页控制台:控制台(Flutter)新增 Web 形态,由运行基座的网关托管;npx @plutokeating/quetzal 装完自动在浏览器里打开 http://127.0.0.1:7788/(新子命令 open,--no-open 不打开),同一台机器的浏览器打开即登录(网关新增 GET /auth/local:只对回环地址、本机 Host 的请求放行,不扩大信任边界),不再需要手机 App 与配对码;ssh 隧道转发也算本机。网页版自带中文字体子集,离线与中国大陆不出方块;Mermaid 图在同源 iframe 里渲染。
  • Web console: the console (Flutter) now also builds for the web and is served by the runtime's gateway; npx @plutokeating/quetzal opens http://127.0.0.1:7788/ in the browser after installing (new subcommand open, --no-open to skip), and a browser on the same machine is logged in as soon as the page opens (new gateway endpoint GET /auth/local, which only accepts loopback connections with a local Host header, so the trust boundary does not widen) — no phone app or pairing code needed; a connection through an ssh tunnel counts as local. The web build ships its own CJK font subset (no missing glyphs offline or in mainland China); Mermaid diagrams render in a same-origin iframe.
  • 桌面外壳:宽屏(≥ 900:电脑浏览器、平板横屏)为电脑横屏重新排布:导航栏 · 列表栏 · 主区 · 「她此刻」四栏,右栏常驻 ta 此刻的样子(光团、想分享的一句话、正在进行的醒来、待审批、内在与身体),对话 Enter 发送、Shift+Enter 换行,地址栏 #/… 记录位置可收藏;手机外壳不变,所有页面两种外壳共用一份代码(PageFrame / showSheet)。
  • Desktop shell: on wide screens (≥ 900: desktop browsers, tablets in landscape) the console is laid out afresh for a wide screen — navigation rail · list · main area · a permanent "right now" pane (orb, the thought it wants to share, a wake in progress, pending approvals, inner state and body); Enter sends and Shift+Enter inserts a newline in chat; the address bar's #/… records where you are and is bookmarkable. The phone shell is unchanged, and every page is one piece of code for both shells (PageFrame / showSheet).
  • npm 包随版本目录放入 web/(releases/<版本>/web/,网关托管 current/web/,QUETZAL_WEB_DIR 可覆盖),包体约 11 MB(解压 34 MB);status 显示网页控制台地址。
  • The npm package places web/ into the version directory (releases/<version>/web/; the gateway serves current/web/, QUETZAL_WEB_DIR overrides it); package size about 11 MB (34 MB unpacked); status shows the web console address.

Full Changelog: v0.4.0...v0.5.0