Skip to content

chore: sync upstream dev - #8

Open
peterkc wants to merge 40 commits into
integration/opencode-devfrom
sync-dev-aug02
Open

chore: sync upstream dev#8
peterkc wants to merge 40 commits into
integration/opencode-devfrom
sync-dev-aug02

Conversation

@peterkc

Copy link
Copy Markdown
Collaborator

Issue for this PR

Closes#7

Type of change

  • Bug fix
  • New feature
  • Refactor / code improvement
  • Documentation

What does this PR do?

Merges upstream/dev at 1882c33827cf0ce5c948b69ab5a87ed8f6790cf8 into integration/opencode-dev without rewriting upstream or fork commit history. This keeps the upstream synchronization separate from subsequent feature work.

The merge completed without manual conflict resolution. The fork's six integration-only commits remain in history.

How did you verify your code works?

  • bun typecheck in packages/core: passed.
  • bun typecheck in packages/opencode: passed.
  • bun test test/config/provider.test.ts in packages/core: 3 passed.
  • bun test test/provider/provider.test.ts test/mcp/transport.test.ts in packages/opencode: 101 passed.
  • Pre-push bun turbo typecheck: 30 participating packages passed.
  • git diff --check HEAD^1..HEAD: passed.
  • Inspected the merge parents and confirmed the second parent exactly matches the audited upstream/dev revision.

Screenshots / recordings

Not applicable: repository history synchronization has no UI change.

Checklist

  • I have tested my changes locally
  • I have not included unrelated changes in this PR

arvsrnand others added 30 commits July 30, 2026 16:56
Co-authored-by: Brendan Allan <14191578+Brendonovich@users.noreply.github.com>
Co-authored-by: Brendan Allan <git@brendonovich.dev>
Co-authored-by: Brendan Allan <14191578+Brendonovich@users.noreply.github.com>
Co-authored-by: Dax Raad <d@ironbay.co>
Co-authored-by: Aiden Cline <rekram1-node@users.noreply.github.com>
Co-authored-by: Brendan Allan <git@brendonovich.dev>
@coderabbitai

coderabbitaiBot commented Aug 2, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are limited based on label configuration.

🏷️ Required labels (at least one) (1)
  • coderabbit

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: f816cbd2-4bf4-4f59-b333-bbb596a89f9d

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Comment @coderabbitai help to get the list of available commands.

@github-actions

Copy link
Copy Markdown

Thanks for your contribution!

This PR doesn't have a linked issue. All PRs must reference an existing issue.

Please:

  1. Open an issue describing the bug/feature (if one doesn't exist)
  2. Add Fixes #<number> or Closes #<number> to this PR description

See CONTRIBUTING.md for details.

@peterkc
peterkc marked this pull request as ready for review August 2, 2026 23:39

@cubic-dev-aicubic-dev-aiBot 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.

17 issues found across 179 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="packages/web/src/content/docs/providers.mdx">
<violation number="1" location="packages/web/src/content/docs/providers.mdx:1518">
P3: The Modal section only documents the interactive `/connect` flow, but the `ModalPlugin` (`packages/opencode/src/plugin/modal/modal.ts`) also reads `process.env.MODAL_PROXY_TOKEN` directly, and Modal's own endpoint-integration docs explicitly show `export MODAL_PROXY_TOKEN=wk-<id>.ws-<secret>` for OpenCode. Other providers in this same document include an "Environment Variable" subsection. Consider adding a short note that the combined proxy token can alternatively be set via `MODAL_PROXY_TOKEN`, matching the surrounding provider sections.</violation>
</file>
<file name="packages/session-ui/src/components/message-part.tsx">
<violation number="1" location="packages/session-ui/src/components/message-part.tsx:587">
P2: Task error subtitles are no longer navigable when a host provides `onNavigateToSession` without `onSessionHref`: this change removes the pathname fallback, leaving `href` undefined, and `ToolErrorCard` never invokes the new click handler without an anchor. Retain a valid fallback href or update the error card to expose `onSubtitleClick` without requiring `href`.</violation>
</file>
<file name="packages/core/src/v1/config/provider.ts">
<violation number="1" location="packages/core/src/v1/config/provider.ts:24">
P2: Remote provider configurations using the newly accepted `interleaved` string or `false` values now parse successfully but are silently ignored, so custom reasoning fields cannot be configured and `false` cannot disable an inherited capability. Applying `config.interleaved` to `model.capabilities.interleaved` in the remote update/migration path would keep the widened schema contract effective.</violation>
</file>
<file name="packages/app/test-browser/prompt-attachments.test.ts">
<violation number="1" location="packages/app/test-browser/prompt-attachments.test.ts:127">
P3: Both V2 tests call dispose() only on the happy path, and `createPromptInputV2Attachments` registers global `document` dragover/dragleave/drop listeners via `makeEventListener` in onMount. If any assertion throws, the root is never disposed and these listeners leak into later tests; also test 1 awaits `duplicate.promise` before asserting, so if the duplicate path ever stops firing the test hangs instead of failing. Consider disposing the root in a finally/cleanup wrapper (and asserting before awaiting the resolver).</violation>
</file>
<file name="packages/app/src/pages/session/session-side-panel.tsx">
<violation number="1" location="packages/app/src/pages/session/session-side-panel.tsx:108">
P2: The new 240px minimum clamp on the file-tree width is applied to the side panel (panelWidth/treeWidth) but not to the session panel width, which still uses the raw layout.fileTree.width() (packages/app/src/pages/session.tsx:502, `calc(100% - ${layout.fileTree.width()}px)`). With the default width of 200 (DEFAULT_FILE_TREE_WIDTH) below the new min, the tree renders 240px wide while the chat content is sized as if only 200px are reserved, causing a ~40px overlap/overflow until the tree is actually dragged. Apply the same clamp in the session.tsx calc (or clamp once in layout) so both sides stay consistent.</violation>
<violation number="2" location="packages/app/src/pages/session/session-side-panel.tsx:108">
P3: The panel now renders the file tree at a minimum of 240px, but the persisted default/saved width (DEFAULT_FILE_TREE_WIDTH = 200 in context/layout.tsx) is still below that floor and is stored unclamped. For users on the default or an older saved width below 240, the displayed tree (240px) and the persisted width diverge until the next resize drag, where the stored value jumps to the new dragged position. Consider rounding the default/clamped width at the source (e.g., bumping DEFAULT_FILE_TREE_WIDTH to 240 or clamping inside `resize`) so the displayed and persisted widths stay consistent without requiring an extra resize.</violation>
</file>
<file name="packages/app/src/entry.tsx">
<violation number="1" location="packages/app/src/entry.tsx:82">
P2: External links stop working with a runtime `TypeError` in browsers that do not implement `URL.canParse`; using `new URL(value)` inside a `try/catch` (or guarding the method as the deep-link parser does) preserves the invalid-URL rejection without requiring this newer API.</violation>
</file>
<file name="packages/ui/src/v2/components/toast-v2.css">
<violation number="1" location="packages/ui/src/v2/components/toast-v2.css:10">
P2: Custom toasts composed with the exported `ToastV2.CloseButton` now lose their close-button layout and appearance because this grid layout only recognizes Sonner's `[data-close-button]`, while the component API emits `data-slot="toast-v2-close-button"`; retain a slot-compatible selector/layout (or emit the Sonner attribute) for the custom-toast path.</violation>
</file>
<file name="packages/ui/src/v2/components/toast-v2.tsx">
<violation number="1" location="packages/ui/src/v2/components/toast-v2.tsx:46">
P2: Toasts emitted before `ToastV2.Region` mounts are lost from the UI because the new `Toaster` does not replay entries already stored in solid-sonner's global queue. Mount the toaster before child effects can publish notifications or hydrate it from `toast.getToasts()` on mount.</violation>
<violation number="2" location="packages/ui/src/v2/components/toast-v2.tsx:108">
P2: Close-button consumers using Solid's tuple event-handler form (`onClick={[handler, data]}`) lose their callback because this wrapper only invokes function-valued handlers; forwarding the event through Solid or handling both `EventHandlerUnion` forms would preserve the button contract.</violation>
</file>
<file name="packages/console/app/src/routes/zen/util/provider/google.ts">
<violation number="1" location="packages/console/app/src/routes/zen/util/provider/google.ts:68">
P2: The console provider usage tests now fail for Gemini thinking responses because they still expect `outputTokens` to exclude the two reasoning tokens. The expectations should be updated to the normalized total and retain a regression case for the separate `reasoningTokens` field.</violation>
<violation number="2" location="packages/console/app/src/routes/zen/util/provider/google.ts:68">
P2: This change makes Google `outputTokens` include reasoning tokens (`candidatesTokenCount + thoughtsTokenCount`) while the helper also returns `reasoningTokens` separately. Downstream consumers assume outputTokens and reasoningTokens are disjoint: `trialLimiter.ts` sums `outputTokens + reasoningTokens`, and the usage breakdown in `usage-section.tsx` shows them as independent rows on top of the total output. As a result, reasoning/thinking tokens are now counted twice for Google models — inflating trial promo-token deductions and showing an inflated/duplicated output total in the usage UI. Consider keeping `outputTokens` as `candidatesTokenCount` (excluding thoughts) and reporting `reasoningTokens` separately, matching the anthropic convention and the consumers' expectations, rather than folding thoughts into outputTokens.</violation>
</file>
<file name="packages/session-ui/src/v2/components/session-review-v2.css">
<violation number="1" location="packages/session-ui/src/v2/components/session-review-v2.css:136">
P3: The new scroll-fade overlays use `position: absolute` on the tree slot's `::before`/`::after`, but the tree slot itself has no `position` set, so the containing block falls back to the nearest positioned ancestor, `[data-component="session-review-v2-sidebar-root"]` (`position: relative`, line 18). Consequence: `::before { top: 0 }` places the 16px top fade at the very top of the whole sidebar (over the header/filter) instead of the top of the scrollable tree, so the fade will render in the wrong spot once the tree is scrolled. Adding `position: relative` to the tree slot (mirroring the pattern already used at lines 330/357 in this file) would anchor both fades to the tree.</violation>
</file>
<file name="packages/session-ui/src/v2/components/session-review-v2.tsx">
<violation number="1" location="packages/session-ui/src/v2/components/session-review-v2.tsx:192">
P2: This switches the previously-documented global key handler from the rare `<`/`>` keys to `ArrowLeft`/`ArrowRight` on the whole `document`. Unlike the old keys, arrow keys are heavily used for horizontal scrolling (e.g. in horizontal diff panes), tree/combobox navigation, and widget focus movement. Because the handler calls `event.preventDefault()` and only skips `input, textarea, select`/contentEditable targets, pressing ArrowLeft/ArrowRight anywhere else in the app while the review pane is mounted and `hasDiffs`/files exist will switch the reviewed file and swallow the key press, potentially breaking horizontal scrolling and arrow-key navigation in the file tree and other tree/scroll widgets. Consider narrowing the trigger (e.g. only when the review pane or its tree has focus) or keeping the modifier-free behavior opt-in.</violation>
</file>
<file name="packages/desktop/src/main/windows.ts">
<violation number="1" location="packages/desktop/src/main/windows.ts:262">
P2: The new navigation policy only guards direct navigations and `window.open` calls. A full-page navigation that originates at the app's own URL but returns a server-side 302 redirect to an external http/https site is not caught by `will-navigate` (Electron does not emit that event for server redirects), so the app window could still be navigated away from the renderer origin to an external page instead of being routed through `openExternalURL`. Consider also guarding `will-redirect` (calling `event.preventDefault()` + `openExternalURL`) so redirect-based escapes are handled the same way.</violation>
</file>
<file name="packages/console/app/src/i18n/en.ts">
<violation number="1" location="packages/console/app/src/i18n/en.ts:344">
P3: The `go.faq.a5.used` and `go.faq.a5.noAgreement` translation keys were added to every locale dictionary but are never referenced in the code. The new model table only ever uses `go.faq.a5.notUsed` for the training column and `retention30`/`retention0` for retention, so these additions are currently dead. If they were meant for a future "used"/"agreement" state in the table, that's fine to keep, but the unused keys add translation debt across 18 files; consider wiring them up or dropping them until they're actually consumed.</violation>
</file>
<file name="packages/app/src/components/external-link.tsx">
<violation number="1" location="packages/app/src/components/external-link.tsx:13">
P2: The styling outcome for these external links is now nondeterministic. The component unconditionally prepends `text-text-strong` to every rendered link, while two callers in this change (dialog-connect-provider.tsx lines 841 and 970) intentionally pass `text-v2-text-text-base` to set the text color. Since both are Tailwind color utilities applied to the same element, the effective color depends on generated-CSS order rather than the caller's explicit class, so the intended muted/secondary color may not render. It would be more predictable to let the caller control the text color (e.g., only apply `underline`/`text-text-strong` when the caller does not supply its own text-color utility), or to provide a separate prop/bool for the base decoration instead of always injecting `text-text-strong`.</violation>
</file>

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

return path.match(/\/session\/([^/?#]+)/)?.[1]
function sessionLink(id: string | undefined, href?: (id: string) => string | undefined) {
if (!id) return undefined
return href?.(id)

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: Task error subtitles are no longer navigable when a host provides onNavigateToSession without onSessionHref: this change removes the pathname fallback, leaving href undefined, and ToolErrorCard never invokes the new click handler without an anchor. Retain a valid fallback href or update the error card to expose onSubtitleClick without requiring href.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/session-ui/src/components/message-part.tsx, line 587:
<comment>Task error subtitles are no longer navigable when a host provides `onNavigateToSession` without `onSessionHref`: this change removes the pathname fallback, leaving `href` undefined, and `ToolErrorCard` never invokes the new click handler without an anchor. Retain a valid fallback href or update the error card to expose `onSubtitleClick` without requiring `href`.</comment>
<file context>
@@ -583,29 +582,18 @@ function urls(text: string | undefined) {
- return path.match(/\/session\/([^/?#]+)/)?.[1]
+function sessionLink(id: string | undefined, href?: (id: string) => string | undefined) {
+ if (!id) return undefined
+ return href?.(id)
}
</file context>

interleaved: Schema.optional(
Schema.Union([
Schema.Literal(true),
Schema.Boolean,

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: Remote provider configurations using the newly accepted interleaved string or false values now parse successfully but are silently ignored, so custom reasoning fields cannot be configured and false cannot disable an inherited capability. Applying config.interleaved to model.capabilities.interleaved in the remote update/migration path would keep the widened schema contract effective.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/core/src/v1/config/provider.ts, line 24:
<comment>Remote provider configurations using the newly accepted `interleaved` string or `false` values now parse successfully but are silently ignored, so custom reasoning fields cannot be configured and `false` cannot disable an inherited capability. Applying `config.interleaved` to `model.capabilities.interleaved` in the remote update/migration path would keep the widened schema contract effective.</comment>
<file context>
@@ -16,9 +21,10 @@ export const Model = Schema.Struct({
interleaved: Schema.optional(
Schema.Union([
- Schema.Literal(true),
+ Schema.Boolean,
+ InterleavedField,
Schema.Struct({
</file context>

}),
)
const open = createMemo(() => reviewOpen() || fileOpen())
const fileTreeWidth = createMemo(() => Math.max(FILE_TREE_WIDTH_MIN, layout.fileTree.width()))

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: The new 240px minimum clamp on the file-tree width is applied to the side panel (panelWidth/treeWidth) but not to the session panel width, which still uses the raw layout.fileTree.width() (packages/app/src/pages/session.tsx:502, calc(100% - ${layout.fileTree.width()}px)). With the default width of 200 (DEFAULT_FILE_TREE_WIDTH) below the new min, the tree renders 240px wide while the chat content is sized as if only 200px are reserved, causing a ~40px overlap/overflow until the tree is actually dragged. Apply the same clamp in the session.tsx calc (or clamp once in layout) so both sides stay consistent.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/app/src/pages/session/session-side-panel.tsx, line 108:
<comment>The new 240px minimum clamp on the file-tree width is applied to the side panel (panelWidth/treeWidth) but not to the session panel width, which still uses the raw layout.fileTree.width() (packages/app/src/pages/session.tsx:502, `calc(100% - ${layout.fileTree.width()}px)`). With the default width of 200 (DEFAULT_FILE_TREE_WIDTH) below the new min, the tree renders 240px wide while the chat content is sized as if only 200px are reserved, causing a ~40px overlap/overflow until the tree is actually dragged. Apply the same clamp in the session.tsx calc (or clamp once in layout) so both sides stay consistent.</comment>
<file context>
@@ -104,13 +105,14 @@ export function SessionSidePanel(props: {
}),
)
const open = createMemo(() => reviewOpen() || fileOpen())
+ const fileTreeWidth = createMemo(() => Math.max(FILE_TREE_WIDTH_MIN, layout.fileTree.width()))
const reviewTab = createMemo(() => isDesktop())
const panelWidth = createMemo(() => {
</file context>

Comment on lines +82 to +83
if (!URL.canParse(value)) return
const url = new URL(value)

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: External links stop working with a runtime TypeError in browsers that do not implement URL.canParse; using new URL(value) inside a try/catch (or guarding the method as the deep-link parser does) preserves the invalid-URL rejection without requiring this newer API.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/app/src/entry.tsx, line 82:
<comment>External links stop working with a runtime `TypeError` in browsers that do not implement `URL.canParse`; using `new URL(value)` inside a `try/catch` (or guarding the method as the deep-link parser does) preserves the invalid-URL rejection without requiring this newer API.</comment>
<file context>
@@ -73,21 +72,17 @@ const notify: Platform["notify"] = async (title, description, href) => {
-const forward: Platform["forward"] = () => {
- window.history.forward()
+const openExternal: Platform["openExternal"] = (value) => {
+ if (!URL.canParse(value)) return
+ const url = new URL(value)
+ if (url.protocol !== "http:" && url.protocol !== "https:" && url.protocol !== "mailto:") return
</file context>
Suggested change
if(!URL.canParse(value))return
consturl=newURL(value)
leturl: URL
try{
url=newURL(value)
}catch{
return
}

flex-direction: column;
gap: 12px;
.toast-v2 {
display: grid;

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: Custom toasts composed with the exported ToastV2.CloseButton now lose their close-button layout and appearance because this grid layout only recognizes Sonner's [data-close-button], while the component API emits data-slot="toast-v2-close-button"; retain a slot-compatible selector/layout (or emit the Sonner attribute) for the custom-toast path.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/ui/src/v2/components/toast-v2.css, line 10:
<comment>Custom toasts composed with the exported `ToastV2.CloseButton` now lose their close-button layout and appearance because this grid layout only recognizes Sonner's `[data-close-button]`, while the component API emits `data-slot="toast-v2-close-button"`; retain a slot-compatible selector/layout (or emit the Sonner attribute) for the custom-toast path.</comment>
<file context>
@@ -1,114 +1,133 @@
- flex-direction: column;
- gap: 12px;
+.toast-v2 {
+ display: grid;
+ grid-template-columns: minmax(0, 1fr) 20px;
+ column-gap: 12px;
</file context>

wk-<id>.ws-<secret>
```

3. Run the `/connect` command, search for **Modal**, and enter the combined proxy token.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P3: The Modal section only documents the interactive /connect flow, but the ModalPlugin (packages/opencode/src/plugin/modal/modal.ts) also reads process.env.MODAL_PROXY_TOKEN directly, and Modal's own endpoint-integration docs explicitly show export MODAL_PROXY_TOKEN=wk-<id>.ws-<secret> for OpenCode. Other providers in this same document include an "Environment Variable" subsection. Consider adding a short note that the combined proxy token can alternatively be set via MODAL_PROXY_TOKEN, matching the surrounding provider sections.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/web/src/content/docs/providers.mdx, line 1518:
<comment>The Modal section only documents the interactive `/connect` flow, but the `ModalPlugin` (`packages/opencode/src/plugin/modal/modal.ts`) also reads `process.env.MODAL_PROXY_TOKEN` directly, and Modal's own endpoint-integration docs explicitly show `export MODAL_PROXY_TOKEN=wk-<id>.ws-<secret>` for OpenCode. Other providers in this same document include an "Environment Variable" subsection. Consider adding a short note that the combined proxy token can alternatively be set via `MODAL_PROXY_TOKEN`, matching the surrounding provider sections.</comment>
<file context>
@@ -1505,6 +1505,30 @@ To use Kimi K2 from Moonshot AI:
+ wk-<id>.ws-<secret>
+ ```
+
+3. Run the `/connect` command, search for **Modal**, and enter the combined proxy token.
+
+ ```txt
</file context>

await duplicate.promise

expect(state.prompt).toHaveLength(1)
dispose()

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P3: Both V2 tests call dispose() only on the happy path, and createPromptInputV2Attachments registers global document dragover/dragleave/drop listeners via makeEventListener in onMount. If any assertion throws, the root is never disposed and these listeners leak into later tests; also test 1 awaits duplicate.promise before asserting, so if the duplicate path ever stops firing the test hangs instead of failing. Consider disposing the root in a finally/cleanup wrapper (and asserting before awaiting the resolver).

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/app/test-browser/prompt-attachments.test.ts, line 127:
<comment>Both V2 tests call dispose() only on the happy path, and `createPromptInputV2Attachments` registers global `document` dragover/dragleave/drop listeners via `makeEventListener` in onMount. If any assertion throws, the root is never disposed and these listeners leak into later tests; also test 1 awaits `duplicate.promise` before asserting, so if the duplicate path ever stops firing the test hangs instead of failing. Consider disposing the root in a finally/cleanup wrapper (and asserting before awaiting the resolver).</comment>
<file context>
@@ -85,6 +88,88 @@ describe("prompt attachment session ownership", () => {
+ await duplicate.promise
+
+ expect(state.prompt).toHaveLength(1)
+ dispose()
+ })
+})
</file context>

[data-component="session-review-v2-sidebar-root"] [data-slot="session-review-v2-sidebar-tree"]::before,
[data-component="session-review-v2-sidebar-root"] [data-slot="session-review-v2-sidebar-tree"]::after {
content: "";
position: absolute;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P3: The new scroll-fade overlays use position: absolute on the tree slot's ::before/::after, but the tree slot itself has no position set, so the containing block falls back to the nearest positioned ancestor, [data-component="session-review-v2-sidebar-root"] (position: relative, line 18). Consequence: ::before { top: 0 } places the 16px top fade at the very top of the whole sidebar (over the header/filter) instead of the top of the scrollable tree, so the fade will render in the wrong spot once the tree is scrolled. Adding position: relative to the tree slot (mirroring the pattern already used at lines 330/357 in this file) would anchor both fades to the tree.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/session-ui/src/v2/components/session-review-v2.css, line 136:
<comment>The new scroll-fade overlays use `position: absolute` on the tree slot's `::before`/`::after`, but the tree slot itself has no `position` set, so the containing block falls back to the nearest positioned ancestor, `[data-component="session-review-v2-sidebar-root"]` (`position: relative`, line 18). Consequence: `::before { top: 0 }` places the 16px top fade at the very top of the whole sidebar (over the header/filter) instead of the top of the scrollable tree, so the fade will render in the wrong spot once the tree is scrolled. Adding `position: relative` to the tree slot (mirroring the pattern already used at lines 330/357 in this file) would anchor both fades to the tree.</comment>
<file context>
@@ -109,10 +109,71 @@
+[data-component="session-review-v2-sidebar-root"] [data-slot="session-review-v2-sidebar-tree"]::before,
+[data-component="session-review-v2-sidebar-root"] [data-slot="session-review-v2-sidebar-tree"]::after {
+ content: "";
+ position: absolute;
+ inset-inline: 0;
+ z-index: 10;
</file context>

}),
)
const open = createMemo(() => reviewOpen() || fileOpen())
const fileTreeWidth = createMemo(() => Math.max(FILE_TREE_WIDTH_MIN, layout.fileTree.width()))

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P3: The panel now renders the file tree at a minimum of 240px, but the persisted default/saved width (DEFAULT_FILE_TREE_WIDTH = 200 in context/layout.tsx) is still below that floor and is stored unclamped. For users on the default or an older saved width below 240, the displayed tree (240px) and the persisted width diverge until the next resize drag, where the stored value jumps to the new dragged position. Consider rounding the default/clamped width at the source (e.g., bumping DEFAULT_FILE_TREE_WIDTH to 240 or clamping inside resize) so the displayed and persisted widths stay consistent without requiring an extra resize.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/app/src/pages/session/session-side-panel.tsx, line 108:
<comment>The panel now renders the file tree at a minimum of 240px, but the persisted default/saved width (DEFAULT_FILE_TREE_WIDTH = 200 in context/layout.tsx) is still below that floor and is stored unclamped. For users on the default or an older saved width below 240, the displayed tree (240px) and the persisted width diverge until the next resize drag, where the stored value jumps to the new dragged position. Consider rounding the default/clamped width at the source (e.g., bumping DEFAULT_FILE_TREE_WIDTH to 240 or clamping inside `resize`) so the displayed and persisted widths stay consistent without requiring an extra resize.</comment>
<file context>
@@ -104,13 +105,14 @@ export function SessionSidePanel(props: {
}),
)
const open = createMemo(() => reviewOpen() || fileOpen())
+ const fileTreeWidth = createMemo(() => Math.max(FILE_TREE_WIDTH_MIN, layout.fileTree.width()))
const reviewTab = createMemo(() => isDesktop())
const panelWidth = createMemo(() => {
</file context>

"go.faq.a5.retention": "Data retention",
"go.faq.a5.retention30": "30 days",
"go.faq.a5.retention0": "0 days",
"go.faq.a5.used": "Used",

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P3: The go.faq.a5.used and go.faq.a5.noAgreement translation keys were added to every locale dictionary but are never referenced in the code. The new model table only ever uses go.faq.a5.notUsed for the training column and retention30/retention0 for retention, so these additions are currently dead. If they were meant for a future "used"/"agreement" state in the table, that's fine to keep, but the unused keys add translation debt across 18 files; consider wiring them up or dropping them until they're actually consumed.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/console/app/src/i18n/en.ts, line 344:
<comment>The `go.faq.a5.used` and `go.faq.a5.noAgreement` translation keys were added to every locale dictionary but are never referenced in the code. The new model table only ever uses `go.faq.a5.notUsed` for the training column and `retention30`/`retention0` for retention, so these additions are currently dead. If they were meant for a future "used"/"agreement" state in the table, that's fine to keep, but the unused keys add translation debt across 18 files; consider wiring them up or dropping them until they're actually consumed.</comment>
<file context>
@@ -336,8 +336,21 @@ export const dict = {
+ "go.faq.a5.retention": "Data retention",
+ "go.faq.a5.retention30": "30 days",
+ "go.faq.a5.retention0": "0 days",
+ "go.faq.a5.used": "Used",
+ "go.faq.a5.notUsed": "Not used",
+ "go.faq.a5.noAgreement": "No agreement",
</file context>

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

8 participants

@peterkc@arvsrn@OpeOginni@rekram1-node@devennavani@Hona@MrMushrooooom@fwang