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:
Mohamed Boudra
2026-04-14 04:07:36 +07:00
249 changed files with 9118 additions and 4973 deletions
+3 -2
View File
@@ -1,11 +1,12 @@
import { AppState, Platform } from "react-native";
import { AppState } from "react-native";
import { isNative } from "@/constants/platform";
export function getIsAppActivelyVisible(appState: string = AppState.currentState): boolean {
if (appState !== "active") {
return false;
}
if (Platform.OS !== "web") {
if (isNative) {
return true;
}
+5 -4
View File
@@ -1,5 +1,6 @@
import { Alert, Platform } from "react-native";
import { Alert } from "react-native";
import { getDesktopHost, type DesktopDialogAskOptions } from "@/desktop/host";
import { isNative } from "@/constants/platform";
export interface ConfirmDialogInput {
title: string;
@@ -49,7 +50,7 @@ async function showNativeConfirmDialog(input: ConfirmDialogInput): Promise<boole
}
function getDesktopApi() {
if (Platform.OS !== "web") {
if (isNative) {
return null;
}
return getDesktopHost();
@@ -67,7 +68,7 @@ function buildDesktopAskOptions(input: ConfirmDialogInput): DesktopDialogAskOpti
}
function blurActiveWebElement(): void {
if (Platform.OS !== "web") {
if (isNative) {
return;
}
const activeElement = (globalThis as { document?: Document }).document?.activeElement;
@@ -103,7 +104,7 @@ function showWebConfirmDialog(input: ConfirmDialogInput): boolean {
}
export async function confirmDialog(input: ConfirmDialogInput): Promise<boolean> {
if (Platform.OS !== "web") {
if (isNative) {
return showNativeConfirmDialog(input);
}
+2 -2
View File
@@ -1,5 +1,4 @@
import { useEffect, useMemo, useState } from "react";
import { Platform } from "react-native";
import {
getIsElectronRuntimeMac,
getIsElectronRuntime,
@@ -10,6 +9,7 @@ import {
} from "@/constants/layout";
import { getDesktopWindow } from "@/desktop/electron/window";
import { usePanelStore } from "@/stores/panel-store";
import { isNative } from "@/constants/platform";
type RawWindowControlsPadding = {
left: number;
@@ -23,7 +23,7 @@ function useRawWindowControlsPadding(): RawWindowControlsPadding {
const [isFullscreen, setIsFullscreen] = useState(false);
useEffect(() => {
if (Platform.OS !== "web" || !getIsElectronRuntime()) return;
if (isNative || !getIsElectronRuntime()) return;
let disposed = false;
let cleanup: (() => void) | undefined;
+1 -3
View File
@@ -80,9 +80,7 @@ describe("workspace route parsing", () => {
it("parses workspace open intent from pathname query", () => {
expect(
parseHostWorkspaceOpenIntentFromPathname(
"/h/local/workspace/164?open=agent%3Aagent-1",
),
parseHostWorkspaceOpenIntentFromPathname("/h/local/workspace/164?open=agent%3Aagent-1"),
).toEqual({
kind: "agent",
agentId: "agent-1",
+6 -2
View File
@@ -321,7 +321,11 @@ export function buildHostAgentDetailRoute(serverId: string, agentId: string, wor
if (!normalizedAgentId) {
return "/" as const;
}
return buildHostWorkspaceOpenRoute(serverId, normalizedWorkspaceId, `agent:${normalizedAgentId}`);
return buildHostWorkspaceOpenRoute(
serverId,
normalizedWorkspaceId,
`agent:${normalizedAgentId}`,
);
}
const normalizedServerId = trimNonEmpty(serverId);
const normalizedAgentId = trimNonEmpty(agentId);
@@ -359,7 +363,7 @@ export function buildHostNewWorkspaceRoute(
serverId: string,
sourceDirectory: string,
options?: { displayName?: string },
){
) {
const base = buildHostRootRoute(serverId);
if (base === "/") {
return "/" as const;
+2 -2
View File
@@ -1,9 +1,9 @@
import * as Linking from "expo-linking";
import { Platform } from "react-native";
import { getDesktopHost } from "@/desktop/host";
import { isWeb } from "@/constants/platform";
export async function openExternalUrl(url: string): Promise<void> {
if (Platform.OS === "web") {
if (isWeb) {
const opener = getDesktopHost()?.opener?.openUrl;
if (typeof opener === "function") {
await opener(url);
+3 -3
View File
@@ -1,7 +1,7 @@
import { Asset } from "expo-asset";
import { Platform } from "react-native";
import { getDesktopHost } from "@/desktop/host";
import { buildNotificationRoute, resolveNotificationTarget } from "./notification-routing";
import { isNative } from "@/constants/platform";
type OsNotificationPayload = {
title: string;
@@ -80,7 +80,7 @@ async function ensureNotificationPermission(): Promise<boolean> {
}
export async function ensureOsNotificationPermission(): Promise<boolean> {
if (Platform.OS !== "web") {
if (isNative) {
return false;
}
return await ensureNotificationPermission();
@@ -154,7 +154,7 @@ function attachWebClickHandler(
export async function sendOsNotification(payload: OsNotificationPayload): Promise<boolean> {
// Mobile/native notifications should be remote push only.
if (Platform.OS !== "web") {
if (isNative) {
return false;
}
@@ -0,0 +1,47 @@
import type { ProviderSnapshotEntry, AgentProvider } from "@server/server/agent/agent-sdk-types";
import {
type AgentModeColorTier,
type AgentModeIcon,
type AgentProviderDefinition,
type AgentProviderModeDefinition,
} from "@server/server/agent/provider-manifest";
function buildProviderModes(entry: ProviderSnapshotEntry): AgentProviderModeDefinition[] {
const entryModes = entry.modes ?? [];
return entryModes.map((mode) => ({
...mode,
icon: (mode.icon ?? "ShieldCheck") as AgentModeIcon,
colorTier: (mode.colorTier ?? "moderate") as AgentModeColorTier,
}));
}
export function buildProviderDefinitions(
snapshotEntries: ProviderSnapshotEntry[] | undefined,
): AgentProviderDefinition[] {
if (!snapshotEntries?.length) {
return [];
}
return snapshotEntries.map((entry) => ({
id: entry.provider,
label: entry.label ?? entry.provider,
description: entry.description ?? "",
defaultModeId: entry.defaultModeId ?? null,
modes: buildProviderModes(entry),
}));
}
export function resolveProviderLabel(
provider: string,
snapshotEntries: ProviderSnapshotEntry[] | undefined,
): string {
return snapshotEntries?.find((entry) => entry.provider === provider)?.label ?? provider;
}
export function resolveProviderDefinition(
provider: string,
snapshotEntries: ProviderSnapshotEntry[] | undefined,
): AgentProviderDefinition | undefined {
return buildProviderDefinitions(snapshotEntries).find((definition) => definition.id === provider);
}
@@ -1,4 +1,4 @@
import { Platform } from "react-native";
import { isWeb } from "@/constants/platform";
type ListenerStats = {
adds: number;
@@ -92,7 +92,7 @@ const SOURCE_LABEL = "[ScrollJankInvestigation]";
function shouldInstall(): boolean {
const runtime = globalThis as ScrollInvestigationGlobal;
const isDev = Boolean((globalThis as { __DEV__?: boolean }).__DEV__);
return Platform.OS === "web" && isDev && !runtime.__PASEO_SCROLL_JANK_INVESTIGATION_DISABLED__;
return isWeb && isDev && !runtime.__PASEO_SCROLL_JANK_INVESTIGATION_DISABLED__;
}
function normalizeCapture(options?: AddEventListenerOptions | boolean): boolean {
+2 -1
View File
@@ -1,9 +1,10 @@
import { Platform } from "react-native";
import { getIsElectronRuntimeMac } from "@/constants/layout";
import type { ShortcutOs } from "@/utils/format-shortcut";
import { isNative } from "@/constants/platform";
export function getShortcutOs(): ShortcutOs {
if (Platform.OS !== "web") {
if (isNative) {
return Platform.OS === "ios" ? "mac" : "non-mac";
}
if (getIsElectronRuntimeMac()) return "mac";
+2 -2
View File
@@ -1,6 +1,6 @@
import { Asset } from "expo-asset";
import { File } from "expo-file-system";
import { Platform } from "react-native";
import { isWeb } from "@/constants/platform";
export { parsePcm16Wav, type Pcm16Wav } from "@/utils/pcm16-wav";
export const THINKING_TONE_REPEAT_GAP_MS = 350;
@@ -11,7 +11,7 @@ async function readThinkingToneArrayBuffer(): Promise<ArrayBuffer> {
const toneModule = require("../../assets/audio/thinking-tone.wav");
const asset = Asset.fromModule(toneModule);
if (Platform.OS === "web") {
if (isWeb) {
const response = await fetch(asset.uri);
if (!response.ok) {
throw new Error(`Failed to fetch thinking tone asset: ${response.status}`);
@@ -9,7 +9,9 @@ export type ResolvedWorkspaceScriptLink = {
function isLoopbackHost(host: string): boolean {
const normalizedHost = host.trim().toLowerCase();
return normalizedHost === "localhost" || normalizedHost === "127.0.0.1" || normalizedHost === "::1";
return (
normalizedHost === "localhost" || normalizedHost === "127.0.0.1" || normalizedHost === "::1"
);
}
function buildDirectServiceUrl(endpoint: string, port: number): string | null {