fix(app,server): discover server-cached setup snapshots across sessions
807cce6a hides the "Show setup" action when there is no workspace setup
snapshot. That broke the case where setup genuinely ran on a different
WebSocket session than the one the browser reconnected with: the snapshot
was cached per-Session, so discovery returned null and the action stayed
hidden.
Share the setup snapshot cache at the websocket-server level and inject
it into every Session. On focus, the workspace screen now requests
fetchWorkspaceSetupStatus when it has no local snapshot; workspaces with
no setup history still return null, preserving 807cce6a's intent.
This commit is contained in:
@@ -976,6 +976,7 @@ function WorkspaceScreenContent({
|
||||
const workspaceSetupSnapshot = useWorkspaceSetupStore((state) =>
|
||||
persistenceKey ? (state.snapshots[persistenceKey] ?? null) : null,
|
||||
);
|
||||
const upsertWorkspaceSetupProgress = useWorkspaceSetupStore((state) => state.upsertProgress);
|
||||
const showWorkspaceSetup = shouldShowWorkspaceSetup(workspaceSetupSnapshot);
|
||||
const uiTabs = useMemo(
|
||||
() => (workspaceLayout ? collectAllTabs(workspaceLayout.root) : EMPTY_UI_TABS),
|
||||
@@ -1191,6 +1192,55 @@ function WorkspaceScreenContent({
|
||||
|
||||
const emptyWorkspaceSeedRef = useRef<string | null>(null);
|
||||
const autoOpenedSetupTabWorkspaceRef = useRef<string | null>(null);
|
||||
const requestedWorkspaceSetupStatusKeyRef = useRef<string | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (!isRouteFocused) {
|
||||
return;
|
||||
}
|
||||
if (!client || !normalizedServerId || !normalizedWorkspaceId || !persistenceKey) {
|
||||
return;
|
||||
}
|
||||
if (workspaceSetupSnapshot) {
|
||||
return;
|
||||
}
|
||||
if (requestedWorkspaceSetupStatusKeyRef.current === persistenceKey) {
|
||||
return;
|
||||
}
|
||||
|
||||
requestedWorkspaceSetupStatusKeyRef.current = persistenceKey;
|
||||
let isCancelled = false;
|
||||
|
||||
client
|
||||
.fetchWorkspaceSetupStatus(normalizedWorkspaceId)
|
||||
.then((response) => {
|
||||
if (isCancelled || response.workspaceId !== normalizedWorkspaceId || !response.snapshot) {
|
||||
return;
|
||||
}
|
||||
upsertWorkspaceSetupProgress({
|
||||
serverId: normalizedServerId,
|
||||
payload: { workspaceId: response.workspaceId, ...response.snapshot },
|
||||
});
|
||||
})
|
||||
.catch(() => {
|
||||
if (requestedWorkspaceSetupStatusKeyRef.current === persistenceKey) {
|
||||
requestedWorkspaceSetupStatusKeyRef.current = null;
|
||||
}
|
||||
});
|
||||
|
||||
return () => {
|
||||
isCancelled = true;
|
||||
};
|
||||
}, [
|
||||
client,
|
||||
isRouteFocused,
|
||||
normalizedServerId,
|
||||
normalizedWorkspaceId,
|
||||
persistenceKey,
|
||||
upsertWorkspaceSetupProgress,
|
||||
workspaceSetupSnapshot,
|
||||
]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!isRouteFocused) {
|
||||
return;
|
||||
|
||||
@@ -508,6 +508,7 @@ export type SessionOptions = {
|
||||
providerSnapshotManager?: ProviderSnapshotManager;
|
||||
scriptRouteStore?: ScriptRouteStore;
|
||||
scriptRuntimeStore?: WorkspaceScriptRuntimeStore;
|
||||
workspaceSetupSnapshots?: Map<string, WorkspaceSetupSnapshot>;
|
||||
onBranchChanged?: (
|
||||
workspaceId: string,
|
||||
oldBranch: string | null,
|
||||
@@ -726,7 +727,7 @@ export class Session {
|
||||
);
|
||||
private readonly checkoutDiffSubscriptions = new Map<string, () => void>();
|
||||
private readonly workspaceGitWatchTargets = new Map<string, WorkspaceGitWatchTarget>();
|
||||
private readonly workspaceSetupSnapshots = new Map<string, WorkspaceSetupSnapshot>();
|
||||
private readonly workspaceSetupSnapshots: Map<string, WorkspaceSetupSnapshot>;
|
||||
private readonly workspaceGitFetchSubscriptions = new Map<string, () => void>();
|
||||
private readonly workspaceGitSubscriptions = new Map<string, () => void>();
|
||||
private readonly registerVoiceSpeakHandler?: (
|
||||
@@ -775,6 +776,7 @@ export class Session {
|
||||
providerSnapshotManager,
|
||||
scriptRouteStore,
|
||||
scriptRuntimeStore,
|
||||
workspaceSetupSnapshots,
|
||||
onBranchChanged,
|
||||
getDaemonTcpPort,
|
||||
getDaemonTcpHost,
|
||||
@@ -816,6 +818,7 @@ export class Session {
|
||||
this.providerSnapshotManager = providerSnapshotManager ?? null;
|
||||
this.scriptRouteStore = scriptRouteStore ?? null;
|
||||
this.scriptRuntimeStore = scriptRuntimeStore ?? null;
|
||||
this.workspaceSetupSnapshots = workspaceSetupSnapshots ?? new Map();
|
||||
this.onBranchChanged = onBranchChanged;
|
||||
this.getDaemonTcpPort = getDaemonTcpPort ?? null;
|
||||
this.getDaemonTcpHost = getDaemonTcpHost ?? null;
|
||||
|
||||
@@ -16,6 +16,7 @@ import type { DaemonConfigStore, MutableDaemonConfig } from "./daemon-config-sto
|
||||
import {
|
||||
type ServerInfoStatusPayload,
|
||||
type SessionOutboundMessage,
|
||||
type WorkspaceSetupSnapshot,
|
||||
type WSHelloMessage,
|
||||
WSInboundMessageSchema,
|
||||
type ServerCapabilityState,
|
||||
@@ -317,6 +318,7 @@ export class VoiceAssistantWebSocketServer {
|
||||
} | null;
|
||||
private readonly voiceSpeakHandlers = new Map<string, VoiceSpeakHandler>();
|
||||
private readonly voiceCallerContexts = new Map<string, VoiceCallerContext>();
|
||||
private readonly workspaceSetupSnapshots = new Map<string, WorkspaceSetupSnapshot>();
|
||||
private readonly agentProviderRuntimeSettings: AgentProviderRuntimeSettingsMap | undefined;
|
||||
private readonly providerOverrides: Record<string, ProviderOverride> | undefined;
|
||||
private readonly isDev: boolean;
|
||||
@@ -766,6 +768,7 @@ export class VoiceAssistantWebSocketServer {
|
||||
providerSnapshotManager: this.providerSnapshotManager,
|
||||
scriptRouteStore: this.scriptRouteStore ?? undefined,
|
||||
scriptRuntimeStore: this.scriptRuntimeStore ?? undefined,
|
||||
workspaceSetupSnapshots: this.workspaceSetupSnapshots,
|
||||
onBranchChanged: this.onBranchChanged ?? undefined,
|
||||
getDaemonTcpPort: this.getDaemonTcpPort ?? undefined,
|
||||
getDaemonTcpHost: this.getDaemonTcpHost ?? undefined,
|
||||
|
||||
Reference in New Issue
Block a user