Remove unnecessary type assertions across codebase
Add oxlint-tsgolint and configure typescript/no-unnecessary-type-assertion to flag redundant `!` and `as Foo` casts. Type-aware mode is left off by default to keep `npm run lint` fast; the rule sits configured for when we turn type-aware on intentionally. Auto-fix removed ~283 redundant casts; two manual touch-ups: a real tsgolint false positive in split-container.tsx and a stale ChildProcess import after a double-cast collapsed.
This commit is contained in:
@@ -422,7 +422,7 @@ function AppContainer({
|
||||
const cycleTheme = useCallback(() => {
|
||||
const currentIndex = THEME_CYCLE_ORDER.indexOf(settings.theme as ThemeName);
|
||||
const nextIndex = (currentIndex + 1) % THEME_CYCLE_ORDER.length;
|
||||
void updateSettings({ theme: THEME_CYCLE_ORDER[nextIndex]! });
|
||||
void updateSettings({ theme: THEME_CYCLE_ORDER[nextIndex] });
|
||||
}, [settings.theme, updateSettings]);
|
||||
|
||||
const isCompactLayout = useIsCompactFormFactor();
|
||||
@@ -785,7 +785,7 @@ function AppWithSidebar({ children }: { children: ReactNode }) {
|
||||
if (hosts.some((host) => host.serverId === activeServerId)) {
|
||||
return;
|
||||
}
|
||||
router.replace(mapPathnameToServer(pathname, hosts[0]!.serverId));
|
||||
router.replace(mapPathnameToServer(pathname, hosts[0].serverId));
|
||||
}, [activeServerId, hosts, pathname, router]);
|
||||
|
||||
// Parse selectedAgentKey directly from pathname
|
||||
|
||||
@@ -22,9 +22,9 @@ class FakeRequest<T = unknown> {
|
||||
class FakeObjectStore {
|
||||
constructor(private readonly onPut: (record: unknown) => void) {}
|
||||
|
||||
put(record: unknown): FakeRequest<unknown> {
|
||||
put(record: unknown): FakeRequest {
|
||||
this.onPut(record);
|
||||
const request = new FakeRequest<unknown>();
|
||||
const request = new FakeRequest();
|
||||
queueMicrotask(() => request.emit("success"));
|
||||
return request;
|
||||
}
|
||||
|
||||
@@ -61,7 +61,7 @@ function runTx<T>(
|
||||
const request = run(store);
|
||||
|
||||
request.addEventListener("success", () => {
|
||||
resolve(request.result as T);
|
||||
resolve(request.result);
|
||||
});
|
||||
|
||||
request.addEventListener("error", () => {
|
||||
|
||||
@@ -234,7 +234,7 @@ function buildFallbackAllProviderModels(
|
||||
map.set(
|
||||
provider,
|
||||
modelOptions.map((option) => ({
|
||||
provider: provider as AgentProvider,
|
||||
provider: provider,
|
||||
id: option.id,
|
||||
label: option.label,
|
||||
})),
|
||||
|
||||
@@ -461,7 +461,7 @@ export function BrowserPane({
|
||||
};
|
||||
const handleFaviconUpdated = (event: Event) => {
|
||||
const favicons = Array.isArray((event as Event & { favicons?: unknown[] }).favicons)
|
||||
? (((event as Event & { favicons?: string[] }).favicons as string[] | undefined) ?? [])
|
||||
? ((event as Event & { favicons?: string[] }).favicons ?? [])
|
||||
: [];
|
||||
updateBrowserRef.current(browserIdRef.current, { faviconUrl: favicons[0] ?? null });
|
||||
};
|
||||
|
||||
@@ -63,8 +63,8 @@ describe("combined model selector helpers", () => {
|
||||
}),
|
||||
]);
|
||||
|
||||
expect(matchesSearch(rows[0]!, "claude")).toBe(true);
|
||||
expect(matchesSearch(rows[1]!, "gpt-5.4")).toBe(true);
|
||||
expect(matchesSearch(rows[0], "claude")).toBe(true);
|
||||
expect(matchesSearch(rows[1], "gpt-5.4")).toBe(true);
|
||||
});
|
||||
|
||||
it("keeps the selected trigger label model-only", () => {
|
||||
|
||||
@@ -622,7 +622,7 @@ export function CombinedModelSelector({
|
||||
const singleProviderView = useMemo<SelectorView | null>(() => {
|
||||
const providers = Array.from(allProviderModels.keys());
|
||||
if (providers.length !== 1) return null;
|
||||
const providerId = providers[0]!;
|
||||
const providerId = providers[0];
|
||||
const label = resolveProviderLabel(providerDefinitions, providerId);
|
||||
return { kind: "provider", providerId, providerLabel: label };
|
||||
}, [allProviderModels, providerDefinitions]);
|
||||
@@ -655,7 +655,7 @@ export function CombinedModelSelector({
|
||||
|
||||
const handleSelect = useCallback(
|
||||
(provider: string, modelId: string) => {
|
||||
onSelect(provider as AgentProvider, modelId);
|
||||
onSelect(provider, modelId);
|
||||
setIsOpen(false);
|
||||
setSearchQuery("");
|
||||
},
|
||||
|
||||
@@ -160,20 +160,17 @@ function removeAttachmentAtIndex<T extends ComposerAttachment>(prev: T[], index:
|
||||
}
|
||||
|
||||
function buildCancelButtonStyle(isConnected: boolean, isCancellingAgent: boolean): object[] {
|
||||
const disabled =
|
||||
!isConnected || isCancellingAgent ? (styles.buttonDisabled as object) : undefined;
|
||||
return [styles.cancelButton as object, disabled].filter((value): value is object =>
|
||||
Boolean(value),
|
||||
);
|
||||
const disabled = !isConnected || isCancellingAgent ? styles.buttonDisabled : undefined;
|
||||
return [styles.cancelButton, disabled].filter((value): value is object => Boolean(value));
|
||||
}
|
||||
|
||||
function buildRealtimeVoiceButtonStyle(
|
||||
hovered: boolean | undefined,
|
||||
voiceButtonDisabled: boolean,
|
||||
): object[] {
|
||||
const hoveredStyle = hovered ? (styles.iconButtonHovered as object) : undefined;
|
||||
const disabledStyle = voiceButtonDisabled ? (styles.buttonDisabled as object) : undefined;
|
||||
return [styles.realtimeVoiceButton as object, hoveredStyle, disabledStyle].filter(
|
||||
const hoveredStyle = hovered ? styles.iconButtonHovered : undefined;
|
||||
const disabledStyle = voiceButtonDisabled ? styles.buttonDisabled : undefined;
|
||||
return [styles.realtimeVoiceButton, hoveredStyle, disabledStyle].filter(
|
||||
(value): value is object => Boolean(value),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -132,7 +132,7 @@ function TreeRowItem({
|
||||
);
|
||||
|
||||
const handleCopy = useCallback(() => {
|
||||
void onCopyPath(entry.path);
|
||||
onCopyPath(entry.path);
|
||||
}, [onCopyPath, entry.path]);
|
||||
|
||||
const handleDownload = useCallback(() => {
|
||||
|
||||
@@ -29,7 +29,7 @@ interface PathRowProps {
|
||||
function PathRow({ path, active, onSelect }: PathRowProps) {
|
||||
const { theme } = useUnistyles();
|
||||
const handlePress = useCallback(() => {
|
||||
void onSelect(path);
|
||||
onSelect(path);
|
||||
}, [onSelect, path]);
|
||||
const pressableStyle = useCallback(
|
||||
({ hovered = false, pressed }: PressableStateCallbackType & { hovered?: boolean }) => [
|
||||
@@ -172,7 +172,7 @@ export function ProjectPickerModal() {
|
||||
if (key === "Enter") {
|
||||
event.preventDefault();
|
||||
if (options.length > 0 && activeIndex < options.length) {
|
||||
void handleSelectPath(options[activeIndex]!);
|
||||
void handleSelectPath(options[activeIndex]);
|
||||
} else if (query.trim()) {
|
||||
handleSubmitCustom();
|
||||
}
|
||||
|
||||
@@ -117,7 +117,7 @@ function CustomModelsSection(props: {
|
||||
},
|
||||
},
|
||||
});
|
||||
await refresh([provider as AgentProvider]);
|
||||
await refresh([provider]);
|
||||
},
|
||||
[patchConfig, provider, refresh],
|
||||
);
|
||||
@@ -284,7 +284,7 @@ export function ProviderDiagnosticSheet({
|
||||
}
|
||||
|
||||
try {
|
||||
const result = await client.getProviderDiagnostic(provider as AgentProvider);
|
||||
const result = await client.getProviderDiagnostic(provider);
|
||||
setDiagnostic(result.diagnostic);
|
||||
} catch (err) {
|
||||
setDiagnostic(err instanceof Error ? err.message : "Failed to fetch diagnostic");
|
||||
@@ -308,7 +308,7 @@ export function ProviderDiagnosticSheet({
|
||||
if (!provider) {
|
||||
return;
|
||||
}
|
||||
void Promise.all([refresh([provider as AgentProvider]), fetchDiagnostic()]).catch((err) => {
|
||||
void Promise.all([refresh([provider]), fetchDiagnostic()]).catch((err) => {
|
||||
setDiagnostic(err instanceof Error ? err.message : "Failed to refresh provider");
|
||||
});
|
||||
}, [fetchDiagnostic, provider, refresh]);
|
||||
|
||||
@@ -351,7 +351,7 @@ describe("sidebar workspace render isolation", () => {
|
||||
act(() => {
|
||||
useSessionStore.getState().mergeWorkspaces(SERVER_ID, [
|
||||
{
|
||||
...createWorkspaces()[1]!,
|
||||
...createWorkspaces()[1],
|
||||
status: "running",
|
||||
},
|
||||
]);
|
||||
|
||||
@@ -439,7 +439,7 @@ function WorkspaceStatusIndicator({
|
||||
);
|
||||
}
|
||||
|
||||
let KindIcon: typeof ThemedMonitor | typeof ThemedFolderGit2 | null;
|
||||
let KindIcon: typeof ThemedMonitor | null;
|
||||
if (workspaceKind === "local_checkout") KindIcon = ThemedMonitor;
|
||||
else if (workspaceKind === "worktree") KindIcon = ThemedFolderGit2;
|
||||
else KindIcon = null;
|
||||
|
||||
@@ -488,7 +488,7 @@ function handleDesktopEnterKey(input: DesktopKeyHandlerInput) {
|
||||
if (input.orderedVisibleOptions.length === 0) return;
|
||||
const { activeIndex, orderedVisibleOptions } = input;
|
||||
const index = activeIndex >= 0 && activeIndex < orderedVisibleOptions.length ? activeIndex : 0;
|
||||
input.handleSelect(orderedVisibleOptions[index]!.id);
|
||||
input.handleSelect(orderedVisibleOptions[index].id);
|
||||
}
|
||||
|
||||
interface FloatingSizeSetters {
|
||||
|
||||
@@ -140,9 +140,9 @@ export function useWebScrollViewScrollbar(
|
||||
const scrollable = scrollableRef.current;
|
||||
if (!scrollable) return;
|
||||
if ("scrollToOffset" in scrollable) {
|
||||
(scrollable as FlatList).scrollToOffset({ offset, animated: false });
|
||||
scrollable.scrollToOffset({ offset, animated: false });
|
||||
} else {
|
||||
(scrollable as ScrollView).scrollTo({ y: offset, animated: false });
|
||||
scrollable.scrollTo({ y: offset, animated: false });
|
||||
}
|
||||
},
|
||||
[scrollableRef],
|
||||
|
||||
@@ -14,11 +14,7 @@ import {
|
||||
type TimelineReducerSideEffect,
|
||||
} from "@/timeline/session-stream-reducers";
|
||||
import { TIMELINE_FETCH_PAGE_SIZE } from "@/timeline/timeline-fetch-policy";
|
||||
import type {
|
||||
AgentAttachment,
|
||||
AgentStreamEventPayload,
|
||||
SessionOutboundMessage,
|
||||
} from "@server/shared/messages";
|
||||
import type { AgentAttachment, SessionOutboundMessage } from "@server/shared/messages";
|
||||
import { parseServerInfoStatusPayload } from "@server/shared/messages";
|
||||
import {
|
||||
buildAgentAttentionNotificationPayload,
|
||||
@@ -1201,7 +1197,7 @@ function SessionProviderInternal({ children, serverId, client }: SessionProvider
|
||||
if (message.type !== "agent_stream") return;
|
||||
const { agentId, event, timestamp, seq, epoch } = message.payload;
|
||||
const parsedTimestamp = new Date(timestamp);
|
||||
const streamEvent = event as AgentStreamEventPayload;
|
||||
const streamEvent = event;
|
||||
if (
|
||||
event.type === "turn_started" ||
|
||||
event.type === "turn_completed" ||
|
||||
|
||||
@@ -140,7 +140,7 @@ export function VoiceProvider({ children }: VoiceProviderProps) {
|
||||
runtimeRef.current = runtime;
|
||||
}
|
||||
|
||||
const engine = engineRef.current!;
|
||||
const engine = engineRef.current;
|
||||
const runtime = runtimeRef.current!;
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
@@ -13,7 +13,7 @@ function encodeBinaryToBase64(data: Uint8Array | ArrayBuffer): string {
|
||||
const bytes = data instanceof ArrayBuffer ? new Uint8Array(data) : data;
|
||||
let binary = "";
|
||||
for (let index = 0; index < bytes.length; index += 1) {
|
||||
binary += String.fromCharCode(bytes[index]!);
|
||||
binary += String.fromCharCode(bytes[index]);
|
||||
}
|
||||
return globalThis.btoa(binary);
|
||||
}
|
||||
|
||||
@@ -110,7 +110,7 @@ export class DictationStreamSender {
|
||||
let sent = 0;
|
||||
while (this.sendSeq < this.segments.length) {
|
||||
const seq = this.sendSeq;
|
||||
const audio = this.segments[seq]!;
|
||||
const audio = this.segments[seq];
|
||||
client.sendDictationStreamChunk(dictationId, seq, audio, this.format);
|
||||
this.sendSeq = seq + 1;
|
||||
sent += 1;
|
||||
|
||||
@@ -35,7 +35,7 @@ const TEST_CLAUDE_DEFINITION: AgentProviderDefinition = {
|
||||
function makeProviderMap(
|
||||
...definitions: AgentProviderDefinition[]
|
||||
): Map<AgentProvider, AgentProviderDefinition> {
|
||||
return new Map(definitions.map((d) => [d.id as AgentProvider, d]));
|
||||
return new Map(definitions.map((d) => [d.id, d]));
|
||||
}
|
||||
|
||||
const codexProviderMap = makeProviderMap(TEST_CODEX_DEFINITION);
|
||||
|
||||
@@ -196,8 +196,8 @@ function resolveProvider(input: {
|
||||
if (initialValues?.provider && allowedProviderMap.has(initialValues.provider)) {
|
||||
return initialValues.provider;
|
||||
}
|
||||
if (preferences?.provider && allowedProviderMap.has(preferences.provider as AgentProvider)) {
|
||||
return preferences.provider as AgentProvider;
|
||||
if (preferences?.provider && allowedProviderMap.has(preferences.provider)) {
|
||||
return preferences.provider;
|
||||
}
|
||||
if (currentProvider && allowedProviderMap.size > 0 && !allowedProviderMap.has(currentProvider)) {
|
||||
return null;
|
||||
@@ -396,7 +396,7 @@ function buildProviderDefinitionMapForStatuses(args: {
|
||||
|
||||
const matchingProviders = new Set(
|
||||
args.snapshotEntries
|
||||
.filter((entry) => args.statuses.has(entry.status) && entry.enabled !== false)
|
||||
.filter((entry) => args.statuses.has(entry.status) && entry.enabled)
|
||||
.map((entry) => entry.provider),
|
||||
);
|
||||
|
||||
|
||||
@@ -341,7 +341,7 @@ export function useAudioRecorder(config?: AudioCaptureConfig) {
|
||||
return () => {
|
||||
attemptGuard.cancel();
|
||||
try {
|
||||
void mediaRecorder.current?.stop();
|
||||
mediaRecorder.current?.stop();
|
||||
} catch {
|
||||
// Ignore stop during unmount.
|
||||
}
|
||||
|
||||
@@ -332,7 +332,7 @@ export function useCommandCenter() {
|
||||
if (currentItems.length === 0) return;
|
||||
event.preventDefault();
|
||||
const index = Math.max(0, Math.min(activeIndexRef.current, currentItems.length - 1));
|
||||
handleSelectItemRef.current(currentItems[index]!);
|
||||
handleSelectItemRef.current(currentItems[index]);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -68,7 +68,7 @@ const concatInt16 = (a: Int16Array, b: Int16Array): Int16Array => {
|
||||
const int16ToFloat32 = (input: Int16Array): Float32Array => {
|
||||
const out = new Float32Array(input.length);
|
||||
for (let i = 0; i < input.length; i += 1) {
|
||||
out[i] = input[i]! / 32768;
|
||||
out[i] = input[i] / 32768;
|
||||
}
|
||||
return out;
|
||||
};
|
||||
@@ -209,8 +209,8 @@ export function useDictationAudioSource(config: DictationAudioSourceConfig): Dic
|
||||
const decodeAudioData = useCallback(
|
||||
async (context: AudioContext, buffer: ArrayBuffer): Promise<AudioBuffer> => {
|
||||
const maybePromise = context.decodeAudioData(buffer);
|
||||
if (maybePromise && typeof (maybePromise as Promise<AudioBuffer>).then === "function") {
|
||||
return maybePromise as Promise<AudioBuffer>;
|
||||
if (maybePromise && typeof maybePromise.then === "function") {
|
||||
return maybePromise;
|
||||
}
|
||||
return await new Promise<AudioBuffer>((resolve, reject) => {
|
||||
context.decodeAudioData(buffer, resolve, reject);
|
||||
@@ -276,7 +276,7 @@ export function useDictationAudioSource(config: DictationAudioSourceConfig): Dic
|
||||
},
|
||||
});
|
||||
|
||||
const stream = rawStream as MediaStream;
|
||||
const stream = rawStream;
|
||||
|
||||
const context = new AudioContextCtor();
|
||||
|
||||
@@ -347,7 +347,7 @@ export function useDictationAudioSource(config: DictationAudioSourceConfig): Dic
|
||||
|
||||
const recorder = new RecorderCtor(stream, {
|
||||
mimeType: "audio/webm;codecs=opus",
|
||||
} as MediaRecorderOptions) as MediaRecorder;
|
||||
} as MediaRecorderOptions);
|
||||
|
||||
const recorderRefs: RecorderRefs = {
|
||||
recorder,
|
||||
|
||||
@@ -260,7 +260,7 @@ export function useKeyboardShortcuts({
|
||||
const handleCommandCenterToggle = (event: KeyboardEvent): boolean => {
|
||||
const store = useKeyboardShortcutsStore.getState();
|
||||
if (!store.commandCenterOpen) {
|
||||
const target = event.target instanceof Element ? (event.target as Element) : null;
|
||||
const target = event.target instanceof Element ? event.target : null;
|
||||
const targetEl =
|
||||
target?.closest?.("textarea, input, [contenteditable='true']") ??
|
||||
(target instanceof HTMLElement ? target : null);
|
||||
|
||||
@@ -86,7 +86,7 @@ export function usePrPaneData({
|
||||
const checkoutPrStatus = useCheckoutPrStatusQuery({ serverId, cwd, enabled });
|
||||
const status = checkoutPrStatus.status;
|
||||
const { prNumber, repoOwner, repoName } = extractPrRepoIdentity(status);
|
||||
const githubFeaturesEnabled = checkoutPrStatus.githubFeaturesEnabled !== false;
|
||||
const githubFeaturesEnabled = checkoutPrStatus.githubFeaturesEnabled;
|
||||
const unsupportedKey =
|
||||
prNumber === null ? null : timelineUnsupportedKey({ serverId, cwd, prNumber });
|
||||
const timelineUnsupported = unsupportedKey ? unsupportedTimelineKeys.has(unsupportedKey) : false;
|
||||
@@ -100,7 +100,7 @@ export function usePrPaneData({
|
||||
timelineUnsupported,
|
||||
});
|
||||
|
||||
const timelineQuery = useQuery<PullRequestTimeline, Error>({
|
||||
const timelineQuery = useQuery<PullRequestTimeline>({
|
||||
queryKey: prPaneTimelineQueryKey({ serverId, cwd, prNumber }),
|
||||
queryFn: async () => {
|
||||
if (!daemonClient || prNumber === null || repoOwner === null || repoName === null) {
|
||||
|
||||
@@ -235,16 +235,16 @@ export async function loadSettingsFromStorage(): Promise<Settings> {
|
||||
function pickAppSettings(stored: Partial<AppSettings>): Partial<AppSettings> {
|
||||
const result: Partial<AppSettings> = {};
|
||||
if (typeof stored.theme === "string" && VALID_THEMES.has(stored.theme)) {
|
||||
result.theme = stored.theme as AppSettings["theme"];
|
||||
result.theme = stored.theme;
|
||||
}
|
||||
if (stored.sendBehavior === "interrupt" || stored.sendBehavior === "queue") {
|
||||
result.sendBehavior = stored.sendBehavior;
|
||||
}
|
||||
if (
|
||||
typeof stored.serviceUrlBehavior === "string" &&
|
||||
VALID_SERVICE_URL_BEHAVIORS.has(stored.serviceUrlBehavior as ServiceUrlBehavior)
|
||||
VALID_SERVICE_URL_BEHAVIORS.has(stored.serviceUrlBehavior)
|
||||
) {
|
||||
result.serviceUrlBehavior = stored.serviceUrlBehavior as ServiceUrlBehavior;
|
||||
result.serviceUrlBehavior = stored.serviceUrlBehavior;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -750,7 +750,7 @@ function ChatAgentContent({
|
||||
};
|
||||
}, []);
|
||||
|
||||
const isInitializing = agentId ? isInitializingFromMap !== false : false;
|
||||
const isInitializing = agentId ? isInitializingFromMap : false;
|
||||
const isHistorySyncing = useMemo(() => {
|
||||
if (!agentId || !isInitializing) {
|
||||
return false;
|
||||
|
||||
@@ -197,7 +197,7 @@ describe("useInlineReviewController", () => {
|
||||
body: "first comment",
|
||||
});
|
||||
|
||||
act(() => result.current.onEditComment(reviewTarget, savedComment!));
|
||||
act(() => result.current.onEditComment(reviewTarget, savedComment));
|
||||
expect(result.current.editor).toEqual({
|
||||
target: reviewTarget,
|
||||
commentId: savedComment?.id,
|
||||
@@ -208,8 +208,8 @@ describe("useInlineReviewController", () => {
|
||||
const updatedComment = useReviewDraftStore.getState().drafts[firstKey]?.[0];
|
||||
expect(updatedComment).toMatchObject({ id: savedComment?.id, body: "updated comment" });
|
||||
|
||||
act(() => result.current.onEditComment(reviewTarget, updatedComment!));
|
||||
act(() => result.current.onDeleteComment(updatedComment!.id));
|
||||
act(() => result.current.onEditComment(reviewTarget, updatedComment));
|
||||
act(() => result.current.onDeleteComment(updatedComment.id));
|
||||
expect(useReviewDraftStore.getState().drafts[firstKey]).toEqual([]);
|
||||
expect(result.current.editor).toBeNull();
|
||||
|
||||
|
||||
@@ -752,7 +752,7 @@ describe("ProjectSettingsScreen — save flow", () => {
|
||||
await flush();
|
||||
|
||||
expect(client.writeProjectConfig).toHaveBeenCalledTimes(1);
|
||||
const callArg = client.writeProjectConfig.mock.calls[0]![0] as {
|
||||
const callArg = client.writeProjectConfig.mock.calls[0][0] as {
|
||||
repoRoot: string;
|
||||
config: PaseoConfigRaw;
|
||||
expectedRevision: PaseoConfigRevision | null;
|
||||
@@ -767,7 +767,7 @@ describe("ProjectSettingsScreen — save flow", () => {
|
||||
// Subsequent saves use the freshly-returned revision.
|
||||
click(requireById("save-button"));
|
||||
await flush();
|
||||
const secondArg = client.writeProjectConfig.mock.calls[1]![0] as {
|
||||
const secondArg = client.writeProjectConfig.mock.calls[1][0] as {
|
||||
expectedRevision: PaseoConfigRevision;
|
||||
};
|
||||
expect(secondArg.expectedRevision).toEqual(newRevision);
|
||||
@@ -869,7 +869,7 @@ describe("ProjectSettingsScreen — round-trip semantics", () => {
|
||||
click(requireById("save-button"));
|
||||
await flush();
|
||||
|
||||
const savedConfig = client.writeProjectConfig.mock.calls[0]![0]!.config as PaseoConfigRaw;
|
||||
const savedConfig = client.writeProjectConfig.mock.calls[0][0]!.config as PaseoConfigRaw;
|
||||
// string stays string when edited in place
|
||||
expect(savedConfig.worktree?.setup).toBe("npm install\nnpm run prepare");
|
||||
});
|
||||
@@ -897,7 +897,7 @@ describe("ProjectSettingsScreen — round-trip semantics", () => {
|
||||
click(requireById("save-button"));
|
||||
await flush();
|
||||
|
||||
const savedConfig = client.writeProjectConfig.mock.calls[0]![0]!.config as PaseoConfigRaw;
|
||||
const savedConfig = client.writeProjectConfig.mock.calls[0][0]!.config as PaseoConfigRaw;
|
||||
expect(savedConfig.worktree?.teardown).toEqual(["docker compose down", "rm -rf .cache"]);
|
||||
});
|
||||
|
||||
@@ -920,7 +920,7 @@ describe("ProjectSettingsScreen — round-trip semantics", () => {
|
||||
click(requireById("save-button"));
|
||||
await flush();
|
||||
|
||||
const savedConfig = client.writeProjectConfig.mock.calls[0]![0]!.config as PaseoConfigRaw;
|
||||
const savedConfig = client.writeProjectConfig.mock.calls[0][0]!.config as PaseoConfigRaw;
|
||||
expect(savedConfig.worktree?.setup).toBe("npm install");
|
||||
});
|
||||
|
||||
@@ -943,7 +943,7 @@ describe("ProjectSettingsScreen — round-trip semantics", () => {
|
||||
click(requireById("save-button"));
|
||||
await flush();
|
||||
|
||||
const savedConfig = client.writeProjectConfig.mock.calls[0]![0]!.config as PaseoConfigRaw;
|
||||
const savedConfig = client.writeProjectConfig.mock.calls[0][0]!.config as PaseoConfigRaw;
|
||||
expect(savedConfig.worktree?.setup).toEqual(["npm install", "npm run prepare"]);
|
||||
});
|
||||
});
|
||||
@@ -996,7 +996,7 @@ describe("ProjectSettingsScreen — scripts editor", () => {
|
||||
click(requireById("save-button"));
|
||||
await flush();
|
||||
|
||||
const savedConfig = client.writeProjectConfig.mock.calls[0]![0]!.config as PaseoConfigRaw;
|
||||
const savedConfig = client.writeProjectConfig.mock.calls[0][0]!.config as PaseoConfigRaw;
|
||||
const scriptKeys = Object.keys((savedConfig as Record<string, unknown>).scripts ?? {});
|
||||
// One of the two scripts was removed.
|
||||
expect(scriptKeys.length).toBe(1);
|
||||
@@ -1031,7 +1031,7 @@ describe("ProjectSettingsScreen — scripts editor", () => {
|
||||
click(requireById("save-button"));
|
||||
await flush();
|
||||
|
||||
const savedConfig = client.writeProjectConfig.mock.calls[0]![0]!.config as PaseoConfigRaw;
|
||||
const savedConfig = client.writeProjectConfig.mock.calls[0][0]!.config as PaseoConfigRaw;
|
||||
expect((savedConfig as Record<string, unknown>).customTopLevel).toBe("preserved");
|
||||
const worktreeRecord = (savedConfig.worktree ?? {}) as Record<string, unknown>;
|
||||
expect(worktreeRecord.customWorktreeField).toBe("keep");
|
||||
|
||||
@@ -1541,7 +1541,7 @@ function WorkspaceScreenContent({
|
||||
if (!client || !workspaceDirectory) {
|
||||
throw new Error("Host is not connected");
|
||||
}
|
||||
return (await client.getCheckoutStatus(workspaceDirectory)) as CheckoutStatusPayload;
|
||||
return await client.getCheckoutStatus(workspaceDirectory);
|
||||
},
|
||||
staleTime: Infinity,
|
||||
refetchOnMount: false,
|
||||
|
||||
@@ -68,7 +68,7 @@ describe("computeWorkspaceTabLayout", () => {
|
||||
expect(result.closeButtonPolicy).toBe("all");
|
||||
expect(result.requiresHorizontalScrollFallback).toBe(false);
|
||||
expect(result.items.map((item) => item.width)).toEqual([60, 60, 60, 60]);
|
||||
expect(result.items.every((item) => item.showLabel === false)).toBe(true);
|
||||
expect(result.items.every((item) => !item.showLabel)).toBe(true);
|
||||
});
|
||||
|
||||
it("allows horizontal scroll only when icon-only tabs still cannot fit", () => {
|
||||
@@ -81,7 +81,7 @@ describe("computeWorkspaceTabLayout", () => {
|
||||
expect(result.closeButtonPolicy).toBe("all");
|
||||
expect(result.requiresHorizontalScrollFallback).toBe(true);
|
||||
expect(result.items.map((item) => item.width)).toEqual([60, 60, 60, 60]);
|
||||
expect(result.items.every((item) => item.showLabel === false)).toBe(true);
|
||||
expect(result.items.every((item) => !item.showLabel)).toBe(true);
|
||||
});
|
||||
|
||||
it("returns empty layout details when there are no tabs", () => {
|
||||
|
||||
@@ -23,7 +23,7 @@ describe("deriveWorkspaceTabModel", () => {
|
||||
];
|
||||
|
||||
const model = deriveWorkspaceTabModel({
|
||||
tabs: [uiTabs[0]!, uiTabs[2]!, uiTabs[1]!],
|
||||
tabs: [uiTabs[0], uiTabs[2], uiTabs[1]],
|
||||
});
|
||||
|
||||
expect(model.tabs.map((tab) => tab.descriptor.tabId)).toEqual([
|
||||
|
||||
@@ -526,7 +526,7 @@ function findNearestSiblingPaneId(root: SplitNodeInternal, paneId: string): stri
|
||||
|
||||
for (let depth = path.length - 1; depth >= 0; depth -= 1) {
|
||||
const parentPath = path.slice(0, depth);
|
||||
const childIndex = path[depth]!;
|
||||
const childIndex = path[depth];
|
||||
const parentNode = getNodeAtPath(root, parentPath);
|
||||
invariant(parentNode.kind === "group", "Expected parent group for pane lookup");
|
||||
|
||||
@@ -667,7 +667,7 @@ function removePaneByPath(root: SplitNodeInternal, path: number[]): SplitNodeInt
|
||||
}
|
||||
|
||||
const parentPath = path.slice(0, -1);
|
||||
const removeIndex = path[path.length - 1]!;
|
||||
const removeIndex = path[path.length - 1];
|
||||
const parentNode = getNodeAtPath(root, parentPath);
|
||||
invariant(parentNode.kind === "group", "Expected parent group while removing pane");
|
||||
|
||||
@@ -676,7 +676,7 @@ function removePaneByPath(root: SplitNodeInternal, path: number[]): SplitNodeInt
|
||||
|
||||
const nextParentNode =
|
||||
nextParentChildren.length === 1
|
||||
? nextParentChildren[0]!
|
||||
? nextParentChildren[0]
|
||||
: createGroupNode({
|
||||
id: parentNode.group.id,
|
||||
direction: parentNode.group.direction,
|
||||
|
||||
@@ -142,7 +142,7 @@ describe("workspace-layout-store tree transforms", () => {
|
||||
|
||||
const nextRoot = insertSplit(root, "right", "tab-c", "right");
|
||||
const nextGroup = expectGroup(nextRoot);
|
||||
const nestedGroup = expectGroup(nextGroup.group.children[1]!);
|
||||
const nestedGroup = expectGroup(nextGroup.group.children[1]);
|
||||
|
||||
expect(nextGroup.group.direction).toBe("horizontal");
|
||||
expect(nextGroup.group.children).toHaveLength(2);
|
||||
@@ -259,7 +259,7 @@ describe("workspace-layout-store actions", () => {
|
||||
kind: "file",
|
||||
path: "/repo/worktree/b.ts",
|
||||
});
|
||||
const layout = useWorkspaceLayoutStore.getState().layoutByWorkspace[workspaceKey]!;
|
||||
const layout = useWorkspaceLayoutStore.getState().layoutByWorkspace[workspaceKey];
|
||||
|
||||
expect(firstTabId).toBe("file_/repo/worktree/a.ts");
|
||||
expect(secondTabId).toBe("file_/repo/worktree/b.ts");
|
||||
@@ -280,7 +280,7 @@ describe("workspace-layout-store actions", () => {
|
||||
kind: "setup",
|
||||
workspaceId: "ws-main",
|
||||
});
|
||||
const layout = useWorkspaceLayoutStore.getState().layoutByWorkspace[workspaceKey]!;
|
||||
const layout = useWorkspaceLayoutStore.getState().layoutByWorkspace[workspaceKey];
|
||||
const pane = findPaneById(layout.root, "main")!;
|
||||
|
||||
expect(agentTabId).toBe("agent_agent-1");
|
||||
@@ -306,7 +306,7 @@ describe("workspace-layout-store actions", () => {
|
||||
kind: "file",
|
||||
path: "/repo/worktree/a.ts",
|
||||
});
|
||||
const layoutAfter = useWorkspaceLayoutStore.getState().layoutByWorkspace[workspaceKey]!;
|
||||
const layoutAfter = useWorkspaceLayoutStore.getState().layoutByWorkspace[workspaceKey];
|
||||
const pane = findPaneById(layoutAfter.root, "main")!;
|
||||
|
||||
expect(duplicateTabId).toBe(firstTabId);
|
||||
@@ -380,7 +380,7 @@ describe("workspace-layout-store actions", () => {
|
||||
|
||||
const firstTabId = store.openTabFocused(workspaceKey, { kind: "draft", draftId: "draft-1" });
|
||||
const secondTabId = store.openTabFocused(workspaceKey, { kind: "draft", draftId: "draft-2" });
|
||||
const layout = useWorkspaceLayoutStore.getState().layoutByWorkspace[workspaceKey]!;
|
||||
const layout = useWorkspaceLayoutStore.getState().layoutByWorkspace[workspaceKey];
|
||||
|
||||
expect(firstTabId).toBe("draft-1");
|
||||
expect(secondTabId).toBe("draft-2");
|
||||
@@ -416,14 +416,14 @@ describe("workspace-layout-store actions", () => {
|
||||
kind: "draft",
|
||||
draftId: "draft-split",
|
||||
});
|
||||
const layout = useWorkspaceLayoutStore.getState().layoutByWorkspace[workspaceKey]!;
|
||||
const layout = useWorkspaceLayoutStore.getState().layoutByWorkspace[workspaceKey];
|
||||
|
||||
expect(newPaneId).toBe("pane_77777777-7777-7777-7777-777777777777");
|
||||
expect(draftTabId).toBe("draft-split");
|
||||
expect(layout.focusedPaneId).toBe(newPaneId);
|
||||
expect(findPaneById(layout.root, "main")?.tabIds).toEqual(["file_/repo/worktree/a.ts"]);
|
||||
expect(findPaneById(layout.root, newPaneId!)?.tabIds).toEqual([draftTabId!]);
|
||||
expect(findPaneById(layout.root, newPaneId!)?.focusedTabId).toBe(draftTabId);
|
||||
expect(findPaneById(layout.root, newPaneId)?.tabIds).toEqual([draftTabId!]);
|
||||
expect(findPaneById(layout.root, newPaneId)?.focusedTabId).toBe(draftTabId);
|
||||
});
|
||||
|
||||
it("focusTab moves workspace focus to the pane containing the tab", () => {
|
||||
@@ -448,14 +448,14 @@ describe("workspace-layout-store actions", () => {
|
||||
});
|
||||
|
||||
store.focusTab(workspaceKey, fileTabId!);
|
||||
let layout = useWorkspaceLayoutStore.getState().layoutByWorkspace[workspaceKey]!;
|
||||
let layout = useWorkspaceLayoutStore.getState().layoutByWorkspace[workspaceKey];
|
||||
expect(layout.focusedPaneId).toBe("main");
|
||||
|
||||
store.focusTab(workspaceKey, terminalTabId!);
|
||||
layout = useWorkspaceLayoutStore.getState().layoutByWorkspace[workspaceKey]!;
|
||||
expect(splitPaneId).toBe("pane_bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb");
|
||||
expect(layout.focusedPaneId).toBe(splitPaneId);
|
||||
expect(findPaneById(layout.root, splitPaneId!)?.focusedTabId).toBe(terminalTabId);
|
||||
expect(findPaneById(layout.root, splitPaneId)?.focusedTabId).toBe(terminalTabId);
|
||||
});
|
||||
|
||||
it("convertDraftToAgent replaces the draft tab with a canonical agent tab in the same pane", () => {
|
||||
@@ -474,8 +474,8 @@ describe("workspace-layout-store actions", () => {
|
||||
});
|
||||
|
||||
const nextTabId = store.convertDraftToAgent(workspaceKey, secondTabId!, "agent-1");
|
||||
const layout = useWorkspaceLayoutStore.getState().layoutByWorkspace[workspaceKey]!;
|
||||
const splitPane = findPaneById(layout.root, splitPaneId!);
|
||||
const layout = useWorkspaceLayoutStore.getState().layoutByWorkspace[workspaceKey];
|
||||
const splitPane = findPaneById(layout.root, splitPaneId);
|
||||
const convertedTab = collectAllTabs(layout.root).find((tab) => tab.tabId === nextTabId);
|
||||
|
||||
expect(splitPaneId).toBe("pane_12121212-1212-1212-1212-121212121212");
|
||||
@@ -501,7 +501,7 @@ describe("workspace-layout-store actions", () => {
|
||||
kind: "file",
|
||||
path: "/repo/worktree/retargeted.ts",
|
||||
});
|
||||
const layout = useWorkspaceLayoutStore.getState().layoutByWorkspace[workspaceKey]!;
|
||||
const layout = useWorkspaceLayoutStore.getState().layoutByWorkspace[workspaceKey];
|
||||
|
||||
expect(draftTabId).toBe("draft-retarget");
|
||||
expect(nextTabId).toBe(draftTabId);
|
||||
@@ -541,7 +541,7 @@ describe("workspace-layout-store actions", () => {
|
||||
kind: "file",
|
||||
path: "/repo/worktree/existing.ts",
|
||||
});
|
||||
const layout = useWorkspaceLayoutStore.getState().layoutByWorkspace[workspaceKey]!;
|
||||
const layout = useWorkspaceLayoutStore.getState().layoutByWorkspace[workspaceKey];
|
||||
|
||||
expect(existingFileTabId).toBe("file_/repo/worktree/existing.ts");
|
||||
expect(draftTabId).toBe("draft-dup");
|
||||
@@ -576,7 +576,7 @@ describe("workspace-layout-store actions", () => {
|
||||
kind: "agent",
|
||||
agentId: "agent-1",
|
||||
});
|
||||
const layout = useWorkspaceLayoutStore.getState().layoutByWorkspace[workspaceKey]!;
|
||||
const layout = useWorkspaceLayoutStore.getState().layoutByWorkspace[workspaceKey];
|
||||
|
||||
expect(firstAgentTabId).toBe(firstDraftTabId);
|
||||
expect(nextTabId).toBe(firstDraftTabId);
|
||||
@@ -608,7 +608,7 @@ describe("workspace-layout-store actions", () => {
|
||||
});
|
||||
|
||||
store.reorderTabs(workspaceKey, [thirdTabId!, firstTabId!]);
|
||||
const layout = useWorkspaceLayoutStore.getState().layoutByWorkspace[workspaceKey]!;
|
||||
const layout = useWorkspaceLayoutStore.getState().layoutByWorkspace[workspaceKey];
|
||||
|
||||
expect(findPaneById(layout.root, "main")).toEqual({
|
||||
id: "main",
|
||||
@@ -663,11 +663,11 @@ describe("workspace-layout-store actions", () => {
|
||||
store.moveTabToPane(workspaceKey, fourthTabId!, splitPaneId!);
|
||||
store.focusPane(workspaceKey, "main");
|
||||
store.reorderTabsInPane(workspaceKey, splitPaneId!, [fourthTabId!, thirdTabId!]);
|
||||
const layout = useWorkspaceLayoutStore.getState().layoutByWorkspace[workspaceKey]!;
|
||||
const layout = useWorkspaceLayoutStore.getState().layoutByWorkspace[workspaceKey];
|
||||
|
||||
expect(splitPaneId).toBe("pane_34343434-3434-3434-3434-343434343434");
|
||||
expect(layout.focusedPaneId).toBe("main");
|
||||
expect(findPaneById(layout.root, splitPaneId!)).toEqual({
|
||||
expect(findPaneById(layout.root, splitPaneId)).toEqual({
|
||||
id: splitPaneId,
|
||||
tabIds: [fourthTabId!, thirdTabId!],
|
||||
focusedTabId: fourthTabId,
|
||||
@@ -705,7 +705,7 @@ describe("workspace-layout-store actions", () => {
|
||||
});
|
||||
|
||||
store.focusPane(workspaceKey, "main");
|
||||
let layout = useWorkspaceLayoutStore.getState().layoutByWorkspace[workspaceKey]!;
|
||||
let layout = useWorkspaceLayoutStore.getState().layoutByWorkspace[workspaceKey];
|
||||
expect(layout.focusedPaneId).toBe("main");
|
||||
|
||||
store.focusPane(workspaceKey, splitPaneId!);
|
||||
@@ -734,7 +734,7 @@ describe("workspace-layout-store actions", () => {
|
||||
});
|
||||
|
||||
store.closeTab(workspaceKey, secondTabId!);
|
||||
const layout = useWorkspaceLayoutStore.getState().layoutByWorkspace[workspaceKey]!;
|
||||
const layout = useWorkspaceLayoutStore.getState().layoutByWorkspace[workspaceKey];
|
||||
|
||||
expect(splitPaneId).toBe("pane_cccccccc-cccc-cccc-cccc-cccccccccccc");
|
||||
expect(layout.focusedPaneId).toBe("main");
|
||||
@@ -782,7 +782,7 @@ describe("workspace-layout-store actions", () => {
|
||||
position: "bottom",
|
||||
});
|
||||
|
||||
const layout = useWorkspaceLayoutStore.getState().layoutByWorkspace[workspaceKey]!;
|
||||
const layout = useWorkspaceLayoutStore.getState().layoutByWorkspace[workspaceKey];
|
||||
expect(pane1).toBe("pane_11111111-1111-1111-1111-111111111111");
|
||||
expect(pane2).toBe("pane_33333333-3333-3333-3333-333333333333");
|
||||
expect(pane3).toBe("pane_55555555-5555-5555-5555-555555555555");
|
||||
@@ -812,11 +812,11 @@ describe("workspace-layout-store actions", () => {
|
||||
});
|
||||
|
||||
store.moveTabToPane(workspaceKey, leftTabId!, splitPaneId!);
|
||||
const layout = useWorkspaceLayoutStore.getState().layoutByWorkspace[workspaceKey]!;
|
||||
const layout = useWorkspaceLayoutStore.getState().layoutByWorkspace[workspaceKey];
|
||||
|
||||
expect(layout.focusedPaneId).toBe(splitPaneId);
|
||||
expect(collectAllPanes(layout.root).map((pane) => pane.id)).toEqual([splitPaneId!]);
|
||||
expect(findPaneById(layout.root, splitPaneId!)?.tabIds).toEqual([
|
||||
expect(findPaneById(layout.root, splitPaneId)?.tabIds).toEqual([
|
||||
"file_/repo/worktree/b.ts",
|
||||
"file_/repo/worktree/a.ts",
|
||||
]);
|
||||
@@ -852,7 +852,7 @@ describe("workspace-layout-store actions", () => {
|
||||
});
|
||||
|
||||
store.closeTab(workspaceKey, secondTabId!);
|
||||
const layout = useWorkspaceLayoutStore.getState().layoutByWorkspace[workspaceKey]!;
|
||||
const layout = useWorkspaceLayoutStore.getState().layoutByWorkspace[workspaceKey];
|
||||
const rootGroup = expectGroup(layout.root);
|
||||
|
||||
expect(paneBId).toBe("pane_78787878-7878-7878-7878-787878787878");
|
||||
@@ -910,7 +910,7 @@ describe("workspace-layout-store actions", () => {
|
||||
kind: "file",
|
||||
path: "/repo/worktree/b.ts",
|
||||
});
|
||||
const layout = useWorkspaceLayoutStore.getState().layoutByWorkspace[workspaceKey]!;
|
||||
const layout = useWorkspaceLayoutStore.getState().layoutByWorkspace[workspaceKey];
|
||||
|
||||
expect(splitPaneId).toBe("pane_abababab-abab-abab-abab-abababababab");
|
||||
expect(duplicateTabId).toBe(secondTabId);
|
||||
@@ -946,14 +946,14 @@ describe("workspace-layout-store actions", () => {
|
||||
position: "right",
|
||||
});
|
||||
|
||||
const splitRoot = useWorkspaceLayoutStore.getState().layoutByWorkspace[workspaceKey]!.root;
|
||||
const splitRoot = useWorkspaceLayoutStore.getState().layoutByWorkspace[workspaceKey].root;
|
||||
const splitGroup = expectGroup(splitRoot);
|
||||
const nestedGroup = expectGroup(splitGroup.group.children[1]!);
|
||||
const nestedGroup = expectGroup(splitGroup.group.children[1]);
|
||||
store.resizeSplit(workspaceKey, nestedGroup.group.id, [0.01, 0.99]);
|
||||
|
||||
const resizedRoot = useWorkspaceLayoutStore.getState().layoutByWorkspace[workspaceKey]!.root;
|
||||
const resizedRoot = useWorkspaceLayoutStore.getState().layoutByWorkspace[workspaceKey].root;
|
||||
const resizedGroup = expectGroup(resizedRoot);
|
||||
const resizedNestedGroup = expectGroup(resizedGroup.group.children[1]!);
|
||||
const resizedNestedGroup = expectGroup(resizedGroup.group.children[1]);
|
||||
const total = resizedNestedGroup.group.sizes.reduce((sum, size) => sum + size, 0);
|
||||
|
||||
expect(rightPaneId).toBe("pane_eeeeeeee-eeee-eeee-eeee-eeeeeeeeeeee");
|
||||
@@ -969,7 +969,7 @@ describe("workspace-layout-store actions", () => {
|
||||
|
||||
const tabId = store.openTabFocused(workspaceKey, { kind: "draft", draftId: "draft-1" });
|
||||
store.closeTab(workspaceKey, tabId!);
|
||||
const layout = useWorkspaceLayoutStore.getState().layoutByWorkspace[workspaceKey]!;
|
||||
const layout = useWorkspaceLayoutStore.getState().layoutByWorkspace[workspaceKey];
|
||||
|
||||
expect(layout).toEqual(createDefaultLayout());
|
||||
});
|
||||
@@ -1065,7 +1065,7 @@ describe("workspace-layout-store actions", () => {
|
||||
});
|
||||
|
||||
const nextTabId = store.convertDraftToAgent(workspaceKey, draftTabId!, "agent-1");
|
||||
const layout = useWorkspaceLayoutStore.getState().layoutByWorkspace[workspaceKey]!;
|
||||
const layout = useWorkspaceLayoutStore.getState().layoutByWorkspace[workspaceKey];
|
||||
|
||||
expect(splitPaneId).toBe("pane_67676767-6767-6767-6767-676767676767");
|
||||
expect(nextTabId).toBe("agent_agent-1");
|
||||
@@ -1129,7 +1129,7 @@ describe("workspace-layout-store actions", () => {
|
||||
hasActivePendingDraftCreate: false,
|
||||
});
|
||||
|
||||
const layout = useWorkspaceLayoutStore.getState().layoutByWorkspace[workspaceKey]!;
|
||||
const layout = useWorkspaceLayoutStore.getState().layoutByWorkspace[workspaceKey];
|
||||
const tabs = collectAllTabs(layout.root);
|
||||
|
||||
expect(tabs.map((tab) => tab.tabId)).toEqual([
|
||||
@@ -1189,7 +1189,7 @@ describe("workspace-layout-store actions", () => {
|
||||
});
|
||||
|
||||
const tabs = useWorkspaceLayoutStore.getState().getWorkspaceTabs(workspaceKey);
|
||||
const layout = useWorkspaceLayoutStore.getState().layoutByWorkspace[workspaceKey]!;
|
||||
const layout = useWorkspaceLayoutStore.getState().layoutByWorkspace[workspaceKey];
|
||||
expect(tabs.map((tab) => tab.tabId)).toEqual(["terminal_term-script", "terminal_term-manual"]);
|
||||
expect(findPaneById(layout.root, layout.focusedPaneId)?.focusedTabId).toBe(scriptTabId);
|
||||
});
|
||||
|
||||
@@ -134,9 +134,8 @@ export function upsertHostConnectionInProfiles(input: {
|
||||
return [...existing, profile];
|
||||
}
|
||||
|
||||
const matchedProfiles = matchingIndexes.map((index) => existing[index]!);
|
||||
const prev =
|
||||
matchedProfiles.find((daemon) => daemon.serverId === serverId) ?? matchedProfiles[0]!;
|
||||
const matchedProfiles = matchingIndexes.map((index) => existing[index]);
|
||||
const prev = matchedProfiles.find((daemon) => daemon.serverId === serverId) ?? matchedProfiles[0];
|
||||
const nextConnections = dedupeHostConnections([
|
||||
...matchedProfiles.flatMap((daemon) => daemon.connections),
|
||||
input.connection,
|
||||
@@ -180,7 +179,7 @@ export function upsertHostConnectionInProfiles(input: {
|
||||
updatedAt: now,
|
||||
};
|
||||
|
||||
const firstIndex = matchingIndexes[0]!;
|
||||
const firstIndex = matchingIndexes[0];
|
||||
const matchingIndexSet = new Set(matchingIndexes);
|
||||
const next = existing.filter((_daemon, index) => !matchingIndexSet.has(index));
|
||||
next.splice(firstIndex, 0, nextProfile);
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import type { FetchAgentHistoryEntry, FetchAgentsEntry } from "@server/client/daemon-client";
|
||||
import type { FetchAgentsEntry } from "@server/client/daemon-client";
|
||||
import { type Agent, useSessionStore } from "@/stores/session-store";
|
||||
import { derivePendingPermissionKey, normalizeAgentSnapshot } from "@/utils/agent-snapshots";
|
||||
import { resolveProjectPlacement } from "@/utils/project-placement";
|
||||
|
||||
type AgentDirectoryFetchEntry = FetchAgentsEntry | FetchAgentHistoryEntry;
|
||||
type AgentDirectoryFetchEntry = FetchAgentsEntry;
|
||||
|
||||
interface PendingPermissionEntry {
|
||||
key: string;
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import type { AgentLifecycleStatus } from "@server/shared/agent-lifecycle";
|
||||
import type { AgentSnapshotPayload } from "@server/shared/messages";
|
||||
import type { AgentPermissionRequest } from "@server/server/agent/agent-sdk-types";
|
||||
|
||||
@@ -31,7 +30,7 @@ export function normalizeAgentSnapshot(snapshot: AgentSnapshotPayload, serverId:
|
||||
serverId,
|
||||
id: snapshot.id,
|
||||
provider: snapshot.provider,
|
||||
status: snapshot.status as AgentLifecycleStatus,
|
||||
status: snapshot.status,
|
||||
createdAt,
|
||||
updatedAt,
|
||||
lastUserMessageAt,
|
||||
|
||||
@@ -148,7 +148,7 @@ describe("sendOsNotification", () => {
|
||||
clicked.clickListeners[0]?.({} as Event);
|
||||
|
||||
expect(dispatchEvent).toHaveBeenCalledTimes(1);
|
||||
const event = dispatchEvent.mock.calls[0]?.[0] as unknown as {
|
||||
const event = dispatchEvent.mock.calls[0]?.[0] as {
|
||||
type?: string;
|
||||
detail?: { data?: Record<string, unknown> };
|
||||
};
|
||||
|
||||
@@ -132,7 +132,7 @@ function dispatchWebNotificationClick(detail: WebNotificationClickDetail): boole
|
||||
cancelable: true,
|
||||
},
|
||||
);
|
||||
return dispatch(event) === false;
|
||||
return !dispatch(event);
|
||||
}
|
||||
|
||||
function fallbackNavigateToNotificationTarget(data: Record<string, unknown> | undefined): void {
|
||||
|
||||
@@ -38,8 +38,8 @@ function resamplePcm16(pcm: Uint8Array, fromRate: number, toRate: number): Uint8
|
||||
if (i + 1 >= pcm.length) {
|
||||
return 0;
|
||||
}
|
||||
const lo = pcm[i]!;
|
||||
const hi = pcm[i + 1]!;
|
||||
const lo = pcm[i];
|
||||
const hi = pcm[i + 1];
|
||||
let value = (hi << 8) | lo;
|
||||
if (value & 0x8000) {
|
||||
value = value - 0x10000;
|
||||
|
||||
@@ -39,7 +39,7 @@ function resampleToPcm16(input: Float32Array, inputRate: number, outputRate: num
|
||||
const i0 = Math.floor(sourceIndex);
|
||||
const i1 = Math.min(input.length - 1, i0 + 1);
|
||||
const frac = sourceIndex - i0;
|
||||
const sample = input[i0]! * (1 - frac) + input[i1]! * frac;
|
||||
const sample = input[i0] * (1 - frac) + input[i1] * frac;
|
||||
output[i] = floatToInt16(sample);
|
||||
}
|
||||
|
||||
@@ -64,8 +64,8 @@ function pcm16LeToAudioBuffer(
|
||||
const audioBuffer = context.createBuffer(1, sampleCount, sampleRate);
|
||||
const channel = audioBuffer.getChannelData(0);
|
||||
for (let i = 0; i < sampleCount; i += 1) {
|
||||
const lo = bytes[i * 2]!;
|
||||
const hi = bytes[i * 2 + 1]!;
|
||||
const lo = bytes[i * 2];
|
||||
const hi = bytes[i * 2 + 1];
|
||||
let value = (hi << 8) | lo;
|
||||
if (value & 0x8000) {
|
||||
value -= 0x10000;
|
||||
@@ -77,8 +77,8 @@ function pcm16LeToAudioBuffer(
|
||||
|
||||
async function decodeAudioData(context: AudioContext, buffer: ArrayBuffer): Promise<AudioBuffer> {
|
||||
const maybePromise = context.decodeAudioData(buffer.slice(0));
|
||||
if (maybePromise && typeof (maybePromise as Promise<AudioBuffer>).then === "function") {
|
||||
return maybePromise as Promise<AudioBuffer>;
|
||||
if (maybePromise && typeof maybePromise.then === "function") {
|
||||
return maybePromise;
|
||||
}
|
||||
return await new Promise<AudioBuffer>((resolve, reject) => {
|
||||
context.decodeAudioData(buffer.slice(0), resolve, reject);
|
||||
@@ -323,7 +323,7 @@ export function createAudioEngine(
|
||||
const input = event.inputBuffer.getChannelData(0);
|
||||
let sumSquares = 0;
|
||||
for (let i = 0; i < input.length; i += 1) {
|
||||
const sample = input[i]!;
|
||||
const sample = input[i];
|
||||
sumSquares += sample * sample;
|
||||
}
|
||||
const rms = Math.sqrt(sumSquares / Math.max(1, input.length));
|
||||
|
||||
@@ -295,7 +295,7 @@ export function createVoiceRuntime(deps: VoiceRuntimeDeps): VoiceRuntime {
|
||||
|
||||
function activateNextPlaybackGroup(): void {
|
||||
while (playback.orderedGroupIds.length > 0) {
|
||||
const groupId = playback.orderedGroupIds[0]!;
|
||||
const groupId = playback.orderedGroupIds[0];
|
||||
if (playback.groups.has(groupId)) {
|
||||
playback.activeGroupId = groupId;
|
||||
return;
|
||||
|
||||
Reference in New Issue
Block a user