Commit Graph
100 Commits
Author SHA1 Message Date
vasyansk 9db52595c7 Add update check functionality
Implement version checking and update notifications in the GUI
2026-06-15 14:23:30 +07:00
vasyanskandClaude Opus 4.8 4c9eacccb7 fix(deploy): put landing on proxy's network + runtime DNS resolve
The landing service had no networks: key, so it joined the auto 'default'
network while proxy was only on spaceshell-network + webproxy — they shared no
network, so proxy_pass to 'landing' couldn't resolve. With a static
upstream{ server landing:80 } nginx fails to boot on an unresolvable name and
restart-loops, so the proxy flapped (page intermittently up/down). Fixes:
- landing now joins spaceshell-network (shared with proxy).
- proxy.conf resolves 'landing' at request time via Docker DNS (127.0.0.11)
  using a variable proxy_pass, so nginx starts even if landing is briefly down.
nginx -t passes.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-15 14:20:33 +07:00
vasyanskandClaude Opus 4.8 1423150b10 docs: repoint README image/doc links to DOCS/ after the move
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-15 14:13:26 +07:00
vasyanskandClaude Opus 4.8 1b8dd9bd93 feat(app): make 'Mark all read' an icon (CheckCheck) next to the trash
Matches the clear-all trash icon; dimmed/disabled when there are no unread events.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-15 14:12:45 +07:00
vasyanskandClaude Opus 4.8 524b3def6b docs: move the user guide to the root README.md
Promotes DOCS/GUIDE.md to the repo root README (image/links repointed to DOCS/).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-15 14:12:45 +07:00
vasyanskandClaude Opus 4.8 a9af60f5cd docs: Russian user guide with screenshots
DOCS/GUIDE.md — feature walkthrough with the two app screenshots from
landing/pics copied into DOCS/images.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-15 14:09:42 +07:00
vasyansk 179744d8b3 fixes port
Build / Build & push landing (push) Successful in 16s
Build / Deploy to prod (push) Successful in 11s
Build / Notify Max (push) Successful in 1s
2026-06-15 14:05:18 +07:00
vasyansk e15146af60 Merge fix-launch-delay: no blocking handshake, fire-and-forget shutdown, .app-only reinstall 2026-06-15 13:58:05 +07:00
vasyanskandClaude Opus 4.8 0a26e77899 fix(app): drop blocking version-handshake; Shutdown is fire-and-forget
The handshake ran synchronously in Bridge::connect: on a build-id mismatch it
sent Cmd::Shutdown and awaited a reply that never flushes (the daemon exits
first), so request() hit its 5s timeout and the reconnect-retry respawned the
daemon and re-sent Shutdown — a loop that produced repeated 'spaceshd
listening' lines and a multi-second launch delay. The id stamps also differed
between the separately-built daemon and GUI, so it fired on normal launches.

- Remove the handshake auto-restart; `make install`/`reinstall` already kill
  and replace the daemon reliably. health.build stays for display in Settings.
- Shutdown now goes through a fire-and-forget send (no reply wait, no retry),
  fixing the same loop for the Settings Restart button.
- Makefile: `make app-bundle` builds just the .app via `tauri build --bundles
  app` (no .dmg, no hdiutil) and `reinstall` uses it — faster self-update that
  can't hang on a mounted DMG volume.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-15 13:58:04 +07:00
vasyansk 75134b6fac add deploy
Build / Build & push landing (push) Successful in 15s
Build / Deploy to prod (push) Successful in 5s
Build / Notify Max (push) Successful in 1s
2026-06-15 13:47:50 +07:00
vasyansk 09e7a2b526 Merge sidebar-rail: collapsed icon rail 2026-06-15 13:41:05 +07:00
vasyanskandClaude Opus 4.8 5d7a80e2a2 feat(app): collapsed sidebar becomes an icon rail (keeps activity visible)
Toggling the sidebar off used to hide it entirely, losing the per-workspace
status rings. It now collapses to a 48px rail showing each workspace's
aggregate status ring (and unread dot), still clickable to switch, plus the
new-workspace button and the daemon live/offline dot. Full sidebar returns
when toggled back on.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-15 13:41:05 +07:00
vasyansk 569aa39444 Merge events-clear-and-settings-x: clear events + settings close button 2026-06-15 13:38:35 +07:00
vasyanskandClaude Opus 4.8 f9a565a712 feat(app): clear all events from the Event Center (red trash icon)
Adds Cmd::ClearEvents + Evt::EventsCleared: the daemon drops the persistent
event log (keeping next_id monotonic), persists, and broadcasts so every
client empties its list. A red trash icon next to 'Mark all read' triggers it;
disabled when the list is empty. Threaded through proto, the daemon handler,
the Tauri bridge, and socketBridge. Includes an EventLog::clear test.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-15 13:38:35 +07:00
vasyanskandClaude Opus 4.8 bcc88b6be7 fix(app): add a close (X) button to the settings modal
Esc and click-outside already closed it, but there was no visible affordance.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-15 13:38:35 +07:00
vasyanskandClaude Opus 4.8 3dc3da072c fix(app): make the bell badge click-through (number opens the log too)
pointer-events:none lets clicks/hover pass through the unread badge to the
bell button beneath, which the badge was previously swallowing.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-15 13:31:47 +07:00
vasyansk 897a3be659 Merge version-handshake: auto-restart stale daemon on GUI launch 2026-06-15 12:39:46 +07:00
vasyanskandClaude Opus 4.8 cf7410b46a feat(app): version handshake — GUI restarts a stale running daemon
The daemon outlives the GUI, so after an update an OLD daemon can keep serving
the socket and the new GUI just connects to it (stale code — e.g. the missing
TERM fix). Both binaries are now stamped with the git build id (build.rs):
the daemon reports it in `health.build`, and on connect the bridge compares it
to the GUI's own SPACESH_BUILD; on mismatch it shuts the daemon down and lets
ensure_daemon respawn the bundled (matching) one. No-op for unstamped dev
builds or daemons too old to report a build. Build id is shown in Settings.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-15 12:39:46 +07:00
vasyanskandClaude Opus 4.8 8f431eaa40 fix(build): clean sidecar dir each build; native-focused install/reinstall
The stale bin/spaceshd-universal-apple-darwin sidecar (left over from an
earlier approach) poisoned the universal bundle — tauri shipped that old
daemon instead of the freshly built one, so the packaged daemon lacked the
TERM fix. dmg/dmg-native now wipe the sidecar dir first. install copies the
native bundle (was preferring the universal one, which could be stale) and
kills the running daemon; reinstall = native rebuild + install for fast
self-updates. Universal stays for distribution via dmg / install-universal.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-15 12:34:57 +07:00
vasyanskandClaude Opus 4.8 79b47d42e7 build: make kill-daemon/install/reinstall — daemon survives reinstall
Rebuilding the .app never replaced the RUNNING daemon (it outlives the GUI),
so a stale spaceshd kept serving old code (e.g. the pre-TERM-fix daemon).
`make install` now stops the daemon, copies the fresh bundle to /Applications,
and clears quarantine; `make reinstall` does dmg+install in one shot.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-15 12:26:49 +07:00
vasyansk df0389b38f Merge fix-double-echo: single reader across reconnects 2026-06-15 11:56:35 +07:00
vasyanskandClaude Opus 4.8 c84b96abc0 fix(app): abort the old reader on reconnect (fixes doubled keystroke echo)
reconnect() spawned a new reader/writer but left the previous reader task
running. A reconnect triggered while the old connection was still alive (e.g.
a request timing out during a slow daemon start) left TWO live connections;
the daemon broadcast Output to both, so every byte — including input echo —
arrived twice ("ccucurcurl"). The bridge now stores the reader's JoinHandle
and aborts it before establishing the new connection, guaranteeing a single
live reader.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-15 11:56:35 +07:00
vasyansk ee969371c9 Merge rename-and-term: workspace rename + TERM env fix 2026-06-15 11:47:21 +07:00
vasyanskandClaude Opus 4.8 07cf7f9ed4 fix(pty): always set TERM/COLORTERM for spawned shells
A GUI/launchd-spawned daemon has no TERM in its environment, so child shells
inherited none and tput/zsh/ncurses failed ('tput: No value for $TERM').
The PTY now defaults TERM=xterm-256color and COLORTERM=truecolor (matching
xterm.js) unless the caller already provides them. Adds a regression test.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-15 11:47:21 +07:00
vasyanskandClaude Opus 4.8 a929c166a3 feat(app): rename a workspace by double-clicking its name
Double-click a sidebar workspace name to edit it inline; Enter/blur commits
via setWorkspaceMeta({name}) (empty/unchanged is a no-op), Esc cancels. The
input stops pointer/key propagation so it doesn't trigger select or drag.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-15 11:47:21 +07:00
vasyanskandClaude Opus 4.8 99a916fed6 fix(bundle): provide per-arch spaceshd sidecars for universal build
Tauri's universal target builds each arch separately and resolves externalBin
with that arch's triple (spaceshd-aarch64-apple-darwin / -x86_64-apple-darwin),
lipo'ing them itself. The previous single -universal-apple-darwin sidecar made
the per-arch sub-build fail with 'resource path ... doesn't exist'.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-15 11:41:57 +07:00
vasyansk 2fc58105a5 Merge bundle-daemon: package spaceshd in the macOS app 2026-06-15 11:39:03 +07:00
vasyanskandClaude Opus 4.8 a7272fc92e fix(bundle): ship spaceshd inside the .app (packaged GUI was offline)
tauri build bundled only the GUI binary, so the packaged app had no daemon:
find_daemon() looks for a sibling `spaceshd` next to the GUI
(Contents/MacOS/spaceshd) and ensure_daemon failed to spawn it → "offline".
(Dev worked only because find_daemon falls back to the repo-root target path.)

- tauri.bundle.conf.json: a build-only overlay adding bundle.externalBin
  ["bin/spaceshd"], kept out of tauri.conf.json so `tauri dev` doesn't require
  a sidecar file.
- Makefile: `make dmg` now builds spaceshd for both arches, lipo's a universal
  sidecar into src-tauri/bin/spaceshd-universal-apple-darwin, and passes
  --config so it lands in Contents/MacOS/spaceshd. `make dmg-native` does the
  host-arch equivalent.
- .gitignore: ignore the generated app/src-tauri/bin/.

After install, the unsigned helper runs once quarantine is cleared recursively:
xattr -dr com.apple.quarantine /Applications/spacesh.app

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-15 11:39:03 +07:00
vasyansk df6eabcd32 Update VERSION
Build / Build & push landing (push) Successful in 18s
Build / Notify Max (push) Successful in 2s
2026-06-15 10:58:31 +07:00
vasyansk d9ea6206c8 Merge ci-landing-only: Gitea builds landing only, DMG is local 2026-06-15 10:57:22 +07:00
vasyanskandClaude Opus 4.8 8015f329ed ci: drop macOS DMG job — build the .dmg locally via make
No self-hosted macOS runner exists and Tauri can't cross-compile a macOS
bundle on Linux, so the DMG is produced locally with `make dmg`. The Gitea
workflow is now landing-only (build & push the nginx image + Max notify);
removed the dmg job, the changes/paths-filter job, and the app/crates triggers.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-15 10:57:22 +07:00
vasyansk 4dad6075a5 Merge makefile: local build helpers 2026-06-15 10:55:48 +07:00
vasyanskandClaude Opus 4.8 78b2e2a162 build: Makefile for local builds (DMG, dev, daemon, tests, landing)
No macOS CI runner available, so the universal .dmg is built locally:
`make dmg` (adds the rust targets + tauri build --target universal-apple-darwin).
Also: deps, dmg-native, dev, daemon, test, landing-image/run/push, clean.
`make` / `make help` lists targets.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-15 10:55:48 +07:00
vasyansk ad09ea6c01 Merge landing-ci: landing site, nginx image, Gitea CI for landing + DMG 2026-06-15 10:54:11 +07:00
vasyanskandClaude Opus 4.8 2f2159a468 feat(landing): static site + nginx image + Gitea CI (landing + macOS DMG)
- landing/: the spaceshell.ru terminal-dark landing (index.html + screenshots),
  containerized as an nginx:alpine image (Dockerfile + nginx.conf with gzip and
  asset caching, VERSION, .dockerignore).
- .gitea/workflows/build.yaml: adapted from the coddykinder pipeline to this repo.
  Path-gated jobs — `landing` builds & pushes the nginx image to the Gitea
  registry on landing changes; `dmg` builds a universal (Intel + Apple Silicon)
  .dmg via `tauri build` on app/crates changes and uploads it as an artifact;
  Max notification summarizes both. Tags build everything (release).
- DOCS/landing/spaceshell-landing.md: build brief + copy + SEO meta.

Notes: the DMG job needs a self-hosted macOS runner labelled `macos` (Tauri
can't cross-compile macOS from Linux); the DMG is unsigned until Developer ID
secrets are wired. Landing image verified locally (HTTP 200, assets served).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-15 10:54:11 +07:00
vasyansk a9836f28b7 Merge bridge-reconnect: GUI self-heals after daemon restart 2026-06-15 10:22:24 +07:00
vasyanskandClaude Opus 4.8 9ca0164d0b fix(app): bridge auto-reconnect so daemon restart no longer bricks the GUI
The Tauri bridge connected to the daemon once at startup and held a single
stream with no recovery: when the daemon exited (Restart/Stop, crash, or an
update), the reader emitted spacesh:disconnected and died, and every later
request went through the dead writer forever — the GUI was permanently stuck
(settings frozen, offline). Since the bridge is Rust-side state that survives
a webview reload, even Cmd+R didn't recover it.

- bridge.rs: requests now reconnect-and-retry on failure with a single-flight
  guard (generation counter) so concurrent failures collapse into one
  reconnect and never open duplicate connections; a 5s reply timeout catches
  silently-dropped connections. ensure_daemon respawns the daemon if it
  exited. On success the bridge emits spacesh:reconnected.
- App.tsx: on spacesh:reconnected, bump a connection epoch that keys
  LayoutEngine, remounting terminals so they re-attach (snapshot + live stream)
  to the restarted daemon; also reload health/config/status.
- Settings: drop the Stop button — with lazy daemon spawn any GUI request
  resurrects the daemon, so an in-GUI "stop" is contradictory. Restart now
  works end to end (shutdown → reconnect respawns → panels re-attach).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-15 10:22:24 +07:00
vasyansk 99f5708cbf Merge settings-bugfixes: live font apply + daemon uptime refresh 2026-06-15 10:08:59 +07:00
vasyanskandClaude Opus 4.8 f8d3876c68 fix(app): settings live-apply — font on open terminals, daemon uptime
- Font change now applies to already-open terminals: the WebGL renderer
  caches glyphs in a texture atlas keyed by the old font/size, so the live
  re-apply effect now calls webglAddon.clearTextureAtlas() (via a new ref)
  after updating fontFamily/fontSize, before refitting.
- Daemon uptime now reflects a restart: the Settings daemon section ticks
  every second for live uptime, and Stop/Restart trigger an onReload callback
  that re-fetches health/status in App so a restarted daemon's new
  started_at_ms is shown instead of the stale value.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-15 10:08:59 +07:00
vasyansk b63ed2ea83 Merge settings-modal: daemon config, Get/Set/ConfigChanged, CSS-var theming, settings modal with Stop/Restart 2026-06-15 09:05:45 +07:00
vasyanskandClaude Sonnet 4.6 5e6cf4d982 fix(app): settings review — startup theme default, slider/shell input UX, dedupe accents, memoize palette
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-14 19:10:19 +07:00
vasyanskandClaude Sonnet 4.6 9ca1ff3bc5 feat(app): daemon status with Stop/Restart in settings
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-14 18:57:53 +07:00
vasyanskandClaude Sonnet 4.6 a2087a0de5 feat(app): settings modal — terminal, appearance, shell
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-14 18:34:14 +07:00
vasyanskandClaude Sonnet 4.6 61c69adb17 feat(app): terminal font and xterm theme from daemon config
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-14 09:43:38 +07:00
vasyanskandClaude Sonnet 4.6 0f28be1300 feat(app): apply theme from daemon config on load and live
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-14 09:41:15 +07:00
vasyanskandClaude Sonnet 4.6 dc95381870 feat(app): CSS-variable theming with dark/light palettes and accents
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-14 09:39:07 +07:00
vasyansk b9f46a407d feat(app): socketBridge getConfig/setConfig + config_changed 2026-06-14 09:37:45 +07:00
vasyansk 62f1f8e9a8 feat(app): tauri get_config/set_config bridge commands 2026-06-14 09:36:53 +07:00
vasyansk ad29665352 feat(spaceshd): GetConfig/SetConfig handlers with live ConfigChanged broadcast 2026-06-14 09:35:27 +07:00
vasyansk c4746f9864 feat(proto): GetConfig/SetConfig commands and ConfigChanged event 2026-06-14 09:22:39 +07:00
vasyansk e990e694b5 feat(proto): ConfigView wire type 2026-06-14 09:21:22 +07:00
vasyansk 80113da066 feat(spaceshd): config terminal+appearance sections and save 2026-06-14 09:20:24 +07:00
vasyanskandClaude Opus 4.8 052f484142 docs: settings modal implementation plan
11 TDD tasks: daemon config model/save, ConfigView + Get/Set/ConfigChanged
protocol, bridge + socketBridge, CSS-var theming, TerminalView font/theme,
settings modal, daemon Stop/Restart.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-14 09:05:22 +07:00
vasyanskandClaude Opus 4.8 4aacebcc60 docs: settings modal design spec
Config in config.toml via daemon (Get/Set/ConfigChanged), low-churn CSS-var
theme switching (Dark/Light + accent), terminal font, default shell, and
daemon status with Stop/Restart.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-14 09:01:53 +07:00
vasyansk 5b08b204b6 Merge workspace-list-features: pinned/favorites, drag-reorder, delete-with-confirm 2026-06-14 08:56:31 +07:00
vasyanskandClaude Opus 4.8 a55555983b feat(app): sidebar favorites, drag-reorder, and delete-with-confirm
- FAVORITES section at the top collects pinned workspaces (removed from their
  group listing); a star toggle on each row pins/unpins via setWorkspaceMeta.
- Drag-to-reorder within a section using raw pointer events (HTML5 DnD is
  unreliable in the macOS WKWebView), with a drop-line indicator; on drop the
  section's `order` is reassigned sequentially and persisted. Cross-section
  drops are ignored (group membership unchanged).
- Trash icon on row hover opens a ConfirmDelete modal that shows the live
  terminal count and warns before terminating them, then calls close_workspace
  and re-points the active workspace.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-14 08:56:20 +07:00
vasyanskandClaude Opus 4.8 7b47052a6f feat(spaceshd): pinned workspace field
Add a `pinned` bool to the workspace model, threaded through proto
(Workspace + WorkspaceView + SetWorkspaceMeta), the registry, the
set_workspace_meta handler, persistence, the CLI mapping, and the Tauri
bridge. serde(default) keeps existing state.json compatible (pinned=false).
Backs the sidebar Favorites section.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-14 08:56:09 +07:00
vasyansk 2c8ac8ebac Merge fix-spawn-search: lazy PTY spawn, working search, prompt-dup fix 2026-06-14 08:34:57 +07:00
vasyanskandClaude Opus 4.8 04ac7cdec2 fix(app): working scrollback search + stop prompt duplication on focus
Search fixes:
- TerminalView sets allowProposedApi (the search addon's match decorations
  use registerMarker/registerDecoration); without it findNext threw before
  firing results, so the counter was stuck at 0/0.
- The search bar now renders inside the panel it targets (in the header)
  instead of a global top-right overlay, so it's obvious which panel is
  searched.
- Search is anchored to the panel it was opened on (searchSurfaceId) and no
  longer follows focus — opening it in one panel and switching away no longer
  shows it open elsewhere.

Prompt duplication:
- The focus border was 1px when unfocused, 2px when focused; with border-box
  that resized the content on every focus switch, firing ResizeObserver -> fit
  -> PTY SIGWINCH and making zsh/powerlevel10k reprint its prompt. The border
  is now a constant 2px, color-only on focus.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-14 08:34:43 +07:00
vasyanskandClaude Opus 4.8 a30ec1cc7f fix(spaceshd): lazy PTY spawn so prompts render at the correct size
A new surface spawned its shell immediately at the default 80x24, so the
shell (e.g. zsh + powerlevel10k) printed its first prompt before the GUI
fit-resized the panel. The post-print resize reflowed the grid, leaving the
prompt invisible until Enter and shifted by a line.

The surface actor now defers the child spawn: it waits for the first Resize
(spawning at that geometry) or, for headless/CLI surfaces that never attach a
GUI, falls back to the spec geometry after 250ms. Attaches received before
the spawn get an empty-grid snapshot plus a live subscription; pre-spawn
input is buffered and replayed. Adds two deterministic tests via `stty size`.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-14 08:34:28 +07:00
vasyansk 907df5b01c Merge backlog-polish: search fix, app icon, shell config, lock-test fix, GUI backlog 2026-06-14 08:01:47 +07:00
vasyanskandClaude Opus 4.8 58c75c71ae feat(app): GUI backlog — splitter, drag-reorder, fit, persist, modal focus
- LayoutEngine: fix splitter resize (track pointer 1:1 via delta-from-start)
  and add panel drag-to-reorder using raw pointer events with drop indicators
- TerminalView: auto-fit xterm to container via FitAddon + ResizeObserver
- App/TopBar: toggleable sidebar; persist sidebar/events collapse in
  localStorage; bell icon opens the activity log
- Wizard: new-workspace modal now grabs focus and handles keyboard
- deps: add @xterm/addon-fit

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-14 08:01:15 +07:00
vasyanskandClaude Opus 4.8 6a3875670a feat(spaceshd): configurable default shell
Add a config.rs module that loads optional ~/.spacesh/config.toml and a
default_shell() resolver: SPACESH_SHELL env -> config.toml default_shell ->
login shell from the passwd DB -> $SHELL -> /bin/sh. The passwd lookup
matters under launchd where $SHELL is absent. All plain-panel spawn sites in
server.rs now use the resolver. Adds toml + libc deps.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-14 08:01:04 +07:00
vasyanskandClaude Opus 4.8 0014d9358d feat(app): app icon and macOS bundle config
The dock showed a black square because tauri.conf.json had no bundle.icon
block and icons/ held only tiny placeholders with no .icns. Add an SVG
source logo (terminal prompt + split workspace panes), generate the full
icon set via `tauri icon` (icon.icns/.ico + all PNG/iOS/Android sizes), and
wire bundle.icon so the daemon embeds and macOS renders it.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-14 08:00:54 +07:00
vasyanskandClaude Opus 4.8 89373676e8 fix(app): incremental scrollback search
Search only ran on Enter; typing merely reset the counter to 0/0, so a
visible term showed no matches until the user pressed Enter. run() now takes
an optional query override and onChange fires it on every keystroke for
search-as-you-type, while Enter/Shift+Enter still navigate matches.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-14 08:00:45 +07:00
vasyanskandClaude Opus 4.8 21180ae9e0 fix(spaceshd): isolate instance-lock test via SPACESH_LOCK
lock_is_exclusive_within_process acquired the global ~/.spacesh/daemon.lock,
so it flaked whenever a real daemon was running. Add a SPACESH_LOCK env
override to lock_path() and point the test at a private temp file under a
serial() guard, making the suite deterministic regardless of a live daemon.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-14 08:00:35 +07:00
vasyanskandClaude Opus 4.8 cd44f0b263 Merge SP1+SP3+SP4: daemon health, scrollback search, panel zoom
- SP1: Cmd::Health (version/pid/uptime) → real sidebar live/uptime footer
- SP3: ⌘F scrollback search on the focused panel via xterm addon-search
- SP4: persisted per-workspace panel zoom (full-grid render, auto-clear on removal)
- 119 workspace tests green; frontend build clean

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-10 12:56:09 +07:00
vasyansk 8ea680d0df docs: SP1/SP3/SP4 manual scenarios and updated limitations 2026-06-10 12:55:07 +07:00
vasyanskandClaude Sonnet 4.6 ac3f0886d5 feat(app): scrollback search bar (⌘F) on the focused panel
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-10 12:48:03 +07:00
vasyansk 52a502c38b feat(app): load xterm search addon + surface→addon registry 2026-06-10 12:35:41 +07:00
vasyanskandClaude Opus 4.8 daf87d3c09 feat(app): panel zoom — full-grid render + header toggle
Wire Cmd::SetZoom through Tauri bridge (set_zoom command), add zoomed
field to WorkspaceView, short-circuit LayoutEngine to render only the
zoomed panel full-grid, and toggle Maximize2/Minimize2 in panel header.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-10 12:33:46 +07:00
vasyanskandClaude Sonnet 4.6 2b1ccaf31d feat: persisted per-workspace panel zoom (proto + daemon, auto-clear on removal)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-10 12:24:23 +07:00
vasyanskandClaude Opus 4.8 defceb1169 feat(app): real daemon health footer (live, uptime, version)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-10 12:09:35 +07:00
vasyansk f7763a84fc feat: Health command — version, pid, started_at (proto + daemon) 2026-06-10 12:06:38 +07:00
vasyanskandClaude Opus 4.8 f18d929c10 docs: SP1+SP3+SP4 implementation plan
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-10 11:57:45 +07:00
vasyanskandClaude Opus 4.8 a707895200 docs: SP1+SP3+SP4 design — observability, scrollback search, panel zoom
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-10 11:52:39 +07:00
vasyanskandClaude Opus 4.8 c9ed522230 chore(app): regenerate Tauri schemas for window-state permission
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-10 09:25:43 +07:00
vasyanskandClaude Opus 4.8 a5156859d6 Merge: persist window size/position via tauri-plugin-window-state
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-10 09:25:29 +07:00
vasyanskandClaude Opus 4.8 7d8e39ca3d feat(app): remember window size/position across restarts (window-state plugin)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-10 09:25:29 +07:00
vasyanskandClaude Opus 4.8 5fca6bfd09 Merge SP2: UI parity + persistent event log & read-model
- UI parity with Pencil mockup (top bar, panel cards, sidebar/event-center polish)
- Daemon-owned, disk-persisted event log (~/.spacesh/events.json) with read-flags
- Event Center sourced from daemon; real Unread/Errors tabs + bell unread badge
- 112 workspace tests green; frontend build clean

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-10 08:59:34 +07:00
vasyanskandClaude Opus 4.8 615b90e887 test(daemon): event log survives cold daemon restart
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-10 08:35:38 +07:00
vasyanskandClaude Sonnet 4.6 a8000323ec docs: SP2 manual test scenario and updated Event Center limitations
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-10 08:30:21 +07:00
vasyanskandClaude Sonnet 4.6 834d61c69a feat(app): daemon-sourced Event Center feed, read-model, bell badge
Source Event Center from daemon event_log (seed + live event/events_read push).
Unread/Errors tabs filter real EventRecord flags; bell shows numeric unread badge;
clicking an entry calls focusSurface + markEventsRead(ids). notify.ts param widened
to string so exit kind type-checks without breaking existing NOTIFY_STATES guard.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-10 08:28:35 +07:00
vasyansk d08a446b6f feat(app): event_log and mark_read bridge commands 2026-06-10 08:19:22 +07:00
vasyanskandClaude Sonnet 4.6 21fe1308cc feat(daemon): EventLog/MarkRead commands; Focus marks surface read
Wire Cmd::EventLog and Cmd::MarkRead to the live EventLog (replacing
NOT_IMPLEMENTED stubs). Cmd::Focus now calls mark_read for the surface,
persists the updated snapshot, and broadcasts Evt::EventsRead.
Add integration tests: event_log_query_and_mark_read and
focus_marks_surface_events_read.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-10 08:13:50 +07:00
vasyanskandClaude Opus 4.8 e83524a076 feat(daemon): record done/wait/error/exit into the event log
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-10 08:02:03 +07:00
vasyanskandClaude Opus 4.8 f7bf9fc5c6 wire(daemon): thread EventLog + EventPersister through serve/router
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-10 07:40:54 +07:00
vasyanskandClaude Sonnet 4.6 ac2d5ca1db feat(daemon): JsonEventStore + debounced EventPersister
Adds disk persistence for the event log: atomic temp+fsync+rename write,
corrupt-file backup, and a debounced coalescing persister task mirroring
state_store/persist patterns. 4 tests: round-trip, missing, corrupt, burst.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-10 07:27:23 +07:00
vasyanskandClaude Sonnet 4.6 56ba1723b9 feat(daemon): EventLog ring model with read-flags
Add event_log.rs with EventLog (capped VecDeque, monotonic ids, mark_read,
snapshot/restore) and EventLogState. Register mod in main.rs. Stub
Cmd::EventLog and Cmd::MarkRead arms in server.rs to keep the exhaustive
match compiling; full wiring follows in Task 4.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-10 07:21:26 +07:00
vasyanskandClaude Sonnet 4.6 5a8596dd0b feat(proto): EventLog/MarkRead commands and Event/EventsRead events
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-10 06:59:27 +07:00
vasyansk fc13e4340c feat(proto): EventKind, EventRecord, MarkReadTarget 2026-06-10 06:52:35 +07:00
vasyanskandClaude Opus 4.8 36964c9f21 feat(app): UI parity with Pencil mockup — top bar, panel cards, sidebar/event-center polish
Top bar (breadcrumb + actions + account), rounded panel cards with active
accent + rich headers, sidebar count pills/collapsible groups/daemon footer,
preset chips + scrollback pill, Event Center tabs + external-notify footer,
JetBrains Mono + Inter via @fontsource, shared theme tokens. Backend-absent
pieces are mocked (search, zoom, uptime, channels) pending SP1–SP5.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-10 06:47:38 +07:00
vasyanskandClaude Opus 4.8 807eab3f6c docs: SP2 implementation plan — persistent event log + read-model
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-10 06:40:15 +07:00
vasyanskandClaude Opus 4.8 e038ff307d docs: SP2 design — persistent event log + read-model
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-10 06:31:26 +07:00
vasyansk 5c47ec25a1 Merge fix: GUI spaceshd discovery + non-fatal connect 2026-06-09 23:31:52 +07:00
vasyanskandClaude Opus 4.8 92706c0780 fix(app): robust spaceshd discovery for tauri dev + non-fatal connect
The app is its own cargo workspace, so in 'tauri dev' the app binary lives
in app/src-tauri/target/ and spaceshd is NOT a sibling — lazy-start failed
and the .expect() crashed the window. Now: find_daemon tries SPACESHD_BIN,
sibling, repo-root target/{debug,release}, then PATH; bridge honors
SPACESH_SOCK like the daemon/CLI; setup logs instead of panicking.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-09 23:31:52 +07:00
vasyanskandClaude Opus 4.8 ec4025a683 docs: manual run & test guide (build, daemon, GUI, CLI, per-milestone checks)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-09 23:26:15 +07:00
vasyanskandClaude Opus 4.8 710fa6473f Merge spacesh M3: status detection sources + UI + native notifications
Claude Code hooks (per-surface CLAUDE_CONFIG_DIR), zsh OSC 133, fallback
patterns → set_state; status rings, sidebar aggregate, Event Center,
native macOS notifications, auto-unread. 87 tests green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-09 23:18:50 +07:00
vasyanskandClaude Opus 4.8 c86627153d chore(app): lock notification plugin deps + regenerated tauri schemas
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-09 23:14:28 +07:00
vasyanskandClaude Opus 4.8 1ecefdeb80 feat(app): Event Center, native notifications, auto-unread, state wiring in App
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-09 23:13:00 +07:00