mirror of
https://github.com/getpaseo/paseo.git
synced 2026-07-29 12:01:31 +00:00
Eliminate hidden host defaults
This commit is contained in:
@@ -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("");
|
||||
|
||||
@@ -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]);
|
||||
}
|
||||
|
||||
9
plan.md
9
plan.md
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user