Repository navigation
Description
English
Problem
Amadeus's core stack is Python + Electron/TypeScript. Windows managed wallpaper currently adds C# projects, NuGet dependencies, .NET SDK build steps, and a self-contained .NET runtime. This increases distribution size, build prerequisites, and maintenance cost, contrary to the goal of simplifying distribution.
Replace Amadeus's own .NET wallpaper helper with the existing Python runtime, while retaining supported managed-wallpaper behavior. Lively remains an optional external application; removing Lively's own dependencies is not a promised outcome.
Implement this in a separate conversation, worktree, and PR, outside #261. The extension-update recovery repairs, CI, and external re-review of #261 continue independently.
Current implementation and checked baseline
Checked revision: 65626b3fcc2d1c4e3ec98e185ff562ec21b0fe02. The wallpaper helper, Electron integration, and build scripts matched main 9547f39a at that checkpoint. Start the migration from the latest main when implementation begins.
- C# helper: connects to Lively, mounts/closes scenes, reads/writes settings, and owns recovery journals and process identities.
- Electron integration: starts an independent helper and manages its lifecycle through stdin/stdout.
- Build script:
dotnet publish --self-contained true. - Lifecycle contracts and known limitations.
- Original scope: Windows: manage wallpaper startup, first-run setup and restoration on exit #110, commit
a19ac3c0(2026-09-22). This issue changes the dependency implementation, without independently changing user-visible startup, shutdown, or recovery contracts.
Verified feasibility and limitations
On 2026-10-26, a temporary read-only probe using Python 3.12's standard library, including ctypes, running in isolated mode with -I, connected directly to an already-running Lively instance on Windows. It did not start the C# helper, load a .NET client, install Python packages, or change wallpaper/settings.
Before sending requests, the probe checked the server identity on the same pipe connection using GetNamedPipeServerProcessId. It successfully called:
DesktopService/GetCoreStats: reported version 2.2.1.0, initialized=true.DisplayService/GetScreens: reported one display.DesktopService/GetWallpapers: reported one wallpaper entry.
This is communication feasibility evidence. The probe did not verify the installed Lively binary's hash against an unmodified release. Entry counts are server reports, not proof of actual scene state or process exit. Writes, failure recovery, a complete replacement, and clean-machine distribution were not qualified. The probe was not committed as a production implementation.
The transport reference is the currently pinned GrpcDotNetNamedPipes @ da307b55, including transport.proto and Windows message-mode framing. A conventional HTTP/2 gRPC client cannot be assumed to implement this transport.
The official Lively CLI supports scripts, but replacing the helper with a few setwp/closewp commands would not establish equivalent state readback, exact-project closure, or recovery.
Smallest implementation direction
- Keep Electron's existing entry points, status presentation, and lifecycle ownership.
- Launch an independent, lightweight wallpaper helper with the existing Python runtime. Do not import the entire server/app or bind its lifetime to the main backend's process-tree cleanup. Preserve cleanup after the parent exits and later recovery from journals.
- Prefer the standard library and existing capabilities. Implement only the bounded RPC/message subset actually needed, rather than introducing a general communication framework. Justify any additional package by necessity, size, and maintenance cost; do not rely on incidental transitive dependencies of optional Providers.
- Preserve the exact request receiver identity, timeout/cancellation semantics, original errors, and recovery journals. Settings read-modify-write must preserve unknown fields and the user's newer choices.
- After implementation and qualification, remove the old C# projects, NuGet build/distribution dependencies, and Amadeus's bundled .NET runtime. Update packaging hooks, source-archive allowlists, CI, documentation, and license inventories. Remove notices only for components no longer distributed.
- Do not retain two production implementations indefinitely. Existing recovery journals need verified compatibility or an explicit migration/recovery path; do not clear journals to bypass unfinished sessions.
Acceptance criteria
- Port the necessary contracts from the current lifecycle suite into the existing test stack. Do not remove assertions or weaken semantics to obtain a pass.
- Qualify normal mount/exit, reuse of an existing host, stopping only an owned host, user wallpaper changes, displays/layouts, and settings restoration against real Lively.
- Test Electron crashes, recovery after helper termination, late connections/requests, identity-read failure, persistence failure, timeouts, and retry after close/restore failure. A successful command or empty list must not be treated as exit proof.
- Preserve and explicitly document the known Lively reporting/close limitations in Windows wallpaper recovery: Lively false-empty reports and unconfirmed project close #233. Migration does not automatically fix them, and their counterexamples must not be counted as successful qualification.
- Verify Amadeus source build/packaging and ordinary startup in a clean environment without a .NET SDK or system .NET runtime. Qualify managed wallpaper with the supported, unmodified Lively release, whose own distribution remains responsible for its prerequisites.
- Add no wallpaper dependency or behavior change to ordinary chat, external-host mode, or Linux/macOS paths.
- Report before/after package size, build prerequisites, first-use setup, and startup time to demonstrate a reduction in total distribution burden.
- Pass Python/Electron, source-archive, real-application, and release-artifact checks, followed by independent review before replacement.
The direction is expected to help, but it cannot be declared risk-free in advance. The evidence above must address regression risks in communication, recovery, persisted state, and process ownership.
Related: #110 (original functionality/dependency contract), #233 (known recovery limitations), and #185 (other wallpaper defects). Deliver separately from #261.
Review addendum — 2026-10-26
The following requirements are accepted for implementation:
- Runtime lifecycle: .NET 8 support ends on 2026-11-10. This is an additional migration driver. If replacement cannot be qualified before that date, retarget the existing helper and CI to
net10.0in a separate bounded change first; do not ship the old runtime beyond its support window while waiting for the migration. - Existing journals:
ProcessIdentity.Startedis .NET UTC ticks, exactly Windows FILETIME + 504911232000000000, using integer arithmetic. A mismatch can incorrectly release the Pending recovery fence for a still-running receiver, so it fails toward allowing recovery, not merely blocking it. Compare Python and the current C# output for the same real live process before deleting C#. Keep PascalCase JSON fields and string-valuedPreparing/Pending/Settledphases unchanged, including existing legacy journals. - Settings wire preservation: retain the original protobuf field sequence and change only 28 (browser), 48 (lock image), 49 (desktop image). Copy every other field's original bytes, including unknown fields and encoding/order; do not build a complete Settings model. In proto3, false/default scalar values are represented by omitting the field.
- Distribution and execution: ship the standard-library-only helper with Electron resources, execute with
-I, and resolve the same interpreter as the backend throughpythonRuntime.ts. The helper version must follow Electron rather than an independently installed script.
Risk is medium, concentrated in transport deadlines/cancellation and the Pending pre-dispatch persistence boundary. #233's false-empty reporting and swallowed-error limitations remain after this migration and remain qualification exclusions. #261 was merged on 2026-10-26 (Pacific/Auckland), so implementation can now start separately from latest main; it does not belong in that PR.
Additional acceptance gates:
- Exact Python/C# live-process tick comparison and old PascalCase/string-enum journal recovery, including a live Pending receiver negative control.
- Raw Settings unknown-field byte preservation, proto3 false omission, and preservation of newer user choices.
- Deadline/cancellation before connect, before dispatch, during persistence, and after dispatch; identity/persistence failure sends no RPC bytes, while uncertain dispatched requests retain Pending.
- Packaged helper uses Electron's resources and backend interpreter in isolated mode, independent of backend process-tree cleanup.
中文
使用场景
Amadeus 的核心技术栈是 Python + Electron/TypeScript。Windows 托管壁纸目前额外维护 C# 项目、NuGet 依赖、.NET SDK 构建步骤,并以 self-contained 方式携带 .NET 运行时。这增加了分发体积、构建工具链和依赖维护成本,与减少分发难度的方向不一致。
目标:复用现有 Python 运行时替换 Amadeus 自己的 .NET 壁纸助手,保留已支持的托管壁纸行为。Lively 继续是可选外部程序;不承诺消除 Lively 自身的依赖。
单独在新会话和独立 worktree/PR 实施,不并入 #261。 #261 的更新恢复修复、CI 和外部复审继续单独推进。
当前实现与检查基线
检查基线:65626b3fcc2d1c4e3ec98e185ff562ec21b0fe02。壁纸 helper、Electron 接线及构建脚本与当时 main 9547f39a 一致;迁移应从开始实施时的最新 main 建立独立分支。
- C# helper:连接 Lively、挂载/关闭场景、读写设置、保存恢复日志及进程所有权。
- Electron 接线:启动独立 helper,以 stdin/stdout 驱动生命周期。
- 构建脚本:
dotnet publish --self-contained true。 - 生命周期合同与已知限制。
- 引入来源:Windows: manage wallpaper startup, first-run setup and restoration on exit #110,提交
a19ac3c0(2026-09-22)。本议题调整其依赖实现,不自行改变用户可见的启停/恢复约定。
已验证的可行性与限制
2026-10-26,在 Windows 上使用 Python 3.12 标准库(ctypes 等),以 -I 隔离运行的临时只读探针,直接连接当时已运行的 Lively;没有启动 C# helper、加载 .NET 客户端、安装新 Python 包或修改壁纸/设置。
探针在发送前使用 GetNamedPipeServerProcessId 核对了同一管道连接的服务端身份,成功执行:
DesktopService/GetCoreStats:报告版本 2.2.1.0,initialized=true;DisplayService/GetScreens:报告 1 个显示器;DesktopService/GetWallpapers:报告 1 个壁纸条目。
这是通信可行性证据。本机 Lively 二进制未在该探针中做原版 hash 核验;条目数量只是服务端报告,不是实际场景/退出证明。探针没有验证写操作、异常恢复、完整替换或干净机器分发,也没有作为生产实现提交。
传输参考是现有依赖锁定的 GrpcDotNetNamedPipes @ da307b55,包括其 transport.proto 和 Windows 消息模式分包。它不是可以直接交给普通 HTTP/2 gRPC 客户端的接口。
Lively 官方 CLI支持脚本控制,但不能仅替换成几条 setwp/closewp 命令就声称保留了当前状态读回、精确项目关闭和恢复能力。
最小实施方向
- Electron 保留现有入口、状态展示和生命周期责任。
- 使用现有 Python 运行时启动独立、轻量的壁纸助手,不导入整个 server/app,不绑定主后端的进程树清理生命周期;保留父进程退出后的清理及后续日志恢复能力。
- 优先标准库和现有能力,仅实现当前需要的有限 RPC/消息适配,避免新增通用通信框架。任何新增包必须说明必要性、体积与维护成本,不能依赖可选 Provider 的偶然传递依赖。
- 保留明确的请求接收进程身份、超时/取消语义、原始错误与恢复日志;设置读改写必须保留未知字段和用户的新选择。
- 迁移完成并验收后,移除旧 C# 项目、NuGet 构建/分发依赖和 Amadeus 自带的 .NET 运行时,更新打包 hook、源码包允许清单、CI、文档和许可证清单。只删除确已不再分发的 notices。
- 不长期保留两套生产实现。旧恢复日志要有经验证的兼容或明确的迁移/恢复路径,不能通过清空日志绕过未完成会话。
验收标准
- 对照现有生命周期测试,将必要合同迁入现有测试栈;不删断言或以弱化语义换取通过。
- 真实 Lively 验证普通挂载/退出、已有宿主复用、只停止自有宿主、用户手动切换壁纸、显示器/布局、设置恢复。
- 验证 Electron 崩溃、助手被终止后的恢复、迟到连接/请求、身份读取失败、持久化失败、超时、关闭/恢复失败重试;不把命令返回成功或空列表当作退出证明。
- 保留并明确标注 Windows wallpaper recovery: Lively false-empty reports and unconfirmed project close #233 的已知 Lively 报告/关闭协议限制。迁移不自动修复该问题,不将其反例算入成功验收。
- 在没有 .NET SDK、没有系统 .NET 运行时的干净环境中,验证 Amadeus 源码构建/打包及普通启动;托管壁纸用受支持的原版 Lively 验收,其自身依赖由其发行包负责。
- 普通聊天、外部宿主模式和 Linux/macOS 路径不新增壁纸依赖或行为变化。
- 报告迁移前后实际包体积、构建 prerequisites、首次设置与启动耗时,证明总分发负担下降。
- Python/Electron、源码包、真实应用和发布产物检查通过;独立审查后替换。
方向预期有收益,但不能预先承诺“有利无害”。通信、恢复、持久状态和进程所有权的回归风险必须用上述证据排除。
关联:#110(原功能/依赖约定)、#233(已知恢复限制)、#185(其他壁纸故障);与 #261 分开交付。
复审补充 — 2026-10-26
接受以下实施约束:
- 运行时支持期:.NET 8 将于 2026-11-10 停止支持,作为本次迁移的额外驱动因素。若届时尚不能完成替代实现验收,先以独立小改动把现有 helper 与 CI 升到
net10.0;不因等待迁移而继续分发已停止支持的旧运行时。 - 旧日志兼容:
ProcessIdentity.Started是 .NET UTC ticks,必须以整数精确计算为 Windows FILETIME + 504911232000000000。不匹配会把仍存活的原接收进程判为已退出,错误方向是放行 Pending 恢复栅栏。删除 C# 前,必须对同一个真实存活进程比较 Python 与现有 C# 输出。保持 PascalCase JSON 字段和Preparing/Pending/Settled字符串枚举,也覆盖既有旧格式日志。 - **Settings 原始字段改写:**保留原始 protobuf 字段序列,仅改 28(浏览器)、48(锁屏图)、49(桌面图);其他字段连同未知字段的编码、顺序、原始字节全部原样写回,不建立完整 Settings 模型。proto3 的 false/default 标量以省略字段表示。
- **分发与执行:**helper 仅用标准库,随 Electron resources 分发,以
-I执行,通过pythonRuntime.ts与后端共用解释器选择;helper 版本随 Electron,不依赖单独安装的脚本。
风险为中等,主要在传输层 deadline/取消语义和 Pending 派发前持久化边界。#233 的假空、吞错限制迁移后仍存在,继续明确列为验收限制。#261 已于 2026-10-26(Pacific/Auckland)合并,现在从最新 main 独立实施,不并入该 PR。
新增验收门槛:
- 真实进程 Python/C# ticks 完全一致;兼容旧 PascalCase/字符串枚举日志,存活 Pending 接收进程必须阻止恢复。
- Settings 未知字段原字节保留、proto3 false 省略、用户新选择优先。
- 连接前、派发前、持久化中、派发后的超时/取消;身份或持久化失败不发送 RPC 字节,不确定的已派发请求保留 Pending。
- 打包 helper 来自 Electron resources,使用后端同一解释器和隔离模式,独立于后端进程树清理。
Activity
refactor(windows): replace wallpaper helper with isolated Python runt…