Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 2 additions & 6 deletions .github/workflows/deploy-site.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,11 @@ jobs:
key: cargo-test-${{ hashFiles('Cargo.lock') }}
restore-keys: cargo-test-

# toolpath-desktop is a Tauri 2 app that pulls in glib-sys /
# webkit2gtk-sys on Linux, which need GTK system libs we don't
# install here. The crate targets macOS primarily; its own tests
# run on dev machines where Tauri's deps are already present.
- name: Test
run: cargo test --workspace --exclude toolpath-desktop
run: cargo test --workspace

- name: Clippy
run: cargo clippy --workspace --exclude toolpath-desktop -- -D warnings
run: cargo clippy --workspace -- -D warnings

deploy:
needs: test
Expand Down
74 changes: 0 additions & 74 deletions .github/workflows/release-desktop.yml

This file was deleted.

5 changes: 4 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ All notable changes to the Toolpath workspace are documented here.

## [Unreleased]

### Removed

- `toolpath-desktop` moved out of the workspace. The Tauri 2 desktop GUI now lives in the private [pathbase](https://github.com/empathic/pathbase) repo as `pathbase-app`. The toolpath derive/render crates remain open-source and are consumed by `pathbase-app` via git/crates.io deps.

### Changed

- `toolpath-convo` 0.7.0: **breaking** — `file_write_diff` gains a `before_state: Option<&str>` parameter. For the `Write { content }` shape, callers can now supply the prior file contents (e.g. resolved from `git show HEAD:<path>`) so the resulting diff shows `-` lines for replaced content instead of an addition-only hunk. `None` preserves the old behaviour (diff against `""`). `Edit` / `MultiEdit` shapes are unaffected — they carry their own `old_string`. `toolpath-claude`'s Claude-JSONL deriver wires a best-effort git-HEAD lookup for `Write` tool invocations; falls back silently to additions-only when the project isn't a git repo, the file isn't tracked, or `git` isn't on `PATH`. (#35)
Expand All @@ -19,7 +23,6 @@ All notable changes to the Toolpath workspace are documented here.
- `toolpath-opencode` 0.1.0: new crate — reads opencode's `~/.local/share/opencode/opencode.db` SQLite database (opened read-only via `rusqlite` with `SQLITE_OPEN_READ_ONLY` so it never interferes with a live opencode process), implements `ConversationProvider`, and derives Toolpath `Path` documents. Strongly types all 12 `part.data` variants (text, reasoning, tool, step-start/-finish, snapshot, patch, file, agent, subtask, retry, compaction) with `#[serde(other)]` catch-alls so new upstream variants round-trip. Each message becomes a step with tool invocations attached; reasoning folds onto `Turn.thinking`. Real unified diffs come from opencode's sibling bare git snapshot repositories via `git2` tree↔tree comparisons, honoring both the current `snapshot/<project-id>/<sha1(worktree)>/` layout and the older `snapshot/<project-id>/` flat layout. Files under `.gitignore`d paths (which opencode never captures in its snapshot store) fall back to tool-input-derived structural changes with `source: "tool_input_gitignored"` labeling. Project id is the SHA of the repo's first root commit (stable across clones and renames). 43 unit + 1 doc test.
- `toolpath-cli` 0.4.0: adds `gen_synthetic_path` binary for generating synthetic `Path` fixtures at configurable step counts (bench support for toolpath-desktop Preview, see issue #41).
- `toolpath-cli` 0.3.1: `path project claude` and `path incept` commands for projecting toolpath documents into Claude sessions; `derive gemini`/`list gemini`, `derive codex`/`list codex`, and `derive opencode [--session ID] [--all] [--project ID] [--no-snapshot-diffs]` / `list opencode [--project ID] [--json]` subcommands.
- `toolpath-desktop` 0.1.0: new crate — Tauri 2 desktop app for non-technical users. Source discovery for Claude Code + Pi + local git + GitHub PRs; interactive DAG preview (d3 + dagre-d3, Svelte 5 + TypeScript frontend); local `.path.json` export; stubbed Pathbase upload. GitHub PAT stored in the OS keychain under `dev.pathbase.toolpath-desktop`. Hot-reloading dev loop via `cargo tauri dev` (spawns Vite on port 1420).

## 0.3.0 — toolpath-cli

Expand Down
42 changes: 5 additions & 37 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ crates/
toolpath-dot/ # Graphviz DOT rendering
toolpath-md/ # Markdown rendering for LLM consumption
toolpath-cli/ # unified CLI (binary: path)
toolpath-desktop/ # Tauri 2 GUI (binary: toolpath-desktop)
schema/toolpath.schema.json # JSON Schema for the format
examples/*.json # 12 example documents (step, path, graph)
RFC.md # full format specification
Expand All @@ -45,12 +44,11 @@ toolpath-cli (binary: path)
├── toolpath-pi → toolpath, toolpath-convo
├── toolpath-dot → toolpath
└── toolpath-md → toolpath

toolpath-desktop (binary: toolpath-desktop, Tauri 2 app)
├── toolpath, toolpath-claude, toolpath-git, toolpath-github
```

Cross-dependencies between satellite crates: `toolpath-claude → toolpath-convo`, `toolpath-gemini → toolpath-convo`, `toolpath-codex → toolpath-convo`, `toolpath-opencode → toolpath-convo`, `toolpath-pi → toolpath-convo`. `toolpath-desktop` is a leaf — nothing depends on it.
Cross-dependencies between satellite crates: `toolpath-claude → toolpath-convo`, `toolpath-gemini → toolpath-convo`, `toolpath-codex → toolpath-convo`, `toolpath-opencode → toolpath-convo`, `toolpath-pi → toolpath-convo`.

The desktop GUI lives in the private [pathbase](https://github.com/empathic/pathbase) repo as `pathbase-app` — it consumes the toolpath crates via git or crates.io.

## Build and test

Expand Down Expand Up @@ -124,7 +122,6 @@ Tests live alongside the code (`#[cfg(test)] mod tests`), plus `toolpath-cli` ha
- `toolpath-pi`: ~88 unit tests (types, paths, error, reader, io, provider)
- `toolpath-dot`: 30 unit + 2 doc tests (render, visual conventions, escaping)
- `toolpath-cli`: 126 unit + 24 integration tests (all commands, track sessions, merge, validate, roundtrip, render-md snapshots)
- `toolpath-desktop`: 17 unit tests (IPC command modules — source listing, derive validation, export round-trip, upload stub, keychain input checks; tray activity-window bucketing, stats-snapshot smoke, session-id/basename helpers)

Validate example documents: `for f in examples/*.json; do cargo run -p toolpath-cli -- validate --input "$f"; done`

Expand All @@ -133,38 +130,9 @@ Validate example documents: `for f in examples/*.json; do cargo run -p toolpath-
- `toolpath-claude` has a `watcher` feature (default: on) gating `notify`/`tokio` dependencies for filesystem watching
- `toolpath-gemini` has a `watcher` feature (default: on) gating the polling-based `ConversationWatcher` module

## toolpath-desktop

Tauri 2 app. Rust backend links `toolpath`, `toolpath-claude`, `toolpath-git`, `toolpath-github` directly (no CLI subprocess). Frontend is Svelte 5 + TypeScript + Vite, in the Elm-architecture (TEA) shape.

Layout:
- `crates/toolpath-desktop/src/` — Rust backend (Tauri IPC commands).
- `crates/toolpath-desktop/frontend/` — Svelte app (bundled by Vite; managed with `bun`).
- `src/lib/types.ts` — `Model`, `Msg`, `Cmd`, IPC payload types (mirror Rust serde).
- `src/lib/update.ts` — pure `update(msg, model) -> [model, cmd]` reducer + `initialModel()`.
- `src/lib/store.svelte.ts` — reactive Svelte 5 store wrapping `update`, runs `Cmd`s (invoke / batch / emitMsg / fn).
- `src/lib/ipc.ts` — typed `invoke()` + `listen()` wrappers around `@tauri-apps/api`.
- `src/lib/viz.ts` — dagre-d3 DAG renderer.
- `src/routes/*.svelte` — one component per route, pure views over `store.m`.
- `src/app.svelte` — top-level switch on `store.m.route`.

Tauri dev loop: `cargo tauri dev` spawns `bun --cwd frontend run dev` (Vite on `http://localhost:1420`), then runs the Rust binary against that URL. Frontend edits hot-reload via Vite HMR without restarting Rust; Rust edits trigger `cargo run` to restart. Production: `cargo tauri build` runs `bun --cwd frontend run build` first, bundling to `frontend/dist/`.

Menu-bar mode: the app runs as a normal GUI app (Dock icon + app-switcher entry) *and* installs a tray icon — the tray is an accessory, not a replacement for the main window. Accessory activation policy was tried and reverted because macOS tiling window managers (yabai, Amethyst) stop managing accessory windows. A tray icon is installed in `src/tray.rs`; a background thread polls every 30s across `toolpath-claude`, `-gemini`, `-codex`, `-opencode`, and `-pi`, classifies sessions as *active* (last activity in the last 2 min) or *recent* (last 24h), updates the tray title (`● N`), and emits a `tray:stats` event. The popover is a second Tauri window (`label = "popover"`, undecorated, hidden by default) with its own Vite entry (`frontend/popover.html` → `src/popover.ts` → `routes/Popover.svelte`); left-clicking the tray toggles it via `tauri-plugin-positioner`. For an on-demand snapshot (no waiting for the next poll) the popover invokes the `tray_stats_now` IPC command.

Opening a trace from the popover: clicking a recent-session row invokes `tray_open_trace { provider, project, session_id }`. The Rust side calls back into the existing `derive_claude` / `derive_pi` commands, shows the main window, and emits a `trace:opened` event to the main window with the derived `{ doc, source, filename }`. `app.svelte` listens for it and dispatches `DeriveSucceeded`, which routes to the preview. Only `claude` and `pi` have derive commands today — rows for `gemini`, `codex`, `opencode` still appear in the list (so users can see activity) but are rendered disabled.

Pre-derive cache: after each 30s poll the tray kicks off background derives for every recent claude/pi session and stashes the result in `src/cache.rs`'s `TraceCache` (shared via `app.manage(Arc<TraceCache>)`). Both the popover's `tray_open_trace` and the main-window's `derive_claude` / `derive_pi` commands route through the same cache (via `derive_claude_impl` / `derive_pi_impl` in `commands/derive.rs`), so clicking a session — whether from Quick View or the Browse view's "Select →" button — usually resolves instantly. Cache freshness keys on the source's `last_activity`; when a session gets new turns its cached entry is replaced on the next poll. Cacheable calls are limited to single-session, `include_thinking=false` derives (the shape the poller prewarms). Warm-up runs with at most 2 concurrent threads.

Two tiers: (1) memory, a `HashMap` capped at 32 entries; (2) disk, under `<temp_dir>/toolpath-desktop/trace-cache/<fnv1a64-of-key>.json`, so caches survive app restarts (macOS/Linux eventually clean `/tmp` themselves). Disk is capped at 200 entries, pruned oldest-first by mtime at startup. Memory misses fall through to disk and promote the hit back into memory. Corrupt files are silently deleted on read so a bad write doesn't poison the cache forever.

Perf tracer (`frontend/src/lib/perf.svelte.ts`, `PerfOverlay.svelte`): the store, Preview, and the `trace:opened` listener call `perfStart` / `perfMark` / `perfEnd` at each checkpoint of a click → derive → render flow (dispatch, invoke-start, invoke-end, model-updated, preview-mounted, viz-rendered). Every completed trace logs a summary to the devtools console; set `localStorage.perf = "1"` and reload to also show a phase-bar overlay in the bottom-right. Use this to tell whether perceived click latency is the Rust derive vs. the Svelte/dagre render.

Streaming pattern (Claude project/session lists): Rust command spawns a thread that emits `claude:project`, `claude:session`, `claude:projects-done`, `claude:sessions-done` events. The Svelte component subscribes with `$effect(() => { listen(...) ... return unlisten; })` — Svelte tears down listeners automatically when the effect's deps change or the component unmounts.

Package manager for the frontend is `bun` (installed at `~/.bun/bin/bun`). `bun install` to set up, `bun run check` for `svelte-check`, `bun run build` for a production Vite build. Never commit `node_modules/` or `dist/` — both are ignored.
## Desktop app

Dev: `cargo tauri dev` from the crate directory. Build: `cargo tauri build`. GitHub PAT is stored in the OS keychain under service `dev.pathbase.toolpath-desktop`. Pathbase upload is a stub as of 0.1.0 — it validates the payload and returns a mock URL.
The Tauri 2 desktop GUI lives in the private [pathbase](https://github.com/empathic/pathbase) repo as `pathbase-app`. It consumes `toolpath`, `toolpath-claude`, `toolpath-git`, `toolpath-github`, `toolpath-gemini`, `toolpath-codex`, `toolpath-opencode`, and `toolpath-pi` via git/crates.io deps. Don't look for it in this workspace — it was moved out when Pathbase went closed-source.

## Versioning and release checklist

Expand Down
Loading
Loading