Skip to content

... #47292

Closed as not planned
Closed as not planned

Description

@JIQ1314an

Bug Report: opencode web — project added via typed path stores raw input, then home session list silently shows 0 sessions

Environment

  • opencode: 1.18.27 (Windows, npm install, win32 native — not WSL)
  • Server: opencode web --port 4096 --hostname 0.0.0.0 started from the project directory
  • Client: Android mobile browser (also reproducible logic-wise on desktop) over LAN
  • Frontend bundle served by 1.18.27 (/assets/index-*.js)

Summary

Two related frontend defects in the web app's "open project" flow combine into a silent failure:
the project card renders normally (correct folder name) but the home session list shows
"Nothing here yet" forever, with no error anywhere.

  1. The directory picker stores the raw typed string as the project identity.
    When the user submits a path by pressing Enter/Go (instead of clicking a suggestion row),
    the raw input is normalized for slashes only — drive-letter / path casing is not resolved
    against the filesystem
    . On mobile, IME suggestions and composition input make it trivial
    to end up with e.g. D:\workSpace\opencode-tmp instead of D:\WorkSpace\opencode-tmp.

  2. Home session grouping is case-sensitive on Windows.
    Sessions are grouped/filtered by a path key that canonicalizes slashes but not case
    (pathKey() in packages/app/src/utils/path-key.ts). Windows paths are case-insensitive
    (NTFS), and the server API is already case-insensitive (verified below), so the frontend is
    the only layer that treats D:/workSpace/... ≠ D:/WorkSpace/.... The mismatched project
    therefore matches zero sessions and renders an empty list with no diagnostics.

Additionally, a usability trap that amplified confusion during debugging:
3. The suggestion list mixes the matched directory and its children (opencode-tmp/ and
opencode-tmp/_smoke/); on narrow screens rows are truncated to the same prefix and are
indistinguishable before tapping.


Reproduction (deterministic, no phone needed)

  1. Start opencode web on Windows from a project dir, e.g. D:\WorkSpace\opencode-tmp
    (not a git repo → project resolves to the "global" pseudo-project; sessions are keyed by
    the exact directory string D:/WorkSpace/opencode-tmp in the DB).
  2. Create a couple of sessions from the TUI.
  3. Open the web UI, "Add project", type the path with any casing difference
    (e.g. D:\workSpace\opencode-tmp) and confirm with Enter (do not click the suggestion row).
  4. The project card is added, titled opencode-tmp (looks completely normal).
  5. Home session list for that card: 0 sessions, no error. TUI sessions never appear.

On mobile the step-3 casing slip happens easily because IME composition/autocorrect
(also full-width punctuation like / \ ?) bypasses or mis-targets the suggestion rows;
submitting via the IME "Go/Enter" stores the raw string. Server logs confirm the wrong-case
directory reaching the server and an instance being created for it:

timestamp=... message="watcher backend" directory="D:\\workSpace\\opencode-tmp" platform=win32

Evidence that each layer behaves differently

Layer Input d:/workspace/opencode-tmp (any case/slash/trailing-slash variant) Result
Windows FS Test-Path D:\workSpace\opencode-tmp exists (case-insensitive)
Server GET /session?directory=... all variants incl. \, /, trailing \, lowercase returns all 3 sessions
Web frontend grouping pathKey(session.directory) ∈ projectDirectories.map(pathKey) 0 sessions for wrong-case project

Relevant code:

  • packages/app/src/utils/path-key.ts — pathKey() canonicalizes slashes only; no case folding
    for Windows drive paths.
  • packages/app/src/pages/home/home-controller.ts —
    projects().find((project) => project.worktree === selection().directory) (strict equality),
    and projects.open(s) stores { worktree: s } with the raw string and an exact-match
    duplicate check, so a wrong-case duplicate card can coexist with the correct one and both
    look identical in the UI.
  • Home session filter (bundle, _et): sessions.filter(r => projectDirectories.has(Ke(r.directory))).

Expected behavior

  • Submitting a typed path should resolve it against the filesystem and store the real,
    FS-canonical casing
    (like native OS file pickers do), regardless of Enter/Go vs suggestion click.
  • On Windows, project↔session matching should be case-insensitive (pathKey() should
    lowercase drive-letter paths, mirroring pickerRelativePath() which already does).
  • A full-width IME character (/\? etc.) in the picker input should be normalized to ASCII
    or rejected with a clear message; currently it degrades into a misleading
    "folder not found" or a silently-broken project entry.
  • Suggestion rows mixing the matched folder with its children should render the distinguishing
    suffix (or indent children) so they are not truncated to identical text on narrow screens.

Workaround for affected users

Remove the broken project card, then add the project by pasting the correctly-cased path
(copy from the PC) and clicking the app's suggestion row (never the IME's Enter/Go).
After that, sessions display normally (verified end-to-end with mobile emulation).

Notes

  • Server log also shows a MaxListenersExceededWarning (11 listeners on an EventTarget) when
    several clients/instances connect — likely listener leak in the event bus; separate issue.

Activity

  1. github-actions commented on Sep 4, 2026

    @github-actions
    Contributor

    This issue doesn't fully meet our contributing guidelines.

    What needs to be fixed:

    • The issue title is ... — a placeholder left unchanged from the template. Please update it to a concise, descriptive title that reflects the actual bug (e.g. the title in the issue body would work well).

    Please edit this issue to address the above within 2 hours, or it will be automatically closed.


    This issue might be a duplicate of existing issues. Please check:

    If you believe this was flagged incorrectly, please let a maintainer know.

  2. github-actions commented on Sep 4, 2026

    @github-actions
    Contributor

    This issue has been automatically closed because it was not updated to meet our contributing guidelines within the 2-hour window.

    Feel free to open a new issue that follows our issue templates.

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

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions