Repository navigation
Adopt clients, edit MCP and scan client configs in the app instead of core - #180
Merged
Merged
Conversation
… core Client adoption, MCP editing, the static scan and the file watcher change files on this machine, so they now run in the desktop app. The tw-adopt and tw-scan crates move here from core (src-tauri/crates/, one workspace with the app; the unused tw-config dependency is dropped). - New Tauri commands replace the control-plane endpoints: list_clients, plan_adopt, adopt_client, plan_restore, restore_client, diagnose_client, prepare_client_key, mcp_targets, plan_mcp, apply_mcp, scan_clients, gateway_base, plus delete_key and rotate_key (the adopted-client check and the key sync need this machine's files). restore_all no longer asks core. - Core is still asked for two things only: the gateway port (Overview) and keys (Keys, ClientKey). The gateway host is a single function so remote mode can swap it; retarget_adopted() repoints every adopted client. - The watcher runs in the app: `local-event` (clients_changed / scan_alert) to the webview, scan alerts into the notice bus; the first scan is a baseline. Core's own ClientsChanged/ScanAlert are ignored. - Types for these commands live in src-tauri/src/wire.rs and generate src/generated/lite-api.ts; names identical to tw-api.ts are imported. - Message codes the app emits itself are listed in src-tauri/msg-codes.txt (generated from source); translations are checked against it plus core's. - The webview endpoint whitelist drops the moved endpoints, and DeleteKey, RotateKey and ClientKey now go only through Rust commands. Works against the pinned core v0.46.0 (its endpoints just go unused). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…e clients list The menu bar's copy-address action still read gateway_base from the /clients endpoint, which core is dropping. It now uses the same function as the clients and keys pages. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This was referenced Sep 24, 2026
Merged
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Phase P3 of the remote-core plan: client adoption, MCP editing, the static scan and the file watcher move from core into the desktop app. They change files on this machine, so they belong here whichever core the app talks to.
What moved
tw-adoptandtw-scannow live insrc-tauri/crates/(copied from core v0.46.0; history not kept).src-tauri/Cargo.tomlis now a workspace (default-membersincludes the crates, so CI'scargo clippy/test --manifest-path src-tauri/Cargo.tomlcovers them). The unusedtw-configdependency is gone. The core crates (tw-api,tw-types,tw-yaml,tw-guard,tw-watch) are pinned once in[workspace.dependencies], all to the same tag.list_clients,plan_adopt,adopt_client,plan_restore,restore_client,diagnose_client,prepare_client_key(returns the key name only; copying goes throughcopy_key), plus the existingcopy_client_endpoint,reveal_client_config,restore_allmcp_targets,plan_mcp,apply_mcp,scan_clients(user-level only; the unused project-directory input is gone)gateway_base,delete_key(refuses a key that an adopted client still has in its config),rotate_key(rotates in core, then writes the new key into the adopted client on this machine)Overview.listen.port), the keys (Keys), and a client's dedicated key (ClientKey). The "wait for a real request" signal still comes from core's event stream (keys'last_seen_msand request events).scan::spawn_watcher). It emits the Tauri eventlocal-event(clients_changed/scan_alert), and scan alerts go into the notice bus (notices::rules::scan_alert). The first scan is a baseline, as before.useCoreEventlistens to both channels and ignores core's same-named events, which the pinned core still sends./clients.Types
src-tauri/src/wire.rsholds the types for these commands and generatessrc/generated/lite-api.ts(checked bytests/ts_bindings.rs, regenerate withUPDATE_TS=1). If a name also exists intw-api.ts, the generator imports it instead of declaring it again, and fails when the two shapes differ. After core drops those types, the same generator declares them here. Renamed where the shape changed:ScanResponse→ScanReport(noprojects),KeyRotated→KeyRotation.Message codes
The moved code keeps its codes (
adopt.*,control.client_unknown,control.no_keys,control.key_used_by_client) because codes are the translation contract. The app now keeps its own manifest,src-tauri/msg-codes.txt. It is generated frommsg!/code!insrc-tauri/srcandsrc-tauri/cratesby the same scanner core uses:UPDATE_MSG_CODES=1 cargo test --manifest-path src-tauri/Cargo.toml --test msg_codes. The translation checks intests/msg_codes.rsnow run against core'stw_api::MSG_CODESplus this file.lite.*codes made by the frontend are still exempt. Nocore.zh.jsonchanges were needed.Webview surface
The whitelist (
call.rsALLOWEDandcontrol.tsWEBVIEW_ENDPOINTS) dropsScan,Clients,PlanAdopt,Adopt,PlanRestore,Restore,Why,McpTargets,McpPlan,McpApply.DeleteKey,RotateKeyandClientKeyare now reachable only through the Rust commands above, and the test that lists what the webview cannot reach includes them.Compatibility
This works against the currently pinned core v0.46.0: its endpoints stay unused, its watcher still runs, and its
ScanAlert/ClientsChangedare ignored. While core still syncs rotated keys itself,rotate_keypasses on core's report instead of writing a second time. That branch goes away with the fields once core drops them. The core PR that deletes the endpoints (ThinkWatchProject/ThinkWatch-Core#186) can merge after this one. I built this branch against it with a[patch]; when lite bumps to that core, only three spots need changes: the transitional sync handling inrotate_key, twocases insrc/types.ts, and thecontrol.key_bind_failedtranslation.For remote mode (P5)
clients::gateway_host()returns the host clients should point at. It is127.0.0.1now; in remote mode it becomes the server's address.clients::gateway_base(control, host)andops::Gateway { base, keys }take the gateway and keys as inputs, so they can come from a remote core.clients::retarget_adopted(control, host)repoints every adopted client at another core's gateway with that core's dedicated keys. It backs the switch-confirm checkbox.Checks
cargo fmt --check,cargo clippy --all-targets -D warnings,cargo test(workspace, includingcontrol_planeagainst a v0.46.0twcore),pnpm typecheck,pnpm testclaude-code-2),no_keys, adopt → restore round trip, the adopted-owner check, repoint after rotation, MCP copy/remove/refusal, the watcher reporting only new findings and never touching a file.list_clients), and the MCP page (scan, targets, copy plan → apply). Alocal-eventscan alert shows the MCP badge; the same event from core is ignored.🤖 Generated with Claude Code