Skip to content
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
0b4f683
fix(cli): make the Agent Team teammate tab transcript scrollable in V…
yiliang114 Aug 20, 2026
21cc989
fix(cli): preserve teammate transcript selection
yiliang114 Aug 29, 2026
4c577f1
Merge origin/main into fix/9507-teammate-tab-scroll
yiliang114 Aug 29, 2026
dc65a4f
fix(cli): re-measure the agent footer when its height changes
yiliang114 Aug 29, 2026
f4921f6
fix(cli): use renamed RespondingSpinner in agent transcript viewport
yiliang114 Aug 29, 2026
5cd3f12
Merge remote-tracking branch 'origin/main' into prmerge-9531
yiliang114 Aug 29, 2026
4e80eae
fix(cli): follow RespondingSpinner rename after merging main
yiliang114 Aug 29, 2026
4da1dae
Merge branch 'fix/9507-teammate-tab-scroll' of https://github.com/Qwe…
yiliang114 Aug 29, 2026
1576cfd
test(cli): guard the AgentViewContext layout-key propagation deps (#9…
yiliang114 Aug 29, 2026
608be44
Merge branch 'main' into fix/9507-teammate-tab-scroll
yiliang114 Aug 30, 2026
a4e5bf9
Merge branch 'main' into fix/9507-teammate-tab-scroll
yiliang114 Sep 1, 2026
e47e576
Merge branch 'main' into fix/9507-teammate-tab-scroll
yiliang114 Sep 2, 2026
747d82f
Merge branch 'main' into fix/9507-teammate-tab-scroll
yiliang114 Sep 2, 2026
0c2bdd1
Merge branch 'main' into fix/9507-teammate-tab-scroll
yiliang114 Sep 3, 2026
8de3aad
Merge branch 'main' into fix/9507-teammate-tab-scroll
yiliang114 Sep 5, 2026
ef5d9b9
Merge remote branch 'origin/fix/9507-teammate-tab-scroll'
yiliang114 Sep 5, 2026
20f1983
Merge branch 'main' into fix/9507-teammate-tab-scroll
yiliang114 Sep 5, 2026
585d8a8
fix(cli): restore full-detail toggle and mouse actions on teammate VP…
yiliang114 Sep 5, 2026
0300eb8
Merge origin/main into fix/9507-teammate-tab-scroll
yiliang114 Sep 5, 2026
c848508
fix(cli): quiet the teammate VP viewport while the context menu is open
yiliang114 Sep 6, 2026
42b629c
Merge origin/main into fix/9507-teammate-tab-scroll
yiliang114 Sep 6, 2026
7bb4adf
fix(cli): clear the painted text selection when its controller unmounts
yiliang114 Sep 6, 2026
b479224
fix(cli): gate the teammate tab's key consumers on the open context m…
yiliang114 Sep 12, 2026
3ba60f9
Merge origin/main into fix/9507-teammate-tab-scroll
yiliang114 Sep 13, 2026
8a9412a
fix(cli): keep teammate approvals answerable and gate the last key co…
yiliang114 Sep 13, 2026
2298210
fix(cli): keep the deps guard's identifier out of comment prose
yiliang114 Sep 19, 2026
a5444d1
Merge origin/main into fix/9507-teammate-tab-scroll
yiliang114 Sep 19, 2026
8bb3755
fix(cli): drop a queued scroll flush on focus loss and gate the neste…
yiliang114 Sep 19, 2026
397f398
Merge origin/main into fix/9507-teammate-tab-scroll
yiliang114 Sep 19, 2026
eee9e12
fix(cli): block stale key handlers while context menus open
yiliang114 Sep 25, 2026
0f8f90a
Merge main to refresh the CI gate
yiliang114 Sep 25, 2026
da35866
fix(cli): preserve keys after input dismisses context menu
yiliang114 Sep 25, 2026
5d9425b
Merge origin/main into fix/9507-teammate-tab-scroll
yiliang114 Sep 25, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions packages/cli/src/ui/AppContainer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3757,6 +3757,12 @@ export const AppContainer = (props: AppContainerProps) => {
streamingState,
updateInfo,
agentViewState.activeView,
// The agent tab footer grows with its own status row / queued messages /
// input text, none of which the deps above track; AgentComposer syncs
// this key to AgentViewContext whenever they change so the footer is
// re-measured and the transcript viewport does not stay stale-high
// (#9507). Mirrors liveAgentPanelLayoutKey.
Comment thread
yiliang114 marked this conversation as resolved.
Resolved
agentViewState.agentComposerLayoutKey,
embeddedShellFocused,
messageQueue.length,
isInputActive,
Expand Down
85 changes: 85 additions & 0 deletions packages/cli/src/ui/app-container-controls-dep.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,12 @@
* leaves the mechanism tests (which use a stand-in component) green. This guard
* pins the dependency directly, so a deps-array cleanup or an `exhaustive-deps`
* autofix cannot quietly delete the fix.
*
* The same reasoning extends to the #9507 provider link: the composer layout
* key must survive in the dependency arrays of the AgentViewContext state and
* actions memos, or setAgentComposerLayoutKey updates never reach the
* AppContainer measure effect guarded above. useMemo deps are invisible to
* TypeScript, so they are pinned here at the source level as well.
*/

import { describe, it, expect } from 'vitest';
Expand All @@ -33,6 +39,16 @@ const source = readFileSync(
'utf8',
);

const composerSource = readFileSync(
join(import.meta.dirname, 'components', 'agent-view', 'AgentComposer.tsx'),
'utf8',
);

const agentViewContextSource = readFileSync(
join(import.meta.dirname, 'contexts', 'AgentViewContext.tsx'),
'utf8',
);

/** Extract the dependency array of the controls-height measurement effect. */
function controlsHeightEffectDeps(): string {
const measureAt = source.indexOf('measureElement(mainControlsRef.current)');
Expand All @@ -44,6 +60,24 @@ function controlsHeightEffectDeps(): string {
return source.slice(depsOpen, depsClose);
}

/**
* Extract the dependency array of a useMemo in AgentViewContext.tsx. The
* slice runs from the deps-array opening bracket to its closing bracket, so
* it covers only the deps list, not the memoized object literal above it.
* That is deliberate: the guarded mutation keeps the value in the literal
* while dropping it from the deps, which must fail the assertion below even
* though the literal still mentions the identifier.
*/
function agentViewMemoDeps(memoAnchor: string): string {
const memoAt = agentViewContextSource.indexOf(memoAnchor);
expect(memoAt).toBeGreaterThan(-1);
const depsOpen = agentViewContextSource.indexOf('\n [', memoAt);
expect(depsOpen).toBeGreaterThan(-1);
const depsClose = agentViewContextSource.indexOf('\n ],', depsOpen);
expect(depsClose).toBeGreaterThan(depsOpen);
return agentViewContextSource.slice(depsOpen, depsClose);
}

describe('AppContainer controls-height measurement wiring', () => {
it('measures controls height from mainControlsRef', () => {
// Sanity: the effect we are guarding still exists and is shaped as expected.
Expand All @@ -67,4 +101,55 @@ describe('AppContainer controls-height measurement wiring', () => {
/liveAgentPanelLayoutKey\s*=\s*getLiveAgentPanelLayoutKey\(\s*bgTaskEntries\s*,\s*bgLivePanelFocused\s*,?\s*\)/,
);
});

it('lists the agent composer layout key in the measurement effect deps', () => {
const deps = controlsHeightEffectDeps();
// The #9507 fix: the agent tab footer grows with its own status row /
// queued messages / input text, none of which the other deps track;
// dropping this entry leaves controlsHeight stale-high on the agent tab
// and the viewport pushes the composer and tab bar off the terminal.
expect(deps).toContain('agentViewState.agentComposerLayoutKey');
});

it('derives the composer layout key from the footer height-shifting state', () => {
// The key must cover every row-count factor the agent footer renders:
// loading row (streamingState), terminal status row, queued messages and
// input text. Whitespace-tolerant so prettier can't break the guard.
expect(composerSource).toMatch(
/getAgentComposerLayoutKey\(\{\s*streamingState\s*,\s*statusLabel:\s*statusLabel\?\.text\s*\?\?\s*''\s*,\s*queuedMessageCount:\s*messageQueue\.length\s*,\s*inputText:\s*buffer\.text\s*,?\s*\}\)/,
);
});

it('syncs the composer layout key to context for the measure effect', () => {
expect(composerSource).toMatch(
/useEffect\(\(\)\s*=>\s*\{\s*setAgentComposerLayoutKey\(composerLayoutKey\);\s*\},\s*\[composerLayoutKey,\s*setAgentComposerLayoutKey\]\)/,
);
});
});

describe('AgentViewContext propagation of the composer layout key (#9507)', () => {
it('lists agentComposerLayoutKey in the state memo dependencies', () => {
const deps = agentViewMemoDeps('const state: AgentViewState = useMemo(');
// Sanity: this is the state memo's deps array (the literal above it
// mirrors the same identifiers, so anchor on entries plus position).
expect(deps).toContain('activeView');
expect(deps).toContain('agentMessageQueues');
// The #9507 provider link: the object literal still lists the key when
// this dep is dropped, so nothing looks wrong — but the memoized context
// value goes stale, setAgentComposerLayoutKey updates stop reaching the
// AppContainer controls-height measure effect, and the composer/tab bar
// overflow fixed in round 2 returns. TypeScript cannot see memo deps, so
// this source guard is the only protection.
expect(deps).toContain('agentComposerLayoutKey');
});

it('lists setAgentComposerLayoutKey in the actions memo dependencies', () => {
const deps = agentViewMemoDeps(
'const actions: AgentViewActions = useMemo(',
);
expect(deps).toContain('setAgentShellFocused');
// Dropping this entry hands consumers a stale actions object whose
// setAgentComposerLayoutKey identity predates the provider re-render.
expect(deps).toContain('setAgentComposerLayoutKey');
});
});
Loading
Loading