From 73c5009b82ee0bb723c9b6883b4ad2682ca477a4 Mon Sep 17 00:00:00 2001 From: Neil <4138956+nwparker@users.noreply.github.com> Date: Sun, 2 Aug 2026 00:33:57 -0700 Subject: [PATCH] chore(dead-code): drop ~2k lines of unreachable exports and orphan modules (#12077) * chore(dead-code): drop 2k lines of unreachable exports and orphan modules Ran knip across every build entry (main, preload, renderer, popout, web, cli, relay, workers, forked sidecars, config scripts) and removed what no entry graph can reach. - 11 orphan modules nothing imported, plus one test that only covered them - 159 unused exports/types, with their now-dead helpers, imports and tests Each candidate was verified against dynamic references before deletion. 42 knip hits were false positives and are kept: shared modules consumed by the mobile/ workspace, the src/shared/plugins/** public API, vendored shadcn primitives, and relay wire-protocol constants held for compatibility. Adds knip.json + `pnpm audit:dead-code` so this stays measurable. Verified: pnpm typecheck, pnpm lint, and 2081 tests across the 73 affected test files all pass. * chore(dead-code): move knip config under config/ Root-level additions are blocked by the root directory guard. Co-authored-by: Orca --------- Co-authored-by: Orca --- config/knip.json | 41 ++++ package.json | 1 + src/cli/runtime/environments.ts | 4 - ...scanner-opencode-sqlite-worker-protocol.ts | 4 +- src/main/claude-usage/scanner.ts | 22 --- src/main/codex-usage/scanner.ts | 14 -- .../computer/macos-native-provider-paths.ts | 17 -- .../daemon/terminal-private-mode-tracker.ts | 89 --------- .../emulator/android/android-input-mapping.ts | 8 - src/main/emulator/emulator-types.ts | 6 - src/main/git/git-username.ts | 8 - src/main/git/repo.ts | 8 - src/main/github/github-api-repository.ts | 9 - .../github/github-enterprise-repository.ts | 5 - src/main/github/project-view.ts | 2 +- src/main/github/project-view/internals.ts | 6 - src/main/gitlab/gl-utils.ts | 5 - src/main/ipc/feedback-image-attachments.ts | 4 - .../ipc/parcel-watcher-host-subscriptions.ts | 15 -- src/main/ipc/parcel-watcher-process.ts | 3 - ...runtime-environment-request-connections.ts | 9 - src/main/ipc/worktree-change-invalidators.ts | 4 - src/main/observability/index.ts | 4 - src/main/observability/instrumentation.ts | 26 --- src/main/observability/redactor.ts | 11 -- src/main/pi/prefill-extension-source.ts | 9 - src/main/pi/titlebar-extension-service.ts | 1 - src/main/plugins/plugin-enablement.ts | 2 - .../providers/pty-process-list-admission.ts | 14 -- src/main/providers/types.ts | 14 +- src/main/rate-limits/grok-auth.ts | 4 - src/main/runtime/orca-runtime-emulator.ts | 18 -- src/main/runtime/orca-runtime.ts | 3 +- src/main/runtime/orchestration/groups.ts | 2 - src/main/runtime/rpc/schemas.ts | 2 - src/main/shell-ready-marker-scanner.ts | 1 - src/main/ssh/relay-protocol.ts | 4 - src/main/ssh/sftp-namespace-resolution.ts | 4 +- src/main/ssh/sftp-upload.ts | 22 --- src/main/ssh/ssh-pty-consumer-session.ts | 3 - .../ssh-relay-session-managed-hooks.test.ts | 1 - src/main/ssh/ssh-relay-session.test.ts | 1 - src/main/system-fonts.ts | 4 - src/main/telemetry/client.ts | 4 - src/relay/fs-handler-file-read.ts | 11 +- .../automations/automation-page-parts.tsx | 9 - .../browser-automation-visibility.ts | 5 - .../browser-pane/browser-page-zoom.ts | 8 - .../components/dashboard/useDashboardData.ts | 187 +----------------- .../components/editor/NotesSendMenu.test.tsx | 3 +- .../ReviewNotesSendMenuContent.test.tsx | 3 +- .../components/editor/markdown-round-trip.ts | 9 - .../emulator-pane/emulator-keyboard-paste.ts | 4 - .../emulator-pane/emulator-pane-types.ts | 2 - .../github-project/column-widths.ts | 14 -- .../github/github-issue-comment-helpers.ts | 77 -------- .../components/linear-issue-workspace-text.ts | 18 -- .../native-chat/native-chat-composer-state.ts | 2 - .../onboarding/use-onboarding-flow.ts | 2 - .../src/components/repo/repo-icon.tsx | 6 - .../CreateHostedReviewComposer.tsx | 7 - .../commit-failure-dialog-state.ts | 4 - .../file-explorer-operation-owner.ts | 10 - ...le-explorer-runtime-owner-boundary.test.ts | 2 +- .../right-sidebar/push-failure-summary.ts | 6 - .../source-control-active-open-file-keys.ts | 4 - ...e-control-ai-commit-failure-launch.test.ts | 175 ---------------- ...source-control-ai-commit-failure-launch.ts | 47 ----- .../source-control-ai-push-failure-launch.ts | 47 ----- .../source-control-create-pr-intent-state.ts | 11 +- .../source-control-primary-action-types.ts | 10 - .../components/settings/SettingsConstants.ts | 2 - .../src/components/settings/general-search.ts | 29 --- .../settings/terminal-windows-search.ts | 7 - .../sidebar/WorktreeCardHelpers.tsx | 13 +- .../components/sidebar/WorktreeCardPorts.tsx | 30 --- .../sidebar/create-project-defaults.ts | 2 - .../components/sidebar/project-header-drop.ts | 10 - .../sidebar/sidebar-host-options.ts | 7 - .../sidebar/sidebar-nav-controls.tsx | 35 ---- .../workspace-kanban-card-drag-preview-dom.ts | 12 -- .../src/components/tab-bar/shell-icons.tsx | 2 - .../tab-create-entry-path-validation.ts | 12 -- .../components/tab-group/tab-drag-context.tsx | 4 - .../terminal-pane/pty-delivery-interest.ts | 5 - .../terminal-pane/pty-pre-handler-buffer.ts | 5 - .../terminal-hidden-delivery-gate.ts | 5 - .../terminal/terminal-tab-actions.ts | 37 ---- src/renderer/src/constants/terminal.ts | 4 - .../hooks/useAutomationDispatchEvents.test.ts | 5 +- src/renderer/src/hooks/useIssueMetadata.ts | 5 - src/renderer/src/hooks/useShortcutLabel.ts | 23 --- .../src/lib/active-agent-note-send.ts | 1 - .../src/lib/active-agent-note-target.ts | 44 ----- .../src/lib/agent-hibernation-coordinator.ts | 4 - src/renderer/src/lib/agent-paste-draft.ts | 18 -- .../src/lib/crash-diagnostics.test.ts | 15 +- src/renderer/src/lib/crash-diagnostics.ts | 4 - src/renderer/src/lib/ensure-simulator-tab.ts | 18 -- .../lib/keyboard-layout/input-source-id.ts | 4 - .../keyboard-layout/option-as-alt-probe.ts | 6 - .../src/lib/open-mobile-emulator-tab.test.ts | 3 +- src/renderer/src/lib/repo-slug-index.ts | 10 - src/renderer/src/lib/setup-script-status.ts | 27 +-- .../src/lib/workspace-port-actions.ts | 18 -- .../store/slices/runtime-detected-agents.ts | 4 - src/shared/agent-session-host-authority.ts | 2 - src/shared/agent-session-option-catalog.ts | 8 - src/shared/commit-message-generation.ts | 8 - src/shared/custom-pet-media-limits.ts | 19 -- src/shared/daemon-audit-eligibility.ts | 1 - src/shared/daemon-lifecycle-telemetry.ts | 2 - src/shared/ephemeral-vm-recipes.ts | 22 +-- src/shared/ephemeral-vm-runtimes.ts | 4 - src/shared/folder-workspaces.ts | 8 +- src/shared/hermes-run-output-limits.ts | 21 -- src/shared/hermes-run-ref-retention.ts | 8 - src/shared/hosted-review.ts | 8 - src/shared/html-to-pdf-memory-limit.ts | 13 -- src/shared/left-sidebar-appearance.ts | 7 - src/shared/linear-agent-access.ts | 5 - src/shared/linux-proc-port-scan-limits.ts | 1 - src/shared/native-file-drop.ts | 8 - src/shared/persisted-state-file-bounds.ts | 20 +- src/shared/pr-refresh-memory-limits.ts | 5 - src/shared/pty-source-credit-contract.ts | 1 - src/shared/relay-json-admission.ts | 12 -- src/shared/remote-runtime-memory-limits.ts | 1 - .../remote-runtime-shared-control-state.ts | 16 -- src/shared/remote-workspace-types.ts | 5 - src/shared/runtime-bootstrap.ts | 13 -- src/shared/runtime-environments.ts | 2 - src/shared/runtime-types.ts | 19 -- src/shared/serve-update-handoff.ts | 12 -- .../source-control-create-review-intent.ts | 11 -- src/shared/ssh-retained-payload-admission.ts | 1 - src/shared/task-source-context.ts | 6 - src/shared/telemetry-events.ts | 7 - src/shared/terminal-custom-themes.ts | 2 - src/shared/terminal-scrollback-policy.ts | 4 - src/shared/terminal-size-limits.ts | 34 ---- src/shared/terminal-title-display.ts | 108 ---------- src/shared/terminal-title-status.ts | 165 ---------------- src/shared/work-items.ts | 17 +- src/shared/workspace-scope.ts | 6 - src/shared/wsl-hook-relay-contract.ts | 10 - 146 files changed, 71 insertions(+), 2102 deletions(-) create mode 100644 config/knip.json delete mode 100644 src/main/daemon/terminal-private-mode-tracker.ts delete mode 100644 src/renderer/src/components/right-sidebar/push-failure-summary.ts delete mode 100644 src/renderer/src/components/right-sidebar/source-control-ai-commit-failure-launch.test.ts delete mode 100644 src/renderer/src/components/right-sidebar/source-control-ai-commit-failure-launch.ts delete mode 100644 src/renderer/src/components/right-sidebar/source-control-ai-push-failure-launch.ts delete mode 100644 src/shared/custom-pet-media-limits.ts delete mode 100644 src/shared/html-to-pdf-memory-limit.ts delete mode 100644 src/shared/pr-refresh-memory-limits.ts delete mode 100644 src/shared/relay-json-admission.ts delete mode 100644 src/shared/terminal-size-limits.ts delete mode 100644 src/shared/terminal-title-display.ts delete mode 100644 src/shared/terminal-title-status.ts diff --git a/config/knip.json b/config/knip.json new file mode 100644 index 00000000000..a48793b7902 --- /dev/null +++ b/config/knip.json @@ -0,0 +1,41 @@ +{ + "$schema": "https://unpkg.com/knip@5/schema.json", + "entry": [ + "src/main/index.ts", + "src/preload/index.ts", + "src/preload/browser-window-close.ts", + "src/main/daemon/daemon-entry.ts", + "src/main/plugins/plugin-host-entry.ts", + "src/main/computer/sidecar-entry.ts", + "src/main/speech/stt-worker.ts", + "src/main/warp-themes/warp-theme-parser-worker.ts", + "src/main/ai-vault/session-scanner-opencode-sqlite-worker-entry.ts", + "src/main/ipc/parcel-watcher-process-entry.ts", + "src/main/hang-watchdog/main-thread-hang-watchdog-entry.ts", + "src/main/codex/codex-app-server-grant-entry.ts", + "src/main/agent-hooks/managed-agent-hook-controls.ts", + "src/main/claude-accounts/keychain.ts", + "src/renderer/src/main.tsx", + "src/renderer/src/popout.tsx", + "src/renderer/src/web/main.tsx", + "src/renderer/src/**/*.worker.ts", + "src/cli/index.ts", + "src/relay/relay.ts", + "src/relay/wsl-agent-hook-relay.ts", + "config/scripts/**/*.{mjs,cjs,js,ts}", + "build-plugins/**/*.ts", + "electron.vite.config.ts", + "vite.web.config.ts", + "config/vitest.config.ts", + "config/i18next.config.ts", + "config/electron-builder.config.cjs", + "config/oxlint-plugins/**/*.{js,mjs,ts}", + "tests/**/*.{ts,tsx,mjs}", + "**/*.test.{ts,tsx}" + ], + "project": ["src/**/*.{ts,tsx}", "config/scripts/**/*.{mjs,cjs,js,ts}", "build-plugins/**/*.ts"], + "ignore": ["mobile/**", "out/**", "dist/**", "node_modules/**", "resources/**"], + "ignoreDependencies": ["electron", "@types/*"], + "ignoreExportsUsedInFile": true, + "includeEntryExports": false +} diff --git a/package.json b/package.json index 7ccb8fabee3..52da12d0278 100644 --- a/package.json +++ b/package.json @@ -16,6 +16,7 @@ "audit:code-quality:native": "oxlint --config config/oxlint-code-quality-native-plugins.json src config tests mobile --deny-warnings", "audit:code-quality:type-aware": "oxlint --type-aware --config config/oxlint-code-quality-type-aware.json src config tests --deny-warnings", "audit:react-doctor": "pnpm dlx react-doctor@0.9.1 . --yes --no-supply-chain --no-telemetry --blocking none", + "audit:dead-code": "pnpm dlx knip@5 --config config/knip.json", "check:code-quality:changed": "node config/scripts/check-changed-code-quality.mjs", "check:react-doctor:changed": "node config/scripts/check-react-doctor-changed.mjs", "check:zustand-selector-fanout": "node config/scripts/zustand-selector-fanout-benchmark.mjs --check", diff --git a/src/cli/runtime/environments.ts b/src/cli/runtime/environments.ts index 3009b11c9cb..c3594254587 100644 --- a/src/cli/runtime/environments.ts +++ b/src/cli/runtime/environments.ts @@ -20,10 +20,6 @@ export type EnvironmentAddResult = { environment: PublicKnownRuntimeEnvironment } -export type EnvironmentListResult = { - environments: PublicKnownRuntimeEnvironment[] -} - export type EnvironmentRemoveResult = { removed: PublicKnownRuntimeEnvironment } diff --git a/src/main/ai-vault/session-scanner-opencode-sqlite-worker-protocol.ts b/src/main/ai-vault/session-scanner-opencode-sqlite-worker-protocol.ts index f0a85edf891..4f67393537a 100644 --- a/src/main/ai-vault/session-scanner-opencode-sqlite-worker-protocol.ts +++ b/src/main/ai-vault/session-scanner-opencode-sqlite-worker-protocol.ts @@ -1,4 +1,4 @@ -import type { AiVaultScanIssue, AiVaultSession } from '../../shared/ai-vault-types' +import type { AiVaultScanIssue } from '../../shared/ai-vault-types' import type { SessionFileCandidate } from './session-scanner-types' // Why: request/response shapes shared by the worker entry and the main-thread @@ -30,8 +30,6 @@ export type OpenCodeSqliteListValue = { issues: AiVaultScanIssue[] } -export type OpenCodeSqliteParseValue = AiVaultSession | null - export type OpenCodeSqliteWorkerResponse = | { id: number; ok: true; value: unknown } | { id: number; ok: false; error: string } diff --git a/src/main/claude-usage/scanner.ts b/src/main/claude-usage/scanner.ts index 565f7e49c81..5006a73db0e 100644 --- a/src/main/claude-usage/scanner.ts +++ b/src/main/claude-usage/scanner.ts @@ -170,24 +170,6 @@ export async function listClaudeTranscriptFiles(): Promise { return [...new Set(files.flat())].sort() } -export async function getProcessedFileInfo(filePath: string): Promise { - const fileStat = await stat(filePath) - let lineCount = 0 - const lines = createInterface({ - input: createReadStream(filePath, { encoding: 'utf-8' }), - crlfDelay: Infinity - }) - for await (const _line of lines) { - lineCount++ - } - return { - path: filePath, - mtimeMs: fileStat.mtimeMs, - size: fileStat.size, - lineCount - } -} - async function getProcessedFileStat( filePath: string ): Promise> { @@ -784,7 +766,3 @@ export function getSessionProjectLabel(locationBreakdown: ClaudeUsageLocationBre } return 'Multiple locations' } - -export function getDefaultWorktreeLabel(pathValue: string): string { - return basename(pathValue) -} diff --git a/src/main/codex-usage/scanner.ts b/src/main/codex-usage/scanner.ts index eb5fbcaab14..86da9db678f 100644 --- a/src/main/codex-usage/scanner.ts +++ b/src/main/codex-usage/scanner.ts @@ -1179,17 +1179,3 @@ export function createWorktreeRefs( } return refs } - -export function getDefaultWorktreeLabel(pathValue: string): string { - return basename(pathValue) -} - -export function getSessionProjectLabel(locationBreakdown: CodexUsageLocationBreakdown[]): string { - if (locationBreakdown.length === 0) { - return 'Unknown location' - } - if (locationBreakdown.length === 1) { - return locationBreakdown[0].projectLabel - } - return 'Multiple locations' -} diff --git a/src/main/computer/macos-native-provider-paths.ts b/src/main/computer/macos-native-provider-paths.ts index 7ca8134f03f..bf0e9f3fc51 100644 --- a/src/main/computer/macos-native-provider-paths.ts +++ b/src/main/computer/macos-native-provider-paths.ts @@ -25,20 +25,3 @@ export function resolveMacOSComputerUseExecutablePath(): string | null { const executablePath = join(appPath, 'Contents', 'MacOS', 'orca-computer-use-macos') return existsSync(executablePath) ? executablePath : null } - -export function resolveMacOSNativeProviderPath(): string | null { - const override = process.env.ORCA_COMPUTER_MACOS_PROVIDER_PATH - if (override && existsSync(override)) { - return override - } - - const packaged = [join(process.resourcesPath ?? '', 'computer-use-macos/orca-computer-use-macos')] - const dev = [ - join(process.cwd(), 'native/computer-use-macos/.build/debug/orca-computer-use-macos'), - join(process.cwd(), 'native/computer-use-macos/.build/release/orca-computer-use-macos'), - resolve(__dirname, '../../native/computer-use-macos/.build/debug/orca-computer-use-macos') - ] - const candidates = process.resourcesPath ? [...packaged, ...dev] : dev - - return candidates.find((candidate) => candidate && existsSync(candidate)) ?? null -} diff --git a/src/main/daemon/terminal-private-mode-tracker.ts b/src/main/daemon/terminal-private-mode-tracker.ts deleted file mode 100644 index a8f20ef7a4d..00000000000 --- a/src/main/daemon/terminal-private-mode-tracker.ts +++ /dev/null @@ -1,89 +0,0 @@ -import type { TerminalModes } from './types' - -// Why: PTY/SSH chunks can split a long combined DECSET before the final h/l. -// Keep parser state far beyond normal mode lists while still bounding memory. -const PRIVATE_MODE_SCAN_TAIL_LIMIT = 4096 - -type MouseTrackingMode = NonNullable - -// Why: @xterm/headless doesn't expose DECSET mouse/SGR encoding state, so the -// emulator mirrors it by scanning the raw byte stream; snapshots restore these -// modes on rehydrate. -export class TerminalPrivateModeTracker { - private scanTail = '' - mouseTrackingMode: MouseTrackingMode = 'none' - sgrMouseMode = false - sgrMousePixelsMode = false - - scan(data: string): void { - const input = this.scanTail + data - this.scanTail = this.extractScanTail(input) - // oxlint-disable-next-line no-control-regex -- terminal escape sequences require control chars - const privateModeRe = /\x1bc|\x1b\[\?([0-9;]+)([hl])|\x9b\?([0-9;]+)([hl])/g - let match: RegExpExecArray | null - while ((match = privateModeRe.exec(input)) !== null) { - if (match[0] === '\x1bc') { - this.mouseTrackingMode = 'none' - this.sgrMouseMode = false - this.sgrMousePixelsMode = false - continue - } - const params = match[1] ?? match[3] - const enabled = (match[2] ?? match[4]) === 'h' - for (const rawParam of params.split(';')) { - if (rawParam === '') { - continue - } - const param = Number(rawParam) - if (!Number.isInteger(param)) { - continue - } - if (param === 9) { - this.mouseTrackingMode = enabled ? 'x10' : 'none' - } - if (param === 1000) { - this.mouseTrackingMode = enabled ? 'vt200' : 'none' - } - if (param === 1002) { - this.mouseTrackingMode = enabled ? 'drag' : 'none' - } - if (param === 1003) { - this.mouseTrackingMode = enabled ? 'any' : 'none' - } - if (param === 1006) { - this.sgrMouseMode = enabled - this.sgrMousePixelsMode = false - } - if (param === 1016) { - this.sgrMouseMode = false - this.sgrMousePixelsMode = enabled - } - } - } - } - - private extractScanTail(input: string): string { - const start = Math.max(input.lastIndexOf('\x1b'), input.lastIndexOf('\x9b')) - if (start === -1) { - return '' - } - const tail = input.slice(start) - if (tail.length > PRIVATE_MODE_SCAN_TAIL_LIMIT) { - return '' - } - if (tail === '\x1b' || tail === '\x1b[' || tail === '\x9b') { - return tail - } - if (tail.startsWith('\x1b[?')) { - return this.isIncompleteParams(tail.slice(3)) ? tail : '' - } - if (tail.startsWith('\x9b?')) { - return this.isIncompleteParams(tail.slice(2)) ? tail : '' - } - return '' - } - - private isIncompleteParams(params: string): boolean { - return /^[0-9;]*$/.test(params) - } -} diff --git a/src/main/emulator/android/android-input-mapping.ts b/src/main/emulator/android/android-input-mapping.ts index 4805800f91d..d068e450e47 100644 --- a/src/main/emulator/android/android-input-mapping.ts +++ b/src/main/emulator/android/android-input-mapping.ts @@ -29,14 +29,6 @@ export function normalizedToDevicePixels( } } -export type AndroidHardwareButton = - | 'home' - | 'back' - | 'recents' - | 'power' - | 'volume_up' - | 'volume_down' - // Android KeyEvent KEYCODE_* values, including the common aliases agents use. const BUTTON_KEYCODES: Record = { home: 3, diff --git a/src/main/emulator/emulator-types.ts b/src/main/emulator/emulator-types.ts index d7bc31a26c5..f675d11bc66 100644 --- a/src/main/emulator/emulator-types.ts +++ b/src/main/emulator/emulator-types.ts @@ -14,9 +14,3 @@ export type EmulatorSessionInfo = { streamCodec?: EmulatorStreamCodec backend?: EmulatorBackendKind } - -export type EmulatorCliTarget = { - worktreeId?: string - deviceUdid?: string - emulatorId?: string // Orca-generated id from list (for stability, like browserPageId) -} diff --git a/src/main/git/git-username.ts b/src/main/git/git-username.ts index 320817b7eb7..da91361d0b8 100644 --- a/src/main/git/git-username.ts +++ b/src/main/git/git-username.ts @@ -219,14 +219,6 @@ async function getGhLoginOutcome(): Promise { return probe } -/** - * Resolve the `gh` CLI's GitHub login without ever blocking the caller for - * longer than the probe wall. Never rejects; unknown resolves to ''. - */ -export async function getGhLoginAsync(): Promise { - return (await getGhLoginOutcome()).login -} - async function readGitStdout(repoPath: string, args: string[]): Promise { try { const { stdout } = await gitExecFileAsync(args, { diff --git a/src/main/git/repo.ts b/src/main/git/repo.ts index ca1b4571c17..05d218e39db 100644 --- a/src/main/git/repo.ts +++ b/src/main/git/repo.ts @@ -911,14 +911,6 @@ async function listRemoteNames(path: string, options: LocalGitExecOptions = {}): } } -/** - * Parse `git for-each-ref --format=%(refname)%00%(refname:short)` stdout into a deduped list of short - * refs, dropping `/HEAD` pseudo-refs. Shared with the SSH branch in ipc/repos.ts so filtering can't drift. - */ -export function parseAndFilterSearchRefs(stdout: string, limit: number): string[] { - return parseAndFilterSearchRefDetails(stdout, limit).map((entry) => entry.refName) -} - export function parseAndFilterSearchRefDetails( stdout: string, limit: number, diff --git a/src/main/github/github-api-repository.ts b/src/main/github/github-api-repository.ts index 08461f849e9..3a61b9387da 100644 --- a/src/main/github/github-api-repository.ts +++ b/src/main/github/github-api-repository.ts @@ -65,11 +65,6 @@ export function _resetOriginGitHubApiRepositoryCache(): void { originRepoInFlight.clear() } -/** @internal - exposed for cache-bound tests only */ -export function _getOriginGitHubApiRepositoryCacheSize(): number { - return originRepoCache.size -} - function pruneOriginRepoCache(now: number): void { for (const [key, entry] of originRepoCache) { if (entry.expiresAt <= now) { @@ -296,10 +291,6 @@ export async function resolveGitHubApiRepository( return null } -export function isGitHubDotComRepository(repository: GitHubApiRepository): boolean { - return isDefaultGitHubHost(repository.host) -} - // Why: the gh runner host-qualifies argv from `options.host`, so every known // host must be carried through. Pinning github.com prevents a process-level // GH_HOST from silently redirecting an otherwise unambiguous API request. diff --git a/src/main/github/github-enterprise-repository.ts b/src/main/github/github-enterprise-repository.ts index fd4401e3f49..89f8bf7bbd7 100644 --- a/src/main/github/github-enterprise-repository.ts +++ b/src/main/github/github-enterprise-repository.ts @@ -49,11 +49,6 @@ export function _resetGitHubHostAuthCache(): void { hostAuthInFlight.clear() } -/** @internal - exposed for cache-bound tests only */ -export function _getGitHubHostAuthCacheSize(): number { - return hostAuthCache.size -} - function pruneHostAuthCache(now: number): void { for (const [key, entry] of hostAuthCache) { if (entry.expiresAt <= now) { diff --git a/src/main/github/project-view.ts b/src/main/github/project-view.ts index 2e53eff357c..db344de7133 100644 --- a/src/main/github/project-view.ts +++ b/src/main/github/project-view.ts @@ -54,7 +54,7 @@ import { import { githubProjectHost } from '../../shared/github-project-identity' // Re-export the public API so existing `./project-view` call sites keep working; the split is internal-only. -export { isValidOwnerSlug, isValidRepoSlug, isValidSlug } from './project-view/internals' +export { isValidOwnerSlug, isValidRepoSlug } from './project-view/internals' export { classifyProjectError } from './project-view/project-error-classification' export { updateProjectItemFieldValue, diff --git a/src/main/github/project-view/internals.ts b/src/main/github/project-view/internals.ts index 5952118ee4c..1dd794370c7 100644 --- a/src/main/github/project-view/internals.ts +++ b/src/main/github/project-view/internals.ts @@ -82,12 +82,6 @@ export function isValidRepoSlug(value: unknown): value is string { ) } -// Backwards-compatible alias for callers that don't distinguish owner vs repo. -// Prefer `isValidOwnerSlug` / `isValidRepoSlug` at new call sites. -export function isValidSlug(value: unknown): value is string { - return isValidOwnerSlug(value) || isValidRepoSlug(value) -} - export function assertSlug( value: unknown, field: 'owner' | 'repo' diff --git a/src/main/gitlab/gl-utils.ts b/src/main/gitlab/gl-utils.ts index 32b25ab0717..a8a7b5705a0 100644 --- a/src/main/gitlab/gl-utils.ts +++ b/src/main/gitlab/gl-utils.ts @@ -1,11 +1,6 @@ -import { execFile } from 'node:child_process' -import { promisify } from 'node:util' import { gitExecFileAsync, glabExecFileAsync } from '../git/runner' import { parseGlabApiResponse, type GlabApiResponse } from './glab-api-response' -// Why: legacy generic execFile wrapper - only used by callers that don't need -// WSL-aware routing. Repo-scoped callers should use the runner exports below. -export const execFileAsync = promisify(execFile) export { glabExecFileAsync, gitExecFileAsync } export { classifyGlabError, classifyListIssuesError } from './glab-error-classification' export { diff --git a/src/main/ipc/feedback-image-attachments.ts b/src/main/ipc/feedback-image-attachments.ts index f574a7129ab..361fe8b3fc0 100644 --- a/src/main/ipc/feedback-image-attachments.ts +++ b/src/main/ipc/feedback-image-attachments.ts @@ -25,10 +25,6 @@ export function isSupportedFeedbackImageContentType(contentType: string): boolea return Object.hasOwn(FEEDBACK_IMAGE_EXTENSIONS, contentType) } -export function getSupportedFeedbackImageContentTypes(): string[] { - return Object.keys(FEEDBACK_IMAGE_EXTENSIONS) -} - export function feedbackImageFilename(index: number, contentType: string): string { return `feedback-image-${index + 1}.${FEEDBACK_IMAGE_EXTENSIONS[contentType]}` } diff --git a/src/main/ipc/parcel-watcher-host-subscriptions.ts b/src/main/ipc/parcel-watcher-host-subscriptions.ts index 24f1803ee68..3dad4dee73c 100644 --- a/src/main/ipc/parcel-watcher-host-subscriptions.ts +++ b/src/main/ipc/parcel-watcher-host-subscriptions.ts @@ -117,21 +117,6 @@ export function resolvePendingWatcherUnsubscribes( pendingUnsubscribes.clear() } -export function disposeWatcherSupervisorSubscriptions( - records: Map, - pendingUnsubscribes: Map void>, - cancelledSubscribesAwaitingChild: Set, - error: Error -): void { - for (const record of records.values()) { - resetPendingSubscribeAttempt(record) - takePendingSubscribe(record)?.reject(error) - } - resolvePendingWatcherUnsubscribes(pendingUnsubscribes) - cancelledSubscribesAwaitingChild.clear() - records.clear() -} - export type CreateHostWatcherSubscriptionOptions = { record: WatcherProcessSubscriptionRecord records: Map diff --git a/src/main/ipc/parcel-watcher-process.ts b/src/main/ipc/parcel-watcher-process.ts index 978edb21c6b..223fed564f8 100644 --- a/src/main/ipc/parcel-watcher-process.ts +++ b/src/main/ipc/parcel-watcher-process.ts @@ -21,9 +21,6 @@ export type { } from './parcel-watcher-process-protocol' const sharedWatcherProcessSupervisor = new WatcherProcessSupervisor() -// Why: the canary pauses during legitimate crawls, so production callers need -// a separate liveness fuse once a child reports that it owns native setup. -export const WATCHER_PROCESS_SUBSCRIBE_TIMEOUT_MS = 60_000 // Why: healthy roots share one child; only fault quarantine scales to four, // containing a failed shard without paying that RSS cost during normal use. const runtimeWatcherProcessPool = new RuntimeWatcherProcessPool() diff --git a/src/main/ipc/runtime-environment-request-connections.ts b/src/main/ipc/runtime-environment-request-connections.ts index 361264d917e..946a0d30cf8 100644 --- a/src/main/ipc/runtime-environment-request-connections.ts +++ b/src/main/ipc/runtime-environment-request-connections.ts @@ -47,15 +47,6 @@ export function closeRemoteRuntimeRequestConnection(environmentId: string): void closeRemoteRuntimeSharedControlConnection(environmentId) } -export function closeAllRemoteRuntimeRequestConnections(): void { - for (const environmentId of Array.from(requestConnections.keys())) { - closeRemoteRuntimeRequestConnection(environmentId) - } - for (const environmentId of Array.from(sharedControlConnections.keys())) { - closeRemoteRuntimeSharedControlConnection(environmentId) - } -} - export function sendRemoteRuntimeSharedControlRequest( environmentId: string, pairing: PairingOffer, diff --git a/src/main/ipc/worktree-change-invalidators.ts b/src/main/ipc/worktree-change-invalidators.ts index a43657743b4..156ce0f722c 100644 --- a/src/main/ipc/worktree-change-invalidators.ts +++ b/src/main/ipc/worktree-change-invalidators.ts @@ -19,7 +19,3 @@ export function runWorktreeChangeInvalidators(repoId: string): void { } } } - -export function __resetWorktreeChangeInvalidatorsForTests(): void { - worktreeChangeInvalidators.clear() -} diff --git a/src/main/observability/index.ts b/src/main/observability/index.ts index 791653d272d..f891da51418 100644 --- a/src/main/observability/index.ts +++ b/src/main/observability/index.ts @@ -167,10 +167,6 @@ export async function shutdownObservability(): Promise { consent = null } -export function getObservabilityConsent(): ObservabilityConsent | null { - return consent -} - // ── Bundle / trace-folder operations exposed to IPC ───────────────────── export type DiagnosticsStatus = { diff --git a/src/main/observability/instrumentation.ts b/src/main/observability/instrumentation.ts index 3e944b23847..d4ab5d4e497 100644 --- a/src/main/observability/instrumentation.ts +++ b/src/main/observability/instrumentation.ts @@ -228,32 +228,6 @@ export async function withWorktreeRemoveStageSpan( }) } -export type PtySpanArgs = { - readonly stage: 'spawn' | 'exit' | 'recover' - readonly shell?: string - readonly cwd?: string -} - -/** Wrap a PTY-lifecycle event in a `pty.` span. The lifecycle is - * long-lived; callers typically use `startSpan` directly for the live - * session and call `withPtySpan` only for the spawn/exit moments. */ -export async function withPtySpan(meta: PtySpanArgs, fn: () => Promise | T): Promise { - return withSpan( - `pty.${meta.stage}`, - async (span) => { - span.setAttribute('pty.stage', meta.stage) - if (meta.shell) { - span.setAttribute('pty.shell', meta.shell) - } - if (meta.cwd) { - span.setAttribute('cwd', meta.cwd) - } - return await fn() - }, - { attributes: { kind: 'pty' } } - ) -} - export type UpdaterSpanArgs = { readonly stage: 'check' | 'download' | 'install' } diff --git a/src/main/observability/redactor.ts b/src/main/observability/redactor.ts index 173382bde58..cd5570f8577 100644 --- a/src/main/observability/redactor.ts +++ b/src/main/observability/redactor.ts @@ -234,14 +234,3 @@ export function redactSpan(span: RedactableSpan, mode: RedactorMode = 'client'): exit } } - -// Test-only introspection: lets tests verify the rule set without re-deriving it. - -export const _internalsForTests = { - PROVIDER_PATTERNS, - CLIENT_ATTR_BLOCKLIST, - SERVER_ATTR_BLOCKLIST_EXTRA, - LABELED_KV, - URL_USERINFO, - ENV_LINE -} diff --git a/src/main/pi/prefill-extension-source.ts b/src/main/pi/prefill-extension-source.ts index 054502c1c39..910c8cb796b 100644 --- a/src/main/pi/prefill-extension-source.ts +++ b/src/main/pi/prefill-extension-source.ts @@ -10,15 +10,6 @@ const PREFILL_ENV_VAR_BY_KIND: Record = { omp: 'ORCA_OMP_PREFILL' } -/** Pi's prefill env var. Exported for callers that need the literal name - * (renderer draft-launch plan builder, tests). OMP callers should read - * `ORCA_OMP_PREFILL_ENV_VAR` instead. */ -export const ORCA_PI_PREFILL_ENV_VAR = PREFILL_ENV_VAR_BY_KIND.pi - -/** OMP's prefill env var. Mirrors `ORCA_PI_PREFILL_ENV_VAR` for OMP launches - * so renderer plans and shell-ready restore lines can stay agent-scoped. */ -export const ORCA_OMP_PREFILL_ENV_VAR = PREFILL_ENV_VAR_BY_KIND.omp - export function getPiPrefillExtensionSource(kind: PiAgentKind): string { const envVar = PREFILL_ENV_VAR_BY_KIND[kind] return [ diff --git a/src/main/pi/titlebar-extension-service.ts b/src/main/pi/titlebar-extension-service.ts index 538d0a0be9d..66f491925ed 100644 --- a/src/main/pi/titlebar-extension-service.ts +++ b/src/main/pi/titlebar-extension-service.ts @@ -11,7 +11,6 @@ import { ORCA_PI_PREFILL_EXTENSION_FILE, getPiPrefillExtensionSource } from './prefill-extension-source' -export { ORCA_OMP_PREFILL_ENV_VAR, ORCA_PI_PREFILL_ENV_VAR } from './prefill-extension-source' import { ORCA_PI_EXTENSION_FILE, getPiTitlebarExtensionSource } from './titlebar-extension-source' import { isSafeDescendCandidate as sharedIsSafeDescendCandidate, diff --git a/src/main/plugins/plugin-enablement.ts b/src/main/plugins/plugin-enablement.ts index 44349ef087b..e81a8c7e522 100644 --- a/src/main/plugins/plugin-enablement.ts +++ b/src/main/plugins/plugin-enablement.ts @@ -14,8 +14,6 @@ import { verifyInstructionalPluginContent } from './plugin-instructional-content * IPC handlers and the headless RPC methods both route through here. */ -export type PluginConsentDecision = PluginConsentRequest['decision'] - /** Records the user's consent-dialog answer. Approving stores the CURRENT * consent fingerprint and clears any disable; declining disables so the plugin * never re-prompts on later launches. */ diff --git a/src/main/providers/pty-process-list-admission.ts b/src/main/providers/pty-process-list-admission.ts index f65a86aacea..bca3bf4fa18 100644 --- a/src/main/providers/pty-process-list-admission.ts +++ b/src/main/providers/pty-process-list-admission.ts @@ -145,17 +145,3 @@ export async function visitPtyProcessListingsInBatches( visit(listing.entry, listing.processes) } } - -export async function collectPtyProcessListings( - sources: Iterable, - load: (source: T) => Promise -): Promise { - const admission = new PtyProcessListAdmission() - const processes: PtyProcessInfo[] = [] - await visitPtyProcessListingsInBatches(sources, load, (_source, listing) => { - for (const process of listing) { - processes.push(admission.admit(process)) - } - }) - return processes -} diff --git a/src/main/providers/types.ts b/src/main/providers/types.ts index a36b222f5e4..23c36859a1f 100644 --- a/src/main/providers/types.ts +++ b/src/main/providers/types.ts @@ -1,9 +1,6 @@ // Aggregate provider contract surface. The three per-domain contracts live in // their own files; this barrel keeps every historical `providers/types` import -// path working and owns the registry that ties them together. -import type { IPtyProvider } from './pty-provider-contract' -import type { IFilesystemProvider } from './filesystem-provider-contract' -import type { IGitProvider } from './git-provider-contract' +// path working. // ─── PTY Provider ─────────────────────────────────────────────────── @@ -31,12 +28,3 @@ export type { // ─── Git Provider ─────────────────────────────────────────────────── export type { GitProviderStatusOptions, IGitProvider } from './git-provider-contract' - -// ─── Provider Registry ────────────────────────────────────────────── - -/** Routes operations by connectionId; null/undefined selects the local provider. */ -export type IProviderRegistry = { - getPtyProvider(connectionId: string | null | undefined): IPtyProvider - getFilesystemProvider(connectionId: string | null | undefined): IFilesystemProvider - getGitProvider(connectionId: string | null | undefined): IGitProvider -} diff --git a/src/main/rate-limits/grok-auth.ts b/src/main/rate-limits/grok-auth.ts index e055c022975..950ab1d3678 100644 --- a/src/main/rate-limits/grok-auth.ts +++ b/src/main/rate-limits/grok-auth.ts @@ -130,10 +130,6 @@ export function readGrokAuthSession(): GrokAuthReadResult { } } -export function hasGrokAuthSession(): boolean { - return readGrokAuthSession().status === 'ok' -} - const TOKEN_SKEW_MS = 5 * 60 * 1000 export function isGrokAccessTokenFresh(session: GrokAuthSession): boolean { diff --git a/src/main/runtime/orca-runtime-emulator.ts b/src/main/runtime/orca-runtime-emulator.ts index b1bcbe5c689..ac67464a533 100644 --- a/src/main/runtime/orca-runtime-emulator.ts +++ b/src/main/runtime/orca-runtime-emulator.ts @@ -321,21 +321,3 @@ export class RuntimeEmulatorCommands { return this.emulatorExec(params) } } - -// Singleton accessor pattern (mirror requireAgentBrowserBridge). -let emulatorBridgeInstance: EmulatorBridge | null = null - -export function setEmulatorBridge(bridge: EmulatorBridge | null): void { - emulatorBridgeInstance = bridge -} - -export function getEmulatorBridge(): EmulatorBridge | null { - return emulatorBridgeInstance -} - -export function requireEmulatorBridge(): EmulatorBridge { - if (!emulatorBridgeInstance) { - throw new EmulatorError('emulator_no_active', 'Emulator bridge not initialized') - } - return emulatorBridgeInstance -} diff --git a/src/main/runtime/orca-runtime.ts b/src/main/runtime/orca-runtime.ts index 698fd80f564..90792d63693 100644 --- a/src/main/runtime/orca-runtime.ts +++ b/src/main/runtime/orca-runtime.ts @@ -512,7 +512,7 @@ import { advanceTerminalTopologyRevision, hasHostAuthoritativeTerminalMembership } from './workspace-session-terminal-membership-authority' -import { RuntimeEmulatorCommands, setEmulatorBridge } from './orca-runtime-emulator' +import { RuntimeEmulatorCommands } from './orca-runtime-emulator' import type { EmulatorBridge } from '../emulator/emulator-bridge' import { RuntimeFileCommands } from './orca-runtime-files' import { RuntimeGitCommands } from './orca-runtime-git' @@ -5167,7 +5167,6 @@ export class OrcaRuntimeService { setEmulatorBridge(bridge: EmulatorBridge | null): void { this.emulatorBridge = bridge - setEmulatorBridge(bridge) } getEmulatorBridge(): EmulatorBridge | null { diff --git a/src/main/runtime/orchestration/groups.ts b/src/main/runtime/orchestration/groups.ts index 5d24f68a107..6f31f5df261 100644 --- a/src/main/runtime/orchestration/groups.ts +++ b/src/main/runtime/orchestration/groups.ts @@ -20,8 +20,6 @@ const AGENT_NAME_GROUPS = [ type AgentNameGroup = (typeof AGENT_NAME_GROUPS)[number] -export type GroupAddress = '@all' | '@idle' | `@${AgentNameGroup}` | `@worktree:${string}` - export function isGroupAddress(to: string): boolean { return to.startsWith('@') } diff --git a/src/main/runtime/rpc/schemas.ts b/src/main/runtime/rpc/schemas.ts index 5324695c090..fb7b09d8ceb 100644 --- a/src/main/runtime/rpc/schemas.ts +++ b/src/main/runtime/rpc/schemas.ts @@ -68,8 +68,6 @@ export const BrowserTarget = z.object({ page: OptionalString }) -export type BrowserTargetInput = z.infer - export function requiredString(message: string) { return z .unknown() diff --git a/src/main/shell-ready-marker-scanner.ts b/src/main/shell-ready-marker-scanner.ts index d0633fa1393..0e6250e1c4e 100644 --- a/src/main/shell-ready-marker-scanner.ts +++ b/src/main/shell-ready-marker-scanner.ts @@ -1,5 +1,4 @@ export const SHELL_READY_MARKER_PREFIX = '\x1b]777;orca-shell-ready' -export const SHELL_READY_MARKER = `${SHELL_READY_MARKER_PREFIX}\x07` export type ShellReadyScanState = { matchPos: number diff --git a/src/main/ssh/relay-protocol.ts b/src/main/ssh/relay-protocol.ts index 4a60237874a..4c5e258b01a 100644 --- a/src/main/ssh/relay-protocol.ts +++ b/src/main/ssh/relay-protocol.ts @@ -2,7 +2,6 @@ // 13-byte framing header matching VS Code's PersistentProtocol wire format. // See design-ssh-support.md § JSON-RPC Protocol Specification. -import { DEFAULT_SSH_RELAY_GRACE_PERIOD_SECONDS } from '../../shared/ssh-types' import { FrameDecoder, FrameDecoderContinuationError, @@ -41,9 +40,6 @@ export const MessageType = { export const KEEPALIVE_SEND_MS = 5_000 export const TIMEOUT_MS = 20_000 -/** Reconnection grace period (default, overridable by relay --grace-time). */ -export const DEFAULT_GRACE_TIME_MS = DEFAULT_SSH_RELAY_GRACE_PERIOD_SECONDS * 1000 - // ── Relay error codes ─────────────────────────────────────────────── export const RelayErrorCode = { diff --git a/src/main/ssh/sftp-namespace-resolution.ts b/src/main/ssh/sftp-namespace-resolution.ts index 5ee329a40c4..dd019a84d88 100644 --- a/src/main/ssh/sftp-namespace-resolution.ts +++ b/src/main/ssh/sftp-namespace-resolution.ts @@ -116,8 +116,8 @@ function realpathSftp(sftp: SFTPWrapper, remotePath: string): Promise { }) } -// Why: sftpPathExists collapses "absent" and "could not tell" into one boolean; -// namespace selection must never treat an inconclusive probe as absence. +// Why: namespace selection must never treat an inconclusive lstat as absence, +// so the probe reports "unknown" rather than collapsing to a boolean. function probeMarkerPath(sftp: SFTPWrapper, remotePath: string): Promise { return new Promise((resolve) => { sftp.lstat(remotePath, (err) => { diff --git a/src/main/ssh/sftp-upload.ts b/src/main/ssh/sftp-upload.ts index e962c7463fa..6344a7c1457 100644 --- a/src/main/ssh/sftp-upload.ts +++ b/src/main/ssh/sftp-upload.ts @@ -282,25 +282,3 @@ async function assertLocalUploadPathInsideRoot( throw new Error(`Path escaped upload root: ${candidatePath}`) } } - -/** - * Check whether a path exists on the remote via SFTP lstat. - * Returns true if the path exists (file, directory, or symlink). - */ -export function sftpPathExists(sftp: SFTPWrapper, remotePath: string): Promise { - return new Promise((resolve, reject) => { - sftp.lstat(remotePath, (err) => { - if (!err) { - resolve(true) - return - } - // Why: SFTP status code 2 = SSH_FX_NO_SUCH_FILE — the path does not - // exist, which is the expected "no collision" signal for deconfliction. - if ((err as { code?: number }).code === 2) { - resolve(false) - return - } - reject(err) - }) - }) -} diff --git a/src/main/ssh/ssh-pty-consumer-session.ts b/src/main/ssh/ssh-pty-consumer-session.ts index 4bfebc6360f..8bb272d7273 100644 --- a/src/main/ssh/ssh-pty-consumer-session.ts +++ b/src/main/ssh/ssh-pty-consumer-session.ts @@ -2,7 +2,6 @@ import { PTY_CONSUMER_SESSION_PROTOCOL_VERSION, type PtyConsumerSessionGrant } from '../../shared/pty-consumer-session' -import { DEFAULT_PTY_SOURCE_WINDOW_SU } from '../../shared/pty-source-credit-contract' import type { SshChannelMultiplexer } from './ssh-channel-multiplexer' export const SSH_PTY_OPEN_CLIENT_METHOD = 'pty.openClient' @@ -140,5 +139,3 @@ export async function openSshPtyConsumerSession( : {}) } } - -export const SSH_PTY_SOURCE_WINDOW_SU = DEFAULT_PTY_SOURCE_WINDOW_SU diff --git a/src/main/ssh/ssh-relay-session-managed-hooks.test.ts b/src/main/ssh/ssh-relay-session-managed-hooks.test.ts index 95492aa3a3a..b0acfeb29e2 100644 --- a/src/main/ssh/ssh-relay-session-managed-hooks.test.ts +++ b/src/main/ssh/ssh-relay-session-managed-hooks.test.ts @@ -15,7 +15,6 @@ const { muxRequestMock, openConsumerSessionMock } = vi.hoisted(() => ({ vi.mock('./ssh-relay-deploy', () => ({ deployAndLaunchRelay: vi.fn() })) vi.mock('./ssh-relay-deploy-helpers', () => ({ execCommand: vi.fn().mockResolvedValue('') })) vi.mock('./ssh-pty-consumer-session', () => ({ - SSH_PTY_SOURCE_WINDOW_SU: 256 * 1024, openSshPtyConsumerSession: openConsumerSessionMock })) vi.mock('./ssh-channel-multiplexer', () => ({ diff --git a/src/main/ssh/ssh-relay-session.test.ts b/src/main/ssh/ssh-relay-session.test.ts index eb81cda4cb1..570fca21fd4 100644 --- a/src/main/ssh/ssh-relay-session.test.ts +++ b/src/main/ssh/ssh-relay-session.test.ts @@ -21,7 +21,6 @@ vi.mock('./ssh-relay-deploy', () => ({ })) vi.mock('./ssh-pty-consumer-session', () => ({ - SSH_PTY_SOURCE_WINDOW_SU: 256 * 1024, openSshPtyConsumerSession: openConsumerSessionMock })) diff --git a/src/main/system-fonts.ts b/src/main/system-fonts.ts index 15ff9c28bde..20a8764548c 100644 --- a/src/main/system-fonts.ts +++ b/src/main/system-fonts.ts @@ -31,10 +31,6 @@ export async function listSystemFontFamilies(): Promise { return fontsPromise } -export function warmSystemFontFamilies(): void { - void listSystemFontFamilies() -} - function loadSystemFontFamilies(): Promise { if (process.platform === 'darwin') { return listMacFonts() diff --git a/src/main/telemetry/client.ts b/src/main/telemetry/client.ts index d1f2b2fa057..93bddaaab81 100644 --- a/src/main/telemetry/client.ts +++ b/src/main/telemetry/client.ts @@ -329,10 +329,6 @@ export function _setShuttingDownForTests(value: boolean): void { shuttingDown = value } -export function _getSessionIdForTests(): string | null { - return sessionId -} - export function _enableTransportForTests(enabled: boolean): void { testTransportEnabled = enabled } diff --git a/src/relay/fs-handler-file-read.ts b/src/relay/fs-handler-file-read.ts index 14672457cc6..4a6f663484d 100644 --- a/src/relay/fs-handler-file-read.ts +++ b/src/relay/fs-handler-file-read.ts @@ -2,12 +2,7 @@ import { open, readFile, stat } from 'node:fs/promises' import type { FileHandle } from 'node:fs/promises' import { extname } from 'node:path' import type { RelayDispatcher, RequestContext } from './dispatcher' -import { - MAX_CONCURRENT_STREAMS, - STREAM_ACK_WINDOW_CHUNKS, - STREAM_CHUNK_SIZE, - RelayErrorCode -} from './protocol' +import { MAX_CONCURRENT_STREAMS, STREAM_ACK_WINDOW_CHUNKS, STREAM_CHUNK_SIZE } from './protocol' import { TooManyStreamsError, type RelayStreamRegistry } from './fs-stream-registry' import { BINARY_PROBE_BYTES, @@ -360,7 +355,3 @@ async function readFullStreamChunk( } return totalRead } - -export function isTooManyStreamsError(err: unknown): err is TooManyStreamsError { - return err instanceof Error && (err as { code?: number }).code === RelayErrorCode.TooManyStreams -} diff --git a/src/renderer/src/components/automations/automation-page-parts.tsx b/src/renderer/src/components/automations/automation-page-parts.tsx index 7d96be1efa3..9b38cac5fc1 100644 --- a/src/renderer/src/components/automations/automation-page-parts.tsx +++ b/src/renderer/src/components/automations/automation-page-parts.tsx @@ -107,12 +107,3 @@ export function Field({ ) } - -export function Metric({ label, value }: { label: string; value: string }): React.JSX.Element { - return ( -
-
{label}
-
{value}
-
- ) -} diff --git a/src/renderer/src/components/browser-pane/browser-automation-visibility.ts b/src/renderer/src/components/browser-pane/browser-automation-visibility.ts index d18c331c801..6b092f2c950 100644 --- a/src/renderer/src/components/browser-pane/browser-automation-visibility.ts +++ b/src/renderer/src/components/browser-pane/browser-automation-visibility.ts @@ -72,11 +72,6 @@ export function isBrowserAutomationVisible(browserPageId: string): boolean { return (leaseCountsByPageId.get(browserPageId) ?? 0) > 0 } -export function useBrowserAutomationVisibility(browserPageId: string | null | undefined): boolean { - useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot) - return Boolean(browserPageId && isBrowserAutomationVisible(browserPageId)) -} - export function useBrowserAutomationVisibilityForAny( browserPageIds: readonly (string | null | undefined)[] ): boolean { diff --git a/src/renderer/src/components/browser-pane/browser-page-zoom.ts b/src/renderer/src/components/browser-pane/browser-page-zoom.ts index 4a4f3924942..2a5233c5cf1 100644 --- a/src/renderer/src/components/browser-pane/browser-page-zoom.ts +++ b/src/renderer/src/components/browser-pane/browser-page-zoom.ts @@ -107,14 +107,6 @@ export function getBrowserPageZoomIndicatorState({ } } -export function dispatchBrowserPageZoomEvent(detail: BrowserPageZoomEventDetail): void { - window.dispatchEvent( - new CustomEvent(ORCA_BROWSER_PAGE_ZOOM_EVENT, { - detail - }) - ) -} - export function addBrowserPageZoomEventListener( callback: (detail: BrowserPageZoomEventDetail) => void ): () => void { diff --git a/src/renderer/src/components/dashboard/useDashboardData.ts b/src/renderer/src/components/dashboard/useDashboardData.ts index 71632ac93e6..65c57ab2f4e 100644 --- a/src/renderer/src/components/dashboard/useDashboardData.ts +++ b/src/renderer/src/components/dashboard/useDashboardData.ts @@ -1,18 +1,9 @@ -import { useMemo } from 'react' -import { useAppStore } from '@/store' -import { isExplicitAgentStatusFresh } from '@/lib/agent-status' -import { - AGENT_STATUS_STALE_AFTER_MS, - type AgentStatusEntry, - type AgentStatusState, - type AgentType, - type MigrationUnsupportedPtyEntry +import type { + AgentStatusEntry, + AgentStatusState, + AgentType } from '../../../../shared/agent-status-types' -import type { Repo, Worktree, TerminalTab } from '../../../../shared/types' -import { parsePaneKey } from '../../../../shared/stable-pane-id' -import { migrationUnsupportedToAgentStatusEntry } from '@/lib/migration-unsupported-agent-entry' - -// ─── Shared data types ──────────────────────────────────────────────────────── +import type { TerminalTab } from '../../../../shared/types' export type DashboardAgentRow = { /** Row identity. For 'subagent' rows this is a synthetic key (the child has @@ -37,171 +28,3 @@ export type DashboardAgentRow = { childCount: number } } - -// Why: the shape here is deliberately minimal. The per-card rendering pipeline -// is separate (WorktreeCardAgents + useWorktreeAgentRows read retained entries -// directly from the store). -export type DashboardWorktreeCard = { - repo: Repo - worktree: Worktree - agents: DashboardAgentRow[] -} - -export type DashboardProjectGroup = { - repo: Repo - worktrees: DashboardWorktreeCard[] -} - -// ─── Helpers ────────────────────────────────────────────────────────────────── - -// Why: only surface agents that have reported state via a hook. A tab hosting -// a shell, a REPL before its first turn, or an agent we have no hook -// integration for will have no entry here — and that's correct. Agent rows -// represent *agent work in progress*, not "which terminals might contain an -// agent". -function buildAgentRowsForWorktree( - worktreeId: string, - tabsByWorktree: Record, - entriesByTabId: Map, - now: number -): DashboardAgentRow[] { - const tabs = tabsByWorktree[worktreeId] ?? [] - const rows: DashboardAgentRow[] = [] - - for (const tab of tabs) { - const explicitEntries = entriesByTabId.get(tab.id) ?? [] - for (const entry of explicitEntries) { - // Why: decay stale working/blocked/waiting entries to 'idle' when the hook - // stream has gone silent past AGENT_STATUS_STALE_AFTER_MS (30 min TTL). - // Without this, an agent process that exited without sending a final - // update would remain "working" forever — the Active/Blocked filters and - // the sidebar's running-agents count would mislead the user into chasing - // dead work. `done` is terminal and must NOT decay to idle: retention - // (collectRetainedAgentsOnDisappear) only retains rows whose prev state - // was 'done', so decaying a stale done → idle would silently drop the - // completion signal when the entry later disappears. - const isFresh = isExplicitAgentStatusFresh(entry, now, AGENT_STATUS_STALE_AFTER_MS) - const shouldDecay = - !isFresh && - (entry.state === 'working' || entry.state === 'blocked' || entry.state === 'waiting') - rows.push({ - paneKey: entry.paneKey, - entry, - tab, - agentType: entry.agentType ?? 'unknown', - rowSource: 'live', - state: shouldDecay ? 'idle' : entry.state, - // Why: the oldest stateHistory entry's startedAt is the agent's original - // "first seen" timestamp. When history is empty the entry has never - // transitioned state, so stateStartedAt (the moment the current — and - // only — state began) is the true first-seen timestamp. Do NOT fall back - // to updatedAt: it advances on every tool/prompt ping within the same - // state, which would corrupt oldest-first ordering and the "started … - // ago" display for long-running agents between state transitions. See - // agent-status.ts (stateStartedAt carry-forward on same-state pings). - startedAt: entry.stateHistory[0]?.startedAt ?? entry.stateStartedAt - }) - } - } - - return rows -} - -function buildDashboardData( - repos: Repo[], - worktreesByRepo: Record, - tabsByWorktree: Record, - agentStatusByPaneKey: Record, - migrationUnsupportedByPtyId: Record, - now: number -): DashboardProjectGroup[] { - // Why: build a tabId -> entries index once per computation instead of - // re-scanning every agent status entry inside the per-tab loop. paneKey is - // formatted as `${tabId}:${leafId}`; parsePaneKey also drops legacy numeric - // suffixes so stale rows do not remain routable after pane replay. - const entriesByTabId = new Map() - for (const [paneKey, entry] of Object.entries(agentStatusByPaneKey)) { - const parsed = parsePaneKey(paneKey) - if (!parsed) { - continue - } - const bucket = entriesByTabId.get(parsed.tabId) - if (bucket) { - bucket.push(entry) - } else { - entriesByTabId.set(parsed.tabId, [entry]) - } - } - for (const unsupported of Object.values(migrationUnsupportedByPtyId)) { - const entry = migrationUnsupportedToAgentStatusEntry(unsupported) - if (!entry) { - continue - } - const parsed = parsePaneKey(entry.paneKey) - if (!parsed) { - continue - } - const bucket = entriesByTabId.get(parsed.tabId) - if (bucket) { - bucket.push(entry) - } else { - entriesByTabId.set(parsed.tabId, [entry]) - } - } - - return repos.map((repo) => { - const worktrees = (worktreesByRepo[repo.id] ?? []) - .filter((w) => !w.isArchived) - .map((worktree) => { - const agents = buildAgentRowsForWorktree(worktree.id, tabsByWorktree, entriesByTabId, now) - return { repo, worktree, agents } satisfies DashboardWorktreeCard - }) - - return { repo, worktrees } satisfies DashboardProjectGroup - }) -} - -// ─── Hook ───────────────────────────────────────────────────────────────────── - -/** - * Cross-worktree aggregate of live agent rows. - * - * Not used to render anything directly — the inline list reads its own - * worktree-scoped slice via useWorktreeAgentRows. - */ -export function useDashboardData(): DashboardProjectGroup[] { - const repos = useAppStore((s) => s.repos) - const worktreesByRepo = useAppStore((s) => s.worktreesByRepo) - const tabsByWorktree = useAppStore((s) => s.tabsByWorktree) - const agentStatusByPaneKey = useAppStore((s) => s.agentStatusByPaneKey) - const migrationUnsupportedByPtyId = useAppStore((s) => s.migrationUnsupportedByPtyId) - // Why: agentStatusEpoch is included in the dependency array (but not in the - // computation itself) so the memo recomputes when freshness boundaries expire, - // even if no new PTY data arrives. - const agentStatusEpoch = useAppStore((s) => s.agentStatusEpoch) - - return useMemo( - // Why: Date.now() is read inside the memo (not as a dep) so stale-decay - // recalculates whenever agentStatusEpoch ticks. The epoch bumps when the - // freshness boundary crosses, driving re-evaluation without coupling to - // wall-clock time directly. - () => - buildDashboardData( - repos, - worktreesByRepo, - tabsByWorktree, - agentStatusByPaneKey, - migrationUnsupportedByPtyId, - Date.now() - ), - // eslint-disable-next-line react-hooks/exhaustive-deps - [ - repos, - worktreesByRepo, - tabsByWorktree, - agentStatusByPaneKey, - migrationUnsupportedByPtyId, - agentStatusEpoch - ] - ) -} diff --git a/src/renderer/src/components/editor/NotesSendMenu.test.tsx b/src/renderer/src/components/editor/NotesSendMenu.test.tsx index d977ec5ae9b..a176594bc80 100644 --- a/src/renderer/src/components/editor/NotesSendMenu.test.tsx +++ b/src/renderer/src/components/editor/NotesSendMenu.test.tsx @@ -134,8 +134,7 @@ vi.mock('./ReviewNotesSendMenuContent', () => ({ vi.mock('@/lib/active-agent-note-send', () => ({ activeAgentNotesSendFailureMessage: (status: string) => status, getActiveTerminalNoteTarget: () => null, - sendNotesToActiveAgentSession: vi.fn(), - useCanSendNotesToActiveTerminal: () => false + sendNotesToActiveAgentSession: vi.fn() })) vi.mock('sonner', () => ({ diff --git a/src/renderer/src/components/editor/ReviewNotesSendMenuContent.test.tsx b/src/renderer/src/components/editor/ReviewNotesSendMenuContent.test.tsx index 2007b142702..92e7e21da80 100644 --- a/src/renderer/src/components/editor/ReviewNotesSendMenuContent.test.tsx +++ b/src/renderer/src/components/editor/ReviewNotesSendMenuContent.test.tsx @@ -91,8 +91,7 @@ vi.mock('@/lib/active-agent-note-send', () => ({ status: string, options: { explicitTarget?: boolean } = {} ) => (options.explicitTarget ? `selected:${status}` : status), - sendNotesToActiveAgentSession: harness.sendNotesToActiveAgentSession, - useCanSendNotesToActiveTerminal: () => true + sendNotesToActiveAgentSession: harness.sendNotesToActiveAgentSession })) vi.mock('@/lib/notes-send-agent-targets', () => ({ diff --git a/src/renderer/src/components/editor/markdown-round-trip.ts b/src/renderer/src/components/editor/markdown-round-trip.ts index fcfa39efdc0..2655ca225b3 100644 --- a/src/renderer/src/components/editor/markdown-round-trip.ts +++ b/src/renderer/src/components/editor/markdown-round-trip.ts @@ -7,11 +7,6 @@ import { createRichMarkdownHtmlSuperscriptLinkContext } from './rich-markdown-ht const roundTripCache = new Map() const MAX_CACHE_ENTRIES = 20 -export function canRoundTripRichMarkdown(content: string): boolean { - const output = getRichMarkdownRoundTripOutput(content) - return output !== null && normalizeMarkdown(content) === normalizeMarkdown(output) -} - export function getRichMarkdownRoundTripOutput(content: string): string | null { const cached = roundTripCache.get(content) if (cached !== undefined) { @@ -59,7 +54,3 @@ export function getRichMarkdownRoundTripOutput(content: string): string | null { return output } - -function normalizeMarkdown(content: string): string { - return content.replace(/\r\n/g, '\n').trimEnd() -} diff --git a/src/renderer/src/components/emulator-pane/emulator-keyboard-paste.ts b/src/renderer/src/components/emulator-pane/emulator-keyboard-paste.ts index ad6a371b334..dd641a83a52 100644 --- a/src/renderer/src/components/emulator-pane/emulator-keyboard-paste.ts +++ b/src/renderer/src/components/emulator-pane/emulator-keyboard-paste.ts @@ -57,10 +57,6 @@ export type PasteTextIntoEmulatorKeyboardOptions = { text: string } -export function getEmulatorKeyboardPasteByteLength(text: string): number { - return measureClipboardTextByteLength(text).byteLength -} - export function buildEmulatorKeyboardPastePlan( text: string, options: { diff --git a/src/renderer/src/components/emulator-pane/emulator-pane-types.ts b/src/renderer/src/components/emulator-pane/emulator-pane-types.ts index bd2b4589f48..80da92fc471 100644 --- a/src/renderer/src/components/emulator-pane/emulator-pane-types.ts +++ b/src/renderer/src/components/emulator-pane/emulator-pane-types.ts @@ -70,5 +70,3 @@ export function pickDefaultDevice(devices: SimulatorDeviceRow[]): SimulatorDevic null ) } - -export const isMacOs = typeof navigator !== 'undefined' && navigator.userAgent.includes('Mac') diff --git a/src/renderer/src/components/github-project/column-widths.ts b/src/renderer/src/components/github-project/column-widths.ts index 678de5de084..68106fb451b 100644 --- a/src/renderer/src/components/github-project/column-widths.ts +++ b/src/renderer/src/components/github-project/column-widths.ts @@ -70,17 +70,3 @@ export function resolveWidth( } return defaultWidthFor(field) } - -export function buildGridTemplate( - fields: GitHubProjectField[], - widths: Readonly> -): string { - // Why: emit `minmax(px, fr)` so the grid honors the - // user's relative weights AND fits within the container — pixel - // widths would let a wide TITLE blow past the parent and push the - // surrounding chrome out. The minmax floor is what stops a column - // from collapsing to zero when its weight is small. - const cols = fields.map((f) => `minmax(${MIN_COLUMN_WIDTH}px, ${resolveWidth(f, widths)}fr)`) - cols.push(`${ACTION_COLUMN_WIDTH}px`) - return cols.join(' ') -} diff --git a/src/renderer/src/components/github/github-issue-comment-helpers.ts b/src/renderer/src/components/github/github-issue-comment-helpers.ts index ab6c3ad4bfc..01f40093db5 100644 --- a/src/renderer/src/components/github/github-issue-comment-helpers.ts +++ b/src/renderer/src/components/github/github-issue-comment-helpers.ts @@ -1,80 +1,3 @@ -import { useAppStore } from '@/store' -import { callRuntimeRpc, getActiveRuntimeTarget } from '@/runtime/runtime-rpc-client' -import type { GitHubIssueCloseReason, GlobalSettings } from '../../../../shared/types' -import type { TaskSourceContext } from '../../../../shared/task-source-context' - -export type GitHubIssueCommentProjectOrigin = { - owner: string - repo: string - cacheKey: string - projectItemId: string -} - -export async function runIssueStateUpdate(args: { - repoPath: string - repoId?: string | null - sourceContext?: TaskSourceContext | null - sourceSettings?: Pick | null | undefined - projectOrigin: GitHubIssueCommentProjectOrigin | undefined - number: number - updates: { - state: 'open' | 'closed' - stateReason?: GitHubIssueCloseReason - duplicateOf?: number - } -}): Promise { - if (args.projectOrigin) { - const target = getActiveRuntimeTarget(args.sourceSettings ?? useAppStore.getState().settings) - const updateArgs = { - owner: args.projectOrigin.owner, - repo: args.projectOrigin.repo, - number: args.number, - updates: args.updates - } - const res = - target.kind === 'environment' - ? await callRuntimeRpc>>( - target, - 'github.project.updateIssueBySlug', - updateArgs, - { timeoutMs: 30_000 } - ) - : await window.api.gh.updateIssueBySlug(updateArgs) - if (!res.ok) { - throw new Error(res.error.message) - } - return - } - const res = await window.api.gh.updateIssue({ - repoPath: args.repoPath, - repoId: args.repoId ?? undefined, - sourceContext: args.sourceContext, - number: args.number, - updates: args.updates - }) - if (!res.ok) { - throw new Error(res.error) - } -} - -export async function addIssueCommentForRepo(args: { - repoId?: string - repoPath: string - sourceContext?: TaskSourceContext | null - number: number - body: string - type?: 'issue' | 'pr' -}): Promise>> { - return window.api.gh.addIssueComment({ - repoPath: args.repoPath, - repoId: args.repoId, - sourceContext: args.sourceContext, - number: args.number, - body: args.body, - type: args.type - }) -} - export function githubAvatarUrl(login: string): string { return `https://github.com/${encodeURIComponent(login)}.png?size=64` } diff --git a/src/renderer/src/components/linear-issue-workspace-text.ts b/src/renderer/src/components/linear-issue-workspace-text.ts index b9a9a518e79..b4e88121bb8 100644 --- a/src/renderer/src/components/linear-issue-workspace-text.ts +++ b/src/renderer/src/components/linear-issue-workspace-text.ts @@ -25,21 +25,3 @@ export function formatLinearIssueRelativeTime(input: string): string { export function buildLinearIssueBranchName(issue: LinearIssue): string { return getUsableLinearBranchName(issue.branchName) ?? getLinearIssueWorkspaceName(issue) } - -export function buildLinearIssuePrompt(issue: LinearIssue): string { - const lines = [ - `Linear issue: ${issue.identifier} ${issue.title}`, - `URL: ${issue.url}`, - `State: ${issue.state.name}`, - `Assignee: ${issue.assignee?.displayName ?? 'Unassigned'}`, - `Team: ${issue.team.name}` - ] - if (issue.workspaceName) { - lines.push(`Workspace: ${issue.workspaceName}`) - } - const description = issue.description?.trim() - if (description) { - lines.push('', 'Description:', description) - } - return lines.join('\n') -} diff --git a/src/renderer/src/components/native-chat/native-chat-composer-state.ts b/src/renderer/src/components/native-chat/native-chat-composer-state.ts index c7c320af52e..a14bed089f6 100644 --- a/src/renderer/src/components/native-chat/native-chat-composer-state.ts +++ b/src/renderer/src/components/native-chat/native-chat-composer-state.ts @@ -24,8 +24,6 @@ export { type NativeChatSkillDiscoverySnapshot } from './native-chat-picker-items' -export type ComposerAutocompleteMode = 'none' | 'slash' | 'mention' | 'skill' - type PickerAutocomplete = { query: string items: NativeChatPickerItem[] diff --git a/src/renderer/src/components/onboarding/use-onboarding-flow.ts b/src/renderer/src/components/onboarding/use-onboarding-flow.ts index e02cb931855..b21b4c742e8 100644 --- a/src/renderer/src/components/onboarding/use-onboarding-flow.ts +++ b/src/renderer/src/components/onboarding/use-onboarding-flow.ts @@ -40,8 +40,6 @@ import { buildWindowsTerminalSnapshotPayload } from './windows-terminal-onboardi export { STEPS } from './use-onboarding-flow-types' export type { StepId, StepNumber } from './use-onboarding-flow-types' -export type OnboardingFlowController = ReturnType - type TaskSourcesSnapshotProps = EventProps<'onboarding_task_sources_snapshot'> type TaskSourcesGithubStatus = TaskSourcesSnapshotProps['github_status'] type TaskSourcesLinearStatus = TaskSourcesSnapshotProps['linear_status'] diff --git a/src/renderer/src/components/repo/repo-icon.tsx b/src/renderer/src/components/repo/repo-icon.tsx index 00d897383df..b82de9e1173 100644 --- a/src/renderer/src/components/repo/repo-icon.tsx +++ b/src/renderer/src/components/repo/repo-icon.tsx @@ -27,12 +27,6 @@ import { cn } from '@/lib/utils' import { translate } from '@/i18n/i18n' import { createLocalizedCatalog } from '@/i18n/localized-catalog' -export type RepoLucideIconOption = { - name: string - label: string - icon: LucideIcon -} - export const getRepoLucideIconOptions = createLocalizedCatalog(() => [ { name: 'Folder', diff --git a/src/renderer/src/components/right-sidebar/CreateHostedReviewComposer.tsx b/src/renderer/src/components/right-sidebar/CreateHostedReviewComposer.tsx index 9656487a72d..7caf09dd128 100644 --- a/src/renderer/src/components/right-sidebar/CreateHostedReviewComposer.tsx +++ b/src/renderer/src/components/right-sidebar/CreateHostedReviewComposer.tsx @@ -33,13 +33,6 @@ import { const EMPTY_DROPDOWN_ITEMS: DropdownEntry[] = [] -export type CreateHostedReviewFields = { - base: string - title: string - body: string - draft: boolean -} - export type CreateHostedReviewComposerPrimaryAction = { disabled: boolean title: string diff --git a/src/renderer/src/components/right-sidebar/commit-failure-dialog-state.ts b/src/renderer/src/components/right-sidebar/commit-failure-dialog-state.ts index e3ed0bd27ea..cf53da6faae 100644 --- a/src/renderer/src/components/right-sidebar/commit-failure-dialog-state.ts +++ b/src/renderer/src/components/right-sidebar/commit-failure-dialog-state.ts @@ -3,10 +3,6 @@ export type CommitFailureDialogState = { open: boolean } -export function getCommitFailureDialogWorktreeKey(worktreeId: string | null | undefined): string { - return worktreeId ?? 'no-worktree' -} - export function shouldShowCommitFailureDialog( state: CommitFailureDialogState, worktreeKey: string, diff --git a/src/renderer/src/components/right-sidebar/file-explorer-operation-owner.ts b/src/renderer/src/components/right-sidebar/file-explorer-operation-owner.ts index cb94f03c978..5ef3c247a4d 100644 --- a/src/renderer/src/components/right-sidebar/file-explorer-operation-owner.ts +++ b/src/renderer/src/components/right-sidebar/file-explorer-operation-owner.ts @@ -128,16 +128,6 @@ export function getFileExplorerOperationRoute( } } -export function requireFileExplorerOperationRoute( - worktreeId: string | null | undefined -): FileExplorerOperationRoute { - const route = getFileExplorerOperationRoute(getFileExplorerOperationOwner(worktreeId)) - if (!route) { - throw new Error(getFileExplorerOwnerUnresolvedMessage()) - } - return route -} - export function requireMatchingFileExplorerOperationRoute( worktreeId: string | null | undefined, expectedOwner: FileExplorerOperationOwner | undefined diff --git a/src/renderer/src/components/right-sidebar/file-explorer-runtime-owner-boundary.test.ts b/src/renderer/src/components/right-sidebar/file-explorer-runtime-owner-boundary.test.ts index 8814019ab7a..766e0f11ade 100644 --- a/src/renderer/src/components/right-sidebar/file-explorer-runtime-owner-boundary.test.ts +++ b/src/renderer/src/components/right-sidebar/file-explorer-runtime-owner-boundary.test.ts @@ -24,7 +24,7 @@ describe('right sidebar file/git runtime ownership boundaries', () => { const text = source(path) expect(text).toMatch( - /getRightSidebarWorktreeRuntimeSettings|getSettingsForWorktreeRuntimeOwner|getFileExplorerOperationOwner|getFileExplorerOperationRoute|captureFileExplorerOperationGuard|requireFileExplorerOperationRoute|requireMatchingFileExplorerOperationRoute/ + /getRightSidebarWorktreeRuntimeSettings|getSettingsForWorktreeRuntimeOwner|getFileExplorerOperationOwner|getFileExplorerOperationRoute|captureFileExplorerOperationGuard|requireMatchingFileExplorerOperationRoute/ ) expect(text).not.toContain('settings: useAppStore.getState().settings') expect(text).not.toContain('const settings = useAppStore.getState().settings') diff --git a/src/renderer/src/components/right-sidebar/push-failure-summary.ts b/src/renderer/src/components/right-sidebar/push-failure-summary.ts deleted file mode 100644 index 4f20d751e13..00000000000 --- a/src/renderer/src/components/right-sidebar/push-failure-summary.ts +++ /dev/null @@ -1,6 +0,0 @@ -export { - PUSH_FAILURE_SUMMARY_SCAN_CODE_UNITS, - hasExpandedPushFailureDetails, - isPushHookFailure, - summarizePushFailure -} from '../../../../shared/source-control-push-failure' diff --git a/src/renderer/src/components/right-sidebar/source-control-active-open-file-keys.ts b/src/renderer/src/components/right-sidebar/source-control-active-open-file-keys.ts index 4c28a1062bb..42f14951f44 100644 --- a/src/renderer/src/components/right-sidebar/source-control-active-open-file-keys.ts +++ b/src/renderer/src/components/right-sidebar/source-control-active-open-file-keys.ts @@ -4,10 +4,6 @@ const EMPTY_OPEN_ROW_KEYS: ReadonlySet = new Set() const SIGNATURE_SEPARATOR = '::' -// Why: a plain edit tab carries no diff source, so it is matched against -// visible pending rows by path instead of a specific diff side. -export type ActiveOpenFileDiffSource = DiffSource | 'edit' - /** * Build the stable string that identifies the active editor file for highlight * matching: `${diffSource}::${relativePath}`. Kept as a primitive so the zustand diff --git a/src/renderer/src/components/right-sidebar/source-control-ai-commit-failure-launch.test.ts b/src/renderer/src/components/right-sidebar/source-control-ai-commit-failure-launch.test.ts deleted file mode 100644 index 030ac680492..00000000000 --- a/src/renderer/src/components/right-sidebar/source-control-ai-commit-failure-launch.test.ts +++ /dev/null @@ -1,175 +0,0 @@ -import { beforeEach, describe, expect, it, vi } from 'vitest' -import type * as SourceControlLaunchAgentSelectionModule from '@/lib/source-control-launch-agent-selection' - -const mocks = vi.hoisted(() => ({ - ensureDetectedAgents: vi.fn(), - ensureRemoteDetectedAgents: vi.fn(), - focusTerminalTabSurface: vi.fn(), - getConnectionId: vi.fn(), - launchAgentInNewTab: vi.fn(), - pickSourceControlLaunchAgent: vi.fn(), - toastError: vi.fn(), - toastSuccess: vi.fn() -})) - -vi.mock('sonner', () => ({ - toast: { - error: mocks.toastError, - success: mocks.toastSuccess - } -})) - -vi.mock('@/lib/connection-context', () => ({ - getConnectionId: mocks.getConnectionId -})) - -vi.mock('@/lib/focus-terminal-tab-surface', () => ({ - focusTerminalTabSurface: mocks.focusTerminalTabSurface -})) - -vi.mock('@/lib/launch-agent-in-new-tab', () => ({ - launchAgentInNewTab: mocks.launchAgentInNewTab -})) - -vi.mock('@/lib/source-control-launch-agent-selection', async () => { - const actual = await vi.importActual( - '@/lib/source-control-launch-agent-selection' - ) - return { - ...actual, - pickSourceControlLaunchAgent: mocks.pickSourceControlLaunchAgent - } -}) - -import { launchSourceControlRecoveryAgentWithDefault } from './source-control-ai-recovery-launch' - -const copy = { - promptUnavailable: 'Could not build the agent prompt.', - emptyPrompt: 'Recovery prompt is empty.', - savedAgentUnavailable: 'Saved AI agent is unavailable.', - noEnabledAgent: 'No enabled AI agents.', - launchCommandUnavailable: 'Could not build the agent launch command.', - connectionUnavailable: 'Unable to resolve the workspace connection.', - success: 'Started an AI agent for the recovery.' -} - -function launchRecovery( - overrides: Partial[0]> = {} -): Promise { - return launchSourceControlRecoveryAgentWithDefault({ - activeWorktreeId: 'wt-1', - activeGroupId: 'group-1', - activeSourceControlLaunchPlatform: 'darwin', - actionId: 'fixCommitFailure', - basePrompt: 'Fix this commit failure.', - getLaunchActionRecipe: () => ({ - commandInputTemplate: '{basePrompt}' - }), - getStoreState: () => ({ - settings: { defaultTuiAgent: 'codex', disabledTuiAgents: [] } as never, - ensureDetectedAgents: mocks.ensureDetectedAgents, - ensureRemoteDetectedAgents: mocks.ensureRemoteDetectedAgents - }), - copy, - ...overrides - }) -} - -describe('launchSourceControlRecoveryAgentWithDefault', () => { - beforeEach(() => { - vi.clearAllMocks() - mocks.getConnectionId.mockReturnValue(null) - mocks.ensureDetectedAgents.mockResolvedValue(['codex']) - mocks.ensureRemoteDetectedAgents.mockResolvedValue(['codex']) - mocks.pickSourceControlLaunchAgent.mockReturnValue('codex') - mocks.launchAgentInNewTab.mockReturnValue({ tabId: 'tab-1' }) - }) - - it('rejects invalid saved CLI arguments before detecting agents', async () => { - await expect( - launchRecovery({ - getLaunchActionRecipe: () => ({ - commandInputTemplate: '{basePrompt}', - agentArgs: '--model "unterminated' - }) - }) - ).resolves.toBe(false) - - expect(mocks.ensureDetectedAgents).not.toHaveBeenCalled() - expect(mocks.ensureRemoteDetectedAgents).not.toHaveBeenCalled() - expect(mocks.launchAgentInNewTab).not.toHaveBeenCalled() - expect(mocks.toastError).toHaveBeenCalledWith( - 'CLI arguments are invalid: Unclosed quote in command template.' - ) - }) - - it('treats a null worktree connection as proven local and does not fall back to SSH', async () => { - mocks.getConnectionId.mockReturnValue(null) - - await expect(launchRecovery({ sourceRepoConnectionId: 'ssh-1' })).resolves.toBe(true) - - expect(mocks.ensureDetectedAgents).toHaveBeenCalledTimes(1) - expect(mocks.ensureRemoteDetectedAgents).not.toHaveBeenCalled() - expect(mocks.launchAgentInNewTab).toHaveBeenCalledWith( - expect.objectContaining({ prompt: 'Fix this commit failure.' }) - ) - expect(mocks.focusTerminalTabSurface).toHaveBeenCalledWith('tab-1') - expect(mocks.toastSuccess).toHaveBeenCalledWith('Started an AI agent for the recovery.') - }) - - it('uses the owning SSH connection when the worktree has one', async () => { - mocks.getConnectionId.mockReturnValue('ssh-worktree') - - await expect(launchRecovery()).resolves.toBe(true) - - expect(mocks.ensureRemoteDetectedAgents).toHaveBeenCalledWith('ssh-worktree') - expect(mocks.ensureDetectedAgents).not.toHaveBeenCalled() - }) - - it('falls back to the repo connection only when the worktree connection is unresolved', async () => { - mocks.getConnectionId.mockReturnValue(undefined) - - await expect(launchRecovery({ sourceRepoConnectionId: 'ssh-repo' })).resolves.toBe(true) - - expect(mocks.ensureRemoteDetectedAgents).toHaveBeenCalledWith('ssh-repo') - }) - - it('errors when both worktree and repo connections are unresolved', async () => { - mocks.getConnectionId.mockReturnValue(undefined) - - await expect(launchRecovery({ sourceRepoConnectionId: undefined })).resolves.toBe(false) - - expect(mocks.toastError).toHaveBeenCalledWith('Unable to resolve the workspace connection.') - expect(mocks.ensureDetectedAgents).not.toHaveBeenCalled() - expect(mocks.ensureRemoteDetectedAgents).not.toHaveBeenCalled() - }) - - it('rejects empty rendered prompts before detecting agents', async () => { - await expect( - launchRecovery({ - getLaunchActionRecipe: () => ({ - commandInputTemplate: ' ' - }) - }) - ).resolves.toBe(false) - - expect(mocks.toastError).toHaveBeenCalledWith('Recovery prompt is empty.') - expect(mocks.ensureDetectedAgents).not.toHaveBeenCalled() - }) - - it('rejects unavailable saved agents before terminal launch', async () => { - mocks.ensureDetectedAgents.mockResolvedValue(['claude']) - - await expect( - launchRecovery({ - getLaunchActionRecipe: () => ({ - agentId: 'codex', - commandInputTemplate: '{basePrompt}' - }) - }) - ).resolves.toBe(false) - - expect(mocks.toastError).toHaveBeenCalledWith('Saved AI agent is unavailable.') - expect(mocks.launchAgentInNewTab).not.toHaveBeenCalled() - }) -}) diff --git a/src/renderer/src/components/right-sidebar/source-control-ai-commit-failure-launch.ts b/src/renderer/src/components/right-sidebar/source-control-ai-commit-failure-launch.ts deleted file mode 100644 index a080f587db5..00000000000 --- a/src/renderer/src/components/right-sidebar/source-control-ai-commit-failure-launch.ts +++ /dev/null @@ -1,47 +0,0 @@ -import type { - SourceControlActionRecipe, - SourceControlLaunchActionId -} from '../../../../shared/source-control-ai-actions' -import { - getDefaultSourceControlRecoveryLaunchCopy, - launchSourceControlRecoveryAgentWithDefault -} from './source-control-ai-recovery-launch' -import type { AppState } from '@/store' - -type SourceControlAiLaunchStoreSnapshot = Pick< - AppState, - 'settings' | 'ensureDetectedAgents' | 'ensureRemoteDetectedAgents' -> - -export async function launchCommitFailureAgentWithDefault({ - activeWorktreeId, - activeGroupId, - activeSourceControlLaunchPlatform, - sourceRepoConnectionId, - commitFailureRecoveryPrompt, - promptOverride, - getLaunchActionRecipe, - getStoreState -}: { - activeWorktreeId: string - activeGroupId: string | null | undefined - activeSourceControlLaunchPlatform: NodeJS.Platform - sourceRepoConnectionId?: string | null - commitFailureRecoveryPrompt: string | null - promptOverride?: string - getLaunchActionRecipe: (actionId: SourceControlLaunchActionId) => SourceControlActionRecipe - getStoreState: () => SourceControlAiLaunchStoreSnapshot -}): Promise { - return launchSourceControlRecoveryAgentWithDefault({ - activeWorktreeId, - activeGroupId, - activeSourceControlLaunchPlatform, - sourceRepoConnectionId, - actionId: 'fixCommitFailure', - basePrompt: commitFailureRecoveryPrompt, - promptOverride, - getLaunchActionRecipe, - getStoreState, - copy: getDefaultSourceControlRecoveryLaunchCopy('commit') - }) -} diff --git a/src/renderer/src/components/right-sidebar/source-control-ai-push-failure-launch.ts b/src/renderer/src/components/right-sidebar/source-control-ai-push-failure-launch.ts deleted file mode 100644 index 33e8ab01580..00000000000 --- a/src/renderer/src/components/right-sidebar/source-control-ai-push-failure-launch.ts +++ /dev/null @@ -1,47 +0,0 @@ -import type { - SourceControlActionRecipe, - SourceControlLaunchActionId -} from '../../../../shared/source-control-ai-actions' -import { - getDefaultSourceControlRecoveryLaunchCopy, - launchSourceControlRecoveryAgentWithDefault -} from './source-control-ai-recovery-launch' -import type { AppState } from '@/store' - -type SourceControlAiLaunchStoreSnapshot = Pick< - AppState, - 'settings' | 'ensureDetectedAgents' | 'ensureRemoteDetectedAgents' -> - -export async function launchPushFailureAgentWithDefault({ - activeWorktreeId, - activeGroupId, - activeSourceControlLaunchPlatform, - sourceRepoConnectionId, - pushFailureRecoveryPrompt, - promptOverride, - getLaunchActionRecipe, - getStoreState -}: { - activeWorktreeId: string - activeGroupId: string | null | undefined - activeSourceControlLaunchPlatform: NodeJS.Platform - sourceRepoConnectionId?: string | null - pushFailureRecoveryPrompt: string | null - promptOverride?: string - getLaunchActionRecipe: (actionId: SourceControlLaunchActionId) => SourceControlActionRecipe - getStoreState: () => SourceControlAiLaunchStoreSnapshot -}): Promise { - return launchSourceControlRecoveryAgentWithDefault({ - activeWorktreeId, - activeGroupId, - activeSourceControlLaunchPlatform, - sourceRepoConnectionId, - actionId: 'fixPushFailure', - basePrompt: pushFailureRecoveryPrompt, - promptOverride, - getLaunchActionRecipe, - getStoreState, - copy: getDefaultSourceControlRecoveryLaunchCopy('push') - }) -} diff --git a/src/renderer/src/components/right-sidebar/source-control-create-pr-intent-state.ts b/src/renderer/src/components/right-sidebar/source-control-create-pr-intent-state.ts index b40976642e1..75c4e04a34e 100644 --- a/src/renderer/src/components/right-sidebar/source-control-create-pr-intent-state.ts +++ b/src/renderer/src/components/right-sidebar/source-control-create-pr-intent-state.ts @@ -1,14 +1,5 @@ import type { PrimaryAction } from './source-control-primary-action-types' -import { - resolveCreateReviewIntentEligibility, - type CreateReviewIntentEligibility, - type CreateReviewIntentKind -} from '../../../../shared/source-control-create-review-intent' - -// Why: renderer APIs keep PR terminology for compatibility, while shared logic -// uses provider-neutral review terminology for PR/MR hosts. -export type CreatePrIntentKind = CreateReviewIntentKind -export type CreatePrIntentEligibility = CreateReviewIntentEligibility +import { resolveCreateReviewIntentEligibility } from '../../../../shared/source-control-create-review-intent' export const resolveCreatePrIntentEligibility = resolveCreateReviewIntentEligibility diff --git a/src/renderer/src/components/right-sidebar/source-control-primary-action-types.ts b/src/renderer/src/components/right-sidebar/source-control-primary-action-types.ts index b3f79e8a69e..da34c8a253d 100644 --- a/src/renderer/src/components/right-sidebar/source-control-primary-action-types.ts +++ b/src/renderer/src/components/right-sidebar/source-control-primary-action-types.ts @@ -62,13 +62,3 @@ export type PrimaryActionInputs = { // while the request is in flight instead of flashing it in after ~1s. isHostedReviewCreationLoading?: boolean } - -export const PRIMARY_LABEL_BY_KIND: Record, string> = { - stage: 'Stage All', - push: 'Push', - pull: 'Pull', - sync: 'Sync', - publish: 'Publish Branch', - create_pr_intent: 'Create PR', - create_pr: 'Create PR' -} diff --git a/src/renderer/src/components/settings/SettingsConstants.ts b/src/renderer/src/components/settings/SettingsConstants.ts index 0c7706be3bc..260d8b48971 100644 --- a/src/renderer/src/components/settings/SettingsConstants.ts +++ b/src/renderer/src/components/settings/SettingsConstants.ts @@ -1,8 +1,6 @@ -import type { OrcaHooks } from '../../../../shared/types' import { DEFAULT_APP_FONT_FAMILY, getDefaultRepoHookSettings } from '../../../../shared/constants' import { DESKTOP_TERMINAL_SCROLLBACK_ROW_PRESETS } from '../../../../shared/terminal-scrollback-policy' -export type HookName = keyof OrcaHooks['scripts'] export const DEFAULT_REPO_HOOK_SETTINGS = getDefaultRepoHookSettings() export const MAX_THEME_RESULTS = 80 export const SCROLLBACK_PRESETS_ROWS = DESKTOP_TERMINAL_SCROLLBACK_ROW_PRESETS diff --git a/src/renderer/src/components/settings/general-search.ts b/src/renderer/src/components/settings/general-search.ts index 9cff3c527d9..a79f994d5fa 100644 --- a/src/renderer/src/components/settings/general-search.ts +++ b/src/renderer/src/components/settings/general-search.ts @@ -193,35 +193,6 @@ export const getGeneralUpdateSearchEntries = createLocalizedCatalog(() => [ } ]) -export const getGeneralAgentSearchEntries = createLocalizedCatalog(() => [ - { - title: translate('auto.components.settings.general.search.db11502270', 'Default Agent'), - description: translate( - 'auto.components.settings.general.search.e2da948f59', - 'Pre-select an AI coding agent in the new-workspace composer.' - ), - keywords: [ - ...translateSearchKeyword('auto.components.settings.general.search.8ea37a05bc', 'agent'), - ...translateSearchKeyword('auto.components.settings.general.search.41c2f9a025', 'default'), - ...translateSearchKeyword('auto.components.settings.general.search.95b63edde7', 'claude'), - ...translateSearchKeyword('auto.components.settings.general.search.aea7d2cccb', 'openclaude'), - ...translateSearchKeyword( - 'auto.components.settings.general.search.5baf51c4d9', - 'open claude' - ), - ...translateSearchKeyword('auto.components.settings.general.search.27d9b996ba', 'codex'), - ...translateSearchKeyword('auto.components.settings.general.search.882c4896fd', 'opencode'), - ...translateSearchKeyword('auto.components.settings.general.search.9b0bc30160', 'pi'), - ...translateSearchKeyword('auto.components.settings.general.search.5fdf1dc2d1', 'omp'), - ...translateSearchKeyword('auto.components.settings.general.search.3c30fe2d51', 'gemini'), - ...translateSearchKeyword('auto.components.settings.general.search.f472e97440', 'aider'), - ...translateSearchKeyword('auto.components.settings.general.search.5d9ba08673', 'copilot'), - ...translateSearchKeyword('auto.components.settings.general.search.c61b14be7c', 'grok'), - ...translateSearchKeyword('auto.lib.agent.catalog.fc80296033', 'devin') - ] - } -]) - type GeneralPaneSearchOptions = { includeProjectRuntime?: boolean } diff --git a/src/renderer/src/components/settings/terminal-windows-search.ts b/src/renderer/src/components/settings/terminal-windows-search.ts index 9aa765177b9..85bb8ed4d76 100644 --- a/src/renderer/src/components/settings/terminal-windows-search.ts +++ b/src/renderer/src/components/settings/terminal-windows-search.ts @@ -1,4 +1,3 @@ -import type { SettingsSearchEntry } from './settings-search' import { translate } from '@/i18n/i18n' import { translateSearchKeyword } from './settings-search-keywords' import { createLocalizedCatalog } from '@/i18n/localized-catalog' @@ -135,9 +134,3 @@ export const getTerminalRightClickToPasteSearchEntry = createLocalizedCatalog(() ] } ]) - -export const getTerminalWindowsSearchEntries = createLocalizedCatalog((): SettingsSearchEntry[] => [ - ...getTerminalWindowsShellSearchEntry(), - ...getTerminalWindowsPowershellImplementationSearchEntry(), - ...getTerminalRightClickToPasteSearchEntry() -]) diff --git a/src/renderer/src/components/sidebar/WorktreeCardHelpers.tsx b/src/renderer/src/components/sidebar/WorktreeCardHelpers.tsx index 43f53b76ede..2d2d081b067 100644 --- a/src/renderer/src/components/sidebar/WorktreeCardHelpers.tsx +++ b/src/renderer/src/components/sidebar/WorktreeCardHelpers.tsx @@ -1,11 +1,5 @@ import React from 'react' -import type { - PRState, - CheckStatus, - GitConflictOperation, - TerminalTab -} from '../../../../shared/types' -import type { AgentStatusEntry } from '../../../../shared/agent-status-types' +import type { CheckStatus, GitConflictOperation, TerminalTab } from '../../../../shared/types' // ── Pure helper functions ──────────────────────────────────────────── @@ -13,10 +7,6 @@ export function branchDisplayName(branch: string): string { return branch.replace(/^refs\/heads\//, '') } -export function prStateLabel(state: PRState): string { - return state.charAt(0).toUpperCase() + state.slice(1) -} - export function checksLabel(status: CheckStatus): string { switch (status) { case 'success': @@ -40,7 +30,6 @@ export const CONFLICT_OPERATION_LABELS: Record ) } - -export function WorktreeCardPorts({ ports }: WorktreeCardPortsProps): React.JSX.Element | null { - if (ports.length === 0) { - return null - } - - return ( - - - - - event.stopPropagation()} - onDoubleClick={(event) => event.stopPropagation()} - > - - - - - - ) -} diff --git a/src/renderer/src/components/sidebar/create-project-defaults.ts b/src/renderer/src/components/sidebar/create-project-defaults.ts index fd5175c8c22..9197a8a7d91 100644 --- a/src/renderer/src/components/sidebar/create-project-defaults.ts +++ b/src/renderer/src/components/sidebar/create-project-defaults.ts @@ -1,5 +1,3 @@ -export type RepoKind = 'git' | 'folder' - export type GitAvailability = 'checking' | 'available' | 'unavailable' | 'unknown' function pathSeparatorFor(pathValue: string): '/' | '\\' { diff --git a/src/renderer/src/components/sidebar/project-header-drop.ts b/src/renderer/src/components/sidebar/project-header-drop.ts index be012eb72ce..1f7418f805c 100644 --- a/src/renderer/src/components/sidebar/project-header-drop.ts +++ b/src/renderer/src/components/sidebar/project-header-drop.ts @@ -28,16 +28,6 @@ export function getProjectHeaderDragBucketKey( return repo.projectGroupId ? `group:${repo.projectGroupId}` : 'ungrouped' } -export function getSidebarOrderedRepoHeaderIds(rows: readonly Row[]): string[] { - const ids: string[] = [] - for (const row of rows) { - if (row.type === 'header' && row.repo) { - ids.push(row.repo.id) - } - } - return ids -} - export function getSidebarOrderedRepoHeaderIdsByBucket( rows: readonly Row[] ): Map { diff --git a/src/renderer/src/components/sidebar/sidebar-host-options.ts b/src/renderer/src/components/sidebar/sidebar-host-options.ts index 248bd98000d..dc764112bcc 100644 --- a/src/renderer/src/components/sidebar/sidebar-host-options.ts +++ b/src/renderer/src/components/sidebar/sidebar-host-options.ts @@ -118,13 +118,6 @@ export function buildSidebarHostScopeOptions( ] } -export function getSidebarHostScopeLabel( - scope: WorkspaceHostScope, - options: readonly SidebarHostScopeOption[] -): string { - return options.find((option) => option.id === scope)?.label ?? 'All hosts' -} - export function getSidebarHostVisibilityLabel( visibleHostIds: readonly ExecutionHostId[] | null | undefined, hosts: readonly SidebarHostOption[] diff --git a/src/renderer/src/components/sidebar/sidebar-nav-controls.tsx b/src/renderer/src/components/sidebar/sidebar-nav-controls.tsx index eb98669a39d..466355be56b 100644 --- a/src/renderer/src/components/sidebar/sidebar-nav-controls.tsx +++ b/src/renderer/src/components/sidebar/sidebar-nav-controls.tsx @@ -1,6 +1,5 @@ import React from 'react' import { EyeOff } from 'lucide-react' -import { cn } from '@/lib/utils' import { ContextMenuContent, ContextMenuItem } from '@/components/ui/context-menu' import { translate } from '@/i18n/i18n' @@ -14,37 +13,3 @@ export function HideSidebarMenu({ onHide }: { onHide: () => void }): React.JSX.E ) } - -export function TaskProviderShortcut({ - canBrowseTasks, - label, - onOpen, - children -}: { - canBrowseTasks: boolean - label: string - onOpen: () => void - children: React.ReactNode -}): React.JSX.Element { - return ( - { - e.stopPropagation() - if (!canBrowseTasks) { - return - } - onOpen() - }} - className={cn( - 'rounded p-0.5 text-muted-foreground/70', - canBrowseTasks ? 'transition-colors hover:text-foreground' : 'cursor-default' - )} - aria-label={canBrowseTasks ? label : undefined} - aria-hidden={canBrowseTasks ? undefined : true} - > - {children} - - ) -} diff --git a/src/renderer/src/components/sidebar/workspace-kanban-card-drag-preview-dom.ts b/src/renderer/src/components/sidebar/workspace-kanban-card-drag-preview-dom.ts index 58dafc5db3f..a78fa1230ad 100644 --- a/src/renderer/src/components/sidebar/workspace-kanban-card-drag-preview-dom.ts +++ b/src/renderer/src/components/sidebar/workspace-kanban-card-drag-preview-dom.ts @@ -25,18 +25,6 @@ export function setDragDocumentStyles(enabled: boolean): void { document.documentElement.toggleAttribute(POINTER_DRAGGING_ATTR, enabled) } -export function getDraggedCards( - board: HTMLElement, - worktreeIds: readonly string[], - fallbackCard: HTMLElement -): HTMLElement[] { - const ids = new Set(worktreeIds) - const cards = Array.from(board.querySelectorAll(CARD_SELECTOR)).filter((card) => - ids.has(card.dataset.workspaceBoardCardId ?? '') - ) - return cards.length > 0 ? cards : [fallbackCard] -} - export function setDraggedCardsDragging(args: { board: HTMLElement | null worktreeIds: readonly string[] diff --git a/src/renderer/src/components/tab-bar/shell-icons.tsx b/src/renderer/src/components/tab-bar/shell-icons.tsx index 8ea837e360f..a5a896154a9 100644 --- a/src/renderer/src/components/tab-bar/shell-icons.tsx +++ b/src/renderer/src/components/tab-bar/shell-icons.tsx @@ -3,8 +3,6 @@ import { WINDOWS_GIT_BASH_SHELL } from '../../../../shared/windows-terminal-shel import { translate } from '@/i18n/i18n' import gitForWindowsLogoUrl from '../../../../../resources/gwindows_logo.svg?url' -export type WindowsShell = 'powershell.exe' | 'cmd.exe' | 'wsl.exe' | typeof WINDOWS_GIT_BASH_SHELL - // Why: the "+" dropdown and per-tab tab strip both need a visual distinction // between PowerShell, CMD, Git Bash, and WSL sessions. Stock lucide glyphs don't // differentiate — every session rendered as the same generic chevron. These diff --git a/src/renderer/src/components/tab-bar/tab-create-entry-path-validation.ts b/src/renderer/src/components/tab-bar/tab-create-entry-path-validation.ts index a73a66da2b5..91a6415bdd6 100644 --- a/src/renderer/src/components/tab-bar/tab-create-entry-path-validation.ts +++ b/src/renderer/src/components/tab-bar/tab-create-entry-path-validation.ts @@ -3,18 +3,6 @@ import { isAbsolutePathLike } from '../editor/editor-panel-file-mode' export type TabEntryLocalPlatform = 'posix' | 'windows' -function hasPathSeparator(query: string): boolean { - return /[\\/]/.test(query) -} - -function hasFilenameExtension(query: string): boolean { - return /(?:^|[\\/])[^\\/]+\.[^\\/]+$/.test(query.trim()) -} - -export function isLikelyNewFileIntent(query: string): boolean { - return hasPathSeparator(query) || hasFilenameExtension(query) -} - export function isTabEntryAbsolutePathLike(query: string): boolean { return isAbsolutePathLike(query.trim()) } diff --git a/src/renderer/src/components/tab-group/tab-drag-context.tsx b/src/renderer/src/components/tab-group/tab-drag-context.tsx index 3cf10ee7e1a..189f583b293 100644 --- a/src/renderer/src/components/tab-group/tab-drag-context.tsx +++ b/src/renderer/src/components/tab-group/tab-drag-context.tsx @@ -31,7 +31,3 @@ export function TabDragProvider({ export function useTabDragActive(): boolean { return useContext(TabDragContext).isTabDragActive } - -export function useTabDragActiveRef(): RefObject { - return useContext(TabDragContext).isTabDragActiveRef -} diff --git a/src/renderer/src/components/terminal-pane/pty-delivery-interest.ts b/src/renderer/src/components/terminal-pane/pty-delivery-interest.ts index 56519c09e90..bb8e7d65a38 100644 --- a/src/renderer/src/components/terminal-pane/pty-delivery-interest.ts +++ b/src/renderer/src/components/terminal-pane/pty-delivery-interest.ts @@ -35,8 +35,3 @@ export function acquirePtyDeliveryInterest(ptyId: string): () => void { } } } - -/** Test seam: drop ref counts between tests (no IPC is sent). */ -export function _resetPtyDeliveryInterestForTest(): void { - ptyDeliveryInterestRefCounts.clear() -} diff --git a/src/renderer/src/components/terminal-pane/pty-pre-handler-buffer.ts b/src/renderer/src/components/terminal-pane/pty-pre-handler-buffer.ts index 83b3a10f1e2..eca3b7644b9 100644 --- a/src/renderer/src/components/terminal-pane/pty-pre-handler-buffer.ts +++ b/src/renderer/src/components/terminal-pane/pty-pre-handler-buffer.ts @@ -176,11 +176,6 @@ export function drainPreHandlerPtyExit(ptyId: string, handler: (code: number) => } } -export function clearPreHandlerPtyData(ptyId: string): void { - preHandlerPtyData.delete(ptyId) - warnedLostHandlerPtyIds.delete(ptyId) -} - export function clearPreHandlerPtyState(ptyId: string): void { preHandlerPtyData.delete(ptyId) preHandlerPtyExit.delete(ptyId) diff --git a/src/renderer/src/components/terminal-pane/terminal-hidden-delivery-gate.ts b/src/renderer/src/components/terminal-pane/terminal-hidden-delivery-gate.ts index 8123b83a9e1..367c42afe78 100644 --- a/src/renderer/src/components/terminal-pane/terminal-hidden-delivery-gate.ts +++ b/src/renderer/src/components/terminal-pane/terminal-hidden-delivery-gate.ts @@ -38,8 +38,3 @@ export function isRendererHiddenPtyDeliveryGateEnabled( // side-effect-authority sync read). return readPersistedHiddenDeliveryGateFlagSync() !== false } - -/** Test seam: reset the persisted-flag cache between tests. */ -export function _resetHiddenPtyDeliveryGateFlagCacheForTest(): void { - persistedGateFlagCache = undefined -} diff --git a/src/renderer/src/components/terminal/terminal-tab-actions.ts b/src/renderer/src/components/terminal/terminal-tab-actions.ts index 70b408a4b39..3dd2762f7f3 100644 --- a/src/renderer/src/components/terminal/terminal-tab-actions.ts +++ b/src/renderer/src/components/terminal/terminal-tab-actions.ts @@ -1,7 +1,5 @@ import { useAppStore } from '@/store' -import { TOGGLE_TERMINAL_PANE_EXPAND_EVENT } from '@/constants/terminal' import { - activateWebRuntimeSessionTab, closeWebRuntimeSessionTab, isWebRuntimeSessionActive, toHostSessionTabId @@ -226,38 +224,3 @@ export function closeTerminalTab( }) options?.onClosed?.() } - -export function activateTerminalTab(tabId: string): void { - const s = useAppStore.getState() - const owningWorktreeId = - Object.entries(s.tabsByWorktree).find(([, worktreeTabs]) => - worktreeTabs.some((tab) => tab.id === tabId) - )?.[0] ?? null - const worktreeRoute = resolveTerminalWorktreeRoute(s, owningWorktreeId) - if (!worktreeRoute) { - return - } - const runtimeEnvironmentId = worktreeRoute.runtimeEnvironmentId - if (owningWorktreeId && isWebRuntimeSessionActive(runtimeEnvironmentId)) { - // Why: activation needs to update the host's active tab as well as the - // local optimistic state, otherwise the next host snapshot snaps back. - void activateWebRuntimeSessionTab({ - worktreeId: owningWorktreeId, - tabId, - environmentId: runtimeEnvironmentId - }) - } - s.setActiveTab(tabId) - s.setActiveTabType('terminal') -} - -export function toggleTerminalPaneExpand(tabId: string): void { - useAppStore.getState().setActiveTab(tabId) - requestAnimationFrame(() => { - window.dispatchEvent( - new CustomEvent(TOGGLE_TERMINAL_PANE_EXPAND_EVENT, { - detail: { tabId } - }) - ) - }) -} diff --git a/src/renderer/src/constants/terminal.ts b/src/renderer/src/constants/terminal.ts index a5af687c466..3aea3426622 100644 --- a/src/renderer/src/constants/terminal.ts +++ b/src/renderer/src/constants/terminal.ts @@ -26,10 +26,6 @@ export const WAKE_HIBERNATED_AGENTS_WORKTREE_EVENT = 'orca-wake-hibernated-agent // per-pane ResizeObserver path instead. export const SYNC_FIT_PANES_EVENT = 'orca-sync-fit-panes' -export type ToggleTerminalPaneExpandDetail = { - tabId: string -} - export type FocusTerminalPaneDetail = { tabId: string /** Stable terminal layout leaf UUID. Numeric PaneManager ids are renderer-local diff --git a/src/renderer/src/hooks/useAutomationDispatchEvents.test.ts b/src/renderer/src/hooks/useAutomationDispatchEvents.test.ts index ae8f70d05dd..160496c3be8 100644 --- a/src/renderer/src/hooks/useAutomationDispatchEvents.test.ts +++ b/src/renderer/src/hooks/useAutomationDispatchEvents.test.ts @@ -3,7 +3,6 @@ import { beforeEach, describe, expect, it, vi } from 'vitest' const mockLaunchAgentBackgroundSession = vi.fn() const mockLaunchWorktreeBackgroundTerminals = vi.fn() -const mockSubmitPromptToAgentTab = vi.fn() const mockFindReusableAutomationSession = vi.fn() const mockObserveExistingAutomationSession = vi.fn() const mockCreateWorktree = vi.fn() @@ -125,9 +124,7 @@ vi.mock('@/lib/launch-worktree-background-terminals', () => ({ launchWorktreeBackgroundTerminals: mockLaunchWorktreeBackgroundTerminals })) -vi.mock('@/lib/agent-paste-draft', () => ({ - submitPromptToAgentTab: mockSubmitPromptToAgentTab -})) +vi.mock('@/lib/agent-paste-draft', () => ({})) vi.mock('@/lib/automation-session-reuse', () => ({ findReusableAutomationSession: mockFindReusableAutomationSession diff --git a/src/renderer/src/hooks/useIssueMetadata.ts b/src/renderer/src/hooks/useIssueMetadata.ts index 2635825f830..b694c5491dc 100644 --- a/src/renderer/src/hooks/useIssueMetadata.ts +++ b/src/renderer/src/hooks/useIssueMetadata.ts @@ -217,11 +217,6 @@ export function clearLinearMetadataCache(): void { clearMetadataRequestStore(linearMemberStore) } -export function clearGitHubMetadataCache(): void { - clearMetadataRequestStore(ghLabelStore) - clearMetadataRequestStore(ghAssigneeStore) -} - export function useTeamStates( teamId: string | null, settings?: RuntimeLinearSettings, diff --git a/src/renderer/src/hooks/useShortcutLabel.ts b/src/renderer/src/hooks/useShortcutLabel.ts index 95dd7320fd3..1d96ad8745a 100644 --- a/src/renderer/src/hooks/useShortcutLabel.ts +++ b/src/renderer/src/hooks/useShortcutLabel.ts @@ -61,18 +61,6 @@ export function useOptionalShortcutLabel(actionId: KeybindingActionId): string | return formatOptionalShortcutLabel(actionId, keybindings) } -export function formatShortcutKeys( - actionId: KeybindingActionId, - overrides?: KeybindingOverrides -): string[] { - return formatShortcutKeyComboDetails(actionId, overrides)[0]?.keys ?? [] -} - -export function useShortcutKeys(actionId: KeybindingActionId): string[] { - const keybindings = useAppStore((state) => state.keybindings) - return formatShortcutKeys(actionId, keybindings) -} - export function formatShortcutKeyComboDetails( actionId: KeybindingActionId, overrides?: KeybindingOverrides @@ -94,14 +82,3 @@ export function useShortcutKeyComboDetails( export function useShortcutKeyDetails(actionId: KeybindingActionId): ShortcutKeyComboDetails { return useShortcutKeyComboDetails(actionId)[0] ?? { keys: [], doubleTap: false } } - -export function formatShortcutKeyCombos( - actionId: KeybindingActionId, - overrides?: KeybindingOverrides -): string[][] { - return formatShortcutKeyComboDetails(actionId, overrides).map((combo) => combo.keys) -} - -export function useShortcutKeyCombos(actionId: KeybindingActionId): string[][] { - return useShortcutKeyComboDetails(actionId).map((combo) => combo.keys) -} diff --git a/src/renderer/src/lib/active-agent-note-send.ts b/src/renderer/src/lib/active-agent-note-send.ts index a2eb9c429d5..0089773c7d3 100644 --- a/src/renderer/src/lib/active-agent-note-send.ts +++ b/src/renderer/src/lib/active-agent-note-send.ts @@ -27,7 +27,6 @@ export { getActiveAgentRuntimeProbeDescriptor, getActiveTerminalNoteTarget, probeActiveAgentNoteTarget, - useCanSendNotesToActiveTerminal, type ActiveTerminalNoteTarget } from './active-agent-note-target' export { diff --git a/src/renderer/src/lib/active-agent-note-target.ts b/src/renderer/src/lib/active-agent-note-target.ts index 9ee0dfc511d..c9e7a833bad 100644 --- a/src/renderer/src/lib/active-agent-note-target.ts +++ b/src/renderer/src/lib/active-agent-note-target.ts @@ -1,11 +1,9 @@ -import { useEffect, useState } from 'react' import type { RuntimeTerminalListResult } from '../../../shared/runtime-types' import { AGENT_STATUS_STALE_AFTER_MS, type AgentStatusEntry } from '../../../shared/agent-status-types' import type { AppState } from '@/store/types' -import { useAppStore } from '@/store' import { callRuntimeRpc, getActiveRuntimeTarget } from '@/runtime/runtime-rpc-client' import { getSettingsForWorktreeRuntimeOwner, @@ -80,48 +78,6 @@ export function getActiveTerminalNoteTarget( return leafId ? { tabId, leafId } : null } -export function useCanSendNotesToActiveTerminal(worktreeId: string): boolean { - const canSendFromRendererState = useAppStore( - (state) => getActiveAgentNoteTarget(state, worktreeId) !== null - ) - const probeKey = useAppStore( - (state) => getActiveAgentRuntimeProbeDescriptor(state, worktreeId)?.key ?? null - ) - const [runtimeProbe, setRuntimeProbe] = useState<{ key: string; canSend: boolean } | null>(null) - - useEffect(() => { - if (canSendFromRendererState || !probeKey) { - return - } - const probeDescriptor = getActiveAgentRuntimeProbeDescriptor(useAppStore.getState(), worktreeId) - if (!probeDescriptor || probeDescriptor.key !== probeKey) { - return - } - - let cancelled = false - void probeActiveAgentNoteTarget(probeDescriptor) - .then((canSend) => { - if (!cancelled) { - setRuntimeProbe({ key: probeKey, canSend }) - } - }) - .catch(() => { - if (!cancelled) { - setRuntimeProbe({ key: probeKey, canSend: false }) - } - }) - - return () => { - cancelled = true - } - }, [canSendFromRendererState, probeKey, worktreeId]) - - return ( - canSendFromRendererState || - (runtimeProbe !== null && runtimeProbe.key === probeKey && runtimeProbe.canSend) - ) -} - export function getActiveAgentNoteTarget( state: ActiveTerminalNoteTargetState, worktreeId: string, diff --git a/src/renderer/src/lib/agent-hibernation-coordinator.ts b/src/renderer/src/lib/agent-hibernation-coordinator.ts index 18948d86e08..b8dd54337b6 100644 --- a/src/renderer/src/lib/agent-hibernation-coordinator.ts +++ b/src/renderer/src/lib/agent-hibernation-coordinator.ts @@ -236,10 +236,6 @@ export function stopAgentHibernationCoordinator(): void { coordinator.confirmationState = {} } -export function isAgentHibernationCoordinatorRunning(): boolean { - return coordinator.interval !== null -} - export function resetAgentHibernationCoordinatorForTests(): void { stopAgentHibernationCoordinator() coordinator.shuttingDownCandidateIds.clear() diff --git a/src/renderer/src/lib/agent-paste-draft.ts b/src/renderer/src/lib/agent-paste-draft.ts index 44495c82e29..4e53f4ac102 100644 --- a/src/renderer/src/lib/agent-paste-draft.ts +++ b/src/renderer/src/lib/agent-paste-draft.ts @@ -167,24 +167,6 @@ export async function pasteDraftToAgentPtyWhenReady(args: { }) } -export async function submitPromptToAgentTab(args: { - tabId: string - content: string - timeoutMs?: number -}): Promise { - const { tabId, content, timeoutMs } = args - const ptyId = await waitForPtyId(tabId, timeoutMs ?? READINESS_TIMEOUT_MS) - if (!ptyId) { - return false - } - return await sendBracketedPasteToAgent({ - settings: getSettingsForAgentTabRuntimeOwner(tabId), - ptyId, - content, - submit: true - }) -} - export async function submitPromptToAgentPty(args: { tabId: string ptyId: string diff --git a/src/renderer/src/lib/crash-diagnostics.test.ts b/src/renderer/src/lib/crash-diagnostics.test.ts index 0b93aa15511..6e96efecf0c 100644 --- a/src/renderer/src/lib/crash-diagnostics.test.ts +++ b/src/renderer/src/lib/crash-diagnostics.test.ts @@ -156,18 +156,6 @@ describe('renderer crash diagnostics', () => { }) }) - it('disposes global listeners and the memory interval', () => { - diagnostics.installRendererCrashDiagnostics() - - diagnostics._disposeRendererCrashDiagnosticsForTests() - - expect(removeEventListenerMock).toHaveBeenCalledWith('error', expect.any(Function)) - expect(removeEventListenerMock).toHaveBeenCalledWith('unhandledrejection', expect.any(Function)) - expect(clearIntervalMock).toHaveBeenCalledWith(1) - expect(listeners.get('error')).toHaveLength(0) - expect(listeners.get('unhandledrejection')).toHaveLength(0) - }) - it('does not throw when preload is unavailable', () => { vi.stubGlobal('window', {}) @@ -223,8 +211,9 @@ describe('renderer crash diagnostics', () => { }) // Why: a heap that jumps straight past 80% must emit both levels at once. - diagnostics._disposeRendererCrashDiagnosticsForTests() + vi.resetModules() recordBreadcrumbMock.mockClear() + diagnostics = (await import('./crash-diagnostics')) as DiagnosticsModule diagnostics.installRendererCrashDiagnostics() expect(highwaterCalls()).toHaveLength(2) expect(getElementsByTagName).toHaveBeenCalledTimes(3) diff --git a/src/renderer/src/lib/crash-diagnostics.ts b/src/renderer/src/lib/crash-diagnostics.ts index 90fa45ebba0..95c9bfe213c 100644 --- a/src/renderer/src/lib/crash-diagnostics.ts +++ b/src/renderer/src/lib/crash-diagnostics.ts @@ -59,10 +59,6 @@ export function installRendererCrashDiagnostics(surface: RendererSurface = 'main } } -export function _disposeRendererCrashDiagnosticsForTests(): void { - disposeRendererCrashDiagnostics() -} - function disposeRendererCrashDiagnostics(): void { if (!rendererCrashDiagnosticsInstalled || typeof window === 'undefined') { return diff --git a/src/renderer/src/lib/ensure-simulator-tab.ts b/src/renderer/src/lib/ensure-simulator-tab.ts index 3c363a5e4d9..af2a1c4bf8f 100644 --- a/src/renderer/src/lib/ensure-simulator-tab.ts +++ b/src/renderer/src/lib/ensure-simulator-tab.ts @@ -4,8 +4,6 @@ import { cancelPendingSimulatorPaneShutdown } from './simulator-pane-shutdown-sc import { shouldShutdownSimulatorForPaneUnmountFromTabs } from './simulator-tab-shutdown' import { translate } from '@/i18n/i18n' -export const isMacOsHost = typeof navigator !== 'undefined' && navigator.userAgent.includes('Mac') - type EnsureSimulatorTabOptions = { targetGroupId?: string placement?: 'activeGroup' | 'rightSplit' @@ -105,20 +103,4 @@ export function ensureSimulatorTab( return tab.id } -export function countSimulatorTabs( - worktreeId: string, - options: { excludingTabId?: string } = {} -): number { - return (useAppStore.getState().unifiedTabsByWorktree[worktreeId] ?? []).filter( - (tab) => tab.contentType === 'simulator' && tab.id !== options.excludingTabId - ).length -} - -export function shouldShutdownSimulatorForPaneUnmount(worktreeId: string, tabId?: string): boolean { - return shouldShutdownSimulatorForPaneUnmountFromTabs( - useAppStore.getState().unifiedTabsByWorktree[worktreeId] ?? [], - tabId - ) -} - export { shouldShutdownSimulatorForPaneUnmountFromTabs } diff --git a/src/renderer/src/lib/keyboard-layout/input-source-id.ts b/src/renderer/src/lib/keyboard-layout/input-source-id.ts index 51c1e821f7c..d9f873e76e5 100644 --- a/src/renderer/src/lib/keyboard-layout/input-source-id.ts +++ b/src/renderer/src/lib/keyboard-layout/input-source-id.ts @@ -74,7 +74,3 @@ export function classifyInputSourceId(id: string | null | undefined): InputSourc // bug from recurring for any future Apple-shipped layout. return 'compose' } - -/** Test-only: exported so tests can assert the allowlist without - * reimporting the private constant. */ -export const __metaInputSourceIdsForTests: readonly string[] = META_INPUT_SOURCE_IDS diff --git a/src/renderer/src/lib/keyboard-layout/option-as-alt-probe.ts b/src/renderer/src/lib/keyboard-layout/option-as-alt-probe.ts index cfad8c55407..c96730959db 100644 --- a/src/renderer/src/lib/keyboard-layout/option-as-alt-probe.ts +++ b/src/renderer/src/lib/keyboard-layout/option-as-alt-probe.ts @@ -204,9 +204,3 @@ export function getOptionAsAltProbe(): OptionAsAltProbe { } return _singleton } - -/** Test-only: reset the singleton. */ -export function _resetOptionAsAltProbeForTests(): void { - _singleton?.dispose() - _singleton = null -} diff --git a/src/renderer/src/lib/open-mobile-emulator-tab.test.ts b/src/renderer/src/lib/open-mobile-emulator-tab.test.ts index 77865652df5..a3d942785b1 100644 --- a/src/renderer/src/lib/open-mobile-emulator-tab.test.ts +++ b/src/renderer/src/lib/open-mobile-emulator-tab.test.ts @@ -35,8 +35,7 @@ vi.mock('sonner', () => ({ vi.mock('./ensure-simulator-tab', () => ({ ensureSimulatorTab: vi.fn(), - getSimulatorTabForWorktree: vi.fn(), - isMacOsHost: true + getSimulatorTabForWorktree: vi.fn() })) const mockAttachResult = { diff --git a/src/renderer/src/lib/repo-slug-index.ts b/src/renderer/src/lib/repo-slug-index.ts index ed1dbe5f5e1..1d5f0a7f172 100644 --- a/src/renderer/src/lib/repo-slug-index.ts +++ b/src/renderer/src/lib/repo-slug-index.ts @@ -18,7 +18,6 @@ import { useAppStore } from '@/store' import type { Repo, GlobalSettings } from '../../../shared/types' import { callRuntimeRpc, getActiveRuntimeTarget } from '@/runtime/runtime-rpc-client' import { - clearRepoSlugCacheValues, deleteRepoSlugCacheKey, nextRepoSlugFailureRetryDelay, readRepoSlugCache, @@ -69,15 +68,6 @@ export function clearRepoSlugCacheEntry(repoId: string): void { } } -/** Clear the entire slug cache. Useful for tests or full repo-list resets. */ -export function clearRepoSlugCache(): void { - clearRepoSlugCacheValues() - for (const key of slugResolutionInFlight.keys()) { - slugResolutionGeneration.set(key, (slugResolutionGeneration.get(key) ?? 0) + 1) - } - slugResolutionInFlight.clear() -} - async function resolveRepoSlug( repo: Repo, settings: Pick | null | undefined diff --git a/src/renderer/src/lib/setup-script-status.ts b/src/renderer/src/lib/setup-script-status.ts index 9f8dc0c4512..a23d0d1a06f 100644 --- a/src/renderer/src/lib/setup-script-status.ts +++ b/src/renderer/src/lib/setup-script-status.ts @@ -1,5 +1,5 @@ import { resolveHookCommandSourcePolicy } from '../../../shared/hook-command-source-policy' -import type { Repo, RepoHookSettings } from '../../../shared/types' +import type { Repo } from '../../../shared/types' import type { HookCheckResult } from '@/runtime/runtime-hooks-client' export function hasEffectiveSetupCommand(repo: Repo, hooksResult: HookCheckResult): boolean { @@ -20,28 +20,3 @@ export function hasEffectiveSetupCommand(repo: Repo, hooksResult: HookCheckResul return Boolean(sharedSetup) } - -export function buildImportedSetupHookSettings( - repo: Repo, - setup: string, - archive: string | undefined, - hasSharedHooks: boolean, - defaults: RepoHookSettings -): RepoHookSettings { - const current = repo.hookSettings - return { - ...defaults, - ...current, - setupRunPolicy: current?.setupRunPolicy ?? defaults.setupRunPolicy, - // Why: imported setup commands are stored as local settings. If a shared - // hook file exists, run-both preserves its archive hook; otherwise local - // settings need to be authoritative so the imported setup actually runs. - commandSourcePolicy: hasSharedHooks ? 'run-both' : 'local-only', - scripts: { - ...defaults.scripts, - ...current?.scripts, - setup, - archive: archive ?? current?.scripts?.archive ?? defaults.scripts.archive - } - } -} diff --git a/src/renderer/src/lib/workspace-port-actions.ts b/src/renderer/src/lib/workspace-port-actions.ts index 06970100cfd..07643a186a8 100644 --- a/src/renderer/src/lib/workspace-port-actions.ts +++ b/src/renderer/src/lib/workspace-port-actions.ts @@ -148,24 +148,6 @@ export async function openWorkspacePortInBrowser(args: { return { ok: true } } -export async function refreshWorkspacePortScanState(args: { - runtimeTarget: RuntimeClientTarget - setWorkspacePortScan: WorkspacePortScanSetter - setWorkspacePortScanRefreshing: WorkspacePortScanRefreshingSetter -}): Promise { - args.setWorkspacePortScanRefreshing(true) - try { - const scan = await scanWorkspacePortsForTarget(args.runtimeTarget) - args.setWorkspacePortScan({ - key: workspacePortScanKeyForTarget(args.runtimeTarget), - result: scan - }) - return scan - } finally { - args.setWorkspacePortScanRefreshing(false) - } -} - export async function refreshWorkspacePortScanAfterStop(args: { runtimeTarget: RuntimeClientTarget setWorkspacePortScan: WorkspacePortScanSetter diff --git a/src/renderer/src/store/slices/runtime-detected-agents.ts b/src/renderer/src/store/slices/runtime-detected-agents.ts index 7da5bef6da9..466c131f4e7 100644 --- a/src/renderer/src/store/slices/runtime-detected-agents.ts +++ b/src/renderer/src/store/slices/runtime-detected-agents.ts @@ -35,10 +35,6 @@ export function _getRuntimeDetectPromiseCountForTest(): number { return runtimeDetectPromises.size } -export function _getRuntimeRefreshPromiseCountForTest(): number { - return runtimeRefreshPromises.size -} - export const createRuntimeDetectedAgentsSlice: StateCreator< AppState, [], diff --git a/src/shared/agent-session-host-authority.ts b/src/shared/agent-session-host-authority.ts index bd138cefd62..96e079afb63 100644 --- a/src/shared/agent-session-host-authority.ts +++ b/src/shared/agent-session-host-authority.ts @@ -28,8 +28,6 @@ export const AGENT_SESSION_RPC_ERROR_CODES = [ 'execution_owner_unavailable' ] as const -export type AgentSessionRpcErrorCode = (typeof AGENT_SESSION_RPC_ERROR_CODES)[number] - export const AGENT_SESSION_CLAIM_DIGEST_VERSION = 1 as const export const AGENT_SESSION_EXECUTION_OWNER_PROTOCOL_VERSION = 2 as const diff --git a/src/shared/agent-session-option-catalog.ts b/src/shared/agent-session-option-catalog.ts index b5520afaa51..6ba6ee65043 100644 --- a/src/shared/agent-session-option-catalog.ts +++ b/src/shared/agent-session-option-catalog.ts @@ -49,14 +49,6 @@ export function findCatalogOption( return model?.options.find((option) => option.id === optionId) } -export function catalogDefaultModel(catalog: AgentSessionOptionCatalog): CatalogModel | undefined { - return catalog.models.find((model) => model.isDefault) ?? catalog.models[0] -} - -export function catalogDefaultValues(model: CatalogModel): Record { - return Object.fromEntries(model.options.map((option) => [option.id, option.kind.defaultValue])) -} - /** Merge live rows over the static seed while retaining only option shapes Orca * can actually map. Newly discovered ids remain model-only until cataloged. */ export function mergeCatalogModels( diff --git a/src/shared/commit-message-generation.ts b/src/shared/commit-message-generation.ts index cd3f8d72a62..3c5c92ad835 100644 --- a/src/shared/commit-message-generation.ts +++ b/src/shared/commit-message-generation.ts @@ -11,14 +11,6 @@ export type CommitMessageDraftContext = { linkedIssue?: number | null } -export type CommitMessageDraftOptions = { - agentId: CommitMessageDraftAgent - model: string - thinkingLevel?: string - customPrompt?: string - customAgentCommand?: string -} - export type GeneratedCommitMessage = { subject: string body: string diff --git a/src/shared/custom-pet-media-limits.ts b/src/shared/custom-pet-media-limits.ts deleted file mode 100644 index f3778069e40..00000000000 --- a/src/shared/custom-pet-media-limits.ts +++ /dev/null @@ -1,19 +0,0 @@ -export const MAX_CUSTOM_PET_FILE_BYTES = 64 * 1024 * 1024 - -// Why: sprite processing holds decoded image, canvas, ImageData, PNG, and -// optional bitmap copies at once, so encoded bytes alone are not a safe bound. -export const MAX_CUSTOM_PET_SHEET_PIXELS = 4 * 1024 * 1024 -export const MAX_CUSTOM_PET_SHEET_DIMENSION = 8_192 -export const MAX_CUSTOM_PET_DETECTED_FRAMES = 128 - -export function isCustomPetSheetSizeSafe(width: number, height: number): boolean { - return ( - Number.isSafeInteger(width) && - Number.isSafeInteger(height) && - width > 0 && - height > 0 && - width <= MAX_CUSTOM_PET_SHEET_DIMENSION && - height <= MAX_CUSTOM_PET_SHEET_DIMENSION && - width * height <= MAX_CUSTOM_PET_SHEET_PIXELS - ) -} diff --git a/src/shared/daemon-audit-eligibility.ts b/src/shared/daemon-audit-eligibility.ts index 5e3bde6fcd0..4e89af300eb 100644 --- a/src/shared/daemon-audit-eligibility.ts +++ b/src/shared/daemon-audit-eligibility.ts @@ -69,7 +69,6 @@ export const DAEMON_AUDIT_PROCESS_REASON_VALUES = [ 'windows_named_pipe_missing' ] as const -export type DaemonAuditState = (typeof DAEMON_AUDIT_STATE_VALUES)[number] export type DaemonAuditTrigger = (typeof DAEMON_AUDIT_TRIGGER_VALUES)[number] export type DaemonAuditFailureTrigger = Exclude export type DaemonEvidenceSource = (typeof DAEMON_EVIDENCE_SOURCE_VALUES)[number] diff --git a/src/shared/daemon-lifecycle-telemetry.ts b/src/shared/daemon-lifecycle-telemetry.ts index 5904195316a..1ec13c985f6 100644 --- a/src/shared/daemon-lifecycle-telemetry.ts +++ b/src/shared/daemon-lifecycle-telemetry.ts @@ -17,13 +17,11 @@ export const DAEMON_RETIRE_REASONS = ['died_respawn'] as const export type DaemonRetireReason = (typeof DAEMON_RETIRE_REASONS)[number] export const DAEMON_LIFECYCLE_TRANSITIONS = ['replaced', 'retired'] as const -export type DaemonLifecycleTransition = (typeof DAEMON_LIFECYCLE_TRANSITIONS)[number] export const DAEMON_LIFECYCLE_REASONS = [ ...DAEMON_REPLACE_REASONS, ...DAEMON_RETIRE_REASONS ] as const -export type DaemonLifecycleReason = (typeof DAEMON_LIFECYCLE_REASONS)[number] // Bucketed, never raw: exact live-session counts could fingerprint heavy users. `unknown` when // the count couldn't be verified (null) — e.g. a wedged daemon or an already-dead respawn target. diff --git a/src/shared/ephemeral-vm-recipes.ts b/src/shared/ephemeral-vm-recipes.ts index 071f1e89c46..9cb4349d928 100644 --- a/src/shared/ephemeral-vm-recipes.ts +++ b/src/shared/ephemeral-vm-recipes.ts @@ -1,10 +1,6 @@ import { z } from 'zod' import { parsePairingCode } from './pairing' -import { - DEFAULT_SSH_RELAY_GRACE_PERIOD_SECONDS, - MAX_SSH_RELAY_GRACE_PERIOD_SECONDS, - MIN_SSH_RELAY_GRACE_PERIOD_SECONDS -} from './ssh-types' +import { MAX_SSH_RELAY_GRACE_PERIOD_SECONDS, MIN_SSH_RELAY_GRACE_PERIOD_SECONDS } from './ssh-types' import { assertJsonTextStructureWithinLimits } from './json-text-structure-limit' const JsonValueSchema: z.ZodType = z.lazy(() => @@ -67,8 +63,6 @@ export const EphemeralVmRecipeSshTargetSchema = z }) .strict() -export type EphemeralVmRecipeSshTarget = z.infer - const EphemeralVmRecipeOrcaServerConnectionSchema = z .object({ type: z.literal('orca-server'), @@ -114,10 +108,6 @@ export const EphemeralVmRecipeResultSchema = z.union([ EphemeralVmRecipeConnectionResultSchema ]) -export type EphemeralVmRecipeLegacyResult = z.infer -export type EphemeralVmRecipeConnectionResult = z.infer< - typeof EphemeralVmRecipeConnectionResultSchema -> export type EphemeralVmRecipeResult = z.infer export type EphemeralVmRecipeResultParseResult = @@ -190,16 +180,6 @@ export function getEphemeralVmRecipeResultPairingCode( return connection.type === 'orca-server' ? connection.pairingCode : null } -export function getEphemeralVmRecipeResultUserData( - result: EphemeralVmRecipeResult -): Record | undefined { - return result.userData -} - -export function getDefaultSshRelayGracePeriodSeconds(): number { - return DEFAULT_SSH_RELAY_GRACE_PERIOD_SECONDS -} - export function isAbsoluteRuntimePath(path: string): boolean { return ( path.startsWith('/') || diff --git a/src/shared/ephemeral-vm-runtimes.ts b/src/shared/ephemeral-vm-runtimes.ts index 517897fcd44..196c3e08184 100644 --- a/src/shared/ephemeral-vm-runtimes.ts +++ b/src/shared/ephemeral-vm-runtimes.ts @@ -27,10 +27,6 @@ export type EphemeralVmCleanupStatus = z.infer - const EphemeralVmRuntimeRecipeSchema = z .object({ id: z.string().min(1), diff --git a/src/shared/folder-workspaces.ts b/src/shared/folder-workspaces.ts index 9798db1f67d..675117dd3eb 100644 --- a/src/shared/folder-workspaces.ts +++ b/src/shared/folder-workspaces.ts @@ -1,4 +1,4 @@ -import type { FolderWorkspace, FolderWorkspaceLinkedTask, ProjectGroup } from './types' +import type { FolderWorkspace, ProjectGroup } from './types' import { isTuiAgent } from './tui-agent-config' import { normalizeStoredTaskSourceContext } from './task-source-context' import { normalizeWorkspaceLinkedItem } from './workspace-linked-item' @@ -12,12 +12,6 @@ export function normalizeFolderWorkspaceName( return trimmed.length > 0 ? trimmed : fallback } -export function normalizeFolderWorkspaceLinkedTask( - value: unknown -): FolderWorkspaceLinkedTask | null { - return normalizeWorkspaceLinkedItem(value) -} - export function normalizeFolderWorkspaces( value: unknown, projectGroups: readonly ProjectGroup[] diff --git a/src/shared/hermes-run-output-limits.ts b/src/shared/hermes-run-output-limits.ts index 99d16feaff0..d456effe8a8 100644 --- a/src/shared/hermes-run-output-limits.ts +++ b/src/shared/hermes-run-output-limits.ts @@ -1,8 +1,6 @@ -export const HERMES_PRIMARY_OUTPUT_MAX_BYTES = 5 * 1024 * 1024 export const HERMES_SESSION_TRANSCRIPT_MAX_BYTES = 8 * 1024 * 1024 export const HERMES_SESSION_TRANSCRIPT_MAX_MESSAGES = 10_000 export const HERMES_RUN_PAGE_MAX_RETAINED_BYTES = 32 * 1024 * 1024 -export const HERMES_RUN_PAGE_MAX_RUNS = 100 export const HERMES_RUN_HYDRATION_CONCURRENCY = 2 export const HERMES_SESSION_RUN_METADATA_MAX_BYTES = 16 * 1024 export const HERMES_RUN_PAGE_OUTPUT_OMITTED_ERROR = @@ -10,7 +8,6 @@ export const HERMES_RUN_PAGE_OUTPUT_OMITTED_ERROR = export const HERMES_SESSION_TRANSCRIPT_TRUNCATED_ERROR = 'Session transcript truncated because it exceeds the 8 MiB or 10,000-message history limit' -const HERMES_SESSION_TRANSCRIPT_FIELD_MAX_BYTES = HERMES_SESSION_TRANSCRIPT_MAX_BYTES + 1 const HERMES_SESSION_TRANSCRIPT_TRUNCATION_NOTICE = `[${HERMES_SESSION_TRANSCRIPT_TRUNCATED_ERROR}.]` const HERMES_SESSION_TRANSCRIPT_SOURCE_TRUNCATED_COLUMN = 'orca_source_truncated' @@ -29,24 +26,6 @@ export const HERMES_SESSION_RUN_SELECT_SQL = `SELECT FROM sessions WHERE id = ?` -export const HERMES_SESSION_TRANSCRIPT_SELECT_SQL = `SELECT - CAST(substr(CAST(role AS BLOB), 1, ${HERMES_SESSION_TRANSCRIPT_FIELD_MAX_BYTES}) AS TEXT) AS role, - CAST(substr(CAST(content AS BLOB), 1, ${HERMES_SESSION_TRANSCRIPT_FIELD_MAX_BYTES}) AS TEXT) AS content, - CAST(substr(CAST(tool_name AS BLOB), 1, ${HERMES_SESSION_TRANSCRIPT_FIELD_MAX_BYTES}) AS TEXT) AS tool_name, - CAST(substr(CAST(reasoning AS BLOB), 1, ${HERMES_SESSION_TRANSCRIPT_FIELD_MAX_BYTES}) AS TEXT) AS reasoning, - CAST(substr(CAST(reasoning_content AS BLOB), 1, ${HERMES_SESSION_TRANSCRIPT_FIELD_MAX_BYTES}) AS TEXT) AS reasoning_content, - CASE WHEN - length(CAST(role AS BLOB)) > ${HERMES_SESSION_TRANSCRIPT_MAX_BYTES} - OR length(CAST(content AS BLOB)) > ${HERMES_SESSION_TRANSCRIPT_MAX_BYTES} - OR length(CAST(tool_name AS BLOB)) > ${HERMES_SESSION_TRANSCRIPT_MAX_BYTES} - OR length(CAST(reasoning AS BLOB)) > ${HERMES_SESSION_TRANSCRIPT_MAX_BYTES} - OR length(CAST(reasoning_content AS BLOB)) > ${HERMES_SESSION_TRANSCRIPT_MAX_BYTES} - THEN 1 ELSE 0 END AS ${HERMES_SESSION_TRANSCRIPT_SOURCE_TRUNCATED_COLUMN} -FROM messages -WHERE session_id = ? -ORDER BY timestamp, id -LIMIT ${HERMES_SESSION_TRANSCRIPT_MAX_MESSAGES + 1}` - type HermesRunPageLimits = { maxConcurrent?: number maxRetainedBytes?: number diff --git a/src/shared/hermes-run-ref-retention.ts b/src/shared/hermes-run-ref-retention.ts index 15aaefe3b13..6d4834db320 100644 --- a/src/shared/hermes-run-ref-retention.ts +++ b/src/shared/hermes-run-ref-retention.ts @@ -1,14 +1,6 @@ export const HERMES_RUN_REF_MAX_ENTRIES = 10_000 export const HERMES_RUN_REF_ID_MAX_BYTES = 4 * 1024 -export const HERMES_SESSION_RUN_REFS_SELECT_SQL = `SELECT - CASE WHEN length(CAST(id AS BLOB)) <= ${HERMES_RUN_REF_ID_MAX_BYTES} THEN id ELSE NULL END AS id, - CASE WHEN typeof(started_at) IN ('integer', 'real') THEN started_at ELSE NULL END AS started_at -FROM sessions -WHERE id LIKE ? ESCAPE '\\' -ORDER BY started_at DESC -LIMIT ${HERMES_RUN_REF_MAX_ENTRIES + 1}` - export type HermesSortableRunRef = { id: string run_at: string | null diff --git a/src/shared/hosted-review.ts b/src/shared/hosted-review.ts index da6584fe574..90a97d0afb9 100644 --- a/src/shared/hosted-review.ts +++ b/src/shared/hosted-review.ts @@ -202,14 +202,6 @@ export type HostedReviewQueueSummary = { draft?: boolean } -export type HostedReviewQueueKey = - | 'mine' - | 'requested' - | 'agent' - | 'teammate' - | 'needs-response' - | 'ready-to-merge' - export type HostedReviewQueueState = 'mine' | 'requested' | 'agent' | 'teammate' export type HostedReviewQueueClassification = { diff --git a/src/shared/html-to-pdf-memory-limit.ts b/src/shared/html-to-pdf-memory-limit.ts deleted file mode 100644 index 061d60eb430..00000000000 --- a/src/shared/html-to-pdf-memory-limit.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { measureUtf8ByteLength } from './utf8-byte-limits' - -export const HTML_TO_PDF_MAX_INPUT_BYTES = 32 * 1024 * 1024 -export const HTML_TO_PDF_MEMORY_LIMIT_ERROR = 'HTML export exceeds the PDF memory limit' - -export function assertHtmlToPdfInputWithinMemoryLimit( - html: string, - maxBytes = HTML_TO_PDF_MAX_INPUT_BYTES -): void { - if (measureUtf8ByteLength(html, { stopAfterBytes: maxBytes }).exceededLimit) { - throw new Error(HTML_TO_PDF_MEMORY_LIMIT_ERROR) - } -} diff --git a/src/shared/left-sidebar-appearance.ts b/src/shared/left-sidebar-appearance.ts index bb77476ba36..8b2f6c58739 100644 --- a/src/shared/left-sidebar-appearance.ts +++ b/src/shared/left-sidebar-appearance.ts @@ -1,5 +1,4 @@ import { HEX_COLOR_RE } from './color-validation' -import type { LeftSidebarAppearanceMode } from './types' export const LEFT_SIDEBAR_APPEARANCE_MODES = ['default', 'match-terminal', 'tinted'] as const @@ -7,12 +6,6 @@ export const DEFAULT_LEFT_SIDEBAR_TINT_COLOR = '#18181b' export const DEFAULT_LEFT_SIDEBAR_TINT_OPACITY = 0.08 export const MAX_LEFT_SIDEBAR_TINT_OPACITY = 0.35 -export function normalizeLeftSidebarAppearanceMode(value: unknown): LeftSidebarAppearanceMode { - return LEFT_SIDEBAR_APPEARANCE_MODES.includes(value as LeftSidebarAppearanceMode) - ? (value as LeftSidebarAppearanceMode) - : 'default' -} - export function normalizeLeftSidebarTintColor(value: unknown): string { if (typeof value !== 'string') { return DEFAULT_LEFT_SIDEBAR_TINT_COLOR diff --git a/src/shared/linear-agent-access.ts b/src/shared/linear-agent-access.ts index eb49dee4af4..2ffa17cb406 100644 --- a/src/shared/linear-agent-access.ts +++ b/src/shared/linear-agent-access.ts @@ -109,11 +109,6 @@ export type LinearWriteTargetRequest = { context?: LinearCurrentIssueContextHints } -export type LinearTeamDiscoveryRequest = { - teamInput?: string - workspaceId?: string | 'all' -} - export type LinearIssueListFilter = 'assigned' | 'created' | 'all' | 'completed' | 'open' export type LinearIssueListRequest = { diff --git a/src/shared/linux-proc-port-scan-limits.ts b/src/shared/linux-proc-port-scan-limits.ts index dd1f9fd5c6e..af6148cd283 100644 --- a/src/shared/linux-proc-port-scan-limits.ts +++ b/src/shared/linux-proc-port-scan-limits.ts @@ -1,7 +1,6 @@ import { readNodeFileWithinLimit } from './node-bounded-file-reader' export const LINUX_PROC_NETWORK_TABLE_MAX_BYTES = 8 * 1024 * 1024 -export const LINUX_PROC_LISTENING_SOCKET_MAX_ENTRIES = 2_048 export const LINUX_PROC_PROCESS_METADATA_MAX_BYTES = 8 * 1024 * 1024 export const LINUX_PROC_PROCESS_METADATA_FILE_MAX_BYTES = 64 * 1024 diff --git a/src/shared/native-file-drop.ts b/src/shared/native-file-drop.ts index 101dfd37d83..4a7ee1860d1 100644 --- a/src/shared/native-file-drop.ts +++ b/src/shared/native-file-drop.ts @@ -135,14 +135,6 @@ export function resolveNativeFileDropPath( return null } -export function measureNativeFileDropPathBytes(paths: readonly string[]): number { - let byteLength = 0 - for (const path of paths) { - byteLength += measureClipboardTextByteLength(path).byteLength - } - return byteLength -} - export function validateNativeFileDropPaths( paths: readonly string[], options: { diff --git a/src/shared/persisted-state-file-bounds.ts b/src/shared/persisted-state-file-bounds.ts index 4fe8a977bb3..8ad92c95435 100644 --- a/src/shared/persisted-state-file-bounds.ts +++ b/src/shared/persisted-state-file-bounds.ts @@ -1,11 +1,7 @@ import { randomUUID, type Hash } from 'node:crypto' import { mkdirSync, renameSync, rmSync, writeFileSync } from 'node:fs' import { dirname } from 'node:path' -import { - NodeFileReadTooLargeError, - readNodeFileSyncWithinLimit, - type BoundedNodeFileRead -} from './node-bounded-file-reader' +import { readNodeFileSyncWithinLimit, type BoundedNodeFileRead } from './node-bounded-file-reader' import { JsonStringifyByteLimitError, stringifyJsonWithinByteLimit @@ -38,12 +34,6 @@ export class PersistedStateSecretCapacityError extends Error { } } -export function isPersistedStateFileCapacityError( - error: unknown -): error is NodeFileReadTooLargeError { - return error instanceof NodeFileReadTooLargeError -} - export function readPersistedStateJsonFileSync( filePath: string, maxBytes = ORCA_PERSISTED_STATE_MAX_BYTES, @@ -86,14 +76,6 @@ export function stringifyPrettyPersistedStateWithinLimit( return stringifyJsonWithinByteLimit(value, maxBytes, 2) } -export function encodePersistedStateJsonStringContent( - value: string, - maxBytes = ORCA_PERSISTED_STATE_MAX_BYTES -): string { - const { serialized } = stringifyJsonWithinByteLimit(value, maxBytes) - return serialized.slice(1, -1) -} - export function assertPersistedStateSecretWithinLimit( value: string, maxBytes = ORCA_PERSISTED_STATE_SECRET_MAX_BYTES diff --git a/src/shared/pr-refresh-memory-limits.ts b/src/shared/pr-refresh-memory-limits.ts deleted file mode 100644 index 8b695adede7..00000000000 --- a/src/shared/pr-refresh-memory-limits.ts +++ /dev/null @@ -1,5 +0,0 @@ -export const PR_REFRESH_QUEUE_ENTRY_LIMIT = 1_024 -export const PR_REFRESH_ALIAS_LIMIT = 64 -export const PR_REFRESH_VISIBLE_CANDIDATE_LIMIT = 1_024 -export const PR_REFRESH_RETRY_STATE_LIMIT = 1_024 -export const PR_REFRESH_ACTIVE_SCOPE_LIMIT = 1_024 diff --git a/src/shared/pty-source-credit-contract.ts b/src/shared/pty-source-credit-contract.ts index a97b66ec4a2..4c3a643b32c 100644 --- a/src/shared/pty-source-credit-contract.ts +++ b/src/shared/pty-source-credit-contract.ts @@ -1,4 +1,3 @@ -export const PTY_SOURCE_CREDIT_VERSION = 1 export const DEFAULT_PTY_SOURCE_WINDOW_SU = 256 * 1024 export const MAX_PTY_ACK_ENTRIES = 64 diff --git a/src/shared/relay-json-admission.ts b/src/shared/relay-json-admission.ts deleted file mode 100644 index a9d256ba904..00000000000 --- a/src/shared/relay-json-admission.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { assertJsonTextStructureWithinLimits } from './json-text-structure-limit' - -export const RELAY_JSON_MAX_STRUCTURAL_TOKENS = 1_000_000 -export const RELAY_JSON_MAX_NESTING_DEPTH = 128 - -export function parseRelayJsonText(text: string): T { - assertJsonTextStructureWithinLimits(text, { - structuralTokens: RELAY_JSON_MAX_STRUCTURAL_TOKENS, - nestingDepth: RELAY_JSON_MAX_NESTING_DEPTH - }) - return JSON.parse(text) as T -} diff --git a/src/shared/remote-runtime-memory-limits.ts b/src/shared/remote-runtime-memory-limits.ts index 62cb62d03cf..8152f58ef66 100644 --- a/src/shared/remote-runtime-memory-limits.ts +++ b/src/shared/remote-runtime-memory-limits.ts @@ -17,7 +17,6 @@ export const REMOTE_RUNTIME_MAX_PROCESS_PENDING_RPC_BYTES = REMOTE_RUNTIME_MAX_P export const REMOTE_RUNTIME_MAX_READY_WAITERS = REMOTE_RUNTIME_MAX_PENDING_REQUESTS + REMOTE_RUNTIME_MAX_SUBSCRIPTIONS export const REMOTE_RUNTIME_MAX_OUTBOUND_BINARY_FRAME_BYTES = 8 * 1024 * 1024 -export const REMOTE_RUNTIME_MAX_SUBSCRIPTION_ID_BYTES = 4 * 1024 export function serializeRemoteRuntimePayload(value: unknown): string { try { diff --git a/src/shared/remote-runtime-shared-control-state.ts b/src/shared/remote-runtime-shared-control-state.ts index 4f62d8298ff..c74c50916c9 100644 --- a/src/shared/remote-runtime-shared-control-state.ts +++ b/src/shared/remote-runtime-shared-control-state.ts @@ -77,22 +77,6 @@ export function refreshSharedControlPendingRequestTimeouts( } } -export function waitForSharedControlReady(ready: Promise, timeoutMs: number): Promise { - return new Promise((resolve, reject) => { - const timeout = setTimeout(() => reject(remoteRuntimeUnavailableError()), timeoutMs) - void ready.then( - () => { - clearTimeout(timeout) - resolve() - }, - (error) => { - clearTimeout(timeout) - reject(error) - } - ) - }) -} - export function rejectAllSharedControlPendingRequests( pendingRequests: Map>, error?: Error diff --git a/src/shared/remote-workspace-types.ts b/src/shared/remote-workspace-types.ts index 419bb765116..3c08f272864 100644 --- a/src/shared/remote-workspace-types.ts +++ b/src/shared/remote-workspace-types.ts @@ -31,11 +31,6 @@ export type RemoteWorkspaceConnectedClient = { isCurrent?: boolean } -export type RemoteWorkspacePatch = { - kind: 'replace-session' - session: RemoteWorkspaceSession -} - export type RemoteWorkspacePatchResult = | { ok: true diff --git a/src/shared/runtime-bootstrap.ts b/src/shared/runtime-bootstrap.ts index efa224d749b..993ab5e023d 100644 --- a/src/shared/runtime-bootstrap.ts +++ b/src/shared/runtime-bootstrap.ts @@ -1,5 +1,4 @@ import { join } from 'node:path' -import { assertJsonTextStructureWithinLimits } from './json-text-structure-limit' export type RuntimeTransportMetadata = | { @@ -23,18 +22,6 @@ export type RuntimeMetadata = { startedAt: number } -export const MAX_RUNTIME_METADATA_FILE_BYTES = 64 * 1024 -export const MAX_RUNTIME_METADATA_JSON_STRUCTURAL_TOKENS = 16 * 1024 -export const MAX_RUNTIME_METADATA_JSON_NESTING_DEPTH = 32 - -export function parseRuntimeMetadataJson(serialized: string): RuntimeMetadata { - assertJsonTextStructureWithinLimits(serialized, { - structuralTokens: MAX_RUNTIME_METADATA_JSON_STRUCTURAL_TOKENS, - nestingDepth: MAX_RUNTIME_METADATA_JSON_NESTING_DEPTH - }) - return JSON.parse(serialized) as RuntimeMetadata -} - // Why: the CLI must handle metadata files written by older Orca versions that // used a singular `transport` field. This helper extracts the first transport // matching the given kinds from either the new `transports` array or the diff --git a/src/shared/runtime-environments.ts b/src/shared/runtime-environments.ts index 131414631c2..f1cfd64085b 100644 --- a/src/shared/runtime-environments.ts +++ b/src/shared/runtime-environments.ts @@ -10,8 +10,6 @@ export const RuntimeAccessEndpointSchema = z.object({ publicKeyB64: z.string().min(1) }) -export type RuntimeAccessEndpoint = z.infer - export const PublicRuntimeAccessEndpointSchema = RuntimeAccessEndpointSchema.omit({ deviceToken: true, publicKeyB64: true diff --git a/src/shared/runtime-types.ts b/src/shared/runtime-types.ts index d0f98e68360..c357ff63d45 100644 --- a/src/shared/runtime-types.ts +++ b/src/shared/runtime-types.ts @@ -545,10 +545,6 @@ export type RuntimeTerminalOrphanAdoptionResult = { snapshot: RuntimeMobileSessionTabsResult } -export type RuntimeWorktreeTerminalSleepFailure = - | 'terminal_liveness_unavailable' - | 'terminal_worktree_sleep_still_live' - export type RuntimeWorktreeTerminalSleepResult = { stopped: number stoppedPtyIds: string[] @@ -1194,18 +1190,10 @@ export type BrowserCaptureStopResult = { stopped: boolean } -export type BrowserExecResult = { - output: unknown -} - export type BrowserTabCreateResult = { browserPageId: string } -export type BrowserTabCloseResult = { - closed: boolean -} - export type BrowserErrorCode = | 'browser_no_tab' | 'browser_tab_not_found' @@ -1222,13 +1210,6 @@ export type BrowserErrorCode = | 'browser_timeout' | 'browser_error' -export type EmulatorErrorCode = - | 'emulator_no_active' - | 'emulator_device_not_found' - | 'emulator_helper_failed' - | 'emulator_not_macos' - | 'emulator_error' - // Keep the broad runtime-types import surface stable while letting computer-use // CI watch a narrow contract file instead of every runtime type change. export * from './computer-use-runtime-types' diff --git a/src/shared/serve-update-handoff.ts b/src/shared/serve-update-handoff.ts index 3dddd2a38da..4d2e1934852 100644 --- a/src/shared/serve-update-handoff.ts +++ b/src/shared/serve-update-handoff.ts @@ -1,11 +1,7 @@ import { join } from 'node:path' -import { assertJsonTextStructureWithinLimits } from './json-text-structure-limit' export const SERVE_UPDATE_HANDOFF_PATH_ENV = 'ORCA_SERVE_UPDATE_HANDOFF_PATH' export const SERVE_UPDATE_HANDOFF_FILE = 'serve-update-handoff.json' -export const MAX_SERVE_UPDATE_HANDOFF_FILE_BYTES = 64 * 1024 -export const MAX_SERVE_UPDATE_HANDOFF_JSON_STRUCTURAL_TOKENS = 16 * 1024 -export const MAX_SERVE_UPDATE_HANDOFF_JSON_NESTING_DEPTH = 32 export type ServeUpdateHandoffState = | { @@ -65,14 +61,6 @@ export function parseServeUpdateHandoffState(value: unknown): ServeUpdateHandoff return state as ServeUpdateHandoffState } -export function parseServeUpdateHandoffJson(serialized: string): ServeUpdateHandoffState | null { - assertJsonTextStructureWithinLimits(serialized, { - structuralTokens: MAX_SERVE_UPDATE_HANDOFF_JSON_STRUCTURAL_TOKENS, - nestingDepth: MAX_SERVE_UPDATE_HANDOFF_JSON_NESTING_DEPTH - }) - return parseServeUpdateHandoffState(JSON.parse(serialized)) -} - export function parseServeSupervisorMessage(value: unknown): ServeSupervisorMessage | null { if (!value || typeof value !== 'object') { return null diff --git a/src/shared/source-control-create-review-intent.ts b/src/shared/source-control-create-review-intent.ts index b7266708b25..45ee2210c7e 100644 --- a/src/shared/source-control-create-review-intent.ts +++ b/src/shared/source-control-create-review-intent.ts @@ -2,7 +2,6 @@ import { isBehindOnlyUpstream, shouldForcePushWithLeaseForUpstream } from './git import type { HostedReviewCreationEligibility } from './hosted-review' import { supportsHostedReviewCreation } from './hosted-review-creation-providers' import type { GitUpstreamStatus } from './git-status-types' -import type { SourceControlPrimaryActionDecision } from './source-control-primary-action-decision-types' export type CreateReviewIntentKind = | 'dirty' @@ -91,13 +90,3 @@ export function resolveCreateReviewIntentEligibility({ return { eligible: false, kind: null } } - -export function resolveVisibleCreateReviewHeaderAction({ - createPrHeaderAction -}: { - createPrHeaderAction: SourceControlPrimaryActionDecision | null -}): SourceControlPrimaryActionDecision | null { - // Why: keep a stable header anchor; disable Create Review when the branch is - // not ready instead of hiding it and shifting toolbar layout. - return createPrHeaderAction -} diff --git a/src/shared/ssh-retained-payload-admission.ts b/src/shared/ssh-retained-payload-admission.ts index cc173c577d5..ba018eb0f5b 100644 --- a/src/shared/ssh-retained-payload-admission.ts +++ b/src/shared/ssh-retained-payload-admission.ts @@ -10,7 +10,6 @@ import { clampUtf8TextPrefix, measureUtf8ByteLength } from './utf8-byte-limits' export const SSH_RETAINED_IDENTIFIER_MAX_UTF8_BYTES = 1024 export const SSH_CONNECTION_ERROR_MAX_UTF8_BYTES = 16 * 1024 export const SSH_PROVIDER_EPOCH_MAX_UTF8_BYTES = 128 -export const SSH_CREDENTIAL_DETAIL_MAX_UTF8_BYTES = 16 * 1024 export const SSH_DETECTED_PORTS_MAX_ENTRIES = 50 export const SSH_DETECTED_PORT_HOST_MAX_UTF8_BYTES = 1024 export const SSH_DETECTED_PORT_PROCESS_NAME_MAX_UTF8_BYTES = 4 * 1024 diff --git a/src/shared/task-source-context.ts b/src/shared/task-source-context.ts index 38e1fb3388f..e1576e2de92 100644 --- a/src/shared/task-source-context.ts +++ b/src/shared/task-source-context.ts @@ -192,12 +192,6 @@ export function buildWorkspaceRunContext(args: { } } -export function getWorkspaceRunRuntimeSettings( - context: Pick | null | undefined -): Pick { - return getTaskSourceRuntimeSettings(context ? { hostId: context.hostId } : null) -} - function getRepoHostId(repo: Pick): ExecutionHostId { const explicit = normalizeExecutionHostId(repo.executionHostId) if (explicit) { diff --git a/src/shared/telemetry-events.ts b/src/shared/telemetry-events.ts index bcf92ef54bc..18f7cd8986f 100644 --- a/src/shared/telemetry-events.ts +++ b/src/shared/telemetry-events.ts @@ -124,7 +124,6 @@ export const addRepoSetupStepActionSchema = z.enum([ 'open_existing', 'back' ]) -export type AddRepoSetupStepAction = z.infer export const addRepoExistingWorkspaceSourceSchema = z.enum([ 'local_folder_picker', @@ -164,7 +163,6 @@ export const addRepoDefaultCheckoutHandoffReasonSchema = z.enum([ ]) export const setupScriptImportProviderSchema = z.enum(SETUP_SCRIPT_IMPORT_PROVIDERS) -export type SetupScriptImportProviderTelemetry = z.infer // Separate enum from `errorClassSchema` — different domain (git/filesystem worktree-create failures); merging would couple the two forever. export const workspaceCreateErrorClassSchema = z.enum([ @@ -215,7 +213,6 @@ export const featureWallTileIdSchema = z.enum([ 'tile-11', 'tile-12' ]) -export type FeatureWallTileIdTelemetry = z.infer export const featureWallOpenSourceSchema = z.enum(['help_menu', 'popup', 'onboarding', 'unknown']) export type FeatureWallOpenSourceTelemetry = z.infer @@ -227,13 +224,10 @@ export const featureWallWorkflowIdSchema = z.enum([ 'workbench', 'review' ]) -export type FeatureWallWorkflowIdTelemetry = z.infer export const featureWallTourDepthStepSchema = z.enum(FEATURE_WALL_TOUR_DEPTH_STEPS) -export type FeatureWallTourDepthStepTelemetry = z.infer export const featureWallExitActionSchema = z.enum(FEATURE_WALL_EXIT_ACTIONS) -export type FeatureWallExitActionTelemetry = z.infer // `env_var` absent — env-var/CI paths override consent at runtime only, never firing an opt-in/out event. // `first_launch_notice` absent — the new-user cohort has no first-launch surface; those opt-outs come via `'settings'`. @@ -1542,7 +1536,6 @@ function eventsWithShapeKey(key: string): ReadonlySet { // Cohort injection is gated on this derived set because `.strict()` schemas drop events that don't declare `nth_repo_added`. const COHORT_EXTENDED_SET = eventsWithShapeKey('nth_repo_added') -export const COHORT_EXTENDED: readonly EventName[] = Array.from(COHORT_EXTENDED_SET) // Compile-time roster guarding the runtime injection set against silent schema drift. type _CohortExtendedRoster = diff --git a/src/shared/terminal-custom-themes.ts b/src/shared/terminal-custom-themes.ts index df6b15f5745..f91b7d8e22e 100644 --- a/src/shared/terminal-custom-themes.ts +++ b/src/shared/terminal-custom-themes.ts @@ -15,8 +15,6 @@ export type TerminalCustomTheme = { unsupportedFeatures?: string[] } -export type TerminalThemeSelection = string - export type WarpThemeImportSource = | { kind: 'auto' } | { kind: 'chooseFile' } diff --git a/src/shared/terminal-scrollback-policy.ts b/src/shared/terminal-scrollback-policy.ts index 3c831234113..0e8753593e9 100644 --- a/src/shared/terminal-scrollback-policy.ts +++ b/src/shared/terminal-scrollback-policy.ts @@ -4,10 +4,6 @@ export const DESKTOP_TERMINAL_SCROLLBACK_ROWS_MAX = 50_000 export const DESKTOP_TERMINAL_SCROLLBACK_ROW_PRESETS = [5_000, 10_000, 25_000, 50_000] as const export const LEGACY_TERMINAL_SCROLLBACK_BYTES_1_MB = 1_000_000 -export const LEGACY_TERMINAL_SCROLLBACK_BYTES_10_MB = 10_000_000 -export const LEGACY_TERMINAL_SCROLLBACK_BYTES_25_MB = 25_000_000 -export const LEGACY_TERMINAL_SCROLLBACK_BYTES_50_MB = 50_000_000 -export const LEGACY_TERMINAL_SCROLLBACK_BYTES_100_MB = 100_000_000 export const LEGACY_TERMINAL_SCROLLBACK_BUCKET_5K_MAX_BYTES = 17_500_000 export const LEGACY_TERMINAL_SCROLLBACK_BUCKET_10K_MAX_BYTES = 37_500_000 diff --git a/src/shared/terminal-size-limits.ts b/src/shared/terminal-size-limits.ts deleted file mode 100644 index fca3d9c8754..00000000000 --- a/src/shared/terminal-size-limits.ts +++ /dev/null @@ -1,34 +0,0 @@ -export const MAX_TERMINAL_COLS = 500 -export const MAX_TERMINAL_ROWS = 500 - -export function terminalSizeAdmissionError( - cols: unknown, - rows: unknown, - field: string, - options: { allowMissing?: boolean } = {} -): string | null { - for (const [name, value, max] of [ - ['cols', cols, MAX_TERMINAL_COLS], - ['rows', rows, MAX_TERMINAL_ROWS] - ] as const) { - if (options.allowMissing && value === undefined) { - continue - } - if (!Number.isSafeInteger(value) || (value as number) < 1 || (value as number) > max) { - return `${field}.${name} must be an integer from 1 through ${max}` - } - } - return null -} - -export function isValidTerminalSize(cols: unknown, rows: unknown): boolean { - return terminalSizeAdmissionError(cols, rows, 'terminal size') === null -} - -export function normalizeTerminalSize( - cols: unknown, - rows: unknown, - fallback: { cols: number; rows: number } = { cols: 80, rows: 24 } -): { cols: number; rows: number } { - return isValidTerminalSize(cols, rows) ? { cols: cols as number, rows: rows as number } : fallback -} diff --git a/src/shared/terminal-title-display.ts b/src/shared/terminal-title-display.ts deleted file mode 100644 index a0f2ad6894c..00000000000 --- a/src/shared/terminal-title-display.ts +++ /dev/null @@ -1,108 +0,0 @@ -import { - AGY_AGENT_NAME_RE, - DROID_AGENT_NAME_RE, - HERMES_AGENT_NAME_RE, - titleHasAnyLegacyAgentName -} from './agent-name-token-match' -import { - GEMINI_IDLE, - GEMINI_PERMISSION, - GEMINI_SILENT_WORKING, - GEMINI_WORKING, - isGeminiTerminalTitle, - isGrokRotatingWorkingTitle, - isPiAgentTitle -} from './terminal-title-agent-type' -import { - detectAgentStatusFromTitle, - STRONG_WORKING_KEYWORDS_RE_GLOBAL -} from './terminal-title-status' - -function containsAgentName(title: string): boolean { - return ( - titleHasAnyLegacyAgentName(title) || - AGY_AGENT_NAME_RE.test(title) || - DROID_AGENT_NAME_RE.test(title) || - HERMES_AGENT_NAME_RE.test(title) - ) -} - -/** - * Strip working-status indicators from a title so that - * `detectAgentStatusFromTitle` will no longer return 'working'. - * Used to clear stale titles when an agent exits without resetting its title. - */ -export function clearWorkingIndicators(title: string): string { - let cleaned = title - - // Gemini working symbols - cleaned = cleaned.replace(GEMINI_WORKING, '') - cleaned = cleaned.replace(GEMINI_SILENT_WORKING, '') - - // Braille spinner characters (U+2800–U+28FF) - // eslint-disable-next-line no-control-regex -- intentional unicode range - cleaned = cleaned.replace(/[\u2800-\u28FF]/g, '') - - // Claude Code ". " working prefix - if (cleaned.startsWith('. ')) { - cleaned = cleaned.slice(2) - } - - // Strip working keywords that detectAgentStatusFromTitle would pick up - // when the title also contains an agent name. - if (containsAgentName(cleaned)) { - cleaned = cleaned.replace(STRONG_WORKING_KEYWORDS_RE_GLOBAL, '') - } - - // Collapse whitespace after removals - cleaned = cleaned.replace(/\s{2,}/g, ' ').trim() - - return cleaned || title -} - -/** - * Normalize high-churn agent titles into stable display labels before storing - * them in app state. Gemini CLI can emit per-keystroke title updates, which - * otherwise causes broad rerenders and visible flashing. - */ -export function normalizeTerminalTitle(title: string): string { - if (!title) { - return title - } - - if (isGeminiTerminalTitle(title)) { - const status = detectAgentStatusFromTitle(title) - if (status === 'permission') { - return `${GEMINI_PERMISSION} Gemini CLI` - } - if (status === 'working') { - return `${GEMINI_WORKING} Gemini CLI` - } - if (status === 'idle') { - return `${GEMINI_IDLE} Gemini CLI` - } - } - - // Why: Pi's titlebar extension animates every 80ms with different braille - // frames. Collapsing those frames into one stable label avoids renderer - // churn while preserving the working/idle transition Orca keys off. - if (isPiAgentTitle(title)) { - const status = detectAgentStatusFromTitle(title) - if (status === 'working') { - return '\u280b Pi' - } - if (status === 'idle') { - return 'Pi' - } - } - - // Why: Grok Build interpolates a rotating status/tool phrase between the - // spinner and its name, so its working frames change the title many times per - // turn. Collapse them to one stable label; idle/session titles carry no - // spinner and pass through, so the meaningful final title still shows. - if (isGrokRotatingWorkingTitle(title)) { - return '\u280b Grok' - } - - return title -} diff --git a/src/shared/terminal-title-status.ts b/src/shared/terminal-title-status.ts deleted file mode 100644 index e0fe8312468..00000000000 --- a/src/shared/terminal-title-status.ts +++ /dev/null @@ -1,165 +0,0 @@ -import { - AGY_AGENT_NAME_RE, - DROID_AGENT_NAME_RE, - HERMES_AGENT_NAME_RE, - titleHasAnyLegacyAgentName -} from './agent-name-token-match' -import { getPiCompatibleSyntheticAgentStatus } from './pi-compatible-synthetic-title' -import { - CLAUDE_IDLE, - containsBrailleSpinner, - GEMINI_IDLE, - GEMINI_PERMISSION, - GEMINI_SILENT_WORKING, - GEMINI_WORKING, - isClaudeManagementTitle, - isPiTerminalTitle -} from './terminal-title-agent-type' - -export type AgentStatus = 'working' | 'permission' | 'idle' - -// Idle-status keywords; `as const` gives consumers literal-union types. -const STRONG_IDLE_KEYWORDS = ['ready', 'idle', 'done'] as const - -// Working-status keywords, shared with `clearWorkingIndicators` so detection and stripping stay in lock-step. -const STRONG_WORKING_KEYWORDS = ['working', 'thinking', 'running'] as const - -// Why: `\b` fails since "-" is a non-word char (`\bready\b` matches "is-ready-cap"); lookarounds are asymmetric — reject path chars left, allow trailing punctuation ("Codex done.") right. -export const STRONG_IDLE_KEYWORDS_RE = new RegExp( - `(? lower.includes(word)) -} - -/** - * Tracks agent status transitions from terminal title changes. - * Fires `onBecameIdle` on working→idle/permission — the trigger for unread notifications. - */ -export function createAgentStatusTracker( - onBecameIdle: (title: string) => void, - onBecameWorking?: () => void, - onAgentExited?: () => void -): { - handleTitle: (title: string) => void - /** Clear status so a stale working→idle transition can't fire after teardown. */ - reset: () => void -} { - let lastStatus: AgentStatus | null = null - - return { - handleTitle(title: string): void { - const newStatus = detectAgentStatusFromTitle(title) - if (lastStatus === 'working' && newStatus !== null && newStatus !== 'working') { - onBecameIdle(title) - } - if (lastStatus !== 'working' && newStatus === 'working') { - onBecameWorking?.() - } - // Why: null title = reverted to a plain shell prompt (agent exited); skip when 'working' since active agents briefly flash shell titles. - if (lastStatus !== null && lastStatus !== 'working' && newStatus === null) { - lastStatus = null - onAgentExited?.() - } - if (newStatus !== null) { - lastStatus = newStatus - } - }, - reset(): void { - lastStatus = null - } - } -} - -// Why: cursor's native title is constant and carries no working/idle info; keep it a no-op so per-turn re-emissions can't stomp Orca-synthesized state. -const CURSOR_NATIVE_TITLE_LOWER = 'cursor agent' - -export function detectAgentStatusFromTitle(title: string): AgentStatus | null { - if (!title) { - return null - } - if (isClaudeManagementTitle(title)) { - return null - } - // Why: exact "Cursor Agent" is cursor's info-free native title; titles with extra tokens are Orca-synthesized and worth classifying. - if (title.trim().toLowerCase() === CURSOR_NATIVE_TITLE_LOWER) { - return null - } - - // Gemini CLI symbols are the most specific and should take precedence. - if (title.includes(GEMINI_PERMISSION)) { - return 'permission' - } - if (title.includes(GEMINI_WORKING) || title.includes(GEMINI_SILENT_WORKING)) { - return 'working' - } - if (title.includes(GEMINI_IDLE)) { - return 'idle' - } - - // Why: resolve synthetic Pi/OMP labels before the broader Pi/braille checks below. - const piCompatibleSyntheticAgentStatus = getPiCompatibleSyntheticAgentStatus(title) - if (piCompatibleSyntheticAgentStatus) { - return piCompatibleSyntheticAgentStatus - } - - // Claude Code uses ✳ idle prefix; check before braille/agent-name since the title is the task description, not "Claude Code". - if (title.startsWith(`${CLAUDE_IDLE} `) || title === CLAUDE_IDLE) { - return 'idle' - } - - if (isPiTerminalTitle(title)) { - return 'idle' - } - - if (containsBrailleSpinner(title)) { - return 'working' - } - - const hasDroidAgentName = DROID_AGENT_NAME_RE.test(title) - const hasHermesAgentName = HERMES_AGENT_NAME_RE.test(title) - const hasAgyAgentName = AGY_AGENT_NAME_RE.test(title) - const hasLegacyAgentName = titleHasAnyLegacyAgentName(title) - if (hasLegacyAgentName || hasDroidAgentName || hasHermesAgentName || hasAgyAgentName) { - if (containsAny(title, ['action required', 'permission', 'waiting'])) { - return 'permission' - } - // Why: boundary match (not substring) so "already" ⊃ "ready" isn't classified idle. See STRONG_IDLE_KEYWORDS_RE. - if (STRONG_IDLE_KEYWORDS_RE.test(title)) { - return 'idle' - } - // Why: false 'working' is worse than false 'idle' (drives active-agent UI); boundary match avoids "reworking" ⊃ "working". - if (STRONG_WORKING_KEYWORDS_RE.test(title)) { - return 'working' - } - - // Claude Code title prefixes: ". " = working, "* " = idle - if (title.startsWith('. ')) { - return 'working' - } - if (title.startsWith('* ')) { - return 'idle' - } - - // Why: Droid's hook events are authoritative; don't treat a name-only native title as a completion. - if (hasDroidAgentName && !hasLegacyAgentName) { - return null - } - - return 'idle' - } - - return null -} diff --git a/src/shared/work-items.ts b/src/shared/work-items.ts index 0a770058cc4..489fe372776 100644 --- a/src/shared/work-items.ts +++ b/src/shared/work-items.ts @@ -26,19 +26,10 @@ export function isGitHubWorkItemsSshRemoteRequiredError(error: unknown): boolean return message.includes(GITHUB_WORK_ITEMS_SSH_REMOTE_REQUIRED_MESSAGE) } -// Why: generic over item shape for the same cross-caller reasons as -// sortWorkItemsByUpdatedAt. Sorting by number descending matches GitHub's -// default Issues view (newest issue number first). +// Why: generic over item shape because main-process callers emit items without +// repoId (stamped by the renderer after IPC), while renderer callers carry the +// full GitHubWorkItem. Sorting by number descending matches GitHub's default +// Issues view (newest issue number first). export function sortWorkItemsByNumber(items: T[]): T[] { return [...items].sort((left, right) => right.number - left.number) } - -// Why: generic over the item shape because main-process callers emit items -// without repoId (stamped by the renderer after IPC), while renderer callers -// carry the full GitHubWorkItem. Both share only the updatedAt field needed -// here. -export function sortWorkItemsByUpdatedAt(items: T[]): T[] { - return [...items].sort((left, right) => { - return new Date(right.updatedAt).getTime() - new Date(left.updatedAt).getTime() - }) -} diff --git a/src/shared/workspace-scope.ts b/src/shared/workspace-scope.ts index 6aed11b6e2d..4993c0599d7 100644 --- a/src/shared/workspace-scope.ts +++ b/src/shared/workspace-scope.ts @@ -8,12 +8,6 @@ export function folderWorkspaceKey(folderWorkspaceId: string): WorkspaceKey { return `folder:${folderWorkspaceId}` } -export function workspaceKeyFromScope(scope: WorkspaceScope): WorkspaceKey { - return scope.type === 'worktree' - ? worktreeWorkspaceKey(scope.worktreeId) - : folderWorkspaceKey(scope.folderWorkspaceId) -} - export function parseWorkspaceKey(value: string): WorkspaceScope | null { if (value.startsWith('worktree:')) { const worktreeId = value.slice('worktree:'.length) diff --git a/src/shared/wsl-hook-relay-contract.ts b/src/shared/wsl-hook-relay-contract.ts index ed6e147de18..87f099e6e0d 100644 --- a/src/shared/wsl-hook-relay-contract.ts +++ b/src/shared/wsl-hook-relay-contract.ts @@ -44,16 +44,6 @@ export const WSL_HOOK_FS_METHODS = { mkdir: 'wslfs.mkdir' } as const -/** Hard guest-side ceilings. Host requests may lower them but cannot raise them. */ -export const WSL_HOOK_FS_MAX_READ_BYTES = 64 * 1024 * 1024 -export const WSL_HOOK_FS_MAX_DIRECTORY_ENTRIES = 10_000 -export const WSL_HOOK_FS_MAX_DIRECTORY_RETAINED_BYTES = 2 * 1024 * 1024 - -export type WslHookFsDirectoryLimits = { - maxEntries: number - maxRetainedBytes: number -} - /** Result envelope for every fs-bridge method. Errors travel as data (not * JSON-RPC faults) so the host adapter can map POSIX errno onto the ssh2 * status codes the shared installer error-classifiers already understand. */