sync: merge upstream v1.0.145 into integration#115
sync: merge upstream v1.0.145 into integration#115shuv1337 wants to merge 71 commits intointegrationfrom
Conversation
Co-authored-by: Ingo Fruend <[email protected]>
- Tauri app now automatically finds an available port instead of defaulting to 4096 - Icon discovery feature is now enabled by default in the Tauri app - Prevents port conflicts when multiple OpenCode instances are running
Frontend now receives the server port via window.__OPENCODE__.port, allowing it to connect when using a random free port instead of hardcoded 4096
Signed-off-by: Christian Stewart <[email protected]>
…co#5337) Signed-off-by: Christian Stewart <[email protected]>
- Add og:image and twitter:image meta tags for better social sharing - Generate dynamic social card URLs with session title, models, and version - Include description meta tag for search engines
- Add og:image and twitter:image meta tags to entry-server - Provide fallback social card image for pages without specific social cards
Resolved conflicts: - .github/workflows/opencode.yml: Keep ours (fork-specific workflow) - .github/workflows/publish.yml: Deleted (fork-specific publishing) - packages/desktop/src/components/prompt-input.tsx: Accept upstream (new model dialog UI) - packages/desktop/src/context/global-sync.tsx: Accept upstream (ProviderListResponse type) - packages/desktop/src/context/layout.tsx: Accept upstream (new dialog system) - packages/desktop/src/pages/home.tsx: Accept upstream (projects property name) - packages/opencode/src/cli/cmd/tui/routes/session/index.tsx: Accept upstream (text styling) - packages/opencode/src/session/prompt.ts: Accept upstream (better error handling) - packages/ui/src/components/icon.tsx: Accept upstream (new icons) - packages/ui/src/components/select-dialog.tsx: Accept upstream (actions prop) - bun.lock: Regenerated
- Update font-picker.tsx to use local state instead of removed layout.font - Update theme-picker.tsx to use local state instead of removed layout.theme - Remove onHighlight prop from SelectDialog (no longer supported) - Replace 'type' icon with 'code-lines' and 'droplet' with 'dot-grid' - Add Command type and command property to State in global-sync.tsx - Fix useKittyKeyboard to use object type instead of boolean
WalkthroughUpstream sync to v1.0.145 introducing provider-aware UI components, refactoring desktop TUI session interface, renaming global data structures (projects→project, adding provider.list), expanding multi-platform availability messaging, version bumping across packages, and API enhancements including a global disposal endpoint. Changes
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Areas requiring extra attention:
Possibly related issues
Possibly related PRs
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
User coderabbitai[bot] does not have write permissions |
There was a problem hiding this comment.
Actionable comments posted: 17
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (5)
packages/console/app/src/routes/index.tsx (1)
145-148: Update platform availability messaging to match changes elsewhere.This section still says "desktop (coming soon)" but the updated FAQ content at line 670 states "OpenCode is now available as an app for your desktop." Additionally, this mentions "web" but doesn't mention "IDE extension," while the updated content throughout the file (lines 160, 196, 648-649) emphasizes "IDE extension" instead.
Apply this diff to align the messaging:
- <p data-slot="installation-options"> - Available in terminal, web, and desktop (coming soon). - <br /> - Extensions for VS Code, Cursor, Windsurf, and more. - </p> + <p data-slot="installation-options"> + Available in terminal, desktop app, and web. + <br /> + Extensions for VS Code, Cursor, Windsurf, and more. + </p>packages/opencode/package.json (1)
12-17: Fix misleading and broken script definitions in packages/opencode/package.json.The scripts section contains several problematic definitions that do not match their intended purpose:
- Line 12 (
random): Placeholder script with multiple echo statements; no functional purpose.- Line 14 (
lint): Mislabeled—runsbun test --coverage(testing) instead of actual linting checks.- Line 15 (
format): Uses non-standardbun run --prettiersyntax; unclear if prettier is actually executed.- Line 16 (
docs): Only echoes file paths withfind; does not generate documentation.- Line 17 (
deploy): Basic echo statements and build execution; appears to be a placeholder.Either replace these with proper implementations or remove them if they are not needed.
packages/opencode/src/session/index.ts (1)
221-234: Add idempotency check before creating a share.The
share()function callsShareNext.create(id)without verifying if a share already exists for the session. Callingshare()multiple times would create duplicate share records on the server, with only the latest URL retained locally, orphaning previous shares.Consider checking
session.sharebefore callingShareNext.create(), or ensure the API endpoint handles idempotency by returning the existing share when one already exists for that session ID.packages/opencode/src/server/server.ts (1)
791-798: Schema requirestimeobject even for title-only updates.The validation schema requires a
timeobject with an optionalarchivedfield. This means clients must always sendtime: {}even when only updatingtitle, which is awkward.Consider making the entire
timeobject optional:validator( "json", z.object({ title: z.string().optional(), - time: z.object({ + time: z.object({ archived: z.number().optional(), - }), + }).optional(), }), ),Then update line 808 to check
updates.time?.archived.packages/sdk/openapi.json (1)
8190-8207: v1 SDK types out of sync with OpenAPI spec — regenerate packages/sdk/js/src/gen/types.gen.tsThe server correctly returns
homeas a required field (confirmed in packages/opencode/src/server/server.ts line 534). However, the v1 SDK generated types at packages/sdk/js/src/gen/types.gen.ts are missing thehomefield, while the v2 SDK at packages/sdk/js/src/v2/gen/types.gen.ts has been properly updated to include it.This creates a type safety gap: the
homefield will be present in responses from/path, but v1 TypeScript clients won't have it in their type definitions. The v1 SDK types must be regenerated from the updated OpenAPI spec to match the server implementation and v2 SDK.
♻️ Duplicate comments (1)
packages/ui/src/styles/tailwind/index.css (1)
60-60: LGTM - Valid Tailwind CSS v4 syntax (static analysis false positive).The syntax
--radius-xl: 0.625rem;is valid CSS custom property syntax within Tailwind CSS v4's@themedirective. The Biome parser errors are false positives caused by the tool not recognizing Tailwind v4's CSS-first configuration pattern. This addition extends the radius scale consistently with other radius tokens defined in the theme.
🧹 Nitpick comments (24)
packages/opencode/src/cli/cmd/tui/routes/session/index.tsx (1)
855-913: Consider extracting the IIFE to a named component.The inline IIFE pattern works but reduces readability and testability. Consider extracting this revert message UI to a separate component like
RevertedMessageBanner.- <Match when={message.id === revert()?.messageID}> - {(function () { - const command = useCommandDialog() - const [hover, setHover] = createSignal(false) - const dialog = useDialog() - - const handleUnrevert = async () => { - const confirmed = await DialogConfirm.show( - dialog, - "Confirm Redo", - "Are you sure you want to restore the reverted messages?", - ) - if (confirmed) { - command.trigger("session.redo") - } - } - - return ( - <box ... > - ... - </box> - ) - })()} - </Match> + <Match when={message.id === revert()?.messageID}> + <RevertedMessageBanner revert={revert()!} keybind={keybind} /> + </Match>packages/console/app/src/routes/index.tsx (1)
160-160: Consider aligning phrasing with other platform descriptions.For consistency with lines 196 and 648-649, consider rephrasing to match the "available as" pattern used elsewhere:
- <p>OpenCode is an open source agent that helps you write code in your terminal, IDE, or desktop.</p> + <p>OpenCode is an open source agent that helps you write code using a terminal interface, IDE extension, or desktop app.</p>packages/ui/src/components/input.tsx (1)
10-32:hiddenprop semantics and overflow when collapsedIntroducing
hidden?: booleanand wiring it into the wrapper style is reasonable, but there are two subtle behavior points worth calling out:
- Because
hiddenis now pulled out insplitProps, it will no longer be forwarded as the nativehiddenattribute to<Kobalte.Input>. If anything relied on<Input hidden />affecting the actual<input>element, this changes that behavior; if that’s not desired, consider either a different prop name or also forwarding ahidden/data-hiddenflag to the inner input.- With only
height: 0, children can visually overflow the wrapper in some layouts. Addingoverflow: "hidden"whenhiddenis true will make the collapse more robust.A small tweak to the style would address the overflow case:
- <Kobalte - data-component="input" - style={{ height: local.hidden ? 0 : undefined }} + <Kobalte + data-component="input" + style={{ + height: local.hidden ? 0 : undefined, + overflow: local.hidden ? "hidden" : undefined, + }}packages/opencode/src/cli/cmd/auth.ts (2)
17-160: Centralized plugin auth flow looks solid; consider small robustness and DRY tweaksThe helper correctly covers method selection, prompt collection, OAuth (
auto/code) and API flows, and returns a clear handled/fallthrough boolean, matching its docstring.Two minor follow‑ups you might consider:
- Add a defensive guard in case a misconfigured plugin exposes
methods.length === 0, to avoidplugin.auth.methods[0]beingundefined.- The success branches for OAuth (
autovscode) duplicate the logic that extractsrefresh/access/expiresvskeyand callsAuth.set. Extracting that into a small helper (e.g.savePluginAuthResult(result, provider)) would reduce repetition and keep future changes in one place.These are non‑blocking and can be deferred.
324-329: Custom provider plugin auth handling is correct; minor duplication opportunityChecking for a matching plugin again after the “other” provider ID is entered is a nice touch and lets plugins own custom IDs too. You’re calling
Plugin.list()twice in the handler now; if this grows, you could optionally cache the result once and reuse it for both lookups, but it’s not critical given expected plugin counts.packages/web/astro.config.mjs (1)
34-40: Brand title change to “OpenCode” is fine; consider fixing Discord label typoThe updated
title: "OpenCode"matches the rest of the branding and is good. While you’re here, you may also want to correct the existinglabel: "Dscord"to"Discord"for polish.packages/web/src/content/docs/index.mdx (1)
10-21: Docs wording update is good; optional hyphenation tweakThe broader description (“terminal-based interface, desktop app, or IDE extension”) and terminal‑specific prerequisites read well and match current product scope. For style, you might consider changing “open source AI coding agent” to “open‑source AI coding agent” since it’s used as a compound adjective.
packages/opencode/src/share/share-next.ts (1)
14-16: Centralized URL helper is fine; consider minor reuse / DRY improvementsThe new
url()helper and updated fetch calls correctly centralize enterprise/base URL resolution and introduce a sensible default (https://opncd.ai). Behaviorally this matches the intent of always having a share host even whenconfig.enterpriseis absent.You might optionally:
- Cache the resolved URL in
url()(or higher up) ifConfig.get()is relatively expensive or always static.- Reuse a single constant or helper for the
"https://opncd.ai"fallback (e.g., aligned withshortDomainusage) to avoid drift if the host ever changes.Not blocking; just a small maintainability win if this URL is reused elsewhere.
Also applies to: 67-76, 133-143, 147-159
packages/enterprise/src/routes/index.tsx (1)
1-3: Component is fine; consider giving the default export a nameThis minimal route component works as expected. For better debugging and consistency with typical JSX/Solid conventions, consider naming it, e.g.:
export default function Index() { return <div>Hello World</div> }Not required, just a clarity/diagnostics improvement.
infra/stage.ts (1)
15-19:shortDomainbehavior is correct; consider deduplicating stage logic
shortDomainuses the same stage rules asdomainwith a different base host, which is correct for the new short hostname.To avoid future drift if stage handling changes, you might extract a small helper, e.g.:
function makeDomain(base: string) { if ($app.stage === "production") return base if ($app.stage === "dev") return `dev.${base}` return `${$app.stage}.dev.${base}` } export const domain = makeDomain("opencode.ai") export const shortDomain = makeDomain("opncd.ai")Optional, but keeps all stage-domain mapping logic in one place.
packages/desktop/src/hooks/use-providers.ts (1)
25-30: Nested memo returns accessor functions instead of values.The returned object contains
popularandconnectedas accessor functions (memos), whileallanddefaultare direct values. This inconsistency means consumers must callproviders().popular()but can directly useproviders().all. Consider destructuring the memo values for a consistent API:return createMemo(() => ({ all: providers().all, default: providers().default, - popular, - connected, + popular: popular(), + connected: connected(), }))packages/desktop/src/components/theme-picker.tsx (1)
14-14: UnusedpreviewThemesignal.The
previewThemesignal is created and cleared in handlers, but never set to a theme value (only toundefined). With the removal ofonHighlightfromSelectDialog, the preview functionality appears incomplete or vestigial. Consider removing if preview-on-hover is no longer supported:-const [previewTheme, setPreviewTheme] = createSignal<Theme | undefined>()And simplify
handleOpenChange:function handleOpenChange(open: boolean) { - if (!open && previewTheme()) { - applyTheme(currentTheme().id) - setPreviewTheme(undefined) - } + // No preview revert needed }packages/ui/src/components/list.css (1)
100-111: Consider avoiding!importantfor icon color overrides.The
!importantdeclarations on lines 101 and 109 suggest specificity conflicts. If possible, increase specificity through more specific selectors rather than using!important, which can make future style overrides difficult:- [data-slot="list-item-extra-icon"] { - color: var(--icon-strong-base) !important; - } + &[data-active="true"] [data-slot="list-item-extra-icon"], + &:hover [data-slot="list-item-extra-icon"] { + color: var(--icon-strong-base); + }packages/opencode/src/session/prompt.ts (1)
366-370: Catch block may receive non-Error values.The catch block types
executionErrorasError | undefined, but JavaScript can throw any value. Consider defensive handling:.catch((error) => { - executionError = error + executionError = error instanceof Error ? error : new Error(String(error)) log.error("subtask execution failed", { error, agent: task.agent, description: task.description }) return undefined })This ensures
executionError.messageon line 396 always works.packages/desktop/src/components/prompt-input.tsx (1)
323-346: Remove commented-out code.The commented code blocks (lines 323-327 and 331-346) appear to be leftover from the refactor. Consider removing them to improve code maintainability.
Apply this diff to clean up the commented code:
- // if (!session.id) { - // session.layout.setOpenedTabs( - // session.layout.copyTabs("", session.id) - // } - const toAbsolutePath = (path: string) => (path.startsWith("/") ? path : sync.absolute(path)) const attachments = prompt.filter((part) => part.type === "file") - - // const activeFile = local.context.active() - // if (activeFile) { - // registerAttachment( - // activeFile.path, - // activeFile.selection, - // activeFile.name ?? formatAttachmentLabel(activeFile.path, activeFile.selection), - // ) - // } - - // for (const contextFile of local.context.all()) { - // registerAttachment( - // contextFile.path, - // contextFile.selection, - // formatAttachmentLabel(contextFile.path, contextFile.selection), - // ) - // } - + const attachmentParts = attachments.map((attachment) => {packages/web/src/content/docs/providers.mdx (1)
571-681: Helicone provider section looks consistent; just confirm JSONC/trailing‑comma supportThe Helicone docs match the structure and tone of other provider sections, and the examples (baseURL, models, headers, plugin) look coherent.
One thing to double‑check: the config snippets are marked as
jsoncand use comments plus trailing commas. That’s fine ifopencode.jsoncis parsed as JSONC with trailing‑comma support; if not, you may want to drop the trailing commas in the examples to avoid copy‑paste parse errors.packages/ui/src/components/select-dialog.css (1)
1-16: Scrollbar hiding inside dialog content: check usability/accessibility impactThe nested
[data-slot="dialog-body"]rules fully hide scrollbars (scrollbar-width: none,-ms-overflow-style: none,::-webkit-scrollbar { display: none; }). That’s visually clean but can make scrollability less discoverable and harder for some users.If this dialog can overflow significantly, consider at least verifying keyboard scrolling works well and that there’s some visual cue (e.g., fade gradient) indicating more content below.
packages/ui/src/components/provider-icon.tsx (1)
6-8: Renaming prop toidchanges its semantics vs DOMidUsing
id: IconNameand pulling it out viasplitPropsmeans thisidis now purely the sprite symbol identifier and is not forwarded as the<svg>’s DOMidattribute anymore.If that’s intentional and call sites have been updated, this is fine. If any consumers relied on setting a DOM
idonProviderIcon, they’ll now need another prop (e.g.svgId) or to pass it via a different name.Also applies to: 11-12, 21-22
packages/opencode/src/provider/transform.ts (2)
77-88: Confirmbuggeddetection is using the correct model identifierThe new
buggedgate usesmodel.id:const bugged = (model.id === "kimi-k2-thinking" && model.providerID === "opencode") || (model.id === "moonshotai/Kimi-K2-Thinking" && model.providerID === "baseten")Everywhere else in this file, checks are done against
model.api.id(e.g., temperature/options logic). If those Kimi identifiers actually live onmodel.api.id, this condition will never trigger and the “bugged” models will still go through thereasoning_contentpath you’re trying to avoid.Consider aligning this with the rest of the file, e.g. by checking
model.api.id(with consistent casing) or by confirming thatProvider.Model["id"]is indeed populated with these exact strings.
237-244: Make the Gemini‑3 thinkingConfig check case‑insensitive for consistencyHere:
if (model.api.npm === "@ai-sdk/google" || model.api.npm === "@ai-sdk/google-vertex") { result["thinkingConfig"] = { includeThoughts: true } if (model.api.id.includes("gemini-3")) { result["thinkingConfig"]["thinkingLevel"] = "high" } }Other logic (e.g.,
temperature) usesmodel.api.id.toLowerCase().includes("gemini-3-pro"). To avoid missing models whose IDs differ only by case (e.g.,Gemini-3-pro), it would be safer to mirror that pattern:if (model.api.id.toLowerCase().includes("gemini-3")) { result.thinkingConfig.thinkingLevel = "high" }This keeps behavior robust across potential ID variants.
packages/ui/src/components/tag.css (1)
25-36: Consider using a CSS variable for font-size consistency.The
normalsize variant usesvar(--font-size-small)for font-size, but thelargevariant hardcodes14px. For consistency and easier theming, consider using a CSS variable likevar(--font-size-base)or equivalent.&[data-size="large"] { height: 22px; padding: 0 8px; /* text-14-medium */ font-family: var(--font-family-sans); - font-size: 14px; + font-size: var(--font-size-base); font-style: normal; font-weight: var(--font-weight-medium); line-height: var(--line-height-large); /* 142.857% */ letter-spacing: var(--letter-spacing-normal); }packages/ui/src/components/select-dialog.tsx (1)
23-30: Consider guarding against missingprops.keyfunction.If
props.currentis truthy butprops.keyis undefined, this will throw. The type system should prevent this, but a defensive check could help.createEffect(() => { if (!props.current) return + if (!props.key) return const key = props.key(props.current) requestAnimationFrame(() => { const element = document.querySelector(`[data-key="${key}"]`) element?.scrollIntoView({ block: "center" }) }) })packages/desktop/src/context/layout.tsx (2)
59-77: Consider handling failures fromproject.updateor at least logging
colorizewritesicon.colorback viaglobalSdk.client.project.updatebut ignores errors. For a noncritical cosmetic field this is mostly fine, but silent failures could leave UI and backend out of sync (client shows a color that never persisted).If this matters operationally, you might consider:
- Adding a
.catchwith a debug log/telemetry hook, or- Making the update fire-and-forget but conditional on some “allow auto-write” flag.
Not urgent, but worth thinking about if users rely on colors being durable.
82-91: Rename innersetStoreinloadProjectSessionsto avoid shadowingInside
loadProjectSessions, the destructuredconst [, setStore] = globalSync.child(directory)shadows the outer layoutsetStorefrommakePersisted. This is easy to misread as updating the layout store instead of the per-directory sync store.A small rename improves clarity:
- async function loadProjectSessions(directory: string) { - const [, setStore] = globalSync.child(directory) + async function loadProjectSessions(directory: string) { + const [, setChildStore] = globalSync.child(directory) globalSdk.client.session.list({ directory }).then((x) => { const sessions = (x.data ?? []) .slice() .sort((a, b) => a.id.localeCompare(b.id)) .slice(0, 5) - setStore("session", sessions) + setChildStore("session", sessions) }) }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (52)
bun.lockis excluded by!**/*.lockpackages/sdk/js/src/v2/gen/sdk.gen.tsis excluded by!**/gen/**packages/sdk/js/src/v2/gen/types.gen.tsis excluded by!**/gen/**packages/tauri/src-tauri/icons/128x128.pngis excluded by!**/*.pngpackages/tauri/src-tauri/icons/[email protected]is excluded by!**/*.pngpackages/tauri/src-tauri/icons/32x32.pngis excluded by!**/*.pngpackages/tauri/src-tauri/icons/64x64.pngis excluded by!**/*.pngpackages/tauri/src-tauri/icons/Square107x107Logo.pngis excluded by!**/*.pngpackages/tauri/src-tauri/icons/Square142x142Logo.pngis excluded by!**/*.pngpackages/tauri/src-tauri/icons/Square150x150Logo.pngis excluded by!**/*.pngpackages/tauri/src-tauri/icons/Square284x284Logo.pngis excluded by!**/*.pngpackages/tauri/src-tauri/icons/Square30x30Logo.pngis excluded by!**/*.pngpackages/tauri/src-tauri/icons/Square310x310Logo.pngis excluded by!**/*.pngpackages/tauri/src-tauri/icons/Square44x44Logo.pngis excluded by!**/*.pngpackages/tauri/src-tauri/icons/Square71x71Logo.pngis excluded by!**/*.pngpackages/tauri/src-tauri/icons/Square89x89Logo.pngis excluded by!**/*.pngpackages/tauri/src-tauri/icons/StoreLogo.pngis excluded by!**/*.pngpackages/tauri/src-tauri/icons/android/mipmap-hdpi/ic_launcher.pngis excluded by!**/*.pngpackages/tauri/src-tauri/icons/android/mipmap-hdpi/ic_launcher_foreground.pngis excluded by!**/*.pngpackages/tauri/src-tauri/icons/android/mipmap-hdpi/ic_launcher_round.pngis excluded by!**/*.pngpackages/tauri/src-tauri/icons/android/mipmap-mdpi/ic_launcher.pngis excluded by!**/*.pngpackages/tauri/src-tauri/icons/android/mipmap-mdpi/ic_launcher_foreground.pngis excluded by!**/*.pngpackages/tauri/src-tauri/icons/android/mipmap-mdpi/ic_launcher_round.pngis excluded by!**/*.pngpackages/tauri/src-tauri/icons/android/mipmap-xhdpi/ic_launcher.pngis excluded by!**/*.pngpackages/tauri/src-tauri/icons/android/mipmap-xhdpi/ic_launcher_foreground.pngis excluded by!**/*.pngpackages/tauri/src-tauri/icons/android/mipmap-xhdpi/ic_launcher_round.pngis excluded by!**/*.pngpackages/tauri/src-tauri/icons/android/mipmap-xxhdpi/ic_launcher.pngis excluded by!**/*.pngpackages/tauri/src-tauri/icons/android/mipmap-xxhdpi/ic_launcher_foreground.pngis excluded by!**/*.pngpackages/tauri/src-tauri/icons/android/mipmap-xxhdpi/ic_launcher_round.pngis excluded by!**/*.pngpackages/tauri/src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher.pngis excluded by!**/*.pngpackages/tauri/src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher_foreground.pngis excluded by!**/*.pngpackages/tauri/src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher_round.pngis excluded by!**/*.pngpackages/tauri/src-tauri/icons/icon.icois excluded by!**/*.icopackages/tauri/src-tauri/icons/icon.pngis excluded by!**/*.pngpackages/tauri/src-tauri/icons/ios/[email protected]is excluded by!**/*.pngpackages/tauri/src-tauri/icons/ios/[email protected]is excluded by!**/*.pngpackages/tauri/src-tauri/icons/ios/[email protected]is excluded by!**/*.pngpackages/tauri/src-tauri/icons/ios/[email protected]is excluded by!**/*.pngpackages/tauri/src-tauri/icons/ios/[email protected]is excluded by!**/*.pngpackages/tauri/src-tauri/icons/ios/[email protected]is excluded by!**/*.pngpackages/tauri/src-tauri/icons/ios/[email protected]is excluded by!**/*.pngpackages/tauri/src-tauri/icons/ios/[email protected]is excluded by!**/*.pngpackages/tauri/src-tauri/icons/ios/[email protected]is excluded by!**/*.pngpackages/tauri/src-tauri/icons/ios/[email protected]is excluded by!**/*.pngpackages/tauri/src-tauri/icons/ios/[email protected]is excluded by!**/*.pngpackages/tauri/src-tauri/icons/ios/[email protected]is excluded by!**/*.pngpackages/tauri/src-tauri/icons/ios/[email protected]is excluded by!**/*.pngpackages/tauri/src-tauri/icons/ios/[email protected]is excluded by!**/*.pngpackages/tauri/src-tauri/icons/ios/[email protected]is excluded by!**/*.pngpackages/tauri/src-tauri/icons/ios/[email protected]is excluded by!**/*.pngpackages/tauri/src-tauri/icons/ios/[email protected]is excluded by!**/*.pngpackages/tauri/src-tauri/icons/ios/[email protected]is excluded by!**/*.png
📒 Files selected for processing (93)
.github/last-synced-tag(1 hunks).opencode/opencode.jsonc(0 hunks)README.md(1 hunks)infra/enterprise.ts(1 hunks)infra/stage.ts(1 hunks)nix/hashes.json(1 hunks)package.json(1 hunks)packages/console/app/package.json(1 hunks)packages/console/app/src/app.tsx(1 hunks)packages/console/app/src/config.ts(2 hunks)packages/console/app/src/routes/index.tsx(4 hunks)packages/console/app/src/routes/t/[...path].tsx(1 hunks)packages/console/core/package.json(1 hunks)packages/console/function/package.json(1 hunks)packages/console/mail/package.json(1 hunks)packages/desktop/package.json(1 hunks)packages/desktop/src/app.tsx(1 hunks)packages/desktop/src/components/font-picker.tsx(3 hunks)packages/desktop/src/components/prompt-input.tsx(10 hunks)packages/desktop/src/components/theme-picker.tsx(2 hunks)packages/desktop/src/context/global-sync.tsx(5 hunks)packages/desktop/src/context/layout.tsx(4 hunks)packages/desktop/src/context/local.tsx(4 hunks)packages/desktop/src/context/session.tsx(1 hunks)packages/desktop/src/context/sync.tsx(2 hunks)packages/desktop/src/hooks/use-providers.ts(1 hunks)packages/desktop/src/pages/home.tsx(4 hunks)packages/desktop/src/pages/layout.tsx(8 hunks)packages/enterprise/package.json(2 hunks)packages/enterprise/src/entry-server.tsx(0 hunks)packages/enterprise/src/routes/index.tsx(1 hunks)packages/enterprise/src/routes/share/[shareID].tsx(4 hunks)packages/enterprise/vite.config.ts(1 hunks)packages/extensions/zed/extension.toml(2 hunks)packages/function/package.json(1 hunks)packages/opencode/package.json(1 hunks)packages/opencode/src/bus/index.ts(2 hunks)packages/opencode/src/cli/cmd/auth.ts(3 hunks)packages/opencode/src/cli/cmd/tui/app.tsx(2 hunks)packages/opencode/src/cli/cmd/tui/context/directory.ts(1 hunks)packages/opencode/src/cli/cmd/tui/context/sync.tsx(4 hunks)packages/opencode/src/cli/cmd/tui/routes/session/index.tsx(6 hunks)packages/opencode/src/flag/flag.ts(1 hunks)packages/opencode/src/project/instance.ts(2 hunks)packages/opencode/src/project/project.ts(1 hunks)packages/opencode/src/provider/provider.ts(1 hunks)packages/opencode/src/provider/transform.ts(2 hunks)packages/opencode/src/server/server.ts(8 hunks)packages/opencode/src/session/compaction.ts(1 hunks)packages/opencode/src/session/index.ts(2 hunks)packages/opencode/src/session/prompt.ts(5 hunks)packages/opencode/src/share/share-next.ts(4 hunks)packages/opencode/src/tool/bash.txt(1 hunks)packages/opencode/test/tool/bash.test.ts(2 hunks)packages/plugin/package.json(1 hunks)packages/sdk/js/package.json(1 hunks)packages/sdk/openapi.json(7 hunks)packages/slack/package.json(1 hunks)packages/tauri/package.json(1 hunks)packages/tauri/src-tauri/capabilities/default.json(1 hunks)packages/tauri/src-tauri/src/lib.rs(4 hunks)packages/tauri/src/index.tsx(0 hunks)packages/ui/index.html(0 hunks)packages/ui/package.json(1 hunks)packages/ui/src/components/avatar.tsx(1 hunks)packages/ui/src/components/button.css(1 hunks)packages/ui/src/components/dialog.css(4 hunks)packages/ui/src/components/dialog.tsx(1 hunks)packages/ui/src/components/icon.tsx(3 hunks)packages/ui/src/components/input.css(1 hunks)packages/ui/src/components/input.tsx(1 hunks)packages/ui/src/components/list.css(1 hunks)packages/ui/src/components/list.tsx(1 hunks)packages/ui/src/components/provider-icon.tsx(2 hunks)packages/ui/src/components/select-dialog.css(2 hunks)packages/ui/src/components/select-dialog.tsx(1 hunks)packages/ui/src/components/tag.css(1 hunks)packages/ui/src/components/tag.tsx(1 hunks)packages/ui/src/demo.tsx(0 hunks)packages/ui/src/index.css(0 hunks)packages/ui/src/index.tsx(0 hunks)packages/ui/src/styles/index.css(2 hunks)packages/ui/src/styles/tailwind/index.css(1 hunks)packages/ui/src/styles/theme.css(1 hunks)packages/util/package.json(1 hunks)packages/web/astro.config.mjs(1 hunks)packages/web/package.json(1 hunks)packages/web/src/content/docs/ecosystem.mdx(1 hunks)packages/web/src/content/docs/index.mdx(2 hunks)packages/web/src/content/docs/permissions.mdx(1 hunks)packages/web/src/content/docs/providers.mdx(1 hunks)packages/web/src/content/docs/sdk.mdx(2 hunks)sdks/vscode/package.json(1 hunks)
💤 Files with no reviewable changes (7)
- packages/enterprise/src/entry-server.tsx
- .opencode/opencode.jsonc
- packages/tauri/src/index.tsx
- packages/ui/src/demo.tsx
- packages/ui/src/index.tsx
- packages/ui/src/index.css
- packages/ui/index.html
🧰 Additional context used
📓 Path-based instructions (9)
packages/opencode/**/*.ts
📄 CodeRabbit inference engine (packages/opencode/AGENTS.md)
packages/opencode/**/*.ts: Use Bun with TypeScript ESM modules as the runtime
Organize file structure using namespace-based organization (e.g.,Tool.define(),Session.create())
Validate all inputs with Zod schemas
UseLog.create({ service: "name" })pattern for logging
UseStoragenamespace for persistence operations
Files:
packages/opencode/src/share/share-next.tspackages/opencode/src/provider/provider.tspackages/opencode/src/project/project.tspackages/opencode/src/project/instance.tspackages/opencode/src/session/compaction.tspackages/opencode/src/session/index.tspackages/opencode/src/cli/cmd/tui/context/directory.tspackages/opencode/src/session/prompt.tspackages/opencode/src/provider/transform.tspackages/opencode/src/server/server.tspackages/opencode/src/bus/index.tspackages/opencode/src/flag/flag.tspackages/opencode/src/cli/cmd/auth.tspackages/opencode/test/tool/bash.test.ts
packages/opencode/**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (packages/opencode/AGENTS.md)
packages/opencode/**/*.{ts,tsx,js,jsx}: Use relative imports for local modules, with named imports preferred
Use camelCase for variable and function names
Use PascalCase for classes and namespaces
Files:
packages/opencode/src/share/share-next.tspackages/opencode/src/provider/provider.tspackages/opencode/src/project/project.tspackages/opencode/src/project/instance.tspackages/opencode/src/cli/cmd/tui/app.tsxpackages/opencode/src/session/compaction.tspackages/opencode/src/session/index.tspackages/opencode/src/cli/cmd/tui/context/directory.tspackages/opencode/src/session/prompt.tspackages/opencode/src/provider/transform.tspackages/opencode/src/server/server.tspackages/opencode/src/bus/index.tspackages/opencode/src/flag/flag.tspackages/opencode/src/cli/cmd/tui/context/sync.tsxpackages/opencode/src/cli/cmd/auth.tspackages/opencode/test/tool/bash.test.tspackages/opencode/src/cli/cmd/tui/routes/session/index.tsx
packages/opencode/**/*.{ts,tsx}
📄 CodeRabbit inference engine (packages/opencode/AGENTS.md)
packages/opencode/**/*.{ts,tsx}: Use Zod schemas for validation and TypeScript interfaces for structure
Use Result patterns for error handling; avoid throwing exceptions in tools
Files:
packages/opencode/src/share/share-next.tspackages/opencode/src/provider/provider.tspackages/opencode/src/project/project.tspackages/opencode/src/project/instance.tspackages/opencode/src/cli/cmd/tui/app.tsxpackages/opencode/src/session/compaction.tspackages/opencode/src/session/index.tspackages/opencode/src/cli/cmd/tui/context/directory.tspackages/opencode/src/session/prompt.tspackages/opencode/src/provider/transform.tspackages/opencode/src/server/server.tspackages/opencode/src/bus/index.tspackages/opencode/src/flag/flag.tspackages/opencode/src/cli/cmd/tui/context/sync.tsxpackages/opencode/src/cli/cmd/auth.tspackages/opencode/test/tool/bash.test.tspackages/opencode/src/cli/cmd/tui/routes/session/index.tsx
packages/desktop/**/*.{ts,tsx}
📄 CodeRabbit inference engine (packages/desktop/AGENTS.md)
packages/desktop/**/*.{ts,tsx}: Use SolidJS with TypeScript as the primary framework
Use@/alias for src/ directory imports (e.g.,import Button from "@/ui/button")
Use function declarations and splitProps for SolidJS component props
Define interfaces for component props and avoid usinganytype
Use PascalCase for component names
Use camelCase for variable and function names
Files:
packages/desktop/src/pages/home.tsxpackages/desktop/src/context/session.tsxpackages/desktop/src/hooks/use-providers.tspackages/desktop/src/context/local.tsxpackages/desktop/src/components/font-picker.tsxpackages/desktop/src/components/prompt-input.tsxpackages/desktop/src/context/sync.tsxpackages/desktop/src/pages/layout.tsxpackages/desktop/src/app.tsxpackages/desktop/src/components/theme-picker.tsxpackages/desktop/src/context/layout.tsxpackages/desktop/src/context/global-sync.tsx
packages/desktop/**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (packages/desktop/AGENTS.md)
Apply Prettier formatting with semicolons disabled and 120 character line width
Files:
packages/desktop/src/pages/home.tsxpackages/desktop/src/context/session.tsxpackages/desktop/src/hooks/use-providers.tspackages/desktop/src/context/local.tsxpackages/desktop/src/components/font-picker.tsxpackages/desktop/src/components/prompt-input.tsxpackages/desktop/src/context/sync.tsxpackages/desktop/src/pages/layout.tsxpackages/desktop/src/app.tsxpackages/desktop/src/components/theme-picker.tsxpackages/desktop/src/context/layout.tsxpackages/desktop/src/context/global-sync.tsx
packages/desktop/**/*.{css,ts,tsx}
📄 CodeRabbit inference engine (packages/desktop/AGENTS.md)
Use TailwindCSS with custom CSS variables theme system for styling
Files:
packages/desktop/src/pages/home.tsxpackages/desktop/src/context/session.tsxpackages/desktop/src/hooks/use-providers.tspackages/desktop/src/context/local.tsxpackages/desktop/src/components/font-picker.tsxpackages/desktop/src/components/prompt-input.tsxpackages/desktop/src/context/sync.tsxpackages/desktop/src/pages/layout.tsxpackages/desktop/src/app.tsxpackages/desktop/src/components/theme-picker.tsxpackages/desktop/src/context/layout.tsxpackages/desktop/src/context/global-sync.tsx
packages/desktop/**/*
📄 CodeRabbit inference engine (packages/desktop/AGENTS.md)
Use snake_case for file names
Files:
packages/desktop/src/pages/home.tsxpackages/desktop/src/context/session.tsxpackages/desktop/src/hooks/use-providers.tspackages/desktop/src/context/local.tsxpackages/desktop/package.jsonpackages/desktop/src/components/font-picker.tsxpackages/desktop/src/components/prompt-input.tsxpackages/desktop/src/context/sync.tsxpackages/desktop/src/pages/layout.tsxpackages/desktop/src/app.tsxpackages/desktop/src/components/theme-picker.tsxpackages/desktop/src/context/layout.tsxpackages/desktop/src/context/global-sync.tsx
packages/desktop/**/pages/**/*.{ts,tsx}
📄 CodeRabbit inference engine (packages/desktop/AGENTS.md)
Place pages in
/pages/directory
Files:
packages/desktop/src/pages/home.tsxpackages/desktop/src/pages/layout.tsx
packages/desktop/**/components/**/*.{ts,tsx}
📄 CodeRabbit inference engine (packages/desktop/AGENTS.md)
Place higher-level components in
/components/directory
Files:
packages/desktop/src/components/font-picker.tsxpackages/desktop/src/components/prompt-input.tsxpackages/desktop/src/components/theme-picker.tsx
🧠 Learnings (22)
📚 Learning: 2025-12-02T19:05:12.128Z
Learnt from: CR
Repo: Latitudes-Dev/shuvcode PR: 0
File: packages/desktop/AGENTS.md:0-0
Timestamp: 2025-12-02T19:05:12.128Z
Learning: Applies to packages/desktop/**/*.{css,ts,tsx} : Use TailwindCSS with custom CSS variables theme system for styling
Applied to files:
packages/ui/src/styles/theme.csspackages/ui/src/styles/tailwind/index.csspackages/ui/src/styles/index.css
📚 Learning: 2025-12-02T19:05:12.128Z
Learnt from: CR
Repo: Latitudes-Dev/shuvcode PR: 0
File: packages/desktop/AGENTS.md:0-0
Timestamp: 2025-12-02T19:05:12.128Z
Learning: Applies to packages/desktop/**/*.{ts,tsx} : Use function declarations and splitProps for SolidJS component props
Applied to files:
packages/ui/src/components/input.tsxpackages/ui/src/components/provider-icon.tsxpackages/ui/src/components/tag.tsxpackages/desktop/src/components/font-picker.tsxpackages/desktop/src/components/prompt-input.tsxpackages/desktop/src/pages/layout.tsxpackages/ui/src/components/avatar.tsxpackages/ui/src/components/list.tsxpackages/opencode/src/cli/cmd/tui/routes/session/index.tsx
📚 Learning: 2025-12-02T19:05:12.128Z
Learnt from: CR
Repo: Latitudes-Dev/shuvcode PR: 0
File: packages/desktop/AGENTS.md:0-0
Timestamp: 2025-12-02T19:05:12.128Z
Learning: Applies to packages/desktop/**/*.{ts,tsx} : Use PascalCase for component names
Applied to files:
packages/desktop/src/pages/home.tsx
📚 Learning: 2025-12-02T19:05:12.128Z
Learnt from: CR
Repo: Latitudes-Dev/shuvcode PR: 0
File: packages/desktop/AGENTS.md:0-0
Timestamp: 2025-12-02T19:05:12.128Z
Learning: Applies to packages/desktop/**/*.{ts,tsx} : Use `@/` alias for src/ directory imports (e.g., `import Button from "@/ui/button"`)
Applied to files:
packages/desktop/src/pages/home.tsxpackages/opencode/src/cli/cmd/tui/context/directory.tspackages/ui/src/components/avatar.tsx
📚 Learning: 2025-12-02T19:05:12.128Z
Learnt from: CR
Repo: Latitudes-Dev/shuvcode PR: 0
File: packages/desktop/AGENTS.md:0-0
Timestamp: 2025-12-02T19:05:12.128Z
Learning: Applies to packages/desktop/**/*.{ts,tsx} : Use camelCase for variable and function names
Applied to files:
packages/desktop/src/pages/home.tsx
📚 Learning: 2025-12-02T19:05:23.634Z
Learnt from: CR
Repo: Latitudes-Dev/shuvcode PR: 0
File: packages/opencode/AGENTS.md:0-0
Timestamp: 2025-12-02T19:05:23.634Z
Learning: Applies to packages/opencode/**/*.{ts,tsx,js,jsx} : Use relative imports for local modules, with named imports preferred
Applied to files:
packages/ui/package.jsonpackages/opencode/package.jsonpackages/opencode/src/cli/cmd/tui/context/directory.tspackages/opencode/src/cli/cmd/tui/context/sync.tsx
📚 Learning: 2025-12-02T19:05:12.128Z
Learnt from: CR
Repo: Latitudes-Dev/shuvcode PR: 0
File: packages/desktop/AGENTS.md:0-0
Timestamp: 2025-12-02T19:05:12.128Z
Learning: Applies to packages/desktop/**/ui/**/*.{ts,tsx} : Place UI primitives in `/ui/` directory
Applied to files:
packages/ui/package.jsonpackages/opencode/src/cli/cmd/tui/context/directory.ts
📚 Learning: 2025-12-02T19:05:23.634Z
Learnt from: CR
Repo: Latitudes-Dev/shuvcode PR: 0
File: packages/opencode/AGENTS.md:0-0
Timestamp: 2025-12-02T19:05:23.634Z
Learning: Use `bun run typecheck` for type checking (or `npm run typecheck` as alternative)
Applied to files:
packages/ui/package.json
📚 Learning: 2025-12-02T19:05:12.128Z
Learnt from: CR
Repo: Latitudes-Dev/shuvcode PR: 0
File: packages/desktop/AGENTS.md:0-0
Timestamp: 2025-12-02T19:05:12.128Z
Learning: Use `bun run dev` to start Vite dev server on port 3000 for development
Applied to files:
packages/ui/package.json
📚 Learning: 2025-12-02T19:05:12.128Z
Learnt from: CR
Repo: Latitudes-Dev/shuvcode PR: 0
File: packages/desktop/AGENTS.md:0-0
Timestamp: 2025-12-02T19:05:12.128Z
Learning: Applies to packages/desktop/**/providers/**/*.{ts,tsx} : Place providers in `/providers/` directory
Applied to files:
packages/desktop/src/context/session.tsxpackages/desktop/src/hooks/use-providers.tspackages/desktop/src/context/sync.tsxpackages/desktop/src/pages/layout.tsxpackages/desktop/src/context/global-sync.tsx
📚 Learning: 2025-12-02T19:05:23.634Z
Learnt from: CR
Repo: Latitudes-Dev/shuvcode PR: 0
File: packages/opencode/AGENTS.md:0-0
Timestamp: 2025-12-02T19:05:23.634Z
Learning: Applies to packages/opencode/**/tools/**/*.ts : Pass `sessionID` in tool context and use `App.provide()` for dependency injection
Applied to files:
packages/desktop/src/context/session.tsxpackages/web/src/content/docs/ecosystem.mdxpackages/opencode/src/session/prompt.tspackages/opencode/src/server/server.tspackages/desktop/src/app.tsxpackages/opencode/test/tool/bash.test.tspackages/opencode/src/cli/cmd/tui/routes/session/index.tsx
📚 Learning: 2025-12-02T19:05:23.634Z
Learnt from: CR
Repo: Latitudes-Dev/shuvcode PR: 0
File: packages/opencode/AGENTS.md:0-0
Timestamp: 2025-12-02T19:05:23.634Z
Learning: Applies to packages/opencode/**/*.ts : Organize file structure using namespace-based organization (e.g., `Tool.define()`, `Session.create()`)
Applied to files:
packages/opencode/package.jsonpackages/web/src/content/docs/ecosystem.mdxpackages/opencode/src/cli/cmd/tui/context/directory.tspackages/opencode/src/cli/cmd/tui/context/sync.tsxpackages/opencode/test/tool/bash.test.tspackages/opencode/src/cli/cmd/tui/routes/session/index.tsx
📚 Learning: 2025-12-02T19:05:23.634Z
Learnt from: CR
Repo: Latitudes-Dev/shuvcode PR: 0
File: packages/opencode/AGENTS.md:0-0
Timestamp: 2025-12-02T19:05:23.634Z
Learning: Applies to packages/opencode/**/*.{ts,tsx} : Use Zod schemas for validation and TypeScript interfaces for structure
Applied to files:
packages/opencode/package.jsonpackages/sdk/js/package.json
📚 Learning: 2025-12-02T19:05:23.634Z
Learnt from: CR
Repo: Latitudes-Dev/shuvcode PR: 0
File: packages/opencode/AGENTS.md:0-0
Timestamp: 2025-12-02T19:05:23.634Z
Learning: Applies to packages/opencode/**/*.ts : Validate all inputs with Zod schemas
Applied to files:
packages/opencode/package.jsonpackages/sdk/js/package.json
📚 Learning: 2025-12-02T19:05:23.634Z
Learnt from: CR
Repo: Latitudes-Dev/shuvcode PR: 0
File: packages/opencode/AGENTS.md:0-0
Timestamp: 2025-12-02T19:05:23.634Z
Learning: Applies to packages/opencode/**/*.ts : Use Bun with TypeScript ESM modules as the runtime
Applied to files:
packages/opencode/package.json
📚 Learning: 2025-12-02T19:05:23.634Z
Learnt from: CR
Repo: Latitudes-Dev/shuvcode PR: 0
File: packages/opencode/AGENTS.md:0-0
Timestamp: 2025-12-02T19:05:23.634Z
Learning: Applies to packages/opencode/**/*.{ts,tsx,js,jsx} : Use PascalCase for classes and namespaces
Applied to files:
packages/opencode/package.jsonpackages/console/app/src/routes/index.tsx
📚 Learning: 2025-12-02T19:05:23.634Z
Learnt from: CR
Repo: Latitudes-Dev/shuvcode PR: 0
File: packages/opencode/AGENTS.md:0-0
Timestamp: 2025-12-02T19:05:23.634Z
Learning: Applies to packages/opencode/**/*.ts : Use `Storage` namespace for persistence operations
Applied to files:
packages/opencode/package.json
📚 Learning: 2025-12-02T19:05:23.634Z
Learnt from: CR
Repo: Latitudes-Dev/shuvcode PR: 0
File: packages/opencode/AGENTS.md:0-0
Timestamp: 2025-12-02T19:05:23.634Z
Learning: Go TUI communicates with TypeScript server via stainless SDK. When adding/modifying server endpoints in `packages/opencode/src/server/server.ts`, ask the user to generate a new client SDK before proceeding with client-side changes
Applied to files:
packages/web/src/content/docs/sdk.mdx
📚 Learning: 2025-12-02T19:05:12.128Z
Learnt from: CR
Repo: Latitudes-Dev/shuvcode PR: 0
File: packages/desktop/AGENTS.md:0-0
Timestamp: 2025-12-02T19:05:12.128Z
Learning: Applies to packages/desktop/**/*.{ts,tsx} : Use SolidJS with TypeScript as the primary framework
Applied to files:
packages/ui/src/components/tag.tsxpackages/desktop/src/components/font-picker.tsxpackages/desktop/src/components/prompt-input.tsxpackages/desktop/src/context/layout.tsxpackages/opencode/src/cli/cmd/tui/routes/session/index.tsx
📚 Learning: 2025-12-02T19:05:12.128Z
Learnt from: CR
Repo: Latitudes-Dev/shuvcode PR: 0
File: packages/desktop/AGENTS.md:0-0
Timestamp: 2025-12-02T19:05:12.128Z
Learning: Applies to packages/desktop/**/*.{ts,tsx} : Define interfaces for component props and avoid using `any` type
Applied to files:
packages/ui/src/components/tag.tsxpackages/ui/src/components/select-dialog.tsx
📚 Learning: 2025-12-02T19:05:23.634Z
Learnt from: CR
Repo: Latitudes-Dev/shuvcode PR: 0
File: packages/opencode/AGENTS.md:0-0
Timestamp: 2025-12-02T19:05:23.634Z
Learning: Applies to packages/opencode/**/*.{ts,tsx,js,jsx} : Use camelCase for variable and function names
Applied to files:
packages/console/app/src/routes/index.tsx
📚 Learning: 2025-12-02T19:05:23.634Z
Learnt from: CR
Repo: Latitudes-Dev/shuvcode PR: 0
File: packages/opencode/AGENTS.md:0-0
Timestamp: 2025-12-02T19:05:23.634Z
Learning: Applies to packages/opencode/**/tools/**/*.ts : Implement tools with the `Tool.Info` interface including an `execute()` method
Applied to files:
packages/opencode/test/tool/bash.test.tspackages/opencode/src/cli/cmd/tui/routes/session/index.tsx
🧬 Code graph analysis (17)
packages/ui/src/components/dialog.tsx (1)
packages/ui/src/components/icon-button.tsx (1)
IconButton(12-28)
infra/enterprise.ts (1)
infra/stage.ts (1)
shortDomain(15-19)
packages/opencode/src/project/instance.ts (1)
packages/opencode/src/bus/global.ts (1)
GlobalBus(3-10)
packages/opencode/src/session/index.ts (2)
packages/sdk/js/src/v2/gen/sdk.gen.ts (1)
share(1062-1085)packages/sdk/js/src/gen/sdk.gen.ts (1)
share(571-576)
packages/opencode/src/session/prompt.ts (3)
packages/sdk/js/src/v2/gen/types.gen.ts (2)
Session(564-592)ToolPart(325-336)packages/opencode/src/tool/task.ts (1)
TaskTool(16-137)packages/opencode/src/session/message-v2.ts (2)
ToolPart(273-281)ToolPart(282-282)
packages/desktop/src/hooks/use-providers.ts (1)
packages/util/src/encode.ts (1)
base64Decode(5-7)
packages/opencode/src/server/server.ts (2)
packages/opencode/src/project/instance.ts (1)
Instance(16-78)packages/opencode/src/bus/global.ts (1)
GlobalBus(3-10)
packages/desktop/src/components/prompt-input.tsx (3)
packages/desktop/src/hooks/use-providers.ts (2)
useProviders(8-31)popularProviders(6-6)packages/util/src/path.ts (2)
getFilename(1-6)getDirectory(8-12)packages/util/src/iife.ts (1)
iife(1-3)
packages/desktop/src/pages/layout.tsx (6)
packages/desktop/src/hooks/use-providers.ts (2)
useProviders(8-31)popularProviders(6-6)packages/util/src/encode.ts (1)
base64Decode(5-7)packages/ui/src/components/select-dialog.tsx (1)
SelectDialog(16-101)packages/desktop/src/context/layout.tsx (4)
open(104-108)open(131-133)open(147-149)open(172-174)packages/ui/src/components/provider-icon.tsx (1)
ProviderIcon(10-24)packages/ui/src/components/tag.tsx (1)
Tag(7-22)
packages/opencode/src/cli/cmd/auth.ts (2)
packages/plugin/src/index.ts (2)
Hooks(144-182)Plugin(33-33)packages/sdk/js/src/gen/types.gen.ts (1)
Auth(1680-1680)
packages/ui/src/components/list.tsx (6)
packages/ui/src/hooks/use-filtered-list.tsx (2)
FilteredListProps(7-16)useFilteredList(18-90)packages/ui/src/components/icon.tsx (2)
IconProps(50-53)Icon(55-73)packages/web/src/components/share/common.tsx (1)
ref(46-58)packages/opencode/src/cli/cmd/tui/ui/dialog-select.tsx (1)
filter(168-170)packages/opencode/src/cli/cmd/tui/context/theme.tsx (1)
selected(314-316)packages/desktop/src/context/session.tsx (1)
setActive(139-141)
packages/enterprise/src/routes/share/[shareID].tsx (5)
packages/ui/src/components/logo.tsx (1)
Mark(1-14)packages/ui/src/components/provider-icon.tsx (1)
ProviderIcon(10-24)packages/ui/src/components/session-turn.tsx (1)
SessionTurn(27-298)packages/ui/src/components/session-message-rail.tsx (1)
SessionMessageRail(14-57)packages/ui/src/components/session-review.tsx (1)
SessionReview(25-125)
packages/opencode/test/tool/bash.test.ts (2)
packages/opencode/test/fixture/fixture.ts (1)
tmpdir(16-34)packages/opencode/src/tool/bash.ts (2)
BashTool(55-369)log(23-23)
packages/console/app/src/routes/t/[...path].tsx (1)
packages/opencode/src/share/share.ts (1)
URL(68-70)
packages/desktop/src/context/layout.tsx (3)
packages/desktop/src/context/sync.tsx (2)
project(45-49)directory(88-90)packages/sdk/js/src/v2/gen/types.gen.ts (1)
Project(21-35)packages/sdk/js/src/v2/gen/sdk.gen.ts (1)
Project(211-291)
packages/opencode/src/cli/cmd/tui/routes/session/index.tsx (4)
packages/opencode/src/cli/cmd/tui/routes/session/header.tsx (1)
Header(31-125)packages/sdk/js/src/gen/sdk.gen.ts (6)
messages(605-610)message(629-634)revert(681-690)command(653-662)text(780-785)prompt(615-624)packages/sdk/js/src/gen/types.gen.ts (1)
AssistantMessage(114-147)packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx (1)
Prompt(49-941)
packages/desktop/src/context/global-sync.tsx (2)
packages/sdk/js/src/v2/gen/types.gen.ts (3)
ProviderListResponse(3135-3135)Command(1479-1486)Project(21-35)packages/sdk/js/src/v2/gen/sdk.gen.ts (2)
Command(1530-1549)Project(211-291)
🪛 Biome (2.1.2)
packages/ui/src/styles/tailwind/index.css
[error] 60-60: expected , but instead found --radius-xl
Remove --radius-xl
(parse)
[error] 60-60: Unexpected value or character.
Expected one of:
(parse)
[error] 60-60: expected , but instead found rem
Remove rem
(parse)
[error] 60-60: expected , but instead found ;
Remove ;
(parse)
[error] 60-60: Unknown type selector is not allowed.
See MDN web docs for more details.
Consider replacing the unknown type selector with valid one.
(lint/correctness/noUnknownTypeSelector)
packages/ui/src/components/button.css
[error] 114-114: Duplicate properties can lead to unexpected behavior and may override previous declarations unintentionally.
font-size is already defined here.
Remove or rename the duplicate property to ensure consistent styling.
(lint/suspicious/noDuplicateProperties)
🪛 LanguageTool
packages/web/src/content/docs/providers.mdx
[grammar] ~571-~571: Ensure spelling is correct
Context: ... txt /models --- ### Helicone Helicone is an LLM...
(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)
[grammar] ~671-~671: Ensure spelling is correct
Context: ...ed as a separate session. ##### Common Helicone headers | Header |...
(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)
packages/web/src/content/docs/permissions.mdx
[grammar] ~143-~143: Use a hyphen to join words.
Context: ...run a command in a pipeline, we use tree sitter to parse each command in the pipe...
(QB_NEW_EN_HYPHEN)
packages/web/src/content/docs/index.mdx
[grammar] ~10-~10: Use a hyphen to join words.
Context: ...ig.console OpenCode is an open source AI coding agent. It's available a...
(QB_NEW_EN_HYPHEN)
| async function handler(evt: APIEvent) { | ||
| const req = evt.request.clone() | ||
| const url = new URL(req.url) | ||
| const targetUrl = `https://enterprise.opencode.ai/${url.pathname}${url.search}` | ||
| const response = await fetch(targetUrl, { | ||
| method: req.method, | ||
| headers: req.headers, | ||
| body: req.body, | ||
| }) | ||
| return response |
There was a problem hiding this comment.
Add error handling and consider security implications.
The proxy lacks error handling for network failures and forwards all request headers (including cookies, authorization) to the target. Consider:
- Wrapping fetch in try-catch
- Filtering sensitive headers if not all should be forwarded
- Adding a timeout
async function handler(evt: APIEvent) {
const req = evt.request.clone()
const url = new URL(req.url)
const targetUrl = `https://enterprise.opencode.ai/${url.pathname}${url.search}`
- const response = await fetch(targetUrl, {
- method: req.method,
- headers: req.headers,
- body: req.body,
- })
- return response
+ try {
+ const response = await fetch(targetUrl, {
+ method: req.method,
+ headers: req.headers,
+ body: req.body,
+ signal: AbortSignal.timeout(30000),
+ })
+ return response
+ } catch (error) {
+ return new Response("Proxy error", { status: 502 })
+ }
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| async function handler(evt: APIEvent) { | |
| const req = evt.request.clone() | |
| const url = new URL(req.url) | |
| const targetUrl = `https://enterprise.opencode.ai/${url.pathname}${url.search}` | |
| const response = await fetch(targetUrl, { | |
| method: req.method, | |
| headers: req.headers, | |
| body: req.body, | |
| }) | |
| return response | |
| async function handler(evt: APIEvent) { | |
| const req = evt.request.clone() | |
| const url = new URL(req.url) | |
| const targetUrl = `https://enterprise.opencode.ai/${url.pathname}${url.search}` | |
| try { | |
| const response = await fetch(targetUrl, { | |
| method: req.method, | |
| headers: req.headers, | |
| body: req.body, | |
| signal: AbortSignal.timeout(30000), | |
| }) | |
| return response | |
| } catch (error) { | |
| return new Response("Proxy error", { status: 502 }) | |
| } | |
| } |
| async function handler(evt: APIEvent) { | ||
| const req = evt.request.clone() | ||
| const url = new URL(req.url) | ||
| const targetUrl = `https://enterprise.opencode.ai/${url.pathname}${url.search}` |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
cd /tmp/repo && find . -type f -name "[...path].tsx" | head -20Repository: Latitudes-Dev/shuvcode
Length of output: 125
🏁 Script executed:
cd /tmp/repo && cat -n packages/console/app/src/routes/t/[...path].tsx 2>/dev/null || echo "File not found"Repository: Latitudes-Dev/shuvcode
Length of output: 157
🏁 Script executed:
cd /tmp/repo && rg -n 'enterprise\.opencode\.ai' packages/console/ --type=ts --type=tsx 2>/dev/null || echo "Pattern not found"Repository: Latitudes-Dev/shuvcode
Length of output: 160
🏁 Script executed:
cd /tmp/repo && git ls-files | grep -E "(routes|proxy)" | head -20Repository: Latitudes-Dev/shuvcode
Length of output: 125
🏁 Script executed:
git ls-files | grep -E "packages/console" | head -20Repository: Latitudes-Dev/shuvcode
Length of output: 914
🏁 Script executed:
git ls-files | grep -E "\[.*\]\.tsx$"Repository: Latitudes-Dev/shuvcode
Length of output: 304
🏁 Script executed:
git ls-files | grep -E "routes" | head -20Repository: Latitudes-Dev/shuvcode
Length of output: 1016
🏁 Script executed:
cat -n packages/console/app/src/routes/t/[...path].tsxRepository: Latitudes-Dev/shuvcode
Length of output: 759
🏁 Script executed:
rg -n 'enterprise\.opencode\.ai' packages/console/app/src/routes/Repository: Latitudes-Dev/shuvcode
Length of output: 197
🏁 Script executed:
rg -n 'OPENCODE_API' packages/console/ --type=ts --type=tsxRepository: Latitudes-Dev/shuvcode
Length of output: 93
🏁 Script executed:
rg -n '\[\.\.\.' packages/console/app/src/routes/ -A 5 -B 2Repository: Latitudes-Dev/shuvcode
Length of output: 1371
🏁 Script executed:
cat -n packages/console/app/src/routes/t/[...path].tsx packages/console/app/src/routes/docs/[...path].ts 2>/dev/null | head -40Repository: Latitudes-Dev/shuvcode
Length of output: 1446
🏁 Script executed:
rg -n 'params\|pathname' packages/console/app/src/routes/ --type=tsRepository: Latitudes-Dev/shuvcode
Length of output: 48
🏁 Script executed:
rg -n 'url\.pathname|params\.' packages/console/app/src/routes/ -B 2 -A 2 --type=ts --type=tsxRepository: Latitudes-Dev/shuvcode
Length of output: 93
🏁 Script executed:
cat -n packages/console/app/src/routes/workspace/[id].tsxRepository: Latitudes-Dev/shuvcode
Length of output: 2905
🏁 Script executed:
rg -n 'export.*handler|export.*GET' packages/console/app/src/routes/docs/ -B 5 -A 5Repository: Latitudes-Dev/shuvcode
Length of output: 1626
🏁 Script executed:
cat -n packages/console/app/src/routes/docs/index.ts packages/console/app/src/routes/docs/[...path].tsRepository: Latitudes-Dev/shuvcode
Length of output: 1439
Remove the trailing slash to match the docs proxy pattern and avoid double slash in URLs.
The URL construction has an inconsistency: the /t/[...path] route includes a trailing slash after the domain (https://enterprise.opencode.ai/), while the similar /docs/[...path] route does not (https://docs.opencode.ai). This creates a double slash when url.pathname starts with /:
-const targetUrl = `https://enterprise.opencode.ai/${url.pathname}${url.search}`
+const targetUrl = `https://enterprise.opencode.ai${url.pathname}${url.search}`This aligns with how the docs proxy route is implemented and ensures clean URLs without double slashes.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const targetUrl = `https://enterprise.opencode.ai/${url.pathname}${url.search}` | |
| const targetUrl = `https://enterprise.opencode.ai${url.pathname}${url.search}` |
🤖 Prompt for AI Agents
packages/console/app/src/routes/t/[...path].tsx around line 6: the targetUrl
includes a trailing slash after the domain which can produce double slashes when
url.pathname starts with '/', so remove the trailing slash from the domain
literal (use "https://enterprise.opencode.ai" instead of
"https://enterprise.opencode.ai/") or alternatively normalize by stripping the
leading slash from url.pathname before concatenation so the final URL matches
the docs proxy pattern and avoids double slashes.
| sdk.client.provider.list().then((x) => { | ||
| setGlobalStore("provider", x.data ?? {}) | ||
| }), |
There was a problem hiding this comment.
Inconsistent fallback for provider data.
The fallback {} doesn't match the expected ProviderListResponse shape used in the default initialization (line 63). If x.data is nullish, accessing provider.all, provider.connected, or provider.default would return undefined instead of the expected arrays/object.
Apply this diff to use a consistent fallback:
sdk.client.provider.list().then((x) => {
- setGlobalStore("provider", x.data ?? {})
+ setGlobalStore("provider", x.data ?? { all: [], connected: [], default: {} })
}),📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| sdk.client.provider.list().then((x) => { | |
| setGlobalStore("provider", x.data ?? {}) | |
| }), | |
| sdk.client.provider.list().then((x) => { | |
| setGlobalStore("provider", x.data ?? { all: [], connected: [], default: {} }) | |
| }), |
🤖 Prompt for AI Agents
In packages/desktop/src/context/global-sync.tsx around lines 196 to 198, the
.then fallback uses {} which doesn't match the ProviderListResponse shape
initialized at line 63; change the fallback from {} to the same structured
default (e.g. { all: [], connected: [], default: {} } or the existing
constant/variable used at line 63) so setGlobalStore("provider", x.data ?? <that
structured default>) returns the expected arrays/objects instead of undefined.
| function isModelValid(model: ModelKey) { | ||
| const provider = sync.data.provider.find((x) => x.id === model.providerID) | ||
| return !!provider?.models[model.modelID] | ||
| const provider = sync.data.provider?.all.find((x) => x.id === model.providerID) | ||
| return !!provider?.models[model.modelID] && sync.data.provider?.connected.includes(model.providerID) | ||
| } |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# First, check if the files exist and their line counts
wc -l packages/desktop/src/context/local.tsx packages/desktop/src/context/sync.tsx 2>/dev/null || echo "Files may not exist at those paths"
# List files in the context directory
find packages/desktop/src/context -type f -name "*.tsx" -o -name "*.ts" 2>/dev/null | head -20Repository: Latitudes-Dev/shuvcode
Length of output: 188
🏁 Script executed:
#!/bin/bash
# Read the relevant sections from local.tsx
echo "=== Lines 35-50 from local.tsx ==="
sed -n '35,50p' packages/desktop/src/context/local.tsx
echo ""
echo "=== Lines 110-125 from local.tsx ==="
sed -n '110,125p' packages/desktop/src/context/local.tsxRepository: Latitudes-Dev/shuvcode
Length of output: 1353
🏁 Script executed:
#!/bin/bash
# Search for sync context definition and provider type
echo "=== Checking sync.tsx for provider definition ==="
rg -n "provider" packages/desktop/src/context/sync.tsx -B 2 -A 2 | head -50Repository: Latitudes-Dev/shuvcode
Length of output: 663
🏁 Script executed:
#!/bin/bash
# Search for the store definition in sync.tsx to see provider's type
echo "=== Store definition in sync.tsx ==="
rg -n "setStore\|provider:" packages/desktop/src/context/sync.tsx -B 5 -A 5 | head -80Repository: Latitudes-Dev/shuvcode
Length of output: 102
🏁 Script executed:
#!/bin/bash
# Check if there's a type definition file for the store
fd -e "ts" -e "tsx" packages/desktop/src -type f | xargs rg -l "ModelKey|provider.*type" | head -10Repository: Latitudes-Dev/shuvcode
Length of output: 545
🏁 Script executed:
#!/bin/bash
# Get more context around line 117 to see if there are guards
echo "=== Full context around lines 110-130 ==="
sed -n '105,135p' packages/desktop/src/context/local.tsxRepository: Latitudes-Dev/shuvcode
Length of output: 1161
🏁 Script executed:
#!/bin/bash
# Read the entire sync.tsx to understand the store definition
cat packages/desktop/src/context/sync.tsxRepository: Latitudes-Dev/shuvcode
Length of output: 3929
🏁 Script executed:
#!/bin/bash
# Also check if there are any type imports or definitions related to provider
rg -n "interface\|type.*[Pp]rovider" packages/desktop/src/context/ -A 3Repository: Latitudes-Dev/shuvcode
Length of output: 48
🏁 Script executed:
#!/bin/bash
# Find and read global-sync.tsx
find packages/desktop/src -name "global-sync*" -type fRepository: Latitudes-Dev/shuvcode
Length of output: 110
🏁 Script executed:
#!/bin/bash
# Read the global-sync file to understand initial store state
cat packages/desktop/src/context/global-sync.tsx 2>/dev/null || cat packages/desktop/src/context/global-sync.ts 2>/dev/nullRepository: Latitudes-Dev/shuvcode
Length of output: 5874
Remove unnecessary optional chaining on sync.data.provider.
Lines 42-43 use optional chaining (sync.data.provider?.all, sync.data.provider?.connected), but provider is initialized as { all: [], connected: [], default: {} } in global-sync.tsx and is never undefined. This contradicts the direct access without optional chaining used at lines 117-120 (sync.data.provider.all, sync.data.provider.connected). Remove the optional chaining operators for consistency.
🤖 Prompt for AI Agents
In packages/desktop/src/context/local.tsx around lines 41 to 44, the
isModelValid function uses unnecessary optional chaining on sync.data.provider
(sync.data.provider?.all and sync.data.provider?.connected) even though provider
is always initialized as { all: [], connected: [], default: {} }; remove the
optional chaining and access sync.data.provider.all and
sync.data.provider.connected directly to match other usages and ensure
consistency.
|
|
||
| for (const p of sync.data.provider.connected) { | ||
| if (p in sync.data.provider.default) { | ||
| return { | ||
| providerID: p, | ||
| modelID: sync.data.provider.default[p], | ||
| } | ||
| } | ||
| } | ||
|
|
||
| throw new Error("No default model found") | ||
| }) |
There was a problem hiding this comment.
Throwing an error here will crash the app if no providers are connected.
When no connected providers have a default model, this throws "No default model found", which will propagate up and likely crash the reactive context. Consider returning a sentinel value or handling this more gracefully.
for (const p of sync.data.provider.connected) {
if (p in sync.data.provider.default) {
return {
providerID: p,
modelID: sync.data.provider.default[p],
}
}
}
- throw new Error("No default model found")
+ // Return undefined to signal no valid model; callers should handle this
+ return undefined
})Then update fallbackModel usage to handle the undefined case appropriately.
Committable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
In packages/desktop/src/context/local.tsx around lines 147 to 158 the code
throws a new Error("No default model found") when no connected provider has a
default model; change this to return a sentinel (e.g., undefined) instead of
throwing so the reactive context won't crash, i.e., return { providerID:
undefined, modelID: undefined } or simply undefined as appropriate for the
surrounding selector, and then update any callers/uses of fallbackModel to
handle the undefined case (fall back to a safe default UI state or no-op) rather
than assuming a non-null value.
| font-size: var(--font-size-small); | ||
| line-height: var(--line-height-large); | ||
| gap: 6px; | ||
|
|
||
| /* text-12-medium */ | ||
| font-family: var(--font-family-sans); | ||
| font-size: var(--font-size-small); | ||
| font-style: normal; | ||
| font-weight: var(--font-weight-medium); | ||
| line-height: var(--line-height-large); /* 166.667% */ | ||
| letter-spacing: var(--letter-spacing-normal); |
There was a problem hiding this comment.
Remove duplicate font-size and line-height declarations in normal button size.
Lines 108–109 declare font-size and line-height, which are redundantly declared again in the explicit typography token block (lines 113–117). This duplication violates DRY and can cause confusion during maintenance.
Apply this diff to remove the earlier, redundant declarations:
&[data-size="normal"] {
height: 24px;
padding: 0 6px;
&[data-icon] {
padding: 0 12px 0 4px;
}
- font-size: var(--font-size-small);
- line-height: var(--line-height-large);
gap: 6px;
/* text-12-medium */
font-family: var(--font-family-sans);
font-size: var(--font-size-small);
font-style: normal;
font-weight: var(--font-weight-medium);
line-height: var(--line-height-large); /* 166.667% */
letter-spacing: var(--letter-spacing-normal);
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| font-size: var(--font-size-small); | |
| line-height: var(--line-height-large); | |
| gap: 6px; | |
| /* text-12-medium */ | |
| font-family: var(--font-family-sans); | |
| font-size: var(--font-size-small); | |
| font-style: normal; | |
| font-weight: var(--font-weight-medium); | |
| line-height: var(--line-height-large); /* 166.667% */ | |
| letter-spacing: var(--letter-spacing-normal); | |
| gap: 6px; | |
| /* text-12-medium */ | |
| font-family: var(--font-family-sans); | |
| font-size: var(--font-size-small); | |
| font-style: normal; | |
| font-weight: var(--font-weight-medium); | |
| line-height: var(--line-height-large); /* 166.667% */ | |
| letter-spacing: var(--letter-spacing-normal); |
🧰 Tools
🪛 Biome (2.1.2)
[error] 114-114: Duplicate properties can lead to unexpected behavior and may override previous declarations unintentionally.
font-size is already defined here.
Remove or rename the duplicate property to ensure consistent styling.
(lint/suspicious/noDuplicateProperties)
🤖 Prompt for AI Agents
In packages/ui/src/components/button.css around lines 108 to 118, remove the
duplicate font-size and line-height declarations at lines 108–109 so only the
explicit typography token block (lines 113–117) defines those properties; update
the CSS by deleting the earlier redundant font-size and line-height lines to
keep a single source of truth under the "text-12-medium" token block.
| [data-component="dialog"] { | ||
| position: fixed; | ||
| inset: 0; | ||
| margin-left: var(--dialog-left-margin); |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
rg -n 'dialog-left-margin' --type cssRepository: Latitudes-Dev/shuvcode
Length of output: 148
Define the --dialog-left-margin CSS variable or remove the margin-left property.
The --dialog-left-margin variable referenced on line 19 is not defined anywhere in the codebase. Without a definition, this property will not apply, and the margin will fall back to browser defaults, defeating the intent of the styling change.
🤖 Prompt for AI Agents
In packages/ui/src/components/dialog.css around line 19, the rule uses
margin-left: var(--dialog-left-margin) but the CSS variable --dialog-left-margin
is not defined; either define --dialog-left-margin (preferably in a global scope
like :root or in the dialog component’s root selector) with the intended value,
or replace the declaration with a concrete margin or a var() call that includes
a fallback (e.g. var(--dialog-left-margin, 1rem)); ensure the variable name and
scope match other component variables if you choose to define it.
| createEffect(() => { | ||
| if (!scrollRef()) return | ||
| if (!props.current) return | ||
| const key = props.key(props.current) | ||
| requestAnimationFrame(() => { | ||
| const element = scrollRef()!.querySelector(`[data-key="${key}"]`) | ||
| element?.scrollIntoView({ block: "center" }) | ||
| }) | ||
| }) |
There was a problem hiding this comment.
Guard scrollRef inside the animation frame to avoid potential runtime errors
The requestAnimationFrame callback dereferences scrollRef()! without rechecking it. If the list unmounts or scrollRef is cleared between scheduling and execution, this can throw at runtime.
You can capture the element up front and bail out early:
- createEffect(() => {
- if (!scrollRef()) return
- if (!props.current) return
- const key = props.key(props.current)
- requestAnimationFrame(() => {
- const element = scrollRef()!.querySelector(`[data-key="${key}"]`)
- element?.scrollIntoView({ block: "center" })
- })
- })
+ createEffect(() => {
+ const container = scrollRef()
+ if (!container) return
+ if (!props.current) return
+ const key = props.key(props.current)
+ requestAnimationFrame(() => {
+ const element = container.querySelector<HTMLElement>(`[data-key="${key}"]`)
+ element?.scrollIntoView({ block: "center" })
+ })
+ })[scratchpad_start]
[done]
- Comment for scrollRef safeguard added.
[scratchpad_end] -->
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| createEffect(() => { | |
| if (!scrollRef()) return | |
| if (!props.current) return | |
| const key = props.key(props.current) | |
| requestAnimationFrame(() => { | |
| const element = scrollRef()!.querySelector(`[data-key="${key}"]`) | |
| element?.scrollIntoView({ block: "center" }) | |
| }) | |
| }) | |
| createEffect(() => { | |
| const container = scrollRef() | |
| if (!container) return | |
| if (!props.current) return | |
| const key = props.key(props.current) | |
| requestAnimationFrame(() => { | |
| const element = container.querySelector<HTMLElement>(`[data-key="${key}"]`) | |
| element?.scrollIntoView({ block: "center" }) | |
| }) | |
| }) |
🤖 Prompt for AI Agents
In packages/ui/src/components/list.tsx around lines 47 to 55, the
requestAnimationFrame callback dereferences scrollRef()! without rechecking it,
which can throw if the ref is cleared before the frame runs; change the code to
capture the current scroll container and derived key before scheduling (const
container = scrollRef(); if (!container) return; const key =
props.key(props.current); requestAnimationFrame(() => { const el =
container.querySelector(`[data-key="${key}"]`); if (!el) return;
el.scrollIntoView({ block: "center" }); })), or alternatively re-read and guard
scrollRef() inside the RAF callback before calling querySelector and
scrollIntoView so you never dereference a possibly null ref.
| > | ||
| {props.children(item)} | ||
| <Show when={item === props.current}> | ||
| <Icon data-slot="list-item-selected-icon" name="check-small" /> | ||
| </Show> | ||
| <Show when={props.activeIcon}> | ||
| {(icon) => <Icon data-slot="list-item-active-icon" name={icon()} />} | ||
| </Show> |
There was a problem hiding this comment.
activeIcon currently renders on every row, not just the active item
Right now the active icon is shown for all items whenever props.activeIcon is set:
<Show when={props.activeIcon}>
{(icon) => <Icon data-slot="list-item-active-icon" name={icon()} />}
</Show>This ignores which item is actually active and will likely confuse users.
A targeted fix is to gate on the active key:
- <Show when={props.activeIcon}>
- {(icon) => <Icon data-slot="list-item-active-icon" name={icon()} />}
- </Show>
+ <Show when={props.activeIcon && props.key(item) === active()}>
+ {(icon) => (
+ <Icon data-slot="list-item-active-icon" name={icon()!} />
+ )}
+ </Show>[scratchpad_start]
[done]
- Comment for activeIcon semantics added.
[scratchpad_end] -->
🤖 Prompt for AI Agents
In packages/ui/src/components/list.tsx around lines 124-131, the current <Show
when={props.activeIcon}> renders the activeIcon for every row whenever
props.activeIcon is truthy; change the guard to only render the icon for the
active item by gating on both the active key and the prop (e.g., Show when={item
=== props.current && props.activeIcon}) and keep using the render function to
call the icon before passing its result to <Icon> so only the active row shows
the activeIcon.
| #### Scope of the `"ask"` option | ||
|
|
||
| When the agent asks for permission to run a particular bash command, it will | ||
| request feedback with the three options "accept", "accept always" and "deny". | ||
| The "accept always" answer applies for the rest of the current session. | ||
|
|
||
| In addition, command permissions are applied to the first two elements of a command. So, an "accept always" response for a command like `git log` would whitelist `git log *` but not `git commit ...`. | ||
|
|
||
| When an agent asks for permission to run a command in a pipeline, we use tree sitter to parse each command in the pipeline. The "accept always" permission thus applies separately to each command in the pipeline. | ||
|
|
There was a problem hiding this comment.
Fix hyphenation of tool name.
The term "tree sitter" should be hyphenated as "tree-sitter" when referring to the parsing tool.
Apply this diff:
-When an agent asks for permission to run a command in a pipeline, we use tree sitter to parse each command in the pipeline. The "accept always" permission thus applies separately to each command in the pipeline.
+When an agent asks for permission to run a command in a pipeline, we use tree-sitter to parse each command in the pipeline. The "accept always" permission thus applies separately to each command in the pipeline.📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| #### Scope of the `"ask"` option | |
| When the agent asks for permission to run a particular bash command, it will | |
| request feedback with the three options "accept", "accept always" and "deny". | |
| The "accept always" answer applies for the rest of the current session. | |
| In addition, command permissions are applied to the first two elements of a command. So, an "accept always" response for a command like `git log` would whitelist `git log *` but not `git commit ...`. | |
| When an agent asks for permission to run a command in a pipeline, we use tree sitter to parse each command in the pipeline. The "accept always" permission thus applies separately to each command in the pipeline. | |
| #### Scope of the `"ask"` option | |
| When the agent asks for permission to run a particular bash command, it will | |
| request feedback with the three options "accept", "accept always" and "deny". | |
| The "accept always" answer applies for the rest of the current session. | |
| In addition, command permissions are applied to the first two elements of a command. So, an "accept always" response for a command like `git log` would whitelist `git log *` but not `git commit ...`. | |
| When an agent asks for permission to run a command in a pipeline, we use tree-sitter to parse each command in the pipeline. The "accept always" permission thus applies separately to each command in the pipeline. |
🧰 Tools
🪛 LanguageTool
[grammar] ~143-~143: Use a hyphen to join words.
Context: ...run a command in a pipeline, we use tree sitter to parse each command in the pipe...
(QB_NEW_EN_HYPHEN)
🤖 Prompt for AI Agents
In packages/web/src/content/docs/permissions.mdx around lines 135 to 144, the
tooling name is written as "tree sitter" but should be hyphenated; update the
text so every occurrence in this block reads "tree-sitter" (e.g., "we use
tree-sitter to parse each command in the pipeline") and ensure consistent
hyphenation across the paragraph.
|
User coderabbitai[bot] does not have write permissions |
|
User coderabbitai[bot] does not have write permissions |
Summary
Conflicts Resolved
.github/workflows/opencode.yml.github/workflows/publish.ymlpackages/desktop/src/components/prompt-input.tsxpackages/desktop/src/context/global-sync.tsxpackages/desktop/src/context/layout.tsxpackages/desktop/src/pages/home.tsxpackages/opencode/src/cli/cmd/tui/routes/session/index.tsxpackages/opencode/src/session/prompt.tspackages/ui/src/components/icon.tsxpackages/ui/src/components/select-dialog.tsxAdditional Fixes
font-picker.tsxandtheme-picker.tsxto use local state (createSignal) instead of removed layout contextCommandtype andcommandproperty to State inglobal-sync.tsxuseKittyKeyboardto use object type instead of boolean in TUI appCloses #113
Summary by CodeRabbit
New Features
Refactor
Bug Fixes
Documentation
Style
✏️ Tip: You can customize this high-level summary in your review settings.