Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
ab8284f
test(agent-pane): every bottom card shares the composer card's edges
teamleaderleo Oct 30, 2026
c755c62
fix(agent-pane): the bottom stack is one glass on the composer's edge…
teamleaderleo Oct 30, 2026
7a0448b
fix(agent-pane): the N PRs count opens Changes; its disclosure opens …
teamleaderleo Oct 30, 2026
aa1b4e9
chore(design): map the bottom stack and the running tray to their specs
teamleaderleo Oct 30, 2026
7e9f7a6
test(agent-pane): the N PRs row is a part of the stack; it rides up w…
teamleaderleo Oct 30, 2026
ec774ad
test(agent-pane): every stacked row's chevron shares one x
teamleaderleo Oct 30, 2026
7128adb
fix(agent-pane): the N PRs chevron ends on the tray's chevron column
teamleaderleo Oct 30, 2026
3015620
test(agent-pane): the folded N PRs count adds no row; × on hover only…
teamleaderleo Oct 30, 2026
1234429
fix(agent-pane): the N PRs count is a compact control in the quiet ro…
teamleaderleo Oct 30, 2026
3ed11db
fix(agent-pane): the opened pull requests skip the stack's rise-on-mount
teamleaderleo Oct 30, 2026
3106205
test(agent-pane): the opened-chips still has the pointer on its first…
teamleaderleo Oct 30, 2026
d0640db
fix(agent-pane): focus goes to the prompt after the last PR row; the …
teamleaderleo Oct 30, 2026
0b58acb
fix(agent-pane): no control repeats on every opened PR row; a row's o…
teamleaderleo Oct 31, 2026
e61c418
test(agent-pane): open a PR row's menu from the keyboard (the hover c…
teamleaderleo Oct 31, 2026
9513ae6
test(agent-pane): every part over the composer on the box's edges, ra…
teamleaderleo Oct 30, 2026
5061a17
fix(agent-pane): every part over the composer on the box's edges and …
teamleaderleo Oct 30, 2026
c86b0e6
test(subagents): the tray's insets are the stack's (the composer's le…
teamleaderleo Oct 31, 2026
3360d26
Merge feat-cmux-next: take #28113's tray trailing grid as settled
teamleaderleo Oct 31, 2026
df31d42
Merge branch 'feat-cmux-next' into lane/ux-bottom-stack-2
teamleaderleo Oct 31, 2026
10adf37
Merge feat-cmux-next into lane/ux-bottom-stack-2
teamleaderleo Oct 31, 2026
3b48b0f
Merge feat-cmux-next into lane/ux-bottom-stack-2
teamleaderleo Nov 1, 2026
cb822e8
fix(agent-pane): the N PRs count and its rows keep the arrow cursor
teamleaderleo Oct 31, 2026
0baccf8
fix(agent-pane): a settled tray stays cardless in the one-glass stack
teamleaderleo Nov 1, 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
15 changes: 13 additions & 2 deletions .github/design-surfaces.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
},
"composer": {
"spec": "leo-workspace design/composer.md",
"aliases": ["composer", "prompt box"],
"aliases": ["composer", "prompt box", "bottom stack", "PR dock", "N PRs"],
"paths": [
"webviews/src/agent-session/acpmux/Composer.tsx",
"webviews/src/agent-session/acpmux/ComposerBox.tsx",
Expand All @@ -36,7 +36,18 @@
"webviews/src/agent-session/acpmux/composerControls.css",
"webviews/src/agent-session/acpmux/composerFooterShared.css",
"webviews/src/agent-session/acpmux/composerLook.css",
"webviews/src/agent-session/acpmux/composerStates.css"
"webviews/src/agent-session/acpmux/composerStates.css",
"webviews/src/agent-session/acpmux/bottomStack.css",
"webviews/src/agent-session/acpmux/summary/PullRequestStack.tsx",
"webviews/src/agent-session/acpmux/summary/PullRequestDockLegacy.tsx"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2: This new composer mapping points to a file that does not exist, so the design-surface validity test fails and the map emits a stale-path warning. Remove this entry; PullRequestStack.tsx is already mapped.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At .github/design-surfaces.json, line 42:

<comment>This new composer mapping points to a file that does not exist, so the design-surface validity test fails and the map emits a stale-path warning. Remove this entry; `PullRequestStack.tsx` is already mapped.</comment>

<file context>
@@ -36,7 +36,18 @@
+        "webviews/src/agent-session/acpmux/composerStates.css",
+        "webviews/src/agent-session/acpmux/bottomStack.css",
+        "webviews/src/agent-session/acpmux/summary/PullRequestStack.tsx",
+        "webviews/src/agent-session/acpmux/summary/PullRequestDockLegacy.tsx"
+      ]
+    },
</file context>

]
},
"running-tray": {
"spec": "leo-workspace design/running-tray.md",
"aliases": ["running tray", "subagent tray", "running in background"],
"paths": [
"webviews/src/agent-session/acpmux/subagents/SubagentTray.tsx",
"webviews/src/agent-session/acpmux/subagents/subagents.css"
]
},
"session-rail": {
Expand Down
2 changes: 1 addition & 1 deletion webviews/scripts/design-tokens-baseline.jsonl
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@
{"file":"agent-session/acpmux/subagents/subagents.css","kind":"spacing","property":"padding-top","values":{"2px":1}}
{"file":"agent-session/acpmux/summary/summary.css","kind":"height","property":"height","values":{"26px":5,"6px":1,"22px":2,"14px":1,"18px":1,"40px":1}}
{"file":"agent-session/acpmux/summary/summary.css","kind":"spacing","property":"gap","values":{"2px":5,"6px":3}}
{"file":"agent-session/acpmux/summary/summary.css","kind":"spacing","property":"padding","values":{"8px 8px 10px":1,"4px 4px 4px 6px":1,"0 2px 4px 4px":1,"0 6px":1,"0 6px 6px":1,"0 0 6px":1,"2px 4px":1,"0 var(--cv-inset,max(18px,calc((100% - 760px)/2))) 6px":1,"6px 8px 0":1,"10px 36px 10px 12px":1,"0 10px":1,"10px 8px 6px":1}}
{"file":"agent-session/acpmux/summary/summary.css","kind":"spacing","property":"padding","values":{"8px 8px 10px":1,"4px 4px 4px 6px":1,"0 2px 4px 4px":1,"0 6px":1,"0 6px 6px":1,"0 0 6px":1,"2px 4px":1,"6px 8px 0":1,"10px 36px 10px 12px":1,"0 10px":1,"10px 8px 6px":1}}
{"file":"agent-session/acpmux/summary/summary.css","kind":"spacing","property":"padding-right","values":{"2px":2}}
{"file":"agent-session/acpmux/summary/WorkflowCard.css","kind":"height","property":"height","values":{"calc(var(--ds-control-icon) + 2px)":1}}
{"file":"agent-session/acpmux/summary/WorkflowSideTab.css","kind":"height","property":"height","values":{"calc(var(--ds-space-3) + 1px)":1}}
Expand Down
35 changes: 33 additions & 2 deletions webviews/src/agent-session/acpmux/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -477,6 +477,14 @@ import {
import { ThreadTitle } from "./header/ThreadTitle";
import { headerState, setHeaderState, useHeaderState } from "./header/headerState";
import { setTabRow, tabRowStyle, useTabRow, useTabRowTools } from "./header/tabRow";
import type { SummaryPullRequest } from "./summary/transcriptPullRequests";
import {
PullRequestCountInStack,
PullRequestList,
PullRequestStackProvider,
pullRequestControlLook,
useTranscriptPullRequests,
} from "./summary/PullRequestStack";
import { SubagentPaneFooter } from "./subagents/SubagentPaneFooter";
import { RecapCard, useRecapCard } from "./RecapCard";
import { HarnessStatusCard } from "./HarnessStatusCard";
Expand Down Expand Up @@ -5140,6 +5148,9 @@ export function NewTabComposerChips({
}

/// The chat's own composer chips, as the pane draws them under a chat (tests drive them directly).
/// No pull requests: a stable empty list for the Quick Composer and a new chat.
const NO_PULL_REQUESTS: readonly SummaryPullRequest[] = [];

export function ChatComposerChips({ snapshot }: { snapshot: AcpmuxSnapshot }) {
return <DefaultComposerChips snapshot={snapshot} />;
}
Expand Down Expand Up @@ -8281,6 +8292,14 @@ function AcpmuxPane() {
</SubagentClockContext.Provider>
</BackgroundTaskOutputContext.Provider>
) : null;
// The chat's pull requests, one "N PRs" row in the bottom stack (summary/PullRequestStack.tsx),
// counted from the transcript's command findings (Session Info's Changes).
const stackPullRequests = useTranscriptPullRequests(snapshot.rows, githubRepository ?? undefined);
// Where the folded count sits: the quiet row, or a gallery comparison's place; the tray's header
// line only while the tray shows there.
const prControlLook = pullRequestControlLook();
const prControlPlacement =
prControlLook === "tray" && !(trayPlacement === "tray" && trayNode) ? "quiet" : prControlLook;
/// The composer's prompt, which dictation writes into.
const prompt = useRef<MarkdownFieldHandle>(null);
/// The composer itself, which takes back prompts a harness switch held; prompts handed back
Expand Down Expand Up @@ -11832,7 +11851,14 @@ function AcpmuxPane() {
<SubagentPaneFooter chat={chatName} />
) : (
!reviewing && (
<>
// The chat's pull requests (summary/PullRequestStack.tsx): the "N PRs" count in the composer's
// quiet row and the chips it opens over the composer, both inside the composer's own element,
// so neither shows where the composer does not (a handoff review, the Sandboxed receipt).
<PullRequestStackProvider
prs={quick || freshView ? NO_PULL_REQUESTS : stackPullRequests}
sessionId={shownSessionId}
placement={prControlPlacement}
>
{recapCard.recap && (
<RecapCard
recap={recapCard.recap}
Expand Down Expand Up @@ -11999,7 +12025,12 @@ function AcpmuxPane() {
</Notice>
{/* The tray (subagents/SubagentTray.tsx): in the bottom stack, right above the composer, every
running or recently ended subagent, background command and started chat, one card each. */}
{/* A gallery comparison's count on the tray's header line (PullRequestCountInStack). */}
<PullRequestCountInStack at="tray" />
{trayPlacement === "tray" && trayNode}
{/* The chips the "N PRs" count opens, right over the composer. */}
<PullRequestList />
<PullRequestCountInStack at="above" />
{statusCardOpen && (
<HarnessStatusCard
summary={snapshot.summary}
Expand Down Expand Up @@ -12311,7 +12342,7 @@ function AcpmuxPane() {
onEdit={(command) => ignoreFailure(callNative("pane.edit", { command }))}
/>
</ImageViewerContext.Provider>
</>
</PullRequestStackProvider>
)
);
// A handshake that still waits for acpmux: once it has waited long, one line says how long, with
Expand Down
3 changes: 3 additions & 0 deletions webviews/src/agent-session/acpmux/Composer.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import React, { useCallback, useEffect, useImperativeHandle, useLayoutEffect, useMemo, useRef, useState } from "react";
import { PullRequestCountSlot } from "./summary/PullRequestStack";
import { createPortal } from "react-dom";
// Send's iMessage colors (--cmux-messages-blue); build-agent-pane-web.sh inlines the sheet.
import "../../theme/messages.css";
Expand Down Expand Up @@ -2501,6 +2502,8 @@ export function Composer({
chips={
<PromptFocus value={focusPrompt}>
<Chips snapshot={snapshot} permissionAccess={permissionAccess} />
{/* The chat's "N PRs" count beside the mode, in a row already there (summary/PullRequestStack.tsx). */}
<PullRequestCountSlot />
</PromptFocus>
}
// Claude Code ends the quiet row on the context ring. It keeps its place before the chat
Expand Down
134 changes: 134 additions & 0 deletions webviews/src/agent-session/acpmux/Localizable.xcstrings
Original file line number Diff line number Diff line change
Expand Up @@ -16252,6 +16252,140 @@
}
}
},
"prDock.label": {
"comment": "Agent pane: name of the bars above the composer listing the pull requests this chat opened (cx-ncc.81)",
"extractionState": "manual",
"localizations": {
"en": {
"stringUnit": {
"state": "translated",
"value": "Pull requests in this chat"
}
},
"ar": {
"stringUnit": {
"state": "needs_review",
"value": "طلبات السحب في هذه المحادثة"
}
},
"bs": {
"stringUnit": {
"state": "needs_review",
"value": "Pull requestovi u ovom chatu"
}
},
"da": {
"stringUnit": {
"state": "needs_review",
"value": "Pull requests i denne chat"
}
},
"de": {
"stringUnit": {
"state": "needs_review",
"value": "Pull Requests in diesem Chat"
}
},
"es": {
"stringUnit": {
"state": "needs_review",
"value": "Pull requests de este chat"
}
},
"fr": {
"stringUnit": {
"state": "needs_review",
"value": "Pull requests de cette discussion"
}
},
"it": {
"stringUnit": {
"state": "needs_review",
"value": "Pull request in questa chat"
}
},
"ja": {
"stringUnit": {
"state": "needs_review",
"value": "このチャットのプルリクエスト"
}
},
"km": {
"stringUnit": {
"state": "needs_review",
"value": "សំណើ Pull ក្នុងការជជែកនេះ"
}
},
"ko": {
"stringUnit": {
"state": "needs_review",
"value": "이 채팅의 풀 리퀘스트"
}
},
"nb": {
"stringUnit": {
"state": "needs_review",
"value": "Pull requests i denne chatten"
}
},
"pl": {
"stringUnit": {
"state": "needs_review",
"value": "Pull requesty w tym czacie"
}
},
"pt-BR": {
"stringUnit": {
"state": "needs_review",
"value": "Pull requests nesta conversa"
}
},
"ru": {
"stringUnit": {
"state": "needs_review",
"value": "Пул-реквесты в этом чате"
}
},
"th": {
"stringUnit": {
"state": "needs_review",
"value": "Pull request ในแชทนี้"
}
},
"tr": {
"stringUnit": {
"state": "needs_review",
"value": "Bu sohbetteki pull request'ler"
}
},
"uk": {
"stringUnit": {
"state": "needs_review",
"value": "Пул-реквести в цьому чаті"
}
},
"vi": {
"stringUnit": {
"state": "needs_review",
"value": "Pull request trong cuộc trò chuyện này"
}
},
"zh-Hans": {
"stringUnit": {
"state": "needs_review",
"value": "此聊天中的拉取请求"
}
},
"zh-Hant": {
"stringUnit": {
"state": "needs_review",
"value": "此聊天中的提取要求"
}
}
}
},
"prDock.countOne": {"comment":"Agent pane: compact count of one pull request above the composer (si-prpills)","extractionState":"manual","localizations":{"en":{"stringUnit":{"state":"needs_review","value":"1 PR"}},"ar":{"stringUnit":{"state":"needs_review","value":"1 PR"}},"bs":{"stringUnit":{"state":"needs_review","value":"1 PR"}},"da":{"stringUnit":{"state":"needs_review","value":"1 PR"}},"de":{"stringUnit":{"state":"needs_review","value":"1 PR"}},"es":{"stringUnit":{"state":"needs_review","value":"1 PR"}},"fr":{"stringUnit":{"state":"needs_review","value":"1 PR"}},"it":{"stringUnit":{"state":"needs_review","value":"1 PR"}},"ja":{"stringUnit":{"state":"needs_review","value":"1 PR"}},"km":{"stringUnit":{"state":"needs_review","value":"1 PR"}},"ko":{"stringUnit":{"state":"needs_review","value":"1 PR"}},"nb":{"stringUnit":{"state":"needs_review","value":"1 PR"}},"pl":{"stringUnit":{"state":"needs_review","value":"1 PR"}},"pt-BR":{"stringUnit":{"state":"needs_review","value":"1 PR"}},"ru":{"stringUnit":{"state":"needs_review","value":"1 PR"}},"th":{"stringUnit":{"state":"needs_review","value":"1 PR"}},"tr":{"stringUnit":{"state":"needs_review","value":"1 PR"}},"uk":{"stringUnit":{"state":"needs_review","value":"1 PR"}},"vi":{"stringUnit":{"state":"needs_review","value":"1 PR"}},"zh-Hans":{"stringUnit":{"state":"needs_review","value":"1 PR"}},"zh-Hant":{"stringUnit":{"state":"needs_review","value":"1 PR"}}}},
"prDock.count": {"comment":"Agent pane: compact count of pull requests above the composer; {count} is the number (si-prpills)","extractionState":"manual","localizations":{"en":{"stringUnit":{"state":"needs_review","value":"{count} PRs"}},"ar":{"stringUnit":{"state":"needs_review","value":"{count} PRs"}},"bs":{"stringUnit":{"state":"needs_review","value":"{count} PRs"}},"da":{"stringUnit":{"state":"needs_review","value":"{count} PRs"}},"de":{"stringUnit":{"state":"needs_review","value":"{count} PRs"}},"es":{"stringUnit":{"state":"needs_review","value":"{count} PRs"}},"fr":{"stringUnit":{"state":"needs_review","value":"{count} PRs"}},"it":{"stringUnit":{"state":"needs_review","value":"{count} PRs"}},"ja":{"stringUnit":{"state":"needs_review","value":"{count} PRs"}},"km":{"stringUnit":{"state":"needs_review","value":"{count} PRs"}},"ko":{"stringUnit":{"state":"needs_review","value":"{count} PRs"}},"nb":{"stringUnit":{"state":"needs_review","value":"{count} PRs"}},"pl":{"stringUnit":{"state":"needs_review","value":"{count} PRs"}},"pt-BR":{"stringUnit":{"state":"needs_review","value":"{count} PRs"}},"ru":{"stringUnit":{"state":"needs_review","value":"{count} PRs"}},"th":{"stringUnit":{"state":"needs_review","value":"{count} PRs"}},"tr":{"stringUnit":{"state":"needs_review","value":"{count} PRs"}},"uk":{"stringUnit":{"state":"needs_review","value":"{count} PRs"}},"vi":{"stringUnit":{"state":"needs_review","value":"{count} PRs"}},"zh-Hans":{"stringUnit":{"state":"needs_review","value":"{count} PRs"}},"zh-Hant":{"stringUnit":{"state":"needs_review","value":"{count} PRs"}}}},

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2: These count entries are English in every non-English locale, so localized users see 1 PR/{count} PRs even though the surrounding dock label is translated. Add locale-specific count wording, including each locale’s plural form, instead of duplicating the English value across all locale entries.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At webviews/src/agent-session/acpmux/Localizable.xcstrings, line 16388:

<comment>These count entries are English in every non-English locale, so localized users see `1 PR`/`{count} PRs` even though the surrounding dock label is translated. Add locale-specific count wording, including each locale’s plural form, instead of duplicating the English value across all locale entries.</comment>

<file context>
@@ -16252,6 +16252,140 @@
+      }
+    },
+    "prDock.countOne": {"comment":"Agent pane: compact count of one pull request above the composer (si-prpills)","extractionState":"manual","localizations":{"en":{"stringUnit":{"state":"needs_review","value":"1 PR"}},"ar":{"stringUnit":{"state":"needs_review","value":"1 PR"}},"bs":{"stringUnit":{"state":"needs_review","value":"1 PR"}},"da":{"stringUnit":{"state":"needs_review","value":"1 PR"}},"de":{"stringUnit":{"state":"needs_review","value":"1 PR"}},"es":{"stringUnit":{"state":"needs_review","value":"1 PR"}},"fr":{"stringUnit":{"state":"needs_review","value":"1 PR"}},"it":{"stringUnit":{"state":"needs_review","value":"1 PR"}},"ja":{"stringUnit":{"state":"needs_review","value":"1 PR"}},"km":{"stringUnit":{"state":"needs_review","value":"1 PR"}},"ko":{"stringUnit":{"state":"needs_review","value":"1 PR"}},"nb":{"stringUnit":{"state":"needs_review","value":"1 PR"}},"pl":{"stringUnit":{"state":"needs_review","value":"1 PR"}},"pt-BR":{"stringUnit":{"state":"needs_review","value":"1 PR"}},"ru":{"stringUnit":{"state":"needs_review","value":"1 PR"}},"th":{"stringUnit":{"state":"needs_review","value":"1 PR"}},"tr":{"stringUnit":{"state":"needs_review","value":"1 PR"}},"uk":{"stringUnit":{"state":"needs_review","value":"1 PR"}},"vi":{"stringUnit":{"state":"needs_review","value":"1 PR"}},"zh-Hans":{"stringUnit":{"state":"needs_review","value":"1 PR"}},"zh-Hant":{"stringUnit":{"state":"needs_review","value":"1 PR"}}}},
+    "prDock.count": {"comment":"Agent pane: compact count of pull requests above the composer; {count} is the number (si-prpills)","extractionState":"manual","localizations":{"en":{"stringUnit":{"state":"needs_review","value":"{count} PRs"}},"ar":{"stringUnit":{"state":"needs_review","value":"{count} PRs"}},"bs":{"stringUnit":{"state":"needs_review","value":"{count} PRs"}},"da":{"stringUnit":{"state":"needs_review","value":"{count} PRs"}},"de":{"stringUnit":{"state":"needs_review","value":"{count} PRs"}},"es":{"stringUnit":{"state":"needs_review","value":"{count} PRs"}},"fr":{"stringUnit":{"state":"needs_review","value":"{count} PRs"}},"it":{"stringUnit":{"state":"needs_review","value":"{count} PRs"}},"ja":{"stringUnit":{"state":"needs_review","value":"{count} PRs"}},"km":{"stringUnit":{"state":"needs_review","value":"{count} PRs"}},"ko":{"stringUnit":{"state":"needs_review","value":"{count} PRs"}},"nb":{"stringUnit":{"state":"needs_review","value":"{count} PRs"}},"pl":{"stringUnit":{"state":"needs_review","value":"{count} PRs"}},"pt-BR":{"stringUnit":{"state":"needs_review","value":"{count} PRs"}},"ru":{"stringUnit":{"state":"needs_review","value":"{count} PRs"}},"th":{"stringUnit":{"state":"needs_review","value":"{count} PRs"}},"tr":{"stringUnit":{"state":"needs_review","value":"{count} PRs"}},"uk":{"stringUnit":{"state":"needs_review","value":"{count} PRs"}},"vi":{"stringUnit":{"state":"needs_review","value":"{count} PRs"}},"zh-Hans":{"stringUnit":{"state":"needs_review","value":"{count} PRs"}},"zh-Hant":{"stringUnit":{"state":"needs_review","value":"{count} PRs"}}}},
     "prDock.dismiss": {
       "comment": "Agent pane: button that hides a pull request's bar above the composer for this chat; {number} is the PR number (cx-ncc.81)",
</file context>

"prDock.dismiss": {
"comment": "Agent pane: button that hides a pull request's bar above the composer for this chat; {number} is the PR number (cx-ncc.81)",
"extractionState": "manual",
Expand Down
Loading
Loading