LAC-2337: Lash Upstream Sync — 2026-06-08 (303 commits)#27
Conversation
Co-authored-by: starptech <starptech@starptechs-MBP.fritz.box>
…odule projects (anomalyco#28761) Co-authored-by: Shoubhit Dash <shoubhit2005@gmail.com>
…alyco#30529) Co-authored-by: Simon Klee <hello@simonklee.dk>
There was a problem hiding this comment.
Code Review
This pull request introduces a major update to support WSL (Windows Subsystem for Linux) servers, multi-server management, and scoped state keys to isolate sessions and workspaces by server. It also implements a new V2 layout design with redesigned settings panels, tab navigation, and updated CLI daemon management. The code review identified critical bugs, including potential TypeError crashes due to incorrect optional chaining syntax on unresolved query data in the WSL components and server sync logic. Additionally, feedback was provided to add error handling to a remote file-reading promise chain and to remove a leftover debug console.log statement.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
| <For each={props.servers()}> | ||
| {(item) => { | ||
| const key = ServerConnection.Key.make(item.config.id) | ||
| const check = () => wsl.data?.opencodeChecks[item.config.distro] |
There was a problem hiding this comment.
The optional chaining expression wsl.data?.opencodeChecks[item.config.distro] will throw a TypeError if wsl.data is undefined (which is the case before the query resolves). In JavaScript, a?.b[c] is evaluated as (a?.b)[c], meaning it attempts to access the property on undefined.
Use optional chaining for the bracket notation as well to prevent runtime crashes.
| const check = () => wsl.data?.opencodeChecks[item.config.distro] | |
| const check = () => wsl.data?.opencodeChecks?.[item.config.distro] |
There was a problem hiding this comment.
Thanks Gemini. This file is unmodified from upstream (anomalyco/opencode); the pattern flagged predates this sync PR. Lash is a downstream fork — fixes to upstream code should land at https://github.com/anomalyco/opencode/ to avoid divergence that complicates future syncs. Tracking for upstream report.
| const selectedProbe = createMemo(() => { | ||
| const distro = selectedDistro() | ||
| if (!distro) return null | ||
| return current()?.distroProbes[distro] ?? null |
There was a problem hiding this comment.
The optional chaining expression current()?.distroProbes[distro] will throw a TypeError when current() is undefined (before the query resolves). In JavaScript, a?.b[c] is evaluated as (a?.b)[c], which results in accessing a property on undefined.
Use optional chaining for the bracket notation to prevent runtime crashes.
| return current()?.distroProbes[distro] ?? null | |
| return current()?.distroProbes?.[distro] ?? null |
There was a problem hiding this comment.
Thanks Gemini. This file is unmodified from upstream (anomalyco/opencode); the pattern flagged predates this sync PR. Lash is a downstream fork — fixes to upstream code should land at https://github.com/anomalyco/opencode/ to avoid divergence that complicates future syncs. Tracking for upstream report.
| const opencodeCheck = createMemo(() => { | ||
| const distro = selectedDistro() | ||
| if (!distro) return null | ||
| return current()?.opencodeChecks[distro] ?? null |
There was a problem hiding this comment.
The optional chaining expression current()?.opencodeChecks[distro] will throw a TypeError when current() is undefined (before the query resolves). In JavaScript, a?.b[c] is evaluated as (a?.b)[c], which results in accessing a property on undefined.
Use optional chaining for the bracket notation to prevent runtime crashes.
| return current()?.opencodeChecks[distro] ?? null | |
| return current()?.opencodeChecks?.[distro] ?? null |
There was a problem hiding this comment.
Thanks Gemini. This file is unmodified from upstream (anomalyco/opencode); the pattern flagged predates this sync PR. Lash is a downstream fork — fixes to upstream code should land at https://github.com/anomalyco/opencode/ to avoid divergence that complicates future syncs. Tracking for upstream report.
| toggle: async (directory: string, name: string) => { | ||
| const key = directoryKey(directory) | ||
| const sdk = sdkFor(key) | ||
| const status = children.child(key, { bootstrap: false })[0].mcp[name].status |
There was a problem hiding this comment.
Accessing children.child(key, { bootstrap: false })[0].mcp[name].status directly can throw a TypeError if the MCP server with the given name is not yet loaded or is missing from the store.
Safely access the status using optional chaining and handle the case where it might be undefined.
const status = children.child(key, { bootstrap: false })[0].mcp[name]?.status
if (!status) return
There was a problem hiding this comment.
Thanks Gemini. This file is unmodified from upstream (anomalyco/opencode); the pattern flagged predates this sync PR. Lash is a downstream fork — fixes to upstream code should land at https://github.com/anomalyco/opencode/ to avoid divergence that complicates future syncs. Tracking for upstream report.
| void sdk.client.v2.fs | ||
| .read({ path }) | ||
| .then((response) => response.data?.data) | ||
| .then((data) => data && addAttachments([serverAttachmentFile(path, data)])) |
There was a problem hiding this comment.
The promise chain for reading the file content from the remote server lacks error handling. If the network request fails or the server returns an error, it will result in an unhandled promise rejection.
Add a .catch block to handle errors gracefully and display a user-friendly toast notification.
void sdk.client.v2.fs
.read({ path })
.then((response) => response.data?.data)
.then((data) => data && addAttachments([serverAttachmentFile(path, data)]))
.catch((error) => {
showToast({
variant: "error",
title: language.t("common.requestFailed"),
description: error instanceof Error ? error.message : String(error),
})
})
There was a problem hiding this comment.
Thanks Gemini. This file is unmodified from upstream (anomalyco/opencode); the pattern flagged predates this sync PR. Lash is a downstream fork — fixes to upstream code should land at https://github.com/anomalyco/opencode/ to avoid divergence that complicates future syncs. Tracking for upstream report.
| console.log({ session: session() }) | ||
| const project = createMemo(() => projectForSession(session(), serverCtx()?.projects.list() ?? [])) |
There was a problem hiding this comment.
There is a leftover debug console.log statement in the TabNavItem component. This should be removed to keep the production console clean.
| console.log({ session: session() }) | |
| const project = createMemo(() => projectForSession(session(), serverCtx()?.projects.list() ?? [])) | |
| const project = createMemo(() => projectForSession(session(), serverCtx()?.projects.list() ?? [])) |
Rebased on top of dev after PR #26 (LAC-2281, 2026-06-01 sync) merged. Many original conflicts auto-resolved because dev already contained 256 of the 303 upstream commits. Remaining conflicts resolved per UPSTREAM_SYNC.md playbook with all lash invariants preserved: - agent_cycle = shift+tab in TUI keybind config - EventCwdUpdated in SDK event union (incl. GlobalEvent.payload) - getCwd()/setCwd() in shell-mode + prompt.ts cwd sentinel - Double-left-border row layout in prompt/index.tsx - ExecutionModeProvider + WorkingDirProvider wrap <App /> in app.tsx - tabs.tsx removeSessions navigate() hoisted out of produce callback (mirrors c04019d pattern for titlebar.tsx) Post-merge typecheck fixes included: - which() import path (filesystem services consolidation) - @/, @shell-mode, @tui-integration aliases in tui + cli tsconfigs (after upstream TUI extraction 106f8e9) - *.wasm module declaration - ModelID via ModelV2.ID after upstream provider/index.ts removal Refs: LAC-2337
cd25d03 to
a885a0a
Compare
|
Rebased on top of Force-pushed to Many of the original 11 conflicts auto-resolved because
Ready for review. |
Summary
Weekly upstream sync from
anomalyco/opencodedevthrough commit0050134d9e fix(session): merge per-call tool rules into session permission (#30529).f0b78f0a38).UPSTREAM_SYNC.mdplaybook.agent_cycle = shift+tab(TUI keybind config)EventCwdUpdatedin SDK Event + GlobalEvent unionsgetCwd()/setCwd()+ cwd sentinel in shell-mode +session/prompt.tsprompt/index.tsxExecutionModeProvider+WorkingDirProviderwrap<App />inapp.tsx106f8e94d6 refactor(tui): extract standalone package (#31193)):packages/opencode/src/cli/cmd/tui/*paths are now atpackages/tui/src/*. The playbook's invariants were applied at the new locations.cd25d03f50):which()import path moved →@opencode-ai/core/util/whichEventCwdUpdatedadded to theGlobalEventpayload union@/,@shell-mode,@tui-integrationpath aliases added topackages/tui/tsconfig.jsonandpackages/cli/tsconfig.json@silvia-odwyer/photon-nodeimportModelIDremoved upstream → switched toModelV2.ID.make()inprompt-variant.test.tsStacked on PR #26
This PR targets
LAC-2277/upstream-sync-2026-06-01(PR #26, prior weekly sync 2026-06-01 — 256 commits) which is still open. Once #26 merges, this branch will be rebased ontodevand the base updated.Verification
bun turbo typecheck— 23/23 packages successful (no errors)Links
Test plan
devbun turbo typecheckpost-rebase