ui: show offline WeChat status without repeated card explanation

This commit is contained in:
鲨鱼辣椒 committed 2026-10-14 12:24:08 +08:00
1 parent 3f10106bdb
commit 55b1d9e821
5 files changed
+11 -6

No files matched your search

@@ -8,14 +8,16 @@
- Worktree: /Users/chillishark/Makelore 麦洛/.codex-worktrees/makelore/20261014-wechat-always-reply-4c92e7a1
- Base commit: d0451e9a9dc85288149376a55ecf2153ba3facb4
- Owner: codex
- Status: Planning
- Status: Ready for Integration
## Scope
- Follow-up: remove the offline explanation paragraph from WeChat cards, retaining the top-right truthful status badge. Actionable bind/reconnect failure dialogs and all readiness checks remain.
- Add authorized device-only removal of safely unbound cards, scoped by tenant/user and bound revision; keep cloud identities/history intact and make rebindings visible again. Remove the WeChat user pause/resume feature. Completed binding, target switch and reconnect keep replies enabled; safely restore healthy old disabled bindings without bypassing original-operation, identity, logout, target or connectivity protections.
## Intent And Constraints
- Latest human request removes only the quoted offline card prose and retains the corner status. Existing task ownership, Yuxi read-only boundary and no planning-with-files preference persist. Coordinate source freeze with the already authorized merge/restart chat; do not race its runtime changes.
- User explicitly reverses the previous manual-pause policy: “不要这个功能,微信永远都可以回复。” This authorizes restoring ready valid old bindings, not changing unavailable Agents or misreporting service availability. Stop using a channel through existing unbind. Persistent constraint: no Yuxi/AgentBus edits; no planning-with-files workflow.
- Official Concurrent/Planning Gate Passed: task4c92e7a1/feature/planning/worktree/branch/base d0451e9 match; primary occupied dirty remains read-only. Independent reviewer65peer records/195sections and incremental changes found no semantic conflict. Earlier pause/preserve-paused ADR/task prose is superseded by current direct human instruction; canonical docs stay read-only.
- Project Context Loaded: read AGENTS; startup/memory/planning/own record; positioning, integrated state, decisions/auth004/personal cloud ADR, architecture/module/data flow, business/success/evidence/reflection/commitment indexes and community boundary. Main owns authentication and original-operation journals; Core/Yuxi persist route state. Source base is prior full trialRenderer including previous copy and homepage sidebar.
@@ -27,6 +29,7 @@
## Outcome
- Latest card-copy follow-up completed: only worker_offline card prose is filtered out; the truthful top-right badge remains, and binding/reconnect error text and all operational guards are unchanged. README and existing tests synchronized. Source feature work is complete, ready for the user's coordinated integration/restart.
- Implemented always-enabled valid bindings, no pause/resume UI, enabled connected target switches and reconnect completion, guarded serial convergence of healthy legacy disabled accounts. Actual online presence is mandatory for automatic restoration; original operation IDs/journals remain unchanged and unknown results stop the batch. Zero-write preflights can retry after a later refresh; changed targets require manual refresh.
- Implemented local card deletion only after confirmed unbind/logout, with explicit device-only confirmation, scoped tenant/user revision preferences, persistence across refresh/reopen, rematerialization after rebind/revision change, fresh owner/recovery/revision/logout checks and visible storage failure. Unbound but still connected/unknown accounts retain safe unbind. No Yuxi/AgentBus or Main backend edits; DTO only declares the existing optional worker_online response.
- README synchronized. Implementation committed at12d856cd60277bcc35670b0dc65dc64de8b4fe48; source complete and independently reviewed.
@@ -35,6 +38,7 @@
## Verification
- Final copy follow-up:108/108 focused unit tests passed (5.81s), final typecheck/scoped lint/default Vite build/diff passed; both Electron scenarios passed together2/2 (9.8s). Root inspected the resulting card screenshot: status badge present, long paragraph absent, layout intact. Actionable QR/final-binding error assertions still pass. Exact logs are /tmp/wechat-always-reply-4c92e7a1-copy-followup-{unit,build,e2e}.log.
- Focused Page unit tests 108/108 passed, including enabled-policy, serial old-record restoration, zero-write same-revision offline recovery, legacy management journals, unknown write identity retention, owner/tenant changes, deletion cancel/persistence/storage failure/rebind and fresh-state denials.
- Final typecheck, scoped ESLint and diff checks passed after fixture correction. Full default build:vite passed for Renderer/Main/Preload/Utility; immutable complete current-source candidate default build also passed, normal setup/login retained.
- Isolated Electron empty-workspace scenario passed. Main interaction scenario initially failed because the mock reused the first QR session for reconnect; source correctly deduplicated it. Test now assigns the second scan a fresh session, scoped scenario passed 1/1 in7.3s. No product dedup change. Both scenarios now passed;16 screenshots produced, root visually inspected deletion confirmation and post-removal/reload list without clipping.
@@ -42,7 +46,7 @@
## Follow-ups
- Finish native cancellation and truthful runtime finalization after manual Mac unlock. No input-discard or force-unlock authorization. Files remain activated but Main and profile unchanged.
- Runtime handoff to explicitly authorized coordination: the earlier3e22804 Renderer is activated in compatibility and its new controls were actually observed, but pointer remainsec07 metadata, final cancellation afterMacLocked not confirmed, and latest one-line card-copy change is source-built/tested only. Do not claim that copy is installed or the earlier stage isactive-verified. The coordinator's requested uniform full-app rebuild/restart after all five source reports supersedes another local overlay; no new activation/restart is being attempted here. Preserve current Main/profile and use a fresh actual UI guard or obtain manual unlock, without reusing input-discard authorization.
- Authorized coordination handoff: verified newest direct human user message in thread01a12eba-e98b-76a3-8fd5-206f2820d623 listing this chat01a13373 and four peers, requiring reports followed by coordinated merge/push/restart/cleanup. Sent current transition/lock status under that human authorization; coordinator waits, no simultaneous pointer/compat changes. Root will send exact final source/docs SHAs and runtime state on completion, then leave consolidated publication/restart/cleanup to coordinator.
- Earlier source status checked against current origin/main: Yuxi adapter979596f8f88a2132bfd35bef0828d0a9f5e0d870 and bindings UIe250b012e14460cf995c1d7141f58e62da44a8a0 already ancestors. Prior prompt implementationa837c4fd7e52fc1288f1f9a6737bd9775bfee56c and final own recordfbfc8b4ab003e7b862a344fe125ff073a83bcb84 not integrated; current final Page and tests include that prompt behavior and explicitly supersede old pause policy. Coordinator should integrate task commits/semantic current blobs, not mistake private full trial composites as independently requested source changes.
+1 -1
View File
@@ -22,7 +22,7 @@ Makelore 是一个面向软件、视觉创作、智能机器人与个人云智
云知识库的 embedding 模型只由平台管理员在 Yuxi 后台维护:在「智能体管理 → 模型供应商」启用供应商,按供应商要求填写有效的服务地址和 API Key,添加并启用 embedding 模型并填写实际向量维度;embedding 向量化费用由平台承担,不计入用户用量、词元点数或智能体费用上限;one-api 不参与 embedding 配置,Works Square 只负责其他应计费模型调用的创建者词元点数账本。客户端区分目录加载中、加载失败与无可用模型,空状态提供管理员配置说明;「刷新知识库与模型」保留未提交名称,未确认的创建请求沿用原操作身份。
Agents 侧栏的「渠道」按每个微信一张卡展示备注、当前智能体与使用状态;一个微信同时只绑定一个智能体,多个微信可以使用同一智能体。绑定有效且服务正常时始终开启回复,不提供暂停或恢复开关;更换智能体保留登录与历史,完成重新登录后也开启回复。旧的关闭记录在页面可见时,重新核对登录、在线服务、可用目标、同步状态及新旧渠道操作恢复记录后串行开启;服务离线、退出待确认、目标不可用和结果未知时不自动写入。常用操作是“更换智能体”;“更多操作”内可以解除微信绑定,停止任务、清除目标并退出微信登录,历史保留,再使用需扫码。确认解绑后的卡片可选择“删除微信卡片”,只从这台设备的当前账号列表移除,刷新和重开后仍保留删除结果;其他设备及云端账号和聊天历史不受影响,同一微信重新绑定后再次显示。本机偏好按账号与租户隔离,删除前再次读取云端状态并检查原操作,保存失败时保留卡片并显示原因。添加流程为选择已开始使用的智能体、扫码、自动完成绑定;扫码确认、目标正确、启用成功且最终状态回读可用后才显示完成。服务离线如实说明,不把扫码成功当作回复可用;未知或未同步状态显示“状态待确认”。无可用智能体时说明创建和“开始使用”的前提,加载失败不冒充空态,已有微信仍可解绑。Main 持有凭据与原操作恢复;解除需要配套 Yuxi 用户级 `/channel-accounts/{id}/unbind`,旧后端不会通过改按钮文案或组合未确认操作假装完成。变更以最新读取状态为准,未完成操作保留原身份供显式恢复;失败在当前窗口可见,结果未知不自动重放。微信退出仍在处理中时,禁止新的连接和绑定变更,保留刷新与原操作恢复。旧请求无法安全恢复、账号关系不一致或目标不可用时提示先核对;“不再提醒”只移除本机提醒,不取消服务端仍在处理的操作。最新 Yuxi 的退出保护条件和持久恢复由服务端负责,发布需配套 Core/Adapter 与 Yuxi business=13、knowledge=2 数据库版本。渠道页不展示微信聊天或活动,既有历史、费用、内容隔离与应用 API 保持原边界。实际微信身份及重复扫码识别仍由云端负责,不从备注推测。
Agents 侧栏的「渠道」按每个微信一张卡展示备注、当前智能体与使用状态;一个微信同时只绑定一个智能体,多个微信可以使用同一智能体。绑定有效且服务正常时始终开启回复,不提供暂停或恢复开关;更换智能体保留登录与历史,完成重新登录后也开启回复。旧的关闭记录在页面可见时,重新核对登录、在线服务、可用目标、同步状态及新旧渠道操作恢复记录后串行开启;服务离线、退出待确认、目标不可用和结果未知时不自动写入。常用操作是“更换智能体”;“更多操作”内可以解除微信绑定,停止任务、清除目标并退出微信登录,历史保留,再使用需扫码。确认解绑后的卡片可选择“删除微信卡片”,只从这台设备的当前账号列表移除,刷新和重开后仍保留删除结果;其他设备及云端账号和聊天历史不受影响,同一微信重新绑定后再次显示。本机偏好按账号与租户隔离,删除前再次读取云端状态并检查原操作,保存失败时保留卡片并显示原因。添加流程为选择已开始使用的智能体、扫码、自动完成绑定;扫码确认、目标正确、启用成功且最终状态回读可用后才显示完成。微信服务离线时,卡片仅保留右上角“微信服务离线”状态,不显示重复的离线长段说明;绑定或重新连接失败的窗口仍说明原因,不把扫码成功当作回复可用。未知或未同步状态显示“状态待确认”。无可用智能体时说明创建和“开始使用”的前提,加载失败不冒充空态,已有微信仍可解绑。Main 持有凭据与原操作恢复;解除需要配套 Yuxi 用户级 `/channel-accounts/{id}/unbind`,旧后端不会通过改按钮文案或组合未确认操作假装完成。变更以最新读取状态为准,未完成操作保留原身份供显式恢复;失败在当前窗口可见,结果未知不自动重放。微信退出仍在处理中时,禁止新的连接和绑定变更,保留刷新与原操作恢复。旧请求无法安全恢复、账号关系不一致或目标不可用时提示先核对;“不再提醒”只移除本机提醒,不取消服务端仍在处理的操作。最新 Yuxi 的退出保护条件和持久恢复由服务端负责,发布需配套 Core/Adapter 与 Yuxi business=13、knowledge=2 数据库版本。渠道页不展示微信聊天或活动,既有历史、费用、内容隔离与应用 API 保持原边界。实际微信身份及重复扫码识别仍由云端负责,不从备注推测。
- `Makelore Canvas|AI 绘画`:每个设计项目(Workspace)维护一份从创建起就存在的 Living Form。左侧项目栏沿用 Agents 的图标徽章与文字入口,新建、切换和项目操作菜单集中管理 Workspace。工作区统一项目标题、设计版本与制作状态,创作对话和作品区支持拖动分栏、键盘调宽及单栏展开;对话以 Markdown 呈现,底部输入器保留草稿、发送状态与 Enter / Shift+Enter 快捷键。右侧通过“当前作品 / 历史作品”切换,在大图或视频预览旁编辑唯一制作方案、确认费用和制作;历史作品可回到工作区查看,切换面板保留未保存的制作参数。紧凑窗口以“创作对话 / 作品与方案”切换面板,通过项目抽屉管理 Workspace。图片支持适应窗口、原始尺寸及 Esc 关闭,视频支持预览和保存到电脑。参考图从本地上传后以 `@图片N` 绑定,具体用法只写在创作提示词中。
- `Makelore Robot|AI 机器`:管理机器人智能体、设备激活绑定、智能体配置与设备分配;机器人工作台的智能体位于 Robot 全局侧栏,选中后在内容区先查看绑定设备、再查看基础设置,当前智能体通过 URL 参数保持可分享选择;绑定设备时默认先选择“引导配网”或“已有激活码”。在 Windows 与 macOS 的引导路径中,Makelore 可在弹窗内扫描并连接附近开放的 `Xiaozhi-*` 配网热点,失败时仍可通过系统 Wi-Fi 手动连接;后续继续复用机器人现有热点配网页面,不修改固件,也不由 Makelore 接收 Wi-Fi 密码。
+1 -1
View File
@@ -917,7 +917,7 @@ export function ChannelAccounts() {
</p>
)}
{usableBlockers(account)
.filter((item) => blockerText[item])
.filter((item) => item !== 'worker_offline' && blockerText[item])
.map((item) => (
<p key={item} className="mb-3 text-xs leading-5 text-[#876033]">
{blockerMessage(item, account)}
+1 -1
View File
@@ -575,7 +575,7 @@ test('WeChat binding cards connect an account and switch its Agent through the c
'智能体的微信服务暂时离线,暂时无法自动回复。微信登录和智能体选择已保留,服务恢复后请刷新状态。',
{ exact: true }
)
).toBeVisible();
).toHaveCount(0);
await expect(legacyCard.getByText('状态待确认', { exact: true })).toHaveCount(0);
await expect(spareCard.getByRole('button', { name: '绑定智能体', exact: true })).toBeVisible();
await expect(page.getByRole('dialog')).toHaveCount(0);
+2 -1
View File
@@ -686,6 +686,7 @@ it('explains an offline Worker after confirmed login and preserves the chosen Ag
fireEvent.click(within(dialog).getByRole('button', { name: '稍后继续' }));
const current = await card('微信 3');
expect(within(current).getByText('微信服务离线')).toBeVisible();
expect(within(current).queryByText(/智能体的微信服务暂时离线/)).not.toBeInTheDocument();
expect(within(current).getByText(agentA.name)).toBeVisible();
});
@@ -740,7 +741,7 @@ it.each(['login_required', 'unknown'] as const)(
accounts[0] = { ...legacy, health, blockers: ['worker_offline'] };
renderPage();
const current = await card();
expect(within(current).getByText('智能体的微信服务暂时离线,暂时无法自动回复。')).toBeVisible();
expect(within(current).queryByText('智能体的微信服务暂时离线,暂时无法自动回复。')).not.toBeInTheDocument();
expect(within(current).queryByText(/微信登录和智能体选择已保留/)).not.toBeInTheDocument();
expect(within(current).queryByText('微信服务离线')).not.toBeInTheDocument();
expect(writes()).toEqual([]);