Skip to content

fix(mobile): 修复插件产物和调用状态的远程显示 - #4692

Merged
MagicLizi merged 6 commits into
makecindy:mainfrom
zqchris:plugin-mobile-results
Sep 19, 2026
Merged

MagicLizi merged 6 commits into
makecindy:mainfrom
zqchris:plugin-mobile-results

Conversation

@zqchris

@zqchris zqchris commented Sep 18, 2026 •

Copy link
Copy Markdown
Contributor

这次改了什么

摘要

修复 Art 等插件产物在远程手机上丢失的问题:工具结果和历史压缩保留图片、音视频、文件及卡片引用,手机用原生组件展示可读内容。补齐普通任务用户消息内的插件调用状态、展开信息与图标;伙伴用户消息继续保持普通气泡,产物和授权卡独立显示。 插件状态按各次调用的配对结果独立结束;大结果投影限制为 8 KiB,优先保留完整引用,完整原文仍保留在宿主。

变更类型

  • feat 新功能
  • fix 缺陷修复
  • refactor / perf 重构或性能优化
  • docs / test / chore 文档、测试或工程维护
  • 其他:

范围

  • 关联 Issue / 需求:远程手机的插件结果与调用状态显示兼容。
  • 本 PR 包含:共享结果解析、长消息投影、只读卡片和公开插件身份远程资源、原生消息呈现、文件导出及回归测试。
  • 明确不包含:服务端、插件管理、HTML/脚本执行、桌面卡片按钮远程执行、原生配置或依赖变更。
  • 用户可见变化:手机能保留插件产物并打开图片;普通任务显示调用状态与详情;伙伴不反向装饰用户消息。
  • 是否存在 breaking change:无。沿用已有远程资源通道;旧宿主不支持身份资源时回退名称/通用图标。

UI 变化

iOS:原生插件调用行、运行双弧动画、完成标记、展开详情及只读结果。截图包含真实消息,未附公开截图。

  • 引用的设计规范:DESIGN.md §2、§10 使用语义颜色适配 Light/Dark;§3、§5 使用字体/间距 token 和 44pt 点击目标;§14.4 保留召唤双弧与 reduced-motion 支持。伙伴用户气泡保持轻量。

怎么验证的

自动验证

pnpm test:unit:related
结果:工程检查及其余 28 个 workspace 通过;Mobile 首轮唯一失败为本机忽略文件中的旧 Scene 配置与更新后的 Expo 重复。
pnpm test:unit:related -- --workspace apps/mobile
结果:清理重复的本机临时配置后,复跑工程检查及全部 Mobile 单测通过。产品代码无追加变更。
pnpm test:unit:related -- --workspace apps/mobile --workspace packages/maker-shared
结果:同步最新主干后复核同页面加载状态及共享历史逻辑,通过。
pnpm --filter desktop run --if-present typecheck
pnpm --filter mobile run --if-present typecheck
pnpm --filter cindy-tools run --if-present typecheck
pnpm --filter @cindy/maker-shared run --if-present typecheck
结果:通过;后两包无 typecheck script,按配置跳过。
pnpm --filter cindy-tools build
结果:通过(tsc --noEmit)。
git diff --check
结果:通过。
pnpm --filter @cindy/maker-shared run build(额外检查)
结果:未通过。现有 brandIdentity/composerPalette/historyView 测试类型与 workRunGrouping 的 findLastIndex lib 配置报错,报错文件均不在本次改动中;本包没有 typecheck script。

本次状态与预算修复(232dffab7)追加验证:pnpm test:unit:related -- --workspace apps/desktop --workspace apps/mobile、Desktop/Mobile typecheck 均通过;Desktop 定向 84 项、Mobile 定向 29 项通过。新增覆盖并发插件独立完成、重复调用、空/失败结果,以及大量引用和 Unicode 内容的最终字节预算。本次未追加模拟器实测。

新增回归覆盖嵌套结果、压缩引用保留、卡片归属及账号切换、迟到响应、重连恢复、媒体去重、调用归属及伙伴授权/产物并存。

手工验证

iOS 模拟器中的真实远程任务验证:Art 图片缩略图、全屏打开、退出重进后的历史显示;插件运行/完成状态、展开/收起详情。复用现有已登录宿主,没有启动 Mac 预览版。

branch/worktree:plugin-mobile-results / cindy-plugin-mobile-results;Metro 为此 worktree 专属实例(8081);DEV build label:plugin-mobile-results@88f491e+0a4a4de690。提交前已同步主干 b4ffa2a 并重新运行自动检查;未为此次基线同步重装模拟器原生包。

附件-only 修复(6982f6a90):Mobile 全部单测及 typecheck 通过;新增实际 MessageRenderer 渲染回归覆盖纯图片/文件的调用中、完成状态和伙伴/无调用对照(4 项)。iOS 27 Light 下用临时无私密数据样例挂载真实组件,核验无正文文件的 Calling… → Called 及展开详情;临时页面未提交,不等同于远程发送链路重新验收。

未执行的验证

Android 和手机真机、Dark 模式目检、视频/音频/文件系统分享、伙伴端到端、升级宿主后的卡片与自定义插件图标未全链路实测;对应代码与回归测试已核对。模拟器的本地原生启动适配未纳入提交,不改变 runtime fingerprint。

风险

风险分类

  • 无已知风险
  • SQLite / migration
  • system prompt
  • 协议兼容
  • 权限 / 安全 / 用户数据
  • 存量插件兼容(批准状态 / 指纹 / manifest 校验 / 安装布局 / 包格式)
  • 原生层 / fingerprint / OTA
  • 跨平台差异
  • 其他:

影响与回滚

  • 影响范围:Desktop 插件结果投影、共享消息解析和 Mobile 消息展示。只读资源按任务授权与数据所有者校验;身份只暴露公开名称/有界位图,卡片不执行 HTML、脚本或动作。未改协议包/schema、IPC allowlist、数据库或凭证。
  • 存量插件影响:无。不改批准状态、指纹、manifest、安装布局或包格式,不要求重装/重新授权;没有迁移逻辑。插件基座相关部分仍需仓库指定审核人确认后合并。
  • 回滚 / 降级方式:可整体 revert;旧宿主身份查询失败回退通用图标,图片沿既有媒体取件路径。新卡片资源需要升级宿主;未实现的交互保留只读文字。无原生冷更。

提交前检查

  • 已 review 完整 diff
  • 每个 commit 都带 DCO 签名(git commit -s)
  • UI 改动已在「UI 变化」注明引用的设计规范章节
  • 未提交凭证、令牌或授权文件
  • 已核对受影响的文档,未改变既有协议和作者契约;已同步设计组件生成清单
  • 已确认测试结果或说明未执行原因

Signed-off-by: zqchris <chrisz83@gmail.com>
@zqchris
zqchris marked this pull request as ready for review September 18, 2026 14:31
@zqchris
zqchris requested a review from a team as a code owner September 18, 2026 14:31
@greptile-apps

greptile-apps Bot commented Sep 18, 2026 •

Copy link
Copy Markdown

RetriggerConfidence Score: 2/5

此 PR 暂不适合合并,因为新增文件导出链路可读取工作区外文件,且插件调用状态在多工具轮次中会持续显示错误。

Findings

  1. P1 Security 文件导出越过工作区 ▶
  2. P1 插件状态按整轮计算 ▶
  3. P2 投影仍可能超出预算 ▶
Fix with agent prompt
### Issue 1
packages/maker-shared/src/payloadSummary.ts:487
这里会从任意工具结果文本中提取 `xdt-file://` 绝对路径,并将其显示为可导出的文件。移动端会把该 URL 原样交给桌面媒体取件;如果 URL 没有 `baseDir`,桌面只检查敏感目录黑名单,不会限制在当前会话的工作目录内。因此,恶意或被污染的插件结果可以指向其他项目或普通用户文档,并在用户点击后将文件上传和分享至手机。请在桌面端根据可信的 session/workdir 强制校验路径,而不要依赖 URL 自带的 `baseDir`。

**How this was verified:** 工具结果中的绝对 `xdt-file` 路径会原样到达桌面取件处理器,而该处理器在 URL 不含 `baseDir` 时只应用敏感目录黑名单、不执行工作目录边界检查。

### Issue 2
apps/mobile/src/session/MessageRenderer.tsx:3300
这里根据整个用户轮次是否仍在流式运行,为该消息下的所有插件传入同一个 `running` 状态,而没有检查每个 `ghost_call` 是否已经收到配对的 `tool_result`。当某个插件已经返回、但模型仍在生成回复或调用其他工具时,该插件仍会显示“调用中”;同一轮的多个插件也无法分别显示完成状态,直到整轮结束才一起变为“已调用”。请根据每次调用的配对结果聚合各插件的实际进行中状态。

### Issue 3
apps/desktop/src/main/device-link/mobileToolProjection.ts:51-64
这里完整复制命中的媒体、文件、音轨和动作字段,却没有限制数组数量、单项大小,也没有在 `JSON.stringify` 后重新检查总字节数。因此,这个 8 KiB 压缩分支仍可能生成数百 KiB、甚至超过传输帧限制的结果。插件返回大量引用或大型动作元数据时,实时事件可能退出批处理并被丢弃,`local-db:messages:created` 路径也没有可用的压缩重试,手机仍可能收不到这些产物。建议限制保留字段的总数量和总字节数,并验证最终序列化结果。

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.
Summary

此 PR 扩展了桌面到移动端的插件结果投影,并在移动会话中增加原生插件调用状态、只读卡片、媒体与文件展示。

  • 新增任务级远程卡片和插件公开身份资源,并在持久化后发送失效通知。
  • 扩展共享结果解析及历史投影,保留媒体、文件和卡片引用。
  • 移动端新增插件调用行、结果卡片、文件导出及账号、设备、重连生命周期围栏。
  • 当前仍存在工作区外文件取件风险、逐插件状态不准确,以及引用投影未真正受总字节预算约束的问题。
Diagram
sequenceDiagram
  participant P as 插件/工具
  participant D as 桌面投影与资源服务
  participant L as Device Link
  participant M as 移动会话
  P->>D: ghost_call 结果
  D->>D: 提取媒体、文件、卡片引用
  D->>L: 投影消息与资源失效通知
  L->>M: 会话消息/远程资源
  M->>D: 按任务读取只读卡片
  D-->>M: Markdown 与受管媒体块
  M->>D: 用户打开或导出文件
  D-->>M: 远程媒体下载地址
Loading

Reviews (1) · Last reviewed commit: "fix(mobile): preserve plugin results and..."

Comment thread packages/maker-shared/src/payloadSummary.ts
Comment thread apps/mobile/src/session/MessageRenderer.tsx
Comment thread apps/desktop/src/main/device-link/mobileToolProjection.ts Outdated
@zqchris

zqchris commented Sep 18, 2026

Copy link
Copy Markdown
Contributor Author

Windows unit tests (2/2) 日志核对:失败为 updateService.test.ts 两项 spawn 等待断言,以及 mirrorCacheStore.test.ts 两项 20s 超时。这两个测试文件及其对应实现与 PR 基线无差异。本地以 --maxWorkers=2 定向复跑两文件,189/189 通过;不能据此宣称 Windows 已通过。

已尝试单独重跑失败 job,GitHub 返回 “The workflow run containing this job is already running” (403):Windows (1/2) 仍在执行。保留原断言与产品代码,待本轮结束后复核/重跑失败分片。

@MagicLizi MagicLizi added status:conflict 与目标分支有冲突(review-pr 自动维护,仅展示) touches:core 改动碰到架构核心路径(review-pr 自动维护,仅展示) touches:plugin-base 改动碰到插件基座(review-pr 自动维护,仅展示) touches:product-ui 改动碰到产品 / UI 面(review-pr 自动维护,仅展示) touches:rules 改动碰到规则 / 规范文档(review-pr 自动维护,仅展示) labels Sep 18, 2026
Signed-off-by: zqchris <chrisz83@gmail.com>
@zqchris

zqchris commented Sep 18, 2026

Copy link
Copy Markdown
Contributor Author

已在 461cff2 同步主干 ca854f7 并解除冲突。唯一文本冲突为自动生成的 design-inventory,按合并后的源码重新生成并校验通过;Mobile 页面自动合并已核对,保留双方行为。

验证:Desktop/Mobile 的 test:unit:related、两包 typecheck、design-inventory 校验、diff 检查和 DCO 均通过。远端已回读为 MERGEABLE,等待新 head CI;之前 Windows 重跑不代表新 head 已通过。

@MagicLizi MagicLizi removed the status:conflict 与目标分支有冲突(review-pr 自动维护,仅展示) label Sep 18, 2026

@MagicLizi MagicLizi left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Findings

  • [P1] apps/mobile/src/session/MessageRenderer.tsx:3461 — 插件调用状态挂在用户气泡内部,但无正文/系统卡/secondaryBody 的附件消息会跳过整颗气泡。用户只发图/文件后触发插件时,调用中/已调用行、展开详情与公开图标都不会出现,与 PR 声称的「普通任务显示调用状态与详情」不符。建议把 PluginInvocationHeader 移出该 skip,或把 pluginInvocations?.length 计入 hasBubbleContent;用附件-only 用户消息加后续 ghost_call 做回归。验证:Mobile 定向单测覆盖该 render 路径,并在模拟器确认无正文附件消息仍显示调用行。

Rule coverage

  • AGENTS.md / docs/dev-rules/development-workflow.md / PR 模板:单一目标是远程手机插件产物与调用状态;描述与 diff 范围一致,无夹带无关功能。未改原生配置/fingerprint。
  • docs/dev-rules/plugin-security-and-authoring.md §5/§8:未改 receipt、manifest、包格式或安装布局;卡片/身份走只读 Remote Resource,不执行 HTML/脚本/动作。存量影响按描述为无。作者契约(FORGE_GUIDE)未改,无需手册同步。
  • docs/dev-rules/remote-and-mobile-adaptation.md:复用既有 remote-resources get/changed 与 media:fetch;未改 device-link 重试/断链半径。手机入口已做,Description 写明适配。
  • docs/dev-rules/media-storage-and-protocols.md:跨端只传托管 URL / 有界 data URL,不暴露宿主绝对路径;文件导出走既有 mediaFetch 受信通道。
  • docs/dev-rules/electron-security-and-process-boundaries.md:Main 侧 provider 再授权、再校验 session 归属与 data-owner scope。
  • docs/dev-rules/architecture-invariants.md:无新 package 反向依赖、无 main 动态 import、无布局树改动。
  • docs/dev-rules/mobile-development.md 冷更边界:未改 app.json / 原生依赖 / fingerprint 输入。
  • docs/dev-rules/protocol-compatibility.md:未改 wire schema;投影是控制端展示压缩,完整原文留宿主。
  • DESIGN.md §2/§3/§5/§10/§14.4:新 UI 走语义 token、44pt 点击目标、召唤双弧与 reduced-motion。PR 描述写了 iOS 实机验证但未附截图/录屏/HTML(非阻断)。
  • docs/design-rules/design-inventory.md:机器生成台账一行,不改变审查判据含义。
  • security.softHits:apps/mobile/src/tests/pluginResultRendering.test.ts:51 为测试里拒绝转发的占位字段名,不是真实凭证。

Verification

  • 已读完整 live diff、PR body、已 resolve 的 3 条 Greptile thread 及作者回复。
  • 未在本 worktree 跑 pnpm test:unit:related / typecheck:worktree 无 node_modules,禁止改工作区安装依赖。GitHub CI client-ci 与 pr-design-basis 对当前 head 为 success。
  • 未执行 Android/真机/Dark 目检(作者已声明未做)。

Overall

changes-requested(1 条 P1;没有 P0)

Comment thread apps/mobile/src/session/MessageRenderer.tsx Outdated
@MagicLizi

Copy link
Copy Markdown
Contributor

命中 UI 路径(apps/mobile/app/sessions/[sessionId].tsx / apps/mobile/src/device-link/remoteResources.ts / apps/mobile/src/session/MessageRenderer.tsx 等)但 description 未附界面效果证据——建议补充改动后效果:截图/录屏,或改动后界面的 HTML 页面(```html 代码块、.html 附件或在线预览链接),便于确认界面符合 DESIGN.md 设计规范。这不是合并阻断。

Signed-off-by: zqchris <chrisz83@gmail.com>
@zqchris

zqchris commented Sep 18, 2026

Copy link
Copy Markdown
Contributor Author

Linux (1/2) failure traced to upstream billing translations: the merge-result checkout lacks 13 billing keys in all five Desktop locales. Current PR head passes i18nCompleteness (5/5), and Mobile tests passed in the failing CI shard. Main regression tracked separately in #4696 with deletion history and log evidence. No test exemptions or unrelated billing changes added to this PR; CI remains blocked until the upstream fix is available.

@zqchris

zqchris commented Sep 18, 2026

Copy link
Copy Markdown
Contributor Author

Linux (2/2) adds two upstream integration failures, tracked with evidence in #4697: latest-catalogue sidebar restoration no longer matches its regression contract, and the auth initialization test harness lacks the newly referenced isCindyVersionLaunchPending dependency. Both suites pass on this PR branch (11/11); the merge-result checkout fails. Mobile tests passed in this shard too. verify only aggregates the Linux failures and has no independent failure. CI remains blocked by upstream #4696 and #4697; no assertions were weakened and no unrelated changes were added here.

Signed-off-by: zqchris <chrisz83@gmail.com>
@zqchris

zqchris commented Sep 19, 2026

Copy link
Copy Markdown
Contributor Author

Attempt 2 still tested the old merge snapshot and reproduced the missing billing translations. Latest main now includes the relevant updates, so I merged 3c6bedf into this branch and pushed afec5d6 to trigger fresh merge-result CI. Local validation passed: Desktop unit suite (including all three previously failing tests), Mobile unit suite after refreshing the lockfile-defined Expo patch, maker-shared/cindy-tools unit suites, Desktop/Mobile typechecks, design inventory and DCO. No new product behavior changes were added. Awaiting the new CI run and re-review.

Signed-off-by: zqchris <chrisz83@gmail.com>
@zqchris

zqchris commented Sep 19, 2026

Copy link
Copy Markdown
Contributor Author

Resolved the new conflict in dc374f4 by merging main 336b8a9 and regenerating the design inventory from the combined source. The only conflicted file was generated inventory; plugin behavior is unchanged and upstream share-bar changes are retained. Mobile unit gate, Mobile typecheck, inventory validation, diff check and DCO all passed. Awaiting fresh CI and re-review.

@MagicLizi MagicLizi left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Findings

  • 无 P0/P1。

Rule coverage

  • AGENTS.md / docs/dev-rules/development-workflow.md / .github/PULL_REQUEST_TEMPLATE.md:单一目标(远程手机保留插件产物与调用状态),模板三段齐全,风险写了协议/权限/跨平台与回滚。DCO 由既有门禁覆盖。
  • docs/dev-rules/plugin-security-and-authoring.md §4–6:未改 receipt/指纹/manifest/安装布局/包格式;卡片远程投影剥 HTML/脚本/动作,身份只暴露公开名与有界 raster data URL;list() 为空;get 绑定 session+callId 并二次授权。存量插件影响按用户可用性为无。作者契约(ghost.json/管子/FORGE_GUIDE)未改;hint 仅模型呈现口径。
  • docs/dev-rules/remote-and-mobile-adaptation.md:复用既有 Remote Resource get/changed 与 media:fetch,无新 IPC、无重试半径改动。手机入口已适配。Description 写明明确不包含桌面卡片按钮远程执行。
  • docs/dev-rules/protocol-compatibility.md:collection/blocks 为字段追加;旧端忽略未知 collection。投影只改控制端可见副本,不改宿主行。
  • docs/dev-rules/media-storage-and-protocols.md:不新建仓/协议;只传托管 URL。文件导出走既有 device-link:media:fetch,用户点击才取件。
  • docs/dev-rules/electron-security-and-process-boundaries.md:Main 侧授权+归属校验;Mobile 侧 getRemoteResource 只拷 data.url,不转发 actions/secret。
  • docs/dev-rules/credentials-and-local-storage.md:security.softHits 为测试桩占位(pluginResultRendering.test.ts:51,kind=credential-assignment),非真实凭证。
  • docs/dev-rules/architecture-invariants.md:无 package 反向依赖 Desktop Main;无 main 动态 import。
  • docs/dev-rules/mobile-development.md:无原生/fingerprint 改动。
  • docs/design-rules/DESIGN.md:调用行用语义 token、44pt 点击目标、召唤双弧与 reduced-motion;无硬编码色。UI 证据缺失为非阻断,历史已有 review-pr:ui-evidence-notice。
  • docs/product-rules/core-product-principles.md:修远程产物丢失,不把插件 HTML/动作搬到手机。
  • docs/dev-rules/engineering-conventions.md / i18n/GLOSSARY.md:五语 locale 同步;Plugin→插件。design-inventory 为生成清单登记 PluginInvocationHeader。
  • 先前 thread:附件-only 气泡、逐调用配对、8KiB 预算均已在当前 head 落地且 thread 已 resolve。

Verification

  • 前置:live context 与任务 head/base/diffHash 一致;gatePass=true;CI status=pass;unresolvedThreads=0;staleRebase 不阻塞;authorIsMaintainer 故审查前不 hold。
  • 定向单测:独立 worktree 无 node_modules,pnpm --filter desktop exec vitest 退出 254(Command "vitest" not found)。未把未运行写成通过。作者声明相关单测/typecheck 已过;本轮以 GitHub CI 全绿为合并证据。
  • 未执行:Android/Dark 目检、完整远程发送链路(作者已声明)。不构成 P0/P1。
  • botSettle:已等 ≥20 分钟超时放行;copilot-pull-request-reviewer / chatgpt-codex-connector 意见可能在合并后到达。

Overall

pass(没有 P0/P1)

@MagicLizi
MagicLizi merged commit c9fadf5 into makecindy:main Sep 19, 2026
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

touches:core 改动碰到架构核心路径(review-pr 自动维护,仅展示) touches:plugin-base 改动碰到插件基座(review-pr 自动维护,仅展示) touches:product-ui 改动碰到产品 / UI 面(review-pr 自动维护,仅展示) touches:rules 改动碰到规则 / 规范文档(review-pr 自动维护,仅展示)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants