Skip to content

Merge develop into main: v0.1.0 → v0.1.40#9

Open
fseiffarth wants to merge 133 commits into
mainfrom
develop
Open

Merge develop into main: v0.1.0 → v0.1.40#9
fseiffarth wants to merge 133 commits into
mainfrom
develop

Conversation

@fseiffarth

Copy link
Copy Markdown
Owner

Brings main up to develop at v0.1.40. main has been sitting at v0.1.0 while release tags (v0.1.21, v0.1.36, v0.1.40) were cut from develop, so this closes a 133-commit gap.

Merges cleanlymain's only two unique commits are prior merges of develop, so it carries no content of its own (git diff origin/develop...origin/main is empty) and merge-tree reports no conflicts.

Scope

629 files changed, +207,645 / −13,799. 50 feat, 17 fix, plus chores/docs/tests.

Remote & SSH — mount-free SSH/SFTP-native remote projects (replacing sshfs), git-aware local↔remote lockstep sync, selective byte-sync with a big-folder census, multi-host compute machines, connection-status lamps, SSH host-key TOFU, password auth via an OpenSSH askpass shim, and tmux-backed session persistence.

HPC — SLURM pipeline wizard, workspace allocation/expiry handling, careful mode for login nodes, and the dial guard that keeps background probes off tagged hosts.

Platforms — Windows support (SEH crash hook, unelevated OpenVPN via the interactive service, popout drag, position_window) and macOS parity (OpenVPN daemon, system monitor, workspace backend, DMG packaging).

Viewers & UI — YAML/JSON tree and card viewers, PDF page tools and outline, table/CSV, GIF, line-diff compare, in-tree file search, git blame, native system monitor, network traffic tab, calendar tab, project containers, popout/detached subwindows, usage recap, and i18n groundwork (en/de/es/fr/it).

Verification

tsc clean · cargo test 1138 passed · vitest 2017 passed (0 unhandled errors) · privacy scan reviewed clean. CI is green on Linux, Windows and macOS for the tagged v0.1.40 build.

Caveats

Most of this is code-complete but not manually validated — per the project's standing "done ≠ tested" position, automated gates are the only checks that have run. The remote-connect hardening in particular has not been exercised against a live cluster; deferred follow-ups and the manual-QA list are tracked as TODO G.24.

🤖 Generated with Claude Code

https://claude.ai/code/session_01KPdhSvAcWJyBc5K9C5sgGz

fseiffarth and others added 30 commits June 24, 2026 11:38
Sync develop into main: README + privacy tooling
The Windows backend never compiled: Unix-only fs APIs were used
unconditionally and the windows-crate calls targeted a pre-0.61 API.

- openvpn.rs: cfg(unix)-gate the 0600 askpass/permission code so the
  module compiles on Windows (VPN stays a Unix-only feature).
- platform/windows.rs: port to windows 0.61 (HWND.0 is now *mut c_void;
  IsWindow takes Option<HWND>; GetParent/GetWindow/GetWindowDesktopId
  return Result; BOOL moved to windows::core).
- commands/apps.rs: port IShellLinkW/IPersistFile shortcut resolution to
  the 0.61 GetPath/GetIconLocation/Load signatures.
- Cargo.toml: add Win32_Storage_FileSystem feature (gates GetPath).
- ci-cd.yml: also look for Linux AppImage/deb bundles under the
  project-root target/ (rust-cache overrides CARGO_TARGET_DIR), and mark
  pre-1.0 GitHub Releases as prerelease (alpha).

Verified: cargo check passes for x86_64-pc-windows-msvc and native
Linux; cargo test green (25 passed).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SFHPkVpagZvJszVt4Avm6G
box_links_block built member doc links with Path::join, which on Windows
splices in a `\`, producing malformed markdown link URLs (and failing
box_links_block_lists_members_with_matching_md on the Windows runner).
Join with a literal `/` so generated markdown is identical on every host.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SFHPkVpagZvJszVt4Avm6G
import_project's "move" mode used a bare fs::rename, which fails across
drives/filesystems (EXDEV on Unix, os error 17 on Windows) — e.g.
importing from a different drive than the eldrun projects root. Fall back
to copy-then-remove (reusing copy_dir_all) when rename fails, matching the
existing move_path behavior. Fixes the Windows runner's projects_commands
integration tests (the move panic also poisoned the shared test lock,
cascading into two unrelated failures).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SFHPkVpagZvJszVt4Avm6G
Windows build support + first alpha (v0.1.0)
The upload steps list two path patterns (src-tauri/target and the
project-root target/ that rust-cache's CARGO_TARGET_DIR override uses),
which makes upload-artifact root each artifact at the workspace dir. The
bundles therefore download nested (target/release/bundle/.../*) rather
than at the artifact root, so the release job's flat globs matched nothing
and v0.1.0 published with no assets attached (uploaded manually after the
fact). Use recursive `**` globs so future releases self-attach.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SFHPkVpagZvJszVt4Avm6G
- Screenshot global app now captures an interactive region into the
  active project's screenshots/ folder, driving the configured tool's
  output path there with a native region-capture fallback.
- New in-app viewers: diff, notebook, table/sheets, html, media, odt,
  sqlite, and image annotator.
- Project search panel + fuzzy quick-open; sqlite/sheets backends.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TQYYMRLqFX53RFaJBonzp3
Backend: Worktree struct, parse_worktree_porcelain helper, and
git_worktree_{list,add,remove,prune} commands in commands/git.rs,
registered in lib.rs. Frontend: a "Worktrees" section in GitHistory
(list, create-from-branch, remove; main worktree non-removable), with
an aria-label on the remove control. Adds Rust unit/integration tests
and GitWorktree.test.tsx. "Open worktree as project" deferred.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…andbox

- Add gitDirty store + GitDirtyState tests for tracking uncommitted state
- Add tabLand store and cross-subwindow tab drag (CrossSubwindowTabDrag,
  DetachedSplit tests); expand TabBar/commitDrop and detached center panel
- Add agent-sandbox Docker image + services/sandbox.rs
- Viewer width reflow handling (ViewerWidthReflow test), TeX/markdown viewer
  tweaks
- Refresh app icons + icon-source.svg, expand themes.css
- Misc: RightPanel git status/history, ProjectDialog/ProjectPill updates

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
# Conflicts:
#	Cargo.lock
#	src-tauri/Cargo.toml
#	src-tauri/src/commands/git.rs
#	src-tauri/src/lib.rs
Detached subwindows gain divider resize and cross-group tab merge by
reusing the shared pure layout paths (applyResize, moveKeyInTree). A
dedicated outer title bar keeps the window controls pinned top-right
regardless of splits. Includes regenerated icons and a hot-reload
dev launcher script.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Each git action button in the right panel now only renders when it has
work: Add when there are unstaged/untracked changes, Commit when changes
are staged, Push when commits are ahead of the remote. The action bar
hides entirely for a clean, pushed repo. Buttons gain live counts in
their labels and titles.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Detached popouts re-implemented their tab bar, so split/merge drags
diverged from the main window: a plain 80px reorder margin instead of
the dashed drop-placeholder + .drop-target wash, and no drop-in landing
flourish on merge/split/move.

Reuse the same code in both windows:
- Extract the drop-placeholder into a shared TabDropPlaceholder used by
  TabBar and DetachedCenterPanel; drop the REORDER_GAP margin.
- Wire useTabLandStore into DetachedCenterPanel on the same cross-group
  rules commitDrop uses (merge/split/move land; same-group reorder does
  not).
- Carry an optional landedKey on the detached seed so a tab docked INTO
  a popout from another window plays the landing too.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ndow drop

Two multi-pane ("Phase 4") popout fixes:

1. Restart respawn — a SPLIT popout was persisted untagged
   (withDetachedDocked only tagged single-group popouts), so on restart it
   re-docked into the main panel instead of reopening as a floating window.
   Now split nodes carry the detached tag through prune/deserialize, the
   liveIds filter checks splits too, and detachGroup re-detaches a whole
   split subtree by id (new findSplit/removeNodeById helpers).

2. Cross-window drop into a split popout — dropping a tab/file from the
   main window always landed in the first pane and highlighted the whole
   window. The host now resolves the pane under the cursor SYNCHRONOUSLY
   from the popout's reported geometry (DETACHED_PANES_REQUEST/PANES +
   resolvePaneTarget) — no release round-trip race — and docks into that
   specific pane via dockTabIntoDetached(target)/placeKeyInTree (body edge
   splits, bar merges). The popout renders the host-resolved target as its
   per-pane preview; the whole-window highlight is now an outline only.

Shared detachedDropTargets.ts session drives both tab (TabBar) and file
(FileTree/commitFileDrop) drops. Tests: SplitPopoutRespawn,
FileDropIntoPopout, ResolvePaneTarget, plus targeted-dock cases in
SubwindowDetach and an updated DetachedSplit assertion.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Replace the per-Ollama-model tab list with one active local model:

- Add a Local Model button in the header, left of the global-apps button
  (LocalModelMenu) — hover to pick from installed models (reusing the
  existing list_ollama_models / ollama_is_installed commands); selecting
  writes settings.ollama_model. Only shown when Ollama is installed.
- TabBar's add menu now offers ONE "Local Model" entry that launches the
  active model, instead of listing every installed model (drops the
  list_ollama_models fetch + ollamaModels/loading/error state).
- Expose ollama_model in the frontend Settings type (the backend field
  already round-trips through save_settings/get_settings).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add agent-CLI registry/install flow (commands/agents.rs) and expand the
Ollama command surface to launch local Ollama-backed agent tabs (Claude
Code, Hermes, OpenClaw, OpenCode) alongside the existing vibe local agent.
Add per-file-type autocomplete completion modes (Sentence/Block/Scope)
across the native viewers, with live Shift+Tab cycling and word-by-word
accept. Drop StatusLamp; update LocalModelMenu, settings panels, themes,
and types accordingly.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01T3S32t1qajiDAFoCtfBz3Q
…cker

Add in-app markdown editing (markdownEdit), viewer formatting helpers
(viewers/format), and an Ollama-backed grammar/format command path.
Add a context file picker for embeds, expand FileViewerPane, and drop
the unused HtmlView. Wire new settings field and tab/right-panel hooks.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014KtzbfNxf4S4KJMcz3e5dX
Wire OpenClaw into the Ollama local-model pipeline as a launch-only
LOCAL_DRIVERS entry (`ollama launch openclaw --model <m>`; no hand-rolled
fallback — `ollama launch` installs and stands up its gateway against the
local endpoint). Also register OpenClaw as a standalone installable agent
in commands/agents.rs (`npm install -g openclaw`, bin `openclaw`) and in
AGENT_ITEMS/AGENT_CMDS so it shows in the regular agent add-menu. Update
the settings glossary and module docs to list it.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01T3S32t1qajiDAFoCtfBz3Q
Bump version to 0.1.5 across package.json, src-tauri/Cargo.toml, tauri.conf.json (+Cargo.lock), and source the header's displayed version from package.json so the UI tracks every bump. Release the GitHub Release job on every v* tag, not just v0.<minor>.0.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018Bfukb8GNY3z64ibZ8Yc98
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018Bfukb8GNY3z64ibZ8Yc98
Use a real grep binary and fail loudly on scan-tool error, so a shell that shadows grep (ugrep wrapper) can no longer make the scan silently pass.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018Bfukb8GNY3z64ibZ8Yc98
pdfjs-dist's package.json exposes only `main` (no `exports`/`module`),
which Vite's package-entry resolver handles inconsistently across
platforms and fails on Windows ("Failed to resolve entry for package
pdfjs-dist"). Add a regex-anchored resolve.alias so the bare specifier
points straight at the file `main` references, leaving the `?url` worker
subpath import untouched.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
When the only/last tab of a subwindow is dragged, that subwindow now
closes live during the drag (siblings reflow to fill) instead of
lingering until the drop:

- dragPreview.ts: pure `dragPreviewLayout` helper that prunes the
  lone-tab source group from the rendered tree (no-op for multi-tab
  sources, the only subwindow, non-tab drags, or while fullscreen).
- CenterPanel: render + measure off this preview layout. Render-only —
  the store layout is untouched, so an aborted drag restores instantly
  and the dragged tab's pane stays mounted (PTY survives).
- TabBar: hold the drag's pointer capture on the document root, not the
  dragged tab, so collapsing (unmounting) the source mid-gesture can't
  drop the capture / fire a spurious pointercancel on Win/macOS.
- DragPreviewCollapse.test.ts: unit coverage for the helper.

Also bundles in-progress cross-platform (Windows) work already present
in the working tree.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…aths

Make the cross-platform paths actually work on Windows:
- detach: apply restore geometry as PHYSICAL px (frontend canonical space)
  so popouts land on-screen on scaled displays; marshal show/resize nudge
  onto the main thread.
- agent_session: PowerShell SessionStart hook + `powershell -File` command
  on Windows; POSIX sh unchanged.
- openvpn: real best-effort tunnel management on Windows (resolve
  openvpn.exe, askpass flow, taskkill teardown) replacing the stub.
- ssh_mount: drive SSHFS-Win/WinFsp; cfg-gate fusermount/proc-mounts to
  unix, add Windows mount-state/teardown.
- tex.ts: route path math through lib/paths helpers so backslash/Windows
  absolute paths resolve correctly; tests added.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…c Windows support

- subwindow: make detach_subwindow async — a sync command blocks the main
  thread that WebView2's create_controller callback needs, deadlocking the
  popout into a blank white window on Windows (wry#583/tauri#4121).
- DetachedCenterPanel: move borderless popouts via the native OS window drag
  on Windows (the custom poll+setPosition gesture can't move the window
  there); swap heavy pane content for a cheap placeholder during the native
  move so WebView2 keeps the surface aligned with the frame.
- SetDefaultAppDialog: lazily resolve and show per-app icons (Windows shell
  icon / Linux theme icon) for the apps currently filtered.
- themes.css: move-placeholder + app-row icon/button styling.
- README: document native Windows support (workspace parking, app launch,
  default apps, downloads, OpenVPN, SSHFS-Win, agent resume) and refresh
  viewer/platform status.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add a navigable 3D project/box cloud as a new tab kind ("projects3d"),
offered from the + menu in the root scope when projects exist and seeded
as the default tab when the root scope is entered. Cards orbit/zoom via
CSS 3D transforms (no new dependency); clicking a project activates it and
a box opens it. Bumps package.json, Cargo.toml, and tauri.conf.json to
0.1.6, plus the current working-tree state.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The frontend tests had drifted behind the components they cover, plus
jsdom was missing shims the newer UI code relies on. Fix all 19 real
failures and the exit-code-1 left by uncaught Tauri-API rejections.

- Add src/test-setup.ts (wired via vitest setupFiles) with global jsdom
  shims: a ResizeObserver no-op (TabBar overflow tracking), a CSS.escape
  polyfill (TabBar drag hit-testing — its absence silently broke the
  split pipeline), and inert __TAURI_INTERNALS__ /
  __TAURI_EVENT_PLUGIN_INTERNALS__ stubs so unmocked listen()/invoke()
  calls don't throw uncaught rejections that fail the run's exit code.
  Also raise Testing Library's asyncUtilTimeout to absorb load spikes.
- vitest.config.ts: bump testTimeout/hookTimeout to 20s — heavy viewer
  renders and real-timer polls were tripping the 5s default under the
  full suite's parallel CPU load.
- AppShellClose: mock the new win.onScaleChanged listener.
- DragDropSplit: mock @tauri-apps/api/window + /event (CenterPanel's
  detached-drag effect needs getCurrentWindow/listen/cursorPosition).
- FileTreeNav: New File moved to the file-tree background context menu;
  right-click there, and mock git_unpushed_commits (null -> .length crash).
- AutoReload/ImageAutoReload: widen the real-timer poll waitFor budgets.

All 89 files / 713 tests pass; tsc --noEmit clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0161dwKecZYT2fc3EVizQqPV
Add an onboarding tour with coachmarks (TourHost/TourCoachmark, tour
store + lib), a Lessons menu, and a tree-style git change view
(GitChangeTree). Introduce a platform abstraction and file-access
helper, plus macOS entitlements/config and CI packaging updates.
Themes, viewers, paths, shortcuts, and SSH/OpenVPN services refined.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013s8uJKV8A99ZcqUVNYtWC4
…on, blob polish

- Add sftp service + remoteConnect helper for remote project browsing
- Rename github.rs → git_publish.rs; generalize publish flow
- Refactor SSH command/mount/exec surface and remote project section
- Add docker-sandbox lesson to the catalog (+ test)
- Expand ProjectBlobPane 3D root tab and theme styling
- OpenVPN service updates, settings/UI and capability schema sync

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NmvRfNfesikVofoaREZHnV
fseiffarth and others added 30 commits July 17, 2026 20:41
…shot

Broad snapshot across remote, terminal, monitoring, and file-viewer work:
- Multi-host remote projects (worker_sync, remote_usage, RemoteMachinesWindow)
- tmux-backed persistent shell sessions (local + remote), Sessions view
- System monitoring: gpustat/sysstat/net_usage expansion, SystemMonitorPane
- Custom agents (CustomAgentDialog/CustomAgents), shell-script run flow
- File viewer refactor (CompareView, FileViewerPane, SyncMergeView, FileTree)
- Remote-usage warnings, local-loss surfacing, terminal control/bus plumbing

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TecnBhmTjeuHqbBxJfLdxk
CI: the Windows backend build failed with E0432 (unresolved import
`windows::Win32::System::Pipes`) — services/openvpn.rs uses PeekNamedPipe /
SetNamedPipeHandleState for the OpenVPN Interactive Service named-pipe IPC but
the `Win32_System_Pipes` feature was never enabled on the target-gated `windows`
dep. Add it.

GitChangeTree flyout on-screen clamp: measure the box with its own transform
cleared instead of `rect − shiftX`, so the correction is a fixed reference and
converges in one pass. `rect − shiftX` converges in a real browser but diverges
by `margin` every render in an env that doesn't reflect the transform into
layout (jsdom under test) — an infinite render loop that reddened 4 tests.

Also carries in-progress work already in the tree: tab-close is now a
non-destructive tmux detach (kill only via the Sessions view ×), tmux session
names minted in split/detach paths, table-viewer column resize, and the
tmux-reattach identity-reply suppression in TerminalView.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TecnBhmTjeuHqbBxJfLdxk
`local_discovery_finds_every_venv_in_the_tree_not_only_the_root` built its
expected nested path from a `"services/api/.venv"` literal, which keeps forward
slashes on Windows — but discovery emits the relative path with the OS
separator (backslash), so the string compare failed there. Build the expected
path from PathBuf components so it matches on every platform. Test-only.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TecnBhmTjeuHqbBxJfLdxk
…ewers

- Slurm job submission/monitoring + HPC pipeline wizard (commands/slurm.rs,
  lib/slurm.ts, stores/hpcJobs.ts, hpcPipeline.ts, HpcPipelineWizard.tsx)
- Global machines registry + header MachinesIndicator (global_machines.rs,
  schema/global_machine.rs, stores/globalMachines.ts)
- Remote folder browser + reusable browse hook (RemoteFolderBrowser.tsx,
  useRemoteBrowse.ts, lib/remoteHosts.ts, stores/runHostPref.ts)
- Tab locality badges + per-host run preference (TabLocalityBadges.tsx)
- New viewers: YAML grid (YamlGrid.tsx, viewers/yamlGrid.ts), PDF outline
  (pdf/outline.ts), presentation overlay (PresentationOverlay.tsx)
- System monitor + remote-usage warning refinements
- Tests for Slurm, YamlGrid, PdfOutline, YamlViewer

The HPC wizard and slurm glue are cluster-agnostic: no institution-specific
hostnames, presets, or identifiers.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0184T6Pj4JrxFgjtaij9uE9n
Frontend
- Add an i18n layer (src/lib/i18n.ts) with a language setting in Settings.
- Global machine monitoring: GlobalMachineMonitorDialog plus a dedicated
  store, surfaced from the Machines menu.
- Machine list import/export and reordering (src/lib/machineSync.ts); the
  export writes host/port/label only, never a username or password.
- Remote auto-reconnect (src/lib/remoteAutoReconnect.ts) and a hostBusy
  store so a working host reads as busy rather than idle.
- File tree shows directory sizes, with a per-view setting.
- Theme work: fancy_dark becomes the default colour scheme.

Backend
- Global machine commands, remote usage sampling and sysstat session
  parsing; OpenVPN and SSH command updates.

Fixes
- globalMachines.load(): .catch guards a rejection but not a command that
  resolves to nothing, which left `machines` non-iterable and crashed
  RemoteUsageWarningDialog. Guard with Array.isArray.
- Update the settings default-colour-scheme test to fancy_dark.

Privacy
- gitignore eldrun-machines.json: the Machines menu export defaults to that
  name and had dropped a file of real hostnames into the repo root.
- Drop a named HPC cluster from three comments; keep the wording
  cluster-agnostic.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…a polls

Severe hangs, all with the same shape: a synchronous Tauri command aimed
at a peer that will never answer, blocking until ssh's own keepalive gives
up (~45s) — and the file tree issues one per visible folder.

VPN drop gating
- vpnStatus.refresh now distinguishes a tunnel that died on its own from
  one torn down deliberately (every deliberate teardown forgets the config
  first, so only an unplanned death reaches the new branch).
- A dropped tunnel clears the status of the projects that were holding it,
  which flips useRemoteBlocked so probes are never dispatched rather than
  each paying the timeout. Scoped to the tunnel's holders: a project that
  never claimed the config reaches its host another way.
- The pooled backend session is deliberately left alone — reaping it is
  the pooled reader's job, and a teardown issued here would itself be a
  call over the dead connection.

Directory sizes (src/lib/dirSizeGuard.ts)
- Folder sizes are a best-effort display aid, so they are safe to bound
  aggressively: timeout, concurrency cap, and a per-project circuit
  breaker that opens after repeated failures.

Ollama status (src/lib/ollamaStatus.ts)
- Collapse the per-component polls into one app-wide timer.

Also: run-host preference handling for shell/python runs, and backend
project/git/openvpn updates.

Tests: DirSizeGuard, VpnDropGating, ShellScriptRun.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
prerelease
- Every release was published with `prerelease: true`, and GitHub never
  marks a pre-release as "Latest". `/releases/latest` therefore 404s — the
  exact link README.md:121 sends users to for a download. Publish as a full
  release; the notes still say alpha, this flag is about discoverability.

macOS asset name
- The DMG was renamed to `Eldrun-<sha>-universal.dmg` while the AppImage,
  deb and exe all carry the version, leaving the one asset a user couldn't
  tie to a release at a glance. Name it `Eldrun_<version>_universal.dmg`.
- The move is now guarded: Tauri may already emit exactly that name, and
  `mv x x` fails. The upload glob widens to `*universal.dmg` so it matches
  either separator.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…emote-features opt-in

- OpenVPN: every tunnel Eldrun starts now carries a loopback management
  socket so disconnect asks the daemon to SIGTERM itself instead of a
  second pkexec prompt; falls back to the old kill path when the
  socket can't be used.
- Big folders: one-time census (local + host du) on new/imported/
  extended remote projects, defaulting giant folders to excluded from
  byte-sync rather than silently hauling them into the mirror.
- VPN/machines indicators are now gated behind an explicit opt-in
  (Settings' "Remote features"), prompted once via RemoteFeaturesPrompt.
- Misc: i18n additions, file-tree row cap, terminal theme renderer test.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QJxJaJuNGEt9jn8jnXYHFW
config_declaring_management_is_detected calls arm_management, which is
unix-only — the test compiled fine on Linux/macOS but broke the Windows
test build. Matches the cfg(unix)/cfg(target_os = "linux") pattern
already used by the neighboring management-socket tests in this file.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QJxJaJuNGEt9jn8jnXYHFW
…, i18n groundwork

Snapshot of accumulated work on develop:

- Deck presenter: native *.eldeck.json editing and presenting (stage, slide
  view, inspector, notes, TeX panel, icon picker, snap/transform, export,
  sidecar, GIF playback) plus the dual-window audience view behind
  open_presenter_window.
- HPC support: hpc_hosts tag and careful_hosts classification, HPC guard
  dialog and prompt store, remote workspace commands (hpc_ws), and the
  toggles that drive them.
- Credentials: keyring helpers, credential paste bar, host-key confirmation
  dialog and store for first contact, terminal sign-in toggle.
- Git: fork command (git_fork), publish-from selection for work-remote
  projects.
- i18n: translation groundwork and TODO group N with the plan doc.
- docs/context/*: per-subsystem design rationale split out of CLAUDE.md.

Test fixes:
- AppShellClose test mocked useSettingsStore without getState, which the
  auto-reconnect sweep reads imperatively; the resulting unhandled rejection
  is gone.
- Scrubbed a real home path and username from the i18n plan doc and two test
  fixtures ahead of the privacy check.

Verified: tsc clean, 2016 vitest tests pass, all cargo test suites pass,
scripts/privacy-check.sh reports only expected matches.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Hi5Wn4w71MJezWadstSnrY
- ShellScriptRun test used a real lab machine label as its run-host fixture;
  now a generic worker id, matching the alice/gpu fixtures around it.
- The careful-mode doc attributed its quoted usage rules to a named
  university; the reasoning is not site-specific, so the attribution is now
  generic.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Hi5Wn4w71MJezWadstSnrY
… tests

Privacy:
- Test fixtures and incident comments named a real project. Renamed to a
  neutral placeholder across the frontend tests, the Rust service tests, and
  the comments in tabs.ts / terminal_service.rs / git_peer.rs.

Flaky tests:
- sysstat's cache-mechanics tests seed a synthetic DESCENDANT_CACHE entry
  under a private CACHE_TEST_LOCK, but terminal::tests::kill_reaps_the_child_
  subtree spawns a PTY and calls invalidate_descendant_cache in a poll loop —
  in the same test binary, on another thread, unable to take a lock private to
  sysstat::tests. A concurrent generation bump turns the seeded cache hit into
  a miss and the assertion fails.
- The lock is now module-level and pub(crate), and the PTY test takes it too.
- Acquisition goes through lock_cache_for_test, which tolerates poisoning: one
  genuine assertion failure used to poison the lock and fail every later cache
  test on the poison rather than on its own behaviour, which is why these
  always failed in pairs.

Verified: tsc clean, 2016 vitest tests pass, all cargo suites pass,
privacy-check reports nothing.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Hi5Wn4w71MJezWadstSnrY
remote_tmux_list only scoped by host, never by project, so two remote
projects sharing a login node saw each other's tmux sessions. Session
names now embed the owning project id (eldrun-<projectId>--<uuid>),
and remote_tmux_list filters the host's tmux ls output down to the
requesting project's own sessions plus unattributable ones (foreign
hand-started sessions, legacy pre-scoping eldrun-<uuid> sessions).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KPdhSvAcWJyBc5K9C5sgGz
…machine sync

Closes three reported bugs in the remote-connect path:

- An HPC-tagged login node was dialled unattended. `ssh_common` now carries an
  authorization registry so a background dial at a tagged target is refused,
  and the refusal is surfaced (`ELDRUN_HPC_GUARD`) rather than swallowed.
- An ordinary connect destroyed an already-saved SSH password. The saved-
  credential read is now a tri-state (`saved` / `notSaved` / `unreadable`) via
  `remote_saved_password_state` + `useSavedCredential`, so a locked keyring no
  longer reads as "nothing saved" and no longer licenses a clearing write.
- A global machine turned green while the project holding it stayed
  disconnected. `lib/machineSync` reconciles on a subscription over the
  machine's `status` rather than at the two call sites that used to do it by
  hand, and `reachable` (a probe) is kept distinct from `status` (a session
  this app opened).

Also: first-contact host-key confirmation (`lib/hostKeyOnce`), the shared
`SavePasswordRow` / `autoConnectEligibility` pieces behind the connect
dialogs, and i18n coverage for the machines/VPN surfaces.

`useSavedCredential` no longer destructures the keychain answer blind — an
empty answer from the bridge read as an unhandled rejection inside an
unawaited promise, leaving the row on "checking" with nothing on screen.

Deferred follow-ups from the audit are recorded as TODO G.24.

Gates: tsc clean, cargo test 1138 passed, vitest 2017 passed (0 unhandled
errors), privacy scan reviewed — all hits are param/field names or fixtures.
Not manually tested against a live cluster; see the G.24 manual-QA item.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KPdhSvAcWJyBc5K9C5sgGz
`scripts/bump-version.sh` rewrites package.json, src-tauri/Cargo.toml and
tauri.conf.json but not the lockfile that records the same version, so the
tree comes back dirty after every auto-bumped push.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KPdhSvAcWJyBc5K9C5sgGz
The bump rewrote package.json, src-tauri/Cargo.toml and tauri.conf.json but
not Cargo.lock, which records the same version for the workspace's own
package. Cargo rewrites that entry the next time it runs, so every
auto-bumped push committed a lockfile one version behind and handed the tree
back dirty — the bump commit and the lockfile could never both be clean.

The lockfile edit is matched on the block's own `name = "eldrun"`, never on
the version string, so a dependency sitting at the same version is not
rewritten with us. A missing lockfile is skipped rather than fatal: it is a
generated file, and a fresh clone must still be able to bump.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KPdhSvAcWJyBc5K9C5sgGz
bump-version.sh now rewrites the lockfile's own package entry, but the hook
staged only the other three files — so the bump commit went out without it and
left the very dirty tree the previous commit set out to stop.

Kept to an explicit file list (behind `--`): a push must never sweep up
whatever else happens to be sitting in the working tree.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KPdhSvAcWJyBc5K9C5sgGz
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant