fix(quality): enforce performance-safe lint baseline (#11074)

* fix(quality): clear safe existing lint findings

* fix(quality): keep lint cleanup allocation-free

* fix(quality): enforce performance-safe baseline

* test(terminal): drain deferred confirmation cleanup
This commit is contained in:
Neil 2026-07-27 20:54:02 -07:00 committed by GitHub
parent 9a3b348e82
commit badf91101b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
143 changed files with 679 additions and 623 deletions

View File

@ -32,6 +32,9 @@ jobs:
- name: Lint
run: pnpm exec oxlint --format github
- name: Enforce full code-quality baseline
run: pnpm run audit:code-quality:native && pnpm run audit:code-quality:type-aware
- name: Check switch exhaustiveness
run: pnpm run lint:switch-exhaustiveness

View File

@ -12,11 +12,16 @@
},
"rules": {
"typescript/await-thenable": "warn",
"typescript/no-floating-promises": "warn",
"typescript/no-misused-promises": "warn",
"typescript/only-throw-error": "warn",
"typescript/restrict-plus-operands": "warn",
"typescript/restrict-template-expressions": "warn"
},
"overrides": [
{
"files": ["**/*.test.*", "**/*.spec.*"],
"rules": {
"typescript/await-thenable": "off"
}
}
],
"ignorePatterns": ["**/node_modules", "**/dist", "**/out"]
}

View File

@ -10,9 +10,6 @@
"restriction": "off",
"nursery": "off"
},
"options": {
"reportUnusedDisableDirectives": "warn"
},
"jsPlugins": [
{
"name": "app-store-performance",
@ -29,15 +26,7 @@
"import/no-cycle": ["warn", { "maxDepth": 3 }],
"import/no-duplicates": "warn",
"import/no-self-import": "warn",
"max-params": ["warn", 5],
"no-fallthrough": "warn",
"no-loop-func": "warn",
"no-promise-executor-return": "warn",
"no-unmodified-loop-condition": "warn",
"preserve-caught-error": "warn",
"promise/no-multiple-resolved": "warn",
"react/no-unstable-nested-components": "warn",
"react/react-compiler": "warn"
"no-fallthrough": "warn"
},
"overrides": [
{
@ -55,9 +44,7 @@
"rules": {
"vitest/no-conditional-tests": "warn",
"vitest/no-focused-tests": "warn",
"vitest/no-identical-title": "warn",
"vitest/valid-expect": "warn",
"vitest/valid-title": "warn"
"vitest/no-identical-title": "warn"
}
},
{

View File

@ -12,11 +12,10 @@
// other work would be a regression, not a win.
//
// Run with: node config/scripts/claude-usage-yield-benchmark.mjs
import { readFileSync } from 'node:fs'
import { readFileSync, readdirSync, statSync } from 'node:fs'
import { homedir } from 'node:os'
import { join } from 'node:path'
import { performance } from 'node:perf_hooks'
import { readdirSync, statSync } from 'node:fs'
const REPO_ROOT = new URL('../..', import.meta.url)
const ROUNDS = Number(process.env.ORCA_YIELD_BENCH_ROUNDS ?? '10')

View File

@ -196,6 +196,7 @@ try {
// Each case is (label, argv, env). The runtime-dependent ones point at an
// empty user-data dir so both arms get the same deterministic answer.
const isolated = { ORCA_USER_DATA_PATH: userDataPath }
/** @type {Array<[string, string[], Record<string, string>]>} */
const cases = [
['orca --help', ['--help'], {}],
['orca help worktree', ['help', 'worktree'], {}],

View File

@ -200,7 +200,7 @@ export async function setupTerminal(page, repoPath, logPhase) {
return pane?.container?.dataset?.ptyId ?? null
})
)
logPhase('setup.pty-bound', `ptyId=${ptyId}`)
logPhase('setup.pty-bound', `ptyId=${String(ptyId)}`)
return ptyId
}

View File

@ -40,7 +40,10 @@ describe('Windows SSH relay node-pty console-list patch', () => {
const tamperedPatch = writeNodePtyFixture('1.1.0', publishedAgentSource())
patchNodePtyConsoleListAgent(tamperedPatch.root)
writeFileSync(tamperedPatch.agentPath, `${readFileSync(tamperedPatch.agentPath)}\n// drift`)
writeFileSync(
tamperedPatch.agentPath,
`${readFileSync(tamperedPatch.agentPath, 'utf8')}\n// drift`
)
expect(() => assertPatchedNodePtyConsoleListAgent(tamperedPatch.root)).toThrow('not installed')
})
})

View File

@ -98,7 +98,7 @@ export async function publishCompleteDraftReleases({
for (const release of candidates) {
const tag = release.tag_name
if (!(await isDraftBuiltFromCurrentRef({ tag, release }))) {
if (!(await Promise.resolve(isDraftBuiltFromCurrentRef({ tag, release })))) {
const reason = 'tag is not built from the current release ref'
skipped.push({ tag, reason })
log(`Skipping stale RC draft release ${tag}: ${reason}`)

View File

@ -572,7 +572,7 @@ async function main() {
if (options.output) {
mkdirSync(path.dirname(path.resolve(options.output)), { recursive: true })
writeFileSync(options.output, `${JSON.stringify(report, null, 2)}\n`)
console.log(`[idle-cpu] wrote ${options.output}`)
console.log(`[idle-cpu] wrote ${String(options.output)}`)
}
console.log(
JSON.stringify(

View File

@ -1,7 +1,9 @@
import { useState, useEffect, useRef, useCallback, useMemo } from 'react'
import { Animated, AppState, Linking, type AppStateStatus } from 'react-native'
import * as Clipboard from 'expo-clipboard'
import {
Animated,
AppState,
Linking,
type AppStateStatus,
BackHandler,
FlatList,
Image,
@ -17,6 +19,7 @@ import {
type LayoutChangeEvent,
type ListRenderItem
} from 'react-native'
import * as Clipboard from 'expo-clipboard'
import { SafeAreaView, useSafeAreaInsets } from 'react-native-safe-area-context'
import { useFocusEffect, useLocalSearchParams, useRouter } from 'expo-router'
import AsyncStorage from '@react-native-async-storage/async-storage'

View File

@ -106,11 +106,9 @@ import {
} from '../../../src/tasks/setup-hook-trust'
import { colors, radii, spacing, typography } from '../../../src/theme/mobile-theme'
import { triggerMediumImpact } from '../../../src/platform/haptics'
import type {
GitHubProjectSortDirection,
GitHubProjectTable as SharedGitHubProjectTable
} from '../../../src/tasks/mobile-github-project-group-sort'
import {
type GitHubProjectSortDirection,
type GitHubProjectTable as SharedGitHubProjectTable,
groupRows,
isIterationCurrent,
sortRows,

View File

@ -1,6 +1,5 @@
import { useEffect, useMemo, useRef, useState } from 'react'
import type { ConnectionState } from '../transport/types'
import type { RpcSuccess } from '../transport/types'
import type { ConnectionState, RpcSuccess } from '../transport/types'
import type { RpcClient } from '../transport/rpc-client'
import { createBotAuthorOverrideSet } from '../../../src/shared/pr-bot-author-overrides'

View File

@ -11,10 +11,10 @@
"main": "./out/main/index.js",
"scripts": {
"format": "oxfmt --write .",
"lint": "oxlint && pnpm run lint:switch-exhaustiveness && node config/scripts/check-styled-scrollbars.mjs && pnpm run check:quadratic-buffer-concat && pnpm run check:reliability-gates && pnpm run check:max-lines-ratchet && pnpm run verify:bundled-skill-guides && pnpm run verify:skill-bundle-manifest && pnpm run verify:localization-catalog && pnpm run verify:localization-coverage",
"lint": "oxlint && pnpm run audit:code-quality:native && pnpm run audit:code-quality:type-aware && pnpm run lint:switch-exhaustiveness && node config/scripts/check-styled-scrollbars.mjs && pnpm run check:quadratic-buffer-concat && pnpm run check:reliability-gates && pnpm run check:max-lines-ratchet && pnpm run verify:bundled-skill-guides && pnpm run verify:skill-bundle-manifest && pnpm run verify:localization-catalog && pnpm run verify:localization-coverage",
"audit:code-quality": "pnpm run audit:code-quality:native && pnpm run audit:code-quality:type-aware && pnpm run audit:react-doctor",
"audit:code-quality:native": "oxlint --config config/oxlint-code-quality.json --report-unused-disable-directives-severity warn src config tests mobile",
"audit:code-quality:type-aware": "oxlint --type-aware --config config/oxlint-code-quality-type-aware.json src config tests mobile",
"audit:code-quality:native": "oxlint --config config/oxlint-code-quality.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",
"check:code-quality:changed": "node config/scripts/check-changed-code-quality.mjs",
"check:react-doctor:changed": "node config/scripts/check-react-doctor-changed.mjs",

View File

@ -1,5 +1,9 @@
import { RuntimeClientError } from './runtime/types'
import { unknownCommandData, unknownFlagData } from './command-suggestion'
import { specPaths, type CommandSpec } from './command-spec'
export { specPaths }
export type { CommandSpec }
export type ParsedArgs = {
commandPath: string[]
@ -7,23 +11,6 @@ export type ParsedArgs = {
positionalFlagConflicts?: string[]
}
export type CommandSpec = {
path: string[]
// Why: conventional alternate verbs should resolve without duplicating specs
// or handler registrations.
aliases?: string[][]
argumentMode?: 'parsed' | 'passthrough'
// Why: irreversibly destroys persistent state — typo recovery must not steer a
// benign mistake into one of these via the agent nextSteps channel. #6303
destructive?: boolean
summary: string
usage: string
allowedFlags: string[]
positionalArgs?: string[]
examples?: string[]
notes?: string[]
}
export const GLOBAL_FLAGS = ['help', 'json', 'pairing-code', 'environment']
const GLOBAL_VALUE_FLAGS = new Set(['pairing-code', 'environment'])
export const BOOLEAN_FLAGS = new Set([
@ -157,12 +144,6 @@ export function matches(actual: string[], expected: string[]): boolean {
)
}
// Why: a spec is reachable by its canonical path plus any declared aliases — one
// definition so resolution, validation, help, and agent-context never disagree.
export function specPaths(spec: CommandSpec): string[][] {
return spec.aliases ? [spec.path, ...spec.aliases] : [spec.path]
}
export function supportsBrowserPageFlag(commandPath: string[]): boolean {
const joined = commandPath.join(' ')
if (['open', 'status'].includes(commandPath[0])) {

View File

@ -293,7 +293,7 @@ describe('orca cli browser page targeting', () => {
})
})
describe('orca cli browser tab profiles', () => {
describe('orca cli browser profile management', () => {
beforeEach(() => {
callMock.mockReset()
})

18
src/cli/command-spec.ts Normal file
View File

@ -0,0 +1,18 @@
export type CommandSpec = {
path: string[]
// Why: conventional alternate verbs should resolve without duplicating specs or handlers.
aliases?: string[][]
argumentMode?: 'parsed' | 'passthrough'
// Why: typo recovery must never steer a benign mistake into destructive state changes.
destructive?: boolean
summary: string
usage: string
allowedFlags: string[]
positionalArgs?: string[]
examples?: string[]
notes?: string[]
}
export function specPaths(spec: CommandSpec): string[][] {
return spec.aliases ? [spec.path, ...spec.aliases] : [spec.path]
}

View File

@ -1,5 +1,4 @@
import type { CommandSpec } from './args'
import { specPaths } from './args'
import { specPaths, type CommandSpec } from './command-spec'
// Why: rank the live registry so typo recovery cannot drift from accepted paths.

View File

@ -4,7 +4,12 @@ import { dirname, join } from 'node:path'
import { randomUUID } from 'node:crypto'
import type { CommandHandler } from '../dispatch'
import { printResult } from '../format'
import { RuntimeClientError, type RuntimeClient, type RuntimeRpcSuccess } from '../runtime-client'
import {
RuntimeClientError,
type RuntimeClient,
type RuntimeRpcSuccess,
getDefaultUserDataPath
} from '../runtime-client'
import type { AgentHookInstallStatus } from '../../shared/agent-hook-types'
import { getDefaultPersistedState } from '../../shared/constants'
import type { PersistedState } from '../../shared/types'
@ -12,7 +17,6 @@ import {
applyAgentStatusHooksEnabled,
getManagedAgentHookStatuses
} from '../../main/agent-hooks/managed-agent-hook-controls'
import { getDefaultUserDataPath } from '../runtime-client'
type AgentHookCommandResult = {
enabled: boolean

View File

@ -1,8 +1,7 @@
import type { CommandHandler } from '../dispatch'
import { formatEnvironment, formatEnvironmentList, printResult } from '../format'
import { getDefaultUserDataPath } from '../runtime-client'
import { getDefaultUserDataPath, RuntimeClientError } from '../runtime-client'
import type { RuntimeRpcSuccess } from '../runtime-client'
import { RuntimeClientError } from '../runtime-client'
import { redactRuntimeEnvironment } from '../../shared/runtime-environments'
import {
addEnvironmentFromPairingCode,

View File

@ -5,11 +5,13 @@ import { RuntimeClientError } from '../runtime-client'
import { parseOrcaYaml } from '../../shared/orca-yaml'
import {
getEphemeralVmRecipeResultProjectRoot,
getEphemeralVmRecipeResultWarnings,
redactEphemeralVmRecipeDiagnosticText,
type EphemeralVmRecipeDoctorCheck,
type EphemeralVmRecipeDoctorResult
} from '../../shared/ephemeral-vm-recipes'
import {
getEphemeralVmRecipeResultWarnings,
redactEphemeralVmRecipeDiagnosticText
} from '../../shared/ephemeral-vm-recipe-diagnostics'
// Why: import directly from the doctor module (not the barrel) — it uses Node
// fs/path and must stay out of the browser bundle that imports the barrel.
import { doctorEphemeralVmRecipe } from '../../shared/ephemeral-vm-recipe-doctor'

View File

@ -88,7 +88,7 @@ export async function sendRequest<TResult>(
)
})
})
socket.on('data', (chunk) => {
socket.on('data', (chunk: string) => {
buffer += chunk
// Why: the server may interleave `{"_keepalive":true}\n` frames with the
// final success/failure frame to keep both idle timers alive during a

View File

@ -7,33 +7,20 @@ vi.mock('electron', () => ({
}
}))
import { CodexHookService } from '../codex/hook-service'
import { DroidHookService } from '../droid/hook-service'
import { CursorHookService } from '../cursor/hook-service'
import { CommandCodeHookService } from '../command-code/hook-service'
import { GeminiHookService } from '../gemini/hook-service'
import { AntigravityHookService } from '../antigravity/hook-service'
import { AmpHookService } from '../amp/hook-service'
import { ClaudeHookService } from '../claude/hook-service'
import { GrokHookService } from '../grok/hook-service'
import { CopilotHookService } from '../copilot/hook-service'
import { HermesHookService } from '../hermes/hook-service'
import { DevinHookService } from '../devin/hook-service'
import { KimiHookService } from '../kimi/hook-service'
import { CodexHookService, codexHookService } from '../codex/hook-service'
import { DroidHookService, droidHookService } from '../droid/hook-service'
import { CursorHookService, cursorHookService } from '../cursor/hook-service'
import { CommandCodeHookService, commandCodeHookService } from '../command-code/hook-service'
import { GeminiHookService, geminiHookService } from '../gemini/hook-service'
import { AntigravityHookService, antigravityHookService } from '../antigravity/hook-service'
import { AmpHookService, ampHookService } from '../amp/hook-service'
import { ClaudeHookService, claudeHookService } from '../claude/hook-service'
import { GrokHookService, grokHookService } from '../grok/hook-service'
import { CopilotHookService, copilotHookService } from '../copilot/hook-service'
import { HermesHookService, hermesHookService } from '../hermes/hook-service'
import { DevinHookService, devinHookService } from '../devin/hook-service'
import { KimiHookService, kimiHookService } from '../kimi/hook-service'
import { openClaudeHookService } from '../openclaude/hook-service'
import { ampHookService } from '../amp/hook-service'
import { antigravityHookService } from '../antigravity/hook-service'
import { claudeHookService } from '../claude/hook-service'
import { codexHookService } from '../codex/hook-service'
import { copilotHookService } from '../copilot/hook-service'
import { cursorHookService } from '../cursor/hook-service'
import { droidHookService } from '../droid/hook-service'
import { commandCodeHookService } from '../command-code/hook-service'
import { geminiHookService } from '../gemini/hook-service'
import { devinHookService } from '../devin/hook-service'
import { grokHookService } from '../grok/hook-service'
import { hermesHookService } from '../hermes/hook-service'
import { kimiHookService } from '../kimi/hook-service'
import { MANAGED_AGENT_HOOK_INSTALLERS } from './managed-agent-hook-controls'
import {
installRemoteManagedAgentHooks,

View File

@ -1,6 +1,8 @@
import type { AiVaultAgent, AiVaultScanIssue } from '../../shared/ai-vault-types'
import { buildOpenCodeSqliteCandidatePath } from './session-scanner-opencode-sqlite-paths'
import { splitOpenCodeSqliteCandidate } from './session-scanner-opencode-sqlite-paths'
import {
buildOpenCodeSqliteCandidatePath,
splitOpenCodeSqliteCandidate
} from './session-scanner-opencode-sqlite-paths'
import type { SessionFileCandidate } from './session-scanner-types'
import { errorMessage } from './session-scanner-values'
import SyncDatabase from '../sqlite/sync-database'

View File

@ -0,0 +1,5 @@
export function asRecord(value: unknown): Record<string, unknown> | null {
return value && typeof value === 'object' && !Array.isArray(value)
? (value as Record<string, unknown>)
: null
}

View File

@ -1,5 +1,5 @@
import type { CodexUsageSnapshot } from './session-scanner-types'
import { asRecord } from './session-scanner-values'
import { asRecord } from './session-scanner-record-value'
export function tokenTotal(value: unknown): number {
const usage = asRecord(value)

View File

@ -1,5 +1,5 @@
import type { AiVaultAgent } from '../../shared/ai-vault-types'
import type {
AiVaultAgent,
AiVaultScanIssue,
AiVaultSession,
AiVaultSessionPreviewMessage

View File

@ -1,6 +1,9 @@
import { homedir } from 'node:os'
import { basename, dirname, join } from 'node:path'
import { readFile } from 'node:fs/promises'
import { asRecord } from './session-scanner-record-value'
export { asRecord }
export function timestampMs(value: unknown): number {
if (typeof value === 'string') {
@ -25,12 +28,6 @@ export function parseJsonObject(line: string): Record<string, unknown> | null {
}
}
export function asRecord(value: unknown): Record<string, unknown> | null {
return value && typeof value === 'object' && !Array.isArray(value)
? (value as Record<string, unknown>)
: null
}
export function extractString(value: unknown): string | null {
if (typeof value !== 'string') {
return null

View File

@ -63,6 +63,8 @@ import {
CLIPBOARD_TEXT_WRITE_TOO_LARGE_ERROR
} from '../../shared/clipboard-text'
type ExecFileCallback = (error: unknown, stdout?: string, stderr?: string) => void
// Why: the bridge resolves webContents via dynamic require('electron').webContents.fromId
// inside a try/catch. Override the private method to inject our mock.
// eslint-disable-next-line @typescript-eslint/no-explicit-any
@ -116,31 +118,37 @@ function mockWebContents(id: number, url = 'https://example.com', title = 'Examp
}
function succeedWith(data: unknown): void {
execFileMock.mockImplementation((_bin: string, _args: string[], _opts: unknown, cb: Function) => {
cb(null, JSON.stringify({ success: true, data }), '')
return {
stdin: { on: vi.fn(), end: (text: string) => stdinWrites.push(text) }
execFileMock.mockImplementation(
(_bin: string, _args: string[], _opts: unknown, cb: ExecFileCallback) => {
cb(null, JSON.stringify({ success: true, data }), '')
return {
stdin: { on: vi.fn(), end: (text: string) => stdinWrites.push(text) }
}
}
})
)
}
function succeedForContentEditable(data: unknown = { ok: true }): void {
execFileMock.mockImplementation((_bin: string, args: string[], _opts: unknown, cb: Function) => {
const result =
args.includes('get') && args.includes('attr') && args.includes('contenteditable')
? { value: 'true' }
: data
cb(null, JSON.stringify({ success: true, data: result }), '')
return {
stdin: { on: vi.fn(), end: (text: string) => stdinWrites.push(text) }
execFileMock.mockImplementation(
(_bin: string, args: string[], _opts: unknown, cb: ExecFileCallback) => {
const result =
args.includes('get') && args.includes('attr') && args.includes('contenteditable')
? { value: 'true' }
: data
cb(null, JSON.stringify({ success: true, data: result }), '')
return {
stdin: { on: vi.fn(), end: (text: string) => stdinWrites.push(text) }
}
}
})
)
}
function failWith(error: string): void {
execFileMock.mockImplementation((_bin: string, _args: string[], _opts: unknown, cb: Function) => {
cb(null, JSON.stringify({ success: false, error }), '')
})
execFileMock.mockImplementation(
(_bin: string, _args: string[], _opts: unknown, cb: ExecFileCallback) => {
cb(null, JSON.stringify({ success: false, error }), '')
}
)
}
class TestEvent {
@ -352,7 +360,7 @@ describe('AgentBrowserBridge', () => {
try {
const closeKill = vi.fn()
execFileMock.mockImplementation(
(_bin: string, args: string[], _opts: unknown, cb: Function) => {
(_bin: string, args: string[], _opts: unknown, cb: ExecFileCallback) => {
if (args.includes('close')) {
return { kill: closeKill }
}
@ -445,7 +453,7 @@ describe('AgentBrowserBridge', () => {
let releaseSnapshot: (() => void) | null = null
const activeChild = { kill: vi.fn() }
execFileMock.mockImplementation(
(_bin: string, args: string[], _opts: unknown, cb: Function) => {
(_bin: string, args: string[], _opts: unknown, cb: ExecFileCallback) => {
if (args.includes('snapshot')) {
releaseSnapshot = () => {
cb(null, JSON.stringify({ success: false, error: CDP_DISCOVERY_FAILURE }), '')
@ -486,7 +494,7 @@ describe('AgentBrowserBridge', () => {
it('handles malformed JSON from agent-browser', async () => {
execFileMock.mockImplementation(
(_bin: string, _args: string[], _opts: unknown, cb: Function) => {
(_bin: string, _args: string[], _opts: unknown, cb: ExecFileCallback) => {
cb(null, 'not json at all', '')
}
)
@ -748,7 +756,7 @@ describe('AgentBrowserBridge', () => {
const commandCalls: string[][] = []
execFileMock.mockImplementation(
(_bin: string, args: string[], _opts: unknown, cb: Function) => {
(_bin: string, args: string[], _opts: unknown, cb: ExecFileCallback) => {
commandCalls.push(args)
cb(null, JSON.stringify({ success: true, data: { ok: true } }), '')
}
@ -782,7 +790,7 @@ describe('AgentBrowserBridge', () => {
let releaseSnapshot: (() => void) | null = null
execFileMock.mockImplementation(
(_bin: string, args: string[], _opts: unknown, cb: Function) => {
(_bin: string, args: string[], _opts: unknown, cb: ExecFileCallback) => {
if (args.includes('close')) {
cb(null, JSON.stringify({ success: true, data: null }), '')
return
@ -877,7 +885,7 @@ describe('AgentBrowserBridge', () => {
const commandCalls: string[][] = []
execFileMock.mockImplementation(
(_bin: string, args: string[], _opts: unknown, cb: Function) => {
(_bin: string, args: string[], _opts: unknown, cb: ExecFileCallback) => {
commandCalls.push(args)
cb(null, JSON.stringify({ success: true, data: { ok: true } }), '')
}
@ -1024,7 +1032,7 @@ describe('AgentBrowserBridge', () => {
let releaseFirstScreenshot: (() => void) | null = null
execFileMock.mockImplementation(
(_bin: string, args: string[], _opts: unknown, cb: Function) => {
(_bin: string, args: string[], _opts: unknown, cb: ExecFileCallback) => {
if (args.includes('close')) {
cb(null, JSON.stringify({ success: true, data: null }), '')
return
@ -1103,7 +1111,7 @@ describe('AgentBrowserBridge', () => {
webContentsFromIdMock.mockReturnValue(wc)
execFileMock.mockImplementation(
(_bin: string, _args: string[], _opts: unknown, cb: Function) => {
(_bin: string, _args: string[], _opts: unknown, cb: ExecFileCallback) => {
cb(null, JSON.stringify({ success: true, data: null }), '')
}
)
@ -1137,7 +1145,7 @@ describe('AgentBrowserBridge', () => {
const killedError = Object.assign(new Error('timeout'), { killed: true })
execFileMock.mockImplementation(
(_bin: string, args: string[], _opts: unknown, cb: Function) => {
(_bin: string, args: string[], _opts: unknown, cb: ExecFileCallback) => {
if (args.includes('close')) {
cb(null, JSON.stringify({ success: true, data: null }), '')
return
@ -1167,7 +1175,7 @@ describe('AgentBrowserBridge', () => {
const commandCalls: string[][] = []
let releaseDestroyClose: (() => void) | null = null
execFileMock.mockImplementation(
(_bin: string, args: string[], _opts: unknown, cb: Function) => {
(_bin: string, args: string[], _opts: unknown, cb: ExecFileCallback) => {
commandCalls.push(args)
if (args.includes('close')) {
if (!releaseDestroyClose) {
@ -1212,7 +1220,7 @@ describe('AgentBrowserBridge', () => {
const commandCalls: string[][] = []
let releaseStaleClose: (() => void) | null = null
execFileMock.mockImplementation(
(_bin: string, args: string[], _opts: unknown, cb: Function) => {
(_bin: string, args: string[], _opts: unknown, cb: ExecFileCallback) => {
commandCalls.push(args)
if (args.includes('close') && !releaseStaleClose) {
releaseStaleClose = () => {
@ -1270,7 +1278,7 @@ describe('AgentBrowserBridge', () => {
}
execFileMock.mockImplementation(
(_bin: string, args: string[], _opts: unknown, cb: Function) => {
(_bin: string, args: string[], _opts: unknown, cb: ExecFileCallback) => {
if (args.includes('snapshot')) {
resolveRunningCommand = () => cb(killedError, '', '')
return activeChild
@ -1354,7 +1362,7 @@ describe('AgentBrowserBridge', () => {
const commandCalls: string[][] = []
execFileMock.mockImplementation(
(_bin: string, args: string[], _opts: unknown, cb: Function) => {
(_bin: string, args: string[], _opts: unknown, cb: ExecFileCallback) => {
commandCalls.push(args)
cb(null, JSON.stringify({ success: true, data: { ok: true } }), '')
}
@ -1390,7 +1398,7 @@ describe('AgentBrowserBridge', () => {
const commandCalls: string[][] = []
execFileMock.mockImplementation(
(_bin: string, args: string[], _opts: unknown, cb: Function) => {
(_bin: string, args: string[], _opts: unknown, cb: ExecFileCallback) => {
commandCalls.push(args)
cb(null, JSON.stringify({ success: true, data: { ok: true } }), '')
}
@ -1577,7 +1585,7 @@ describe('AgentBrowserBridge', () => {
let releaseSnapshot: (() => void) | null = null
execFileMock.mockImplementation(
(_bin: string, args: string[], _opts: unknown, cb: Function) => {
(_bin: string, args: string[], _opts: unknown, cb: ExecFileCallback) => {
if (args.includes('close')) {
cb(null, JSON.stringify({ success: true, data: null }), '')
return
@ -1875,7 +1883,7 @@ describe('AgentBrowserBridge', () => {
let helperSessionIsStale = false
execFileMock.mockImplementation(
(_bin: string, args: string[], _opts: unknown, cb: Function) => {
(_bin: string, args: string[], _opts: unknown, cb: ExecFileCallback) => {
if (args.includes('close')) {
cb(null, JSON.stringify({ success: true, data: null }), '')
} else if (args.includes('snapshot')) {
@ -2549,7 +2557,7 @@ describe('AgentBrowserBridge', () => {
it('returns browser_timeout for timed conditional waits without recycling the session', async () => {
const killedError = Object.assign(new Error('timeout'), { killed: true })
execFileMock.mockImplementation(
(_bin: string, args: string[], _opts: unknown, cb: Function) => {
(_bin: string, args: string[], _opts: unknown, cb: ExecFileCallback) => {
if (args.includes('wait')) {
cb(killedError, '', '')
return
@ -2573,7 +2581,7 @@ describe('AgentBrowserBridge', () => {
it('passes stderr through as error message on execFile failure', async () => {
execFileMock.mockImplementation(
(_bin: string, args: string[], _opts: unknown, cb: Function) => {
(_bin: string, args: string[], _opts: unknown, cb: ExecFileCallback) => {
if (args.includes('close')) {
cb(null, JSON.stringify({ success: true, data: null }), '')
return
@ -2586,7 +2594,7 @@ describe('AgentBrowserBridge', () => {
it('falls back to error.message when stderr is empty', async () => {
execFileMock.mockImplementation(
(_bin: string, args: string[], _opts: unknown, cb: Function) => {
(_bin: string, args: string[], _opts: unknown, cb: ExecFileCallback) => {
if (args.includes('close')) {
cb(null, JSON.stringify({ success: true, data: null }), '')
return
@ -2601,7 +2609,7 @@ describe('AgentBrowserBridge', () => {
it('returns browser_error with truncated output for malformed JSON', async () => {
execFileMock.mockImplementation(
(_bin: string, _args: string[], _opts: unknown, cb: Function) => {
(_bin: string, _args: string[], _opts: unknown, cb: ExecFileCallback) => {
cb(null, 'Error: not json output', '')
}
)

View File

@ -596,7 +596,7 @@ async function importValidatedCookies(
}
}
diag(
` cookie.set FAILED: domain=${cookie.domain} name=${cookie.name} valLen=${val.length} badChar=${badInfo} err=${err}`
` cookie.set FAILED: domain=${cookie.domain} name=${cookie.name} valLen=${val.length} badChar=${badInfo} err=${String(err)}`
)
}
}
@ -1019,7 +1019,7 @@ function getWindowsEncryptionKey(browser: DetectedBrowser): EncryptionKeyResult
return { key: Buffer.from(result, 'base64'), mode: 'aes-256-gcm' }
} catch (err) {
diag(` Windows DPAPI key extraction failed: ${err}`)
diag(` Windows DPAPI key extraction failed: ${String(err)}`)
return null
}
}
@ -1339,7 +1339,7 @@ async function importCookiesFromFirefox(
return importValidatedCookies(validated, rows.length, targetPartition)
} catch (err) {
rmSync(tmpDir, { recursive: true, force: true })
diag(` Firefox import failed: ${err}`)
diag(` Firefox import failed: ${String(err)}`)
return {
ok: false,
reason: 'Could not import cookies from Firefox. Try closing Firefox first.'
@ -1361,7 +1361,7 @@ async function importCookiesFromSafari(
try {
data = readFileSync(browser.cookiesPath)
} catch (err) {
diag(` Safari read failed: ${err}`)
diag(` Safari read failed: ${String(err)}`)
// Why: Safari's Cookies.binarycookies is in a sandbox container; reading it needs Full Disk Access.
const isPermError =
err instanceof Error && 'code' in err && (err as NodeJS.ErrnoException).code === 'EPERM'
@ -1392,7 +1392,7 @@ async function importCookiesFromSafari(
return importValidatedCookies(valid, cookies.length, targetPartition)
} catch (err) {
diag(` Safari import failed: ${err}`)
diag(` Safari import failed: ${String(err)}`)
return { ok: false, reason: 'Could not import cookies from Safari.' }
}
}
@ -1480,7 +1480,7 @@ export async function importCookiesFromBrowser(
} catch {
/* best-effort */
}
diag(` Chromium snapshot failed: ${err}`)
diag(` Chromium snapshot failed: ${String(err)}`)
return {
ok: false,
reason: `Could not copy ${browser.label} cookies database. Try closing ${browser.label} first.`
@ -1527,7 +1527,7 @@ export async function importCookiesFromBrowser(
placeholders = targetCols.map(() => '?').join(', ')
stagingDb.exec('DELETE FROM cookies')
} catch (err) {
diag(` staging database unusable, restart fallback disabled: ${err}`)
diag(` staging database unusable, restart fallback disabled: ${String(err)}`)
stagingAvailable = false
targetColumnInfo = null
colList = null
@ -1807,7 +1807,7 @@ export async function importCookiesFromBrowser(
} catch {
/* may not exist yet */
}
diag(` SQLite import failed: ${err}`)
diag(` SQLite import failed: ${String(err)}`)
return {
ok: false,
reason: reasonWithDiagLog(
@ -1818,7 +1818,7 @@ export async function importCookiesFromBrowser(
try {
sourceSnapshot.cleanup()
} catch (err) {
diag(` Chromium snapshot cleanup failed: ${err}`)
diag(` Chromium snapshot cleanup failed: ${String(err)}`)
}
}
}

View File

@ -43,14 +43,17 @@ import {
buildBrowserIframeClickedLinkRoutingScript
} from './browser-clicked-link-routing'
import { cleanElectronUserAgent } from './browser-session-ua'
import type { BrowserViewportOverride } from '../../shared/types'
import type {
BrowserViewportOverride,
BrowserCertificateFailure,
BrowserLoadError
} from '../../shared/types'
import {
type BrowserAnnotationViewportBridgeOptions,
BROWSER_ANNOTATION_VIEWPORT_BRIDGE_WORLD_ID,
buildBrowserAnnotationViewportBridgeScript
} from '../../shared/browser-annotation-viewport-bridge'
import type { KeybindingOverrides } from '../../shared/keybindings'
import type { BrowserCertificateFailure, BrowserLoadError } from '../../shared/types'
import {
BrowserCertificateTrustController,
type ManagedBrowserGuestContext

View File

@ -250,7 +250,7 @@ async function sendRequest(
let buffer = ''
socket.setEncoding('utf8')
socket.once('error', reject)
socket.on('data', (chunk) => {
socket.on('data', (chunk: string) => {
buffer += chunk
const newlineIndex = buffer.indexOf('\n')
if (newlineIndex === -1) {

View File

@ -170,9 +170,9 @@ function isKeychainNotFoundError(error: unknown): boolean {
: undefined
const message =
error && typeof error === 'object'
? `${(error as { stderr?: unknown }).stderr ?? ''} ${
? `${String((error as { stderr?: unknown }).stderr ?? '')} ${String(
(error as { message?: unknown }).message ?? ''
}`.toLowerCase()
)}`.toLowerCase()
: String(error).toLowerCase()
return code === 44 || message.includes('could not be found') || message.includes('not be found')
}

View File

@ -654,7 +654,7 @@ export class CliInstaller {
private isWindowsPackagedBundledCommand(
commandPath: string | null,
launcherPath: string | null
): commandPath is string {
): boolean {
return (
this.platform === 'win32' &&
this.isPackaged &&

View File

@ -8,12 +8,12 @@ import {
rmSync,
symlinkSync,
statSync,
writeFileSync
writeFileSync,
existsSync
} from 'node:fs'
import { tmpdir } from 'node:os'
import type * as Os from 'node:os'
import { join } from 'node:path'
import { existsSync } from 'node:fs'
import { wrapPosixHookCommand } from '../agent-hooks/installer-utils'
import {
computeTrustKey,

View File

@ -2,9 +2,15 @@ import type { DaemonPtyAdapter } from './daemon-pty-adapter'
import { combineUnsubscribes } from './combine-unsubscribes'
import { shutdownDegradedFallbackSessions } from './degraded-daemon-fallback-shutdown'
import { inspectPtyProviderProcess } from '../providers/pty-process-inspection'
import type { IPtyProvider, PtyBackgroundStreamEvent } from '../providers/types'
import type { PtyDataEvent, PtyProviderBufferSnapshot } from '../providers/types'
import type { PtyProcessInfo, PtySpawnOptions, PtySpawnResult } from '../providers/types'
import type {
IPtyProvider,
PtyBackgroundStreamEvent,
PtyDataEvent,
PtyProviderBufferSnapshot,
PtyProcessInfo,
PtySpawnOptions,
PtySpawnResult
} from '../providers/types'
export class DegradedDaemonPtyProvider implements IPtyProvider {
readonly routesFreshSpawnsToLocalProvider = true

View File

@ -340,7 +340,7 @@ export class HistoryManager {
private async waitForSessionMutations(sessionId: string): Promise<void> {
while (this.pendingSessionMutations.has(sessionId)) {
await Promise.allSettled(this.pendingSessionMutations.get(sessionId) ?? [])
await Promise.allSettled(this.pendingSessionMutations.get(sessionId)!)
}
}
}

View File

@ -44,7 +44,7 @@ export async function fetchGitHubPullRequestHeadRef(
options: { localGitExecOptions?: LocalGitExecOptions } = {}
): Promise<string> {
if (!isValidReviewHeadNumber(prNumber)) {
throw new Error(`Invalid pull request number: ${prNumber}`)
throw new Error(`Invalid pull request number: ${String(prNumber)}`)
}
if (!isSafeReviewHeadFetchRemote(remote)) {
throw new Error('Pull request fetch remote must not start with "-".')

View File

@ -25,7 +25,7 @@ export async function fetchGitLabMergeRequestHeadRef(
options: { localGitExecOptions?: LocalGitExecOptions } = {}
): Promise<string> {
if (!isValidReviewHeadNumber(mrIid)) {
throw new Error(`Invalid merge request iid: ${mrIid}`)
throw new Error(`Invalid merge request iid: ${String(mrIid)}`)
}
if (!isSafeReviewHeadFetchRemote(remote)) {
throw new Error('Merge request fetch remote must not start with "-".')

View File

@ -10,6 +10,7 @@ import type {
GitLabPipelineJob,
GitLabWorkItem,
GitLabWorkItemDetails,
IssueSourcePreference,
MRComment
} from '../../shared/types'
import { mapIssueToWorkItem, mapMRToWorkItem } from './mappers'
@ -24,7 +25,6 @@ import {
type LocalGitExecOptions,
type ProjectRef
} from './gl-utils'
import type { IssueSourcePreference } from '../../shared/types'
function encodedProject(projectPath: string): string {
return encodeURIComponent(projectPath)

View File

@ -20,7 +20,15 @@ import { StatsCollector, initStatsPath } from './stats/collector'
import { ClaudeUsageStore, initClaudeUsagePath } from './claude-usage/store'
import { CodexUsageStore, initCodexUsagePath } from './codex-usage/store'
import { OpenCodeUsageStore, initOpenCodeUsagePath } from './opencode-usage/store'
import { killAllPty } from './ipc/pty'
import {
killAllPty,
clearProviderPtyState,
getPtyIdForPaneKey,
registerPaneKeyTeardownListener,
getLocalPtyProvider,
getSshPtyProvider,
registerHeadlessPtyRuntime
} from './ipc/pty'
import { initDaemonPtyProvider, disconnectDaemon, shutdownDaemon } from './daemon/daemon-init'
import { closeAllWatchers } from './ipc/filesystem-watcher'
import { disposeWorktreeBaseDirectoryWatchers } from './ipc/worktree-base-directory-watcher'
@ -203,14 +211,6 @@ import { setDefaultWslDistroOverride } from './git/runner'
import { getRepoIdFromWorktreeId } from '../shared/worktree-id'
import { parseWorkspaceKey } from '../shared/workspace-scope'
import { setMigrationUnsupportedPtyListener } from './agent-hooks/migration-unsupported-pty-state'
import {
clearProviderPtyState,
getPtyIdForPaneKey,
registerPaneKeyTeardownListener,
getLocalPtyProvider,
getSshPtyProvider,
registerHeadlessPtyRuntime
} from './ipc/pty'
import { AgentBrowserBridge } from './browser/agent-browser-bridge'
import { EmulatorBridge } from './emulator/emulator-bridge'
import { browserCertificateTrustController, browserManager } from './browser/browser-manager'

View File

@ -121,21 +121,18 @@ async function scanAiVaultSessionsByHostScope(
if (executionHostScope === 'all') {
const runtimeHosts = getActiveRuntimeAiVaultHostInfosResult()
const runtimeResults = runtimeHosts.issue ? [runtimeHosts.issue] : []
return mergeAiVaultListResults(
await Promise.all([
scanLocalAiVaultSessions(args),
...getActiveSshAiVaultHostInfos().map((hostInfo) =>
scanSshAiVaultSessions(hostInfo.targetId, args)
),
...runtimeHosts.hostInfos.map((hostInfo) =>
scanRuntimeAiVaultSessions(hostInfo, args, {
timeoutMs: AI_VAULT_ALL_HOST_RUNTIME_TIMEOUT_MS
})
),
...runtimeResults
]),
args?.limit
)
const scannedResults = await Promise.all([
scanLocalAiVaultSessions(args),
...getActiveSshAiVaultHostInfos().map((hostInfo) =>
scanSshAiVaultSessions(hostInfo.targetId, args)
),
...runtimeHosts.hostInfos.map((hostInfo) =>
scanRuntimeAiVaultSessions(hostInfo, args, {
timeoutMs: AI_VAULT_ALL_HOST_RUNTIME_TIMEOUT_MS
})
)
])
return mergeAiVaultListResults([...scannedResults, ...runtimeResults], args?.limit)
}
const parsed = parseExecutionHostId(executionHostScope)

View File

@ -20,8 +20,7 @@
import { app, dialog, ipcMain, shell } from 'electron'
import { existsSync, mkdirSync, unlinkSync, writeFileSync } from 'node:fs'
import { arch as osArch, platform as osPlatform, release as osRelease } from 'node:os'
import { tmpdir } from 'node:os'
import { arch as osArch, platform as osPlatform, release as osRelease, tmpdir } from 'node:os'
import { join } from 'node:path'
import {
collectDiagnosticBundle,

View File

@ -2,11 +2,13 @@ import { app, ipcMain } from 'electron'
import type { Store } from '../persistence'
import {
getEphemeralVmRecipeResultConnection,
getEphemeralVmRecipeResultWarnings,
redactEphemeralVmRecipeDiagnosticText,
type EphemeralVmRecipeResultWarning,
type EphemeralVmRecipeDoctorResult
} from '../../shared/ephemeral-vm-recipes'
import {
getEphemeralVmRecipeResultWarnings,
redactEphemeralVmRecipeDiagnosticText,
type EphemeralVmRecipeResultWarning
} from '../../shared/ephemeral-vm-recipe-diagnostics'
// Why: import directly from the doctor module (not the barrel) — it uses Node
// fs/path and must stay out of the browser bundle that imports the barrel.
import { doctorEphemeralVmRecipe } from '../../shared/ephemeral-vm-recipe-doctor'

View File

@ -13,7 +13,8 @@ import type {
GitHubPRRefreshCandidate,
GitHubPRRefreshEnqueueResult,
GitHubPRRefreshReason,
PRRefreshOutcome
PRRefreshOutcome,
GitHubPRFile
} from '../../shared/types'
import { getRepoExecutionHostId } from '../../shared/execution-host'
import type { TaskSourceContext } from '../../shared/task-source-context'
@ -68,7 +69,6 @@ import {
type PRRefreshValidationDenialReason
} from '../github/pr-refresh-validation-backoff'
import { getLocalProjectWorktreeGitOptions } from '../project-runtime-git-options'
import type { GitHubPRFile } from '../../shared/types'
import { dispatchWorkItem, type WorkItemArgs } from './github-work-item-args'
import {
getProjectViewTable,

View File

@ -205,7 +205,10 @@ vi.mock('../codex/codex-pane-account-registry', () => ({
recordCodexPaneAccount: recordCodexPaneAccountMock,
forgetCodexPaneAccount: forgetCodexPaneAccountMock
}))
import { LocalPtyProvider } from '../providers/local-pty-provider'
import {
LocalPtyProvider,
_resetLocalPtyProviderStateForTest
} from '../providers/local-pty-provider'
import { makePaneKey } from '../../shared/stable-pane-id'
import { SETUP_AGENT_SEQUENCE_STARTUP_COMMAND_ENV } from '../../shared/setup-agent-sequencing'
import {
@ -228,7 +231,6 @@ import {
restorePtyIncarnation,
type PrepareCodexSessionResume
} from './pty'
import { _resetLocalPtyProviderStateForTest } from '../providers/local-pty-provider'
import { resetMacosLoginShellPreflightForTests } from '../providers/macos-tcc-login-shell'
import {
_resetHiddenRendererPtyDeliveryGateForTest,

View File

@ -34,7 +34,11 @@ import { registerDashboardPopoutHandlers } from './dashboard-popout'
import { registerTerminalPreviewHandlers } from './terminal-preview'
import { registerDeveloperPermissionHandlers } from './developer-permissions'
import { registerComputerUsePermissionHandlers } from './computer-use-permissions'
import { setTrustedBrowserRendererWebContentsId, setAgentBrowserBridgeRef } from './browser'
import {
setTrustedBrowserRendererWebContentsId,
setAgentBrowserBridgeRef,
registerBrowserHandlers
} from './browser'
import { registerSessionHandlers } from './session'
import { registerSettingsHandlers } from './settings'
import { registerDiagnosticsHandlers } from './diagnostics'
@ -45,7 +49,6 @@ import { registerLocalhostWorktreeLabelHandlers } from './localhost-worktree-lab
import { registerAutomationHandlers } from './automations'
import { registerKeybindingHandlers } from './keybindings'
import { registerTelemetryHandlers } from './telemetry'
import { registerBrowserHandlers } from './browser'
import { registerShellHandlers } from './shell'
import { registerPetHandlers } from './pet'
import { registerPluginHandlers } from './plugins'

View File

@ -1,5 +1,5 @@
import { ipcMain } from 'electron'
import type { SshConnectionManager } from '../ssh/ssh-connection'
import type { SshConnectionManager } from '../ssh/ssh-connection-manager'
import type { SshExecOptions } from '../ssh/ssh-connection-utils'
import { powerShellCommand, powerShellLiteral } from '../ssh/ssh-remote-powershell'

View File

@ -106,7 +106,7 @@ vi.mock('../ssh/ssh-connection-store', () => ({
}
}))
vi.mock('../ssh/ssh-connection', () => ({
vi.mock('../ssh/ssh-connection-manager', () => ({
SshConnectionManager: class MockSshConnectionManager {
constructor(callbacks: unknown) {
const manager = (mockNextConnectionManagers.shift() ??

View File

@ -3,7 +3,8 @@ import { ipcMain, powerMonitor, type BrowserWindow } from 'electron'
import { appendFileSync } from 'node:fs'
import type { Store } from '../persistence'
import { SshConnectionStore } from '../ssh/ssh-connection-store'
import { SshConnectionManager, type SshConnectionCallbacks } from '../ssh/ssh-connection'
import type { SshConnectionCallbacks } from '../ssh/ssh-connection'
import { SshConnectionManager } from '../ssh/ssh-connection-manager'
import type { SshChannelMultiplexer } from '../ssh/ssh-channel-multiplexer'
import { SshRelaySession, type SshRelayAiVaultHostInfo } from '../ssh/ssh-relay-session'
import { SshPortForwardManager } from '../ssh/ssh-port-forward'

View File

@ -17,8 +17,7 @@ import { getOnboardingCohortAtEmit } from '../telemetry/onboarding-cohort-classi
import { resolveConsent, type ConsentState } from '../telemetry/consent'
import type { Store } from '../persistence'
import { isCohortExtendedEvent, isOnboardingEvent } from '../../shared/telemetry-events'
import type { EventName, EventProps } from '../../shared/telemetry-events'
import type { OptInVia } from '../../shared/telemetry-events'
import type { EventName, EventProps, OptInVia } from '../../shared/telemetry-events'
// Module-level store ref: handlers need a synchronous `settings.telemetry` read to derive `via` before any mutation.
let storeRef: Store | null = null

View File

@ -28,7 +28,7 @@ import {
resolveDefaultBaseRefViaExec,
resolveDefaultBaseRefWithLocalGit
} from '../git/repo'
import { resolveLocalGitUsername } from '../git/git-username'
import { resolveLocalGitUsername, getSshGitUsername } from '../git/git-username'
import { hasCommitObjectViaGitExec } from '../git/commit-object-ref'
import { resolveWorktreeCreateBase } from '../worktree-create-base'
import { resolveWorktreeAddBaseRef } from '../../shared/worktree-base-ref'
@ -38,8 +38,11 @@ import { validateGitPushTarget } from '../git/push-target-validation'
import { assertGitPushTargetShape } from '../../shared/git-push-target-validation'
import { gitExecFileAsync } from '../git/runner'
import { parseGitHubOwnerRepo } from '../github/gh-utils'
import type { OrcaRuntimeService } from '../runtime/orca-runtime'
import type { RemoteFetchResult, RemoteTrackingBase } from '../runtime/orca-runtime'
import type {
OrcaRuntimeService,
RemoteFetchResult,
RemoteTrackingBase
} from '../runtime/orca-runtime'
import { getProjectHostSetupWorktreeMeta } from '../../shared/project-host-setup-projection'
import {
buildPosixRunnerScript,
@ -58,7 +61,6 @@ import { getSshFilesystemProvider } from '../providers/ssh-filesystem-dispatch'
import type { SshGitProvider } from '../providers/ssh-git-provider'
import { TUI_AGENT_CONFIG, isTuiAgent } from '../../shared/tui-agent-config'
import { isWindowsAbsolutePathLike } from '../../shared/cross-platform-path'
import { getSshGitUsername } from '../git/git-username'
import { runWorktreeChangeInvalidators } from './worktree-change-invalidators'
import {
registerOptionalSshWorktreeCreateRoots,

View File

@ -94,7 +94,16 @@ import {
type SshTarget
} from '../shared/ssh-types'
import { isFolderRepo } from '../shared/repo-kind'
import { getRepoExecutionHostId, parseExecutionHostId } from '../shared/execution-host'
import {
getRepoExecutionHostId,
parseExecutionHostId,
LOCAL_EXECUTION_HOST_ID,
normalizeExecutionHostOrder,
normalizeExecutionHostId,
normalizeVisibleExecutionHostIds,
toSshExecutionHostId,
type ExecutionHostId
} from '../shared/execution-host'
import {
getDefaultPersistedState,
getDefaultNotificationSettings,
@ -116,14 +125,6 @@ import { normalizeStatusBarUsageMode } from '../shared/status-bar-usage-mode'
import { isExistingPersistedProfile } from '../shared/project-order-manual-default-notice'
import { resolveUsagePercentageDisplayChangeNoticeDismissed } from '../shared/usage-percentage-display-change-notice'
import { normalizePRBotAuthorOverrides } from '../shared/pr-bot-author-overrides'
import {
LOCAL_EXECUTION_HOST_ID,
normalizeExecutionHostOrder,
normalizeExecutionHostId,
normalizeVisibleExecutionHostIds,
toSshExecutionHostId,
type ExecutionHostId
} from '../shared/execution-host'
import { toRelaySshPtyId } from './providers/ssh-pty-id'
import {
migrateUiHostScopeSshTargetId,

View File

@ -60,11 +60,10 @@ export class PluginContentPackRegistry {
while (true) {
const approveAtomically = (plugin: ValidDiscoveredPlugin): boolean =>
approvedKeys.has(plugin.pluginKey) && !excluded.has(plugin.pluginKey)
await Promise.all([
this.languagePacks.reconcile(discovered, approveAtomically),
this.vmRecipes.reconcile(discovered, approveAtomically),
this.commands.reconcile(discovered, approveAtomically, keybindings)
])
const languagePacks = this.languagePacks.reconcile(discovered, approveAtomically)
const vmRecipes = this.vmRecipes.reconcile(discovered, approveAtomically)
this.commands.reconcile(discovered, approveAtomically, keybindings)
await Promise.all([languagePacks, vmRecipes])
let foundNewError = false
for (const pluginKey of approvedKeys) {

View File

@ -1,7 +1,6 @@
/* eslint-disable max-lines -- Why: splitting spawn() would scatter tightly coupled PTY lifecycle logic (scan → ready → write → exit) with no cleaner ownership seam. */
import { basename, delimiter } from 'node:path'
import { basename, delimiter, win32 as pathWin32 } from 'node:path'
import { randomUUID } from 'node:crypto'
import { win32 as pathWin32 } from 'node:path'
import { resolveWindowsShellLaunchArgs } from './windows-shell-args'
import {
resolveEffectiveWindowsPowerShell,

View File

@ -1009,7 +1009,7 @@ describe('SshGitProvider', () => {
expect(mux.request).toHaveBeenCalledTimes(1)
pendingDiff.resolve()
await expect(Promise.all(reads)).resolves.toEqual(Array(8).fill(diff))
await expect(Promise.all(reads)).resolves.toEqual(Array.from({ length: 8 }, () => diff))
mux.request.mockReset()
const branchDiffs = [diff]
@ -1026,7 +1026,9 @@ describe('SshGitProvider', () => {
await waitForRequestCount(mux.request, 1)
expect(mux.request).toHaveBeenCalledTimes(1)
pendingBranchDiff.resolve()
await expect(Promise.all(branchReads)).resolves.toEqual(Array(8).fill(branchDiffs))
await expect(Promise.all(branchReads)).resolves.toEqual(
Array.from({ length: 8 }, () => branchDiffs)
)
mux.request.mockReset()
const pendingCommitDiff = deferredValue(diff)
@ -1043,7 +1045,7 @@ describe('SshGitProvider', () => {
await waitForRequestCount(mux.request, 1)
expect(mux.request).toHaveBeenCalledTimes(1)
pendingCommitDiff.resolve()
await expect(Promise.all(commitReads)).resolves.toEqual(Array(8).fill(diff))
await expect(Promise.all(commitReads)).resolves.toEqual(Array.from({ length: 8 }, () => diff))
})
it('retries diff RPCs after an in-flight rejection settles', async () => {

View File

@ -20,14 +20,14 @@ import {
readActiveClaudeKeychainCredentials,
readActiveClaudeKeychainCredentialsStrict,
readManagedClaudeKeychainCredentials,
writeActiveClaudeKeychainCredentials
writeActiveClaudeKeychainCredentials,
writeManagedClaudeKeychainCredentials
} from '../claude-accounts/keychain'
import {
readClaudeManagedAuthFile,
resolveOwnedClaudeManagedAuthPath,
writeClaudeManagedAuthFile
} from '../claude-accounts/managed-auth-path'
import { writeManagedClaudeKeychainCredentials } from '../claude-accounts/keychain'
import {
isOauthTokenExpiring,
refreshClaudeOauthCredentials

View File

@ -1286,7 +1286,7 @@ export class RuntimeFileCommands {
callback: (events: FsChangeEvent[]) => void,
onTerminalError: (error: Error) => void = () => undefined,
signal?: AbortSignal
): Promise<() => void> {
): Promise<() => Promise<void>> {
const target = await this.resolveFileExplorerPath(worktreeSelector, '')
const open = async (): Promise<{
unsubscribe: () => Promise<void>

View File

@ -184,7 +184,20 @@ import type {
TuiAgent,
WorkspaceCreateTelemetrySource,
WorkspaceSessionState,
DirEntry
DirEntry,
GitHubIssueUpdate,
GitHubPullRequestStateUpdate,
GitHubPRFile,
GitHubPRReviewCommentInput,
GitLabIssueUpdate,
GitLabMRInlineCommentInput,
GitLabProjectRef,
GitLabWorkItem,
ListWorkItemsResult,
MRListState,
PRRefreshOutcome,
ClaudeRateLimitAccountsState,
CodexRateLimitAccountsState
} from '../../shared/types'
import { assertWorktreeUnlockedForRemoval } from '../../shared/worktree-removal'
import {
@ -237,7 +250,65 @@ import type {
} from '../../shared/linear-agent-access'
import {
HEADLESS_RUNTIME_WINDOW_ID,
type RuntimeDesktopWindowStatus
type RuntimeDesktopWindowStatus,
type RuntimeGraphStatus,
type RuntimeRepoSearchRefs,
type RuntimeTerminalRead,
type RuntimeTerminalRename,
type RuntimeTerminalAgentStatus,
type RuntimeTerminalSend,
type RuntimeTerminalCreate,
type RuntimeTerminalPresentation,
type RuntimeTerminalSplit,
type RuntimeTerminalFocus,
type RuntimeTerminalClose,
type RuntimeTerminalListResult,
type RuntimeTerminalOrphanAdoptionRequest,
type RuntimeTerminalOrphanAdoptionResult,
type RuntimeWorktreeTerminalSleepResult,
type RuntimeTerminalResolvePane,
type RuntimeTerminalState,
type RuntimeStatus,
type RuntimeSyncWindowGraphResult,
type RuntimeTerminalWait,
type RuntimeTerminalWaitBlockedReason,
type RuntimeTerminalWaitCondition,
type RuntimeWorktreePsSummary,
type RuntimeWorktreeAgentRow,
type RuntimeWorktreeStatus,
type RuntimeSpeechModelSummary,
type RuntimeSpeechSetupState,
type RuntimeTerminalShow,
type RuntimeTerminalSummary,
type RuntimeTerminalVisualGroupNode,
type RuntimeTerminalVisualLayout,
type RuntimeTerminalVisualLayoutNode,
type RuntimeTerminalVisualPaneNode,
type RuntimeTerminalVisualTab,
type RuntimeSyncedLeaf,
type RuntimeSyncedTab,
type RuntimeMarkdownReadTabResult,
type RuntimeMarkdownSaveTabResult,
type RuntimeMobileSessionCreateTerminalResult,
type RuntimeMobileSessionClientTab,
type RuntimeMobileSessionTabCloseResult,
type RuntimeMobileSessionMarkdownTab,
type RuntimeMobileSessionTabMove,
type RuntimeMobileSessionTabMoveResult,
type RuntimeMobileSessionTabGroup,
type RuntimeMobileSessionSnapshotTab,
type RuntimeMobileSessionTerminalTab,
type RuntimeMobileSessionBrowserTab,
type RuntimeMobileSessionTabsRemovedResult,
type RuntimeMobileSessionTabsResult,
type RuntimeMobileSessionTabsSnapshot,
type RuntimeSessionTabCloseReason,
type RuntimeBrowserDriverState,
type RuntimeTerminalDriverState,
type RuntimeSyncWindowGraph,
type RuntimeWorktreeListResult,
type BrowserTabInfo,
type BrowserScreencastResult
} from '../../shared/runtime-types'
import {
LINEAR_SEARCH_MAX_LIMIT,
@ -377,66 +448,6 @@ import {
scanWorkspacePortProbes
} from '../ports/workspace-port-ownership'
import { advertisedUrlWatcher } from '../ports/advertised-url-watcher'
import type {
RuntimeGraphStatus,
RuntimeRepoSearchRefs,
RuntimeTerminalRead,
RuntimeTerminalRename,
RuntimeTerminalAgentStatus,
RuntimeTerminalSend,
RuntimeTerminalCreate,
RuntimeTerminalPresentation,
RuntimeTerminalSplit,
RuntimeTerminalFocus,
RuntimeTerminalClose,
RuntimeTerminalListResult,
RuntimeTerminalOrphanAdoptionRequest,
RuntimeTerminalOrphanAdoptionResult,
RuntimeWorktreeTerminalSleepResult,
RuntimeTerminalResolvePane,
RuntimeTerminalState,
RuntimeStatus,
RuntimeSyncWindowGraphResult,
RuntimeTerminalWait,
RuntimeTerminalWaitBlockedReason,
RuntimeTerminalWaitCondition,
RuntimeWorktreePsSummary,
RuntimeWorktreeAgentRow,
RuntimeWorktreeStatus,
RuntimeSpeechModelSummary,
RuntimeSpeechSetupState,
RuntimeTerminalShow,
RuntimeTerminalSummary,
RuntimeTerminalVisualGroupNode,
RuntimeTerminalVisualLayout,
RuntimeTerminalVisualLayoutNode,
RuntimeTerminalVisualPaneNode,
RuntimeTerminalVisualTab,
RuntimeSyncedLeaf,
RuntimeSyncedTab,
RuntimeMarkdownReadTabResult,
RuntimeMarkdownSaveTabResult,
RuntimeMobileSessionCreateTerminalResult,
RuntimeMobileSessionClientTab,
RuntimeMobileSessionTabCloseResult,
RuntimeMobileSessionMarkdownTab,
RuntimeMobileSessionTabMove,
RuntimeMobileSessionTabMoveResult,
RuntimeMobileSessionTabGroup,
RuntimeMobileSessionSnapshotTab,
RuntimeMobileSessionTerminalTab,
RuntimeMobileSessionBrowserTab,
RuntimeMobileSessionTabsRemovedResult,
RuntimeMobileSessionTabsResult,
RuntimeMobileSessionTabsSnapshot,
RuntimeSessionTabCloseReason,
RuntimeBrowserDriverState,
RuntimeTerminalDriverState,
RuntimeSyncWindowGraph,
RuntimeWorktreeListResult,
BrowserTabInfo,
BrowserScreencastResult
} from '../../shared/runtime-types'
import type { AutomationService } from '../automations/service'
import { RuntimeBrowserCommands } from './orca-runtime-browser'
import { RemoteRuntimeTerminalCreateIdempotency } from './remote-runtime-terminal-create-idempotency'
@ -474,7 +485,13 @@ import {
deriveClientSessionTabSelection,
projectClientSessionTabSelection
} from './client-session-tab-selection'
import type { PtyProviderBufferSnapshot } from '../providers/types'
import type {
PtyProviderBufferSnapshot,
IFilesystemProvider,
IPtyProvider,
PtyProcessInfo,
PtyTransientFact
} from '../providers/types'
import { ClaudeAgentTeamsService } from './claude-agent-teams-service'
import type {
AgentTeamsTmuxCompatRequest,
@ -527,9 +544,9 @@ import {
addPRReviewCommentReply,
listLabels,
listAssignableUsers,
type MainWorkItem
type MainWorkItem,
type GitHubPRBranchLookupOptions
} from '../github/client'
import type { GitHubPRBranchLookupOptions } from '../github/client'
import { resolveGitHubPrStartPoint } from '../github/pr-start-point'
import {
fetchGitHubPullRequestHeadRef,
@ -579,19 +596,6 @@ import {
type GitLabIssueListState
} from '../gitlab/gitlab-preload-args'
import { recordGitLabProjectRecent } from '../gitlab/gitlab-project-recents'
import type {
GitHubIssueUpdate,
GitHubPullRequestStateUpdate,
GitHubPRFile,
GitHubPRReviewCommentInput,
GitLabIssueUpdate,
GitLabMRInlineCommentInput,
GitLabProjectRef,
GitLabWorkItem,
ListWorkItemsResult,
MRListState,
PRRefreshOutcome
} from '../../shared/types'
import { inspectSetupScriptImportCandidates } from '../../shared/setup-script-imports'
import type {
CreateHostedReviewInput,
@ -785,7 +789,7 @@ import {
removeWorktree
} from '../git/worktree'
import type { AddWorktreeOptions, AddWorktreeResult } from '../git/worktree'
import { isENOENT } from '../ipc/filesystem-auth'
import { isENOENT, invalidateAuthorizedRootsCache } from '../ipc/filesystem-auth'
import {
createSetupRunnerScript,
getDefaultTabCommandTrustContent,
@ -862,7 +866,6 @@ import {
UNREGISTERED_MISSING_WORKTREE_MESSAGE
} from '../worktree-removal-safety'
import { prefetchWorktreeCreateBase } from '../worktree-create-base-prefetch'
import { invalidateAuthorizedRootsCache } from '../ipc/filesystem-auth'
import { prepareLocalWorktreeRootForRepo } from '../worktree-root-preparation'
import {
closeLocalWatcherForWorktreePath,
@ -894,12 +897,6 @@ import {
createMobileSessionTabsNotifyCoalescer,
type MobileSessionTabsNotifyCoalescer
} from './mobile-session-tabs-notify-coalescer'
import type {
IFilesystemProvider,
IPtyProvider,
PtyProcessInfo,
PtyTransientFact
} from '../providers/types'
import { getSshFilesystemProvider } from '../providers/ssh-filesystem-dispatch'
import {
assertFolderWorkspacePathUsable,
@ -922,7 +919,6 @@ import type {
} from '../codex-accounts/service'
import type { CodexAccountSelectionTarget } from '../codex-accounts/runtime-selection'
import type { RateLimitService } from '../rate-limits/service'
import type { ClaudeRateLimitAccountsState, CodexRateLimitAccountsState } from '../../shared/types'
import { applyPRBotAuthorOverride } from '../../shared/pr-bot-author-overrides'
import type { CodexRateLimitResetOutcome, RateLimitState } from '../../shared/rate-limit-types'
import type { CodexResetCreditExpectedScope } from '../../shared/codex-reset-credit-scope'

View File

@ -367,7 +367,7 @@ export class Coordinator {
terminals.push(created.handle)
this.opts.onLog(`Created worker terminal ${created.handle}`)
} catch (err) {
this.opts.onLog(`Failed to create terminal: ${err}`)
this.opts.onLog(`Failed to create terminal: ${String(err)}`)
return
}
}
@ -383,7 +383,7 @@ export class Coordinator {
try {
await this.dispatchTask(task, targetHandle)
} catch (err) {
this.opts.onLog(`Failed to dispatch task ${task.id}: ${err}`)
this.opts.onLog(`Failed to dispatch task ${task.id}: ${String(err)}`)
}
}
}

View File

@ -6,8 +6,10 @@ import {
RUNTIME_CAPABILITIES,
RUNTIME_PROTOCOL_VERSION
} from '../../../../shared/protocol-version'
import { AGENT_SESSION_RPC_ERROR_CODES } from '../../../../shared/agent-session-host-authority'
import { AGENT_SESSION_OPERATION_FUTURE_SKEW_MS } from '../../../../shared/agent-session-host-authority'
import {
AGENT_SESSION_RPC_ERROR_CODES,
AGENT_SESSION_OPERATION_FUTURE_SKEW_MS
} from '../../../../shared/agent-session-host-authority'
import type { OrcaRuntimeService } from '../../orca-runtime'
import type { RpcRequest, RpcResponse } from '../core'
import { RpcDispatcher } from '../dispatcher'

View File

@ -3,8 +3,7 @@ import { defineMethod, type RpcMethod } from '../core'
import { OptionalBoolean } from '../schemas'
import { restampAiVaultListResult } from '../../../ai-vault/session-list-results'
import { AI_VAULT_AGENTS, AI_VAULT_SCOPE_PATHS_MAX_COUNT } from '../../../../shared/ai-vault-types'
import { LOCAL_EXECUTION_HOST_ID } from '../../../../shared/execution-host'
import { parseExecutionHostId } from '../../../../shared/execution-host'
import { LOCAL_EXECUTION_HOST_ID, parseExecutionHostId } from '../../../../shared/execution-host'
// Why: bound limit + scopePaths so a client cannot force an unbounded scan.
// Each scopePath is a host-local match prefix (validated/capped, never used for

View File

@ -17,9 +17,9 @@ export async function runFileWatchStream(args: {
let settled = false
let setupFailed = false
let watchReady = false
let unwatch: (() => void) | null = null
let unwatch: (() => Promise<void>) | null = null
let terminalError: Error | null = null
let setupPromise: Promise<() => void> | null = null
let setupPromise: Promise<() => Promise<void>> | null = null
let cleanupPromise: Promise<void> | null = null
let logicalCleanupStarted = false
let endEmitted = false

View File

@ -1,6 +1,9 @@
import { z } from 'zod'
import type { NativeChatBlock, NativeChatMessage } from '../../../../shared/native-chat-types'
import type { AgentType } from '../../../../shared/native-chat-types'
import type {
NativeChatBlock,
NativeChatMessage,
AgentType
} from '../../../../shared/native-chat-types'
import {
readNativeChatTranscriptTail,
subscribeNativeChatTranscript

View File

@ -50,7 +50,7 @@ async function sendRequest(
let buffer = ''
socket.setEncoding('utf8')
socket.once('error', reject)
socket.on('data', (chunk) => {
socket.on('data', (chunk: string) => {
buffer += chunk
const newlineIndex = buffer.indexOf('\n')
if (newlineIndex === -1) {
@ -4061,7 +4061,7 @@ describe('OrcaRuntimeRpcServer', () => {
let buffer = ''
socket.setEncoding('utf8')
socket.once('error', reject)
socket.on('data', (chunk) => {
socket.on('data', (chunk: string) => {
buffer += chunk
const newlineIndex = buffer.indexOf('\n')
if (newlineIndex === -1) {

View File

@ -301,7 +301,7 @@ export function parseJsonRpcMessage(payload: Buffer): JsonRpcMessage {
const text = payload.toString('utf-8')
const msg = JSON.parse(text) as JsonRpcMessage
if (msg.jsonrpc !== '2.0') {
throw new Error(`Invalid JSON-RPC version: ${(msg as Record<string, unknown>).jsonrpc}`)
throw new Error(`Invalid JSON-RPC version: ${String((msg as Record<string, unknown>).jsonrpc)}`)
}
return msg
}

View File

@ -154,10 +154,10 @@ vi.mock('./ssh-config-parser', () => ({
import {
SshConnection,
SshConnectionManager,
shouldUseSystemSshTransport,
type SshConnectionCallbacks
} from './ssh-connection'
import { SshConnectionManager } from './ssh-connection-manager'
import { resolveWithSshG, type SshResolvedConfig } from './ssh-config-parser'
import {
downloadFileViaSystemSsh,

View File

@ -1371,5 +1371,3 @@ export function shouldUseSystemSshTransport(
resolved?.proxyJump != null
)
}
export { SshConnectionManager } from './ssh-connection-manager'

View File

@ -32,7 +32,15 @@ import type {
} from '../shared/terminal-render-desync-evidence'
import type { MobileRelayStatus } from '../shared/mobile-relay-status'
import type { MobilePairingConnectionMode } from '../shared/mobile-pairing-connection-mode'
import type { SshMutationExpectation } from '../shared/ssh-types'
import type {
SshMutationExpectation,
SshConnectionState,
SshConfigImportResult,
SshTargetAddResult,
SshTarget,
PortForwardEntry,
EnrichedDetectedPort
} from '../shared/ssh-types'
import type {
CreateLocalOrcaProfileArgs,
CreateLocalOrcaProfileResult,
@ -260,10 +268,8 @@ import type {
import type { SetupScriptImportCandidate } from '../shared/setup-script-imports'
import type { GitHistoryOptions, GitHistoryResult } from '../shared/git-history'
import type { PublicKnownRuntimeEnvironment } from '../shared/runtime-environments'
import type {
EphemeralVmRecipeDoctorResult,
EphemeralVmRecipeResultWarning
} from '../shared/ephemeral-vm-recipes'
import type { EphemeralVmRecipeDoctorResult } from '../shared/ephemeral-vm-recipes'
import type { EphemeralVmRecipeResultWarning } from '../shared/ephemeral-vm-recipe-diagnostics'
import type { EphemeralVmRuntimeRecord } from '../shared/ephemeral-vm-runtimes'
import type { RuntimeAccessGrant } from '../shared/runtime-access-grants'
import type { RuntimeRpcResponse } from '../shared/runtime-rpc-envelope'
@ -431,14 +437,6 @@ import type {
WorkspacePortScanResult
} from '../shared/workspace-ports'
import type { GhAuthDiagnostic } from '../shared/github-auth-types'
import type {
SshConnectionState,
SshConfigImportResult,
SshTargetAddResult,
SshTarget,
PortForwardEntry,
EnrichedDetectedPort
} from '../shared/ssh-types'
import type {
CodexUsageBreakdownKind,
CodexUsageBreakdownRow,

View File

@ -21,7 +21,15 @@ import type {
} from '../shared/agent-session-resume'
import type { MobileRelayStatus } from '../shared/mobile-relay-status'
import type { MobilePairingConnectionMode } from '../shared/mobile-pairing-connection-mode'
import type { SshMutationExpectation } from '../shared/ssh-types'
import type {
SshMutationExpectation,
SshConnectionState,
SshConfigImportResult,
SshTargetAddResult,
SshTarget,
PortForwardEntry,
EnrichedDetectedPort
} from '../shared/ssh-types'
import type {
PluginPanelActionOutcome,
PluginPanelEntry
@ -158,14 +166,6 @@ import {
richMarkdownContextMenuCommandChannel,
type RichMarkdownContextMenuCommandPayload
} from '../shared/rich-markdown-context-menu'
import type {
SshConnectionState,
SshConfigImportResult,
SshTargetAddResult,
SshTarget,
PortForwardEntry,
EnrichedDetectedPort
} from '../shared/ssh-types'
import type {
AgentStatusClearIpcPayload,
AgentStatusIpcPayload,
@ -182,7 +182,18 @@ import type {
SpeechTranscriptEvent
} from '../shared/speech-types'
import type { TelemetryConsentState } from '../shared/telemetry-consent-types'
import type { PreflightRuntimeContext, RefreshAgentsResult } from './api-types'
import type {
PreflightRuntimeContext,
RefreshAgentsResult,
NativeChatAppendedPayload,
NativeChatReadSessionResult,
NativeChatSubscriptionFrame,
PluginHostInstallResult,
PluginHostInstallSource,
PluginHostListEntry,
PluginHostLogLine,
PreloadApi
} from './api-types'
import type { AgentKind, LaunchSource, RequestKind } from '../shared/telemetry-events'
import type { AppStarSource } from '../shared/gh-star-source'
import type { ExecutionHostId } from '../shared/execution-host'
@ -205,11 +216,6 @@ import type { KeybindingActionId, KeybindingFileSnapshot } from '../shared/keybi
import type { AiVaultListArgs, AiVaultSubagentListArgs } from '../shared/ai-vault-types'
import type { AiVaultPrepareSessionResumeArgs } from '../shared/ai-vault-resume-preparation'
import type { AgentType } from '../shared/native-chat-types'
import type {
NativeChatAppendedPayload,
NativeChatReadSessionResult,
NativeChatSubscriptionFrame
} from './api-types'
import {
ORCA_APP_RESTART_ABORTED_EVENT,
ORCA_APP_RESTART_STARTED_EVENT,
@ -252,13 +258,6 @@ import type {
} from '../shared/crash-reporting'
import type { RendererHeapStatistics } from '../shared/renderer-heap-statistics'
import { readRendererHeapStatistics } from './renderer-heap-statistics-reader'
import type {
PluginHostInstallResult,
PluginHostInstallSource,
PluginHostListEntry,
PluginHostLogLine,
PreloadApi
} from './api-types'
import {
createUpdaterQuitAbortRelay,
prepareRendererForAppRestart

View File

@ -286,7 +286,7 @@ export function parseJsonRpcMessage(payload: Buffer): JsonRpcMessage {
const text = payload.toString('utf-8')
const msg = JSON.parse(text) as JsonRpcMessage
if (msg.jsonrpc !== '2.0') {
throw new Error(`Invalid JSON-RPC version: ${(msg as Record<string, unknown>).jsonrpc}`)
throw new Error(`Invalid JSON-RPC version: ${String((msg as Record<string, unknown>).jsonrpc)}`)
}
return msg
}

View File

@ -342,7 +342,7 @@ async function main(): Promise<void> {
})
process.on('unhandledRejection', (reason) => {
relayLogLine(`[relay] Unhandled rejection: ${reason}`)
relayLogLine(`[relay] Unhandled rejection: ${String(reason)}`)
})
// Why: guards writes after the stdin/SSH channel drops so keepalive/pty.data frames don't hit a dead pipe (EPIPE).

View File

@ -1,7 +1,6 @@
// @vitest-environment happy-dom
import React from 'react'
import { act } from 'react'
import React, { act } from 'react'
import { createRoot, type Root } from 'react-dom/client'
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
import NewWorkspaceComposerCard from './NewWorkspaceComposerCard'

View File

@ -33,6 +33,10 @@ import { SettingsSwitch } from '@/components/settings/SettingsFormControls'
import type RepoCombobox from '@/components/repo/RepoCombobox'
import AgentCombobox from '@/components/agent/AgentCombobox'
import { getAgentCatalog } from '@/lib/agent-catalog'
import {
DEFAULT_DISABLED_TUI_AGENTS,
filterEnabledTuiAgents
} from '../../../shared/tui-agent-selection'
import { useAppStore } from '@/store'
import { cn } from '@/lib/utils'
import { WORKSPACE_FILE_PATH_MIME } from '@/lib/workspace-file-drag'
@ -44,7 +48,6 @@ import {
} from '@/lib/text-control-paste'
import { getScreenSubmitModifierLabel } from '@/lib/screen-submit-shortcut'
import { useContextualTour } from '@/components/contextual-tours/use-contextual-tour'
import { filterEnabledTuiAgents } from '../../../shared/tui-agent-selection'
import type {
GitHubWorkItem,
GitLabWorkItem,
@ -955,7 +958,9 @@ export default function NewWorkspaceComposerCard({
const openModal = useAppStore((s) => s.openModal)
const activeModal = useAppStore((s) => s.activeModal)
const defaultTuiAgent = useAppStore((s) => s.settings?.defaultTuiAgent ?? null)
const disabledTuiAgents = useAppStore((s) => s.settings?.disabledTuiAgents ?? [])
const disabledTuiAgents = useAppStore(
(s) => s.settings?.disabledTuiAgents ?? DEFAULT_DISABLED_TUI_AGENTS
)
const updateSettings = useAppStore((s) => s.updateSettings)
const nameInputFocusFrameRef = React.useRef<number | null>(null)
const branchNameInputId = React.useId()

View File

@ -44,7 +44,8 @@ import { getLocalPreflightContext, localPreflightContextKey } from '@/lib/local-
import { getProviderRuntimeContextKey } from '@/lib/provider-runtime-context'
import {
getSettingsFocusedExecutionHostId,
parseExecutionHostId
parseExecutionHostId,
getRepoExecutionHostId
} from '../../../shared/execution-host'
import { Button } from '@/components/ui/button'
import { ButtonGroup } from '@/components/ui/button-group'
@ -179,7 +180,6 @@ import {
readLinearBoardIssueDragData,
writeLinearBoardIssueDragData
} from '@/lib/linear-board-drag-payload'
import { getRepoExecutionHostId } from '../../../shared/execution-host'
import { projectHostSetupProjectionFromRepos } from '../../../shared/project-host-setup-projection'
import { TASK_SOURCE_CONTEXT_RUNTIME_CAPABILITY } from '../../../shared/protocol-version'
import {

View File

@ -1,7 +1,6 @@
// @vitest-environment happy-dom
import React, { type ReactNode } from 'react'
import { act } from 'react'
import React, { type ReactNode, act } from 'react'
import { createRoot, type Root } from 'react-dom/client'
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
import type { AgentSessionContinuationRequest } from '@/lib/agent-session-continuation'

View File

@ -1,7 +1,6 @@
// @vitest-environment happy-dom
import { createRef, type MutableRefObject } from 'react'
import { act } from 'react'
import { createRef, type MutableRefObject, act } from 'react'
import { createRoot, type Root } from 'react-dom/client'
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
import type { DictationState } from '../../../../shared/speech-types'

View File

@ -1,6 +1,5 @@
// @vitest-environment happy-dom
import { Suspense } from 'react'
import { act } from 'react'
import { act, Suspense } from 'react'
import { createRoot, type Root } from 'react-dom/client'
import { afterEach, describe, expect, it, vi } from 'vitest'
import type { OpenFile } from '@/store/slices/editor'

View File

@ -4,7 +4,7 @@ import React, { useRef, useCallback, useEffect, useLayoutEffect, useMemo, useSta
import Editor, { type OnMount } from '@monaco-editor/react'
import type { editor } from 'monaco-editor'
import { toast } from 'sonner'
import type { MarkdownDocument } from '../../../../shared/types'
import type { MarkdownDocument, DiffComment } from '../../../../shared/types'
import { useAppStore } from '@/store'
import { scrollTopCache, cursorPositionCache, setWithLRU } from '@/lib/scroll-cache'
import '@/lib/monaco-setup'
@ -36,7 +36,6 @@ import {
} from './monaco-markdown-doc-link-decorations'
import { buildGitConflictDecorations, hasGitConflictMarkers } from './monaco-conflict-decorations'
import { selectWorktreeDiffComments } from '@/store/worktree-diff-comments-selector'
import type { DiffComment } from '../../../../shared/types'
import { isMarkdownComment } from '@/lib/diff-comment-compat'
import { formatMarkdownReviewNotes, type MarkdownReviewNote } from '@/lib/markdown-review-notes'
import { useDiffCommentDecorator } from '../diff-comments/useDiffCommentDecorator'

View File

@ -20,8 +20,11 @@ import {
deriveNotesSendAgentTargets,
type NotesSendAgentTarget
} from '@/lib/notes-send-agent-targets'
import { agentKindForAgentType, formatAgentTypeLabel } from '@/lib/agent-status'
import { agentTypeToIconAgent } from '@/lib/agent-status'
import {
agentKindForAgentType,
formatAgentTypeLabel,
agentTypeToIconAgent
} from '@/lib/agent-status'
import { track } from '@/lib/telemetry'
import { useNow } from '@/components/dashboard/useNow'
import type { DashboardAgentRow as DashboardAgentRowData } from '@/components/dashboard/useDashboardData'

View File

@ -32,9 +32,9 @@ function markdownAfterTextReplace(content: string, search: string, replacement:
})
try {
let from: number | null = null
let from = -1
editor.state.doc.descendants((node, pos) => {
if (from !== null || !node.isText || !node.text) {
if (from !== -1 || !node.isText || !node.text) {
return
}
const index = node.text.indexOf(search)
@ -42,7 +42,7 @@ function markdownAfterTextReplace(content: string, search: string, replacement:
from = pos + index
}
})
if (from === null) {
if (from === -1) {
throw new Error(`Missing text: ${search}`)
}
editor.view.dispatch(editor.state.tr.insertText(replacement, from, from + search.length))

View File

@ -329,7 +329,7 @@ export function useEditorPanelContentState({
[file.id]: {
kind: 'text',
originalContent: '',
modifiedContent: `Error loading diff: ${err}`,
modifiedContent: `Error loading diff: ${String(err)}`,
originalIsBinary: false,
modifiedIsBinary: false
}

View File

@ -1,7 +1,9 @@
import { useCallback, useEffect, useRef } from 'react'
import { FEATURE_WALL_MAX_DWELL_MS } from '../../../../shared/feature-wall-telemetry'
import type { FeatureWallExitAction } from '../../../../shared/feature-wall-tour-depth'
import type { FeatureWallTourDepthSummary } from '../../../../shared/feature-wall-tour-depth'
import type {
FeatureWallExitAction,
FeatureWallTourDepthSummary
} from '../../../../shared/feature-wall-tour-depth'
import type {
EventProps,
FeatureWallOpenSourceTelemetry

View File

@ -10,7 +10,10 @@ import { buildAgentStartupPlan } from '@/lib/tui-agent-startup'
import { tuiAgentToAgentKind } from '@/lib/telemetry'
import { useAppStore } from '@/store'
import { FLOATING_TERMINAL_WORKTREE_ID } from '../../../../shared/constants'
import { isTuiAgentEnabled } from '../../../../shared/tui-agent-selection'
import {
DEFAULT_DISABLED_TUI_AGENTS,
isTuiAgentEnabled
} from '../../../../shared/tui-agent-selection'
import {
resolveTuiAgentLaunchArgs,
resolveTuiAgentLaunchEnv
@ -49,7 +52,9 @@ export function FloatingTerminalWindowControls({
const maximizeShortcutLabel = useOptionalShortcutLabel('floatingWorkspace.maximize')
const minimizeShortcutLabel = useOptionalShortcutLabel('floatingWorkspace.minimize')
const disabledTuiAgents = useAppStore((s) => s.settings?.disabledTuiAgents ?? [])
const disabledTuiAgents = useAppStore(
(s) => s.settings?.disabledTuiAgents ?? DEFAULT_DISABLED_TUI_AGENTS
)
const defaultAgent =
defaultTuiAgent &&
defaultTuiAgent !== 'blank' &&

View File

@ -7,9 +7,8 @@ import { Input } from '@/components/ui/input'
import CommentMarkdown from '@/components/sidebar/CommentMarkdown'
import { useAppStore } from '@/store'
import { callRuntimeRpc, getActiveRuntimeTarget } from '@/runtime/runtime-rpc-client'
import type { GitHubWorkItemDetails } from '../../../../../shared/types'
import type { GitHubWorkItemDetails, GlobalSettings } from '../../../../../shared/types'
import type { GitHubItemDialogProjectOrigin } from '@/components/GitHubItemDialog'
import type { GlobalSettings } from '../../../../../shared/types'
import { LabelsEditor } from './LabelsEditor'
import { AssigneesEditor } from './AssigneesEditor'
import { CommentsList, NewCommentForm } from './Comments'

View File

@ -1,7 +1,13 @@
import { translate } from '@/i18n/i18n'
import type { MobileNetworkInterface } from '../settings/mobile-network-interface-selection'
import { HeroFlow, HeroIntro, HeroPaired, type PairedDevice, type Platform } from './MobileHero'
import type { StepIndex } from './MobileHero'
import {
HeroFlow,
HeroIntro,
HeroPaired,
type PairedDevice,
type Platform,
type StepIndex
} from './MobileHero'
import { getInstallCopy, type IosChannel } from './mobile-platform-copy'
import type { MobilePageStage } from './mobile-page-stage'
import { MobilePageToolbar } from './MobilePageToolbar'

View File

@ -1,8 +1,7 @@
// @vitest-environment happy-dom
import { afterEach, describe, expect, it, vi } from 'vitest'
import { act } from 'react'
import { act, createElement, useRef, useState } from 'react'
import { createRoot, type Root } from 'react-dom/client'
import { createElement, useRef, useState } from 'react'
import {
clearNativeChatAttachmentCacheForTests,
readNativeChatAttachmentCache,

View File

@ -1,8 +1,7 @@
// @vitest-environment happy-dom
import { afterEach, describe, expect, it, vi } from 'vitest'
import { act } from 'react'
import { act, createElement } from 'react'
import { createRoot, type Root } from 'react-dom/client'
import { createElement } from 'react'
import type { NativeChatAttachmentOwner } from './native-chat-attachment-upload'
const mocks = vi.hoisted(() => ({

View File

@ -1,8 +1,7 @@
// @vitest-environment happy-dom
import { afterEach, describe, expect, it, vi } from 'vitest'
import { act } from 'react'
import { act, createElement } from 'react'
import { createRoot, type Root } from 'react-dom/client'
import { createElement } from 'react'
const mocks = vi.hoisted(() => ({
resolveNativeChatAttachmentOwner: vi.fn(),

View File

@ -1,7 +1,6 @@
// @vitest-environment happy-dom
import { createElement, useEffect } from 'react'
import { act } from 'react'
import { createElement, useEffect, act } from 'react'
import { createRoot, type Root } from 'react-dom/client'
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
import { getDefaultOnboardingState } from '../../../../shared/constants'

View File

@ -1,8 +1,7 @@
// @vitest-environment happy-dom
import path from 'node:path'
import React, { type ReactNode, useState } from 'react'
import { act } from 'react'
import React, { type ReactNode, useState, act } from 'react'
import { createRoot, type Root } from 'react-dom/client'
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
import { getDefaultSettings } from '../../../../shared/constants'

View File

@ -25,9 +25,9 @@ import {
Pencil,
SlidersHorizontal,
Trash,
X
X,
ExternalLink
} from 'lucide-react'
import { ExternalLink } from 'lucide-react'
import { Button } from '@/components/ui/button'
import { Checkbox } from '@/components/ui/checkbox'
import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip'

View File

@ -2,11 +2,10 @@
import React, { useEffect, useMemo, useRef, useState } from 'react'
import { Plug, Files, GitBranch, ListChecks, PanelRight, Workflow } from 'lucide-react'
import { useAppStore } from '@/store'
import type { ActiveRightSidebarTab } from '@/store/slices/editor'
import type { ActiveRightSidebarTab, ActivityBarPosition } from '@/store/slices/editor'
import { useRepoById } from '@/store/selectors'
import { cn } from '@/lib/utils'
import { useSidebarResize } from '@/hooks/useSidebarResize'
import type { ActivityBarPosition } from '@/store/slices/editor'
import { isFolderRepo } from '../../../../shared/repo-kind'
import { parseWorkspaceKey } from '../../../../shared/workspace-scope'
import { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider } from '@/components/ui/tooltip'

View File

@ -68,6 +68,7 @@ export function resolveBlockedCreateReviewNoticeMessage(
case 'unsupported_provider':
// Why: base_not_on_remote is a create-time hard failure surfaced as an error
// result, not an inline-actionable eligibility state, so it is non-clickable.
// falls through
case 'base_not_on_remote':
case null:
return null

View File

@ -14,6 +14,7 @@ import { useAppStore } from '@/store'
import { OpenInApplicationIcon } from '@/lib/open-in-app-catalog'
import { translate } from '@/i18n/i18n'
import { getLocalFileManagerLabel } from '@/lib/local-file-manager-label'
import { NO_OPEN_IN_APPLICATIONS } from '@/lib/open-in-application-selection'
import {
getOpenInEntryAvailability,
getWorktreeOpenInEntries,
@ -42,7 +43,9 @@ export function SourceControlEntryContextMenu({
onOpenChange,
children
}: SourceControlEntryContextMenuProps): React.JSX.Element {
const openInApplications = useAppStore((s) => s.settings?.openInApplications ?? [])
const openInApplications = useAppStore(
(s) => s.settings?.openInApplications ?? NO_OPEN_IN_APPLICATIONS
)
const settings = useAppStore((s) => s.settings)
const fileManagerLabel = getLocalFileManagerLabel()
const openInEntries = React.useMemo(

View File

@ -3,8 +3,7 @@ import { toast } from 'sonner'
import { useConfirmationDialog } from '@/components/confirmation-dialog'
import type { GitHubPRAutoMergeAction } from '@/components/github-pr-merge-state'
import type { HostedReviewInfo } from '../../../../shared/hosted-review'
import type { PRInfo, Repo } from '../../../../shared/types'
import type { GitHubPRMergeMethod } from '../../../../shared/types'
import type { PRInfo, Repo, GitHubPRMergeMethod } from '../../../../shared/types'
import {
mergeGitHubHostedReview,
setGitHubHostedReviewAutoMerge,

View File

@ -1,7 +1,6 @@
// @vitest-environment happy-dom
import React from 'react'
import { act } from 'react'
import React, { act } from 'react'
import { createRoot, type Root } from 'react-dom/client'
import { describe, expect, it, vi } from 'vitest'
import type { HostedReviewCreationEligibility } from '../../../../shared/hosted-review'

View File

@ -13,10 +13,9 @@ import {
getRuntimeRepoBaseRefDefault,
searchRuntimeRepoBaseRefDetails
} from '@/runtime/runtime-repo-client'
import type { Repo } from '../../../../shared/types'
import type { Repo, BaseRefSearchResult } from '../../../../shared/types'
import type { HostedReviewCreationEligibility } from '../../../../shared/hosted-review'
import { normalizeHostedReviewBaseRef } from '../../../../shared/hosted-review-refs'
import type { BaseRefSearchResult } from '../../../../shared/types'
import {
DEFAULT_SOURCE_CONTROL_AI_PR_CREATION_DEFAULTS,
resolveSourceControlAiForOperation

View File

@ -35,7 +35,7 @@ type EmulatorAvailability = {
type MobileEmulatorSettingsPaneProps = {
settings: GlobalSettings
updateSettings: (updates: Partial<GlobalSettings>) => void
updateSettings: (updates: Partial<GlobalSettings>) => Promise<void>
}
const AUTOMATIC_DEVICE_VALUE = '__orca_automatic_emulator_device__'

View File

@ -1,7 +1,6 @@
// @vitest-environment happy-dom
import React from 'react'
import { act } from 'react'
import React, { act } from 'react'
import { createRoot, type Root } from 'react-dom/client'
import { afterEach, describe, expect, it, vi } from 'vitest'
import type { Repo } from '../../../../shared/types'

View File

@ -21,9 +21,8 @@ import {
getTerminalWindowSearchEntries
} from './terminal-search'
import { Button } from '../ui/button'
import { SettingsRow, SettingsSubsectionHeader } from './SettingsFormControls'
import { SettingsRow, SettingsSubsectionHeader, FontAutocomplete } from './SettingsFormControls'
import { SearchableSetting } from './SearchableSetting'
import { FontAutocomplete } from './SettingsFormControls'
import { TerminalFontSizeSetting } from './TerminalFontSizeSetting'
import { TerminalAdvancedTypographyControls } from './TerminalAdvancedTypographyControls'
import { TerminalThemeCatalogSection } from './TerminalThemeSections'

Some files were not shown because too many files have changed in this diff Show More