Files
orca/src/preload/api/skills-bridge.ts
T
Neil 401664298f fix(preload): make a dropped bridge key a compile error
The split silently dropped jira.searchUsers and
runtimeEnvironments.retryControlConnection. Neither failed typecheck: the bridge
modules carried no satisfies annotation and the composed api object was
unannotated, so a missing key was only a runtime TypeError in the renderer.

Annotates each module against PreloadApi, the type window.api is already
declared as, so the contract supplies the shape rather than a parallel copy.
Deleting jira.searchUsers now fails with TS2741 naming the key.

Turning this on surfaced 106 places where a bridge locally annotated
Promise<unknown> or unknown[] over a contract that declares concrete types --
the bridge was erasing types the renderer relied on. Those annotations are gone.

Also exposes app.awaitBeforeUnloadCheckpoint, which was declared and called but
never actually on the bridge, so the lazy-chunk recovery reload optional-chained
to a no-op and navigated without joining the checkpoint. The missing key was
caught by the new annotation rather than by hand.
2026-09-01 18:24:49 -07:00

131 lines
6.2 KiB
TypeScript

import { ipcRenderer } from 'electron'
import type {
SkillDeletePlan,
SkillDeleteRequest,
SkillDeleteResult
} from '../../shared/skill-delete-contract'
import type { SkillDiscoveryResult, SkillDiscoveryTarget } from '../../shared/skills'
import type {
SkillCloudOwnedShare,
SkillCloudOperation,
SkillCloudPackageDetails
} from '../../shared/skill-cloud-contract'
import type {
SkillBundleInstallPreviewInput,
SkillBundleInstallPreviewOperation,
SkillBundlePackageVersionInstallInput,
SkillBundleShareInstallInput,
SkillBundleShareInstallOperation,
SkillInstallPreviewInput,
SkillInstallPreviewOperation,
ManagedSkillInstallListOperation,
SkillPackageVersionInstallInput,
SkillRemoveInput,
SkillRemoveOperation,
SkillShareInstallInput,
SkillShareInstallOperation,
SkillInstallCancelInput,
SkillInstallProgress,
SkillSharePreview,
SkillShareProgress,
SkillSharePublishInput,
SkillSharePublishOperation,
SkillShareResolvedOperation
} from '../../shared/skill-sharing-contract'
import type {
SkillFreshnessInventory,
SkillUpdateRun,
SkillUpdateStartResult
} from '../../shared/skill-freshness'
import type { PreloadApi } from '../api-types'
export const skillsApi = {
discover: (target?: SkillDiscoveryTarget): Promise<SkillDiscoveryResult> =>
ipcRenderer.invoke('skills:discover', target),
freshnessInventory: (): Promise<SkillFreshnessInventory> =>
ipcRenderer.invoke('skills:freshnessInventory'),
startUpdateRun: (names: string[]): Promise<SkillUpdateStartResult> =>
ipcRenderer.invoke('skills:startUpdateRun', names),
cancelUpdateRun: (): Promise<void> => ipcRenderer.invoke('skills:cancelUpdateRun'),
acknowledgeUpdateRun: (): Promise<void> => ipcRenderer.invoke('skills:acknowledgeUpdateRun'),
getUpdateRun: (): Promise<SkillUpdateRun> => ipcRenderer.invoke('skills:getUpdateRun'),
prepareShare: (input: {
skillIds: string[]
bundleName: string
target?: SkillDiscoveryTarget
packageId?: string
}): Promise<SkillSharePreview> => ipcRenderer.invoke('skills:prepareShare', input),
publishShare: (input: SkillSharePublishInput): Promise<SkillSharePublishOperation> =>
ipcRenderer.invoke('skills:publishShare', input),
cancelShare: (preparationId: string): Promise<void> =>
ipcRenderer.invoke('skills:cancelShare', preparationId),
releaseShare: (preparationId: string): Promise<void> =>
ipcRenderer.invoke('skills:releaseShare', preparationId),
resolveShare: (shareId: string): Promise<SkillShareResolvedOperation> =>
ipcRenderer.invoke('skills:resolveShare', shareId),
installShare: (input: SkillShareInstallInput): Promise<SkillShareInstallOperation> =>
ipcRenderer.invoke('skills:installShare', input),
installBundleShare: (
input: SkillBundleShareInstallInput
): Promise<SkillBundleShareInstallOperation> =>
ipcRenderer.invoke('skills:installBundleShare', input),
installBundlePackageVersion: (
input: SkillBundlePackageVersionInstallInput
): Promise<SkillBundleShareInstallOperation> =>
ipcRenderer.invoke('skills:installBundlePackageVersion', input),
installPackageVersion: (
input: SkillPackageVersionInstallInput
): Promise<SkillShareInstallOperation> =>
ipcRenderer.invoke('skills:installPackageVersion', input),
cancelInstall: (input: SkillInstallCancelInput): Promise<{ cancelled: boolean }> =>
ipcRenderer.invoke('skills:cancelInstall', input),
previewInstall: (input: SkillInstallPreviewInput): Promise<SkillInstallPreviewOperation> =>
ipcRenderer.invoke('skills:previewInstall', input),
previewBundleInstall: (
input: SkillBundleInstallPreviewInput
): Promise<SkillBundleInstallPreviewOperation> =>
ipcRenderer.invoke('skills:previewBundleInstall', input),
removeInstall: (input: SkillRemoveInput): Promise<SkillRemoveOperation> =>
ipcRenderer.invoke('skills:removeInstall', input),
// Desktop always registers the delete IPC handlers in its own main process.
deleteSupported: (): Promise<boolean> => Promise.resolve(true),
previewDelete: (request: SkillDeleteRequest): Promise<SkillDeletePlan> =>
ipcRenderer.invoke('skills:previewDelete', request),
delete: (request: SkillDeleteRequest): Promise<SkillDeleteResult> =>
ipcRenderer.invoke('skills:delete', request),
listManagedInstalls: (environmentId?: string): Promise<ManagedSkillInstallListOperation> =>
ipcRenderer.invoke('skills:listManagedInstalls', environmentId),
getPackage: (packageId: string): Promise<SkillCloudOperation<SkillCloudPackageDetails>> =>
ipcRenderer.invoke('skills:getPackage', packageId),
listOwnedShares: (): Promise<SkillCloudOperation<SkillCloudOwnedShare[]>> =>
ipcRenderer.invoke('skills:listOwnedShares'),
revokeShare: (shareId: string): Promise<SkillCloudOperation<void>> =>
ipcRenderer.invoke('skills:revokeShare', shareId),
deletePackageVersion: (input: {
packageId: string
versionId: string
}): Promise<SkillCloudOperation<void>> =>
ipcRenderer.invoke('skills:deletePackageVersion', input),
deletePackage: (packageId: string): Promise<SkillCloudOperation<void>> =>
ipcRenderer.invoke('skills:deletePackage', packageId),
listWslDistros: (environmentId?: string): Promise<string[]> =>
ipcRenderer.invoke('skills:listWslDistros', environmentId),
onInstallProgress: (callback: (progress: SkillInstallProgress) => void): (() => void) => {
const listener = (_event: Electron.IpcRendererEvent, progress: SkillInstallProgress): void =>
callback(progress)
ipcRenderer.on('skills:installProgress', listener)
return () => ipcRenderer.removeListener('skills:installProgress', listener)
},
onShareProgress: (callback: (progress: SkillShareProgress) => void): (() => void) => {
const listener = (_event: Electron.IpcRendererEvent, progress: SkillShareProgress): void =>
callback(progress)
ipcRenderer.on('skills:shareProgress', listener)
return () => ipcRenderer.removeListener('skills:shareProgress', listener)
},
onUpdateRun: (callback: (run: SkillUpdateRun) => void): (() => void) => {
const listener = (_event: Electron.IpcRendererEvent, run: SkillUpdateRun): void => callback(run)
ipcRenderer.on('skills:updateRun', listener)
return () => ipcRenderer.removeListener('skills:updateRun', listener)
}
} satisfies PreloadApi['skills']