feat(app): external-spawn via single-instance args (reference impl for #340)#341
Open
akamrume328 wants to merge 1 commit into
Open
feat(app): external-spawn via single-instance args (reference impl for #340)#341akamrume328 wants to merge 1 commit into
akamrume328 wants to merge 1 commit into
Conversation
Launch a member pane from outside the GUI: a second launch of the shape agmsg-app spawn <team> <role> is forwarded by the single-instance handler to the running instance, which emits an external-spawn event. The frontend validates <team>/<role> against the live member registry before calling the existing spawnMember (idempotent: an already-running member just gets focused). The Rust side never execs the args itself, keeping the trust boundary at the same place a GUI click is. Enables scripted / orchestrator-driven launch (the missing counterpart to the app's stdin-inject delivery), needed for headless team automation on Windows where there is no LaunchAgent-style external launcher.
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.
Implements #340.
This is a reference implementation using the
single-instanceargs approach described in #340. I'm happy to reshape it to a deep-link handler or a local-IPC endpoint if you'd prefer one of those as the front door — see the design question in #340. Posting the working diff here in case a concrete implementation is easier to react to than prose.What
Add a way to open a member's pane in the already-running app from outside the GUI:
A second launch with this shape is caught by the existing
single-instancehandler, which forwards
(team, role)to the running instance as anexternal-spawnevent. The frontend validates them against the live memberregistry, then calls the existing
spawnMember.Why
The app already delivers agmsg messages to spawned panes via stdin-inject, but
a pane can only be created by a human clicking a member in the GUI. There is
no way for a script, an orchestrator agent, or a shell alias to launch a member.
On Windows this gap is sharper: there is no LaunchAgent-style external launcher,
so headless / automated team setups cannot bring members up programmatically.
This is the smallest possible entry point for that: the
single-instancepluginis already registered and its callback already receives the second launch's
argv/cwd— this change just stops ignoring them for the singlespawnverb.How / trust boundary
spawnverb and forwards the rawteam/rolestrings. It never execs anything from the args itself.
team(must be the active team) androle(must existin the live member registry) before calling
spawnMember. Unknown values arelogged, not silently dropped.
spawnMemberis idempotent: an already-running member is just focused, so aduplicate
spawncannot create two panes for one identity.So the trust boundary stays exactly where a manual member click already puts it.
Scope / follow-ups (intentionally out of this PR)
spawnlaunch races app startup before thefrontend listener is registered, the event can be missed. A small Rust-side
pending buffer drained by the frontend on ready would close this; kept out to
keep the diff minimal.
served later by a deep-link handler (
agmsg://spawn?...) or an authenticatedlocal IPC endpoint.
single-instance argsis meant as the minimal bootstrapentry, not the final API.
Testing
tsc --noEmit: clean.vite build: clean (frontend bundles with the new listener).agmsg-app spawn <team> <role>focuses the running window and opensthe member's pane exactly once; unknown team/role is logged and ignored.
rolemay contain non-ASCII (e.g. Japanese member names),so it is passed through as a plain arg string end to end (no URL/quote
transform), which the manual test exercises.
Diff
2 files, +47/-1:
app/src-tauri/src/lib.rs,app/src/App.tsx.