Repository navigation
Release v1.0.0 — OpenCode V2, on desktop and mobile - #1028
Draft
pascalandr wants to merge 250 commits into
Draft
pascalandr wants to merge 250 commits into
pascalandr wants to merge 250 commits into
Conversation
## Summary Follow-up to #836 and #838. An expanded interruption now takes priority over an enlarged composer without changing its saved height or draft. Collapse/settlement restores normal sizing. Keep the dock non-shrinking and bound the stack to Android visualViewport changes so response fields and actions remain reachable. ## Reproduction and scope Real InstanceShell at 851x393 with maximum composer height reduced the dock to 54px and its body to 11px, clipping the response and submit controls. The regression uses native Form events, mobile web/remote runtime and coarse-pointer Chromium emulation. The user's separate screenshot showed pre-836 navigation buttons: the installed bundle still contains those old labels. Merged PRs had not replaced that installed build. This follow-up fixes the independently reproduced current-code height issue; it does not claim deployment to the user's phone. ## Validation - 7 mobile shell tests: portrait, short viewport, landscape, immersive, saved maximum size, keyboard resize/pan, long Forms, background/global requests and permission actions. - 44 header/composer/interruption browser regressions and 1 isolated Electron zoom test pass. - UI TypeScript, production UI build and diff check pass; rendered captures inspected. ## Gatekeeper Independent review will be published and corrected in a loop until zero findings before the requested admin merge. ## Maintenance Existing large components touched: packages/ui/src/components/instance/instance-shell2.tsx (~1327 lines), prompt-input.tsx (~1081), session/session-view.tsx (~711).
## Summary I added a permanent **Restart OpenCode service** control under **Settings → OpenCode → Troubleshooting**, shared with startup recovery. It confirms interruption of active work across connected clients and does not delete session history. The existing post-update shortcut remains available. I enabled authenticated same-version restarts through the existing host/WSL lifecycle while retaining downgrade/unknown-version fences, mutation serialization and no automatic retry. Configuration reload remains a separate action that does not replace the daemon process. This is a troubleshooting tool, not a fix for the memory behavior reported in #833. ## Validation - Final commit `84b4c743e447a7bb68b81e2a276389f94d4dcbaf`: 23 service/reconnect tests and 29 real Solid/Chromium setup tests passed. - UI and server typechecks passed; production UI build passed. - Browser captures inspected, including French settings at 390px. - Native desktop packaging/live installed-application validation was not performed; no shared daemon was restarted. The ten touched `packages/ui/src/lib/i18n/messages/*/settings.ts` translation files remain approximately 692–706 lines. No unrelated refactor. Independent gatekeeper reviews are published below: pass 1 identified one P2 (superseded confirmation could lock the runtime controls); I fixed it and added a browser regression. Pass 2 reviewed the complete final diff and returned **zero actionable findings**.
## Summary Follow up the three full-CI failures reported after #845. A delayed session-activation callback could steal focus from an answer field and insert the answer into the composer. Recheck input/dock/modal ownership at execution and fence deactivation, disposal and superseded callbacks. ## Baseline evidence The focus race reproduces at baseline 0465499 and #845 head; deterministic new coverage fails against the old focus implementation. The other two failures also reproduce on both snapshots: the transcript fixture returned an empty body for permission-receipts, rendering error panels that changed row geometry. Fulfill that route with valid empty receipts; no assertion changes, added waits or forced clicks. ## Validation - 7 deterministic activation/selection tests pass; competing inputs, modal/dock ownership, stale callbacks, normal activation and phone behavior covered. - 46 transcript tests pass. - Header/mobile/dock: 57/58 initially; one cold fixture navigation timeout passed its isolated rerun. - UI TypeScript and production UI build pass. - Independent gatekeeper and full CI required before the requested admin merge. ## Maintenance Existing oversized file: packages/ui/src/components/session/session-view.tsx (~720 lines).
…nts (#847) ## User-requested behavior The user reported that seeing a question from an unrelated conversation was problematic and explicitly selected **conversation and subagents**. This change scopes the visible dock to the open conversation and recursive descendants, excluding parents, siblings and unrelated roots. ## Implementation - Shared hierarchy scope for dock and project badge; visible counts/navigation/composer compaction use only that scope. - Keep off-scope editors mounted, hidden and inert so answer and permission drafts survive navigation; remember selection per conversation. - Explicit project-badge navigation opens the actual owner. Sessionless global Forms use the no-session surface and remain reachable through the badge. - No unrelated fallback for stale focus intents; preserve native reply identity. ## Validation - 37 interruption dock/selection/mobile browser tests pass. - Real-shell badge regression passes; 2 additional desktop/mobile permission draft and owner-identity checks pass. - UI TypeScript, production UI build and diff check pass. - Independent gatekeeper in progress; full CI will be awaited before merge. ## Scope This implements the user's explicit conversation-scope preference. It does not claim to resolve the separately observed Android form disappearance after reconnect. No installed application was rebuilt/replaced. ## Maintenance Existing oversized component touched: packages/ui/src/components/instance/instance-shell2.tsx (~1344 lines).
…848) ## Approved UX The user found cross-conversation authorization useful after trying it, but could not clearly identify the source. They explicitly approved revising #847: keep in-place replies with compact external previews and prominent persistent provenance. ## Behavior - External conversations and sessionless project requests start compact; deliberate expansion opens their form without changing conversations. - Source name becomes the primary heading. Subagents show their parent context; View conversation explicitly navigates to the source. - One bounded external preview remains discoverable alongside a local request. Arrival does not replace the current draft; settlement leaves foreign fallbacks compact. - The red badge expands the selected request in place, including from the project Info view. Native reply identity, hidden drafts and short-keyboard footer access remain preserved. - Labels translated in all ten locales. ## Validation - 71 affected browser checks pass; six targeted Info-badge checks pass after reproducing/fixing the Info entry regression. - UI TypeScript, production UI build and diff checks pass. - Desktop/Android-touch compact, expanded, alongside-local and short-keyboard captures inspected. - Independent gatekeeper will be published and corrected until zero findings; user requested admin merge without waiting for CI. ## Scope and maintenance This implements the revised interaction preference, not a claimed fix for the separate Android reconnect disappearance. Installation remains separate. Existing oversized component touched: packages/ui/src/components/instance/instance-shell2.tsx (~1335 lines).
## Summary I stopped window resize events from overwriting the right panel's saved width. Minimizing can briefly report a tiny viewport and previously persisted the 200px minimum; restoring then retained that reduced width. The existing drawer layout still constrains the displayed width when space is limited. Explicit divider resizing still updates the saved preference. This is a shared UI change for Tauri and Electron, with no host-specific workaround. ## Validation I added browser regressions using the real Solid shell for transient 0/160/320px viewport measurements, ordinary viewport shrink/restore, overlay transitions, and subsequent divider resizing. Both new tests fail before the fix. I ran the UI typecheck, two drawer-layout unit tests, and 33 renderer checks across runs. One cold-navigation timeout passed on an isolated rerun. The existing Electron-only fixture was unavailable in this checkout and excluded from the Tauri-only validation. I built the Windows Tauri release executable (`tauri build --no-bundle`), passed packaged-resource checks, and launched/closed it with an isolated config. I did not replace the installed app, restart OpenCode, or repeat the native minimize reproduction after the user's confirmation. Native minimize/restore acceptance on the new binary is therefore not claimed; the regressions cover the real renderer's resize and persistence path. Independent gatekeeper review: zero actionable findings on `a0a02fc3398aaf1de35ac29e408336b909ce1650`, published in this PR. The existing `instance-shell2.tsx` remains approximately 1,335 lines; no unrelated refactor is included. Closes #849
## Summary I reduced two independently demonstrated sources of redundant work in the UI shared by Electron and Tauri: - I reuse the timeline projection when the outline snapshot, resident marker identities and translated labels have not changed, preserving reactive locale updates and structural marker changes. - I discard superseded or disposed Markdown invocations before parsing and before publishing results, including same-key language retries and cache hits. Related to #851, **not a confirmed fix for its Linux Electron freeze**. I have not reproduced the reporter's environment, and this PR intentionally does not close the issue. Native events, transcript authority and OpenCode service lifecycle are unchanged. ## Evidence and validation - Real native-dispatcher/SessionView fixture with 10k outline entries: 64 sub-bucket deltas trigger **64 full-history projections before / zero after**; changed text buckets, locale and final text still update. - Real Markdown/parser instrumentation: cold burst **33 parses before / one after**, warm burst **32 before / one after**. Disposal, same-key retries, cached results, theme/highlight, wrap and full-source copy are covered. - 100 browser regressions passed (70 renderer/parser/outline + 6 full-source-copy + 24 history-navigation/reasoning), plus 3 outline unit tests; UI typecheck passed. - Independent gatekeeper: **zero actionable findings**, with 60 browser and 6 unit tests passed independently. - Windows Tauri `build --no-bundle`, packaged-resource smoke and isolated launch/capture/close passed. I did not replace the installed app or restart OpenCode. No Electron desktop build/test was run; Chromium fixture tests do not establish Linux Electron host behavior. - The initial concurrent history/reasoning regression run hit a shared Vite cache `EPERM` on Windows and timed out; all 24 affected checks passed when rerun sequentially. The broad synthetic stream profile still shows pauses and does **not** demonstrate an overall responsiveness win. I recorded the measured work reductions and remaining limits in `dev-docs/STREAMING_RESPONSIVENESS.md`, with reproducible profiling scripts.
## Résumé Place les chevrons d’ouverture à gauche dans le panneau de questions/permissions, ses aperçus externes et les messages **System**. Pour une question provenant d’une autre conversation hors de la hiérarchie active, remplace l’icône de question bleue par un **blason rouge seul**, avec les couleurs et la forme du badge de statut partagé. ## Comportement - En-tête d’une question externe : **chevron → blason rouge → titre**. - Dock et aperçus : chevron vers le haut quand repliés ; dock vers le bas quand ouvert. - System : chevron vers la droite quand replié, vers le bas quand ouvert, suivi de l’icône Info. - Les demandes externes arrivent repliées et s’ouvrent par une action explicite. - Le blason dispose d’un libellé accessible et d’une infobulle localisés. ## Validation - Typecheck et build de production UI réussis. - Tests navigateur ciblés : **47/48 réussis** ; un timeout au chargement initial de la fixture avant les assertions. - Assertions sur l’ordre des éléments, le sens des chevrons, la portée du blason et la conservation des brouillons. - [Revue indépendante : zéro constat actionnable](#853 (review)).
Replay queued native events in bounded cooperative chunks so a delayed SDK window rotation cannot monopolize the renderer thread with repeated full-page hydration. Skip unchanged queued-ingress projection and publish one ordered dispatcher snapshot per chunk, preserving the existing pre-reduction compaction buffer. Keep event-specific callbacks as ordering barriers, including inbox cancellation and revert, and revalidate transcript identity and generations after publications and macrotask yields. Disposal, reconnect, overflow recovery and later rotations cannot publish stale continuations. The shared UI path applies to both desktop hosts without host-specific changes. Add real SDK/dispatcher regressions for queued hydration, unfinished replay at a timer boundary, FIFO arrivals, callback isolation boundaries and reset/overflow fencing. Update existing rotation tests to await final state. Targeted regressions and UI typechecking pass; the two full-suite failures also reproduce on the unchanged base. A Tauri guest reproduces the prior conditional stall; this does not claim attribution or resolution of every symptom in issue #851.
## Change I made transcript rotation replay cooperative and publish once per bounded chunk, instead of repeatedly hydrating the complete page for every queued event. I also skip unchanged projection while events are waiting. FIFO reduction, cancellation/revert barriers and generation fences remain intact; the existing compaction buffer is unchanged. ## Validation I ran the targeted SDK/dispatcher regressions and UI typecheck. The full UI suite passes 1,186/1,188 tests; both failures also reproduce on the unchanged base. Two new regressions fail before this change and pass afterward. I compared both versions in an isolated Tauri/WebView2 guest, with observation hooks disabled: the longest release task fell from 3,195 ms to 62 ms, and replay completion from 3,237 ms to 184 ms. Both retained all 120 new characters. The fixture preloads 200 SDK messages, retains a 4 MiB tool result and deliberately delays one sync; it does not establish incident attribution or physical keyboard latency. I also completed the Tauri resource build and packaged-resource checks. Independent review of `3b21c84566d2686f286139a98b11294f31389515` reports no actionable findings, with 66/66 expanded tests and UI typecheck passing. The installed app and shared daemon were not replaced or restarted. Related: #851
Replace transcript search DOM rewrites with document-scoped CSS Highlight registrations owned by each mounted message. Preserve selection, repaint committed asynchronous content, reveal active occurrences through nested scrollers and retain an overlap-safe Unicode mark fallback. Review findings were corrected and the integrated search/system regressions and typecheck pass. Production fixtures pass on Chromium, Electron and WebKit. Record reproducible raw measurements: reduced synchronous work, alongside Electron's worse paint-opportunity tail and three unrelated permission tests reproduced on the original base. Administrator merge explicitly requested by the maintainer.
…#856) Removes the four benchmark JSON exports, two screenshots, evaluation Markdown and AGENTS note introduced by #854: 31,419 text lines deleted. Runtime code and runnable tests are retained. Measurement summaries stay in #854's discussion. Validation: deletion-only diff, git diff --check, and no remaining references to the removed paths.
## Summary Cleanup following an inventory of 146 merged PRs from August 29 through October 6, 2026, with targeted inspection of oversized diffs, generated files, historical reports and current references. - Remove the palette gallery, 21 PR screenshots, ten historical reports/plans, the historical tail of the compatibility register, and the unused February SDK tarball/metadata under `temp/`. - Stop tracking five generated Tauri schemas; ignore their output directory and root `temp/`. Keep capability/permission sources, build logic and the vendored native fixes intact. - Remove exactly 16 unused Plugins translation keys in each of ten locales. Preserve the dynamically selected Global/Project labels and all active labels. - Repair links, index descriptions and the palette-test comment. Preserve current runtime qualification/ownership contracts, palette attribution and all executable regression tests. 58 files changed: **7 insertions, 11,723 deletions** (net **-11,716 lines**), including 22 binary removals. No new repository files or committed audit artifacts. ## Validation - UI typecheck: passed. - Production UI build through Tauri `dev:prep`: passed. - Palette quality: 40/40 passed. - Real-component browser Plugins regressions: 8/8 passed. - Clean Windows Tauri build with all five checked-in schemas absent: 188/188 tests passed, including actual generated ACL authority checks. - Warm build, delete generated schemas again, incremental rebuild: passed; generated JSON exists and remains ignored. - Exact baseline comparison: only the intended 16 translation entries removed per locale; retained compatibility body unchanged. - Retained tracked text: no references to deleted reports or removed translation keys. Synthetic Git-history fixture paths remain synthetic and do not read the deleted gallery. - Permission sources and runtime/build code unchanged; no added files; staged whitespace check passed. Validation was local on Windows, not a claim of completed Linux/macOS CI. Existing locale `settings.ts` files remain approximately 677-691 lines; this cleanup removes entries without unrelated restructuring.
## Summary Remove the hardcoded `base_version: 0.20.0` from the development release workflow. The reusable workflow already defaults to the package version at the exact dev SHA being built, currently `0.20.1`. One-line deletion; the date/SHA suffix, development npm channel and remote UI policy are unchanged. Future stable version bumps no longer require updating this workflow. ## Validation - Parsed both workflows with the existing YAML dependency and checked the default/fallback contract and retained source SHA/channel inputs. - Confirmed the source package version is `0.20.1`. - `git diff --check` passes. Existing prereleases are not renamed. No CI waiting or monitoring.
Resolve each @./ and @. mention directly in the shared prompt preparation helper. Previously every occurrence became a temporary root marker but only the first marker was restored, so later references could reach the model as ___ROOT___. Removing the sentinels also preserves literal marker text written by the user. Keep parent-path matching, attached-path handling and verbatim pasted content unchanged. Add regression checks for repeated references, pasted display metadata, message history, shell submission and slash-command arguments. The three new tests fail on the unchanged helper and pass with this fix; all 21 targeted tests and UI typechecking pass.
I removed the temporary root markers from prompt preparation. Each `@./` or `@.` reference now resolves directly, so repeated references no longer send `___ROOT___` to the model. I added regression tests for repeated references, literal marker text, pasted content and display metadata, shell input and command arguments. All three new tests fail before the fix; all 21 targeted tests and UI typechecking pass afterward. I also built the Tauri resources and passed the packaged-resource checks. I did not replace the installed app or restart the shared daemon. Fixes #863
…2.0.24 (#865) ## Summary - Qualify and pin the generated client/plugin at OpenCode **2.0.24**, recommended independently of the unchanged **2.0.7** technical minimum. - **On every runtime version**, automatic Form/permission recovery uses only the authenticated loaded-only broker. Missing capacity stops recovery non-authoritatively; it never falls back to ordinary lists across historical/inactive worktrees. - Retain known requests and editor drafts through unavailable/partial recovery and rehydration, and show a localized recovery-incomplete status even when no request is known. Only explicit settlement reconciliation may use ordinary lists at the attempted request's authorized location. Keep mutation fences and settlement tombstones. - **Remove the private reader's runtime and Effect version allowlist.** An untested/custom/prerelease/missing version label no longer disables recovery. Registration checks the real native RPC capability; each read validates graph, existing-only lease, queue, codec and identity contracts. These checks fail safely without mass-loading fallback. Tested versions remain evidence, not grounds for blocking other versions. ## Contract audit The authenticated isolated 2.0.24 daemon exposes 117 native OpenAPI paths vs 116 on 2.0.22. The new `/api/vcs/init` is not exposed by CodeNomad. Of 167 structural schema changes, most add declared `LocationNotFoundError` failures to location-sensitive routes; other changes add optional `ServerInfo.capabilities.persistentPty`, WorktreeError's literal `_tag` and the VCS-init error. Published declaration changes: 11/30 client files (+service-probe), 3/60 plugin, 8/36 protocol and 3/102 schema files (three retired IDE/question declarations removed). No removed declaration is imported by CodeNomad; no consumed dependency establishes a higher minimum. The upstream source audit leaves LocationServiceMap, Form, Permission and RPC contracts unchanged; the Location-services wrapper changes only its TypeScript error parameter. Effect remains rc.112. The published native implementation chunks are hash-checked against separate receipts before each isolated fixture run. Native SDK service contender/probe/PTY handoff internals change, but CodeNomad retains its selected-CLI lifecycle adapter and bounded authenticated registration fallback rather than using `Service.ensure/stop`. **No shared daemon restart, storage mutation or OpenCode PR is part of this change.** The source audit also covers compaction-agent model/budget selection, ChatGPT's temporary remote-model synchronization removal, local-provider discovery/cache sharing, text-capable default selection, bounded MCP connection/catalog retries and OAuth callback timing, Windows instruction ancestry, skill frontmatter, subagent text boundaries and PTY runtime storage/availability. These remain native-owned; no CodeNomad adapter change is justified by the consumed contracts. `dev-docs/OPENCODE_V2_COMPATIBILITY.md` records the consequences and limits: synthetic account tests are not real OAuth/provider certification, compaction isolation does not exhaust alternate summarizer configurations, and no desktop terminal-survival test across service restart is claimed. ## Native loaded-only evidence ### Follow-up: unjustified version lock removed At the user's explicit direction, remove both `PENDING_SNAPSHOT_NATIVE_VERSIONS` and the Effect-version equality check, as well as all version checks in registration and reader execution. The reader no longer accepts or consults an executing-version argument. Regression coverage registers across 2.0.7–2.0.24, newer/custom/prerelease/missing labels and a context whose `app` getter throws if accessed. Actual malformed/missing contracts, unsafe data, eviction/disposal races and timeouts remain non-authoritative. The rule against blocking untested versions is recorded in `AGENTS.md`. The source comparison across published tags 2.0.7–2.0.24 finds an unchanged LocationServiceMap and existing-only lookup, RPC contracts and queue-list interfaces. Changes in older releases affect Form cancellation feedback/state and permission rejection feedback, not queue listing. All these tags use Effect rc.112. This is source evidence, not a claim that all eighteen releases have passed native fixtures. After gate removal, **29/29 reader/broker/admission tests pass**, as do server typecheck and pruning build. Fresh published native fixtures on **2.0.23 and 2.0.24 pass**, recovering permissions/global Forms with 100 cold candidates (three actual Git worktrees), four native boots before/after and zero cold constructions. The fresh bounded **full-server run on the follow-up passes: 888 passed, 0 failed, 6 skipped (894 tests, 76 suites)**. Receipts: `no-gate-server.log`, `no-gate-native-23/receipt.json`, `no-gate-native-24/receipt.json`, `matrix-source-inventory.json`, `server-all-no-gate-final.log`. The follow-up also records the distinction between pinned build dependencies and an independently updated external service in `AGENTS.md`; no README changes. Independent read-only gatekeeper review of the **full diff** `1abeba78043fc6ec1fac4eb57eb6c82a541cf66e..e159068`: **APPROVE, 0 findings**, 59 independent targeted tests passed plus an isolated reactive check. The review is published separately on this PR; it is an agent review, not human approval or deployment acceptance. At the pre-merge CI inspection, runtime contracts (minimum/latest), OpenCode compatibility (Linux/Windows/macOS) and native pruning (Linux/macOS) passed; general tests, native pruning on Windows and Tauri tests were still in progress. Earlier cancelled/skipped runs are not passes. The user explicitly requested an admin merge after zero gatekeeper findings; no all-green CI claim is made. The committed Bun fixture now uses the same managed `.ts` plugin discovery shape as production, not configured-package directory resolution. It uses an authenticated unmodified published HTTP router in-process, with an in-memory database, private discovery paths, no listener/service discovery and no external provider. | Published runtime | Preloaded Locations | Locations after recovery | Native boot logs before/after | Cold candidates | Cold constructed | |---|---:|---:|---:|---:|---:| | 2.0.22 | 4 | 4 | 4 / 4 | 100 (three actual Git worktrees) | 0 | | 2.0.24 | 4 | 4 | 4 / 4 | 100 (three actual Git worktrees) | 0 | Both runs recover three permissions, six Forms including three global Forms. They exercise absent/present backend presence, two backends retaining registration, expiry, return and final disposal, coexistence with the existing Promise pruning RPC, authenticated 401 rejection, schema limits and non-authoritative failures. The boot-log assertion also detects briefly constructed Locations even if they later disappear from the map. Short-fixture RSS: 2.0.24 460,599,296 → 461,824,000 bytes; 2.0.22 463,929,344 → 461,701,120 bytes. These are receipts, **not a memory profile or comparable deployment soak**, and do not attribute the reported 10 GiB to this fallback. ## Validation Environment: Windows, Node **25.2.1**, Bun **1.3.14**. All native checks use owned processes, synthetic providers/configuration/data and explicit isolated CLI paths; never the shared daemon or user database. - `bun scripts/test-pending-snapshot-native.mjs <qualified-packages> <fresh-output>`: passes separately on published 2.0.22 and 2.0.24. - 2.0.24 native automation, pruning parent runner, Location/worktree/proxy/event relay, environment, fork, aside, degraded Git, prompt skills, provider usage/accounts, permission receipts and blank-session cleanup: **12 suites pass**. - Minimum 2.0.7 with the same 2.0.24 client/plugin dependencies: **nine isolated suites pass** (automation, pruning, Location/worktree/proxy/relay, environment, fork, aside, degraded Git, prompt skills and blank-session cleanup). Operation-specific usage/account/receipt checks do not establish a new global minimum. - `test-compaction-isolation-native.mjs <2.0.24-cli> --context-mib 2`: passes with native compaction and outline enabled; the second session completes before releasing the first session's provider gate. - Focused UI pending recovery, compaction, Forms and permission lifecycle: **37/37 pass**. Coverage includes 100 cold worktrees on unsupported capability, reconnection, request retention, per-kind mutation fences, settlement reconciliation, late supported/unsupported responses and compaction admission. - Final browser dock/selection/mobile regressions: **44/44 pass**. The incomplete status appears with no known request at 393 px, has no horizontal overflow, preserves a typed answer on repeated unavailable recovery and disappears only after full recovery. Real-shell provenance, recursive interruptions, Android keyboards and per-conversation drafts remain covered. - Server/UI typechecks and shared server/UI/plugin builds: pass. - Final full server unit run after dependency reinstall, `node --import tsx --test --test-concurrency=2 'packages/server/src/**/*.test.ts'`: **888 pass, 0 fail, 6 skipped** (894 tests, 76 suites). An earlier unbounded parallel run exceeded the existing 30-second pending-broker deadline; the bounded rerun passes without changing that deadline. - Broad UI unit tests: **1189 pass, 2 fail**. Both failures are reproduced from unmodified base `1abeba78` sources in an extracted tree: `classic-dark-surfaces.test.ts` expects a removed accent-hover override; `tool-content.test.ts` expects copy text where the renderer returns none. These paths use OpenCode types only, no runtime client import. This suite is **not green**; unrelated UI corrections are intentionally not included. - `git diff --check`: pass. Lockfile retains unrelated package versions/integrities; npm peer metadata recalculation remains. - Lockfile reproducibility: `npm ci --ignore-scripts --no-audit --no-fund` passes after browser fixtures release the Windows esbuild executable. An earlier attempt during those fixtures encountered `EPERM`; a simultaneously launched server rerun was invalidated by dependency removal and is not counted as product evidence. Detailed local receipts/logs are retained under `C:\Users\Admin\AppData\Local\Temp\opencode\q224`: `pending-native-final/receipt.json`, `pending-native-22/receipt.json`, `schema-audit.log`, `*-declarations.diff`, `server-all-bounded-final.log`, `ui-pending-final.log`, `ui-all-final.log`, `ui-unrelated-baseline.log`, `browser-interruption-final.log`, native-suite logs and `compaction-2mib-final.log`. ## Deployment acceptance and limits Not deployed to the active user service. After authorized deployment, compare passive-recovery Location boot/eviction counts and process RSS/private memory over a comparable observation window, separating explicit user actions. Accumulated pre-fix Locations are not automatically evicted. Only an explicitly confirmed shared-service restart may release them. The separate Usage-flicker work is not a substitute for this fix. Unknown requests cannot be exhaustively recovered on a daemon without the capability; known requests and live events remain usable. Existing bootstrap warming, bounded coverage, compaction admission and ownership constraints remain documented in `dev-docs/OPENCODE_V2_COMPATIBILITY.md`. File-size signal: `packages/ui/src/stores/instances.ts` remains approximately 2,300 lines; no threshold-only refactor is included.
#862) ## What changes I add independently distributed right-panel UI extensions and an official online catalogue in Customize right panel. Users browse/search available addons, choose one and confirm installation directly from its exact GitHub Release, without a manual ZIP download, rebuilding CodeNomad or restarting OpenCode. Manual ZIP installation remains available. I publish the curated index, contribution rules and Session info demo at https://github.com/NeuralNomadsAI/CodeNomad-Extensions. That repository can host several official addons; the index can also reference author-owned repositories. Separate means independent of the main application repository, not a mandatory repository per addon. I show the manifest and exact archive SHA-256 before trust confirmation. Installation starts disabled; users enable it for all projects in the server profile or for the exact opened folder. Replacement requires the previous digest and revokes every activation grant. Removal is explicit. Packages and grants stay outside project/OpenCode storage. I keep author code out of the main renderer. API 1 exposes only session ID, locale and appearance through a per-mount MessageChannel. It does not expose filesystem, transcript, images, credentials, native commands or the OpenCode proxy. Frames are sandboxed without same-origin access and receive a restrictive CSP; obsolete responses and ports are fenced on project/session changes, disconnects, revocation and replacement. I document the package, permissions, API compatibility, scope, release/checksum and maintainer rules in `dev-docs/PANEL_EXTENSIONS.md`, with a standalone starter in `examples/panel-extension/`. GitHub's source ZIP is not an installable package. There is no arbitrary URL installer or automatic update. I load catalogue metadata only during discovery. Inspection and installation each revalidate a fresh index, exact ZIP digest and full manifest; unsupported APIs/permissions cannot install. Downloads are bounded, deadline-limited, credential-free HTTPS requests to GitHub's exact release hosts, with constrained redirects. A withdrawn or changed selection cannot become a different trusted package. Offline catalogue failures leave installed addons and ZIP installation available. ## Scope and limits I keep #801's assets gallery for a separate follow-up. It needs a bounded, authorized image/history capability rather than access to internal stores. This PR only establishes external distribution and a minimal context API. Windows Tauri may inject native bridge objects into subframes: object presence is not a grant. My isolated WebView2 fixture proves parent command execution while direct/raw child calls do not reach it, and verifies context delivery plus DOM/network restrictions. A trusted hostile extension can still stall its renderer or attempt self-navigation; this is not process isolation or a universal offline guarantee. The installer warns users to trust the author. I have not run a native Electron/macOS/Linux qualification or changed the shared daemon. The runtime implementation is shared between desktop hosts; native GUI validation here is Tauri only. ## Validation - UI and server typechecks. - 14 focused server/registry/manifest tests. - Real right-panel browser tests for ZIP consent, activation scopes, replacement, revocation, context changes, stale reads and frame isolation. - Five catalogue/server checks and seven right-panel browser scenarios cover metadata-only browse/search, online consent, withdrawal, incompatibility, offline ZIP fallback, hashes/manifests, redirect restrictions and size budgets. - Live public GitHub index and Release download matched SHA-256 `cf80226a40dd077a6a8cc2a4b65bbb46bf33619d62007982bd7dcea34ae4545f`; installation and activation used a disposable isolated store. - `node scripts/test-panel-extension-native.mjs` on Windows, using the application's locked Tauri dependencies and an isolated browser profile: parent native call allowed; child native calls, parent DOM and network APIs blocked; session context delivered. - UI build, Windows Tauri release build (`--no-bundle`) and packaged-resource smoke passed. Full browser suite results are recorded in the follow-up validation comment. Existing oversized files touched only for integration: `packages/server/src/api-types.ts` (~735 lines), `packages/server/src/index.ts` (~713), `packages/server/src/server/http-server.ts` (~2,438).
I restore right-panel customization to one compact Extensions action and move catalogue, ZIP installation, activation and trust/removal confirmations into a separate non-modal utility window. Lists stay single-line, metadata is available on hover and keyboard focus, toolbar actions remain reachable at narrow translated widths, and disposal fences late results.\n\nI remove speculative per-folder activation from the UI, client contract and backend. Each installed addon has one general activation control per CodeNomad profile. Existing packages and general grants survive; legacy folder-only consent is never broadened, and obsolete grants are removed only during an explicit successful mutation. Trust, digest-bound replacement/removal and owned-instance executable-panel reads remain enforced.\n\nI publish independent gatekeeper iterations until zero findings on the exact final head. Both typechecks, nine server tests and thirteen real-component extension/Status tests pass, including migration and French/Hebrew/Japanese/Spanish narrow layouts. Windows Tauri/WebView2 command denial passes. I use the requested admin override with the documented CI caveat: four unrelated browser failures also occurred in the final pre-correction run. The installed desktop and shared OpenCode daemon are unchanged.
## Requested change Restore the normal question/permission icon for requests from unrelated conversations. Show the complete shared red status badge, including its localized text, separately at the trailing end of the collapsed bar. Clicking the badge expands the selected request. ## Layout Retain leading disclosure chevrons and source titles. Crowded mobile headers wrap trailing controls instead of squeezing away the conversation name. Reuse existing badge geometry, colors and translations. ## Validation - Initial dock/mobile run: 36 passes, one cold fixture navigation timeout. - All six final targeted checks pass, including the previously timed-out recovery case; fixture initial navigation now has the same 60-second budget as the real-shell fixture. Assertions preserved. - Final UI TypeScript, production UI build and diff checks pass. - Desktop/mobile compact question and permission captures inspected. - Independent gatekeeper reviewed final diff/captures: ZERO FINDINGS. Review will be published before the requested admin merge without waiting for CI. Installation is separate; no running application or native daemon was restarted.
I put Extensions below a separator in the customization popup, collapsed by default. I combine installed addons and the catalogue in one compact searchable list and remove the separate modes and floating window. I make the existing addon checkbox the only profile-wide activation control. Disabled installed addons stay listed; reset never grants consent. Explicit trust, digest-bound replacement/removal, offline ZIP installation and sandbox protections remain intact. I pass the UI typecheck, 9 server tests and 14 real-component extension/Status browser tests, including narrow translated/RTL layouts and real ZIP gestures. I inspect the interactive preview validated by the user. Windows Tauri release qualification and the final independent gatekeeper review are in progress; I do not replace the installed app or stop the shared daemon.
Project the existing bell/history unread count onto browser tab favicons and the native dock or taskbar in both Electron and Tauri. Reading, deleting or clearing notifications updates the badge without querying sessions or adding polling; the original favicon returns when no unread items remain. Aggregate per-window counts in the native hosts, accept bounded count-only calls from owned local and remote primary renderers, and keep preferences windows and preview guests outside the capability. Navigation and closure remove only that window's contribution, with document-generation and main-frame checks fencing stale updates. Windows overlays are generated by the host; other platforms use available native count APIs. Add real Chromium regressions for notification lifecycle, icon pixels and restoration, unavailable native support and late image completion, alongside focused Electron bridge/security and Tauri state/ACL tests. UI/Electron typechecks, 15 focused Electron Node tests, four Tauri tests and Windows Tauri resource prebuild/smoke checks pass; no installed app or shared daemon was restarted.
Serialize the shared renderer-to-host badge calls so asynchronous Tauri dispatch cannot publish an older unread count after a newer clear. Final cleanup stays in the same FIFO, while rejected native calls do not prevent subsequent updates. Add a Chromium regression with deliberately held native promises to check send order through a rejected call, rapid add/clear, and disposal. All six browser badge tests and the UI typecheck pass; Tauri resource prebuild and packaged smoke checks also pass with the ordered adapter.
Make the history search window and command palette movable from their existing top bars with native mouse and touch pointers. Share placement, pointer cleanup and viewport bounds in DismissibleWindow while leaving inputs, selectors and close buttons interactive and retaining non-modal dismissal and session authority. Portal the movable inline search without losing its initial transcript anchor. Align utility stacking with opening order, revalidate placement as content grows, and bound height to the visual viewport. Native overflow and a sticky existing toolbar keep the last result, pagination and drag/close controls reachable in landscape and at pinch zoom; preserve the palette's 60vh limit and horizontal edge access when zoomed. Extend the real-component browser regressions with drag, touch, RTL, viewport shrink, content growth, asymmetric drawers, overlap, zoom/pan and pagination. All 62 targeted browser scenarios, UI typecheck and production build pass. Five independent Gatekeeper passes corrected eight findings and the final review reports zero actionable findings on bb13b96. Merge with the requested administrator override. Native CI jobs pass; the full browser suite has 489 passes, three pre-existing permission-fallback-diff failures and two skips. Read-only base/head reproduction confirms those unchanged tests wait for Copy patch in an intentionally collapsed external request without expanding it. Do not change permission semantics or hide these unrelated failures.
Observe primary WebView2 renderer/browser exits and WebKitGTK web-process termination without polling, new dependencies or guest capabilities. Factory enrollment happens before native build, so first loads do not depend on registration timing. Physical-window identities fence retired page, failure and close callbacks; failure revokes count admission until a new page starts. Native subscriptions capture only a weak host rooted outside managed application state, avoiding controller/handler/AppHandle ownership cycles. Windows ignores frame, GPU, utility and unresponsive-process events. Update the existing narrow remote-capability regression to include the badge-only command. Document the macOS limitation: pinned Tauri does not forward Wry's Darwin builder termination hook, so a surviving-window crash may retain its count until reload/navigation/close. Do not replace the runtime-owned WKWebView delegate or invent process monitoring. All 195 Windows Rust tests pass serially; Linux API review is not presented as compile/runtime qualification.
## Summary Mirror the existing bell/history unread notifications on the browser tab favicon and native desktop dock/taskbar, as clarified in #868. This includes all existing notification kinds, including update notices; session idle/attention status does not introduce a separate counter. - Use a small red dot on the tab favicon and restore the original icon when the unread count reaches zero. - Forward count-only updates through the shared native adapter for both Electron and Tauri. Native hosts aggregate live primary-window contributions so clearing one window does not clear another's unread notifications. - Keep native badge authorization restricted to owned local/remote application renderers, not preferences windows or preview guests, and remove contributions on reload/navigation and window closure. Electron handles renderer crashes; Tauri uses native termination signals on Windows/Linux, with physical-window fences and weak native handler ownership. - Reuse history add/read/read-all/delete/clear updates without scanning sessions or polling. History remains per-window and in-memory, as before. Browser tabs are covered, not installed-PWA launcher icons. Native dock/taskbar availability depends on the operating system and desktop environment. **Tauri/macOS limitation:** the pinned public Tauri API does not forward Wry's Darwin web-content termination hook. A surviving-window renderer crash may retain its last count until reload/navigation/close. This does not replace or swizzle the runtime's WKWebView delegate or add process polling; normal macOS badge updates remain supported. See `packages/tauri-app/NOTIFICATION_BADGES.md` for the API evidence. ## Validation - Six real Chromium regressions cover unread lifecycle, generated badge pixels, icon restoration, the 50-item history cap, Electron/Tauri adapter dispatch, unavailable native support, disposal before image load and FIFO native updates through failures/cleanup. - UI and Electron typechecks passed. - Fifteen focused Electron Node tests and all 195 Windows Tauri Rust tests passed without launching either application. The Rust suite runs serially (`--test-threads=1`); an initial parallel run had three native-service fixture failures that pass serially. - Windows Tauri resource prebuild/smoke checks passed. No native visual/runtime qualification or Linux/macOS validation is claimed. - The Linux termination hook was reviewed against the installed API, but was not compiled or runtime-tested on this Windows host. - Broad Electron Node suite: 208 passed; two failures outside the badge tests (missing local Electron installation and a Windows process-termination assertion). The broad suite is not claimed green. Fixes #868
Do not mount a permission-receipt request for the internal no-session draft sentinel. Reject malformed session IDs at the receipt API boundary with a 400 instead of forwarding them to the native client where they raise a 500. Cover the draft-to-session transition and reconnect in the browser fixture, and exercise malformed IDs alongside valid pagination and ownership checks on the server. Targeted browser/server tests and both TypeScript typechecks pass.
Closes #876. The no-session draft sentinel is only a local draft identity; it must never enter the permission-receipt API. Skip the read while that draft is selected and reject invalid session IDs as HTTP 400 at the API boundary rather than forwarding them to OpenCode as HTTP 500. Valid session pagination and ownership checks remain unchanged. Validation: 12/12 server permission-receipt tests; 9/9 targeted browser tests; UI and server TypeScript typechecks.
Treat idle historical session directories as optional recovery hints while keeping roots, registered worktrees, active sessions and known request placements required. Exclude only paths rejected by ownership, retaining real loaded-only RPC negotiation and non-authoritative failure behavior. Replace the recurring interruption banner with the existing once-per-episode notification.\n\nIndependent gatekeeper reviewed the complete change and the updated dev merge tree with zero findings; the verdict is published as agent review comments. Targeted broker, UI and browser suites, typechecks and server build passed; other CI jobs were still running at admin merge.
## Behavior - Selected skills appear once in the existing composer attachment bar alongside files. Removing a skill preserves the draft and other attachments. - Sent and historical user messages display their attached skill names, including messages containing only a skill. Labels survive native history reloads. - Long skill names wrap within the message width instead of being clipped on narrow desktop, touch and RTL transcripts. ## Implementation The shared message content filter now admits normalized skill parts into the existing badge renderer. The redundant composer skill row and its styles are removed. ## Validation - The browser fixture exercises native message loading, normalization, the store and the full transcript rather than an isolated badge. It covers mixed attachments, deduplication, removal, sending, skill-only history and reloads. - The history-label regression fails on the original content filter. - All three narrow long-name regressions fail before the wrapping fix and pass afterward, measuring message, badge and text bounds. - Final head `b2a31f339c6879f1fd76d32c55db9375669547cf`: focused browser/skill checks: 16 passed. Session-action regressions: 53 passed. UI typecheck and build passed; narrow rendered captures inspected. Existing large files touched: `packages/ui/src/components/message-block.tsx` (~1,889 lines), `packages/ui/src/components/prompt-input.tsx` (~1,078 lines).
… on quit (#1091) ## Problem Quitting the Linux **Tauri AppImage** can show Ubuntu's "Sorry, Ubuntu 24.04 has experienced an internal error" dialog. apport records a `WebKitWebProcess` crash with **SIGBUS**. The AppImage runtime unmounts the bundle as soon as the main process exits. WebKit's helper processes, started from that mount, can still be running for a moment: their next page fault in the vanished mount raises SIGBUS. - Ubuntu 24.04 VM, `1.0.0-dev-20261022-1840c710` AppImage: 2 crashes in 3 quits. - The same build extracted with `--appimage-extract` (no mount) never crashed. - Stable releases shipped Tauri Linux as a `.deb`, so the problem comes with the AppImage distribution. ## Fix On `RunEvent::Exit`, which covers ordinary quits and updater restarts, an AppImage launch (`APPIMAGE` + `APPDIR` set) stops its direct child processes whose executable lies under the mount, before the process exits. The WebKit helpers are direct children of the main process. The new module is `appimage_exit.rs`: - each child is pinned with a **pidfd**, then checked again as a child of this process running from the mount, so a process that reused a PID is never signalled; - `SIGTERM`, then pidfd polling up to 1.5 s, then `SIGKILL` and a final 0.5 s; - children running from elsewhere (the shared OpenCode service) keep running; - `.deb`/Electron, Windows and macOS are unchanged; kernels without `pidfd_open` keep the previous behaviour. `dev-docs/TAURI_UPDATER.md` documents the exit contract and its validation. ## Validation - **Linux unit tests** (new): `/proc/<pid>/stat` parsing with command names containing spaces and parentheses, and a real child started from a temporary "mount" that is stopped while a child started elsewhere keeps running. They pass on Ubuntu 24.04. - **Real AppImages** on the Ubuntu 24.04 VM, repacked with appimagetool around the released AppDir, once with the original binary and once with the fixed one: | Trial | Original binary | Fixed binary | |---|---|---| | Secondary `WebKitWebProcess` frozen (`SIGSTOP`) before closing the window | survives the main process, i.e. outlives the mount | stopped before the main process exits | | Normal quit | 0.06 s, no leftover | 0.08 s, no leftover, no crash report | The shared OpenCode service kept running throughout. - `cargo check -p codenomad-tauri` passes on Windows. - Running the whole crate suite on the VM, only the cross-host election tests (they need the full checkout with `tsx`) and the zsh test (zsh not installed) failed. Linux CI has both.
…lerators (#1092) ## Problem On Linux the **Tauri** app showed a GTK menu bar ("File Edit View Window Help", in English until the renderer reported its labels) above the application's own title-bar menus, so every window had two menu rows. Windows and Linux present menus in the title bar, and the host already called `hide_menu()` on non-macOS platforms, but on Linux the hide never stuck. Windows are created invisible, hidden, then shown, and Tao shows a window with GTK's `show_all()`, which shows every child widget again, including the menu bar. ## Fix `menu_bar::hide` (new `menu_bar.rs`) replaces the four scattered `hide_menu()` calls: local windows, Preferences, fullscreen restore and fullscreen toggle. - **Windows**: same `hide_menu()` as before. - **macOS**: nothing, since its menu bar is global. - **Linux**: on the main thread, where GTK widgets live, the GTK menu bar is also marked **no-show-all**, so `show_all()` leaves it hidden. - GTK only activates the accelerators of on-screen widgets. A merely hidden bar would therefore have disabled native accelerators such as `Mod+Shift+N` (New Window) that the visible bar provided, and that `docs/help` documents. The bar answers `can-activate-accel` with `true`, connected once per bar. `gtk` becomes a direct Linux dependency, already locked at 0.18.2 through Tauri. `dev-docs/UI_SHELL.md` documents the hidden native bar; the public help stays accurate. ## Validation Ubuntu 24.04 VM, AppImages repacked around the released AppDir: | Build | GTK menu bar | Ctrl+Shift+N | |---|---|---| | Original binary | shown above the title-bar menus | opens a new window | | Hide + no-show-all only (intermediate) | gone | falls through to the renderer's New session ✗ | | **This PR** | gone in the main, second and Preferences windows | opens a new window ✓ | Quitting leaves no helper process or crash report. `cargo check -p codenomad-tauri` passes on Windows, and the Linux release build compiles the GTK calls.
…lder command (#1093) ## Problem On an Ubuntu 24.04 VM, OpenCode 1.17.18 was installed by curl in `~/.opencode/bin` and also linked as `~/.local/bin/opencode`. With that setup, the OpenCode panel offered **no installation**, only the generic "Select a supported executable or install @opencode/cli on the execution host" advice. On macOS/Linux the user npm prefix is `~/.local`, so that link occupies OpenCode's command name exactly where OpenCode 2 would be installed beside the older version. npm refuses to link over it, and CodeNomad never modifies a foreign installation. The plan therefore correctly had no prefix, but nothing told the user why. ## Fix `sharedInstallationPlan` reports the obstacle on the foreign installation, forwarded as `foreignInstallation.blocked`: | `reason` | `path` | When | |---|---|---| | `occupied` | the occupying command | a non-npm command holds OpenCode's name in the user npm bin directory | | `unwritable` | the user npm prefix | the prefix, or a recognized npm installation in it (an `@opencode/cli` launcher, a Windows npm shim or an `opencode-ai` 1.x installation), cannot be written | The installation notice then says how to clear it: move or rename that command, or fix the folder's permissions, then choose **Check status and updates**. The usual curl layout, on PATH only through `~/.opencode/bin`, still offers **Install OpenCode 2 for CodeNomad**. This was verified on the same VM, where the installation then succeeded. The English messages and their nine translations, the `opencode.md` help page in all ten locales and `dev-docs/OPENCODE_RUNTIME_SETUP.md` describe the obstacle. ## Tests - `legacy-installation.test.ts`: builds the exact VM layout (link in the user npm bin directory) and checks that the plan never offers a prefix over the foreign command and reports `occupied`. The ordinary layout must still offer the prefix, and a read-only prefix must report `unwritable` (POSIX, non-root). - `opencode-setup.test.ts`: renders the occupied notice with no install action. - A second POSIX regression puts a verified npm OpenCode 1.x installation in a read-only user prefix and expects `unwritable`, never `occupied`. - Results: - the `opencode-update` unit tests: 51/51 on Windows (1 POSIX-only skipped); on the Ubuntu VM as uid 1000, 48 passed, 0 failed, 4 Windows-only skipped, including both POSIX cases; - the `opencode-setup` browser tests: 34/34; - the server and UI typechecks; - `npm run test:help`.
…oute (#1094) ## Problem The **macOS quarantine** troubleshooting section said that macOS "can report that the application is damaged". On a macOS 15.8 Intel VM, the `1.0.0-dev-20261022` Tauri and Electron apps behave differently once downloaded with a quarantine attribute: - both are rejected at first launch with **"CodeNomad" Not Opened**: Apple could not verify "CodeNomad" is free of malware… The only choices are Done or Move to Trash; - `spctl` rejects both bundles: Electron is only ad-hoc signed, Tauri is unsigned, and neither is notarized. The section also limited the **System Settings → Privacy & Security** step to Intel Macs and did not name the actual action. ## Change Ten locales, `docs/help/<locale>/troubleshooting.md`, with headings unchanged: - The introduction states that the macOS releases are not notarized. A downloaded copy is therefore blocked at first launch with **"CodeNomad" Not Opened**, or reported as damaged. - Step 3: for the **Not Opened** message, **Open Anyway** for CodeNomad in **System Settings → Privacy & Security**, confirmed with an administrator password, is an alternative to `xattr`. The Intel-only wording is gone. - macOS labels stay in English in every locale, as in the existing translations. ## Verification - On the VM, after a blocked launch, Privacy & Security showed **"CodeNomad" was blocked to protect your Mac.** with **Open Anyway**. I did not click it, since it needs the user's password. - The documented `xattr -dr com.apple.quarantine /Applications/CodeNomad.app` let both apps start. - `npm run test:help`: 9/9.
… composer (#1095) Agent message headers showed raw identifiers (build • claude-code/claude-opus-5-5[1m]:fast • xhigh) while the composer footer names the same choice Build, Opus 5.5 Fast, xhigh. The header now looks up the agent and model names in the instance's agent and provider catalogs, as the composer selectors do, and keeps the identifier when an agent or model is missing from them. A usage-metrics browser test asserts the header text and fails on the previous code; usage-metrics and the UI typecheck pass. Independent review approved with no findings.
One automatic compaction stacked several identical "Session … was compacted" notifications. The notification path was not idempotent: every delivered session.compaction.ended created a bubble (and a history entry when routed there), and the same event reaches a window once per project tab open on its folder (the server publishes one envelope per owning workspace) and again when the event stream replays it. stores/compaction-notice.ts claims each compaction end once per window by its durable position (aggregate and sequence, or the event ID without one), within a bounded memory of recent compactions; later deliveries still update the session's status in their tab but no longer notify. One bubble per session: a later compaction of the same session replaces the bubble still shown, each bubble is forgotten when it expires unless a newer one replaced it, and a notice routed away from the screen retains nothing. Each distinct compaction still reaches the history when routed there. Validation: unit tests for the claims and the bubble lifecycle; a browser regression delivers one compaction to two tabs on the same folder plus a replay through the real event dispatcher and toaster and asserts one bubble and one history entry, then one replaced bubble and a second entry for the next compaction (three bubbles without the claim, two without the replacement). notification-icon-badge and compaction-responsiveness pass; UI own-tsconfig typecheck and root typecheck pass. Gatekeeper review (GPT-6.1 Sol): one P3 (retained bubble handles) fixed, then zero actionable findings at 585140a. Fixes #986
## Problem Since #1096, the UI unit job on `dev` fails in two `instances-pending-compaction.test.ts` tests, with `TypeError: toast.dismiss is not a function` (also in #1096's own PR run). #1096 shows one bubble per session, so a later compaction end dismisses the session's earlier bubble. These tests end several compactions in one session. Under Node with tsx, `import toast from "solid-toast"` yields the CommonJS module object, which has no `dismiss`. The fixture replaced only `toast.custom`, so the dismissal threw. The app is not affected: Vite resolves the real `toast` function, which has `dismiss`. ## Fix The fixture also replaces `toast.dismiss` with a no-op and restores it after each test, as `session-lifecycle-signals.test.ts` already does. Test-only change. ## Validation - Reproduced on unmodified `dev` (`333d73452`): 2 of 7 tests in the file fail. - With the fix: - `instances-pending-compaction`, `compaction-notice` and `session-lifecycle-signals`: 18/18; - full UI unit suite: 1694/1694; - UI typecheck.
## Summary
- Qualify OpenCode **2.1.3** (latest stable, 22 October) with the
existing locked **2.1.0 client/plugin** dependencies, and **recommend**
it.
- Keep the technical **minimum at 2.1.2**: nothing CodeNomad consumes
changed, so the minimum has no new reason to move.
- A 2.1.2 daemon stays ready and gets an optional upgrade offer. 2.1.3
is the `tested` version. Newer and custom labels keep authenticated
contract recognition.
- The reviewed-contract fast path lists 2.1.3 beside the 2.1.2 minimum.
- The recommended version is updated in the help (all ten locales), both
READMEs, `dev-docs/OPENCODE_COMPATIBILITY.md` and the architecture
skill.
## Contract review (v2.1.2 → v2.1.3, 66 commits)
- **Authenticated OpenAPI:** 119 → **121 paths**, 144 → **146
operations**. Every consumed operation is unchanged. The only changes:
- added `GET /api/experimental/voice/models`;
- added `POST /api/experimental/voice/session/{sessionID}/instructions`;
- an optional hosted `session.id` in the `POST
/api/experimental/voice/session` response.
None of these is on the instance proxy allowlist, so they stay closed.
- **Published declarations:** the client adds only `voice.models` /
`voice.instructions`. The schema changes only typing (agent `color`
decoding, `Durable` as a tagged union). The plugin is unchanged.
- **Windows managed services** move their default port from **45278 to
28894** ([#57428](anomalyco/opencode#57428)).
CodeNomad discovers the daemon through the selected CLI's `service
status` and the service registration, and assumes no port.
- Live check: this machine's shared daemon was upgraded to 2.1.3 and
restarted on 28894, and the running CodeNomad desktop kept working
through it.
- **Core:** mostly refactors, plus behaviour fixes that the native
suites below exercise:
- compaction summary output limit;
- `keepID` validated as a message ID;
- MCP media kept out of attachments;
- only changed instruction entries resent;
- relative-directory V1 migration;
- legacy `apply_patch` permission mapped to `edit`.
## Isolated Windows qualification
Base: dev `333d73452`, rebased on `853b14f2f` (#1097) for the final UI
unit run; Node **24.20.0**; exact official CLI **2.1.3**; unchanged
locked client/plugin **2.1.0**.
- **Build and checks:** production server/UI/native plugin builds,
server and root typechecks, native bundle guard.
- **Native runtime (9/9):**
- Code Mode job ordering, plugin runtime, automation;
- complete pruning, history, ownership, worktree and event relay;
- loaded-only pending snapshot;
- Missions contract, family control, native and Compare/Wayfinder
trajectory.
- **Sessions (15/15):** environment, fork, aside, interrupt, lifecycle,
blank cleanup, prompt skills, provider usage/accounts/selection, service
usage, web search, plugin packages, output limit, Promise-tool failure.
- **Recurring (5/5):** all **11 recurring Mission journeys**, subagent
depth, **2 MiB** compaction, permission receipts.
- **Migrations (9/9):**
- history from **2.0.3, beta-19271, 2.0.32, 2.1.0, 2.1.1 and 2.1.2** to
2.1.3;
- Git degraded/init;
- temporary workspaces.
- **Installation (3/3), with the 2.1.3 recommendation:**
- fresh install of the 2.1.2 minimum;
- native **2.0.15 → 2.1.3** upgrade, after which the already-running
daemon keeps its PID and 2.0.15 version;
- explicit OpenCode **1.18.10 → 2.1.3** replacement.
- **After the recommendation change:**
- admission/transport/update/setup units **36/36**;
- full server **2,463 passed, 8 skipped**, no failure or cancellation;
- UI units **1,694/1,694** (with #1097);
- focused browser **126/126**;
- native pruning with the real rendered UI;
- the exact CI invocation of the Code Mode regression (without tsx);
- ten-locale help checks.
The UI unit run on `333d73452` itself had two failures, in
`instances-pending-compaction.test.ts` (`toast.dismiss is not a
function`). They come from #1096 and also fail on unmodified `dev`;
#1097 fixes that fixture.
This is Windows automation evidence. In CI, `latest` now resolves to
2.1.3: the compatibility job runs the native suites against the minimum
and latest on Windows, and the migration and Git-degraded certification
runs them on Ubuntu, Windows and macOS. WSL, packaged desktop,
installers/updater end-to-end and real mobile devices keep their
separate release gates.
## Summary
- Replace the CodeNomad logo with the new **bare CN mark**: a bold C and
N in saturated blue `#0088ad` on a transparent background, an orange
ring `#f7970e` at the centre of the C and a trace joining it to the N.
No tile.
- One source drives every placement: the Electron and Tauri app icons
(ICO, ICNS, PNG, Linux hicolor sizes), the favicon and PWA icons, the
home, empty-session, empty-state and loading screens, and the help site.
- No code or layout changes: every placement keeps its square image box.
## Assets
- `images/CodeNomad-Icon.svg` (new): vector source, the mark on a square
552-unit canvas. The trace overlaps the N stem so anti-aliasing leaves
no seam where the shapes meet.
- `images/CodeNomad-Icon.png` and
`packages/ui/src/images/CodeNomad-Icon.png`: 1024×1024 transparent
export of the SVG.
- `electron/resources/icon.{icns,ico,png}`: regenerated with
`packages/electron-app/scripts/generate-icons.js` and copied to
`packages/tauri-app/src-tauri/`. The ICO keeps its nine frames (16–256)
and the ICNS its twelve entries.
- `packages/tauri-app/src-tauri/icons/linux/*.png`: exported straight
from the SVG at 32–512 px.
- `BUILD.md` documents the source and the regeneration steps, including
the Tauri copies.
## Validation
- Rendered every ICO frame (16–256 px) on dark and light backgrounds:
legible from 24 px; at 16 px the trace fades and the ring reads as an
orange dot.
- Screenshots of the real `FolderSelectionView`, `BrandedEmptyState`,
`EmptyState` and loading screen components in dark and light themes.
- `node --import tsx --test
tests/browser/notification-icon-badge.test.ts` (favicon drawing from the
icon): 6/6 pass.
- `npm run test:help`: pass.
## Summary - Remove `images/CodeNomad-Icon-original.png`, the source of the previous tile logo. The new bare CN mark comes from `images/CodeNomad-Icon.svg` (#1099). - Nothing references the file: no build script, document or component. ## Validation - `git grep Icon-original` finds no reference.
…1102) ## Summary - The main window's custom title bar (Windows and Linux) shows the new CN mark instead of the text "CodeNomad" before its menus. The Preferences window keeps its text title. - `NativeTitlebar` gains an optional `logo` prop: it renders `packages/ui/src/images/CodeNomad-Mark.svg` (the mark from `images/CodeNomad-Icon.svg` cropped to its bounds) 24 px high, centred in the 36 px bar, with the title as `alt` so the accessible name stays "CodeNomad". - The image is `draggable={false}` so pressing it still moves the window, and it hides below 640 px like the title did. - `BUILD.md` lists the cropped asset beside its source. ## Validation - `npm run typecheck --workspace @codenomad/ui`: pass. - Screenshots of the real `NativeTitlebar` at 1x and 2x in dark and light themes: mark 24×45.5 px at y=6 in the 36 px bar, `alt="CodeNomad"`, Preferences title unchanged.
## Summary - The title-bar mark from #1102 goes from 24 px to **20 px** high, at the owner's request: 8 px of margin above and below it in the 36 px bar, closer to the weight of the menu labels. - Only `.native-titlebar-logo` height changes; the brand container still centres it vertically. ## Validation - Screenshot of the real `NativeTitlebar` at 20 px in dark and light themes, 1x and 2x: mark 20×38 px at y=8 in the 36 px bar.
## Summary - The title-bar mark goes from 20 px to **14 px** high, at the owner's request after trying it live: it now matches the visual weight of the menu labels, with 11 px of margin above and below it in the 36 px bar. - Only `.native-titlebar-logo` height changes; the brand container still centres it vertically. ## Validation - Tried live in the owner's installed Tauri app with a 14 px override. - Screenshots of the real `NativeTitlebar` at 14 px in dark and light themes, 1x and 2x: mark 14×26.5 px at y=11 in the 36 px bar.
## Summary Large logos follow their title instead of the window, on the plain empty state's ratio (6rem logo above a `text-3xl` title, 3.2x): - **Home page** and **branded empty session**: 6rem (the home page's 12rem rule from 640 x 721 px goes; the session drops `h-48`). - **Narrow session column**: the title shrinks to 1.5rem, so the logo shows 4.8rem. - **Loading screen**: 8rem (128 px) beside its larger 2.8rem title, instead of 180 px. - `dev-docs/UI_CONVENTIONS.md` records the rule. ## Validation - Real home page, branded and plain empty states, narrow session column and loading screen in dark and light at 1100 x 760: logo/title 96/30, 96/30, 96/30, 76.8/24 and 128/44.8 px. - Tried in the owner's installed app through a temporary override. - `npm run typecheck --workspace @codenomad/ui`.
…bar (#1105) ## Summary On macOS, CodeNomad showed **two menu bars**: the system menu bar and, inside the window, the UI title bar with the same File/Edit/View/Window/Help menus plus Windows-style buttons at the right. macOS windows now follow the platform convention (as in VS Code or Slack): - The menus live only in the **global menu bar**. - The **native traffic lights** sit at the left of CodeNomad's title bar, which keeps the theme colours and shows the CodeNomad mark (Preferences: its title) after them. - The main window's title bar now also holds **Settings, the notification history bell and Remote Access**, so the project tab bar gives that space to the tabs (and drops its separator). - Windows, Linux and browsers are unchanged. ## Implementation - **Tauri**: new `title_bar.rs` configures local application and Preferences windows: overlay title bar with a hidden title on macOS, no decorations elsewhere. - **Electron**: `titleBarStyle: "hidden"` on macOS, `frame: false` elsewhere, for the same two windows. - Both keep the traffic lights at their **standard place**. Tauri loses a custom `traffic_light_position` once the window is shown and resized (it came back to the default on the VM), so on macOS the UI bar takes the native **28 px** title bar height instead, which centres them, and leaves their 60 px clear in every writing direction. - `NativeTitlebar` drops the in-window menus and window buttons on macOS. The actions move from `InstanceTabs` into a shared `AppActions` component, rendered by the title bar on macOS and by the tab bar elsewhere (`appActionsInTitlebar`). - The native close button of Preferences goes through the existing guarded close request, like Cmd+W. - `dev-docs/UI_SHELL.md` describes the per-platform title bar; the Settings help says where the gear and bell are on macOS, in all ten languages. ## Validation - **macOS 15 test VM**, Electron app and Tauri build patched with this change: traffic lights and mark centred in the 28 px bar in both hosts (measured from screenshots), no in-window menus or buttons, actions at the right end opening Preferences, Remote Access and the notification history below the bar, Preferences title after the lights, and its red button closing the window. - New `tests/browser/macos-titlebar.test.ts` renders the real title bar and tab bar as macOS and as Windows. - `tab-chrome`, `new-instance-launcher`, `opencode-setup` and `notification-icon-badge` browser tests (58 pass, 1 skipped), `npm run test:help`, `npm run typecheck` pass.
…ory (#1107) ## Summary - The notification history's **Clear all** and **Settings** text buttons become icon buttons (red trash can, gear), like the panel's close button. - Their labels stay as tooltips (`title`) and accessible names (`aria-label`), with the existing translations. **Mark all as read** keeps its text. - Shared `window-icon-button` geometry; the existing toast-history action classes keep hover, danger and disabled styling. ## Validation - Screenshots of the real `ToastHistoryPanel` with two notifications, dark and light themes, including the hover state. - `npm run typecheck --workspace @codenomad/ui`.
## Summary The app icon looked smaller than its neighbours in the Windows taskbar: the square source SVG kept an empty ~4 % margin on each side, so the 24 px icon drew the CN in 22 x 12 px on a transparent background. - `images/CodeNomad-Icon.svg` is cropped to a square centred on the mark, touching the left and right edges (height stays about half: the CN is twice as wide as tall). - Master PNG, in-app copy, Electron/Tauri `.ico`/`.icns`/`.png` and Linux sizes regenerated: 24 px now 24 x 14 px, 32 px now 32 x 18 px. - In-app logos use the same PNG, so their heights shrink by the same ratio to keep the approved on-screen sizes (5.55rem, 4.44rem narrow, 7.4rem loading); `dev-docs/UI_CONVENTIONS.md` updated. ## Validation - Regenerated `icon.png` loses no opaque pixel of the master; the mark spans columns 0-1023. - Measured bounding boxes in the 16/24/32/48 px `.ico` entries before and after. - `npm run typecheck --workspace @codenomad/ui`.
…permission (#1109) ## Summary System notifications on Windows: everything about them in one PR. 1. **Windows data profiles never showed system notifications** (`fix(windows): show system notifications from every data profile`). Tauri runs each data profile, such as **dev**, under its own AppUserModelID (`…client.scope.s<hash>`), and its notifications carry that ID; Windows shows a desktop app's notifications only under an ID it knows, and the installer's Start menu shortcut carries the stable ID alone. Windows recorded every notification (100 on the affected machine) and displayed none. Every launch now registers the running ID under `HKCU\Software\Classes\AppUserModelId\<identifier>` (`DisplayName` CodeNomad, `IconUri` the bundled web app icon `resources\server\public\pwa-192x192.png`, which the packaged-resource smoke check requires; `windows_notification_identity.rs`). Electron always uses the stable ID. 2. **The permission was lost at every restart on Windows.** The notification plugin's page script reports *denied* there until the page requests permission, though Windows never asks, so Settings asked again after each restart. The check now asks the native plugin command, which answers granted on desktop: granted once, kept. 3. **Notifications were held back whenever the window was visible** (`fix(notifications): hold system notifications back only while focused`). With **Notify when the app is focused** off (the default), an open window stays visible behind other applications or on another screen, so nothing was sent unless CodeNomad was minimized. Delivery is now skipped only while the window is visible and focused (`document.hasFocus()`). The setting's subtitle and the Settings help say *focused* in all ten languages; `dev-docs/SETTINGS.md` records the rule. Out of scope by decision: several CodeNomad windows open on the same project may each send the event's notification (as they already do when the setting is on), and focus inside a browser preview counts as leaving the page. ## Validation - Affected machine: no profile notification showed before; after registering its ID as above, a notification sent under it showed in the notification centre under CodeNomad. - `cargo test --bins -- windows_notification_identity` (writes the key, reads back both values). - `tests/browser/system-notification-focus.test.ts`: real routed notification from a visible page; nothing while focused, one once focus is lost, one while focused with the setting on; red on the previous visibility check. - `npm run typecheck --workspace @codenomad/ui`, `npm run test:help`.
…bound (#1106) ## Problem Long model reasoning still appears to freeze roughly 30 seconds in, even after #1088 kept the store streaming across shared-stream reconnects. The visible thinking text stops growing while the panel keeps visibly refreshing — the live duration keeps ticking, the transcript keeps following, and the reasoning scroller stays pinned to its bottom. To a user watching a long think, it is indistinguishable from the earlier store freeze, which is why the previous fix looked like it had not worked. ## Root cause The record display projection caps every reasoning part's text at `REASONING_RENDER_CHARACTER_LIMIT` (10 000 characters — `extractReasoningTextForRender` inside `buildRecordDisplayData`, introduced by #648's memory bounding). The cap applies while the part streams, not only once it settles: - A reasoning stream at typical model speed crosses 10 000 characters around 30 seconds in — the same moment the connection-recheck freeze used to surface, so the two bugs produced nearly identical symptoms. - Past the bound, every delta still re-projects the message (the row re-renders, the header duration ticks, the transcript keeps following — "refreshing, just no content"), but the displayed text is byte-for-byte the same 10 000-character prefix, so `ReasoningStreamOutput`'s `<pre>` never changes again until the part completes. - The store keeps the whole text the whole time and copy actions read it whole; only the display copy is silently capped, with no reveal. ## Changes - `stores/message-v2/record-display-cache.ts`: a reasoning part without `time.completed` (still streaming) now projects its whole `text`. That is a reference to the store's string, not a copy — per delta it is cheaper than the previous sliced 10 000-character copy. Once the part completes, the projection returns to the bounded 10 000-character prefix, preserving #648's retained-copy bound for settled transcripts. - `dev-docs/TEXT_DISPLAY_BOUNDS.md` describes the split: completed reasoning keeps the bounded prefix; a still-streaming part renders whole. ## Behavior compatibility - Completed reasoning renders exactly as before (bounded prefix, whole-text copy). - Timeline markers, hover previews and search slice their own text from the raw parts (`message-timeline.tsx` still bounds previews at 4096 characters) and are unchanged. - A reasoning part that never settles (interrupted mid-think) keeps its whole text by reference — it renders live and retains no extra copy. - No help-page change: the bound was never documented in the user help and no labels, controls or defaults changed. ## Validation - Red→green unit regression in `instance-store.test.ts`: the streaming projection keeps the whole text past the bound; the completed projection keeps the bounded prefix. Pre-fix it fails at the first assertion (10 000 vs 10 020 characters). - New browser regression `tests/browser/reasoning-stream.test.ts` (real `SessionView`, native SSE dispatcher): three ~6.9K-character reasoning deltas keep rendering whole past the bound, and `session.reasoning.ended` returns the card to the 10 000-character prefix. Pre-fix it fails exactly like the live bug: `AssertionError: delta 2 renders whole (got 10000)`. - The `session.tsx` fixture gains `startReasoning` / `reasoningDelta` / `endReasoning` emitters plus an opt-in `revealThinking` preferences hook (thinking rows are hidden by default). - `tsc --noEmit` clean; `instance-store` 30/30; `empty-content` + `message-part-grouping` + `render-text-window` 18/18. - Shared-fixture `message-scroll` suite: 127/128 **identically on this branch and on the clean base commit**; the single failure is the first test's page-load navigation timeout, a pre-existing local Vite cold-start issue (the same environment phenomenon class #1088 documented), not a regression. --------- Co-authored-by: Pascal André <pascalandr@gmail.com>
) ## Summary - New logo: a hexagon framing a C and an n, in equal bands (ring, gap, strokes, counters share one width), readable down to 16 px. - **App icon**: white ring and letters over black gaps, transparent canvas, hexagon spanning top to bottom; one fixed icon for light and dark taskbars, docks and tabs. - **In the UI** (`components/brand-logo.tsx`): black hexagon with white gaps on light palettes, white version on dark ones, picked in CSS from `data-theme` (system appearance when unset), so it also works outside ThemeProvider (title bar). Loading screen (always dark) uses the white one. Sizes: 4rem beside a text-3xl title, 3.2rem narrow column, 5.3rem loading screen, 16px title bar. - **Icons rendered from the vector**: `scripts/generate-icons.mjs` draws every `.ico` entry (16-256 px), `.icns` slot, Linux size and the 1024 px master straight from `images/CodeNomad-Icon.svg` with Chromium, instead of shrinking one large PNG; it writes the containers itself, so Electron drops `png2icons`/`pngjs`. One command replaces BUILD.md's four manual steps. ## Validation - New `tests/browser/brand-logo.test.ts`: real title bar + home page; which hexagon each logo shows on light, dark and system (both ways) palettes, with heights; red without the logo stylesheet. - UI + Electron typechecks, Electron tests (283), `macos-titlebar` and `notification-icon-badge` browser tests, `npm run test:help`. - Icon checks: ICO entries 16-256 (DIB, PNG at 256), ICNS slots icp4-ic14; UI captures on porcelain, linen, mist and ember palettes.
This branch was successfully deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
CodeNomad 1.0.0 — OpenCode V2, on desktop and mobile
Draft covering changes since 0.20.0, including 0.20.1. Release validation remains in progress.
The best desktop and mobile client for OpenCode V2.
0.20.0 brought CodeNomad to OpenCode V2. 1.0.0 turns more of its native power into a complete workspace: coordinated agents, deeper history access and visual automation, with speed, efficiency and everyday stability at its core.
Highlights
Built for demanding workflows
Built around OpenCode V2
@; inspect Code Mode scripts, nested tool calls and web-search sources. Search providers support global defaults and project overrides.Missions and native multi-agent coordination
From your desktop to your phone
History and visual automation
Files, Git and everyday work
/btwbuild on 0.20.0. After sending, use the conversation for keyboard reading; typing resumes the composer.Extensions, help and customization
Desktop updates and setup
Upgrading
.exe; Linux Tauri AppImage or Electron.deb; separate Intel/Apple Silicon macOS builds. The Electron.debreplaces the former Tauri.deb—choose AppImage to stay on Tauri.Thanks for contributions
Thanks to creator @shantur, @pascalandr, @heunghingwan, and everyone who contributed ideas, reports and testing.
Changes since 0.20.0: v0.20.0...dev