Skip to content

feat(terminal): 等待 banner + 跳过等待(terminal_wait_for 增 skipped) - #606

Open
HuanLinOTO wants to merge 12 commits into
mainfrom
feat/wait-banner
Open

feat(terminal): 等待 banner + 跳过等待(terminal_wait_for 增 skipped)#606
HuanLinOTO wants to merge 12 commits into
mainfrom
feat/wait-banner

Conversation

@HuanLinOTO

Copy link
Copy Markdown
Collaborator

设计:docs/plans/2026-09-09-terminal-wait-banner-design.md(含实施偏差记录,随本 PR)。

功能

agent 阻塞在 \ erminal_wait_for\ 时:

  • 对应终端卡片顶部显示「Agent 正在等待 {needle}」banner,右侧「跳过等待」按钮 → 新增 \�gent-pty.skip-wait\ API → registry \skipWait()\ → 工具返回新增的 {kind:'skipped'}\
  • 终端 tab 标题显示 ⏳ 徽章(shell 层 tabBadgeOf 特例,不动 TabDescriptor 外部 API)
  • 等待状态随现有 /sidebar/ws/agent-terminals 推送快照(\waiting\ 字段)分发,旧客户端向后兼容

实现要点

  • 并发多个 wait 显示最新 needle,跳过一次跳过全部;abort/exit/skip 统一经 notify() 推送收敛
  • agentWaits 瞬态不持久化(sanitizeState 不恢复,首条推送即纠正)
  • 词典同步全部 21 个语言文件(locales.spec 键集守护);CSS 全令牌无硬编码色
  • 徽章走 shell 特例的原因:TabDescriptor.badge 是 type-keyed API,无法定位单 tab

验证

  • 新增 4 套测试:registry(32/32)、tools(12/12)、reconcile(12/12)、banner 组件(2/2)+ jsdom 推送→状态→⏳ 全链路(2/2)
  • 本机全量 \pnpm test\ 28 failed 均为已知环境性非回归(Node 26 无 --localstorage-file 致上游 jsdom 测试 afterEach 崩溃 + 1 个并行抖动单跑即绿),失败点均为本 diff 未触碰的上游测试基建行
  • lint / typecheck / build 0 error

Copilot AI lite review requested due to automatic review settings September 9, 2026 05:47

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

🟡 Changes recommended

There are a couple of small but concrete test robustness issues (hard-coded uuid in tools test and insufficient localStorage guard) that should be fixed to avoid brittleness/flakiness.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Pull request overview

This PR adds a user-visible “waiting” affordance for terminal_wait_for across host → push feed → client state → UI, including a skip mechanism that returns a new { kind: 'skipped' } tool result, plus an hourglass badge on agent terminal tabs.

Changes:

  • Extend AgentPtyRegistry.waitFor() with wait registration/snapshot exposure (waiting) and a new skipWait() path returning { kind: 'skipped' }.
  • Mirror pushed waiting state into client state.agentWaits (transient) and render a Terminal wait banner + ⏳ tab badge for agent terminals.
  • Update tool schema/rendering and add tests covering registry skip, tool output validity, reconcile behavior, banner component, and badge end-to-end.
File summaries
File Description
tests/tools.spec.ts Adds tool-layer coverage for terminal_wait_for returning skipped and render messaging.
tests/terminal-wait-banner.spec.tsx New jsdom unit tests for the wait banner text, skip button wiring, and needle truncation behavior.
tests/agent-wait-badge.spec.tsx New jsdom end-to-end test for ⏳ badge driven by /sidebar/ws/agent-terminals pushes.
tests/agent-terminal-reconcile.spec.ts Adds reconcile tests for mirroring/clearing agentWaits and idempotency on waits-only updates.
tests/agent-pty.spec.ts Adds registry tests for skip behavior, snapshot waiting, notifications, and unknown-uuid handling.
src/tools.ts Extends terminal_wait_for description, output schema, and render to include skipped.
src/index.ts Adds host API route agent-pty.skip-wait returning { ok, skipped }.
src/client/TerminalWaitBanner.tsx New banner component for displaying the current wait needle and skip button.
src/client/TerminalView.tsx Wires banner into agent terminal view by subscribing to state.agentWaits and calling api.agentSkipWait.
src/client/state.ts Adds transient agentWaits to sidebar state and reconciles it from agent-terminals push snapshots.
src/client/sidebar/use-host-feeds.ts Extends agent-terminals push parsing type to include optional waiting.
src/client/Sidebar.tsx Adds a shell-level tabBadgeOf special-case to show ⏳ on waiting agent terminal tabs.
src/client/sidebar.module.css Adds styles for the wait banner layout and needle display.
src/client/locales.ts Adds terminalWaitBanner / terminalSkipWait keys to zh/en.
src/client/locales-zh-TW.ts Adds the two new terminal wait keys for zh-TW.
src/client/locales-zh-MO.ts Adds the two new terminal wait keys for zh-MO.
src/client/locales-zh-HK.ts Adds the two new terminal wait keys for zh-HK.
src/client/locales-vi.ts Adds the two new terminal wait keys for vi.
src/client/locales-tr.ts Adds the two new terminal wait keys for tr.
src/client/locales-th.ts Adds the two new terminal wait keys for th.
src/client/locales-sv.ts Adds the two new terminal wait keys for sv.
src/client/locales-ru.ts Adds the two new terminal wait keys for ru.
src/client/locales-pt.ts Adds the two new terminal wait keys for pt.
src/client/locales-pl.ts Adds the two new terminal wait keys for pl.
src/client/locales-nl.ts Adds the two new terminal wait keys for nl.
src/client/locales-ko.ts Adds the two new terminal wait keys for ko.
src/client/locales-ja.ts Adds the two new terminal wait keys for ja.
src/client/locales-it.ts Adds the two new terminal wait keys for it.
src/client/locales-id.ts Adds the two new terminal wait keys for id.
src/client/locales-hi.ts Adds the two new terminal wait keys for hi.
src/client/locales-fr.ts Adds the two new terminal wait keys for fr.
src/client/locales-de.ts Adds the two new terminal wait keys for de.
src/client/locales-ar.ts Adds the two new terminal wait keys for ar.
docs/plans/2026-09-09-terminal-wait-banner-plan.md Adds an implementation plan document for the wait banner + skip feature.
docs/plans/2026-09-09-terminal-wait-banner-design.md Adds the design doc (incl. implementation deviations) for the wait banner + skip feature.
Review details
  • Files reviewed: 37/37 changed files
  • Comments generated: 2
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread tests/agent-wait-badge.spec.tsx Outdated
// a pending 200ms debounce write left behind between tests. Guarded — some
// node/jsdom combos (node >=22 without --localstorage-file) expose no
// working localStorage and a bare access would throw in the hook.
if (typeof localStorage !== 'undefined') localStorage.clear()
Comment thread tests/tools.spec.ts Outdated
Comment on lines +206 to +209
registry.create('s1', 'skipper', '')
registry.nextWaitResult = { kind: 'skipped' }
const value = await tool.execute({ uuid: 'uuid-1', needle: 'BUILD_OK', timeout_ms: 1000 }, exec('s1'))
expect(value).toEqual({ kind: 'skipped', needle: 'BUILD_OK' })

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

🟡 Changes recommended

Cross-session pinned agent terminals cannot receive the new live banner or wait badge.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Review details
  • Files reviewed: 37/37 changed files
  • Comments generated: 2
  • Review effort level: Balanced

Comment thread src/client/Sidebar.tsx
Comment on lines +834 to +836
if (isAgentTabId(tab.id)) {
const wait = state.agentWaits?.[agentUuidOf(tab.id)]
if (wait !== undefined) return <span className={css.tabBadge}>{'⏳'}</span>
Comment on lines +137 to +138
const read = (): void => {
const next = store.getSnapshot().state?.agentWaits?.[agentUuid]
@HuanLinOTO

Copy link
Copy Markdown
Collaborator Author

Copilot review 处置(9a2c56e):

  • localStorage 兜底(agent-wait-badge.spec):已改为 try/catch 包裹——jsdom opaque origin 下 localStorage 可以是 throwing accessor,typeof 也不安全。
  • 硬编码 uuid-1(tools.spec):已改为使用 registry.create() 返回的 uuid。
  • pinned 跨会话虚拟 tab 收不到 banner/⏳:确认为真实限制——等待状态 feed 按 viewer 会话订阅,pinned tab 的 home 会话推送在 viewer 切走后不可达;修复需跨会话 feed 多路复用,超出本特性范围。已在设计文档「实施偏差记录」记录该限制与后续方向(跳过 API 按 uuid 全局寻址,不受影响)。

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.

2 participants