mirror of
https://github.com/NeuralNomadsAI/CodeNomad.git
synced 2026-11-01 11:30:33 +00:00
7 commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
87ae7050c6
|
fix(tauri): ship a single desktop entry in the Linux AppImage (#1179)
## Problem Every Tauri Linux build since 2026-10-28 fails in "Package and verify Tauri AppImage" with `Expected exactly one desktop entry in the Tauri AppImage, found 2`. This blocks dev pre-releases and releases. ## Cause Tauri's AppImage bundler copies `bundle.linux.appimage.files` into `usr/share/applications` next to its generated `CodeNomad.desktop`, symlinks `CodeNomad.desktop` at the AppDir root, then runs linuxdeploy without a desktop-file argument (tauri-bundler `linuxdeploy.rs`). linuxdeploy logs `No desktop file specified, using first desktop file found` and deploys whichever entry the directory listing returns first. When that is the hidden alias `ai.neuralnomads.codenomad.client.desktop` (`NoDisplay=true`, added in #334), it lands at the root beside Tauri's entry. The 2026-10-27 build picked `CodeNomad.desktop`; today's builds pick the alias. No repository change between them touches packaging. ## Fix - Remove the alias from `bundle.linux.appimage.files` only. Inside an AppImage, files under `usr/share/applications` are not registered with the desktop; integration tools install the root entry. deb/rpm keep the alias for GTK app id association. - Document the constraint in `dev-docs/TAURI_UPDATER.md`. ## Validation - This PR's Tauri Linux packaging job extracts the AppImage and requires exactly one root desktop entry. |
||
|
|
2eb1fb1797
|
fix(tauri): stop F11 from freezing the Linux app (#1143)
Pressing F11 froze the Tauri app on Linux under X11 or XWayland: GNOME reported "CodeNomad is not responding" and the window never went fullscreen. The released 1.0.0 AppImage froze the same way, so this predates the AppImage display-stack fix (#1138), which keeps GTK on X11 for this very shortcut. A backtrace of the frozen process showed a deadlock between two threads: - global-hotkey's X11 thread received F11 and ran the plugin handler on that thread. toggle_fullscreen_window then asked the main thread whether the window was focused (is_focused) and waited. - The key grab itself moves X11 focus. Its focus events reached the main thread, where update_fullscreen_shortcut re-registered F11 and waited for the X11 thread to confirm. The handler now queues the toggle on the main thread (run_on_main_thread) and returns, so the shortcut thread is free to answer the registration. Two leaks from #1138 are closed on the way: - prefer_x11_display exported GDK_BACKEND=x11,wayland, which every child inherited: the backend, the shared OpenCode service it may start, agent shells, editors and the browser opened for links. Their GUI programs then ran under XWayland. CodeNomad now sets its own GTK's preference with gdk_set_allowed_backends, and children keep the session's choice. A GDK_BACKEND set by the session still wins. - Children that leave an AppImage's mount started in AppRun's working directory inside it (PWD=/tmp/.mount_*/usr for the browser opened by a link). use_host_environment now starts them in / while ours is inside the mount; callers that pick a directory (backend, editors) still do. dev-docs/HOTKEYS.md records that a global-shortcut handler only queues work on the main thread; dev-docs/TAURI_UPDATER.md describes the GTK backend preference and the working directory. Validation on Ubuntu 24.04 GNOME Wayland, with the #1141 CI AppImage repacked around a binary built from this branch: - After focusing the window, about ten F11 presses toggle fullscreen in and out. The main thread stays in its event loop (poll), where the CI build and the 1.0.0 release deadlock on the first press (gdb backtraces). - The window is still an XWayland client. The backend and the OpenCode service carry neither GDK_BACKEND nor mount paths. - The help link opens Firefox with / as working directory, PWD=/ and no GDK_BACKEND. - The appimage_environment and appimage_exit tests pass, and the Linux release binary builds. |
||
|
|
a6c19d19d7
|
fix(tauri): leave the display stack to the host in the Linux AppImage (#1138)
The Tauri AppImage showed a black window on up-to-date Linux systems (#1136: Arch, sway, AMD, Mesa 26.2). WebKit aborted with "Could not create surfaceless EGL display: EGL_BAD_ALLOC", and no WebKit or GDK variable helped. Tauri CLI 2.11.5's linuxdeploy copied the build runner's display stack into the image: Ubuntu 24.04's libwayland-client, -cursor, -egl and -server, libxkbcommon, libxcb-render and -shm, libXau and libXdmcp. AppRun puts usr/lib first on the library path, so the host's Mesa EGL loaded the stale libwayland-client and failed even on the surfaceless platform. This is tauri-apps/tauri#15976, fixed upstream in CLI 2.12.1. On a current Arch userland (Mesa 26.2.5, wayland 1.26), `eglinfo -p surfaceless` initializes with the host libraries and fails with the 1.0.0 image's bundled ones, or with its libwayland-client alone. Packaging: - The Tauri CLI moves to ^2.12.4. - The Linux job defines APPIMAGE_HOST_LIBRARIES once (wayland, xkbcommon, xcb, X11, Xau, Xdmcp, EGL, GL, gbm, drm). It is passed to linuxdeploy as LINUXDEPLOY_EXCLUDED_LIBRARIES, because 2.12.4's own excludelist still deploys GDK's display libraries. - The AppImage verification step rejects an image that bundles any of them. Runtime, because the 2.12 GTK hook leaves GDK_BACKEND unset and exports mount-scoped module paths: - main() sets GDK_BACKEND=x11,wayland unless the session sets it. This keeps the XWayland windowing that the F11 X11 key grab needs, with a Wayland fallback. - appimage_environment.rs drops variables inside the mount (byte-wise, plus the lossy spelling of the Node-serialized shell snapshot) and the mount's path-list entries. GIO_MODULE_DIR, unlike GIO_EXTRA_MODULES, replaces the host's module directory. It applies to children that outlive the mount: the backend (and through it the shared OpenCode service), the editors CodeNomad opens, and link handlers. - Links open through external_open.rs. On Linux it uses the opener plugin's launchers with the host environment, detached; elsewhere it delegates to the plugin. The renderer reaches it through a new open_external_url command (http, https, mailto). The windows hold that command instead of opener:allow-open-url. - The plugin's injected click handler is off. Its replacement, lib/native/external-link-clicks.ts, takes the same decisions in the application and Preferences windows and in trusted same-origin SideCar documents. Opaque previews and panel extensions stay fenced. - The unused @tauri-apps/plugin-opener npm dependency is dropped. Validation: - Ubuntu 24.04: the Linux crate compiles, and the appimage_* tests (path lists, non-UTF-8 entries and mounts, lossy snapshot) and the capability test pass. - The inventory check accepts GTK, WebKit and GLib, and rejects flat, multiarch, dangling-symlink and GLES copies. - Browser tests drive the real link handler (target="_blank", Ctrl, Shift, nested, mailto; plain, Alt, tel and custom schemes untouched) and the real SideCarView and preview frames in a stubbed Tauri window. Each fails without its fix. - The UI own-tsconfig and root typechecks pass. |
||
|
|
9d9fc8d235
|
fix(tauri): stop AppImage helpers before exit so WebKit never crashes 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. |
||
|
|
7a1fc90310
|
docs(agents): keep AGENTS.md to universal rules and agent docs to the current state (#1082)
AGENTS.md loaded about 33,000 tokens into every agent session, subagent and reviewer, mostly per-feature contracts, and the agent documentation around it had accumulated duplicates, dated logs and history of removed designs. This PR makes AGENTS.md a short set of rules that apply everywhere plus an index of area documents, and leaves AGENTS.md, dev-docs and the repository skills describing only the current state. Three commits, reviewable separately: 1. **Move (lossless).** Every per-area rule moved verbatim from AGENTS.md into its area document (existing ones, or six new ones: UI_CONVENTIONS, UI_SHELL, COMPOSER, TRANSCRIPT, SETTINGS, PROJECTS). A script split the old file into 208 units, required one destination for each and checked all 199 content units verbatim at their destination. AGENTS.md went from 134,000 to 16,000 characters. 2. **Trim.** A per-area ponytail review removed rules stated two or three times (keeping the more precise copy), dated validation logs, per-version qualification sections below the current minimum, abandoned designs and self-references; seven documents whose surviving rules live elsewhere were deleted. It also fixed statements the code contradicts (locale registration, the Mission play/recovery condition, plugin package updates, cleanup progress UI, timeline index persistence, automation restart/targets, stale pins and minimums). 3. **Current state only.** The new AGENTS.md rule: no history (removed features and their names, former behavior, provenance, dated logs) and no denials; correct a contradicted statement at its source. DEVELOPER_MODE.md is merged into BROWSER_AUTOMATION.md and every Developer Mode mention is gone (including the README and the browser help page in ten locales). Names that only made sense against older designs are renamed with every reference updated, MISSIONS_ENVIRONMENT_ADMISSION is folded into SESSION_ENVIRONMENT, and INDEX lists every document. The server npm README now states the real OpenCode minimum (2.1.2). AGENTS.md is now about 14,000 characters (roughly 3,500 tokens); AGENTS.md, dev-docs and the vendor README went from about 11,200 lines to under 4,700. Validation: every relative Markdown link and every cited dev-docs path resolves; no reference to a renamed or deleted document remains; `npm run test:help` passes for all ten locales. Review: three independent GPT-6.1 Sol (high) reviews by area found binding rules lost in the trim and current-state passes; 25 were restored as present-tense facts or prohibitions and four contradicting statements corrected, each checked against code. A Fable 5.1 gatekeeper review of the whole PR passed; its follow-up routes session recovery from the index, points to dev-docs/INDEX.md and documents the family identity read. |
||
|
|
4e0b62bc7f
|
build: ship the Linux deb from Electron and the Windows installer without a ZIP (#955)
## Summary One download per need, with fewer duplicate or unused assets: | | Before | After | |---|---|---| | **Linux Electron** | portable `tar.gz` | **`.deb`** | | **Linux Tauri** | `.deb` + AppImage | **AppImage** (self-updating) | | **Windows Tauri** | ZIP wrapping the installer + the same installer as `.exe` | **`.exe`** only | | **Updater signatures** | `latest.json` + separate `.sig` assets | **`latest.json` only** | ### Linux: Electron deb, Tauri AppImage - The Electron deb installs as root, so electron-builder's post-install script gives Chromium's `chrome-sandbox` the `root:root` ownership and `4755` mode that a user-extracted archive cannot. Electron starts **with its sandbox** and without any manual step. This fixes #541 properly. - The package is named `codenomad` and **conflicts with / replaces** the former Tauri deb (`code-nomad`). Both ship `/usr/share/applications/CodeNomad.desktop`, so without this, installing over an existing Tauri deb would fail on the shared file. - The deb declares Electron's full runtime closure. electron-builder's default `Depends` omit `libgbm1` and ALSA, which previously arrived only through Recommends. ALSA is declared as `libasound2t64 | libasound2`, because `libasound2` is a multi-provider virtual package on Ubuntu 24.04. - Debian versions: dev builds (`<stable>-dev-<date>-<sha>`) become `<stable>+dev.<date>.<HHMMSS commit time>.<sha>`, so they install as upgrades after their stable base and in order on the same day; other prereleases keep electron-builder's `~`, which sorts before the release. The workflow rewrites the control `Version` with `dpkg-deb` when it differs; PR and stable builds rewrite a copy to a synthetic dev version and check that fields, files, modes, owners and control members are preserved. - Tauri Linux builds only the AppImage (`tauri build --bundles appimage`). - No unused electron-updater metadata is generated (`publish: null`). ### Windows: installer only - The Tauri NSIS installer is published directly as `CodeNomad-Tauri-windows-x64-<version>.exe`. It is also the signed updater payload, so signed builds upload it once. - The ZIP that wrapped the same installer is no longer published. - The WinGet automation defaults now point to the `.exe`. ### Updater signatures - The updater reads each signature from `latest.json`, never from a `.sig` asset. Staging still verifies every signature and its trusted comment and records it in the receipt, and publication still requires every payload's uploaded digest to match. - Releases no longer carry `.sig` assets, and staging deletes any left on a rebuilt tag by older builds. Rebuilt tags also delete obsolete Electron `tar.gz`, Tauri deb and Windows ZIP assets. ### Docs - **README:** shows the deb and AppImage commands. The AppImage uses the static type2 runtime, so it needs no `libfuse2`; `--appimage-extract-and-run` covers environments without FUSE. The Wayland/NVIDIA command now targets the AppImage. - **BUILD.md, `TAURI_UPDATER.md` and the WinGet guide** describe the new formats. ## Migration note Installing the Electron deb over a Tauri deb switches the app from Tauri to Electron: - `code-nomad` and `codenomad-tauri` are removed, and the launcher becomes `CodeNomad`; - server configuration is shared, but desktop window state is not migrated. Tauri deb users never had in-app updates, so the release notes should say this. The AppImage is their Tauri option. ## Validation - **Electron deb packaging (CI):** checks package, conflicts, replaces and version metadata, the contents, the post-install `chmod 4755` step, the resources/asar smoke checks and `ldd`. - **Electron deb install (CI):** installs on Ubuntu 24.04 **without recommends**, so `ldd` proves the declared `Depends` are enough. It installs over a stand-in `code-nomad` package, then checks that the old package was replaced, the owner of the desktop entry, `/usr/bin/CodeNomad`, `chrome-sandbox` `root:root 4755` and shared libraries. - **Version mapping:** the mapping, the ordering against stable, later releases and same-day builds, and both repack branches were checked with dpkg 1.22.6 on Ubuntu 24.04. The repack keeps the control fields and root ownership. - **Dependencies:** every declared dependency resolves on Ubuntu 24.04, either as a real package or through its t64 provider. - **Updater scripts:** `updater-artifacts.test.mjs` passes, including signature-in-manifest publication with no staged `.sig`. - **Workflow:** the YAML parses. - **Independent review:** no blocker. The major finding (missing deb dependencies) and the minor ones (dev version ordering, stale BUILD.md and README command, unchecked exit codes, unused updater metadata) are addressed. ## Follow-ups outside this PR - **WinGet:** the `WINGET_WINDOWS_ASSET_NAME_TEMPLATE` repository variable still pins the `.zip` name and overrides the new default. Before the next stable release: - update it to `.exe`, or delete it; - check that the automated `winget-pkgs` PR declares a direct `nullsoft` installer without the old ZIP fields, and correct it if not. Until then, a stable release's WinGet job waits for the ZIP and fails without side effects. - **Ubuntu desktop trial:** test the Electron deb on a real Ubuntu desktop. |
||
|
|
dac236c8fd
|
feat(tauri): signed cross-platform updates with stable and preview feeds (#786)
Desktop Tauri builds now update themselves in place on Windows (signed NSIS), macOS x64/arm64 (signed .app.tar.gz) and Linux x64 (signed AppImage), and Linux gains AppImage distribution. The application no longer shells out to `winget upgrade`; WinGet remains a distribution channel. Updates follow the same two feeds as the server notifications: `stable` offers GitHub's latest final release when it is newer; `preview` (dev + release) offers the newest publication of any kind, ordered by publication because dev labels reuse their base version. The saved `server.updateFeed` selects the feed (otherwise the build label). Only releases carrying their signed `latest.json` are installable, so releases still building are never offered. Native code owns URLs, keys and installers: renderers pass only the feed and, after an explicit "Install and restart", the accepted version. The manifest must announce exactly the selected version and `requireSignedVersion` binds it to the signature. Full verification precedes shutdown; installation and restart are admitted atomically with an all-window flush; timeouts, cancellation and failed cleanup discard the installer without replay. Failures belong to the installing window, survive reloads and are reported once; concurrent checks report "busy". Menu actions reach only the focused local application document. The vendored tauri-plugin-updater 2.12.0 runs its Windows exit callback only after a successful installer launch. Publication stages four verified payloads (signed version required) and publishes each release's `latest.json` only after validating every receipt and uploaded digest; rebuilt tags drop a stale manifest first. The signing private key reaches only `tauri build` steps. Unsigned builds and PR runs publish nothing. Debian/RPM and unsupported formats use the release-page fallback. The Tauri CLI minimum is 2.11.5. Validated by eight rounds of independent review (zero findings on both native/CI and renderer/docs), 268 native tests, script and browser regressions, real signed update trials on Windows and Linux (from loopback endpoints, before feed selection), and published-package trials on Windows, Linux and macOS x64. A production-signed dev prerelease, macOS signed updates and draft restoration across an update remain to be exercised. |