Merge origin/main into dev (second round)
Resolve 21 conflicts from latest main (provider profiles, Windows fixes, 0.1.55-rc.1). Fix all type errors and syntax issues from merge artifacts.
This commit is contained in:
@@ -1,11 +1,11 @@
|
||||
import { create } from "zustand";
|
||||
import { Platform } from "react-native";
|
||||
import { File as FSFile, Paths } from "expo-file-system";
|
||||
import * as LegacyFileSystem from "expo-file-system/legacy";
|
||||
import * as Sharing from "expo-sharing";
|
||||
import type { HostProfile } from "@/types/host-connection";
|
||||
import { buildDaemonWebSocketUrl } from "@/utils/daemon-endpoints";
|
||||
import { openExternalUrl } from "@/utils/open-external-url";
|
||||
import { isWeb } from "@/constants/platform";
|
||||
|
||||
interface DownloadProgress {
|
||||
percent: number;
|
||||
@@ -97,10 +97,10 @@ export const useDownloadStore = create<DownloadState>()((set, get) => ({
|
||||
const downloadUrl = buildDownloadUrl(
|
||||
downloadTarget.baseUrl,
|
||||
tokenResponse.token,
|
||||
Platform.OS === "web" ? downloadTarget.authCredentials : null,
|
||||
isWeb ? downloadTarget.authCredentials : null,
|
||||
);
|
||||
|
||||
if (Platform.OS === "web") {
|
||||
if (isWeb) {
|
||||
triggerBrowserDownload(downloadUrl, resolvedFileName);
|
||||
get().completeDownload(id);
|
||||
return;
|
||||
@@ -153,7 +153,7 @@ export const useDownloadStore = create<DownloadState>()((set, get) => ({
|
||||
}
|
||||
} catch (error) {
|
||||
const message = error instanceof Error ? error.message : "Failed to download file.";
|
||||
if (Platform.OS === "web") {
|
||||
if (isWeb) {
|
||||
console.warn("[DownloadStore] Download failed:", message);
|
||||
get().failDownload(id, message);
|
||||
return;
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { create } from "zustand";
|
||||
import { persist, createJSONStorage } from "zustand/middleware";
|
||||
import AsyncStorage from "@react-native-async-storage/async-storage";
|
||||
import { Platform } from "react-native";
|
||||
import {
|
||||
buildExplorerCheckoutKey,
|
||||
coerceExplorerTabForCheckout,
|
||||
@@ -9,6 +8,7 @@ import {
|
||||
resolveExplorerTabForCheckout,
|
||||
type ExplorerTab,
|
||||
} from "./explorer-tab-memory";
|
||||
import { isWeb } from "@/constants/platform";
|
||||
export type { ExplorerTab } from "./explorer-tab-memory";
|
||||
|
||||
/**
|
||||
@@ -128,7 +128,7 @@ function resolveExplorerTabFromActiveCheckout(state: PanelState): ExplorerTab |
|
||||
});
|
||||
}
|
||||
|
||||
const DEFAULT_DESKTOP_OPEN = Platform.OS === "web";
|
||||
const DEFAULT_DESKTOP_OPEN = isWeb;
|
||||
|
||||
export const usePanelStore = create<PanelState>()(
|
||||
persist(
|
||||
@@ -318,11 +318,7 @@ export const usePanelStore = create<PanelState>()(
|
||||
const state = persistedState as Partial<PanelState> & Record<string, unknown>;
|
||||
|
||||
if (version < 2) {
|
||||
if (
|
||||
Platform.OS === "web" &&
|
||||
typeof state.explorerWidth === "number" &&
|
||||
state.explorerWidth === 400
|
||||
) {
|
||||
if (isWeb && typeof state.explorerWidth === "number" && state.explorerWidth === 400) {
|
||||
state.explorerWidth = DEFAULT_EXPLORER_SIDEBAR_WIDTH;
|
||||
}
|
||||
|
||||
@@ -337,7 +333,7 @@ export const usePanelStore = create<PanelState>()(
|
||||
|
||||
if (version < 3) {
|
||||
if (
|
||||
Platform.OS === "web" &&
|
||||
isWeb &&
|
||||
typeof state.explorerWidth === "number" &&
|
||||
(state.explorerWidth === 400 || state.explorerWidth === 520)
|
||||
) {
|
||||
|
||||
@@ -46,10 +46,7 @@ describe("provider-recency-store", () => {
|
||||
useProviderRecencyStore.getState().recordUsage("opencode");
|
||||
useProviderRecencyStore.getState().recordUsage("codex");
|
||||
|
||||
expect(useProviderRecencyStore.getState().recentProviderIds).toEqual([
|
||||
"codex",
|
||||
"opencode",
|
||||
]);
|
||||
expect(useProviderRecencyStore.getState().recentProviderIds).toEqual(["codex", "opencode"]);
|
||||
});
|
||||
|
||||
it("filters invalid and duplicate providers during migration", () => {
|
||||
|
||||
@@ -67,7 +67,9 @@ export function sortProvidersByRecency<T extends { id: string }>(
|
||||
.map((entry) => entry.provider);
|
||||
}
|
||||
|
||||
function migratePersistedState(state: unknown): Pick<ProviderRecencyStoreState, "recentProviderIds"> {
|
||||
function migratePersistedState(
|
||||
state: unknown,
|
||||
): Pick<ProviderRecencyStoreState, "recentProviderIds"> {
|
||||
const record = state as { recentProviderIds?: string[] } | null | undefined;
|
||||
return {
|
||||
recentProviderIds: sanitizeRecentProviderIds(record?.recentProviderIds),
|
||||
|
||||
@@ -110,7 +110,6 @@ interface OpenTabInLayoutResult {
|
||||
tabId: string;
|
||||
}
|
||||
|
||||
|
||||
interface RetargetTabInLayoutInput {
|
||||
layout: WorkspaceLayout;
|
||||
tabId: string;
|
||||
@@ -802,7 +801,8 @@ function replaceTabInTree(
|
||||
}
|
||||
: tab,
|
||||
),
|
||||
focusedTabId: node.pane.focusedTabId === input.tabId ? input.nextTabId : node.pane.focusedTabId,
|
||||
focusedTabId:
|
||||
node.pane.focusedTabId === input.tabId ? input.nextTabId : node.pane.focusedTabId,
|
||||
}),
|
||||
};
|
||||
});
|
||||
@@ -1388,7 +1388,9 @@ function isEntityTarget(
|
||||
return target.kind === "agent" || target.kind === "terminal";
|
||||
}
|
||||
|
||||
function isAgentTab(tab: WorkspaceTab): tab is WorkspaceTab & { target: { kind: "agent"; agentId: string } } {
|
||||
function isAgentTab(
|
||||
tab: WorkspaceTab,
|
||||
): tab is WorkspaceTab & { target: { kind: "agent"; agentId: string } } {
|
||||
return tab.target.kind === "agent";
|
||||
}
|
||||
|
||||
@@ -1398,7 +1400,10 @@ function isTerminalTab(
|
||||
return tab.target.kind === "terminal";
|
||||
}
|
||||
|
||||
function openEntityTabWithoutFocusing(layout: WorkspaceLayout, target: WorkspaceTabTarget): WorkspaceLayout {
|
||||
function openEntityTabWithoutFocusing(
|
||||
layout: WorkspaceLayout,
|
||||
target: WorkspaceTabTarget,
|
||||
): WorkspaceLayout {
|
||||
const internalLayout = asInternalLayout(layout);
|
||||
const focusedPane =
|
||||
findPaneById(internalLayout.root, internalLayout.focusedPaneId) ??
|
||||
@@ -1445,7 +1450,9 @@ export function reconcileWorkspaceTabs(
|
||||
}
|
||||
|
||||
const initialTabs = collectAllTabs(nextLayout.root);
|
||||
const representedAgentIds = new Set(initialTabs.filter(isAgentTab).map((tab) => tab.target.agentId));
|
||||
const representedAgentIds = new Set(
|
||||
initialTabs.filter(isAgentTab).map((tab) => tab.target.agentId),
|
||||
);
|
||||
|
||||
const entityGroups = new Map<
|
||||
string,
|
||||
@@ -1482,10 +1489,7 @@ export function reconcileWorkspaceTabs(
|
||||
if (group.tabs.some((tab) => tab.tabId === originalFocusedTabId)) {
|
||||
reconciledFocusedTabId = canonicalTabId;
|
||||
}
|
||||
if (
|
||||
keeper.tabId !== canonicalTabId ||
|
||||
!workspaceTabTargetsEqual(keeper.target, group.target)
|
||||
) {
|
||||
if (keeper.tabId !== canonicalTabId || !workspaceTabTargetsEqual(keeper.target, group.target)) {
|
||||
nextLayout = {
|
||||
root: replaceTabInTree(asInternalLayout(nextLayout).root, {
|
||||
tabId: keeper.tabId,
|
||||
@@ -1515,7 +1519,11 @@ export function reconcileWorkspaceTabs(
|
||||
tabId: tab.tabId,
|
||||
}) ?? nextLayout;
|
||||
}
|
||||
if (isTerminalTab(tab) && snapshot.terminalsHydrated && !standaloneTerminalIds.has(tab.target.terminalId)) {
|
||||
if (
|
||||
isTerminalTab(tab) &&
|
||||
snapshot.terminalsHydrated &&
|
||||
!standaloneTerminalIds.has(tab.target.terminalId)
|
||||
) {
|
||||
nextLayout =
|
||||
closeTabInLayout({
|
||||
layout: nextLayout,
|
||||
|
||||
@@ -393,8 +393,9 @@ describe("workspace-layout-store actions", () => {
|
||||
});
|
||||
|
||||
it("retargetTab closes a draft tab and focuses the existing canonical target tab", () => {
|
||||
vi.spyOn(globalThis.crypto, "randomUUID")
|
||||
.mockReturnValueOnce("55555555-5555-5555-5555-555555555555");
|
||||
vi.spyOn(globalThis.crypto, "randomUUID").mockReturnValueOnce(
|
||||
"55555555-5555-5555-5555-555555555555",
|
||||
);
|
||||
const workspaceKey = createWorkspaceKey();
|
||||
const store = useWorkspaceLayoutStore.getState();
|
||||
|
||||
@@ -432,12 +433,18 @@ describe("workspace-layout-store actions", () => {
|
||||
const workspaceKey = createWorkspaceKey();
|
||||
const store = useWorkspaceLayoutStore.getState();
|
||||
|
||||
const firstDraftTabId = store.openTab(workspaceKey, { kind: "draft", draftId: "draft-agent-1" });
|
||||
const firstDraftTabId = store.openTab(workspaceKey, {
|
||||
kind: "draft",
|
||||
draftId: "draft-agent-1",
|
||||
});
|
||||
const firstAgentTabId = store.retargetTab(workspaceKey, firstDraftTabId!, {
|
||||
kind: "agent",
|
||||
agentId: "agent-1",
|
||||
});
|
||||
const secondDraftTabId = store.openTab(workspaceKey, { kind: "draft", draftId: "draft-agent-2" });
|
||||
const secondDraftTabId = store.openTab(workspaceKey, {
|
||||
kind: "draft",
|
||||
draftId: "draft-agent-2",
|
||||
});
|
||||
|
||||
const nextTabId = store.retargetTab(workspaceKey, secondDraftTabId!, {
|
||||
kind: "agent",
|
||||
|
||||
@@ -33,10 +33,7 @@ interface WorkspaceSetupStoreState {
|
||||
clearServer: (serverId: string) => void;
|
||||
}
|
||||
|
||||
function buildWorkspaceSetupKey(input: {
|
||||
serverId: string;
|
||||
workspaceId: string;
|
||||
}): string | null {
|
||||
function buildWorkspaceSetupKey(input: { serverId: string; workspaceId: string }): string | null {
|
||||
return buildWorkspaceTabPersistenceKey(input);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user