Files
yaak-mountain-loop/crates/common/yaak-rpc-schema
Gregory SchierandClaude Opus 5 bd932ce85f feat(import): remember the user's import selection
Yaak now remembers, per item of a linked import source, whether the user
wants it. A mapping row that still points at a model means wanted, so
re-imports merge into it; a row with no model behind it means not wanted,
so re-imports leave it alone. Wanted-ness is structural rather than a flag:
deleting the model locally, or turning the item down in the preview, is
what makes it not wanted.

- import_source_resources drops `snapshot` for a nullable `content_hash`
  and lets `model_id` be NULL. The migration keeps every beta row's
  key to model mapping and starts hashes empty; until a hash is recorded,
  a difference can't be attributed to either side, so the item is offered
  once as a conflict that keeps local changes.
- comparable() ignores sortPriority. Importers number it from source
  order, so inserting one operation used to plan a fake update for
  everything after it. The trade is that pure reorders don't propagate.
- Keys the user turned down come back as unchecked "not imported" rows
  instead of being re-offered as new resources or resurrected. Checking
  one imports it under the same source key and pulls in the folders it
  needs.
- An imported resource the source moves into a folder that isn't imported
  is offered as a deletion, with a tooltip pointing at the folder.
- Plan-time source resolution binds by source-key overlap instead of by
  path, so a renamed or moved file merges into what it created and heals
  the stored origin. Several sources sharing keys never guess-merge: the
  plan says so and imports everything as new.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-02 10:56:34 -07:00
..

yaak-rpc-schema

The wire schema for the app's RPC surface: every command name, its request payload, and its response type, declared once.

Every host that serves the Yaak UI — the desktop app today, the browser bridge and anything after it — imports these types and implements the commands against them. That is what keeps a request's shape from drifting between hosts, and it is why the TypeScript bindings (bindings/gen_rpc.ts, exposed to the frontend as @yaakapp-internal/rpc-schema) are generated from one place.

Nothing here depends on Tauri or on any host. Request structs are plain data, and so are the few response types declared here rather than in an engine crate. Command bodies live with the host that runs them.

Adding a command

  1. Add its request struct and an entry in with_commands! in src/lib.rs.
  2. Write the adapter in each host — the desktop's live in crates-tauri/yaak-app-client/src/rpc_ext.rs. A host that does not support the command still has to say so; a missing adapter fails to compile.
  3. Regenerate the bindings: cargo test -p yaak-rpc-schema writes bindings/gen_rpc.ts, which is committed.

How hosts consume the list

with_commands! takes the name of a macro_rules! macro and calls it with the full name(Req) -> Res list. Each host writes a small macro that receives that list and builds its router:

macro_rules! register_commands {
    ( $( $name:ident ( $req:ty ) -> $res:ty ),* $(,)? ) => {
        pub fn build_router() -> RpcRouter<MyCtx> {
            let mut router = RpcRouter::new();
            $( router.register(stringify!($name), rpc_handler_async!($name)); )*
            router
        }
    };
}
yaak_rpc_schema::with_commands!(register_commands);

The schema decides what commands exist; the host decides how each one runs.