fix(desktop): remove stale sprout-admin prereq, add sidecar tooling (#371)

This commit is contained in:
Wes
2026-04-20 13:30:37 -06:00
committed by GitHub
parent fa5a0b77fe
commit 28bf8bfeee
11 changed files with 38 additions and 69 deletions

View File

@@ -6,7 +6,7 @@ use crate::{
managed_agents::{
command_availability, discover_local_acp_providers, AcpProviderInfo,
DiscoverManagedAgentPrereqsRequest, ManagedAgentPrereqsInfo, RelayAgentInfo,
DEFAULT_ACP_COMMAND, DEFAULT_ADMIN_COMMAND, DEFAULT_MCP_COMMAND,
DEFAULT_ACP_COMMAND, DEFAULT_MCP_COMMAND,
},
relay::{build_authed_request, send_json_request},
};
@@ -37,7 +37,6 @@ pub fn discover_managed_agent_prereqs(
ManagedAgentPrereqsInfo {
acp: command_availability(acp_command, Some(&app)),
mcp: command_availability(mcp_command, Some(&app)),
admin: command_availability(DEFAULT_ADMIN_COMMAND, Some(&app)),
}
}

View File

@@ -273,7 +273,6 @@ pub struct DiscoverManagedAgentPrereqsRequest {
pub struct ManagedAgentPrereqsInfo {
pub acp: CommandAvailabilityInfo,
pub mcp: CommandAvailabilityInfo,
pub admin: CommandAvailabilityInfo,
}
/// Patch request for updating a managed agent's mutable fields.
@@ -374,7 +373,6 @@ pub struct UpdateTeamRequest {
}
pub const DEFAULT_ACP_COMMAND: &str = "sprout-acp";
pub const DEFAULT_ADMIN_COMMAND: &str = "sprout-admin";
pub const DEFAULT_AGENT_COMMAND: &str = "goose";
pub const DEFAULT_MCP_COMMAND: &str = "sprout-mcp-server";
/// ~5 min (320s) — matches the CLI harness default (SPROUT_ACP_IDLE_TIMEOUT).

View File

@@ -99,11 +99,9 @@ export function CreateAgentDialog({
// Use this everywhere instead of raw `mintToken` for validation/rendering.
const effectiveMintToken = isProviderMode || mintToken;
const isMintSupported = prereqs?.admin.available ?? false;
const isSpawnSupported =
prereqs?.acp.available === true && prereqs?.mcp.available === true;
const mintToggleDisabled =
prereqsQuery.isLoading || (prereqs !== null && !isMintSupported);
const mintToggleDisabled = prereqsQuery.isLoading;
const spawnToggleDisabled =
prereqsQuery.isLoading || (prereqs !== null && !isSpawnSupported);
const isDiscoveryPending = providersQuery.isLoading || prereqsQuery.isLoading;
@@ -126,15 +124,6 @@ export function CreateAgentDialog({
providersQuery.isLoading,
]);
React.useEffect(() => {
// Don't auto-disable minting in provider mode — it's required.
if (!prereqs || prereqs.admin.available || !mintToken || isProviderMode) {
return;
}
setMintToken(false);
}, [mintToken, prereqs, isProviderMode]);
React.useEffect(() => {
if (
!prereqs ||
@@ -305,7 +294,6 @@ export function CreateAgentDialog({
name.trim().length > 0 &&
(!effectiveMintToken || selectedScopes.size > 0) &&
!isDiscoveryPending &&
!(effectiveMintToken && prereqs !== null && !isMintSupported) &&
!(
!isProviderMode &&
spawnAfterCreate &&
@@ -464,7 +452,6 @@ export function CreateAgentDialog({
) : null}
<CreateAgentOptionToggles
isMintSupported={isMintSupported}
isSpawnSupported={isSpawnSupported}
mintToken={effectiveMintToken}
mintToggleDisabled={isProviderMode || mintToggleDisabled}

View File

@@ -325,7 +325,6 @@ export function CreateAgentRuntimeFields({
}
export function CreateAgentOptionToggles({
isMintSupported,
isSpawnSupported,
mintToken,
mintToggleDisabled,
@@ -338,7 +337,6 @@ export function CreateAgentOptionToggles({
onToggleStartOnAppLaunch,
onToggleSpawnAfterCreate,
}: {
isMintSupported: boolean;
isSpawnSupported: boolean;
mintToken: boolean;
mintToggleDisabled: boolean;
@@ -369,9 +367,7 @@ export function CreateAgentOptionToggles({
>
<p className="text-sm font-semibold tracking-tight">Mint token</p>
<p className="mt-1 text-sm text-foreground/70">
{prereqs !== null && !isMintSupported
? `Unavailable until ${prereqs.admin.command} is installed.`
: "Use sprout-admin to create a bearer token for this agent."}
Mint a relay API token for this agent.
</p>
</button>

View File

@@ -141,8 +141,8 @@ function SetupHelpCard() {
<code className="rounded bg-background px-1.5 py-0.5 font-mono text-[12px]">
cargo build --release --workspace
</code>{" "}
when you want the desktop app to mint tokens or spawn ACP harnesses
from this checkout.
when you want the desktop app to spawn ACP harnesses from this
checkout.
</p>
<p>
If you keep binaries outside your PATH, use the custom ACP and MCP
@@ -168,13 +168,6 @@ export function DoctorSettingsPanel() {
const isRefreshing = providersQuery.isFetching || prereqsQuery.isFetching;
const toolChecks = [
{
id: "admin",
label: "Token minting",
purpose:
"Desktop uses `sprout-admin` to mint managed-agent bearer tokens.",
availability: prereqs?.admin ?? null,
},
{
id: "acp",
label: "ACP harness",
@@ -192,10 +185,7 @@ export function DoctorSettingsPanel() {
];
const hasMissingSproutTools =
prereqs !== null &&
(!prereqs.admin.available ||
!prereqs.acp.available ||
!prereqs.mcp.available);
prereqs !== null && (!prereqs.acp.available || !prereqs.mcp.available);
return (
<section className="space-y-5" data-testid="settings-doctor">
@@ -306,11 +296,6 @@ export function DoctorSettingsPanel() {
/>
</div>
</div>
<p className="mt-3 text-xs text-muted-foreground">
Token minting always checks the default{" "}
<code className="font-mono">sprout-admin</code> command.
</p>
</div>
</div>

View File

@@ -289,7 +289,6 @@ type RawCommandAvailability = {
};
type RawManagedAgentPrereqs = {
admin: RawCommandAvailability;
acp: RawCommandAvailability;
mcp: RawCommandAvailability;
};
@@ -1046,7 +1045,6 @@ export async function discoverManagedAgentPrereqs(input: {
);
return {
admin: fromRawCommandAvailability(response.admin),
acp: fromRawCommandAvailability(response.acp),
mcp: fromRawCommandAvailability(response.mcp),
};

View File

@@ -386,7 +386,6 @@ export type CommandAvailability = {
};
export type ManagedAgentPrereqs = {
admin: CommandAvailability;
acp: CommandAvailability;
mcp: CommandAvailability;
};

View File

@@ -348,7 +348,6 @@ type RawCommandAvailability = {
};
type RawManagedAgentPrereqs = {
admin: RawCommandAvailability;
acp: RawCommandAvailability;
mcp: RawCommandAvailability;
};
@@ -3056,11 +3055,6 @@ async function handleDiscoverManagedAgentPrereqs(args: {
};
}): Promise<RawManagedAgentPrereqs> {
return {
admin: {
command: "sprout-admin",
resolved_path: "/Users/wesb/dev/sprout/target/debug/sprout-admin",
available: true,
},
acp: {
command: args.input?.acpCommand ?? "sprout-acp",
resolved_path: "/Users/wesb/dev/sprout/target/debug/sprout-acp",

View File

@@ -393,9 +393,6 @@ test("shows doctor checks for local sprout tooling", async ({ page }) => {
await openSettings(page, "doctor");
await expect(page.getByTestId("settings-doctor")).toBeVisible();
await expect(page.getByTestId("doctor-check-admin")).toContainText(
"sprout-admin",
);
await expect(page.getByTestId("doctor-check-acp")).toContainText(
"sprout-acp",
);

View File

@@ -85,14 +85,18 @@ desktop-tauri-fmt:
desktop-tauri-fmt-check:
cargo fmt --manifest-path {{desktop_tauri_manifest}} --all -- --check
# Check the desktop Tauri Rust crate compiles
desktop-tauri-check:
# Ensure sidecar placeholder binaries exist (Tauri validates externalBin at compile time)
_ensure-sidecar-stubs:
#!/usr/bin/env bash
set -euo pipefail
TARGET=$(rustc -vV | sed -n 's|host: ||p')
mkdir -p desktop/src-tauri/binaries
touch "desktop/src-tauri/binaries/sprout-acp-$TARGET"
touch "desktop/src-tauri/binaries/sprout-mcp-server-$TARGET"
for bin in sprout-acp sprout-mcp-server; do
touch "desktop/src-tauri/binaries/${bin}-${TARGET}"
done
# Check the desktop Tauri Rust crate compiles
desktop-tauri-check: _ensure-sidecar-stubs
cargo check --manifest-path {{desktop_tauri_manifest}}
# Build the full desktop Tauri app locally (unsigned, for testing)
@@ -156,31 +160,21 @@ proxy-release:
cargo run -p sprout-proxy --release
# Run the desktop Tauri app in dev mode (ports and identity derived from worktree)
dev *ARGS:
dev *ARGS: _ensure-sidecar-stubs
#!/usr/bin/env bash
set -euo pipefail
cd {{desktop_dir}}
[[ -d node_modules ]] || pnpm install
# Ensure sidecar placeholder binaries exist (Tauri validates externalBin at compile time)
TARGET=$(rustc -vV | sed -n 's|host: ||p')
mkdir -p src-tauri/binaries
touch "src-tauri/binaries/sprout-acp-$TARGET"
touch "src-tauri/binaries/sprout-mcp-server-$TARGET"
source ../scripts/instance-env.sh
echo "Starting on Vite port ${SPROUT_VITE_PORT}, relay ${SPROUT_RELAY_URL}"
pnpm exec tauri dev --config "$SPROUT_TAURI_CONFIG" {{ARGS}}
# Run the desktop app against the internal staging relay (installs deps + builds agent tools automatically)
staging *ARGS:
staging *ARGS: _ensure-sidecar-stubs
#!/usr/bin/env bash
set -euo pipefail
cd {{desktop_dir}}
pnpm install
# Ensure sidecar placeholder binaries exist (Tauri validates externalBin at compile time)
TARGET=$(rustc -vV | sed -n 's|host: ||p')
mkdir -p src-tauri/binaries
touch "src-tauri/binaries/sprout-acp-$TARGET"
touch "src-tauri/binaries/sprout-mcp-server-$TARGET"
cd ..
cargo build --release -p sprout-acp -p sprout-mcp
cd {{desktop_dir}}

22
scripts/bundle-sidecars.sh Executable file
View File

@@ -0,0 +1,22 @@
#!/usr/bin/env bash
set -euo pipefail
SIDECARS=(sprout-acp sprout-mcp-server)
TARGET=${1:-$(rustc -vV | sed -n 's|host: ||p')}
BINARIES_DIR="desktop/src-tauri/binaries"
missing=()
for bin in "${SIDECARS[@]}"; do
[[ -f "target/release/$bin" ]] || missing+=("$bin")
done
if [[ ${#missing[@]} -gt 0 ]]; then
echo "Error: missing release binaries: ${missing[*]}" >&2
echo "Run 'cargo build --release -p sprout-acp -p sprout-mcp' first." >&2
exit 1
fi
mkdir -p "$BINARIES_DIR"
for bin in "${SIDECARS[@]}"; do
cp "target/release/$bin" "$BINARIES_DIR/${bin}-${TARGET}"
done
echo "Sidecars bundled for $TARGET"