Eliminate hidden host defaults

This commit is contained in:
Mohamed Boudra
2025-11-26 19:02:47 +01:00
parent 670c38ab8c
commit 4f00e07284
3 changed files with 34 additions and 30 deletions

View File

@@ -218,10 +218,11 @@ function AgentFlowModal({
const { connectionStates } = useDaemonConnections();
const daemonEntries = useMemo(() => Array.from(connectionStates.values()), [connectionStates]);
const initialServerId = useMemo(() => {
if (serverId) {
return serverId;
if (!serverId) {
return null;
}
return daemonEntries[0]?.daemon.id ?? null;
const exists = daemonEntries.some((entry) => entry.daemon.id === serverId);
return exists ? serverId : null;
}, [serverId, daemonEntries]);
const [selectedServerId, setSelectedServerId] = useState<string | null>(initialServerId);
const selectedSession = useSessionForServer(selectedServerId);
@@ -229,21 +230,26 @@ function AgentFlowModal({
const sessionDirectory = useSessionDirectory();
useEffect(() => {
if (!selectedServerId) {
setSelectedServerId(initialServerId);
if (selectedServerId) {
const exists = daemonEntries.some((entry) => entry.daemon.id === selectedServerId);
if (!exists) {
setSelectedServerId(initialServerId);
}
return;
}
const exists = daemonEntries.some((entry) => entry.daemon.id === selectedServerId);
if (!exists) {
if (initialServerId && selectedServerId !== initialServerId) {
setSelectedServerId(initialServerId);
}
}, [daemonEntries, selectedServerId, initialServerId]);
useEffect(() => {
if (isVisible && initialServerId && selectedServerId !== initialServerId) {
if (!isVisible) {
return;
}
if (initialServerId && selectedServerId !== initialServerId) {
setSelectedServerId(initialServerId);
}
}, [isVisible, initialServerId]);
}, [isVisible, initialServerId, selectedServerId]);
const ws = session?.ws ?? null;
const inertWebSocket = useMemo<UseWebSocketReturn>(
@@ -323,15 +329,18 @@ function AgentFlowModal({
selectedDaemonId ??
"Selected host";
const selectedDaemonStatusLabel = formatConnectionStatus(selectedDaemonStatus);
const hasSelectedDaemon = Boolean(selectedServerId);
const selectedDaemonIsUnavailable =
!session || selectedDaemonStatus !== "online" || !ws?.isConnected;
const selectedDaemonLastError = selectedDaemonConnection?.lastError?.trim();
const daemonAvailabilityError = selectedDaemonIsUnavailable
? `${selectedDaemonLabel} is ${selectedDaemonStatusLabel}. Connect to it before creating or importing agents.${
selectedDaemonLastError ? ` ${selectedDaemonLastError}` : ""
}`
: null;
const isTargetDaemonReady = Boolean(session && !selectedDaemonIsUnavailable);
const daemonAvailabilityError = !hasSelectedDaemon
? "Select a host before creating or importing agents."
: selectedDaemonIsUnavailable
? `${selectedDaemonLabel} is ${selectedDaemonStatusLabel}. Connect to it before creating or importing agents.${
selectedDaemonLastError ? ` ${selectedDaemonLastError}` : ""
}`
: null;
const isTargetDaemonReady = Boolean(hasSelectedDaemon && session && !selectedDaemonIsUnavailable);
const [isMounted, setIsMounted] = useState(isVisible);
const [workingDir, setWorkingDir] = useState("");

View File

@@ -9,8 +9,6 @@ export interface AggregatedAgentGroup {
agents: Agent[];
}
const EMPTY_AGENT_MAP: Map<string, Agent> = new Map();
const sortAgents = (agents: Agent[]): Agent[] => {
return [...agents].sort((left, right) => {
const leftRunning = left.status === "running";
@@ -27,10 +25,9 @@ const sortAgents = (agents: Agent[]): Agent[] => {
});
};
export function useAggregatedAgents(fallbackAgents?: Map<string, Agent>): AggregatedAgentGroup[] {
export function useAggregatedAgents(): AggregatedAgentGroup[] {
const { connectionStates } = useDaemonConnections();
const sessionDirectory = useSessionDirectory();
const fallback = fallbackAgents ?? EMPTY_AGENT_MAP;
return useMemo(() => {
const groups = new Map<string, { serverLabel: string; agents: Agent[] }>();
@@ -58,15 +55,6 @@ export function useAggregatedAgents(fallbackAgents?: Map<string, Agent>): Aggreg
});
}
if (groups.size === 0 && fallback.size > 0) {
const fallbackServerId = connectionStates.keys().next().value ?? "default";
const label = connectionStates.get(fallbackServerId)?.daemon.label ?? fallbackServerId;
const fallbackList = Array.from(fallback.values());
if (fallbackList.length > 0) {
groups.set(fallbackServerId, { serverLabel: label, agents: fallbackList });
}
}
const aggregatedGroups = Array.from(groups.entries()).map(([serverId, { serverLabel, agents }]) => ({
serverId,
serverLabel,
@@ -89,5 +77,5 @@ export function useAggregatedAgents(fallbackAgents?: Map<string, Agent>): Aggreg
});
return aggregatedGroups;
}, [sessionDirectory, fallback, connectionStates]);
}, [sessionDirectory, connectionStates]);
}

View File

@@ -35,7 +35,8 @@ The multi-daemon infrastructure is in place: session directory with daemon-scope
- Removed the legacy autoConnect state from daemon profiles and session hosts so every host hydrates automatically, refreshed the host-unavailable messaging/docs, and verified via `npm run typecheck --workspace=@paseo/app`.
### Review: No Silent Defaults
- [ ] Review the changes to ensure we didn't just replace "active daemon" with "first host" (e.g., `hosts[0]}`. The goal is explicit user choice, not a hidden default.
- [x] Review the changes to ensure we didn't just replace "active daemon" with "first host" (e.g., `hosts[0]}`). The goal is explicit user choice, not a hidden default.
- Create/import modal now requires explicit host selection (no first entry default) and `useAggregatedAgents` no longer fabricates a host id via `connectionStates.keys().next()`; verified with `npm run typecheck --workspace=@paseo/app`.
### 3. Simplify Settings Screen
- [ ] Remove the standalone "Test Connection" form/URL input at the top of settings.
@@ -50,6 +51,12 @@ The multi-daemon infrastructure is in place: session directory with daemon-scope
- [ ] A stopped/disconnected host is NOT an error—don't show error states on home screen just because a host is offline.
- [ ] Only show errors when the user tries to interact with an agent whose host is stopped.
- [ ] Update connection banners/indicators to show neutral "offline" state instead of error styling.
- [ ] Make the Git Diff offline/unavailable state neutral and stop instructing users to "connect" manually.
- Context: `packages/app/src/app/git-diff.tsx:233-241` still renders the destructive error container and tells users "Connect this host or switch to another one to continue," violating the auto-connect guidance.
- [ ] Update the File Explorer offline state to match the new philosophy (neutral messaging, no manual connect CTA).
- Context: `packages/app/src/app/file-explorer.tsx:690-698` presents the offline host as an error and asks users to "Connect this host and try again."
- [ ] Audit the agent detail flows for the same issue (offline agent screen + delete sheet) and replace the "connect this host" requirement with passive/offline messaging.
- Context: `packages/app/src/app/agent/[serverId]/[agentId].tsx:651-660` and `packages/app/src/components/agent-list.tsx:149` continue to show destructive states directing users to manually connect before managing agents.
### 6. Agent Creation Flow
- [ ] Remove reliance on "primary" or "active" daemon for agent creation.