mirror of
https://github.com/getpaseo/paseo.git
synced 2026-07-29 12:01:31 +00:00
chore(lint): convert type aliases to interfaces (autofix)
- Remove no-use-before-define rule (conflicts with unistyles ordering) - Add typescript/consistent-type-definitions: interface - Run oxlint --fix: 606 type->interface conversions across 268 files Typecheck green. Warnings: 5432 -> 3787 (-1645).
This commit is contained in:
@@ -18,7 +18,6 @@
|
||||
"no-empty-pattern": "warn",
|
||||
"no-self-assign": "warn",
|
||||
"no-shadow": "warn",
|
||||
"no-use-before-define": ["warn", { "functions": false, "classes": false, "variables": true }],
|
||||
"require-await": "off",
|
||||
"unicorn/consistent-function-scoping": "off",
|
||||
"unicorn/no-array-sort": "off",
|
||||
@@ -53,6 +52,7 @@
|
||||
"typescript/no-explicit-any": "warn",
|
||||
"typescript/prefer-as-const": "warn",
|
||||
"typescript/no-this-alias": "warn",
|
||||
"typescript/consistent-type-definitions": ["warn", "interface"],
|
||||
|
||||
"no-nested-ternary": "warn",
|
||||
"no-unneeded-ternary": "warn",
|
||||
|
||||
@@ -8,13 +8,13 @@ import { Buffer } from "node:buffer";
|
||||
import dotenv from "dotenv";
|
||||
import { forkPaseoHomeMetadata, resolvePaseoHomePath } from "./helpers/paseo-home-fork";
|
||||
|
||||
type WaitForServerOptions = {
|
||||
interface WaitForServerOptions {
|
||||
host?: string;
|
||||
timeoutMs?: number;
|
||||
label: string;
|
||||
childProcess?: ChildProcess | null;
|
||||
getRecentOutput?: () => string;
|
||||
};
|
||||
}
|
||||
|
||||
async function getAvailablePort(): Promise<number> {
|
||||
return new Promise((resolve, reject) => {
|
||||
@@ -197,12 +197,12 @@ function resolveOptionalPaseoHomeEnv(value: string | undefined): string | null {
|
||||
return resolvePaseoHomePath(trimmed);
|
||||
}
|
||||
|
||||
type OfferPayload = {
|
||||
interface OfferPayload {
|
||||
v: 2;
|
||||
serverId: string;
|
||||
daemonPublicKeyB64: string;
|
||||
relay: { endpoint: string };
|
||||
};
|
||||
}
|
||||
|
||||
async function createFakeGhBin(): Promise<string> {
|
||||
const binDir = await mkdtemp(path.join(tmpdir(), "paseo-e2e-gh-bin-"));
|
||||
|
||||
@@ -7,22 +7,22 @@ import { buildHostWorkspaceRoute } from "../../src/utils/host-routes";
|
||||
|
||||
const NEAR_BOTTOM_THRESHOLD_PX = 72;
|
||||
|
||||
export type ScrollMetrics = {
|
||||
export interface ScrollMetrics {
|
||||
offsetY: number;
|
||||
contentHeight: number;
|
||||
viewportHeight: number;
|
||||
distanceFromBottom: number;
|
||||
};
|
||||
}
|
||||
|
||||
export type SeededAgent = {
|
||||
export interface SeededAgent {
|
||||
id: string;
|
||||
title: string;
|
||||
expectedTailText: string;
|
||||
url: string;
|
||||
workspaceUrl: string;
|
||||
};
|
||||
}
|
||||
|
||||
export type DaemonClientInstance = {
|
||||
export interface DaemonClientInstance {
|
||||
connect(): Promise<void>;
|
||||
close(): Promise<void>;
|
||||
createAgent(options: {
|
||||
@@ -36,7 +36,7 @@ export type DaemonClientInstance = {
|
||||
}): Promise<{ id: string }>;
|
||||
sendAgentMessage(agentId: string, text: string): Promise<void>;
|
||||
waitForFinish(agentId: string, timeout?: number): Promise<{ status: string }>;
|
||||
};
|
||||
}
|
||||
|
||||
function getDaemonWsUrl(): string {
|
||||
const daemonPort = process.env.E2E_DAEMON_PORT;
|
||||
@@ -84,12 +84,12 @@ export function createReplyTurn(label: string): {
|
||||
};
|
||||
}
|
||||
|
||||
type DaemonClientConfig = {
|
||||
interface DaemonClientConfig {
|
||||
url: string;
|
||||
clientId: string;
|
||||
clientType: "cli";
|
||||
webSocketFactory?: NodeWebSocketFactory;
|
||||
};
|
||||
}
|
||||
|
||||
async function loadDaemonClientConstructor(): Promise<
|
||||
new (config: DaemonClientConfig) => DaemonClientInstance
|
||||
|
||||
@@ -11,13 +11,13 @@ import {
|
||||
buildHostWorkspaceRoute,
|
||||
} from "@/utils/host-routes";
|
||||
|
||||
export type ArchiveTabAgent = {
|
||||
export interface ArchiveTabAgent {
|
||||
id: string;
|
||||
title: string;
|
||||
cwd: string;
|
||||
};
|
||||
}
|
||||
|
||||
type ArchiveTabDaemonClient = {
|
||||
interface ArchiveTabDaemonClient {
|
||||
connect(): Promise<void>;
|
||||
close(): Promise<void>;
|
||||
createAgent(options: {
|
||||
@@ -36,7 +36,7 @@ type ArchiveTabDaemonClient = {
|
||||
predicate: (snapshot: { status: string }) => boolean,
|
||||
timeout?: number,
|
||||
): Promise<{ status: string }>;
|
||||
};
|
||||
}
|
||||
|
||||
function getDaemonPort(): string {
|
||||
const daemonPort = process.env.E2E_DAEMON_PORT;
|
||||
@@ -73,12 +73,12 @@ function buildSeededStoragePayload() {
|
||||
};
|
||||
}
|
||||
|
||||
type ArchiveTabDaemonClientConfig = {
|
||||
interface ArchiveTabDaemonClientConfig {
|
||||
url: string;
|
||||
clientId: string;
|
||||
clientType: "cli";
|
||||
webSocketFactory?: NodeWebSocketFactory;
|
||||
};
|
||||
}
|
||||
|
||||
async function loadDaemonClientConstructor(): Promise<
|
||||
new (config: ArchiveTabDaemonClientConfig) => ArchiveTabDaemonClient
|
||||
|
||||
@@ -17,21 +17,21 @@ type NewWorkspaceDaemonClient = Pick<
|
||||
| "openProject"
|
||||
>;
|
||||
|
||||
type NewWorkspaceDaemonClientConfig = {
|
||||
interface NewWorkspaceDaemonClientConfig {
|
||||
url: string;
|
||||
clientId: string;
|
||||
clientType: "cli";
|
||||
webSocketFactory?: NodeWebSocketFactory;
|
||||
};
|
||||
}
|
||||
|
||||
type OpenProjectPayload = Awaited<ReturnType<NewWorkspaceDaemonClient["openProject"]>>;
|
||||
|
||||
export type OpenedProject = {
|
||||
export interface OpenedProject {
|
||||
workspaceId: string;
|
||||
projectKey: string;
|
||||
projectDisplayName: string;
|
||||
workspaceName: string;
|
||||
};
|
||||
}
|
||||
|
||||
function getDaemonPort(): string {
|
||||
const daemonPort = process.env.E2E_DAEMON_PORT;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import WebSocket from "ws";
|
||||
|
||||
type WebSocketLike = {
|
||||
interface WebSocketLike {
|
||||
readyState: number;
|
||||
send: (data: string | Uint8Array | ArrayBuffer) => void;
|
||||
close: (code?: number, reason?: string) => void;
|
||||
@@ -14,7 +14,7 @@ type WebSocketLike = {
|
||||
onclose?: ((event: any) => void) | null;
|
||||
onerror?: ((event: any) => void) | null;
|
||||
onmessage?: ((event: any) => void) | null;
|
||||
};
|
||||
}
|
||||
|
||||
export type NodeWebSocketFactory = (
|
||||
url: string,
|
||||
|
||||
@@ -3,7 +3,7 @@ import { copyFile, mkdir, readdir, rm, stat } from "node:fs/promises";
|
||||
import { homedir } from "node:os";
|
||||
import path from "node:path";
|
||||
|
||||
export type PaseoHomeMetadataForkResult = {
|
||||
export interface PaseoHomeMetadataForkResult {
|
||||
sourceHome: string;
|
||||
targetHome: string;
|
||||
agentFiles: number;
|
||||
@@ -13,13 +13,13 @@ export type PaseoHomeMetadataForkResult = {
|
||||
copiedFiles: number;
|
||||
copiedBytes: number;
|
||||
skippedMissing: string[];
|
||||
};
|
||||
}
|
||||
|
||||
type CopyStats = {
|
||||
interface CopyStats {
|
||||
files: number;
|
||||
bytes: number;
|
||||
skippedMissing: string[];
|
||||
};
|
||||
}
|
||||
|
||||
export function resolvePaseoHomePath(value: string): string {
|
||||
if (value === "~") {
|
||||
|
||||
@@ -6,11 +6,11 @@ const SEED_NONCE_KEY = "@paseo:e2e-seed-nonce";
|
||||
const REGISTRY_KEY = "@paseo:daemon-registry";
|
||||
const E2E_KEY = "@paseo:e2e";
|
||||
|
||||
type SavedHostInput = {
|
||||
interface SavedHostInput {
|
||||
serverId: string;
|
||||
label: string;
|
||||
endpoint: string;
|
||||
};
|
||||
}
|
||||
|
||||
export function startupScenario(page: Page) {
|
||||
return new StartupScenario(page);
|
||||
|
||||
@@ -7,16 +7,16 @@ import {
|
||||
type TerminalPerfDaemonClient,
|
||||
} from "./terminal-perf";
|
||||
|
||||
type TempRepo = {
|
||||
interface TempRepo {
|
||||
path: string;
|
||||
cleanup: () => Promise<void>;
|
||||
};
|
||||
}
|
||||
|
||||
export type TerminalInstance = {
|
||||
export interface TerminalInstance {
|
||||
id: string;
|
||||
name: string;
|
||||
cwd: string;
|
||||
};
|
||||
}
|
||||
|
||||
export class TerminalE2EHarness {
|
||||
readonly client: TerminalPerfDaemonClient;
|
||||
|
||||
@@ -5,7 +5,7 @@ import { randomUUID } from "node:crypto";
|
||||
import { createNodeWebSocketFactory, type NodeWebSocketFactory } from "./node-ws-factory";
|
||||
import { buildHostWorkspaceRoute } from "../../src/utils/host-routes";
|
||||
|
||||
export type TerminalPerfDaemonClient = {
|
||||
export interface TerminalPerfDaemonClient {
|
||||
connect(): Promise<void>;
|
||||
close(): Promise<void>;
|
||||
openProject(cwd: string): Promise<{
|
||||
@@ -37,7 +37,7 @@ export type TerminalPerfDaemonClient = {
|
||||
handler: (event: { terminalId: string; type: string; data?: Uint8Array }) => void,
|
||||
): () => void;
|
||||
killTerminal(terminalId: string): Promise<{ error: string | null }>;
|
||||
};
|
||||
}
|
||||
|
||||
function getDaemonWsUrl(): string {
|
||||
const daemonPort = process.env.E2E_DAEMON_PORT;
|
||||
@@ -55,12 +55,12 @@ function getServerId(): string {
|
||||
return serverId;
|
||||
}
|
||||
|
||||
type TerminalPerfDaemonClientConfig = {
|
||||
interface TerminalPerfDaemonClientConfig {
|
||||
url: string;
|
||||
clientId: string;
|
||||
clientType: "cli";
|
||||
webSocketFactory?: NodeWebSocketFactory;
|
||||
};
|
||||
}
|
||||
|
||||
async function loadDaemonClientConstructor(): Promise<
|
||||
new (config: TerminalPerfDaemonClientConfig) => TerminalPerfDaemonClient
|
||||
@@ -191,10 +191,10 @@ export async function setupDeterministicPrompt(page: Page, sentinel?: string): P
|
||||
await page.waitForTimeout(300);
|
||||
}
|
||||
|
||||
export type LatencySample = {
|
||||
export interface LatencySample {
|
||||
char: string;
|
||||
latencyMs: number;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Measures keystroke echo round-trip latency.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { Page } from "@playwright/test";
|
||||
|
||||
export type TerminalRenderProbeSnapshot = {
|
||||
export interface TerminalRenderProbeSnapshot {
|
||||
setCount: number;
|
||||
unsetCount: number;
|
||||
writeCount: number;
|
||||
@@ -10,28 +10,28 @@ export type TerminalRenderProbeSnapshot = {
|
||||
altExitWrites: number;
|
||||
events: TerminalRenderProbeEvent[];
|
||||
frames: TerminalFrame[];
|
||||
};
|
||||
}
|
||||
|
||||
export type TerminalRenderProbeEvent = {
|
||||
export interface TerminalRenderProbeEvent {
|
||||
at: number;
|
||||
type: "set" | "unset" | "reset-write" | "clear-write" | "alt-enter-write" | "alt-exit-write";
|
||||
preview?: string;
|
||||
};
|
||||
}
|
||||
|
||||
export type TerminalFrame = {
|
||||
export interface TerminalFrame {
|
||||
at: number;
|
||||
rowCount: number;
|
||||
nonEmptyRows: number;
|
||||
firstNonEmptyRow: number | null;
|
||||
text: string;
|
||||
topText: string;
|
||||
};
|
||||
}
|
||||
|
||||
export type TerminalRenderProbeSummary = Omit<TerminalRenderProbeSnapshot, "frames"> & {
|
||||
frameCount: number;
|
||||
};
|
||||
|
||||
export type TerminalKeystrokeStressReport = {
|
||||
export interface TerminalKeystrokeStressReport {
|
||||
inputTextLength: number;
|
||||
keydownCount: number;
|
||||
inputFrameCount: number;
|
||||
@@ -70,20 +70,20 @@ export type TerminalKeystrokeStressReport = {
|
||||
keydownToXtermCommitMs: LatencyStats | null;
|
||||
firstKeydownAt: number | null;
|
||||
lastXtermCommitAt: number | null;
|
||||
};
|
||||
}
|
||||
|
||||
export type LatencyStats = {
|
||||
export interface LatencyStats {
|
||||
count: number;
|
||||
minMs: number;
|
||||
p50Ms: number;
|
||||
p95Ms: number;
|
||||
maxMs: number;
|
||||
avgMs: number;
|
||||
};
|
||||
}
|
||||
|
||||
export async function installTerminalRenderProbe(page: Page): Promise<void> {
|
||||
await page.addInitScript(() => {
|
||||
type ProbeState = {
|
||||
interface ProbeState {
|
||||
term: any;
|
||||
setCount: number;
|
||||
unsetCount: number;
|
||||
@@ -99,7 +99,7 @@ export async function installTerminalRenderProbe(page: Page): Promise<void> {
|
||||
reset: () => void;
|
||||
snapshot: () => TerminalRenderProbeSnapshot;
|
||||
startSampling: (durationMs: number) => void;
|
||||
};
|
||||
}
|
||||
|
||||
const win = window as any;
|
||||
const existingDescriptor = Object.getOwnPropertyDescriptor(win, "__paseoTerminal");
|
||||
@@ -272,29 +272,29 @@ export function summarizeTerminalRenderProbe(
|
||||
|
||||
export async function installTerminalKeystrokeStressProbe(page: Page): Promise<void> {
|
||||
await page.addInitScript(() => {
|
||||
type TimedTextEvent = {
|
||||
interface TimedTextEvent {
|
||||
at: number;
|
||||
text: string;
|
||||
bytes: number;
|
||||
};
|
||||
type TimedTextMessageEvent = {
|
||||
}
|
||||
interface TimedTextMessageEvent {
|
||||
at: number;
|
||||
bytes: number;
|
||||
kind: string | null;
|
||||
};
|
||||
type XtermWriteEvent = {
|
||||
}
|
||||
interface XtermWriteEvent {
|
||||
at: number;
|
||||
committedAt: number | null;
|
||||
text: string;
|
||||
bytes: number;
|
||||
};
|
||||
type AppProbeEvent = {
|
||||
}
|
||||
interface AppProbeEvent {
|
||||
type: string;
|
||||
at: number;
|
||||
bytes?: number;
|
||||
queueDepth?: number;
|
||||
};
|
||||
type StressProbeState = {
|
||||
}
|
||||
interface StressProbeState {
|
||||
keydowns: Array<{ at: number; key: string }>;
|
||||
inputFrames: TimedTextEvent[];
|
||||
outputFrames: TimedTextEvent[];
|
||||
@@ -303,7 +303,7 @@ export async function installTerminalKeystrokeStressProbe(page: Page): Promise<v
|
||||
appEvents: AppProbeEvent[];
|
||||
reset: () => void;
|
||||
report: (inputText: string) => TerminalKeystrokeStressReport;
|
||||
};
|
||||
}
|
||||
|
||||
const INPUT_OPCODE = 0x02;
|
||||
const OUTPUT_OPCODE = 0x01;
|
||||
|
||||
@@ -8,7 +8,7 @@ import { gotoAppShell } from "./app";
|
||||
import { createNodeWebSocketFactory, type NodeWebSocketFactory } from "./node-ws-factory";
|
||||
import type { SessionOutboundMessage } from "@server/shared/messages";
|
||||
|
||||
type WorkspaceSetupDaemonClient = {
|
||||
interface WorkspaceSetupDaemonClient {
|
||||
connect(): Promise<void>;
|
||||
close(): Promise<void>;
|
||||
openProject(cwd: string): Promise<{
|
||||
@@ -52,7 +52,7 @@ type WorkspaceSetupDaemonClient = {
|
||||
error?: string | null;
|
||||
}>;
|
||||
subscribeRawMessages(handler: (message: SessionOutboundMessage) => void): () => void;
|
||||
};
|
||||
}
|
||||
|
||||
export type WorkspaceSetupProgressPayload = Extract<
|
||||
SessionOutboundMessage,
|
||||
|
||||
@@ -3,11 +3,11 @@ import { mkdtemp, writeFile, rm, mkdir, realpath } from "node:fs/promises";
|
||||
import { tmpdir } from "node:os";
|
||||
import path from "node:path";
|
||||
|
||||
type TempRepo = {
|
||||
interface TempRepo {
|
||||
path: string;
|
||||
branchHeads: Record<string, string>;
|
||||
cleanup: () => Promise<void>;
|
||||
};
|
||||
}
|
||||
|
||||
export const createTempGitRepo = async (
|
||||
prefix = "paseo-e2e-",
|
||||
|
||||
@@ -7,13 +7,13 @@ import { waitForSidebarHydration } from "./helpers/workspace-ui";
|
||||
type WireDirection = "sent" | "received";
|
||||
type WirePhase = "startup" | "workspace_clicks";
|
||||
|
||||
type ParsedWireMessage = {
|
||||
interface ParsedWireMessage {
|
||||
type: string | null;
|
||||
requestId: string | null;
|
||||
entryCount: number | null;
|
||||
hasMore: boolean | null;
|
||||
providerEntries: ProviderSnapshotWireEntry[] | null;
|
||||
};
|
||||
}
|
||||
|
||||
type WireFrameRecord = ParsedWireMessage & {
|
||||
phase: WirePhase;
|
||||
@@ -21,23 +21,23 @@ type WireFrameRecord = ParsedWireMessage & {
|
||||
bytes: number;
|
||||
};
|
||||
|
||||
type ProviderSnapshotWireEntry = {
|
||||
interface ProviderSnapshotWireEntry {
|
||||
provider: string;
|
||||
status: string | null;
|
||||
modelCount: number;
|
||||
modeCount: number;
|
||||
bytes: number;
|
||||
};
|
||||
}
|
||||
|
||||
type WebSocketFrameEvent = {
|
||||
interface WebSocketFrameEvent {
|
||||
requestId: string;
|
||||
response: {
|
||||
opcode: number;
|
||||
payloadData: string;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
type WireSummary = {
|
||||
interface WireSummary {
|
||||
totalFrames: number;
|
||||
totalBytes: number;
|
||||
byDirection: Record<WireDirection, { frames: number; bytes: number }>;
|
||||
@@ -84,7 +84,7 @@ type WireSummary = {
|
||||
copiedFiles: number | null;
|
||||
copiedBytes: number | null;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
class WireMonitor {
|
||||
private phase: WirePhase = "startup";
|
||||
|
||||
@@ -17,7 +17,7 @@ const STRESS_TIMEOUT_MS = 15_000;
|
||||
const RUN_MANUAL_TERMINAL_PERF = process.env.PASEO_TERMINAL_PERF_E2E === "1";
|
||||
const terminalPerfDescribe = RUN_MANUAL_TERMINAL_PERF ? test.describe : test.describe.skip;
|
||||
|
||||
type DaemonEchoReport = {
|
||||
interface DaemonEchoReport {
|
||||
inputTextLength: number;
|
||||
inputFrameCount: number;
|
||||
outputEventCount: number;
|
||||
@@ -25,7 +25,7 @@ type DaemonEchoReport = {
|
||||
sendToOutputMs: LatencyStats;
|
||||
firstSendAt: number;
|
||||
lastOutputAt: number;
|
||||
};
|
||||
}
|
||||
|
||||
terminalPerfDescribe("Terminal keystroke stress", () => {
|
||||
let harness: TerminalE2EHarness;
|
||||
|
||||
@@ -19,7 +19,7 @@ function getServerId(): string {
|
||||
return serverId;
|
||||
}
|
||||
|
||||
type WorkspaceScriptStarter = {
|
||||
interface WorkspaceScriptStarter {
|
||||
startWorkspaceScript(
|
||||
workspaceId: string,
|
||||
scriptName: string,
|
||||
@@ -29,7 +29,7 @@ type WorkspaceScriptStarter = {
|
||||
terminalId: string | null;
|
||||
error: string | null;
|
||||
}>;
|
||||
};
|
||||
}
|
||||
|
||||
/** Click the sidebar row for a workspace (by ID) and wait for navigation. */
|
||||
async function navigateToWorkspaceViaSidebar(
|
||||
|
||||
@@ -98,11 +98,11 @@ import { prepareWorkspaceTab } from "@/utils/workspace-navigation";
|
||||
|
||||
polyfillCrypto();
|
||||
|
||||
export type HostRuntimeBootstrapState = {
|
||||
export interface HostRuntimeBootstrapState {
|
||||
phase: "starting-daemon" | "connecting" | "online" | "error";
|
||||
error: string | null;
|
||||
retry: () => void;
|
||||
};
|
||||
}
|
||||
|
||||
function getRouteParamValue(value: string | string[] | undefined): string | undefined {
|
||||
if (typeof value === "string") {
|
||||
|
||||
@@ -10,12 +10,12 @@ import {
|
||||
parseDataUrl,
|
||||
} from "@/attachments/utils";
|
||||
|
||||
type StoredBlobRecord = {
|
||||
interface StoredBlobRecord {
|
||||
id: string;
|
||||
blob: Blob;
|
||||
createdAt: number;
|
||||
fileName: string | null;
|
||||
};
|
||||
}
|
||||
|
||||
const DB_NAME = "paseo-attachment-bytes";
|
||||
const STORE_NAME = "attachments";
|
||||
|
||||
@@ -51,14 +51,14 @@ import { isWeb as platformIsWeb } from "@/constants/platform";
|
||||
import { useToast } from "@/contexts/toast-context";
|
||||
import { toErrorMessage } from "@/utils/error-messages";
|
||||
|
||||
type StatusOption = {
|
||||
interface StatusOption {
|
||||
id: string;
|
||||
label: string;
|
||||
};
|
||||
}
|
||||
|
||||
type StatusSelector = "provider" | "mode" | "model" | "thinking" | `feature-${string}`;
|
||||
|
||||
type ControlledAgentStatusBarProps = {
|
||||
interface ControlledAgentStatusBarProps {
|
||||
provider: string;
|
||||
providerOptions?: StatusOption[];
|
||||
selectedProviderId?: string;
|
||||
@@ -84,7 +84,7 @@ type ControlledAgentStatusBarProps = {
|
||||
onSetFeature?: (featureId: string, value: unknown) => void;
|
||||
onDropdownClose?: () => void;
|
||||
onModelSelectorOpen?: () => void;
|
||||
};
|
||||
}
|
||||
|
||||
export interface DraftAgentStatusBarProps {
|
||||
providerDefinitions: AgentProviderDefinition[];
|
||||
|
||||
@@ -11,37 +11,37 @@ import {
|
||||
} from "./stream-strategy";
|
||||
import { resolveStreamRenderStrategy } from "./stream-strategy-resolver";
|
||||
|
||||
export type StreamRenderSegments = {
|
||||
export interface StreamRenderSegments {
|
||||
historyVirtualized: StreamItem[];
|
||||
historyMounted: StreamItem[];
|
||||
liveHead: StreamItem[];
|
||||
};
|
||||
}
|
||||
|
||||
export type StreamHistoryBoundary = {
|
||||
export interface StreamHistoryBoundary {
|
||||
hasVirtualizedHistory: boolean;
|
||||
hasMountedHistory: boolean;
|
||||
hasLiveHead: boolean;
|
||||
historyToHeadGap: number;
|
||||
};
|
||||
}
|
||||
|
||||
export type StreamRenderAuxiliary = {
|
||||
export interface StreamRenderAuxiliary {
|
||||
pendingPermissions: ReactNode;
|
||||
workingIndicator: ReactNode;
|
||||
};
|
||||
}
|
||||
|
||||
export type AgentStreamRenderModel = {
|
||||
export interface AgentStreamRenderModel {
|
||||
history: StreamItem[];
|
||||
segments: StreamRenderSegments;
|
||||
boundary: StreamHistoryBoundary;
|
||||
auxiliary: StreamRenderAuxiliary;
|
||||
};
|
||||
}
|
||||
|
||||
export type BuildAgentStreamRenderModelInput = {
|
||||
export interface BuildAgentStreamRenderModelInput {
|
||||
tail: StreamItem[];
|
||||
head: StreamItem[];
|
||||
platform: "web" | "native";
|
||||
isMobileBreakpoint: boolean;
|
||||
};
|
||||
}
|
||||
|
||||
const EMPTY_STREAM_ITEMS: StreamItem[] = [];
|
||||
const EMPTY_AUXILIARY: StreamRenderAuxiliary = {
|
||||
|
||||
@@ -31,15 +31,15 @@ export function getWebMountedRecentStreamItems(): number {
|
||||
return override ?? DEFAULT_WEB_MOUNTED_RECENT_STREAM_ITEMS;
|
||||
}
|
||||
|
||||
export type IndexedStreamItem = {
|
||||
export interface IndexedStreamItem {
|
||||
item: StreamItem;
|
||||
index: number;
|
||||
};
|
||||
}
|
||||
|
||||
export type WebVirtualizedHistoryWindow = {
|
||||
export interface WebVirtualizedHistoryWindow {
|
||||
virtualizedEntries: IndexedStreamItem[];
|
||||
mountedEntries: IndexedStreamItem[];
|
||||
};
|
||||
}
|
||||
|
||||
export function estimateStreamItemHeight(item: StreamItem): number {
|
||||
switch (item.kind) {
|
||||
|
||||
@@ -14,12 +14,12 @@ function agentKey(agent: Pick<AggregatedAgent, "serverId" | "id">): string {
|
||||
return `${agent.serverId}:${agent.id}`;
|
||||
}
|
||||
|
||||
type CommandCenterRowProps = {
|
||||
interface CommandCenterRowProps {
|
||||
active: boolean;
|
||||
children: ReactNode;
|
||||
onPress: () => void;
|
||||
registerRow: (el: View | null) => void;
|
||||
};
|
||||
}
|
||||
|
||||
const CommandCenterRow = memo(function CommandCenterRow({
|
||||
active,
|
||||
|
||||
@@ -71,11 +71,11 @@ import { AttachmentLightbox } from "@/components/attachment-lightbox";
|
||||
import { openExternalUrl } from "@/utils/open-external-url";
|
||||
import { useIsDictationReady } from "@/hooks/use-is-dictation-ready";
|
||||
|
||||
type QueuedMessage = {
|
||||
interface QueuedMessage {
|
||||
id: string;
|
||||
text: string;
|
||||
attachments: ComposerAttachment[];
|
||||
};
|
||||
}
|
||||
|
||||
type AttachmentListUpdater =
|
||||
| ComposerAttachment[]
|
||||
|
||||
@@ -3,10 +3,10 @@ import Svg, { Circle } from "react-native-svg";
|
||||
import { StyleSheet, useUnistyles } from "react-native-unistyles";
|
||||
import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip";
|
||||
|
||||
type ContextWindowMeterProps = {
|
||||
interface ContextWindowMeterProps {
|
||||
maxTokens: number;
|
||||
usedTokens: number;
|
||||
};
|
||||
}
|
||||
|
||||
const SVG_SIZE = 16;
|
||||
const CENTER = SVG_SIZE / 2;
|
||||
|
||||
@@ -8,12 +8,12 @@ import { useSessionStore } from "@/stores/session-store";
|
||||
import { resolveAppVersion } from "@/utils/app-version";
|
||||
import { buildSettingsHostRoute } from "@/utils/host-routes";
|
||||
|
||||
type DaemonVersionMismatch = {
|
||||
interface DaemonVersionMismatch {
|
||||
serverId: string;
|
||||
label: string;
|
||||
appVersion: string;
|
||||
daemonVersion: string;
|
||||
};
|
||||
}
|
||||
|
||||
function useDaemonVersionMismatches(): DaemonVersionMismatch[] {
|
||||
const hosts = useHosts();
|
||||
|
||||
@@ -7,10 +7,10 @@ import { createRoot, type Root } from "react-dom/client";
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { DraggableList } from "./draggable-list.web";
|
||||
|
||||
type DndContextProps = {
|
||||
interface DndContextProps {
|
||||
onDragStart?: (event: { active: { id: string } }) => void;
|
||||
onDragCancel?: () => void;
|
||||
};
|
||||
}
|
||||
|
||||
let latestDndContextProps: DndContextProps | null = null;
|
||||
|
||||
|
||||
@@ -152,7 +152,7 @@ type WebTextInputKeyPressEvent = NativeSyntheticEvent<
|
||||
}
|
||||
>;
|
||||
|
||||
type TextAreaHandle = {
|
||||
interface TextAreaHandle {
|
||||
scrollHeight?: number;
|
||||
clientHeight?: number;
|
||||
offsetHeight?: number;
|
||||
@@ -163,7 +163,7 @@ type TextAreaHandle = {
|
||||
height?: string;
|
||||
overflowY?: string;
|
||||
} & Record<string, unknown>;
|
||||
};
|
||||
}
|
||||
|
||||
function logWebStickyBottom(_event: string, _details: Record<string, unknown>): void {
|
||||
// Intentionally disabled: this path is too noisy during voice debugging.
|
||||
|
||||
@@ -132,7 +132,7 @@ const MARKDOWN_ALLOWED_IMAGE_HANDLERS = [
|
||||
] as const;
|
||||
const MARKDOWN_TOP_LEVEL_MAX_EXCEEDED_ITEM = <Text key="dotdotdot">...</Text>;
|
||||
|
||||
type MarkdownWithStableRendererProps = {
|
||||
interface MarkdownWithStableRendererProps {
|
||||
children: ReactNode;
|
||||
style: ReturnType<typeof createMarkdownStyles>;
|
||||
rules: RenderRules;
|
||||
@@ -140,7 +140,7 @@ type MarkdownWithStableRendererProps = {
|
||||
onLinkPress: (url: string) => boolean;
|
||||
allowedImageHandlers: readonly string[];
|
||||
topLevelMaxExceededItem: ReactNode;
|
||||
};
|
||||
}
|
||||
|
||||
const MarkdownWithStableRenderer = Markdown as ComponentType<MarkdownWithStableRendererProps>;
|
||||
const WEB_TOOLCALL_SHIMMER_KEYFRAME_CSS = `
|
||||
|
||||
@@ -45,13 +45,13 @@ vi.mock("@react-native-async-storage/async-storage", () => ({
|
||||
|
||||
const SERVER_ID = "sidebar-render-count";
|
||||
|
||||
type RenderCounts = {
|
||||
interface RenderCounts {
|
||||
frame: number;
|
||||
headers: Record<string, number>;
|
||||
rows: Record<string, number>;
|
||||
projectSelection: Record<string, number>;
|
||||
rowSelection: Record<string, number>;
|
||||
};
|
||||
}
|
||||
|
||||
const runningScript: WorkspaceScriptPayload = {
|
||||
scriptName: "web",
|
||||
|
||||
@@ -7,10 +7,10 @@ import { createRoot, type Root } from "react-dom/client";
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { SortableInlineList } from "./sortable-inline-list.web";
|
||||
|
||||
type DndContextProps = {
|
||||
interface DndContextProps {
|
||||
onDragStart?: (event: { active: { id: string } }) => void;
|
||||
onDragCancel?: () => void;
|
||||
};
|
||||
}
|
||||
|
||||
let latestDndContextProps: DndContextProps | null = null;
|
||||
|
||||
|
||||
@@ -13,9 +13,9 @@ import { estimateStreamItemHeight } from "./agent-stream-web-virtualization";
|
||||
import type { StreamRenderInput, StreamStrategy, StreamViewportHandle } from "./stream-strategy";
|
||||
import { createStreamStrategy } from "./stream-strategy";
|
||||
|
||||
type CreateWebStreamStrategyInput = {
|
||||
interface CreateWebStreamStrategyInput {
|
||||
isMobileBreakpoint: boolean;
|
||||
};
|
||||
}
|
||||
|
||||
type ScrollBehaviorLike = "auto" | "smooth";
|
||||
|
||||
|
||||
@@ -21,36 +21,36 @@ export type BottomAnchorTransportBehavior = Readonly<{
|
||||
verificationRetryMode: "rescroll" | "recheck";
|
||||
}>;
|
||||
|
||||
export type StreamViewportMetrics = {
|
||||
export interface StreamViewportMetrics {
|
||||
contentHeight: number;
|
||||
viewportHeight: number;
|
||||
};
|
||||
}
|
||||
|
||||
export type StreamNearBottomInput = StreamViewportMetrics & {
|
||||
offsetY: number;
|
||||
threshold: number;
|
||||
};
|
||||
|
||||
export type StreamEdgeSlotProps = {
|
||||
export interface StreamEdgeSlotProps {
|
||||
ListHeaderComponent?: ReactElement | ComponentType<any> | null;
|
||||
ListHeaderComponentStyle?: StyleProp<ViewStyle>;
|
||||
ListFooterComponent?: ReactElement | ComponentType<any> | null;
|
||||
ListFooterComponentStyle?: StyleProp<ViewStyle>;
|
||||
};
|
||||
}
|
||||
|
||||
export type StreamViewportHandle = {
|
||||
export interface StreamViewportHandle {
|
||||
scrollToBottom: (reason?: BottomAnchorLocalRequest["reason"]) => void;
|
||||
prepareForViewportChange: () => void;
|
||||
};
|
||||
}
|
||||
|
||||
export type StreamSegmentRenderers = {
|
||||
export interface StreamSegmentRenderers {
|
||||
renderHistoryVirtualizedRow: (item: StreamItem, index: number, items: StreamItem[]) => ReactNode;
|
||||
renderHistoryMountedRow: (item: StreamItem, index: number, items: StreamItem[]) => ReactNode;
|
||||
renderLiveHeadRow: (item: StreamItem, index: number, items: StreamItem[]) => ReactNode;
|
||||
renderLiveAuxiliary: () => ReactNode;
|
||||
};
|
||||
}
|
||||
|
||||
export type StreamRenderInput = {
|
||||
export interface StreamRenderInput {
|
||||
agentId: string;
|
||||
segments: StreamRenderSegments;
|
||||
boundary: StreamHistoryBoundary;
|
||||
@@ -64,12 +64,12 @@ export type StreamRenderInput = {
|
||||
listStyle: StyleProp<ViewStyle>;
|
||||
baseListContentContainerStyle: StyleProp<ViewStyle>;
|
||||
forwardListContentContainerStyle: StyleProp<ViewStyle>;
|
||||
};
|
||||
}
|
||||
|
||||
export type ResolveStreamRenderStrategyInput = {
|
||||
export interface ResolveStreamRenderStrategyInput {
|
||||
platform: string;
|
||||
isMobileBreakpoint: boolean;
|
||||
};
|
||||
}
|
||||
|
||||
export interface StreamStrategy {
|
||||
render: (input: StreamRenderInput) => ReactNode;
|
||||
@@ -98,7 +98,7 @@ export interface StreamStrategy {
|
||||
shouldUseVirtualizedList: () => boolean;
|
||||
}
|
||||
|
||||
type StreamStrategyConfig = {
|
||||
interface StreamStrategyConfig {
|
||||
render: StreamStrategy["render"];
|
||||
orderTailReverse: boolean;
|
||||
orderHeadReverse: boolean;
|
||||
@@ -114,7 +114,7 @@ type StreamStrategyConfig = {
|
||||
useVirtualizedList: boolean;
|
||||
isNearBottom: (input: StreamNearBottomInput) => boolean;
|
||||
getBottomOffset: (metrics: StreamViewportMetrics) => number;
|
||||
};
|
||||
}
|
||||
|
||||
const NATIVE_SETTLING_VERIFICATION_DELAY_FRAMES = 4;
|
||||
|
||||
|
||||
@@ -35,11 +35,11 @@ const SCROLLBAR_HANDLE_SCROLL_VISIBILITY_MS = 1_200;
|
||||
const SCROLLBAR_HANDLE_SCROLL_ACTIVE_MS = 110;
|
||||
const WEBKIT_SCROLLBAR_STYLE_ID = "terminal-emulator-webkit-scrollbar-style";
|
||||
|
||||
type ViewportMetrics = {
|
||||
interface ViewportMetrics {
|
||||
offset: number;
|
||||
viewportSize: number;
|
||||
contentSize: number;
|
||||
};
|
||||
}
|
||||
|
||||
function buildXtermThemeKey(theme: ITheme): string {
|
||||
const values: Array<string> = [
|
||||
|
||||
@@ -51,11 +51,11 @@ const KEY_BUTTONS: Array<{ id: string; label: string; key: string }> = [
|
||||
{ id: "c", label: "C", key: "c" },
|
||||
];
|
||||
|
||||
type ModifierState = {
|
||||
interface ModifierState {
|
||||
ctrl: boolean;
|
||||
shift: boolean;
|
||||
alt: boolean;
|
||||
};
|
||||
}
|
||||
|
||||
type PendingTerminalInput =
|
||||
| {
|
||||
|
||||
@@ -15,15 +15,15 @@ import {
|
||||
|
||||
export type ToastVariant = "default" | "success" | "error";
|
||||
|
||||
export type ToastShowOptions = {
|
||||
export interface ToastShowOptions {
|
||||
icon?: ReactNode;
|
||||
variant?: ToastVariant;
|
||||
durationMs?: number;
|
||||
nativeAndroid?: boolean;
|
||||
testID?: string;
|
||||
};
|
||||
}
|
||||
|
||||
export type ToastState = {
|
||||
export interface ToastState {
|
||||
id: number;
|
||||
content: ReactNode;
|
||||
nativeMessage: string | null;
|
||||
@@ -31,13 +31,13 @@ export type ToastState = {
|
||||
variant: ToastVariant;
|
||||
durationMs: number;
|
||||
testID?: string;
|
||||
};
|
||||
}
|
||||
|
||||
export type ToastApi = {
|
||||
export interface ToastApi {
|
||||
show: (content: ReactNode, options?: ToastShowOptions) => void;
|
||||
copied: (label?: string) => void;
|
||||
error: (message: string) => void;
|
||||
};
|
||||
}
|
||||
|
||||
type ToastViewportPlacement = "app-shell" | "panel";
|
||||
|
||||
|
||||
@@ -18,14 +18,14 @@ import { ToolCallDetailsContent } from "./tool-call-details";
|
||||
|
||||
// ----- Types -----
|
||||
|
||||
export type ToolCallSheetData = {
|
||||
export interface ToolCallSheetData {
|
||||
toolName: string;
|
||||
displayName: string;
|
||||
summary?: string;
|
||||
detail?: ToolCallDetail;
|
||||
errorText?: string;
|
||||
showLoadingSkeleton?: boolean;
|
||||
};
|
||||
}
|
||||
|
||||
interface ToolCallSheetContextValue {
|
||||
openToolCall: (data: ToolCallSheetData) => void;
|
||||
|
||||
@@ -53,13 +53,13 @@ interface Rect {
|
||||
height: number;
|
||||
}
|
||||
|
||||
type ContextMenuContextValue = {
|
||||
interface ContextMenuContextValue {
|
||||
open: boolean;
|
||||
setOpen: (open: boolean) => void;
|
||||
triggerRef: React.RefObject<View | null>;
|
||||
anchorRect: Rect | null;
|
||||
setAnchorRect: (rect: Rect | null) => void;
|
||||
};
|
||||
}
|
||||
|
||||
const ContextMenuContext = createContext<ContextMenuContextValue | null>(null);
|
||||
|
||||
@@ -235,7 +235,11 @@ export function ContextMenu({
|
||||
return <ContextMenuContext.Provider value={value}>{children}</ContextMenuContext.Provider>;
|
||||
}
|
||||
|
||||
type TriggerState = { pressed: boolean; hovered: boolean; open: boolean };
|
||||
interface TriggerState {
|
||||
pressed: boolean;
|
||||
hovered: boolean;
|
||||
open: boolean;
|
||||
}
|
||||
type TriggerStyleProp = StyleProp<ViewStyle> | ((state: TriggerState) => StyleProp<ViewStyle>);
|
||||
|
||||
export function ContextMenuTrigger({
|
||||
|
||||
@@ -43,13 +43,13 @@ interface Rect {
|
||||
height: number;
|
||||
}
|
||||
|
||||
type DropdownMenuContextValue = {
|
||||
interface DropdownMenuContextValue {
|
||||
open: boolean;
|
||||
setOpen: (open: boolean) => void;
|
||||
selectItem: (onSelect: (() => void) | undefined, closeOnSelect: boolean) => void;
|
||||
flushPendingSelect: () => void;
|
||||
triggerRef: React.RefObject<View | null>;
|
||||
};
|
||||
}
|
||||
|
||||
const DropdownMenuContext = createContext<DropdownMenuContextValue | null>(null);
|
||||
|
||||
@@ -224,7 +224,11 @@ export function DropdownMenu({
|
||||
return <DropdownMenuContext.Provider value={value}>{children}</DropdownMenuContext.Provider>;
|
||||
}
|
||||
|
||||
type TriggerState = { pressed: boolean; hovered: boolean; open: boolean };
|
||||
interface TriggerState {
|
||||
pressed: boolean;
|
||||
hovered: boolean;
|
||||
open: boolean;
|
||||
}
|
||||
type TriggerStyleProp = StyleProp<ViewStyle> | ((state: TriggerState) => StyleProp<ViewStyle>);
|
||||
|
||||
interface DropdownMenuTriggerProps extends Omit<PressableProps, "style" | "children"> {
|
||||
|
||||
@@ -7,15 +7,15 @@ type SegmentedControlSize = "sm" | "md";
|
||||
|
||||
type SegmentedControlIconRenderer = (props: { color: string; size: number }) => ReactNode;
|
||||
|
||||
export type SegmentedControlOption<T extends string> = {
|
||||
export interface SegmentedControlOption<T extends string> {
|
||||
value: T;
|
||||
label: string;
|
||||
icon?: SegmentedControlIconRenderer;
|
||||
disabled?: boolean;
|
||||
testID?: string;
|
||||
};
|
||||
}
|
||||
|
||||
type SegmentedControlProps<T extends string> = {
|
||||
interface SegmentedControlProps<T extends string> {
|
||||
options: SegmentedControlOption<T>[];
|
||||
value: T;
|
||||
onValueChange: (value: T) => void;
|
||||
@@ -23,7 +23,7 @@ type SegmentedControlProps<T extends string> = {
|
||||
hideLabels?: boolean;
|
||||
style?: StyleProp<ViewStyle>;
|
||||
testID?: string;
|
||||
};
|
||||
}
|
||||
|
||||
export function SegmentedControl<T extends string>({
|
||||
options,
|
||||
|
||||
@@ -41,14 +41,14 @@ interface Rect {
|
||||
height: number;
|
||||
}
|
||||
|
||||
type TooltipContextValue = {
|
||||
interface TooltipContextValue {
|
||||
open: boolean;
|
||||
setOpen: (open: boolean) => void;
|
||||
triggerRef: React.RefObject<View | null>;
|
||||
enabled: boolean;
|
||||
openOnPress: boolean;
|
||||
delayDuration: number;
|
||||
};
|
||||
}
|
||||
|
||||
const TooltipContext = createContext<TooltipContextValue | null>(null);
|
||||
|
||||
|
||||
@@ -3,16 +3,16 @@ import type { BottomAnchorTransportBehavior } from "./agent-stream-render-strate
|
||||
|
||||
export type BottomAnchorMode = "sticky-bottom" | "detached";
|
||||
|
||||
export type BottomAnchorRouteRequest = {
|
||||
export interface BottomAnchorRouteRequest {
|
||||
reason: "initial-entry" | "resume";
|
||||
agentId: string;
|
||||
requestKey: string;
|
||||
};
|
||||
}
|
||||
|
||||
export type BottomAnchorLocalRequest = {
|
||||
export interface BottomAnchorLocalRequest {
|
||||
reason: "jump-to-bottom" | "message-sent";
|
||||
agentId: string;
|
||||
};
|
||||
}
|
||||
|
||||
export type BottomAnchorBlockedReason =
|
||||
| "waiting_for_history_readiness"
|
||||
@@ -24,14 +24,14 @@ type BottomAnchorRequestReason =
|
||||
| BottomAnchorRouteRequest["reason"]
|
||||
| BottomAnchorLocalRequest["reason"];
|
||||
|
||||
type BottomAnchorRequest = {
|
||||
interface BottomAnchorRequest {
|
||||
id: number;
|
||||
agentId: string;
|
||||
reason: BottomAnchorRequestReason;
|
||||
requestKey: string;
|
||||
};
|
||||
}
|
||||
|
||||
type ControllerMeasurementState = {
|
||||
interface ControllerMeasurementState {
|
||||
containerKey: string;
|
||||
viewportWidth: number;
|
||||
viewportHeight: number;
|
||||
@@ -39,23 +39,23 @@ type ControllerMeasurementState = {
|
||||
offsetY: number;
|
||||
viewportMeasuredForKey: string | null;
|
||||
contentMeasuredForKey: string | null;
|
||||
};
|
||||
}
|
||||
|
||||
type AttemptContext = {
|
||||
interface AttemptContext {
|
||||
requestId: number | null;
|
||||
retries: number;
|
||||
confirmationPasses?: number;
|
||||
startedContentHeight?: number;
|
||||
startedOffsetY?: number;
|
||||
startedViewportHeight?: number;
|
||||
};
|
||||
}
|
||||
|
||||
type ScheduledFrameHandle = {
|
||||
interface ScheduledFrameHandle {
|
||||
cancelled: boolean;
|
||||
rafId: number | null;
|
||||
remainingFrames: number;
|
||||
callback: () => void;
|
||||
};
|
||||
}
|
||||
|
||||
type BottomAnchorEvent =
|
||||
| "request_created"
|
||||
@@ -69,7 +69,7 @@ type BottomAnchorEvent =
|
||||
| "verification_scheduled"
|
||||
| "blocked_reason_changed";
|
||||
|
||||
type BottomAnchorControllerDriver = {
|
||||
interface BottomAnchorControllerDriver {
|
||||
destroy: () => void;
|
||||
getSnapshot: () => {
|
||||
mode: BottomAnchorMode;
|
||||
@@ -99,9 +99,9 @@ type BottomAnchorControllerDriver = {
|
||||
}) => void;
|
||||
notifyAuthoritativeHistoryMaybeChanged: () => void;
|
||||
reevaluate: (animated?: boolean) => void;
|
||||
};
|
||||
}
|
||||
|
||||
type CreateBottomAnchorControllerDriverInput = {
|
||||
interface CreateBottomAnchorControllerDriverInput {
|
||||
getAgentId: () => string;
|
||||
getIsAuthoritativeHistoryReady: () => boolean;
|
||||
getRenderStrategy: () => string;
|
||||
@@ -116,7 +116,7 @@ type CreateBottomAnchorControllerDriverInput = {
|
||||
delayFrames?: number;
|
||||
}) => unknown;
|
||||
cancelFrame: (handle: unknown) => void;
|
||||
};
|
||||
}
|
||||
|
||||
const MAX_VERIFICATION_RETRIES = 3;
|
||||
const WEB_PARTIAL_VIRTUALIZED_CONFIRMATION_DELAY_FRAMES = 1;
|
||||
|
||||
@@ -4,20 +4,20 @@ function clamp(value: number, min: number, max: number): number {
|
||||
return Math.min(max, Math.max(min, value));
|
||||
}
|
||||
|
||||
export type VerticalScrollbarGeometryInput = {
|
||||
export interface VerticalScrollbarGeometryInput {
|
||||
viewportSize: number;
|
||||
contentSize: number;
|
||||
offset: number;
|
||||
minHandleSize?: number;
|
||||
};
|
||||
}
|
||||
|
||||
export type VerticalScrollbarGeometry = {
|
||||
export interface VerticalScrollbarGeometry {
|
||||
isVisible: boolean;
|
||||
maxScrollOffset: number;
|
||||
handleSize: number;
|
||||
handleOffset: number;
|
||||
maxHandleOffset: number;
|
||||
};
|
||||
}
|
||||
|
||||
export function computeVerticalScrollbarGeometry(
|
||||
input: VerticalScrollbarGeometryInput,
|
||||
@@ -55,12 +55,12 @@ export function computeVerticalScrollbarGeometry(
|
||||
};
|
||||
}
|
||||
|
||||
export type ScrollOffsetFromDragDeltaInput = {
|
||||
export interface ScrollOffsetFromDragDeltaInput {
|
||||
startOffset: number;
|
||||
dragDelta: number;
|
||||
maxScrollOffset: number;
|
||||
maxHandleOffset: number;
|
||||
};
|
||||
}
|
||||
|
||||
export function computeScrollOffsetFromDragDelta(input: ScrollOffsetFromDragDeltaInput): number {
|
||||
if (input.maxScrollOffset <= 0 || input.maxHandleOffset <= 0) {
|
||||
|
||||
@@ -37,11 +37,11 @@ function clamp(value: number, min: number, max: number): number {
|
||||
return Math.min(max, Math.max(min, value));
|
||||
}
|
||||
|
||||
export type ScrollbarMetrics = {
|
||||
export interface ScrollbarMetrics {
|
||||
offset: number;
|
||||
viewportSize: number;
|
||||
contentSize: number;
|
||||
};
|
||||
}
|
||||
|
||||
function areMetricsEqual(a: ScrollbarMetrics, b: ScrollbarMetrics): boolean {
|
||||
return (
|
||||
@@ -107,12 +107,12 @@ export function useWebDesktopScrollbarMetrics() {
|
||||
};
|
||||
}
|
||||
|
||||
type WebDesktopScrollbarOverlayProps = {
|
||||
interface WebDesktopScrollbarOverlayProps {
|
||||
enabled: boolean;
|
||||
metrics: ScrollbarMetrics;
|
||||
onScrollToOffset: (offset: number) => void;
|
||||
inverted?: boolean;
|
||||
};
|
||||
}
|
||||
|
||||
export function WebDesktopScrollbarOverlay({
|
||||
enabled,
|
||||
|
||||
@@ -16,14 +16,14 @@ import { PaseoLogo } from "@/components/icons/paseo-logo";
|
||||
import { openExternalUrl } from "@/utils/open-external-url";
|
||||
import { isWeb, isNative } from "@/constants/platform";
|
||||
|
||||
type WelcomeAction = {
|
||||
interface WelcomeAction {
|
||||
key: "scan-qr" | "direct-connection" | "paste-pairing-link";
|
||||
label: string;
|
||||
testID: string;
|
||||
primary: boolean;
|
||||
icon: typeof QrCode;
|
||||
onPress: () => void;
|
||||
};
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create((theme) => ({
|
||||
root: {
|
||||
|
||||
@@ -25,11 +25,11 @@ const AGENT_STREAM_REDUCER_FLUSH_DELAY_MS = 16 * 3;
|
||||
// Shared cursor type
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
export type TimelineCursor = {
|
||||
export interface TimelineCursor {
|
||||
epoch: string;
|
||||
startSeq: number;
|
||||
endSeq: number;
|
||||
};
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Side-effect discriminated unions
|
||||
@@ -39,10 +39,10 @@ export type TimelineReducerSideEffect =
|
||||
| { type: "catch_up"; cursor: { epoch: string; endSeq: number } }
|
||||
| { type: "flush_pending_updates" };
|
||||
|
||||
export type AgentStreamReducerSideEffect = {
|
||||
export interface AgentStreamReducerSideEffect {
|
||||
type: "catch_up";
|
||||
cursor: { epoch: string; endSeq: number };
|
||||
};
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// processTimelineResponse
|
||||
@@ -51,13 +51,13 @@ export type AgentStreamReducerSideEffect = {
|
||||
type TimelineDirection = "tail" | "before" | "after";
|
||||
type InitRequestDirection = "tail" | "after";
|
||||
|
||||
type TimelineResponseEntry = {
|
||||
interface TimelineResponseEntry {
|
||||
seqStart: number;
|
||||
seqEnd: number;
|
||||
provider: string;
|
||||
item: Record<string, unknown>;
|
||||
timestamp: string;
|
||||
};
|
||||
}
|
||||
|
||||
export interface ProcessTimelineResponseInput {
|
||||
payload: {
|
||||
@@ -337,37 +337,37 @@ export interface ProcessAgentStreamEventOutput {
|
||||
sideEffects: AgentStreamReducerSideEffect[];
|
||||
}
|
||||
|
||||
export type AgentStreamReducerEvent = {
|
||||
export interface AgentStreamReducerEvent {
|
||||
event: AgentStreamEventPayload;
|
||||
seq: number | undefined;
|
||||
epoch: string | undefined;
|
||||
timestamp: Date;
|
||||
};
|
||||
}
|
||||
|
||||
export type AgentStreamReducerAgentSnapshot = {
|
||||
export interface AgentStreamReducerAgentSnapshot {
|
||||
status: AgentLifecycleStatus;
|
||||
updatedAt: Date;
|
||||
lastActivityAt: Date;
|
||||
};
|
||||
}
|
||||
|
||||
export type ProcessAgentStreamEventsInput = {
|
||||
export interface ProcessAgentStreamEventsInput {
|
||||
events: AgentStreamReducerEvent[];
|
||||
currentTail: StreamItem[];
|
||||
currentHead: StreamItem[];
|
||||
currentCursor: TimelineCursor | undefined;
|
||||
currentAgent: AgentStreamReducerAgentSnapshot | null;
|
||||
};
|
||||
}
|
||||
|
||||
export type AgentStreamReducerSnapshot = Omit<ProcessAgentStreamEventsInput, "events">;
|
||||
|
||||
export type AgentStreamReducerQueue = {
|
||||
export interface AgentStreamReducerQueue {
|
||||
enqueue: (agentId: string, event: AgentStreamReducerEvent) => void;
|
||||
flush: () => void;
|
||||
flushAgent: (agentId: string) => void;
|
||||
dispose: (options?: { flush?: boolean }) => void;
|
||||
};
|
||||
}
|
||||
|
||||
export type CreateAgentStreamReducerQueueInput = {
|
||||
export interface CreateAgentStreamReducerQueueInput {
|
||||
getSnapshot: (agentId: string) => AgentStreamReducerSnapshot;
|
||||
commit: (
|
||||
agentId: string,
|
||||
@@ -377,7 +377,7 @@ export type CreateAgentStreamReducerQueueInput = {
|
||||
handleSideEffects: (agentId: string, sideEffects: AgentStreamReducerSideEffect[]) => void;
|
||||
scheduleFlush: (callback: () => void) => number;
|
||||
cancelFlush: (id: number) => void;
|
||||
};
|
||||
}
|
||||
|
||||
function applyAgentPatch(
|
||||
currentAgent: AgentStreamReducerAgentSnapshot | null,
|
||||
@@ -632,12 +632,12 @@ export function createAgentStreamReducerQueue(
|
||||
};
|
||||
}
|
||||
|
||||
type StreamStatePatch = {
|
||||
interface StreamStatePatch {
|
||||
tail?: StreamItem[];
|
||||
head?: StreamItem[];
|
||||
};
|
||||
}
|
||||
|
||||
export type CreateSessionAgentStreamReducerQueueInput = {
|
||||
export interface CreateSessionAgentStreamReducerQueueInput {
|
||||
serverId: string;
|
||||
setAgentStreamState: (serverId: string, agentId: string, state: StreamStatePatch) => void;
|
||||
setAgentTimelineCursor: (
|
||||
@@ -646,7 +646,7 @@ export type CreateSessionAgentStreamReducerQueueInput = {
|
||||
) => void;
|
||||
setAgents: (serverId: string, state: (prev: Map<string, Agent>) => Map<string, Agent>) => void;
|
||||
requestCanonicalCatchUp: (agentId: string, cursor: { epoch: string; endSeq: number }) => void;
|
||||
};
|
||||
}
|
||||
|
||||
function scheduleAgentStreamReducerFlush(callback: () => void): number {
|
||||
return setTimeout(callback, AGENT_STREAM_REDUCER_FLUSH_DELAY_MS) as unknown as number;
|
||||
|
||||
@@ -3,7 +3,7 @@ import { invokeDesktopCommand } from "@/desktop/electron/invoke";
|
||||
|
||||
export type DesktopDaemonState = "starting" | "running" | "stopped" | "errored";
|
||||
|
||||
export type DesktopDaemonStatus = {
|
||||
export interface DesktopDaemonStatus {
|
||||
serverId: string;
|
||||
status: DesktopDaemonState;
|
||||
listen: string | null;
|
||||
@@ -13,25 +13,25 @@ export type DesktopDaemonStatus = {
|
||||
version: string | null;
|
||||
desktopManaged: boolean;
|
||||
error: string | null;
|
||||
};
|
||||
}
|
||||
|
||||
export type DesktopDaemonLogs = {
|
||||
export interface DesktopDaemonLogs {
|
||||
logPath: string;
|
||||
contents: string;
|
||||
};
|
||||
}
|
||||
|
||||
export type DesktopPairingOffer = {
|
||||
export interface DesktopPairingOffer {
|
||||
relayEnabled: boolean;
|
||||
url: string | null;
|
||||
qr: string | null;
|
||||
};
|
||||
}
|
||||
|
||||
export type LocalTransportTarget = {
|
||||
export interface LocalTransportTarget {
|
||||
transportType: "socket" | "pipe";
|
||||
transportPath: string;
|
||||
};
|
||||
}
|
||||
|
||||
type LocalTransportEventPayload = {
|
||||
interface LocalTransportEventPayload {
|
||||
sessionId: string;
|
||||
kind: "open" | "message" | "close" | "error";
|
||||
text?: string | null;
|
||||
@@ -39,7 +39,7 @@ type LocalTransportEventPayload = {
|
||||
code?: number | null;
|
||||
reason?: string | null;
|
||||
error?: string | null;
|
||||
};
|
||||
}
|
||||
|
||||
function isRecord(value: unknown): value is Record<string, unknown> {
|
||||
return typeof value === "object" && value !== null;
|
||||
|
||||
@@ -2,9 +2,9 @@ import { getDesktopHost } from "@/desktop/host";
|
||||
|
||||
export type DesktopEventUnlisten = () => void;
|
||||
|
||||
type EventEnvelope = {
|
||||
interface EventEnvelope {
|
||||
payload?: unknown;
|
||||
};
|
||||
}
|
||||
|
||||
export async function listenToDesktopEvent<TPayload>(
|
||||
event: string,
|
||||
|
||||
@@ -2,12 +2,12 @@ import { afterEach, describe, expect, it, vi } from "vitest";
|
||||
|
||||
type MockPlatform = "web" | "ios" | "android";
|
||||
|
||||
type GlobalSnapshot = {
|
||||
interface GlobalSnapshot {
|
||||
Notification: unknown;
|
||||
navigatorDescriptor?: PropertyDescriptor;
|
||||
windowDescriptor?: PropertyDescriptor;
|
||||
paseoDesktop: unknown;
|
||||
};
|
||||
}
|
||||
|
||||
const originalGlobals: GlobalSnapshot = {
|
||||
Notification: (globalThis as { Notification?: unknown }).Notification,
|
||||
|
||||
@@ -22,27 +22,27 @@ export interface DesktopPermissionSnapshot {
|
||||
microphone: DesktopPermissionStatus;
|
||||
}
|
||||
|
||||
type NotificationConstructorLike = {
|
||||
interface NotificationConstructorLike {
|
||||
permission?: string;
|
||||
requestPermission?: () => Promise<string>;
|
||||
};
|
||||
}
|
||||
|
||||
type MediaStreamTrackLike = {
|
||||
interface MediaStreamTrackLike {
|
||||
stop?: () => void;
|
||||
};
|
||||
}
|
||||
|
||||
type MediaStreamLike = {
|
||||
interface MediaStreamLike {
|
||||
getTracks?: () => MediaStreamTrackLike[];
|
||||
};
|
||||
}
|
||||
|
||||
type NavigatorLike = {
|
||||
interface NavigatorLike {
|
||||
mediaDevices?: {
|
||||
getUserMedia?: (constraints: { audio: boolean }) => Promise<MediaStreamLike>;
|
||||
};
|
||||
permissions?: {
|
||||
query?: (descriptor: { name: string }) => Promise<{ state?: string }>;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function shouldShowDesktopPermissionSection(): boolean {
|
||||
return isWeb && getDesktopHost() !== null;
|
||||
|
||||
@@ -2,9 +2,20 @@ import { describe, expect, it } from "vitest";
|
||||
|
||||
import { DictationStreamSender } from "@/dictation/dictation-stream-sender";
|
||||
|
||||
type FakeFinish = { dictationId: string; finalSeq: number };
|
||||
type FakeStart = { dictationId: string; format: string };
|
||||
type FakeChunk = { dictationId: string; seq: number; audio: string; format: string };
|
||||
interface FakeFinish {
|
||||
dictationId: string;
|
||||
finalSeq: number;
|
||||
}
|
||||
interface FakeStart {
|
||||
dictationId: string;
|
||||
format: string;
|
||||
}
|
||||
interface FakeChunk {
|
||||
dictationId: string;
|
||||
seq: number;
|
||||
audio: string;
|
||||
format: string;
|
||||
}
|
||||
|
||||
class FakeDaemonClient {
|
||||
isConnected = true;
|
||||
|
||||
@@ -1,13 +1,16 @@
|
||||
import { generateMessageId } from "@/types/stream";
|
||||
import type { DaemonClient } from "@server/client/daemon-client";
|
||||
|
||||
export type DictationStreamSenderParams = {
|
||||
export interface DictationStreamSenderParams {
|
||||
client: DaemonClient | null;
|
||||
format: string;
|
||||
createDictationId?: () => string;
|
||||
};
|
||||
}
|
||||
|
||||
type DictationFinishResult = { dictationId: string; text: string };
|
||||
interface DictationFinishResult {
|
||||
dictationId: string;
|
||||
text: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Small, non-React state machine for dictation streaming.
|
||||
|
||||
@@ -55,16 +55,16 @@ interface FormState {
|
||||
workingDir: string;
|
||||
}
|
||||
|
||||
type UseAgentFormStateOptions = {
|
||||
interface UseAgentFormStateOptions {
|
||||
initialServerId?: string | null;
|
||||
initialValues?: FormInitialValues;
|
||||
isVisible?: boolean;
|
||||
isCreateFlow?: boolean;
|
||||
isTargetDaemonReady?: boolean;
|
||||
onlineServerIds?: string[];
|
||||
};
|
||||
}
|
||||
|
||||
export type UseAgentFormStateResult = {
|
||||
export interface UseAgentFormStateResult {
|
||||
selectedServerId: string | null;
|
||||
setSelectedServerId: (value: string | null) => void;
|
||||
setSelectedServerIdFromUser: (value: string | null) => void;
|
||||
@@ -95,7 +95,7 @@ export type UseAgentFormStateResult = {
|
||||
setProviderAndModelFromUser: (provider: AgentProvider, modelId: string) => void;
|
||||
workingDirIsEmpty: boolean;
|
||||
persistFormPreferences: () => Promise<void>;
|
||||
};
|
||||
}
|
||||
|
||||
function normalizeSelectedModelId(modelId: string | null | undefined): string {
|
||||
const normalized = typeof modelId === "string" ? modelId.trim() : "";
|
||||
|
||||
@@ -26,10 +26,10 @@ export interface AgentHistoryResult {
|
||||
loadMore: () => void;
|
||||
}
|
||||
|
||||
type AgentHistoryPage = {
|
||||
interface AgentHistoryPage {
|
||||
agents: AggregatedAgent[];
|
||||
pageInfo: FetchAgentHistoryPageInfo;
|
||||
};
|
||||
}
|
||||
|
||||
async function fetchAgentHistoryPage(input: {
|
||||
client: DaemonClient;
|
||||
|
||||
@@ -16,25 +16,25 @@ type AttachmentUpdater =
|
||||
| ComposerAttachment[]
|
||||
| ((prev: ComposerAttachment[]) => ComposerAttachment[]);
|
||||
|
||||
type AgentInputDraftComposerOptions = {
|
||||
interface AgentInputDraftComposerOptions {
|
||||
initialServerId: string | null;
|
||||
initialValues?: CreateAgentInitialValues;
|
||||
isVisible?: boolean;
|
||||
onlineServerIds?: string[];
|
||||
lockedWorkingDir?: string;
|
||||
};
|
||||
}
|
||||
|
||||
type DraftKeyContext = {
|
||||
interface DraftKeyContext {
|
||||
selectedServerId: string | null;
|
||||
};
|
||||
}
|
||||
|
||||
type DraftKeyInput = string | ((context: DraftKeyContext) => string);
|
||||
|
||||
type UseAgentInputDraftInput = {
|
||||
interface UseAgentInputDraftInput {
|
||||
draftKey: DraftKeyInput;
|
||||
initialCwd?: string;
|
||||
composer?: AgentInputDraftComposerOptions;
|
||||
};
|
||||
}
|
||||
|
||||
type DraftComposerState = UseAgentFormStateResult & {
|
||||
workingDir: string;
|
||||
|
||||
@@ -4,13 +4,13 @@ import { JSDOM } from "jsdom";
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { useClientActivity } from "./use-client-activity";
|
||||
|
||||
type HeartbeatPayload = {
|
||||
interface HeartbeatPayload {
|
||||
deviceType: "web" | "mobile";
|
||||
focusedAgentId: string | null;
|
||||
lastActivityAt: string;
|
||||
appVisible: boolean;
|
||||
appVisibilityChangedAt?: string;
|
||||
};
|
||||
}
|
||||
|
||||
const { platformState, getDesktopSystemIdleTimeMs } = vi.hoisted(() => ({
|
||||
platformState: {
|
||||
|
||||
@@ -51,14 +51,14 @@ function sortAgents(left: AggregatedAgent, right: AggregatedAgent): number {
|
||||
return right.lastActivityAt.getTime() - left.lastActivityAt.getTime();
|
||||
}
|
||||
|
||||
type CommandCenterActionDefinition = {
|
||||
interface CommandCenterActionDefinition {
|
||||
id: string;
|
||||
title: string;
|
||||
icon?: "plus" | "settings";
|
||||
actionId?: string;
|
||||
keywords: string[];
|
||||
routeKind: "settings" | "none";
|
||||
};
|
||||
}
|
||||
|
||||
const COMMAND_CENTER_ACTIONS: readonly CommandCenterActionDefinition[] = [
|
||||
{
|
||||
@@ -87,14 +87,14 @@ function matchesActionQuery(query: string, action: CommandCenterActionDefinition
|
||||
return action.keywords.some((keyword) => keyword.includes(normalized));
|
||||
}
|
||||
|
||||
export type CommandCenterActionItem = {
|
||||
export interface CommandCenterActionItem {
|
||||
kind: "action";
|
||||
id: string;
|
||||
title: string;
|
||||
icon?: "plus" | "settings";
|
||||
route?: Href;
|
||||
shortcutKeys?: ShortcutKey[][];
|
||||
};
|
||||
}
|
||||
|
||||
export type CommandCenterItem =
|
||||
| {
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
export type DictationAudioSourceConfig = {
|
||||
export interface DictationAudioSourceConfig {
|
||||
onPcmSegment: (pcm16Base64: string) => void;
|
||||
onError?: (error: Error) => void;
|
||||
};
|
||||
}
|
||||
|
||||
export type DictationAudioSource = {
|
||||
export interface DictationAudioSource {
|
||||
start: () => Promise<void>;
|
||||
stop: () => Promise<void>;
|
||||
volume: number;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -82,13 +82,13 @@ const int16ToBase64 = (pcm: Int16Array): string => {
|
||||
return btoa(binary);
|
||||
};
|
||||
|
||||
type RecorderRefs = {
|
||||
interface RecorderRefs {
|
||||
recorder: MediaRecorder | null;
|
||||
audioChunks: Blob[];
|
||||
stoppedPromise: Promise<Blob> | null;
|
||||
stoppedResolve: ((blob: Blob) => void) | null;
|
||||
stoppedReject: ((error: unknown) => void) | null;
|
||||
};
|
||||
}
|
||||
|
||||
export function useDictationAudioSource(config: DictationAudioSourceConfig): DictationAudioSource {
|
||||
const [volume, setVolume] = useState(0);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
export type DictationStatus = "idle" | "recording" | "uploading" | "failed";
|
||||
|
||||
export type UseDictationOptions = {
|
||||
export interface UseDictationOptions {
|
||||
client: import("@server/client/daemon-client").DaemonClient | null;
|
||||
onTranscript: (text: string, meta: { requestId: string }) => void;
|
||||
onPartialTranscript?: (text: string, meta: { requestId: string }) => void;
|
||||
@@ -10,9 +10,9 @@ export type UseDictationOptions = {
|
||||
canConfirm?: () => boolean;
|
||||
autoStopWhenHidden?: { isVisible: boolean };
|
||||
enableDuration?: boolean;
|
||||
};
|
||||
}
|
||||
|
||||
export type UseDictationResult = {
|
||||
export interface UseDictationResult {
|
||||
isRecording: boolean;
|
||||
isProcessing: boolean;
|
||||
partialTranscript: string;
|
||||
@@ -26,7 +26,7 @@ export type UseDictationResult = {
|
||||
retryFailedDictation: () => Promise<void>;
|
||||
discardFailedDictation: () => void;
|
||||
reset: () => void;
|
||||
};
|
||||
}
|
||||
|
||||
export const DURATION_TICK_MS = 1000;
|
||||
export const PCM_DICTATION_FORMAT = "audio/pcm;rate=16000;bits=16";
|
||||
|
||||
@@ -11,12 +11,12 @@ import type { AgentAttachment } from "@server/shared/messages";
|
||||
|
||||
const EMPTY_STREAM_ITEMS: StreamItem[] = [];
|
||||
|
||||
type CreateAttempt = {
|
||||
interface CreateAttempt {
|
||||
clientMessageId: string;
|
||||
text: string;
|
||||
timestamp: Date;
|
||||
images?: UserMessageImageAttachment[];
|
||||
};
|
||||
}
|
||||
|
||||
type DraftAgentMachineState =
|
||||
| { tag: "draft"; errorMessage: string }
|
||||
@@ -56,24 +56,24 @@ function reducer(
|
||||
}
|
||||
}
|
||||
|
||||
type CreateRequestResult<TCreateResult> = {
|
||||
interface CreateRequestResult<TCreateResult> {
|
||||
agentId: string | null;
|
||||
result: TCreateResult;
|
||||
};
|
||||
}
|
||||
|
||||
type SubmitContext = {
|
||||
interface SubmitContext {
|
||||
text: string;
|
||||
attachments: ComposerAttachment[];
|
||||
cwd: string;
|
||||
};
|
||||
}
|
||||
|
||||
type CreateRequestContext = {
|
||||
interface CreateRequestContext {
|
||||
attempt: CreateAttempt;
|
||||
text: string;
|
||||
images?: UserMessageImageAttachment[];
|
||||
attachments?: AgentAttachment[];
|
||||
cwd: string;
|
||||
};
|
||||
}
|
||||
|
||||
interface UseDraftAgentCreateFlowOptions<TDraftAgent, TCreateResult> {
|
||||
draftId: string;
|
||||
|
||||
@@ -46,9 +46,9 @@ type DesktopDragDropPayload =
|
||||
type: "leave";
|
||||
};
|
||||
|
||||
type DesktopDragDropEvent = {
|
||||
interface DesktopDragDropEvent {
|
||||
payload: DesktopDragDropPayload;
|
||||
};
|
||||
}
|
||||
|
||||
function isImageFile(file: File): boolean {
|
||||
return file.type.startsWith("image/");
|
||||
|
||||
@@ -12,12 +12,12 @@ vi.mock("@/constants/platform", () => ({
|
||||
isWeb: true,
|
||||
}));
|
||||
|
||||
type RectInput = {
|
||||
interface RectInput {
|
||||
left: number;
|
||||
right: number;
|
||||
top: number;
|
||||
bottom: number;
|
||||
};
|
||||
}
|
||||
|
||||
let root: Root | null = null;
|
||||
let container: HTMLElement | null = null;
|
||||
|
||||
@@ -6,14 +6,14 @@ import {
|
||||
type KeyboardActionId,
|
||||
} from "@/keyboard/keyboard-action-dispatcher";
|
||||
|
||||
type UseKeyboardActionHandlerInput = {
|
||||
interface UseKeyboardActionHandlerInput {
|
||||
handlerId: string;
|
||||
actions: readonly KeyboardActionId[];
|
||||
enabled: boolean;
|
||||
priority: number;
|
||||
isActive?: () => boolean;
|
||||
handle: (action: KeyboardActionDefinition) => boolean;
|
||||
};
|
||||
}
|
||||
|
||||
export function useKeyboardActionHandler(input: UseKeyboardActionHandlerInput) {
|
||||
useEffect(() => {
|
||||
|
||||
@@ -11,20 +11,20 @@ import type { ProviderSnapshotEntry } from "@server/server/agent/agent-sdk-types
|
||||
import { useSessionStore } from "@/stores/session-store";
|
||||
import { providersSnapshotQueryKey, useProvidersSnapshot } from "./use-providers-snapshot";
|
||||
|
||||
type ProviderSnapshotUpdateMessage = {
|
||||
interface ProviderSnapshotUpdateMessage {
|
||||
type: "providers_snapshot_update";
|
||||
payload: {
|
||||
cwd: string;
|
||||
entries: ProviderSnapshotEntry[];
|
||||
generatedAt: string;
|
||||
};
|
||||
};
|
||||
}
|
||||
type ProviderSnapshotUpdateListener = (message: ProviderSnapshotUpdateMessage) => void;
|
||||
type ProvidersSnapshot = {
|
||||
interface ProvidersSnapshot {
|
||||
entries: ProviderSnapshotEntry[];
|
||||
generatedAt: string;
|
||||
requestId: string;
|
||||
};
|
||||
}
|
||||
type HookResult = ReturnType<typeof renderProvidersSnapshotHook>["result"];
|
||||
|
||||
const { mockClient, mockRuntime, snapshotUpdateListeners } = vi.hoisted(() => {
|
||||
|
||||
@@ -58,14 +58,14 @@ export type KeyboardActionDefinition =
|
||||
| { id: "worktree.new"; scope: KeyboardActionScope }
|
||||
| { id: "worktree.archive"; scope: KeyboardActionScope };
|
||||
|
||||
export type KeyboardActionHandler = {
|
||||
export interface KeyboardActionHandler {
|
||||
handlerId: string;
|
||||
actions: readonly KeyboardActionId[];
|
||||
enabled: boolean;
|
||||
priority: number;
|
||||
isActive?: () => boolean;
|
||||
handle: (action: KeyboardActionDefinition) => boolean;
|
||||
};
|
||||
}
|
||||
|
||||
type KeyboardActionRegistryEntry = KeyboardActionHandler & {
|
||||
registeredAt: number;
|
||||
|
||||
@@ -94,7 +94,7 @@ function expectNoShortcutResolution(input: {
|
||||
expect(result.nextChordState).toEqual(initialChordState());
|
||||
}
|
||||
|
||||
type MatchingShortcutCase = {
|
||||
interface MatchingShortcutCase {
|
||||
name: string;
|
||||
event: Partial<KeyboardEvent>;
|
||||
context?: Partial<KeyboardShortcutContext>;
|
||||
@@ -102,22 +102,22 @@ type MatchingShortcutCase = {
|
||||
payload?: unknown;
|
||||
preventDefault?: boolean;
|
||||
stopPropagation?: boolean;
|
||||
};
|
||||
}
|
||||
|
||||
type NonMatchingShortcutCase = {
|
||||
interface NonMatchingShortcutCase {
|
||||
name: string;
|
||||
event: Partial<KeyboardEvent>;
|
||||
context?: Partial<KeyboardShortcutContext>;
|
||||
};
|
||||
}
|
||||
|
||||
type HelpSectionCase = {
|
||||
interface HelpSectionCase {
|
||||
name: string;
|
||||
context: {
|
||||
isMac: boolean;
|
||||
isDesktop: boolean;
|
||||
};
|
||||
expectedKeys: Record<string, string[]>;
|
||||
};
|
||||
}
|
||||
|
||||
describe("keyboard-shortcuts", () => {
|
||||
const matchingCases: MatchingShortcutCase[] = [
|
||||
|
||||
@@ -11,41 +11,41 @@ export type { KeyCombo } from "@/keyboard/shortcut-string";
|
||||
|
||||
// --- Public types ---
|
||||
|
||||
export type KeyboardShortcutContext = {
|
||||
export interface KeyboardShortcutContext {
|
||||
isMac: boolean;
|
||||
isDesktop: boolean;
|
||||
focusScope: KeyboardFocusScope;
|
||||
commandCenterOpen: boolean;
|
||||
};
|
||||
}
|
||||
|
||||
export type KeyboardShortcutMatch = {
|
||||
export interface KeyboardShortcutMatch {
|
||||
action: KeyboardActionId;
|
||||
payload: KeyboardShortcutPayload;
|
||||
preventDefault: boolean;
|
||||
stopPropagation: boolean;
|
||||
};
|
||||
}
|
||||
|
||||
export type KeyboardShortcutHelpRow = {
|
||||
export interface KeyboardShortcutHelpRow {
|
||||
id: string;
|
||||
label: string;
|
||||
keys: ShortcutKey[];
|
||||
note?: string;
|
||||
};
|
||||
}
|
||||
|
||||
export type ShortcutSectionId = "navigation" | "tabs-panes" | "projects" | "panels" | "agent-input";
|
||||
|
||||
export type KeyboardShortcutHelpSection = {
|
||||
export interface KeyboardShortcutHelpSection {
|
||||
id: ShortcutSectionId;
|
||||
title: string;
|
||||
rows: KeyboardShortcutHelpRow[];
|
||||
};
|
||||
}
|
||||
|
||||
// --- Binding definition types ---
|
||||
|
||||
type KeyboardShortcutPlatformContext = {
|
||||
interface KeyboardShortcutPlatformContext {
|
||||
isMac: boolean;
|
||||
isDesktop: boolean;
|
||||
};
|
||||
}
|
||||
|
||||
interface ShortcutWhen {
|
||||
/** true = mac only, false = non-mac only */
|
||||
|
||||
@@ -15,7 +15,7 @@ import type { PendingPermission } from "@/types/shared";
|
||||
import type { StreamItem } from "@/types/stream";
|
||||
import type { AgentPermissionRequest } from "@server/server/agent/agent-sdk-types";
|
||||
|
||||
type PanelTestTheme = {
|
||||
interface PanelTestTheme {
|
||||
colors: {
|
||||
foreground: string;
|
||||
foregroundMuted: string;
|
||||
@@ -31,7 +31,7 @@ type PanelTestTheme = {
|
||||
fontSize: Record<string, number>;
|
||||
fontWeight: Record<string, string>;
|
||||
iconSize: Record<string, number>;
|
||||
};
|
||||
}
|
||||
type PanelTestStyles = Record<string, unknown>;
|
||||
type PanelTestStyleFactory = (input: PanelTestTheme) => PanelTestStyles;
|
||||
|
||||
|
||||
@@ -55,7 +55,7 @@ export type HostRuntimeAgentDirectoryStatus =
|
||||
| "error_before_first_success"
|
||||
| "error_after_ready";
|
||||
|
||||
export type HostRuntimeSnapshot = {
|
||||
export interface HostRuntimeSnapshot {
|
||||
serverId: string;
|
||||
activeConnectionId: string | null;
|
||||
activeConnection: ActiveConnection | null;
|
||||
@@ -68,7 +68,7 @@ export type HostRuntimeSnapshot = {
|
||||
hasEverLoadedAgentDirectory: boolean;
|
||||
probeByConnectionId: Map<string, ConnectionProbeState>;
|
||||
clientGeneration: number;
|
||||
};
|
||||
}
|
||||
|
||||
type HostRuntimeSnapshotPatch = Partial<Omit<HostRuntimeSnapshot, "serverId" | "clientGeneration">>;
|
||||
|
||||
@@ -112,7 +112,7 @@ function hashForLog(value: string): string {
|
||||
return `h_${Math.abs(hash).toString(16)}`;
|
||||
}
|
||||
|
||||
export type HostRuntimeControllerDeps = {
|
||||
export interface HostRuntimeControllerDeps {
|
||||
createClient: (input: {
|
||||
host: HostProfile;
|
||||
connection: HostConnection;
|
||||
@@ -125,15 +125,15 @@ export type HostRuntimeControllerDeps = {
|
||||
hostname: string | null;
|
||||
}>;
|
||||
getClientId: () => Promise<string>;
|
||||
};
|
||||
}
|
||||
|
||||
export type HostRuntimeStartOptions = {
|
||||
export interface HostRuntimeStartOptions {
|
||||
autoProbe?: boolean;
|
||||
initialConnection?: {
|
||||
connectionId: string;
|
||||
existingClient: DaemonClient;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
const PROBE_TICK_MS = 2_000;
|
||||
const PROBE_STEADY_MS = 10_000;
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import type { BottomAnchorRouteRequest } from "@/components/use-bottom-anchor-controller";
|
||||
|
||||
export type RouteBottomAnchorIntent = {
|
||||
export interface RouteBottomAnchorIntent {
|
||||
routeKey: string;
|
||||
reason: BottomAnchorRouteRequest["reason"];
|
||||
};
|
||||
}
|
||||
|
||||
export function deriveRouteBottomAnchorIntent(input: {
|
||||
cachedIntent: RouteBottomAnchorIntent | null;
|
||||
|
||||
@@ -12,13 +12,13 @@ import { TitlebarDragRegion } from "@/components/desktop/titlebar-drag-region";
|
||||
import { isWeb } from "@/constants/platform";
|
||||
import { useWebScrollbarStyle } from "@/hooks/use-web-scrollbar-style";
|
||||
|
||||
type StartupSplashScreenProps = {
|
||||
interface StartupSplashScreenProps {
|
||||
bootstrapState?: {
|
||||
phase: "starting-daemon" | "connecting" | "online" | "error";
|
||||
error: string | null;
|
||||
retry: () => void;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
const GITHUB_ISSUE_URL = "https://github.com/getpaseo/paseo/issues/new";
|
||||
const DOCS_URL = "https://paseo.sh/docs";
|
||||
|
||||
@@ -5,7 +5,7 @@ import {
|
||||
type WorkspaceTabLayoutResult,
|
||||
} from "@/screens/workspace/workspace-tab-layout";
|
||||
|
||||
type UseWorkspaceTabLayoutInput = {
|
||||
interface UseWorkspaceTabLayoutInput {
|
||||
tabLabelLengths: number[];
|
||||
viewportWidthOverride?: number | null;
|
||||
metrics: {
|
||||
@@ -19,11 +19,11 @@ type UseWorkspaceTabLayoutInput = {
|
||||
estimatedCharWidth: number;
|
||||
closeButtonWidth: number;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
type UseWorkspaceTabLayoutResult = {
|
||||
interface UseWorkspaceTabLayoutResult {
|
||||
layout: WorkspaceTabLayoutResult;
|
||||
};
|
||||
}
|
||||
|
||||
export function useWorkspaceTabLayout(
|
||||
input: UseWorkspaceTabLayoutInput,
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import type { DaemonClient } from "@server/client/daemon-client";
|
||||
import type { WorkspaceTabDescriptor } from "@/screens/workspace/workspace-tabs-types";
|
||||
|
||||
export type BulkClosableTabGroups = {
|
||||
export interface BulkClosableTabGroups {
|
||||
agentTabs: Array<{ tabId: string; agentId: string }>;
|
||||
terminalTabs: Array<{ tabId: string; terminalId: string }>;
|
||||
otherTabs: Array<{ tabId: string }>;
|
||||
};
|
||||
}
|
||||
|
||||
interface CloseWorkspaceTabWithCleanupInput {
|
||||
tabId: string;
|
||||
|
||||
@@ -63,7 +63,7 @@ export interface WorkspaceDesktopTabRowItem {
|
||||
isClosingTab: boolean;
|
||||
}
|
||||
|
||||
type WorkspaceDesktopTabsRowProps = {
|
||||
interface WorkspaceDesktopTabsRowProps {
|
||||
paneId?: string;
|
||||
isFocused?: boolean;
|
||||
tabs: WorkspaceDesktopTabRowItem[];
|
||||
@@ -90,7 +90,7 @@ type WorkspaceDesktopTabsRowProps = {
|
||||
activeDragTabId?: string | null;
|
||||
tabDropPreviewIndex?: number | null;
|
||||
showPaneSplitActions?: boolean;
|
||||
};
|
||||
}
|
||||
|
||||
function getFallbackTabLabel(tab: WorkspaceTabDescriptor): string {
|
||||
if (tab.target.kind === "draft") {
|
||||
|
||||
@@ -31,7 +31,7 @@ const DRAFT_CAPABILITIES: AgentCapabilityFlags = {
|
||||
supportsToolInvocations: false,
|
||||
};
|
||||
|
||||
type WorkspaceDraftAgentTabProps = {
|
||||
interface WorkspaceDraftAgentTabProps {
|
||||
serverId: string;
|
||||
workspaceId: string;
|
||||
tabId: string;
|
||||
@@ -39,7 +39,7 @@ type WorkspaceDraftAgentTabProps = {
|
||||
isPaneFocused: boolean;
|
||||
onCreated: (snapshot: AgentSnapshotPayload) => void;
|
||||
onOpenWorkspaceFile: (input: { filePath: string }) => void;
|
||||
};
|
||||
}
|
||||
|
||||
export function WorkspaceDraftAgentTab({
|
||||
serverId,
|
||||
|
||||
@@ -129,11 +129,11 @@ const EMPTY_UI_TABS: WorkspaceTab[] = [];
|
||||
const EMPTY_PINNED_AGENT_IDS = new Set<string>();
|
||||
const EMPTY_SET = new Set<string>();
|
||||
|
||||
type WorkspaceScreenProps = {
|
||||
interface WorkspaceScreenProps {
|
||||
serverId: string;
|
||||
workspaceId: string;
|
||||
isRouteFocused?: boolean;
|
||||
};
|
||||
}
|
||||
|
||||
type WorkspaceScreenContentProps = WorkspaceScreenProps & {
|
||||
isRouteFocused: boolean;
|
||||
@@ -187,7 +187,7 @@ function getFallbackTabOptionDescription(tab: WorkspaceTabDescriptor): string {
|
||||
return tab.target.path;
|
||||
}
|
||||
|
||||
type MobileWorkspaceTabSwitcherProps = {
|
||||
interface MobileWorkspaceTabSwitcherProps {
|
||||
tabs: WorkspaceTabDescriptor[];
|
||||
activeTabKey: string;
|
||||
activeTab: WorkspaceTabDescriptor | null;
|
||||
@@ -203,7 +203,7 @@ type MobileWorkspaceTabSwitcherProps = {
|
||||
onCloseTabsAbove: (tabId: string) => Promise<void> | void;
|
||||
onCloseTabsBelow: (tabId: string) => Promise<void> | void;
|
||||
onCloseOtherTabs: (tabId: string) => Promise<void> | void;
|
||||
};
|
||||
}
|
||||
|
||||
function MobileActiveTabTrigger({
|
||||
activeTab,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
export type WorkspaceTabCloseButtonPolicy = "all";
|
||||
|
||||
export type WorkspaceTabLayoutInput = {
|
||||
export interface WorkspaceTabLayoutInput {
|
||||
viewportWidth: number;
|
||||
tabLabelLengths: number[];
|
||||
metrics: {
|
||||
@@ -14,19 +14,19 @@ export type WorkspaceTabLayoutInput = {
|
||||
estimatedCharWidth: number;
|
||||
closeButtonWidth: number;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export type WorkspaceTabLayoutItem = {
|
||||
export interface WorkspaceTabLayoutItem {
|
||||
width: number;
|
||||
showLabel: boolean;
|
||||
labelCharCap: number;
|
||||
};
|
||||
}
|
||||
|
||||
export type WorkspaceTabLayoutResult = {
|
||||
export interface WorkspaceTabLayoutResult {
|
||||
items: WorkspaceTabLayoutItem[];
|
||||
closeButtonPolicy: WorkspaceTabCloseButtonPolicy;
|
||||
requiresHorizontalScrollFallback: boolean;
|
||||
};
|
||||
}
|
||||
|
||||
function clamp(value: number, min: number, max: number): number {
|
||||
if (value < min) {
|
||||
|
||||
@@ -26,12 +26,12 @@ const EMPHASIZED_STATUS_DOT_SIZE = 9;
|
||||
const DEFAULT_STATUS_DOT_OFFSET = -2;
|
||||
const EMPHASIZED_STATUS_DOT_OFFSET = -3;
|
||||
|
||||
type WorkspaceTabPresentationResolverProps = {
|
||||
interface WorkspaceTabPresentationResolverProps {
|
||||
tab: WorkspaceTabDescriptor;
|
||||
serverId: string;
|
||||
workspaceId: string;
|
||||
children: (presentation: WorkspaceTabPresentation) => ReactNode;
|
||||
};
|
||||
}
|
||||
|
||||
type WorkspaceTabPresentationResolverInnerProps = WorkspaceTabPresentationResolverProps & {
|
||||
registration: NonNullable<ReturnType<typeof getPanelRegistration>>;
|
||||
@@ -96,12 +96,12 @@ function WorkspaceTabPresentationResolverInner({
|
||||
return <>{children(presentation)}</>;
|
||||
}
|
||||
|
||||
type WorkspaceTabIconProps = {
|
||||
interface WorkspaceTabIconProps {
|
||||
presentation: WorkspaceTabPresentation;
|
||||
active?: boolean;
|
||||
size?: number;
|
||||
statusDotBorderColor?: string;
|
||||
};
|
||||
}
|
||||
|
||||
export function WorkspaceTabIcon({
|
||||
presentation,
|
||||
@@ -168,13 +168,13 @@ export function WorkspaceTabIcon({
|
||||
);
|
||||
}
|
||||
|
||||
type WorkspaceTabOptionRowProps = {
|
||||
interface WorkspaceTabOptionRowProps {
|
||||
presentation: WorkspaceTabPresentation;
|
||||
selected: boolean;
|
||||
active: boolean;
|
||||
onPress: () => void;
|
||||
trailingAccessory?: ReactNode;
|
||||
};
|
||||
}
|
||||
|
||||
export function WorkspaceTabOptionRow({
|
||||
presentation,
|
||||
|
||||
@@ -3,7 +3,7 @@ import type { UserMessageImageAttachment } from "@/types/stream";
|
||||
|
||||
export type CreateFlowLifecycleState = "active" | "abandoned" | "sent";
|
||||
|
||||
type PendingCreateAttempt = {
|
||||
interface PendingCreateAttempt {
|
||||
draftId: string;
|
||||
serverId: string;
|
||||
agentId: string | null;
|
||||
@@ -12,9 +12,9 @@ type PendingCreateAttempt = {
|
||||
timestamp: number;
|
||||
lifecycle: CreateFlowLifecycleState;
|
||||
images?: UserMessageImageAttachment[];
|
||||
};
|
||||
}
|
||||
|
||||
type CreateFlowState = {
|
||||
interface CreateFlowState {
|
||||
pendingByDraftId: Record<string, PendingCreateAttempt>;
|
||||
setPending: (pending: Omit<PendingCreateAttempt, "lifecycle">) => void;
|
||||
updateAgentId: (input: { draftId: string; agentId: string }) => void;
|
||||
@@ -22,7 +22,7 @@ type CreateFlowState = {
|
||||
rekeyDraft: (input: { fromDraftId: string; toDraftId: string }) => void;
|
||||
clear: (input: { draftId: string }) => void;
|
||||
clearAll: () => void;
|
||||
};
|
||||
}
|
||||
|
||||
export const useCreateFlowStore = create<CreateFlowState>((set) => ({
|
||||
pendingByDraftId: {},
|
||||
|
||||
@@ -236,11 +236,11 @@ function findMostRecentDownloadId(downloads: Map<string, Download>): string | nu
|
||||
return mostRecent?.id ?? null;
|
||||
}
|
||||
|
||||
type DownloadTarget = {
|
||||
interface DownloadTarget {
|
||||
baseUrl: string | null;
|
||||
authHeader: string | null;
|
||||
authCredentials: { username: string; password: string } | null;
|
||||
};
|
||||
}
|
||||
|
||||
function resolveDaemonDownloadTarget(daemon?: HostProfile): DownloadTarget {
|
||||
const endpoint = daemon?.connections.find((conn) => conn.type === "directTcp")?.endpoint ?? null;
|
||||
|
||||
@@ -14,10 +14,10 @@ import { useSessionStore } from "@/stores/session-store";
|
||||
const DRAFT_STORE_VERSION = 4;
|
||||
const FINALIZED_DRAFT_TTL_MS = 5 * 60 * 1000;
|
||||
|
||||
type LegacyDraftImage = {
|
||||
interface LegacyDraftImage {
|
||||
uri: string;
|
||||
mimeType?: string;
|
||||
};
|
||||
}
|
||||
|
||||
type PersistedDraftImage = AttachmentMetadata | LegacyDraftImage;
|
||||
|
||||
|
||||
@@ -17,15 +17,15 @@ interface ActivateWorkspaceSelectionOptions {
|
||||
historyMode?: "push" | "replace";
|
||||
}
|
||||
|
||||
type NavigationRouteParams = {
|
||||
interface NavigationRouteParams {
|
||||
serverId?: string | string[];
|
||||
workspaceId?: string | string[];
|
||||
};
|
||||
}
|
||||
|
||||
type NavigationRouteLike = {
|
||||
interface NavigationRouteLike {
|
||||
params?: NavigationRouteParams | null;
|
||||
path?: string | null;
|
||||
};
|
||||
}
|
||||
|
||||
type NavigationWorkspaceRouteState =
|
||||
| { kind: "workspace"; selection: ActiveWorkspaceSelection }
|
||||
|
||||
@@ -218,13 +218,13 @@ export interface AgentFileExplorerState {
|
||||
selectedEntryPath: string | null;
|
||||
}
|
||||
|
||||
export type DaemonServerInfo = {
|
||||
export interface DaemonServerInfo {
|
||||
serverId: string;
|
||||
hostname: string | null;
|
||||
version: string | null;
|
||||
capabilities?: ServerCapabilities;
|
||||
features?: ServerInfoStatusPayload["features"];
|
||||
};
|
||||
}
|
||||
|
||||
export interface AgentTimelineCursorState {
|
||||
epoch: string;
|
||||
|
||||
@@ -8,9 +8,9 @@ interface SidebarCollapsedSectionsState {
|
||||
setProjectCollapsed: (projectKey: string, collapsed: boolean) => void;
|
||||
}
|
||||
|
||||
type PersistedSidebarCollapsedSectionsState = {
|
||||
interface PersistedSidebarCollapsedSectionsState {
|
||||
collapsedProjectKeys?: string[];
|
||||
};
|
||||
}
|
||||
|
||||
function serializeCollapsedProjectKeys(keys: Set<string>): string[] {
|
||||
return Array.from(keys);
|
||||
|
||||
@@ -17,7 +17,7 @@ export interface PendingWorkspaceDraftSubmission {
|
||||
allowEmptyText?: boolean;
|
||||
}
|
||||
|
||||
type WorkspaceDraftSubmissionState = {
|
||||
interface WorkspaceDraftSubmissionState {
|
||||
pendingByDraftId: Record<string, PendingWorkspaceDraftSubmission>;
|
||||
setPending: (submission: PendingWorkspaceDraftSubmission) => void;
|
||||
consumePending: (input: {
|
||||
@@ -25,7 +25,7 @@ type WorkspaceDraftSubmissionState = {
|
||||
workspaceId: string;
|
||||
draftId: string;
|
||||
}) => PendingWorkspaceDraftSubmission | null;
|
||||
};
|
||||
}
|
||||
|
||||
function matchesPendingSubmission(
|
||||
pending: PendingWorkspaceDraftSubmission | null | undefined,
|
||||
|
||||
@@ -14,11 +14,11 @@ export type WorkspaceTabTarget =
|
||||
| { kind: "file"; path: string }
|
||||
| { kind: "setup"; workspaceId: string };
|
||||
|
||||
export type WorkspaceTab = {
|
||||
export interface WorkspaceTab {
|
||||
tabId: string;
|
||||
target: WorkspaceTabTarget;
|
||||
createdAt: number;
|
||||
};
|
||||
}
|
||||
|
||||
function trimNonEmpty(value: string | null | undefined): string | null {
|
||||
if (typeof value !== "string") {
|
||||
@@ -64,7 +64,7 @@ function ensureInOrder(input: { current: string[]; tabId: string }): string[] {
|
||||
return [...input.current, input.tabId];
|
||||
}
|
||||
|
||||
type WorkspaceTabsState = {
|
||||
interface WorkspaceTabsState {
|
||||
uiTabsByWorkspace: Record<string, WorkspaceTab[]>;
|
||||
tabOrderByWorkspace: Record<string, string[]>;
|
||||
focusedTabIdByWorkspace: Record<string, string>;
|
||||
@@ -94,7 +94,7 @@ type WorkspaceTabsState = {
|
||||
reorderTabs: (input: { serverId: string; workspaceId: string; tabIds: string[] }) => void;
|
||||
getWorkspaceTabs: (input: { serverId: string; workspaceId: string }) => WorkspaceTab[];
|
||||
purgeWorkspace: (input: { serverId: string; workspaceId: string }) => void;
|
||||
};
|
||||
}
|
||||
|
||||
export const useWorkspaceTabsStore = create<WorkspaceTabsState>()(
|
||||
persist(
|
||||
|
||||
@@ -30,22 +30,22 @@ StyleSheet.configure({
|
||||
});
|
||||
|
||||
// Type augmentation for TypeScript
|
||||
type AppThemes = {
|
||||
interface AppThemes {
|
||||
light: typeof lightTheme;
|
||||
dark: typeof darkTheme;
|
||||
darkZinc: typeof darkZincTheme;
|
||||
darkMidnight: typeof darkMidnightTheme;
|
||||
darkClaude: typeof darkClaudeTheme;
|
||||
darkGhostty: typeof darkGhosttyTheme;
|
||||
};
|
||||
}
|
||||
|
||||
type AppBreakpoints = {
|
||||
interface AppBreakpoints {
|
||||
xs: number;
|
||||
sm: number;
|
||||
md: number;
|
||||
lg: number;
|
||||
xl: number;
|
||||
};
|
||||
}
|
||||
|
||||
declare module "react-native-unistyles" {
|
||||
export interface UnistylesThemes extends AppThemes {}
|
||||
|
||||
@@ -10,19 +10,22 @@ vi.mock("@xterm/addon-webgl", () => ({
|
||||
},
|
||||
}));
|
||||
|
||||
type TerminalSize = { rows: number; cols: number };
|
||||
interface TerminalSize {
|
||||
rows: number;
|
||||
cols: number;
|
||||
}
|
||||
|
||||
type BrowserTerminal = TerminalSize & {
|
||||
refresh: (start: number, end: number) => void;
|
||||
reset: () => void;
|
||||
};
|
||||
|
||||
type MountedTerminal = {
|
||||
interface MountedTerminal {
|
||||
host: HTMLDivElement;
|
||||
root: HTMLDivElement;
|
||||
runtime: TerminalEmulatorRuntime;
|
||||
sizes: TerminalSize[];
|
||||
};
|
||||
}
|
||||
|
||||
const mountedTerminals: MountedTerminal[] = [];
|
||||
|
||||
|
||||
@@ -41,7 +41,7 @@ vi.mock("@xterm/xterm", () => ({
|
||||
|
||||
import { TerminalEmulatorRuntime } from "./terminal-emulator-runtime";
|
||||
|
||||
type StubTerminal = {
|
||||
interface StubTerminal {
|
||||
write: (text: string, callback?: () => void) => void;
|
||||
reset: () => void;
|
||||
resize?: (cols: number, rows: number) => void;
|
||||
@@ -50,7 +50,7 @@ type StubTerminal = {
|
||||
options?: { theme?: unknown };
|
||||
rows?: number;
|
||||
cols?: number;
|
||||
};
|
||||
}
|
||||
|
||||
function createRuntimeWithTerminal(): {
|
||||
runtime: TerminalEmulatorRuntime;
|
||||
|
||||
@@ -18,14 +18,14 @@ import {
|
||||
} from "@/utils/terminal-keys";
|
||||
import { renderTerminalSnapshotToAnsi } from "./terminal-snapshot";
|
||||
|
||||
export type TerminalEmulatorRuntimeMountInput = {
|
||||
export interface TerminalEmulatorRuntimeMountInput {
|
||||
root: HTMLDivElement;
|
||||
host: HTMLDivElement;
|
||||
initialSnapshot: TerminalState | null;
|
||||
theme: ITheme;
|
||||
};
|
||||
}
|
||||
|
||||
export type TerminalEmulatorRuntimeCallbacks = {
|
||||
export interface TerminalEmulatorRuntimeCallbacks {
|
||||
onInput?: (data: string) => Promise<void> | void;
|
||||
onResize?: (input: { rows: number; cols: number }) => Promise<void> | void;
|
||||
onTerminalKey?: (input: {
|
||||
@@ -37,9 +37,9 @@ export type TerminalEmulatorRuntimeCallbacks = {
|
||||
}) => Promise<void> | void;
|
||||
onPendingModifiersConsumed?: () => Promise<void> | void;
|
||||
onOpenExternalUrl?: (url: string) => Promise<void> | void;
|
||||
};
|
||||
}
|
||||
|
||||
type TerminalEmulatorRuntimeDisposables = {
|
||||
interface TerminalEmulatorRuntimeDisposables {
|
||||
disposeInput: () => void;
|
||||
disconnectResizeObserver: () => void;
|
||||
removeWindowResize: () => void;
|
||||
@@ -55,16 +55,16 @@ type TerminalEmulatorRuntimeDisposables = {
|
||||
disposeFitAddon: () => void;
|
||||
disposeWebglAddon: () => void;
|
||||
disposeTerminal: () => void;
|
||||
};
|
||||
}
|
||||
|
||||
type TerminalOutputOperation = {
|
||||
interface TerminalOutputOperation {
|
||||
type: "write" | "clear" | "snapshot";
|
||||
text: string;
|
||||
rows?: number;
|
||||
cols?: number;
|
||||
suppressInput?: boolean;
|
||||
onCommitted?: () => void;
|
||||
};
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface Window {
|
||||
|
||||
@@ -4,7 +4,7 @@ import { describe, expect, it } from "vitest";
|
||||
|
||||
import { renderTerminalSnapshotToAnsi } from "./terminal-snapshot";
|
||||
|
||||
type SnapshotCell = {
|
||||
interface SnapshotCell {
|
||||
char: string;
|
||||
fg: number | undefined;
|
||||
bg: number | undefined;
|
||||
@@ -13,9 +13,9 @@ type SnapshotCell = {
|
||||
bold?: boolean;
|
||||
italic?: boolean;
|
||||
underline?: boolean;
|
||||
};
|
||||
}
|
||||
|
||||
type SnapshotState = {
|
||||
interface SnapshotState {
|
||||
rows: number;
|
||||
cols: number;
|
||||
grid: SnapshotCell[][];
|
||||
@@ -27,7 +27,7 @@ type SnapshotState = {
|
||||
style?: "block" | "underline" | "bar";
|
||||
blink?: boolean;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
async function writeToTerminal(
|
||||
terminal: Pick<ClientTerminal | HeadlessTerminal, "write">,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { TerminalCell, TerminalState } from "@server/shared/messages";
|
||||
|
||||
type TerminalStyle = {
|
||||
interface TerminalStyle {
|
||||
fg: number | undefined;
|
||||
bg: number | undefined;
|
||||
fgMode: number | undefined;
|
||||
@@ -11,7 +11,7 @@ type TerminalStyle = {
|
||||
dim: boolean;
|
||||
inverse: boolean;
|
||||
strikethrough: boolean;
|
||||
};
|
||||
}
|
||||
|
||||
const DEFAULT_STYLE: TerminalStyle = {
|
||||
fg: undefined,
|
||||
|
||||
@@ -6,13 +6,13 @@ import {
|
||||
type TerminalStreamControllerStatus,
|
||||
} from "./terminal-stream-controller";
|
||||
|
||||
type TerminalSnapshot = {
|
||||
interface TerminalSnapshot {
|
||||
rows: number;
|
||||
cols: number;
|
||||
grid: Array<Array<{ char: string }>>;
|
||||
scrollback: Array<Array<{ char: string }>>;
|
||||
cursor: { row: number; col: number };
|
||||
};
|
||||
}
|
||||
|
||||
type TerminalStreamEvent =
|
||||
| { terminalId: string; type: "output"; data: Uint8Array }
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { TerminalState } from "@server/shared/messages";
|
||||
|
||||
export type TerminalStreamControllerClient = {
|
||||
export interface TerminalStreamControllerClient {
|
||||
subscribeTerminal: (terminalId: string) => Promise<{
|
||||
terminalId: string;
|
||||
error?: string | null;
|
||||
@@ -17,26 +17,26 @@ export type TerminalStreamControllerClient = {
|
||||
| { terminalId: string; type: "snapshot"; state: TerminalState },
|
||||
) => void,
|
||||
) => () => void;
|
||||
};
|
||||
}
|
||||
|
||||
export type TerminalStreamControllerSize = {
|
||||
export interface TerminalStreamControllerSize {
|
||||
rows: number;
|
||||
cols: number;
|
||||
};
|
||||
}
|
||||
|
||||
export type TerminalStreamControllerStatus = {
|
||||
export interface TerminalStreamControllerStatus {
|
||||
terminalId: string | null;
|
||||
isAttaching: boolean;
|
||||
error: string | null;
|
||||
};
|
||||
}
|
||||
|
||||
export type TerminalStreamControllerOptions = {
|
||||
export interface TerminalStreamControllerOptions {
|
||||
client: TerminalStreamControllerClient;
|
||||
getPreferredSize: () => TerminalStreamControllerSize | null;
|
||||
onOutput: (input: { terminalId: string; text: string }) => void;
|
||||
onSnapshot: (input: { terminalId: string; state: TerminalState }) => void;
|
||||
onStatusChange?: (status: TerminalStreamControllerStatus) => void;
|
||||
};
|
||||
}
|
||||
|
||||
const TERMINAL_EXITED_ERROR = "Terminal exited";
|
||||
|
||||
|
||||
@@ -1,21 +1,21 @@
|
||||
import type { TerminalState } from "@server/shared/messages";
|
||||
|
||||
export type WorkspaceTerminalSnapshots = {
|
||||
export interface WorkspaceTerminalSnapshots {
|
||||
get: (input: { terminalId: string }) => TerminalState | null;
|
||||
set: (input: { terminalId: string; state: TerminalState }) => void;
|
||||
clear: (input: { terminalId: string }) => void;
|
||||
prune: (input: { terminalIds: string[] }) => void;
|
||||
};
|
||||
}
|
||||
|
||||
export type WorkspaceTerminalSession = {
|
||||
export interface WorkspaceTerminalSession {
|
||||
scopeKey: string;
|
||||
snapshots: WorkspaceTerminalSnapshots;
|
||||
};
|
||||
}
|
||||
|
||||
type WorkspaceTerminalSessionRecord = {
|
||||
interface WorkspaceTerminalSessionRecord {
|
||||
snapshotByTerminalId: Map<string, TerminalState>;
|
||||
session: WorkspaceTerminalSession;
|
||||
};
|
||||
}
|
||||
|
||||
const sessionsByScopeKey = new Map<string, WorkspaceTerminalSessionRecord>();
|
||||
const refCountByScopeKey = new Map<string, number>();
|
||||
|
||||
@@ -123,12 +123,12 @@ export interface MergedToolCall {
|
||||
|
||||
export type GroupedActivity = GroupedTextMessage | MergedToolCall | AgentActivity;
|
||||
|
||||
type TextGroup = {
|
||||
interface TextGroup {
|
||||
messageType: TextMessageType;
|
||||
chunks: string[];
|
||||
startTimestamp: Date;
|
||||
endTimestamp: Date;
|
||||
};
|
||||
}
|
||||
|
||||
type ToolCallAccumulator = Omit<MergedToolCall, "kind"> & {
|
||||
insertIndex: number;
|
||||
|
||||
@@ -1,29 +1,29 @@
|
||||
import { normalizeHostPort, normalizeLoopbackToLocalhost } from "@server/shared/daemon-endpoints";
|
||||
|
||||
export type DirectTcpHostConnection = {
|
||||
export interface DirectTcpHostConnection {
|
||||
id: string;
|
||||
type: "directTcp";
|
||||
endpoint: string;
|
||||
};
|
||||
}
|
||||
|
||||
export type DirectSocketHostConnection = {
|
||||
export interface DirectSocketHostConnection {
|
||||
id: string;
|
||||
type: "directSocket";
|
||||
path: string;
|
||||
};
|
||||
}
|
||||
|
||||
export type DirectPipeHostConnection = {
|
||||
export interface DirectPipeHostConnection {
|
||||
id: string;
|
||||
type: "directPipe";
|
||||
path: string;
|
||||
};
|
||||
}
|
||||
|
||||
export type RelayHostConnection = {
|
||||
export interface RelayHostConnection {
|
||||
id: string;
|
||||
type: "relay";
|
||||
relayEndpoint: string;
|
||||
daemonPublicKeyB64: string;
|
||||
};
|
||||
}
|
||||
|
||||
export type HostConnection =
|
||||
| DirectTcpHostConnection
|
||||
@@ -33,7 +33,7 @@ export type HostConnection =
|
||||
|
||||
export type HostLifecycle = Record<string, never>;
|
||||
|
||||
export type HostProfile = {
|
||||
export interface HostProfile {
|
||||
serverId: string;
|
||||
label: string;
|
||||
lifecycle: HostLifecycle;
|
||||
@@ -41,7 +41,7 @@ export type HostProfile = {
|
||||
preferredConnectionId: string | null;
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
};
|
||||
}
|
||||
|
||||
export function defaultLifecycle(): HostLifecycle {
|
||||
return {};
|
||||
|
||||
@@ -9,7 +9,10 @@ import {
|
||||
import type { AgentStreamEventPayload } from "@server/shared/messages";
|
||||
import type { ToolCallDetail } from "@server/server/agent/agent-sdk-types";
|
||||
|
||||
type HarnessUpdate = { event: AgentStreamEventPayload; timestamp: Date };
|
||||
interface HarnessUpdate {
|
||||
event: AgentStreamEventPayload;
|
||||
timestamp: Date;
|
||||
}
|
||||
type ToolStatus = "running" | "completed" | "failed" | "canceled";
|
||||
|
||||
const HARNESS_CALL_IDS = {
|
||||
|
||||
@@ -142,7 +142,10 @@ export interface CompactionItem {
|
||||
preTokens?: number;
|
||||
}
|
||||
|
||||
export type TodoEntry = { text: string; completed: boolean };
|
||||
export interface TodoEntry {
|
||||
text: string;
|
||||
completed: boolean;
|
||||
}
|
||||
|
||||
export interface TodoListItem {
|
||||
kind: "todo_list";
|
||||
|
||||
@@ -5,11 +5,11 @@ import { resolveProjectPlacement } from "@/utils/project-placement";
|
||||
|
||||
type AgentDirectoryFetchEntry = FetchAgentsEntry | FetchAgentHistoryEntry;
|
||||
|
||||
type PendingPermissionEntry = {
|
||||
interface PendingPermissionEntry {
|
||||
key: string;
|
||||
agentId: string;
|
||||
request: Agent["pendingPermissions"][number];
|
||||
};
|
||||
}
|
||||
|
||||
export function buildAgentDirectoryState(input: {
|
||||
serverId: string;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user