Skip to content

feat(im): 新增 Lark 机器人接入 - #1133

Merged
MagicLizi merged 6 commits into
mainfrom
xdt/auto-35j0hm
Jul 31, 2026
Merged

feat(im): 新增 Lark 机器人接入#1133
MagicLizi merged 6 commits into
mainfrom
xdt/auto-35j0hm

Conversation

@DavidShenXD

Copy link
Copy Markdown
Collaborator

这次改了什么

摘要

在 Cindy 现有 IM transport 和桌面编排中加入 Lark 支持,让用户可以在飞书与 Lark 之间选择对应开放平台,并复用一致的私聊、附件、交互卡片、Agent 交互和跨对话通知能力。实现保持 Cindy 自有结构、命名与文案,同时保留现有飞书内部 channel ID 以兼容历史配置和调用方。

变更类型

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

范围

  • 关联 Issue / 需求:Lark IM 工具接入
  • 本 PR 包含:飞书/Lark 服务选择、SDK 与开放平台域名路由、注册流程、凭证服务类型持久化、owner 边界、Lark 对话标题、冲突弹窗、MCP 工具文案、四语 i18n、术语登记及回归测试
  • 明确不包含:新增技术设计 Markdown、服务端改动、Mobile 原生配置或依赖、真实企业凭证
  • 用户可见变化:Settings 的飞书机器人入口升级为“飞书 / Lark 机器人”,可选择对应服务并打开其开放平台;Lark 对话和冲突提示显示正确品牌
  • 是否存在 breaking change:无。旧凭证未保存服务类型时继续按飞书处理,现有 IPC/channel/tool ID 保持兼容

UI 变化

  • Settings 的 IM Bot 配置新增飞书/Lark 服务选择;注册入口、已保存服务与冲突弹窗会随服务切换
  • 引用的设计规范:docs/design-rules/DESIGN.md §2 Color Palette & Roles、§4 Component Stylings、§10 Theme System & Token Reference(含 Light / Dark 双模式门槛)、§11 Voice & Content。新增控件沿用语义 token,没有新增硬编码颜色

怎么验证的

自动验证

pnpm test:unit
结果:通过;Desktop、Mobile、IM、MCP 及其余要求执行的 workspace 均为 PASS

pnpm --filter desktop run --if-present typecheck
pnpm --filter @cindy/im build
pnpm --filter @cindy/mcps build
pnpm --filter @cindy/wechat-ilink run --if-present typecheck
结果:全部通过

pnpm --filter @cindy/im test
结果:22 个测试文件、243 项测试通过

pnpm check:i18n
pnpm check:i18n-glossary
结果:四语 key 一致,术语门禁无新增违规

pnpm check:dco
git diff --check origin/main..HEAD
结果:通过;PR 范围为 1 个 DCO 签名提交

手工验证

  • 不涉及:本次未使用真实 Lark 企业凭证进行端到端联调

未执行的验证

  • 未执行真实 Lark 企业 App 的 WebSocket、收发消息、附件和卡片联调:当前环境没有企业凭证
  • 未执行 Settings 的 Light / Dark 实机目检;实现沿用现有语义 token,但不将代码复用视为已完成视觉验证

风险

风险分类

  • 无已知风险
  • SQLite / migration
  • system prompt
  • 协议兼容
  • 权限 / 安全 / 用户数据
  • 原生层 / fingerprint / OTA
  • 跨平台差异
  • 其他:依赖 Lark 开放平台与 SDK 的线上行为

影响与回滚

  • 影响范围:Desktop Settings、@cindy/im 的飞书兼容 transport、相关 Desktop IM 编排和内置 IM 通知工具。凭证继续使用现有本地 secrets 存储,只新增服务类型标记
  • 回滚 / 降级方式:回滚本提交即可;用户侧也可清除机器人凭证或继续选择飞书服务
  • Mobile runtime fingerprint:未变化。本 PR 没有修改 apps/mobile、Mobile 原生配置、原生依赖、config plugin 或原生模块

提交前检查

  • 已 review 完整 diff
  • 每个 commit 都带 DCO 签名(git commit -s,见 DCO
  • UI 改动已在「UI 变化」注明引用的设计规范章节
  • 未提交凭证、令牌或授权文件
  • 已补充必要的既有工具说明;未提交新增设计 Markdown
  • 已确认测试结果或说明未执行原因

Copilot AI review requested due to automatic review settings July 31, 2026 01:37

Copilot AI 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.

Pull request overview

在现有 Feishu IM bot 通道的基础上引入 Lark 支持:增加“Feishu / Lark”服务选择与域名路由、凭证服务类型持久化与兼容旧凭证默认 Feishu,并同步更新 Desktop Settings UI、MCP 工具提示文案、i18n/术语登记与相关测试覆盖。

Changes:

  • @cindy/im 的 Feishu 通道中新增 service: 'feishu' | 'lark',用于 OpenAPI / WebSocket SDK 域名路由与凭证持久化(旧凭证缺省回落 Feishu)。
  • Desktop Settings 的“飞书机器人”升级为“飞书 / Lark 机器人”,支持服务切换、打开对应开放平台、以及冲突弹窗与通知文案的品牌适配。
  • MCP 工具提示与术语表/i18n 更新,并新增/更新多处单测覆盖服务路由与存储语义。

Reviewed changes

Copilot reviewed 37 out of 38 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
packages/wechat-ilink/src/transport.ts 调整 iLink aes_key 注释表述
packages/lizi-mcps/src/prompts/cindy_feishu_bot/tools/send_message_to_user.md 工具说明扩展到 Feishu/Lark
packages/lizi-mcps/src/prompts/cindy_feishu_bot/tools/send_file_to_user.md 工具说明扩展到 Feishu/Lark
packages/lizi-mcps/src/prompts/cindy_feishu_bot/tools/list_tools.md 工具列表文案更新为 Feishu/Lark
packages/lizi-mcps/src/prompts/cindy_feishu_bot/tools/call_tool.md 工具调用说明文案更新
packages/lizi-mcps/src/cindy_feishuBotMcpServer.ts MCP server 文案/格式调整与错误提示更新
packages/lizi-im/src/feishu/wsClient.ts WSClient 增加按 service 的 Domain 路由与相关文案更新
packages/lizi-im/src/feishu/storage.ts 凭证新增 service 存储键,兼容旧凭证默认 Feishu
packages/lizi-im/src/feishu/outbound.ts OpenAPI Client 增加按 service 的 Domain 路由
packages/lizi-im/src/feishu/messages.ts 生命周期离线文案泛化为“当前 IM”
packages/lizi-im/src/feishu/ipc.ts IPC 支持保存/注册时传入 service,并将 service 暴露到 public state
packages/lizi-im/src/feishu/internal-types.ts 新增 FeishuService 与 BotCredentials.service 字段
packages/lizi-im/src/feishu/index.ts FeishuIM 增加 getService() 供上层路由/展示
packages/lizi-im/src/feishu/appRegistration.ts 注册流程支持按 brand 路由 endpoints
packages/lizi-im/src/feishu/tests/wsClientConflict.test.ts 覆盖 WSClient domain 路由与格式调整
packages/lizi-im/src/feishu/tests/storageService.test.ts 新增 service 存储/回滚语义单测
packages/lizi-im/src/feishu/tests/serviceRouting.test.ts 新增 outbound domain 路由单测
packages/lizi-im/src/feishu/tests/ipcAccountScope.test.ts IPC payload 增加 service 并覆盖注册/切换语义
packages/lizi-im/src/feishu/tests/appRegistration.test.ts 新增 app registration 的 Lark endpoint 单测
i18n/GLOSSARY.md 术语表登记 Lark(proposed)
i18n/glossary.json glossary.json 新增 lark 条目(proposed)
apps/desktop/src/renderer/vite-env.d.ts Renderer 侧 ElectronAPI 类型增加 service 与 registrationBegin 入参
apps/desktop/src/renderer/i18n/locales/zh-CN/common.json 中文文案:Feishu/Lark 选择、冲突弹窗与通知文案更新
apps/desktop/src/renderer/i18n/locales/ko/common.json 韩文文案:Feishu/Lark 选择与相关文案更新
apps/desktop/src/renderer/i18n/locales/ja/common.json 日文文案:Feishu/Lark 选择与相关文案更新
apps/desktop/src/renderer/i18n/locales/en/common.json 英文文案:Feishu/Lark 选择与相关文案更新
apps/desktop/src/renderer/hooks/useFeishuBotRegistration.ts 注册 hook 增加 service 入参并透传到 IPC
apps/desktop/src/renderer/hooks/useFeishuBot.ts 状态/缓存/保存逻辑增加 service 字段
apps/desktop/src/renderer/hooks/tests/useFeishuBot.test.ts 覆盖 service hydrate + save 的单测
apps/desktop/src/renderer/components/settings/FeishuBotSection.tsx Settings UI 增加 Feishu/Lark 服务选择与开放平台跳转路由
apps/desktop/src/renderer/components/feishuBot/FeishuConflictDialogHost.tsx 冲突弹窗 host 增加按 service 路由打开平台链接
apps/desktop/src/renderer/components/feishuBot/FeishuConflictDialog.tsx 冲突弹窗增加 service 占位符渲染
apps/desktop/src/preload/preload.ts preload API:getState/save/registrationBegin 增加 service 透传
apps/desktop/src/main/im/shared/types.ts session 标题前缀支持 string 或 thunk
apps/desktop/src/main/im/shared/turnRunner.ts 生成标题逻辑支持动态前缀函数
apps/desktop/src/main/im/feishu/uiText.ts Feishu UI 文案泛化为“IM”表述
apps/desktop/src/main/im/feishu/adapter.ts 会话标题前缀随 service 切换(Feishu/Lark)
apps/desktop/src/main/im/feishu/tests/feishuAdapter.test.ts 覆盖 adapter 在 Lark 服务下的标题前缀行为

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread packages/lizi-mcps/src/prompts/cindy_feishu_bot/tools/call_tool.md Outdated
Comment thread apps/desktop/src/renderer/components/feishuBot/FeishuConflictDialog.tsx Outdated
Copilot AI review requested due to automatic review settings July 31, 2026 03:13
@DavidShenXD

Copy link
Copy Markdown
Collaborator Author

反馈已处理

已处理:

  • 冲突弹窗复用现有飞书 / Lark 服务名翻译,中文环境正确显示“飞书”。
  • 修正 NO_CHAT_CONTEXT 描述,使其与“无当前 chatId 且 bot 未绑定 owner”的实际语义一致。

变更:

  • FeishuConflictDialogserviceName 改由 settings.feishuBot.services.* 提供。
  • 更新 cindy_feishu_bot.call_tool 工具说明。

验证:

  • pnpm --filter desktop run --if-present typecheck:通过。
  • pnpm --filter @cindy/mcps test:通过(423 passed,2 skipped)。
  • pnpm check:i18n:通过。
  • pnpm check:i18n-glossary:通过。
  • pnpm test:unit:通过。
  • pnpm check:dco:通过(2 commits signed off)。

备注:

  • 已 rebase 最新 main 并使用 --force-with-lease 更新 PR 分支;未执行 UI 实机目检,未等待 GitHub Actions 完成。

Copilot AI 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.

Pull request overview

Copilot reviewed 37 out of 38 changed files in this pull request and generated no new comments.

Suppressed comments (6)

apps/desktop/src/renderer/components/settings/FeishuBotSection.tsx:339

  • 这个服务选择控件用 role="radiogroup"/"radio" 模拟单选,但当前按钮缺少 roving tabIndex 与方向键切换处理,键盘用户很难在两个选项间移动,属于可访问性缺口。建议跟 Settings 里 LanguageSection 的实现对齐:仅选中项 tabIndex=0,并在 ArrowLeft/Right/Up/Down 时切换服务。
              <button
                key={service}
                type="button"
                role="radio"
                aria-checked={selected}
                onClick={() => props.setService(service)}
                className={cn(

apps/desktop/src/renderer/i18n/locales/zh-CN/common.json:470

  • 这里的 aria 文案仍然只提到“飞书通知”,但该开关已升级为“飞书 / Lark 消息”。为避免读屏文案与实际功能不一致,建议同步更新 feishuAria
      "feishuLabel": "对话完成或需要回复时发送飞书 / Lark 消息",
      "feishuHint": "通过已绑定的飞书或 Lark 机器人,向你私聊发送一条消息;仅在窗口失焦时发送。",
      "feishuDisabledHint": "需要先在「飞书 / Lark 机器人」中配置 bot 并向它发送一条消息以完成绑定。",
      "feishuAria": "切换对话完成的飞书通知"

apps/desktop/src/renderer/i18n/locales/en/common.json:470

  • 这里的 aria 文案仍然写的是“FeiShu notifications”,但该开关现在覆盖 Feishu / Lark。建议把 feishuAria 更新为与 UI 一致的“Feishu / Lark notifications”,并统一大小写(上文已使用 Feishu)。
      "feishuLabel": "Send a Feishu / Lark DM when a session finishes or needs a reply",
      "feishuHint": "Sends a private message via the linked Feishu or Lark bot; only when the window is unfocused.",
      "feishuDisabledHint": "First set up the bot in \"Feishu / Lark Bot\" and DM it once to complete binding.",
      "feishuAria": "Toggle session-done FeiShu notifications"

apps/desktop/src/renderer/i18n/locales/ja/common.json:470

  • ここは aria 文言がまだ Feishu のみに言及していますが、機能は Feishu / Lark に拡張されています。feishuAria も同じく Feishu / Lark に更新して、読み上げ内容と実機表示を一致させてください。
      "feishuLabel": "セッション完了または返信が必要な時に Feishu / Lark メッセージを送信",
      "feishuHint": "連携済みの Feishu または Lark ボットからプライベートメッセージを送信します。ウィンドウが非アクティブの場合のみ送信。",
      "feishuDisabledHint": "先に「Feishu / Lark ボット」で設定し、ボットに 1 度メッセージを送ってバインドを完了してください。",
      "feishuAria": "セッション完了時の Feishu 通知を切り替え"

apps/desktop/src/renderer/i18n/locales/ko/common.json:470

  • aria 안내 문구가 아직 Feishu만 가리키고 있는데, 실제 기능은 Feishu / Lark 로 확장되었습니다. feishuAria 를 Feishu / Lark 로 맞춰 스크린리더 문구와 UI 의미가 어긋나지 않게 해주세요.
      "feishuLabel": "세션 완료 또는 응답 필요 시 Feishu / Lark 메시지 전송",
      "feishuHint": "연동된 Feishu 또는 Lark 봇을 통해 개인 메시지를 보냅니다. 창이 비활성 상태일 때만 전송됩니다.",
      "feishuDisabledHint": "먼저 \"Feishu / Lark 봇\"에서 봇을 설정하고 한 번 메시지를 보내 바인딩을 완료하세요.",
      "feishuAria": "세션 완료 Feishu 알림 전환"

packages/lizi-im/src/feishu/outbound.ts:62

  • 错误信息仍然写死为 “feishu connection not established”,在支持 Lark 后会误导排查(尤其是 service=lark 时)。建议把文案改成更中性的 “IM bot connection not established”。
function ensureClient(): Lark.Client {
  if (!client)
    throw new Error('[feishu/outbound] Lark.Client not bound — feishu connection not established');
  return client;

@DavidShenXD
DavidShenXD marked this pull request as ready for review July 31, 2026 11:55
@DavidShenXD
DavidShenXD requested a review from a team as a code owner July 31, 2026 11:55
@greptile-apps

greptile-apps Bot commented Jul 31, 2026

Copy link
Copy Markdown

Greptile Summary

本次变更在现有飞书兼容通道中加入 Lark 服务支持,并完成注册、连接与界面品牌路由。

  • 持久化凭证所属服务,并按飞书或 Lark 选择 SDK 域名、开放平台入口及用户文案
  • 注册轮询可根据租户品牌从飞书端点切换至 Lark,并持续处理 pendingslow_down
  • 为桌面设置、冲突提示、会话标题、MCP 文案和四语本地化补充对应支持

Confidence Score: 5/5

当前修复覆盖了此前报告的 Lark 跨域凭证补拉及暂态轮询问题,PR 看起来可以安全合并。

当前代码在发现 Lark 租户后切换轮询端点,并在 Lark 返回 pending、slow_down 或凭证尚不完整时继续轮询,因此没有阻塞性故障残留。

Important Files Changed

Filename Overview
packages/lizi-im/src/feishu/ipc.ts 注册轮询现可识别 Lark 租户、跨域补拉凭证,并在暂态响应后继续轮询。
packages/lizi-im/src/feishu/appRegistration.ts 注册响应保留暂态阶段发现的租户品牌,为后续端点切换提供依据。
packages/lizi-im/src/feishu/wsClient.ts WebSocket 客户端根据持久化服务类型选择飞书或 Lark SDK 域名。
packages/lizi-im/src/feishu/storage.ts 凭证存储新增服务类型,同时为历史凭证保留飞书默认值。
apps/desktop/src/renderer/components/settings/FeishuBotSection.tsx 设置界面新增飞书与 Lark 服务选择及对应品牌入口。

Sequence Diagram

sequenceDiagram
    participant UI as Desktop Settings
    participant IPC as IM IPC
    participant F as Feishu Registration
    participant L as Lark Registration
    participant WS as IM WebSocket
    UI->>IPC: 开始飞书/Lark 注册
    IPC->>F: 获取设备码并开始轮询
    alt 检测到 Lark 租户
        F-->>IPC: "tenantBrand=lark"
        IPC->>L: 继续轮询直至凭证完整
        L-->>IPC: clientId + clientSecret
    else 飞书租户
        F-->>IPC: clientId + clientSecret
    end
    IPC->>IPC: 持久化凭证及服务类型
    IPC->>WS: 使用对应服务域名连接
Loading

Reviews (7): Last reviewed commit: "fix(im): persist Lark registration polli..." | Re-trigger Greptile

Comment thread packages/lizi-im/src/feishu/ipc.ts

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 84b35bd2f1

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread packages/lizi-im/src/feishu/appRegistration.ts Outdated
Copilot AI review requested due to automatic review settings July 31, 2026 12:18
@DavidShenXD

Copy link
Copy Markdown
Collaborator Author

反馈已处理

已处理:

  • 恢复 Lark 一键注册的 Feishu bootstrap:设备码 begin 固定请求 accounts.feishu.cn,用户选择的服务仅决定验证页域名。
  • 恢复 Lark 跨域凭证补拉:首次从 Feishu 轮询识别到 tenantBrand=lark 且缺少 clientSecret 时,立即切到 Lark 端点补拉完整凭证。

变更:

  • 调整 appRegistration.tsipc.ts 的注册端点和跨域轮询逻辑,并保留异步补拉后的 account scope 校验。
  • 更新注册端点测试,新增 Feishu→Lark 两阶段轮询及 Lark 凭证持久化测试。
  • 修复提交:9a7c48a0,已推送至 xdt/auto-35j0hm

验证:

  • pnpm --filter @cindy/im exec vitest run src/feishu/__tests__/appRegistration.test.ts src/feishu/__tests__/ipcAccountScope.test.ts:通过,2 个文件、19 个测试。
  • pnpm --filter @cindy/im run build:通过。
  • pnpm test:unit -- --workspace-concurrency=1:通过,全仓 unit workspace 均通过。
  • pnpm --filter @cindy/im run --if-present typecheck:通过(该包无 typecheck script,命令按规则跳过;已由 build 执行 tsc --noEmit)。
  • pnpm check:dco:通过。
  • pnpm --filter @cindy/im run lint:未通过,仅命中本次未修改的 Telegram 既有未使用函数(telegram/inbound.tstelegram/index.ts)。

备注:

  • 未执行真实 Lark 租户扫码注册:需要外部账号环境;协议行为已按官方 Lark CLI 实现核对并由单元测试覆盖。
  • 未等待 GitHub Actions 或其他自动检查完成。

Copilot AI 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.

Pull request overview

Copilot reviewed 37 out of 38 changed files in this pull request and generated no new comments.

Suppressed comments (2)

packages/lizi-im/src/feishu/outbound.ts:62

  • ensureClient() 的异常信息仍写死为 “feishu connection not established”,但当前 outbound 已支持按 service 路由到 Feishu/Lark 两套域名;这里会在排障时误导为仅 Feishu 连接问题。建议改为更通用的 IM 表述(保留 tag 前缀即可)。
function ensureClient(): Lark.Client {
  if (!client)
    throw new Error('[feishu/outbound] Lark.Client not bound — feishu connection not established');
  return client;

packages/lizi-im/src/feishu/ipc.ts:86

  • 这里对 appId/appSecret 的长度校验发生在 trim() 之前:当 payload 传入全空白字符串时会通过校验,但随后被 trim 成空串并继续保存/连接,可能导致凭证被写入为空值并引发后续连接异常。建议对 trim 后的值再做一次非空校验(或改为先 trim 再校验)。
      (p.service !== 'feishu' && p.service !== 'lark') ||
      p.appId.length === 0 ||
      p.appSecret.length === 0
    ) {
      throw new Error('[INVALID_PAYLOAD] appId, appSecret and service required');

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

if (success.tenantBrand === 'lark' && !success.clientSecret) {

P1 Badge Handle cross-brand pending registration responses

Fresh evidence after the earlier bootstrap feedback is that this version now starts polling on Feishu, but it only switches to Lark after a Feishu success result with missing credentials. The official Lark CLI says the cross-brand tenant signal can arrive alongside non-final responses and that incomplete credentials should keep polling (source); in that case pollAppRegistration returns pending without exposing tenant_brand, so this loop keeps polling Feishu until expiry (or emits the missing-secret error) even though the user approved the Lark flow. Lark one-click registration can therefore time out despite successful authorization.

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

@MagicLizi

Copy link
Copy Markdown
Contributor

⏸️ 本 PR 触发 product 签字门(新增飞书 Bot 集成功能),等待放行名单成员 Approve 后继续。

讨论 issue 见下方链接。放行方式:直接在本 PR 上 Approve;需要修改就 Request Changes,作者改完后重新 Approve 即放行。

讨论 issue:#1220

@DavidShenXD

Copy link
Copy Markdown
Collaborator Author

反馈已处理

已处理:

  • 已确认 product 签字门有效:本 PR 新增飞书 / Lark Bot 接入,需要等待放行名单成员在 PR 上 Approve。

变更:

  • 无代码或文档改动;该反馈属于人工产品审核流程,不能也不应通过代码修改消除。

验证:

  • 未执行:本轮仅处理 product 签字门反馈,没有代码变更。

备注:

  • PR 当前等待 product 放行名单成员 Approve;未自行 Approve,也未 merge。需要调整时可由审核人 Request Changes,修改完成后再重新 Approve。

Copilot AI 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.

Pull request overview

Copilot reviewed 40 out of 41 changed files in this pull request and generated no new comments.

Suppressed comments (5)

packages/lizi-im/src/feishu/outbound.ts:61

  • 这里的异常信息仍写成“feishu connection not established”,但该 outbound 客户端现在同时用于 Feishu / Lark(domain 由 creds.service 决定)。错误信息应改为更通用的 IM 语义,避免在 Lark 场景下误导排障。
    apps/desktop/src/renderer/i18n/locales/en/common.json:470
  • 本次已将通知文案升级为“Feishu / Lark”,但 aria 文案仍是 “FeiShu notifications”,屏幕阅读器会读到与实际功能不一致的品牌信息。建议同步更新为 Feishu / Lark。
      "feishuLabel": "Send a Feishu / Lark DM when a session finishes or needs a reply",
      "feishuHint": "Sends a private message via the linked Feishu or Lark bot; only when the window is unfocused.",
      "feishuDisabledHint": "First set up the bot in \"Feishu / Lark Bot\" and DM it once to complete binding.",
      "feishuAria": "Toggle session-done FeiShu notifications"

apps/desktop/src/renderer/i18n/locales/zh-CN/common.json:470

  • 本次已将通知文案升级为“飞书 / Lark”,但 aria 文案仍是“飞书通知”,对辅助技术用户会产生不一致的提示。建议同步更新 aria 文案为“飞书 / Lark”。
      "feishuLabel": "对话完成或需要回复时发送飞书 / Lark 消息",
      "feishuHint": "通过已绑定的飞书或 Lark 机器人,向你私聊发送一条消息;仅在窗口失焦时发送。",
      "feishuDisabledHint": "需要先在「飞书 / Lark 机器人」中配置 bot 并向它发送一条消息以完成绑定。",
      "feishuAria": "切换对话完成的飞书通知"

apps/desktop/src/renderer/i18n/locales/ja/common.json:470

  • 本次已将通知文案升级为“Feishu / Lark”,但 aria 文案仍是“Feishu 通知”。为避免屏幕阅读器读到不一致的品牌信息,建议同步更新为 Feishu / Lark。
      "feishuLabel": "セッション完了または返信が必要な時に Feishu / Lark メッセージを送信",
      "feishuHint": "連携済みの Feishu または Lark ボットからプライベートメッセージを送信します。ウィンドウが非アクティブの場合のみ送信。",
      "feishuDisabledHint": "先に「Feishu / Lark ボット」で設定し、ボットに 1 度メッセージを送ってバインドを完了してください。",
      "feishuAria": "セッション完了時の Feishu 通知を切り替え"

apps/desktop/src/renderer/i18n/locales/ko/common.json:470

  • 本次已将通知文案升级为“Feishu / Lark”,但 aria 文案仍是“Feishu 알림”。为保证辅助技术提示一致,建议同步更新 aria 文案为 Feishu / Lark。
      "feishuLabel": "세션 완료 또는 응답 필요 시 Feishu / Lark 메시지 전송",
      "feishuHint": "연동된 Feishu 또는 Lark 봇을 통해 개인 메시지를 보냅니다. 창이 비활성 상태일 때만 전송됩니다.",
      "feishuDisabledHint": "먼저 \"Feishu / Lark 봇\"에서 봇을 설정하고 한 번 메시지를 보내 바인딩을 완료하세요.",
      "feishuAria": "세션 완료 Feishu 알림 전환"

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

if (success.tenantBrand === 'lark' && !success.clientSecret) {

P1 Badge Keep polling after Lark brand discovery

When a Lark registration reports tenant_brand=lark before complete credentials are ready, this branch only switches after a success result with a missing secret and then performs a single Lark poll; if Lark returns authorization_pending/slow_down or another incomplete 200 response, the flow falls through to the missing-secret error instead of continuing on the Lark domain. The official discovery loop switches as soon as tenant_brand is present, even on pending responses, and keeps polling incomplete credentials (source), so valid Lark one-click registrations can fail intermittently depending on poll timing.

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

@dashhuang dashhuang left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

产品签字确认,同意恢复推进。此批准仅代表产品 / UI 方向确认;现有技术审阅意见仍需按流程处理。

Copilot AI review requested due to automatic review settings July 31, 2026 12:51

Copilot AI 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.

Pull request overview

Copilot reviewed 40 out of 41 changed files in this pull request and generated no new comments.

Suppressed comments (3)

apps/desktop/src/renderer/components/settings/FeishuBotSection.tsx:366

  • 这里用 role="radiogroup"/role="radio" 实现服务切换,但缺少 roving tabIndex 与方向键切换处理;键盘用户在组内导航体验会明显弱于同项目的 LanguageSection(支持 Arrow 键)。建议给选中项设置 tabIndex=0,其余为 -1,并处理 ArrowLeft/Right/Up/Down 切换选项。
              <button
                key={service}
                type="button"
                role="radio"
                aria-checked={selected}

packages/lizi-im/src/feishu/outbound.ts:62

  • ensureClient() 抛错文案仍写成“feishu connection not established”,在接入 Lark 后该错误也可能发生于 Lark 场景,会误导排障方向。建议改成与服务无关的 IM 连接描述。
    packages/lizi-im/src/feishu/ipc.ts:308
  • 当 tenantBrand=lark 且首次 poll 未返回 clientSecret 时,这里会再 poll 一次 Lark;但这次 poll 没有 try/catch。若网络/SDK 抛错,会导致 pollRegistrationInBackground 直接抛出(因为它是后台 fire-and-forget),从而漏发 registration-status:error,且可能产生未处理的 Promise rejection。建议对二次 poll 同样做错误捕获并广播 error。

Comment thread packages/lizi-im/src/feishu/ipc.ts Outdated
@DavidShenXD

Copy link
Copy Markdown
Collaborator Author

反馈已处理

已处理:

  • 已修复 Lark 品牌发现信息在 authorization_pending 或凭证未完整响应中被丢弃的问题;检测到 tenant_brand=lark 后,轮询状态机立即从飞书域切换到 Lark 域。
  • 已修复 Lark 二次 poll 只尝试一次的问题;Lark 返回 pending、slow_down 或未完整凭证时,会在原注册截止时间内继续轮询,不再提前判定注册失败。

变更:

  • appRegistration poll 结果携带可选 tenantBrand,并将无错误但凭证未完整的响应视为 pending。
  • 注册状态机维护当前 pollBrand,一次性即时切换到 Lark,并以实际轮询域作为最终凭证品牌兜底。
  • 新增品牌发现、跨域切换、Lark pending 重试和不完整凭证重试测试。

验证:

  • pnpm --filter @cindy/im test:247/247 通过。
  • pnpm --filter @cindy/im build:通过。
  • 相关文件 ESLint:通过。
  • pnpm test:unit:通过。
  • pnpm check:dco:通过。

备注:

  • 已推送提交 a45377b;未等待 GitHub Actions 或其他远端检查完成。

Copilot AI 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.

Pull request overview

Copilot reviewed 40 out of 41 changed files in this pull request and generated no new comments.

Suppressed comments (1)

packages/lizi-im/src/feishu/outbound.ts:62

  • 这里的报错文案仍写成 “feishu connection not established”,在已支持 Lark 的情况下会误导排查(同样的调用路径也可能是 Lark 域名/凭证)。建议改成与品牌无关的描述(例如 “IM connection not established” / “IM bot connection not established”),或把 service 打出来。

@DavidShenXD DavidShenXD changed the title feat(im): add Lark bot integration feat(im): 新增 Lark 机器人接入 Jul 31, 2026

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: a45377bfa8

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread apps/desktop/src/renderer/i18n/locales/en/common.json Outdated
@MagicLizi

Copy link
Copy Markdown
Contributor

@DavidShenXD 👋 这个 PR 还有 1 条 review conversation 没 resolve(apps/desktop/src/renderer/i18n/locales/en/common.json),auto-review 因此暂时跳过、没法继续审查 / 合并。

如果你已经按评论改完或回应了,请到对应 thread 上点 Resolve conversation;全部 resolve 后,下一轮 auto-review 会自动重新审查这个 PR。

Copilot AI review requested due to automatic review settings July 31, 2026 13:48
@DavidShenXD

Copy link
Copy Markdown
Collaborator Author

反馈已处理

已处理:

  • 修正 CN/dev 个人云账号场景的个人 IM 提示,不再展示该场景不可用的 Lark。

变更:

  • 将 en、zh-CN、ja、ko 的 personalFeishuOnly 文案恢复为仅描述飞书;未改动渠道可见性逻辑。

验证:

  • pnpm test:unit:通过。
  • pnpm --filter desktop run --if-present typecheck:通过。
  • pnpm check:i18n-glossary:通过。

备注:

  • 首轮测试曾遇到 Windows Vitest fork / 测试锁环境性失败,最终完整重跑通过;无剩余代码风险。

Copilot AI 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.

Pull request overview

Copilot reviewed 40 out of 41 changed files in this pull request and generated no new comments.

Suppressed comments (1)

packages/lizi-im/src/feishu/outbound.ts:62

  • 这里的异常信息仍写成“feishu connection not established”,但该模块已支持根据凭据选择 Feishu/Lark domain;错误文案建议改为更中性的 IM/机器人连接描述,避免误导排查。

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 5139ab53c9

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread packages/lizi-mcps/src/cindy_feishuBotMcpServer.ts
Signed-off-by: DavidShen <david@xd.com>
Signed-off-by: david <david@xd.com>
Signed-off-by: david <david@xd.com>
Signed-off-by: david <david@xd.com>
Signed-off-by: david <david@xd.com>
Signed-off-by: david <david@xd.com>
Copilot AI review requested due to automatic review settings July 31, 2026 14:29

Copilot AI 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.

Pull request overview

Copilot reviewed 40 out of 41 changed files in this pull request and generated no new comments.

Suppressed comments (5)

packages/lizi-im/src/feishu/outbound.ts:62

  • ensureClient() 的错误信息仍写成“feishu connection not established”,在已支持 Lark 的情况下会误导排障(同一错误会发生在 Lark 连接未绑定时)。建议改成更中性的 IM 表述(或同时涵盖 Feishu/Lark)。
    apps/desktop/src/renderer/i18n/locales/en/common.json:470
  • 这里的 aria 文案仍写成 “FeiShu notifications”,但同一段落已升级为 “Feishu / Lark”。建议同步更新以避免辅助功能读屏与实际功能不一致(顺便统一 Feishu 的大小写)。
      "feishuLabel": "Send a Feishu / Lark DM when a session finishes or needs a reply",
      "feishuHint": "Sends a private message via the linked Feishu or Lark bot; only when the window is unfocused.",
      "feishuDisabledHint": "First set up the bot in \"Feishu / Lark Bot\" and DM it once to complete binding.",
      "feishuAria": "Toggle session-done FeiShu notifications"

apps/desktop/src/renderer/i18n/locales/zh-CN/common.json:470

  • 这里的 aria 文案仍只提“飞书”,但同一段落已改为“飞书 / Lark”。Screen reader 会读到不一致的服务名,建议同步更新。
      "feishuLabel": "对话完成或需要回复时发送飞书 / Lark 消息",
      "feishuHint": "通过已绑定的飞书或 Lark 机器人,向你私聊发送一条消息;仅在窗口失焦时发送。",
      "feishuDisabledHint": "需要先在「飞书 / Lark 机器人」中配置 bot 并向它发送一条消息以完成绑定。",
      "feishuAria": "切换对话完成的飞书通知"

apps/desktop/src/renderer/i18n/locales/ja/common.json:470

  • aria 文案仍只提 Feishu,但同一段落已变为 Feishu / Lark。读屏会产生不一致,建议同步更新。
      "feishuLabel": "セッション完了または返信が必要な時に Feishu / Lark メッセージを送信",
      "feishuHint": "連携済みの Feishu または Lark ボットからプライベートメッセージを送信します。ウィンドウが非アクティブの場合のみ送信。",
      "feishuDisabledHint": "先に「Feishu / Lark ボット」で設定し、ボットに 1 度メッセージを送ってバインドを完了してください。",
      "feishuAria": "セッション完了時の Feishu 通知を切り替え"

apps/desktop/src/renderer/i18n/locales/ko/common.json:470

  • aria 문구가 아직 Feishu만 언급하지만, 같은 섹션의 라벨/힌트는 Feishu / Lark로 확장되었습니다. 스크린리더 일관성을 위해 aria 문구도 함께 갱신하는 게 좋습니다.
      "feishuLabel": "세션 완료 또는 응답 필요 시 Feishu / Lark 메시지 전송",
      "feishuHint": "연동된 Feishu 또는 Lark 봇을 통해 개인 메시지를 보냅니다. 창이 비활성 상태일 때만 전송됩니다.",
      "feishuDisabledHint": "먼저 \"Feishu / Lark 봇\"에서 봇을 설정하고 한 번 메시지를 보내 바인딩을 완료하세요.",
      "feishuAria": "세션 완료 Feishu 알림 전환"

@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.

Review passed: well-structured Lark integration with proper input validation at IPC boundaries, transactional credential storage with rollback, backward-compatible defaults, correct owner-boundary clearing, masked secrets in logs, and comprehensive test coverage. No P0/P1 findings.

@MagicLizi
MagicLizi merged commit 8d6952e into main Jul 31, 2026
13 of 14 checks passed
@MagicLizi
MagicLizi deleted the xdt/auto-35j0hm branch July 31, 2026 14:42
@MagicLizi

Copy link
Copy Markdown
Contributor

Lark 接入架构扎实——凭证事务性存储带回滚、服务切换时正确清理边界、secrets 全程 mask,测试也覆盖到了新路径的关键分支。

dashhuang added a commit that referenced this pull request Jul 31, 2026
rebase 到最新 origin/main(带进 Lark 接入 #1133、钉钉连接器一整串、侧栏 mod+1..9
快速切换 #1184 等 20+ 提交),按 task-and-conversation-naming.md 逐条过了新增文案。

冲突 1 处(zh-CN/common.json 的 settings.notifications):main 把飞书改成
「飞书 / Lark」,本 PR 把「对话」改成「任务」—— 取两者合并。

新带进的 21 条含术语词文案,逐条判断后改 19 条:

- settings.shortcuts.items.switch-session-1..9 的 label + description(18 条):
  zh 写「切换到第 N 个对话」「跳转到侧边栏第 N 个可见对话」,而 en 是
  `Go to session N` / `…visible session in the sidebar`,ja/ko 也已是
  セッション / 세션 —— 典型的中英不成对(§4.2),且指的就是侧栏条目(§2.2)。
  只改 zh,其余三语本就正确
- im/dingtalk/uiText.ts 的 `/stop 停止当前任务,并撤掉排队消息` →「中止当前执行」。
  新渠道的文案包重复了同一个坑:/stop 只中止执行、任务条目保留(§3.1、与
  telegram / wechat 已改的同款)

判为正确保留的:
- channelDescriptions.dingtalk「钉钉新对话会使用…已有对话发送 /new 后应用」——
  与其它渠道同款,且 /new 不产生新任务(§6.0.3)
- dingtalk 的 `/new 开个新对话(清掉当前上下文)`——同上
- imBot.tips.personalFeishuOnly 里的「新对话配置」——设置项真名
- 新增的 hook-control LLM 指令串(「当前是 Slack 会话」「飞书 / Lark session」等)
  ——给模型读的,不是 UI 文案(§6.0.4)

门禁:GATE_EXIT=0;desktop / mobile / maker-shared / maker-core typecheck 全 0;
check:i18n ✅ 6168 key 四语一致;check:i18n-glossary ✅。

Signed-off-by: Dash <dashhuang@gmail.com>
dashhuang added a commit that referenced this pull request Jul 31, 2026
rebase 到最新 origin/main(带进 Lark 接入 #1133、钉钉连接器一整串、侧栏 mod+1..9
快速切换 #1184 等 20+ 提交),按 task-and-conversation-naming.md 逐条过了新增文案。

冲突 1 处(zh-CN/common.json 的 settings.notifications):main 把飞书改成
「飞书 / Lark」,本 PR 把「对话」改成「任务」—— 取两者合并。

新带进的 21 条含术语词文案,逐条判断后改 19 条:

- settings.shortcuts.items.switch-session-1..9 的 label + description(18 条):
  zh 写「切换到第 N 个对话」「跳转到侧边栏第 N 个可见对话」,而 en 是
  `Go to session N` / `…visible session in the sidebar`,ja/ko 也已是
  セッション / 세션 —— 典型的中英不成对(§4.2),且指的就是侧栏条目(§2.2)。
  只改 zh,其余三语本就正确
- im/dingtalk/uiText.ts 的 `/stop 停止当前任务,并撤掉排队消息` →「中止当前执行」。
  新渠道的文案包重复了同一个坑:/stop 只中止执行、任务条目保留(§3.1、与
  telegram / wechat 已改的同款)

判为正确保留的:
- channelDescriptions.dingtalk「钉钉新对话会使用…已有对话发送 /new 后应用」——
  与其它渠道同款,且 /new 不产生新任务(§6.0.3)
- dingtalk 的 `/new 开个新对话(清掉当前上下文)`——同上
- imBot.tips.personalFeishuOnly 里的「新对话配置」——设置项真名
- 新增的 hook-control LLM 指令串(「当前是 Slack 会话」「飞书 / Lark session」等)
  ——给模型读的,不是 UI 文案(§6.0.4)

门禁:GATE_EXIT=0;desktop / mobile / maker-shared / maker-core typecheck 全 0;
check:i18n ✅ 6168 key 四语一致;check:i18n-glossary ✅。

Signed-off-by: Dash <dashhuang@gmail.com>
dashhuang added a commit that referenced this pull request Jul 31, 2026
rebase 到最新 origin/main(带进 Lark 接入 #1133、钉钉连接器一整串、侧栏 mod+1..9
快速切换 #1184 等 20+ 提交),按 task-and-conversation-naming.md 逐条过了新增文案。

冲突 1 处(zh-CN/common.json 的 settings.notifications):main 把飞书改成
「飞书 / Lark」,本 PR 把「对话」改成「任务」—— 取两者合并。

新带进的 21 条含术语词文案,逐条判断后改 19 条:

- settings.shortcuts.items.switch-session-1..9 的 label + description(18 条):
  zh 写「切换到第 N 个对话」「跳转到侧边栏第 N 个可见对话」,而 en 是
  `Go to session N` / `…visible session in the sidebar`,ja/ko 也已是
  セッション / 세션 —— 典型的中英不成对(§4.2),且指的就是侧栏条目(§2.2)。
  只改 zh,其余三语本就正确
- im/dingtalk/uiText.ts 的 `/stop 停止当前任务,并撤掉排队消息` →「中止当前执行」。
  新渠道的文案包重复了同一个坑:/stop 只中止执行、任务条目保留(§3.1、与
  telegram / wechat 已改的同款)

判为正确保留的:
- channelDescriptions.dingtalk「钉钉新对话会使用…已有对话发送 /new 后应用」——
  与其它渠道同款,且 /new 不产生新任务(§6.0.3)
- dingtalk 的 `/new 开个新对话(清掉当前上下文)`——同上
- imBot.tips.personalFeishuOnly 里的「新对话配置」——设置项真名
- 新增的 hook-control LLM 指令串(「当前是 Slack 会话」「飞书 / Lark session」等)
  ——给模型读的,不是 UI 文案(§6.0.4)

门禁:GATE_EXIT=0;desktop / mobile / maker-shared / maker-core typecheck 全 0;
check:i18n ✅ 6168 key 四语一致;check:i18n-glossary ✅。

Signed-off-by: Dash <dashhuang@gmail.com>
dashhuang added a commit that referenced this pull request Jul 31, 2026
rebase 到最新 origin/main(带进 Lark 接入 #1133、钉钉连接器一整串、侧栏 mod+1..9
快速切换 #1184 等 20+ 提交),按 task-and-conversation-naming.md 逐条过了新增文案。

冲突 1 处(zh-CN/common.json 的 settings.notifications):main 把飞书改成
「飞书 / Lark」,本 PR 把「对话」改成「任务」—— 取两者合并。

新带进的 21 条含术语词文案,逐条判断后改 19 条:

- settings.shortcuts.items.switch-session-1..9 的 label + description(18 条):
  zh 写「切换到第 N 个对话」「跳转到侧边栏第 N 个可见对话」,而 en 是
  `Go to session N` / `…visible session in the sidebar`,ja/ko 也已是
  セッション / 세션 —— 典型的中英不成对(§4.2),且指的就是侧栏条目(§2.2)。
  只改 zh,其余三语本就正确
- im/dingtalk/uiText.ts 的 `/stop 停止当前任务,并撤掉排队消息` →「中止当前执行」。
  新渠道的文案包重复了同一个坑:/stop 只中止执行、任务条目保留(§3.1、与
  telegram / wechat 已改的同款)

判为正确保留的:
- channelDescriptions.dingtalk「钉钉新对话会使用…已有对话发送 /new 后应用」——
  与其它渠道同款,且 /new 不产生新任务(§6.0.3)
- dingtalk 的 `/new 开个新对话(清掉当前上下文)`——同上
- imBot.tips.personalFeishuOnly 里的「新对话配置」——设置项真名
- 新增的 hook-control LLM 指令串(「当前是 Slack 会话」「飞书 / Lark session」等)
  ——给模型读的,不是 UI 文案(§6.0.4)

门禁:GATE_EXIT=0;desktop / mobile / maker-shared / maker-core typecheck 全 0;
check:i18n ✅ 6168 key 四语一致;check:i18n-glossary ✅。

Signed-off-by: Dash <dashhuang@gmail.com>
GaoWeiLiuXD pushed a commit to GaoWeiLiuXD/cindy that referenced this pull request Jul 31, 2026
* feat(i18n): session 面向用户改称「任务」,并厘清任务/对话/消息的边界

`session` 原先中文译作「对话」,这个词表达不出 Cindy 最重要的能力——同时跑
多个互不干扰的工作。用户看不出左侧列表里的每一条其实是一个有自己空间、可以
并行推进的独立工作。

但这不是全局替换。概念分三层,各有明确所指:

  任务 (Session) —— 左侧列表里可打开 / 删除 / 分享的条目
  对话 (Chat)    —— 任务内人与 AI 交流的过程与内容
  消息 (Message) —— 对话里的一条往来

「轮次」刻意不作为界面术语:AI 在一轮里的思考与工具调用最终折叠成一条消息,
所以消息与轮次是同粒度的两种切法、不是包含关系——现有删除行为就是这个口径
(「AI 消息会删除上一次用户输入之后产生的整轮输出」)。弹窗 (Dialog) 与本次
改名无关,未动。

英文侧一并收敛。改名前同一个东西有五种写法,只改中文治不了根——写文案的人看到
`Dialogue` 仍会译成「对话」:`conversation`(124) 与 `dialogue`(16) 全部改为
`session`,指容器的 `chat`(53) 同样改为 `session`,`chat` 仅保留 12 处指交流
过程与内容(chat history / chat panel / chat text)。

「任务」与 `task` 的歧义是落地最大的坑:"This session is currently running a
task" 直译会变成「当前任务正在执行任务」。原则是**同句出现时 task 一侧必须
改写**(优先动词化,确需名词用「执行」/「作业」),不同句且语境清晰时沿用
「任务」(104 处未动,「后台任务」「定时任务」本身不歧义)。`automation` 原先
叫「自动化任务」,与 session 同句会出现「删除任务和任务」这种读不通的文案,
中文统一为「自动化」——英文侧本来就以 `automation`(38) 为主、只有 4 处叫
`automation task`。

顺带修掉两批既有译名错误(与改名无关,本来就该修):42 处英文是 `message` 却
译成「对话」("Delete this message" → 「删除本条对话」)、7 处英文是 `turn`
同样译成「对话」。

未改:代码标识符与内部字段;ja / ko 文案(セッション / 세션 是音译,不存在中文
这种一词多义);SSH 远程会话 / Agent 进程会话 / 登录绑定会话 / 操作系统桌面
会话(那是另一类 session,与产品概念无关)。

门禁不能笼统禁「对话」——那会把「对话区」「对话正文」这些合法用法一并拦下。
`session` 用 alsoAllowed + when 按语境豁免;`message` 的 forbidden 收窄到精确
的错译形式「条对话」,因为一句话里可能既有 message 又有合法的「对话X」,机器
分不清对应关系。

验证:pnpm test:unit 全绿(desktop 16537 / mobile 2660 / 根 316,零失败);
desktop 与 mobile typecheck 通过;pnpm check:i18n-glossary 通过。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Dash <dashhuang@gmail.com>

* fix(i18n): /new 类命令改回「新对话」,并把四个 IM 渠道文案包一起收敛

review 第 8 轮。两条反馈同一不变量: IM 的 `/new` 走 resetSessionToDefaults,
只 UPDATE 原 session 行、不产生可单独打开的条目,所以描述这条路径的文案不能
说「新任务」。按落库行为(INSERT / UPDATE)重新判定了整族触点:

- settings.wechatBot.workingDir.* 与 toasts.workingDir*: 四语回 origin/main
  的 conversation 口径(该设置同时管首次私聊与 /new,只有「新对话」两边都成立)
- settings.telegramBot.commandMenu.new: zh 回「开启新对话」;en/ja/ko 一并按
  §4.2 成对改成 chat / 会話 / 대화(原文 session 同样不准确)
- settings.telegramBot.commandMenu.stop: 「停止当前任务」→「中止当前执行」。
  /stop 只中止执行、条目保留,而本 PR 让「任务」专指条目;en/ja/ko 的
  task/タスク/작업 不与 session 撞车,保持不动

同时做收敛检查点(同族第 3 轮返工): 上轮只改了 telegram/uiText.ts,而 discord /
feishu / wechat 是同形近亲文案包。本轮四个包一起过完,「会话」在这四个文件清零
——接管流程指桌面条目的改「任务」,同句含 task 的按 §3.1 消歧,引用设置项名字的
改成「新对话配置」,🤖 自动任务 → 🤖 自动化。刻意保留三个渠道的「存档 / 上号」
(feishu/uiText.ts 文件头写明的渠道语气,非错译)。

另修 copilot 指出的两处:
- sessionActionStrip 的 filesDisabledReason 判据只是 !!workingDir,不能断言
  「因为不绑项目」(同文件测试 fixture 恰好是有 worktreePath 的 Orca Worker),
  改成只陈述状态;测试断言同步
- codex agent 的 memory description: 「从聊天中」→「从对话中」(聊天是 chat
  条目的 forbidden 译法)

规则落进 task-and-conversation-naming.md §6.0.3 / §6.0.4,并按读者把全仓 102 处
硬编码「会话」分了改与不改。

Signed-off-by: Dash <dashhuang@gmail.com>

* fix(i18n): 同步注释与测试常量里已过时的「未命名对话」等文案陈述

review 第 9 轮。copilot 连两轮列出不同实例,做检查点后归成一族: 注释或测试常量
里**断言「用户看到的是 X」**的地方,X 已被本 PR 改掉,注释就变成了错的 —— 比不改
更坏,后来人会照注释把代码往反方向"修正"。

- 「未命名对话」→「未命名任务」41 处 / 20 个文件: 兜底文案实际值已是「未命名任务」
  (ccAgent.common.unnamedSession / sessionHeader.untitled / mobile
  devices.list.untitled 实测)。含 test 里 `const UNNAMED = '未命名对话'` 这类替身
  常量 —— 值是注入的、不影响行为,但留着会变成下一个人改代码的依据
- hook-control/__tests__/interactions.test.ts: 「注:按钮文案用「对话」」而按钮已是
  「本任务总是允许」
- sessionList.ts / sessionTitleProjection.test.ts: 同段注释里「会话」与「任务」混用

泛指 session 的普通注释仍按 §8 不动(「idle 会话直接显示」这类)。

另把 im/shared/__tests__/threadUiFixture.ts 整体回退到 origin/main: 它保存的是
2026-07-17 退役的 SlackIM 文案包原件(文件头写明不进产品包),价值就是忠实副本;
上轮误改 4 句,反而让「开一个新会话」与「同一个任务」并列进同一句。三个引用它的
测试只按结构使用,不断言这些字面量。

copilot 另提的 shared 层硬编码中文(remoteSessionListTitle /
deviceSessionEmptyState / mobile messageActionMenu)是 origin/main 既有状态,
下沉到 i18n 属独立重构,已记进 §8 遗留。规则落进 §6.0.5。

Signed-off-by: Dash <dashhuang@gmail.com>

* fix(i18n): 补上「原样展示给用户」的三条路径,并修正过宽的不改规则

review 第 10 轮。三条反馈都指向同一件事: 判据不能按文件目录归类,只能按
**这句话会不会原样出现在用户眼前**。

- maker-ipc/sessionReferenceResolver.ts(14 处): SessionReferenceError 经
  agent-input-coordinator::resolveReferenceContexts 落进 projection.error,
  CCAgentSessionView 的 ErrorBanner **原样展示**(同文件测试
  `error).toContain('snapshot is missing')` 钉着这条链)。所以粘贴「任务链接」
  失败时用户看到的是「找不到本机会话」「最多引用 N 个会话」。全部改「任务」;
  「无效的会话历史」按 §2 改「无效的对话记录」
- maker-ipc/register.ts: renameSessionsConfirmBridge 把「批量重命名会话」的确认卡
  交给 desktopConfirmImNotifier,飞书通知原文即此串,而桌面卡片已是「确认批量
  重命名任务」—— 同一次确认两套术语
- commands/builtins.ts: /clear 描述引用了侧栏「New Chat」按钮,该标签已不存在
  (现为 New / 新建)。改成不引用标签的说法;顺带 /jump-session 的「跳转到该会话」
- help-knowledge/collaboration.md 同样引用 "New Chat",改后跑 pnpm gen:help-kb
  重新生成 helpKnowledge.generated.ts(help-kb-guard PASS)

顺带修掉一处 origin/main 既有乱码: sessionReferenceResolver.ts 有两句
`来源设备返回了无效的会话历史` 存成了 UTF-8 字节按 GBK 解过一遍的形态
(鏉ユ簮璁惧杩斿洖浜嗘棤鏁堢殑浼氳瘇鍘嗗彶),真触发时用户看到乱码。

文档侧把 §6.0.4 那条过宽的规则改掉(原文把「main 抛给 renderer 的 Error」整类判成
不改,只对 fork / rewind 那种按 code 映射 i18n 的成立),并补上连续四轮返工的路径
清单 —— 每轮漏的都是一条**展示路径**,不是一个目录。

Signed-off-by: Dash <dashhuang@gmail.com>

* fix(i18n): 枚举 main 侧全部"直送用户"出口,补齐通知与 device-link 文案

review 第 11 轮,同族第 5 次返工 —— 触发收敛检查点,这轮不再逐条等 reviewer 点,
把 main 侧的出口(sink)一次枚举干净。判据不是文件在哪个目录,而是这个函数把
字符串送去了哪里。

codex 点到的:
- notificationService.buildFeishuText(): 飞书完成/失败/需回复通知实际发的是
  `Cindy · 会话「X」…`,而设置页已是「任务完成或需要回复时发送飞书消息」——
  同一条通知两套术语。改「任务「X」」,3 条测试断言同步
- 同文件 showDesktopSessionEvent 的 safeTitle 兜底 '会话' → '任务'(标题为空时
  直接显示在系统 toast 上),两条描述 toast 内容的 jsdoc 一并跟改(§6.0.5)

检查点顺带查出的同族两处(reviewer 未点):
- device-link/ipc.ts ×3: throwIpcError('SESSION_REFERENCE_UNSUPPORTED' /
  '..._UNAVAILABLE', '…会话引用…')。确认 ipcError.* 里没有这两个 code 的 i18n
  条目,所以 message 原样展示 —— 与上一轮改的 sessionReferenceResolver 同一功能、
  同一展示路径
- ORCA_WORKER_READY_MESSAGE: 注入 worker 对话流的系统消息,「Orca Worker 会话已
  就绪」→「Orca Worker 已就绪」(去掉冗余名词,不动 Orca 自己的 Worker/Lead 术语);
  测试断言同步

文档新增「main 侧直接送到用户眼前的出口清单」(12 行表 + 两条可复现的 grep),
连续五轮的返工路径表补上第 5 行。

门禁:GATE_EXIT=1,唯一失败是 voice-input/ElevenLabsScribeProvider 的 WS 握手撞
HTTP 403(单文件复跑 7/7 通过,与本轮 diff 无代码路径交集),其余 17137 passed。

Signed-off-by: Dash <dashhuang@gmail.com>

* docs(naming): 按当前 HEAD 实测重写英文侧与 ja/ko 盘点数字,并标注口径

codex 指出 §4 那张表自相矛盾: 表里写「Conversation 已全部改为 Session、英文侧不再
使用」,而同文档 §4.1 明确要求保留 IM 平台 / conversation lane / 隐私文案三类,en
catalog 里也确实还有 New Feishu conversations 这类合法实例;`Chat` 的「改了 12 处」
又和 §6 的 11 处冲突。这份文档是后续改术语的权威入口,这种表会让维护者去删掉刻意
保留的表达 —— 属实。

三张表全部按当前 HEAD 重新实测,并写清口径:

- §4 英文侧: Session 365→476 / Conversation 136→**19** / Dialogue 16→**0** /
  Chat 131→144 / Thread 11→11。去向拆开写(conversation: 101→Session、12→Chat、
  4 改写、19 保留),并加了一条醒目提示「不要读成 Conversation 已清零」
- §5.1 ja/ko: 原表的 271/16、277/11 用当前口径复现不出来(它们来自会话早期一次
  针对旧 origin/main 的测量)。换成「key 名含 session 的条目」这个可复现口径:
  ja セッション 124→143 / 会話 23→4;ko 세션 127→143 / 대화 25→8
- §6 落地记录: chat→Session 11→14;新增「conversation 改写成别的说法 4」一行;
  conversation 保留 16→19;ja/ko 收敛数改成实测并注明两种口径的差别
  (全部 key 残留 60/96 里多数与 session 无关,如 会話コンテキスト)
- zh 侧 478/87 → 466/99: review 期间的多次回退(imBot.defaults、wechatBot
  .workingDir、commandMenu.new 等)把条目从「改动」挪回了「原样保留」

§4 末尾附了可复现的统计脚本(口径 = 值里含该词的 key 数,不看 key 名、不数出现
次数),并在 §6 开头写明数字会随 rebase 漂移、重跑脚本而不是拿旧数字对账。

上一轮报告的 ElevenLabs WS 握手失败本轮未复现,GATE_EXIT=0。

Signed-off-by: Dash <dashhuang@gmail.com>

* fix(mobile): 消息操作菜单文案改走 i18n,并修 ja/ko 的「复制对话链接」误译

copilot 第 4 次提 messageActionMenu.ts 硬编码中文,这次给了个之前被我忽略的证据:
同目录 sessionMenu.ts 的注释明写「文案走 i18n:本模块四语言都在用 i18n.t,不能塞
硬编码中文(mobile 支持 en / ja / ko)」——也就是说这个目录本来就有规则,
messageActionMenu.ts 是唯一的例外。原判「pre-existing、属独立重构」不成立:改法
就是照抄隔壁,5 个 label 而已。

- apps/mobile/src/i18n/locales/{zh-CN,en,ja,ko}/session.json 新增 messageMenu 段
  (fork / addToChat / copyLink / rewind / deleteOne),措辞与 desktop 的
  chat.messageActionBar.* 对齐;四语各 235 key,手工核对一致
- messageActionMenu.ts 改为 i18n.t('session.messageMenu.*'),并把「为什么必须走
  i18n」写进文件头注释
- 测试按 sessionMenu.test.ts 的先例加 beforeAll(changeLanguage('zh-CN')),让字面量
  断言与语言环境解耦

顺手修一处同源漏改:desktop 的 chat.messageActionBar.copyLink 在 ja/ko 仍是
「現在の会話リンクをコピー」/「현재 대화 링크 복사」,而该操作复制的是带
messageClientId 的**消息**深链 —— zh/en 早先已按此改过,ja/ko 漏了。

文档 §8 两条遗留更新:messageActionMenu 移出「仍硬编码」清单;新增一条记录
pnpm check:i18n 只覆盖 desktop common.json、mobile 的 15 个 locale json 没有 key
对齐门禁(本次靠手工核对),扩门禁属独立改动。

Signed-off-by: Dash <dashhuang@gmail.com>

* fix: 修 i18n 化引入的语言切换回归,并补齐「对话」侧的漏改

## 上一轮我自己引入的回归(codex 指出)

messageActionMenu 改走 i18n.t 之后,MessageRenderer.tsx:1648 那个 useMemo 只依赖
5 个 capability,于是 label 只在首次计算时取值 —— 用户在任务页挂载期间切显示语言,
菜单会一直停在切换前的语言。把 i18nInstance.language 加进依赖(同目录
SessionMenuSheet 的做法是不 memo,这里是热路径、保留 memo 更合适)。

## 映射竞态守卫(codex 指出)

- hook-control/dispatcher.ts:1142:「这个对话所在的目录已不在工作目录映射里…」经
  outcome.errorMessage → turn.end.errorMessage 原样发给渠道用户
- hook-control/session-runner.ts:520:复用运行中实例的守卫,「这个对话正在一个…」
  且让用户「关掉这个对话」

两处都指条目,改「任务」。同目录另两条 IM 通知上轮已改,这两条是同一流程的守卫分支。

## 补扫「对话」查出的两处同源漏改

上一轮枚举 main 侧出口时只反向扫了「会话」,没扫「对话」—— 补扫 35 处后逐条判过:

- im/wechat/WechatIM.ts:1210 的 /help:「/stop 停止当前任务;/stop all 停止全部任务」
  → 「中止当前执行 / 中止全部执行」。核过实现:/stop 走 stopActiveTurn,/stop all 走
  disposeAllSessions + stopActiveTurn,都不删任务条目;原文会让人以为任务被停掉
- maker-core codex 的 memory description:「在新任务中召回」→「在新会话中召回」。
  按 §6.0.2 判据(会不会让用户做多余动作)——说「新任务」会让人以为必须新建任务才能
  用上记忆;同款的 claude-code/index.ts:563 本来就写「新会话」,两条现已一致

其余 33 处判为正确保留(IM 的 /new 语义、§2.3 归属分类、对话记录/对话压缩等)。

## 文档

§6.0.4 出口清单补两条方法论:①「按出口函数名 grep」看不见文案当返回值逐层传出的
情形(dispatcher/session-runner 就是),必须配反向扫描;②反向扫描要同时搜「会话」
和「对话」。返工路径表补第 6 行。

Signed-off-by: Dash <dashhuang@gmail.com>

* fix(i18n): rebase 后按命名规则处理新带进的文案(侧栏快捷键 / 钉钉渠道)

rebase 到最新 origin/main(带进 Lark 接入 makecindy#1133、钉钉连接器一整串、侧栏 mod+1..9
快速切换 makecindy#1184 等 20+ 提交),按 task-and-conversation-naming.md 逐条过了新增文案。

冲突 1 处(zh-CN/common.json 的 settings.notifications):main 把飞书改成
「飞书 / Lark」,本 PR 把「对话」改成「任务」—— 取两者合并。

新带进的 21 条含术语词文案,逐条判断后改 19 条:

- settings.shortcuts.items.switch-session-1..9 的 label + description(18 条):
  zh 写「切换到第 N 个对话」「跳转到侧边栏第 N 个可见对话」,而 en 是
  `Go to session N` / `…visible session in the sidebar`,ja/ko 也已是
  セッション / 세션 —— 典型的中英不成对(§4.2),且指的就是侧栏条目(§2.2)。
  只改 zh,其余三语本就正确
- im/dingtalk/uiText.ts 的 `/stop 停止当前任务,并撤掉排队消息` →「中止当前执行」。
  新渠道的文案包重复了同一个坑:/stop 只中止执行、任务条目保留(§3.1、与
  telegram / wechat 已改的同款)

判为正确保留的:
- channelDescriptions.dingtalk「钉钉新对话会使用…已有对话发送 /new 后应用」——
  与其它渠道同款,且 /new 不产生新任务(§6.0.3)
- dingtalk 的 `/new 开个新对话(清掉当前上下文)`——同上
- imBot.tips.personalFeishuOnly 里的「新对话配置」——设置项真名
- 新增的 hook-control LLM 指令串(「当前是 Slack 会话」「飞书 / Lark session」等)
  ——给模型读的,不是 UI 文案(§6.0.4)

门禁:GATE_EXIT=0;desktop / mobile / maker-shared / maker-core typecheck 全 0;
check:i18n ✅ 6168 key 四语一致;check:i18n-glossary ✅。

Signed-off-by: Dash <dashhuang@gmail.com>

* fix(i18n): 修同句内换概念的运行时提示,并绕开 memory 描述里两难的名词

本轮两位 reviewer 给了**相反**的建议,核过之后各取其正确的一半。

## codex:computerUse 三处 toggleHint 句中换了概念(对)

「这个开关只对之后新建的 **Agent 会话**生效;已在运行的**任务**不受影响。」——前半句
说运行时、后半句跳到产品条目,用户读完不知道该重启当前任务还是新建一个。对照三语:
en `does not affect a session that is already running`、ja「実行中のセッション」、
ko「진행 중인 세션」,两个半句都用同一个 session,只有 zh 在句中换了概念。而且这三个 key
本来就登记在 glossary 的 session.exempt 里,改一半更不自洽。改回「已在运行的 Agent
会话不受影响」,en/ja/ko 本就正确、不动。

顺手把 exempt 列表里 desktop: 前缀的条目全打出来自查了一遍同句混用:另外 5 处
(stopBashTitle、forkErrors.unsupportedHistory、collaboration 两条、subagentModels.hint)
都是两个词各指其物、句意清晰,刻意保留 —— 要看的是「同一个所指被换了两种叫法」。

## copilot:maker-core 的 memory description 该用「新任务」(与 codex 口径冲突)

copilot 说「新会话」是禁用译法、应写「新任务」;而按 §6.0.2,写「新任务」会让用户以为
必须新建任务才能用上记忆(rewind / 重启同一任务也生效)。两边都对,说明是**这个名词本身
选错了**:该 capability 描述的是「记忆之后会被自动召回」,且它落在 maker-core、不是
locale 文件、没法登记 exempt。所以两个 agent 的描述统一改成「从对话中生成新记忆并在
**后续对话**中召回」——用户视角真实、不含禁用词、也不暗示任何多余动作。

## 文档

§6.0.2 从一条判据扩成三条:①会不会让用户做多余动作;②同句前后两半必须在同一个概念上
(附 exempt 自查办法,并说明同句混用不等于错);③两个词都不合适时把名词绕开——遇到
reviewer 意见相反,先怀疑名词选错了。

Signed-off-by: Dash <dashhuang@gmail.com>

* fix(i18n): MCP 生效范围改回 Agent 会话口径,并扫全 24 篇帮助文档

## MCP 生效范围(codex,对)

「保存后新建的**任务**即可调用,已在进行中的任务不受影响」会让用户为用上 MCP 白开一条
新任务。核过代码:claude-code/index.ts:1935 的 buildMcpServers() 在 buildQuery 里求值,
而同文件 :982 注释写明「一次性 buildQuery + buildMcpServers」——/clear、rewind 等重启
同一任务的 Agent runtime 时会重新执行,所以同一任务的下一个 Agent 会话就生效。

zh 两条改成与兄弟文案 settings.builtinTools.toggleHint 同款措辞:
「新建或重启的 Agent 会话即可调用,正在运行的 Agent 会话不受影响」;deleteConfirm
.message 同步。en/ja/ko 与 origin 一致、本就用 session/セッション/세션,不动。

两个 key 现在含「会话」,已登记进 glossary session.exempt(共 37 条),并重跑
pnpm i18n:glossary-doc 同步 GLOSSARY.md(门禁的「文档过期」分支会拦)。

## 帮助文档(codex,对)—— 这次扫全 24 篇

sidebar.md 的任务菜单说明仍写 **Copy conversation link**,而界面已是
`Copy session link`,帮助把用户指向一个不存在的菜单项。这是同一目录第 3 次被点
(前两次是 collaboration.md 的 "New Chat"),所以这轮不再只改被点的行,把 24 篇扫完:

- sidebar.md ×2:Copy conversation link → Copy session link
- import-sessions.md:「by dialogue」→「by chat」(位置筛选的真实标签是 `Chat`,
  见 settings.sessionImport.filters.dialogue)
- sessions-and-chat.md:小标题 **Conversation controls:** → **Chat controls:**

判为内容义、保持不动的 9 处:conversation history / Memory across conversations /
rewinds the conversation / Codex and Claude conversations(CLI 磁盘上的)等。

改完跑 gen:help-kb 重新生成 helpKnowledge.generated.ts,gen:help-kb:check PASS。

## 文档

§6.0.4 返工路径表补第 7 行,并新增一节:帮助内容要单独扫,判据是「引用的是界面标签
还是交流内容」,附 grep 与「改完必须 gen:help-kb + gen:help-kb:check」。

Signed-off-by: Dash <dashhuang@gmail.com>

* fix: /clear 描述订正为实际行为,mobile fork 弹窗走 i18n,并处理 rebase 新文案

## /clear 的描述与实现不符(copilot,对)

上一轮我为了去掉过时的「New Chat」标签引用重写了这条描述,但**沿用了 origin 里本来
就错的行为声明**。核过实现:renderer 收到 DESKTOP_COMMAND_TRIGGERED 后调
clearSession() → clearSessionAfterGuard,注释写明「把窗口清空、从最新重新拉起」,
是**原地**清空当前任务的对话上下文,不新建草稿、也不切走。

而 help-knowledge/{commands,sessions-and-chat}.md 写的才是对的(「resets the
conversation in place without creating a new session」),两边一直互相矛盾。改成与
实现和帮助一致的说法,并把判据写进代码注释。

## mobile fork 确认弹窗硬编码中文(copilot,对)

同页其它 Alert 已走 t('session.screen.*'),这个弹窗是唯一例外 —— 与上一轮
messageActionMenu 同一类缺陷、同一个论据(en/ja/ko 环境下显示中文)。

- 四语 session.json 的 screen 段新增 forkConfirmTitle / forkConfirmDescription /
  forkConfirm / forkCancel,措辞与 desktop 的 chat.messageActionBar.fork* 逐条对齐
- [sessionId].tsx 改为 t(...),并把「为什么必须走 i18n」写进注释

## rebase 到最新 origin/main(X hook / device-link 协同入口 / scheduler 阶段机等 6 提交)

冲突 1 处(settings.tina.chat.description):main 把平台清单加了 X,本 PR 把
「独立复用 session」改成「独立对应一个任务」—— 取两者合并。

新带进 2 条含术语词文案,处理 1 条:
- newChat.collaboration.remoteContinueNotice(新):四语都与**同流程的兄弟 key**
  startFailedContinue 不一致 —— 后者已是「单任务 / a single session / 単一セッション /
  단일 세션」,前者却写「单对话 / a single conversation / 単一の対話 / 단일 대화」。
  同一功能两种叫法,四语一并对齐
- 硬编码新增的「当前是 X (Twitter) 会话」是给模型读的指令串,不改(§6.0.4)

门禁:GATE_EXIT=0;mobile / desktop typecheck 双 0;check:i18n ✅ 6195 key;
check:i18n-glossary ✅。

Signed-off-by: Dash <dashhuang@gmail.com>

* fix(desktop): 同步 Agent Island 两处影子 catalog 的回退文案

codex 指出:agentIsland.native.newConversationTitle 改成 New Session 后,Agent Island
的**冷启动 / 回退态**仍会露出旧名 —— 该 helper 是独立进程,拿到 main 的本地化状态之前
用自带默认值。核实并改了两处:

- apps/desktop/src/shared/agentIsland.ts 的 DEFAULT_AGENT_ISLAND_STRINGS:
  'New Chat' / 'Start a new conversation' → 'New Session' / 'Start a new session'
- native/agent-island/macos-agent-island-helper.swift 的 AgentIslandStrings.fallback:
  "New Maker" / "Start a new conversation" → "New Session" / "Start a new session"
  (前者是更早的品牌名,比 locale 落后两代)

两处都与 en locale 逐字对齐。该目录只有 .swift 源、无签入产物,改源即生效。

## 顺手穷尽了「影子 catalog」这一类

§6.0.1 早把影子 catalog 列为一类,但我只找过 applicationMenuLabels.ts。这次换成
**在 locale 之外搜英文旧标签**(而不是搜代码里的中文),确认本仓只有这两处;命中的其余
结果全是数据库默认标题哨兵 'New Maker'(deviceLinkCreateArgs 写入、
isDefaultDraftSessionTitle 判定、swift 侧 normalized != "new maker"),**绝对不能改**
——projectDraftSessionTitle 那套机制存在的意义就是把哨兵挡在用户视线外。

文档把这两处 + 搜法 + 哨兵红线写成了表。

## copilot:glossary note 里的韩文错字

session 条目 note 里同一句写了「대話」(末字误用汉字)又写了正确的「대화」,已统一;
重跑 pnpm i18n:glossary-doc 同步 GLOSSARY.md。

门禁:GATE_EXIT=0(首轮 SIGSEGV,是与另一 worktree 门禁并发跑时崩的,非断言失败;
另一门禁结束后重跑通过);desktop typecheck 0;check:i18n ✅ 6195 key;
check:i18n-glossary ✅;定向跑 agent-island 6 文件 243 tests 全过。

Signed-off-by: Dash <dashhuang@gmail.com>

* fix(i18n): fork / rewind 的运行时失败改回 Agent 会话口径

codex:这两条报的都是「Codex 运行时状态 / live Query 不可用」,产品任务本身没坏,
说「任务」会让用户以为任务损坏。对照 en/ja/ko —— 三语说的都是 runtime
(`The Codex session state` / `Codex セッションの状態` / `Codex 세션 상태`;
`Session is inactive` / `セッションが非アクティブ` / `세션이 비활성 상태`),又是只有 zh
被我改坏。

- chat.userMessage.forkErrors.codexStateUnavailable:「Codex 任务状态不可用,无法开启
  新任务」→「Codex **Agent 会话**状态不可用,无法开启新任务」。前半句指 runtime、
  后半句指 fork 真的产出一条新任务,两半各指其物(§6.0.2 第二条允许的那种混用)
- chat.rewind.errors.noLiveQuery:「任务未激活」→「Agent 会话未激活」。抛错条件就是
  SDK live Query 没起来,提示也正是「先发一条消息把 SDK 唤起来」

两个 key 登记进 glossary session.exempt(共 39 条),重跑 i18n:glossary-doc 同步
GLOSSARY.md。en/ja/ko 与 origin 一致,不动。

## 文档:把共享层 i18n 缺口的清单记全

copilot 已就这一类点了 4 轮,每轮多报一个函数。§8 那条从「两个函数」扩成完整表:
sessionList 的 remoteSessionListTitle / deviceSessionEmptyState、sessionSelection 的
summarizeMobileSessionBulkAction、scheduleModel 的 summarizeRun,并写明各自被哪个
mobile 页面直接渲染。

同时点明**修法不是改用词、而是让共享层不产出文案**(调用方传 t/strings,或只返回结构化
数据),要动 3 个模块 + 调用点 + 测试,属独立重构;并区分它与本 PR 内已迁 i18n 的
messageActionMenu / fork 弹窗——后者是页面自己的文案,改法就是照抄同目录既有写法。

门禁:GATE_EXIT=0;desktop typecheck 0;check:i18n ✅ 6195 key;check:i18n-glossary ✅。

Signed-off-by: Dash <dashhuang@gmail.com>

* feat(i18n): 新增 agent-session 术语,把 session 的五个语义拆开并加门禁

这条不是 reviewer 提的,是我复盘 20+ 轮反馈后认定的**根因修复**。

## 问题

本 PR 的反馈里有 4 轮是同一类错误:把 Agent 运行时会话译成了「任务」
(memory toast / computerUse toggleHint / MCP 生效范围 / forkErrors 与 rewind)。
每一次 en/ja/ko 都是对的 —— 因为它们一词通用、没有可错的空间;**只有中文被迫二分**。

而术语表把这件事表达成了「一个 session 条目 + 39 条路径白名单」。白名单只说明
「这里允许出现『会话』」,没说明「这里指的是哪一种 session」—— 逐条判断时没有可对照的
名字,于是同一个错反复犯。实际上那 39 条覆盖了**五个**不同概念:

  产品条目 / Agent 运行时会话(22 条) / 登录校验会话(2) / SSH 远程与传输(5) /
  操作系统桌面与 mobile 语音连接(6)

## 改动

新增 **agent-session** 条目(decided):

- 译法:zh「Agent 会话」/ ja「Agent セッション」/ ko「Agent 세션」——把最容易译错、
  且唯一「译错会改变用户行为」的那一类给了名字,可正向查
- forbidden: zh 禁「任务」when 英文源含 agent session。精确、当前零误报;唯一的合法
  混用 forkErrors.unsupportedHistory(前半指运行时、后半指条目)已登记 exempt
- note 写明**门禁拦不住哪一半**:英文只写 session 的那批(`The Codex session state` /
  `Session is inactive` / `in-flight sessions`)机器判不出来 —— 英语本身不区分,同句
  两个所指并存也合法。与其加个会误伤的词形规则,不如把「为什么不能加」写清楚

实测:把 computerUse 三处 toggleHint 改回犯错时的写法,门禁报 3 处违规并阻断;
回滚后恢复绿。

session 条目的 note 从散述改成明确交叉引用 agent-session。

## 文档

§6.0.2 从「Agent 进程会话不跟改」改写成「英文的 session 在本仓是五个概念」,开头给
五语义对照表 + 术语表条目归属,再给三条人工判据(多余动作 / 同句同概念 / 绕开名词),
并说明门禁能拦与不能拦的边界。文档抬头加了「动手前先读 §6.0.2」。

门禁:GATE_EXIT=0;check:i18n-glossary ✅ 32 条已裁决;GLOSSARY.md 已重新生成(60 条)。

Signed-off-by: Dash <dashhuang@gmail.com>

* fix(i18n): 任务导入的「内部任务」改回「内部 Agent 会话」

codex 指出被过滤掉的不是产品任务。核实 maker-host/codex-local-sessions.ts 的
isInternalSourceValue:过滤的是 source / originator 为 exec、codex_exec、subagent 的
底层 thread —— 即 Codex 的非交互运行与子代理线程,用户在侧栏里根本没有对应条目。
说「已跳过的内部任务」会让用户以为自己有一批任务被藏起来了。

en/ja/ko 也都是 runtime 口径(`skipped internal sessions` /「内部セッション」/
「내부 세션」),又是只有 zh 被我改坏:

- settings.sessionImport.description:「已跳过的内部任务」→「已跳过的内部 Agent 会话」。
  同句前半「只有列表里勾选的任务会被导入」保持不变 —— 那些确实会变成产品任务,属
  §6.0.2 判据二允许的「两个词各指其物」
- settings.sessionImport.summary.filteredHint:「内部任务或已在应用内」→
  「内部 Agent 会话或已在应用内」

两个 key 登记进 glossary session.exempt(共 41 条),重跑 i18n:glossary-doc 同步。

顺带说明:这一条的判断直接来自上一轮新建的 agent-session 条目与 §6.0.2 的五语义表
(「Agent / 引擎运行时会话 → Agent 会话」),不再需要临时权衡 —— 那个术语条目开始起作用了。

另本轮 rebase 到最新 origin/main(auto-review 基础设施、SkillHub 本地导入、插件基座
revert 等 12 提交)。冲突 1 处 × 四语:main 给 issueTracker 加了 emptyTitleUnverified,
本 PR 改了同段 startIssueChat —— 取两者合并。按规则检查 rebase 带进的新文案:locale
侧 0 条含术语词,硬编码侧 0 条,无需跟改。

门禁:GATE_EXIT=0;四包 typecheck 全 0;check:i18n ✅ 6204 key;check:i18n-glossary ✅。

Signed-off-by: Dash <dashhuang@gmail.com>

* fix(i18n): 修正项目插件开关的生效时机

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Dash <dashhuang@gmail.com>

* fix(i18n): 同步任务改名的影子契约

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Dash <dashhuang@gmail.com>

* fix(i18n): 内置工具默认值改用 Agent 会话

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Dash <dashhuang@gmail.com>

* fix(mobile): 协作任务文案统一使用任务

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Dash <dashhuang@gmail.com>

* fix(i18n): 清理 rebase 冲突标记

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Dash <dashhuang@gmail.com>

* fix(i18n): 同步 rebase 新增任务文案

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Dash <dashhuang@gmail.com>

* docs: 修正 Orca 协作任务命名指引

Co-Authored-By: Claude <noreply@anthropic.com>
Signed-off-by: Dash <dashhuang@gmail.com>

---------

Signed-off-by: Dash <dashhuang@gmail.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants