chore: update oxlint and oxfmt (#17150)

This commit is contained in:
Neil
2026-08-29 14:13:35 -07:00
committed by GitHub
parent b17f60d744
commit 2dfaa676d8
68 changed files with 1110 additions and 1256 deletions
+12
View File
@@ -40,6 +40,18 @@
"react/no-string-refs": "error",
"react/no-unescaped-entities": "error",
"react/require-render-return": "error",
"react/error-boundaries": "off",
"react/globals": "off",
"react/immutability": "off",
"react/incompatible-library": "off",
"react/preserve-manual-memoization": "off",
"react/purity": "off",
"react/refs": "off",
"react/set-state-in-effect": "off",
"react/set-state-in-render": "off",
"react/static-components": "off",
"react/use-memo": "off",
"react/void-use-memo": "off",
"react/jsx-curly-brace-presence": [
"error",
{ "props": "never", "children": "never", "propElementValues": "always" }
+2 -2
View File
@@ -74,8 +74,8 @@
"esbuild": "0.25.4",
"expo-module-scripts": "^55.0.2",
"happy-dom": "^20.9.0",
"oxfmt": "^0.52.0",
"oxlint": "^1.71.0",
"oxfmt": "^0.65.0",
"oxlint": "^1.80.0",
"react-test-renderer": "19.2.6",
"tsx": "^4.22.4",
"typescript": "6.0.3",
+383 -414
View File
File diff suppressed because it is too large Load Diff
+4 -7
View File
@@ -60,13 +60,10 @@ export function directoryCacheFromFileList(files: LegacyMobileFileEntry[]): Dire
Array.from(childrenByDir, ([path, children]) => [
path,
{
entries: Array.from(
children,
([name, isDirectory]): MobileDirEntry => ({
name,
isDirectory
})
)
entries: Array.from(children, ([name, isDirectory]): MobileDirEntry => ({
name,
isDirectory
}))
}
])
)
@@ -72,12 +72,10 @@ function makeHarness(options?: {
} as unknown as RpcClient
const apply =
options?.apply ??
vi.fn(
(value: TestResult): SessionTabsApplyOutcome<string> => ({
accepted: true,
effectiveTabs: value.tabs
})
)
vi.fn((value: TestResult): SessionTabsApplyOutcome<string> => ({
accepted: true,
effectiveTabs: value.tabs
}))
const consumeAccepted = vi.fn()
let recoveryNeeded = false
const controller = new MobileSessionTabsStreamHealth<TestResult, string>({
@@ -306,9 +304,8 @@ describe('MobileSessionTabsStreamHealth', () => {
})
it('does not consume a rejected stream snapshot or update', () => {
const apply = vi.fn(
(value: TestResult): SessionTabsApplyOutcome<string> =>
value.type ? { accepted: false } : { accepted: true, effectiveTabs: value.tabs }
const apply = vi.fn((value: TestResult): SessionTabsApplyOutcome<string> =>
value.type ? { accepted: false } : { accepted: true, effectiveTabs: value.tabs }
)
const harness = makeHarness({ apply })
const subscription = harness.controller.beginSubscription()
@@ -39,12 +39,10 @@ type TestResult = {
}
const fetchTerminals = vi.fn(async () => {})
const applySessionTabs = vi.fn(
(value: TestResult): SessionTabsApplyOutcome<string> => ({
accepted: true,
effectiveTabs: value.tabs
})
)
const applySessionTabs = vi.fn((value: TestResult): SessionTabsApplyOutcome<string> => ({
accepted: true,
effectiveTabs: value.tabs
}))
const consumeAcceptedSessionTabs = vi.fn()
let recoveryNeeded = false
let clearRecoveryAt = Number.POSITIVE_INFINITY
@@ -4,14 +4,12 @@ import { openAuthenticatedDirectEndpoint } from './mobile-direct-endpoint-probe'
import type { ConnectionState, HostProfile, RpcResponse } from './types'
class FakeClient implements RpcClient {
readonly sendRequest = vi.fn(
async (): Promise<RpcResponse> => ({
id: 'rpc-1',
ok: true,
result: {},
_meta: { runtimeId: 'runtime-1' }
})
)
readonly sendRequest = vi.fn(async (): Promise<RpcResponse> => ({
id: 'rpc-1',
ok: true,
result: {},
_meta: { runtimeId: 'runtime-1' }
}))
readonly subscribe = vi.fn(() => () => {})
readonly updateTerminalSubscriptionViewport = vi.fn()
readonly notifyForeground = vi.fn()
@@ -41,14 +41,12 @@ vi.mock('./e2ee', () => ({
}))
class FakeSession implements RpcClient {
readonly sendRequest = vi.fn(
async (): Promise<RpcResponse> => ({
id: 'rpc-1',
ok: true,
result: {},
_meta: { runtimeId: 'runtime-1' }
})
)
readonly sendRequest = vi.fn(async (): Promise<RpcResponse> => ({
id: 'rpc-1',
ok: true,
result: {},
_meta: { runtimeId: 'runtime-1' }
}))
readonly subscribe = vi.fn(() => () => {})
readonly updateTerminalSubscriptionViewport = vi.fn()
readonly notifyForeground = vi.fn()
+2 -2
View File
@@ -239,8 +239,8 @@
"marked": "^17.0.1",
"mermaid": "^11.16.1",
"monaco-editor": "^0.55.1",
"oxfmt": "^0.52.0",
"oxlint": "^1.77.0",
"oxfmt": "^0.65.0",
"oxlint": "^1.80.0",
"oxlint-plugin-react-doctor": "0.9.1",
"oxlint-tsgolint": "7.0.2001",
"pdfjs-dist": "^6.2.108",
+162 -162
View File
@@ -396,11 +396,11 @@ importers:
specifier: ^0.55.1
version: 0.55.1
oxfmt:
specifier: ^0.52.0
version: 0.52.0
specifier: ^0.65.0
version: 0.65.0
oxlint:
specifier: ^1.77.0
version: 1.77.0(oxlint-tsgolint@7.0.2001)
specifier: ^1.80.0
version: 1.80.0(oxlint-tsgolint@7.0.2001)
oxlint-plugin-react-doctor:
specifier: 0.9.1
version: 0.9.1
@@ -1444,124 +1444,124 @@ packages:
'@oxc-project/types@0.141.0':
resolution: {integrity: sha512-S4as7z0j0xQkXcJlyY5ehntwK8/wRkQb9Cyqw+J/N2rkWGQGK0SxD6X6DhQTc7qsxVTBxXbxZtBJh3mr3PtIzQ==}
'@oxfmt/binding-android-arm-eabi@0.52.0':
resolution: {integrity: sha512-17EMSJnQ9g+upVHrAUYDMfH5lvRKQ9Nvg8WtEoH72oDr1VpWz+7/o3tD97U1EToen2YAQ/68JmtDYkQUi20dfQ==}
'@oxfmt/binding-android-arm-eabi@0.65.0':
resolution: {integrity: sha512-M10Gs1SSpTNI6ahGx3M/OlIdUF4hkaP6OgUb+MS79t/Pgflk3r1nW5gPFqsZGUAXg0H1AfANT9AvLdBSTIhZKg==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [arm]
os: [android]
'@oxfmt/binding-android-arm64@0.52.0':
resolution: {integrity: sha512-A2G1IdwGEW2lLJkIxcvuirRH1CzSl/e0NX11zTlW1gvxJThfwbI/BEoaKrTNpm7M2FchvIf6guvIQU7d5iz+OQ==}
'@oxfmt/binding-android-arm64@0.65.0':
resolution: {integrity: sha512-6DXH5sftNlaHpWJG50hFMF+Qxtq5D2TmahvcDPxWNcGIf8qrC9Y0YgHYcYZ2hlWzaccKXh/f3GcssH8vtkl4JA==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [arm64]
os: [android]
'@oxfmt/binding-darwin-arm64@0.52.0':
resolution: {integrity: sha512-f9+bLvOYxy7NttCLFTvQ7afmqDOWY4wIP9xdvfj5trQ1qj6f2UFAGwZESlfsMjvJNTyRpXfIlOanCI9FOvoeQA==}
'@oxfmt/binding-darwin-arm64@0.65.0':
resolution: {integrity: sha512-K9m7lr53pcOLETNsC88sWes/GWHUGjZyHx95UhYcSXy0r30haLdeXlSufSenEAtoLaW753WN8/l4M7GYcRt6cg==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [arm64]
os: [darwin]
'@oxfmt/binding-darwin-x64@0.52.0':
resolution: {integrity: sha512-YSTB9sJ5nnQd/Q0ddHkgof0ZCHPAnWZT1IW2SJ8omz7CP7KluJhO1fNHrpqdxCtpztJwSs4hY1uAee35wKxxaw==}
'@oxfmt/binding-darwin-x64@0.65.0':
resolution: {integrity: sha512-sTNwIx1gre3MyiHOPLu7IGW4UyMScYL4DTmJT01p4vzB0En+OJUQz6KuH8t0PpsClRSaMuY3b0QmtoPItfO8Lg==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [x64]
os: [darwin]
'@oxfmt/binding-freebsd-x64@0.52.0':
resolution: {integrity: sha512-NIrRNTTPCs4UbmVs0bxLSCDlLCtIRMJIXklNKaXa5Oj2/K1UIMBvgE8+uPVo01Io3N9HF0+GAX+aAHjUgZS7vA==}
'@oxfmt/binding-freebsd-x64@0.65.0':
resolution: {integrity: sha512-lYZMVIiIpnjGu5hJb2jxA8NYQ/e0OTGuaiAf4dqlGPNnPmUTu23FZRMltmjro/KkQm1uE4NT4n5yJ2zWmKcpfA==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [x64]
os: [freebsd]
'@oxfmt/binding-linux-arm-gnueabihf@0.52.0':
resolution: {integrity: sha512-JXUCde8mn3GpgQouz2PXUokgy/uT1QrRJBL2s983VWcSQp62wTFYiNXgTKdeo1Jgbr0IgUnKKvzIk/YBlj/nVQ==}
'@oxfmt/binding-linux-arm-gnueabihf@0.65.0':
resolution: {integrity: sha512-gIdXFAt/bURnjxuoedDEWdZ0PEWEmdDcm8qdpoFYYvW3QMk/5D4vUaH4mlMeRpeTdST4izUgHVO6RawQ4QulJw==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [arm]
os: [linux]
'@oxfmt/binding-linux-arm-musleabihf@0.52.0':
resolution: {integrity: sha512-psbUXaRZ+V8DaXz10Qf7LSHtdtdKAmC8fxXgeU608jjzrmWK4quamZMOpl6sf+dikoFHA85uE93Q0BqxrCdQrQ==}
'@oxfmt/binding-linux-arm-musleabihf@0.65.0':
resolution: {integrity: sha512-jJVyADto7gA2AaX5qAjAexrxx9PJQaKWOe8PICE7yKMbjBRyOHcmj9TtVJ+MZYDUQ3hodU0AcoTj0jFQ1W4C6Q==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [arm]
os: [linux]
'@oxfmt/binding-linux-arm64-gnu@0.52.0':
resolution: {integrity: sha512-Jw7MgWUU9lcLCcy82updISP3EthTlfvAwR6gWNxPzqly7+fLvOi2gHQE9xXQjpqaVLm/8P+gOzlv9ODuoVlaaw==}
'@oxfmt/binding-linux-arm64-gnu@0.65.0':
resolution: {integrity: sha512-p3RFkB+u7u+8up99b/NEcI1hdpLDiGgJYNwDorB60n7eH+eKposAKuMBxx+NqB3b+sJP4CZmYDh9G7X62tUsKg==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [arm64]
os: [linux]
libc: [glibc]
'@oxfmt/binding-linux-arm64-musl@0.52.0':
resolution: {integrity: sha512-wZg6bLjDvh2KibyI3QFUYo8GTXneIFsd0JvehtvJiUmQ8WRPERgxd/VM4ctWb86U5FT1FkqgS8/wZKVB+AZScg==}
'@oxfmt/binding-linux-arm64-musl@0.65.0':
resolution: {integrity: sha512-5Prb0uFzJHr+OUD/qS/TmU526wD+PaHDsm3KoRiUXbMIDpTSErjeQYkK3OQeshAvD/PuLa9WGEi9WPajjdOZJg==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [arm64]
os: [linux]
libc: [musl]
'@oxfmt/binding-linux-ppc64-gnu@0.52.0':
resolution: {integrity: sha512-IngE8uxhNvxcMrLjZNDo9xNLY7rEK33AKnaMd2B46he1e/mz2CfcW6If/U1wUjdRZddm1QzQaciqZkuMkdh1FA==}
'@oxfmt/binding-linux-ppc64-gnu@0.65.0':
resolution: {integrity: sha512-S8svxTp81obnF3admN9yd+u2rOYXtyzThLGBTg1PY6TPtGcC09BaaXLQD+TBSMa7yvqhCDZ8DFri+S/yG60qCg==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [ppc64]
os: [linux]
libc: [glibc]
'@oxfmt/binding-linux-riscv64-gnu@0.52.0':
resolution: {integrity: sha512-H3+DdFMv/efN3Efmhsv18jDrpiWWqKG7wsfAlQBqAt6z/E2Bx+TwEj2Nowe51CPOWB8/mFBC2dAMSgVFLvvowA==}
'@oxfmt/binding-linux-riscv64-gnu@0.65.0':
resolution: {integrity: sha512-WtXBr75G/h2qOHy8SiGtC1R6aS3jt4mE52v1D8AtwMXIgoOmSNP9lKvbSaTRoL0e5wsMPoi6T72QWDYPu+S+nA==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [riscv64]
os: [linux]
libc: [glibc]
'@oxfmt/binding-linux-riscv64-musl@0.52.0':
resolution: {integrity: sha512-zji+1kb7lJKohSDjzC1IsS+K/cKRs1hdVf0ZH0VbdbiakmtLvN9twBoXo/k8VdjFax7kfo+DyPxS7vv52br1aw==}
'@oxfmt/binding-linux-riscv64-musl@0.65.0':
resolution: {integrity: sha512-YwSLVvpaz4o/nv/miiPEBJz+eJ+VmbgNIrao6RccK9ce+L5EA8wP+ZD0uFeq6wKOza6zoWv/dR0sj6lip6R3EA==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [riscv64]
os: [linux]
libc: [musl]
'@oxfmt/binding-linux-s390x-gnu@0.52.0':
resolution: {integrity: sha512-hcLBYedpCy7ToUvvBidWk7+11Yhg1oAZ4+6hKPic/mQI6NaqXJSXMps5nFlwUuX2ewhtLZZDPg63TI042qGKBg==}
'@oxfmt/binding-linux-s390x-gnu@0.65.0':
resolution: {integrity: sha512-XQTPqgvyrgkKcFq+Tp2eK6JS7sqqJ+nRmy2Fav4j3I+i4dJoPJm7YwEdoeSDX9xkqj9jZ/lWfF3bXUWztIrn6A==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [s390x]
os: [linux]
libc: [glibc]
'@oxfmt/binding-linux-x64-gnu@0.52.0':
resolution: {integrity: sha512-IDO2loXK2OtTOhSPchU9MW25mWL2QCDGdJbjN8MXKZVS80qXe5gMTwQWu/gMJ3juoBHbkuUZNB2N1LHzNT7DoA==}
'@oxfmt/binding-linux-x64-gnu@0.65.0':
resolution: {integrity: sha512-cjZlx6S/VkeCNWCbwZriTnLnZeTcV3DEyeRGSw/2wwLP9viq+C0bJ4bC1k/ZLkFxDcB1lUgSasPkYGP1bdraOg==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [x64]
os: [linux]
libc: [glibc]
'@oxfmt/binding-linux-x64-musl@0.52.0':
resolution: {integrity: sha512-mAV2Hjn0SatJ+KoAzKUC3eJhdJ8wv+3m1KyuS0dTsbF0c5weq+QrCt/DRZZM+uj/XiKzCDEUKYsBF30e2qkcyw==}
'@oxfmt/binding-linux-x64-musl@0.65.0':
resolution: {integrity: sha512-2azCjxdLtK4zCcIOU1dlXlU0xxfbPi6EjwWx7Ac7teWPidIIDOcIhudup83xNCKYhtqeVd/gaVDOxbUq4syXWA==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [x64]
os: [linux]
libc: [musl]
'@oxfmt/binding-openharmony-arm64@0.52.0':
resolution: {integrity: sha512-vd4npaUIwChxp7XzkqmepBWTT9YMcSe/NBApVGPC30/lLyOVaV3dvma1SKo03t8O73BPRAG7EyJzGlN5cJM5hQ==}
'@oxfmt/binding-openharmony-arm64@0.65.0':
resolution: {integrity: sha512-KXQ7xi1e/voP0IQaw6fG6XY4Z5+Llf1XmRSZS1t7pVFCecFJ0iXaboKmVwjFtp5MLlT5iWQrJ2U1C3GJdZ2u+Q==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [arm64]
os: [openharmony]
'@oxfmt/binding-win32-arm64-msvc@0.52.0':
resolution: {integrity: sha512-k2sz6gWQdMfh5HPpIS+Bw/0UEV/kaK2xuqJRrWL233sEHx9WLlsmvlPFM4HUNThkYbSN0U0vPW7LVKZWDS8hPQ==}
'@oxfmt/binding-win32-arm64-msvc@0.65.0':
resolution: {integrity: sha512-2FbbjG5jEqLSLKVJwBap84uJfpn5Y5A53KEO0aUNr+zeiRB9nyPUIFMcSbZVMFLitfBytFWRNngozXYjb6Rsbw==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [arm64]
os: [win32]
'@oxfmt/binding-win32-ia32-msvc@0.52.0':
resolution: {integrity: sha512-rhke69GTcArodLHpjMTfNnvjTEBryDeZcUCKK/VjXDMtfTULl6QRh0ymX5/hbCUv2WjYm9h/QbW++q2vE15gWQ==}
'@oxfmt/binding-win32-ia32-msvc@0.65.0':
resolution: {integrity: sha512-LJ+ZacAPSjegDOnSLyA1TMWAhdDrsK4el3REdr1oL2UtVBCMhO2II/Sb3cEW6mF2MfLhl8hDNCSvc7KSbgk3LQ==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [ia32]
os: [win32]
'@oxfmt/binding-win32-x64-msvc@0.52.0':
resolution: {integrity: sha512-q5xL7oeXkZdEtNZWBdvehJcmt+GRu9l2bK40yJs1jJXlqq+r0Hygb1rTjq+FM2o/2xyt4cufH6KRplHp3Jjsvw==}
'@oxfmt/binding-win32-x64-msvc@0.65.0':
resolution: {integrity: sha512-higu9cWEO6XXFzATD1jf0mCK34rNfN2H9JrJie7QB1IhleVpTh0QlLH9Ip2C1H/Nd5n0v5pvRtC+5R0uE4HpVg==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [x64]
os: [win32]
@@ -1596,124 +1596,124 @@ packages:
cpu: [x64]
os: [win32]
'@oxlint/binding-android-arm-eabi@1.77.0':
resolution: {integrity: sha512-E06sKWS6PiI6HRxS1wyQg22HvApt01hI7fV+T3wUk3OSbaaP4a3hYGY/MIQDmASqCiRjBdpRQYkgMkqH82cWmQ==}
'@oxlint/binding-android-arm-eabi@1.80.0':
resolution: {integrity: sha512-RM3Plj+biQpxa5d1GOOX6ciDlcUROmm4OZ/pLTpitkQt2mJv4jhtY4cbgaetOm5UKWZe05/TGQ6o1Vl8EOHkrA==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [arm]
os: [android]
'@oxlint/binding-android-arm64@1.77.0':
resolution: {integrity: sha512-NvsKz0KZxTp9cYWPLf+FXaSZwB3oO3peAjtukpOMBgse2vhQSoIIVqeO1yR0lEo/UcdZIDL18uq+kL0LzQ0ytA==}
'@oxlint/binding-android-arm64@1.80.0':
resolution: {integrity: sha512-YlO5JEf0Yr2bUUlu8O8daVcUxtcGGbcSmyV7E7nSbJbfAdxTE0PFPwgnIlw7wXJaTYjb+qs5hI5q3jxUkI7cAw==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [arm64]
os: [android]
'@oxlint/binding-darwin-arm64@1.77.0':
resolution: {integrity: sha512-bgjTn6nW4bQCFBvSvuHCpDD+sONvmpo4lGI4PxzMt1quBA+xYxhczk6RiCn3GZ9gY8uhaBbwhj9MdKGfu6T9DA==}
'@oxlint/binding-darwin-arm64@1.80.0':
resolution: {integrity: sha512-BULDOyO3AhsmdWfQeIUCykDt3dd7XZBGLhp1eIh56skRv01O+cNjNPwXMIbeW1x4+pxcln5if72wcRgViVo7PA==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [arm64]
os: [darwin]
'@oxlint/binding-darwin-x64@1.77.0':
resolution: {integrity: sha512-aotaIttH1R6j1Rwhx0M0htgeZyGtVQqYNTVEYMN/UcgHPquGA6kmk9OyuDc3a2GKUQBC+3C3GVQCcrRPMYqAFA==}
'@oxlint/binding-darwin-x64@1.80.0':
resolution: {integrity: sha512-YJ4JzLw7N5TDSQFlA0hAQGHvnDZgyypm1yunObVWcWiF9KM7eGCJKYKLgTC2Fi/57OdnBhbj4OkzPGdFQJ6HyA==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [x64]
os: [darwin]
'@oxlint/binding-freebsd-x64@1.77.0':
resolution: {integrity: sha512-nNx/wta7ksRAdYvq+l4AWjXkLxEXHALhENxjj2cYbQAIR4ybaA5L+hCbE63HOmft5czQ6ks+hb8vmEAnn7YGPg==}
'@oxlint/binding-freebsd-x64@1.80.0':
resolution: {integrity: sha512-AYUIk5QnL0s8oWAYsREZwkRYy1SupJTXALo93J1TgzHywxQtdM99FecRMQ87MXEdPQ0j1TmEpeeq3fGNkpvMqg==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [x64]
os: [freebsd]
'@oxlint/binding-linux-arm-gnueabihf@1.77.0':
resolution: {integrity: sha512-tMLLjM7xXtzXisVCzkOTXNCy9bZVId2wteNwjohlFDR/jY6WagpEDA1c1wu4xRc20Hojaxj+V6DSR7gbKxijWA==}
'@oxlint/binding-linux-arm-gnueabihf@1.80.0':
resolution: {integrity: sha512-9hBZVANupQ89W9dXyE0n8doCyaW5pDyGn3y6XlIMPZ+rIKuyqkr3SNUXmVJIhuvUq0NBU3RBiSXXE69l4XI6KA==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [arm]
os: [linux]
'@oxlint/binding-linux-arm-musleabihf@1.77.0':
resolution: {integrity: sha512-MiAFDFaqR0tmHTAyo0YDcZ5hyLREdYw/RQhc2R3cbT+8O3tB+zqPM2th9TTQ+Uo3jn/embS+DO+HyX9ztCPkOQ==}
'@oxlint/binding-linux-arm-musleabihf@1.80.0':
resolution: {integrity: sha512-SvS2uKqzY+pbfuvAHzH4338R6Zwo805GAwrIMVvK1KxoOWCIjZUdfzTCvilD7z6JK91v011+zYMryabhDo2AsQ==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [arm]
os: [linux]
'@oxlint/binding-linux-arm64-gnu@1.77.0':
resolution: {integrity: sha512-/xqQ3B16i1T4cyt/9Mn+4CpzhUXoBXp7kVpIwzOXNFLj5JmK1bIjsbSnX296Gg8A/o7oDtKWikFgBx0SLwztkw==}
'@oxlint/binding-linux-arm64-gnu@1.80.0':
resolution: {integrity: sha512-tCLadyqRVL3pQTRPNg7cjXKvcvS4fbyXeQHhKk5BTJ1oftQln5/yIIWbu/Xom/DX41zv2P9QGt6+D/TtQVtY3A==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [arm64]
os: [linux]
libc: [glibc]
'@oxlint/binding-linux-arm64-musl@1.77.0':
resolution: {integrity: sha512-LSbwuRKiNCenPDcbARqAZ5RfBy7gmj7vOvfJRLeCDU3gFtSxWbhv/+VTlaUqzUhNj1gFLHB8h7ALnxa/Az6z6g==}
'@oxlint/binding-linux-arm64-musl@1.80.0':
resolution: {integrity: sha512-XfpCNRlOPcLlJl4Bn/FUhjqlR6BVavEykERBf/MV7YA9VZDa5g5znVqYhyviMafcxS9Pe/i/kPvHNO0U6svEHQ==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [arm64]
os: [linux]
libc: [musl]
'@oxlint/binding-linux-ppc64-gnu@1.77.0':
resolution: {integrity: sha512-QWdcH31mXEUe5Nq1s0CfCpceaKjIo9uZtwDjAuL681g1axf+5x8xrg/eXWaw//4NCxYZ4V4e5Hu5tvdR+pTBlg==}
'@oxlint/binding-linux-ppc64-gnu@1.80.0':
resolution: {integrity: sha512-3I4yMwcFG9NeO8ioY6JBBuKsIm5GL/x7MATt1S4tVWaxPu5HcJ+XnLUbcVBTxG8q2Wu56HSj+NmXQiVYb1lp6A==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [ppc64]
os: [linux]
libc: [glibc]
'@oxlint/binding-linux-riscv64-gnu@1.77.0':
resolution: {integrity: sha512-GnOfYgJxbcElOiPZaDFDl406ONddwvOWk2jvAAAEjwAl4GofNoHF+/HHUIBYa6bFCArlcGPi0XjC4cU1pkgF/Q==}
'@oxlint/binding-linux-riscv64-gnu@1.80.0':
resolution: {integrity: sha512-E1wAKymkpe1/E8helzBKdm81OBOF+ezxRyXRMEuik3ZpWDER5CPOKZwF66RsdwW98uwZv8UTFremUQtC1CzdJA==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [riscv64]
os: [linux]
libc: [glibc]
'@oxlint/binding-linux-riscv64-musl@1.77.0':
resolution: {integrity: sha512-AyEMTUCf0xY+hHF+IxqXFQIX0yQOIR8ykpY0lJNOw9xYqOzUX8dyZfRvlG0RfXwuQn2eonf/8NrMmDSZJjdqsA==}
'@oxlint/binding-linux-riscv64-musl@1.80.0':
resolution: {integrity: sha512-+gLRGD4sIo3+VA++iham5UxD9tKSoJ/VOrROCEXIcknrYtQg6iIQgvjN0cpiRF7N6UYC7pJbvHJlDnMge5LRpQ==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [riscv64]
os: [linux]
libc: [musl]
'@oxlint/binding-linux-s390x-gnu@1.77.0':
resolution: {integrity: sha512-sPLzEcNvxd/oyVQ5oZo92CiHkFkpBeRop13E/P3TPY+hZfXHKCOWKI70TE2RYwMKFJDc20EMjH16L7NZICtKTw==}
'@oxlint/binding-linux-s390x-gnu@1.80.0':
resolution: {integrity: sha512-aR0PrzHj9leW3NmzBAAP4EzdoBNoJcs9sjnIQPIwyRnBGYrRbXUIpEB5Q39AqK3PLY5JK5uEhDQDiUa1QSAstw==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [s390x]
os: [linux]
libc: [glibc]
'@oxlint/binding-linux-x64-gnu@1.77.0':
resolution: {integrity: sha512-1Oh2ssH2L7lwyvkdSqaMUfsGfwU2Wfvew+obBUYjRVqhpBcUpwnsPSEr1IzVi9XqkuY10geiLsNKecqaZC34Dw==}
'@oxlint/binding-linux-x64-gnu@1.80.0':
resolution: {integrity: sha512-vSVh5cSo3Xxs6ghBCcFJlpbkbENzDog1qXtoXLa/HC3aCrR4XO76GZbXmQoCPHnu99nQpdCeC3H9tdNICfDh7A==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [x64]
os: [linux]
libc: [glibc]
'@oxlint/binding-linux-x64-musl@1.77.0':
resolution: {integrity: sha512-0j/2wRgNGO+Qj/M1uu/p57h/hFTTWWcfie0ufkbabeus2s5+/QqkCflnMOwLLN5m2GsNeWp4xdl4cPa4n7QCOQ==}
'@oxlint/binding-linux-x64-musl@1.80.0':
resolution: {integrity: sha512-FfzBXpNQ8u7/ZI/p8bl73MeZ508Ax3hxWp3SiJpEFiC+BB9XcXy5FAZHTLKDPSzrUpxQZSZJAVdDmuJp/+HDBQ==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [x64]
os: [linux]
libc: [musl]
'@oxlint/binding-openharmony-arm64@1.77.0':
resolution: {integrity: sha512-BJ/j54qS0usEnyDkLYURMj2iiD9h5Cyy+ppzeMSXBGRXaGRNWnj1Mw14NqWMR5E/PzdgB30OOCCzLzbRoduafw==}
'@oxlint/binding-openharmony-arm64@1.80.0':
resolution: {integrity: sha512-zMzbkumtmprCgRwoYNzcB3iC39fXdJIMLMU33KdCjEGLlJGOEt1+LwQ4LF8ndLzAEKVz4BR0y3V6Xrkk3Nm3yA==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [arm64]
os: [openharmony]
'@oxlint/binding-win32-arm64-msvc@1.77.0':
resolution: {integrity: sha512-Yh8w+g2Lpx7StrvtYkoz9JJvXjB9wxgFChFNb85nrXm/wj/XTwGWS1hve9+900HL7llrntYB3YP+y32E3tRqzA==}
'@oxlint/binding-win32-arm64-msvc@1.80.0':
resolution: {integrity: sha512-ib6iRcrXsk4t1fm3iKcwksyWh1ZkZXC/2mEzakl0ai2+6HZunf1WWMZ/xP9EJAvw9g9K4UVTC3NF/+G2qLrbTQ==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [arm64]
os: [win32]
'@oxlint/binding-win32-ia32-msvc@1.77.0':
resolution: {integrity: sha512-zja5b7+6a7UsRFgAQSrnax5vrzliEyNPLCjfXONu/vTWswaIVZGFajJZptaeRvPE4LghtFdAzVFlexTm7MVTGA==}
'@oxlint/binding-win32-ia32-msvc@1.80.0':
resolution: {integrity: sha512-xhRWBMpLxZvgKAH6+DJZmpP+W8Y8UdQOSU1JfxSWNXsaBaRGW77j+1hCuNHlzj7OH4SPN8fYd1q0o2qrDtoVyw==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [ia32]
os: [win32]
'@oxlint/binding-win32-x64-msvc@1.77.0':
resolution: {integrity: sha512-+teyvPDZ2RjUvo+SuCqS/UhaJl1QtdW5fWT5NJTV61V5MIuIS90Db9LixmtEGvXixyttiK62P96MSu3UlpviBw==}
'@oxlint/binding-win32-x64-msvc@1.80.0':
resolution: {integrity: sha512-yAnO7lwBYQnz2pcfBPIGQQZWIX5zd5R/1aAKIF3oE+TVj7IhoHcROjOkz3sRDngzqhfPKfFaXqug5j5rE5dn6Q==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [x64]
os: [win32]
@@ -5638,8 +5638,8 @@ packages:
resolution: {integrity: sha512-uFkGGr1KMWd6aWv9UAqooYrN78trw8MWWmoPvgWokfBEUq1+eiIQ+qfj3wokhy0fxtZWZk+0dHoS7/yRTJtd6w==}
engines: {node: ^20.19.0 || >=22.12.0}
oxfmt@0.52.0:
resolution: {integrity: sha512-nJlYM35F64zTDMecCNhoHNkf+D/eHv7xcjj9XDSj+bFAVtN93m7v8DQMdHd6nDG6Akf/kEYYHmDUBs2Dz27Sug==}
oxfmt@0.65.0:
resolution: {integrity: sha512-SgS5VgnP42T0zl3zWD+xoH8FCqg1SAFnSRoOT/qeoa6gxcYIqrDMOmcXIg/EWSN92Du4ogB4riuKhKd6Y4CGhw==}
engines: {node: ^20.19.0 || >=22.12.0}
hasBin: true
peerDependencies:
@@ -5659,8 +5659,8 @@ packages:
resolution: {integrity: sha512-KjK/XLcXr1DSyonKhsuFqJRiuKqcyG9j3LJ8nkOsrLzGvodBPqzHOKauy10asLMDI0sUpvb+1sxlzff3udZvfg==}
hasBin: true
oxlint@1.77.0:
resolution: {integrity: sha512-qnGh8XJHaQ0dprrDXNQZgS0FgjI6v+V3+X8DwmaV++5Aamy6jGKfDdQ1TUvhUxtmKFAbEf4/WeO5QZX+5WSngg==}
oxlint@1.80.0:
resolution: {integrity: sha512-5nTiSps4qdbCWLbxzuO00alHkEO2exR9YMN/ig6QXWrLsYSG0KaObOAM+l6oU2LcKPWoSAGYbkZIGEu1ViiWKA==}
engines: {node: ^20.19.0 || >=22.12.0}
hasBin: true
peerDependencies:
@@ -7852,61 +7852,61 @@ snapshots:
'@oxc-project/types@0.141.0': {}
'@oxfmt/binding-android-arm-eabi@0.52.0':
'@oxfmt/binding-android-arm-eabi@0.65.0':
optional: true
'@oxfmt/binding-android-arm64@0.52.0':
'@oxfmt/binding-android-arm64@0.65.0':
optional: true
'@oxfmt/binding-darwin-arm64@0.52.0':
'@oxfmt/binding-darwin-arm64@0.65.0':
optional: true
'@oxfmt/binding-darwin-x64@0.52.0':
'@oxfmt/binding-darwin-x64@0.65.0':
optional: true
'@oxfmt/binding-freebsd-x64@0.52.0':
'@oxfmt/binding-freebsd-x64@0.65.0':
optional: true
'@oxfmt/binding-linux-arm-gnueabihf@0.52.0':
'@oxfmt/binding-linux-arm-gnueabihf@0.65.0':
optional: true
'@oxfmt/binding-linux-arm-musleabihf@0.52.0':
'@oxfmt/binding-linux-arm-musleabihf@0.65.0':
optional: true
'@oxfmt/binding-linux-arm64-gnu@0.52.0':
'@oxfmt/binding-linux-arm64-gnu@0.65.0':
optional: true
'@oxfmt/binding-linux-arm64-musl@0.52.0':
'@oxfmt/binding-linux-arm64-musl@0.65.0':
optional: true
'@oxfmt/binding-linux-ppc64-gnu@0.52.0':
'@oxfmt/binding-linux-ppc64-gnu@0.65.0':
optional: true
'@oxfmt/binding-linux-riscv64-gnu@0.52.0':
'@oxfmt/binding-linux-riscv64-gnu@0.65.0':
optional: true
'@oxfmt/binding-linux-riscv64-musl@0.52.0':
'@oxfmt/binding-linux-riscv64-musl@0.65.0':
optional: true
'@oxfmt/binding-linux-s390x-gnu@0.52.0':
'@oxfmt/binding-linux-s390x-gnu@0.65.0':
optional: true
'@oxfmt/binding-linux-x64-gnu@0.52.0':
'@oxfmt/binding-linux-x64-gnu@0.65.0':
optional: true
'@oxfmt/binding-linux-x64-musl@0.52.0':
'@oxfmt/binding-linux-x64-musl@0.65.0':
optional: true
'@oxfmt/binding-openharmony-arm64@0.52.0':
'@oxfmt/binding-openharmony-arm64@0.65.0':
optional: true
'@oxfmt/binding-win32-arm64-msvc@0.52.0':
'@oxfmt/binding-win32-arm64-msvc@0.65.0':
optional: true
'@oxfmt/binding-win32-ia32-msvc@0.52.0':
'@oxfmt/binding-win32-ia32-msvc@0.65.0':
optional: true
'@oxfmt/binding-win32-x64-msvc@0.52.0':
'@oxfmt/binding-win32-x64-msvc@0.65.0':
optional: true
'@oxlint-tsgolint/darwin-arm64@7.0.2001':
@@ -7927,61 +7927,61 @@ snapshots:
'@oxlint-tsgolint/win32-x64@7.0.2001':
optional: true
'@oxlint/binding-android-arm-eabi@1.77.0':
'@oxlint/binding-android-arm-eabi@1.80.0':
optional: true
'@oxlint/binding-android-arm64@1.77.0':
'@oxlint/binding-android-arm64@1.80.0':
optional: true
'@oxlint/binding-darwin-arm64@1.77.0':
'@oxlint/binding-darwin-arm64@1.80.0':
optional: true
'@oxlint/binding-darwin-x64@1.77.0':
'@oxlint/binding-darwin-x64@1.80.0':
optional: true
'@oxlint/binding-freebsd-x64@1.77.0':
'@oxlint/binding-freebsd-x64@1.80.0':
optional: true
'@oxlint/binding-linux-arm-gnueabihf@1.77.0':
'@oxlint/binding-linux-arm-gnueabihf@1.80.0':
optional: true
'@oxlint/binding-linux-arm-musleabihf@1.77.0':
'@oxlint/binding-linux-arm-musleabihf@1.80.0':
optional: true
'@oxlint/binding-linux-arm64-gnu@1.77.0':
'@oxlint/binding-linux-arm64-gnu@1.80.0':
optional: true
'@oxlint/binding-linux-arm64-musl@1.77.0':
'@oxlint/binding-linux-arm64-musl@1.80.0':
optional: true
'@oxlint/binding-linux-ppc64-gnu@1.77.0':
'@oxlint/binding-linux-ppc64-gnu@1.80.0':
optional: true
'@oxlint/binding-linux-riscv64-gnu@1.77.0':
'@oxlint/binding-linux-riscv64-gnu@1.80.0':
optional: true
'@oxlint/binding-linux-riscv64-musl@1.77.0':
'@oxlint/binding-linux-riscv64-musl@1.80.0':
optional: true
'@oxlint/binding-linux-s390x-gnu@1.77.0':
'@oxlint/binding-linux-s390x-gnu@1.80.0':
optional: true
'@oxlint/binding-linux-x64-gnu@1.77.0':
'@oxlint/binding-linux-x64-gnu@1.80.0':
optional: true
'@oxlint/binding-linux-x64-musl@1.77.0':
'@oxlint/binding-linux-x64-musl@1.80.0':
optional: true
'@oxlint/binding-openharmony-arm64@1.77.0':
'@oxlint/binding-openharmony-arm64@1.80.0':
optional: true
'@oxlint/binding-win32-arm64-msvc@1.77.0':
'@oxlint/binding-win32-arm64-msvc@1.80.0':
optional: true
'@oxlint/binding-win32-ia32-msvc@1.77.0':
'@oxlint/binding-win32-ia32-msvc@1.80.0':
optional: true
'@oxlint/binding-win32-x64-msvc@1.77.0':
'@oxlint/binding-win32-x64-msvc@1.80.0':
optional: true
'@parcel/watcher-android-arm64@2.5.6':
@@ -12264,29 +12264,29 @@ snapshots:
'@oxc-parser/binding-win32-ia32-msvc': 0.141.0
'@oxc-parser/binding-win32-x64-msvc': 0.141.0
oxfmt@0.52.0:
oxfmt@0.65.0:
dependencies:
tinypool: 2.1.0
optionalDependencies:
'@oxfmt/binding-android-arm-eabi': 0.52.0
'@oxfmt/binding-android-arm64': 0.52.0
'@oxfmt/binding-darwin-arm64': 0.52.0
'@oxfmt/binding-darwin-x64': 0.52.0
'@oxfmt/binding-freebsd-x64': 0.52.0
'@oxfmt/binding-linux-arm-gnueabihf': 0.52.0
'@oxfmt/binding-linux-arm-musleabihf': 0.52.0
'@oxfmt/binding-linux-arm64-gnu': 0.52.0
'@oxfmt/binding-linux-arm64-musl': 0.52.0
'@oxfmt/binding-linux-ppc64-gnu': 0.52.0
'@oxfmt/binding-linux-riscv64-gnu': 0.52.0
'@oxfmt/binding-linux-riscv64-musl': 0.52.0
'@oxfmt/binding-linux-s390x-gnu': 0.52.0
'@oxfmt/binding-linux-x64-gnu': 0.52.0
'@oxfmt/binding-linux-x64-musl': 0.52.0
'@oxfmt/binding-openharmony-arm64': 0.52.0
'@oxfmt/binding-win32-arm64-msvc': 0.52.0
'@oxfmt/binding-win32-ia32-msvc': 0.52.0
'@oxfmt/binding-win32-x64-msvc': 0.52.0
'@oxfmt/binding-android-arm-eabi': 0.65.0
'@oxfmt/binding-android-arm64': 0.65.0
'@oxfmt/binding-darwin-arm64': 0.65.0
'@oxfmt/binding-darwin-x64': 0.65.0
'@oxfmt/binding-freebsd-x64': 0.65.0
'@oxfmt/binding-linux-arm-gnueabihf': 0.65.0
'@oxfmt/binding-linux-arm-musleabihf': 0.65.0
'@oxfmt/binding-linux-arm64-gnu': 0.65.0
'@oxfmt/binding-linux-arm64-musl': 0.65.0
'@oxfmt/binding-linux-ppc64-gnu': 0.65.0
'@oxfmt/binding-linux-riscv64-gnu': 0.65.0
'@oxfmt/binding-linux-riscv64-musl': 0.65.0
'@oxfmt/binding-linux-s390x-gnu': 0.65.0
'@oxfmt/binding-linux-x64-gnu': 0.65.0
'@oxfmt/binding-linux-x64-musl': 0.65.0
'@oxfmt/binding-openharmony-arm64': 0.65.0
'@oxfmt/binding-win32-arm64-msvc': 0.65.0
'@oxfmt/binding-win32-ia32-msvc': 0.65.0
'@oxfmt/binding-win32-x64-msvc': 0.65.0
oxlint-plugin-react-doctor@0.9.1:
dependencies:
@@ -12304,27 +12304,27 @@ snapshots:
'@oxlint-tsgolint/win32-arm64': 7.0.2001
'@oxlint-tsgolint/win32-x64': 7.0.2001
oxlint@1.77.0(oxlint-tsgolint@7.0.2001):
oxlint@1.80.0(oxlint-tsgolint@7.0.2001):
optionalDependencies:
'@oxlint/binding-android-arm-eabi': 1.77.0
'@oxlint/binding-android-arm64': 1.77.0
'@oxlint/binding-darwin-arm64': 1.77.0
'@oxlint/binding-darwin-x64': 1.77.0
'@oxlint/binding-freebsd-x64': 1.77.0
'@oxlint/binding-linux-arm-gnueabihf': 1.77.0
'@oxlint/binding-linux-arm-musleabihf': 1.77.0
'@oxlint/binding-linux-arm64-gnu': 1.77.0
'@oxlint/binding-linux-arm64-musl': 1.77.0
'@oxlint/binding-linux-ppc64-gnu': 1.77.0
'@oxlint/binding-linux-riscv64-gnu': 1.77.0
'@oxlint/binding-linux-riscv64-musl': 1.77.0
'@oxlint/binding-linux-s390x-gnu': 1.77.0
'@oxlint/binding-linux-x64-gnu': 1.77.0
'@oxlint/binding-linux-x64-musl': 1.77.0
'@oxlint/binding-openharmony-arm64': 1.77.0
'@oxlint/binding-win32-arm64-msvc': 1.77.0
'@oxlint/binding-win32-ia32-msvc': 1.77.0
'@oxlint/binding-win32-x64-msvc': 1.77.0
'@oxlint/binding-android-arm-eabi': 1.80.0
'@oxlint/binding-android-arm64': 1.80.0
'@oxlint/binding-darwin-arm64': 1.80.0
'@oxlint/binding-darwin-x64': 1.80.0
'@oxlint/binding-freebsd-x64': 1.80.0
'@oxlint/binding-linux-arm-gnueabihf': 1.80.0
'@oxlint/binding-linux-arm-musleabihf': 1.80.0
'@oxlint/binding-linux-arm64-gnu': 1.80.0
'@oxlint/binding-linux-arm64-musl': 1.80.0
'@oxlint/binding-linux-ppc64-gnu': 1.80.0
'@oxlint/binding-linux-riscv64-gnu': 1.80.0
'@oxlint/binding-linux-riscv64-musl': 1.80.0
'@oxlint/binding-linux-s390x-gnu': 1.80.0
'@oxlint/binding-linux-x64-gnu': 1.80.0
'@oxlint/binding-linux-x64-musl': 1.80.0
'@oxlint/binding-openharmony-arm64': 1.80.0
'@oxlint/binding-win32-arm64-msvc': 1.80.0
'@oxlint/binding-win32-ia32-msvc': 1.80.0
'@oxlint/binding-win32-x64-msvc': 1.80.0
oxlint-tsgolint: 7.0.2001
p-cancelable@2.1.1: {}
+20 -20
View File
@@ -85,23 +85,21 @@ export async function scanAiVaultSessions(
const candidates = dedupeCodexRolloutFileAliases(
discoveries
.flatMap((discovery) =>
discovery.files.map(
(file): SessionFileCandidate => ({
agent: discovery.agent,
file,
codexHome:
discovery.agent === 'codex'
? codexHomeForSessionsDir(
discovery.rootDir,
options.defaultCodexHomeDir ?? DEFAULT_CODEX_HOME_DIR
)
: null,
antigravityHistoryPath:
discovery.agent === 'antigravity'
? antigravityHistoryPathForBrainDir(discovery.rootDir)
: undefined
})
)
discovery.files.map((file): SessionFileCandidate => ({
agent: discovery.agent,
file,
codexHome:
discovery.agent === 'codex'
? codexHomeForSessionsDir(
discovery.rootDir,
options.defaultCodexHomeDir ?? DEFAULT_CODEX_HOME_DIR
)
: null,
antigravityHistoryPath:
discovery.agent === 'antigravity'
? antigravityHistoryPathForBrainDir(discovery.rootDir)
: undefined
}))
)
.sort((left, right) => right.file.mtimeMs - left.file.mtimeMs),
{
@@ -203,9 +201,11 @@ async function scanInScopeSessions(args: {
excludedFilePaths: args.alreadyParsedFilePaths,
issues: args.issues
})
const candidates = files.map(
(file): SessionFileCandidate => ({ agent: 'claude', file, codexHome: null })
)
const candidates = files.map((file): SessionFileCandidate => ({
agent: 'claude',
file,
codexHome: null
}))
if (candidates.length === 0) {
return []
}
+1 -1
View File
@@ -822,7 +822,7 @@ export class CdpBridge {
async tabSwitch(index: number): Promise<BrowserTabSwitchResult> {
// Why: filter to live tabs so indices match tabList(), skipping destroyed-but-uncleaned entries.
const liveEntries = [...this.getRegisteredTabs()].filter(([_, wcId]) => {
const liveEntries = [...this.getRegisteredTabs()].filter(([_tabId, wcId]) => {
const guest = webContents.fromId(wcId)
return guest && !guest.isDestroyed()
})
@@ -33,8 +33,8 @@ describe('estimateCostUsd cache-write TTL rates', () => {
})
it('never lowers a long-context estimate as writes shift from 5-minute to 1-hour', () => {
const costs = [0, 50_000, 100_000, 200_000, 300_000, 400_000].map(
(write1h) => estimateCostUsd('claude-sonnet-4-6', 0, 0, 0, 400_000, write1h)!
const costs = [0, 50_000, 100_000, 200_000, 300_000, 400_000].map((write1h) =>
estimateCostUsd('claude-sonnet-4-6', 0, 0, 0, 400_000, write1h)!
)
for (let index = 1; index < costs.length; index++) {
expect(costs[index]).toBeGreaterThan(costs[index - 1])
@@ -205,9 +205,10 @@ export function createRuntimeHome(): RuntimeHomeStub {
return {
syncForCurrentSelection: vi.fn(),
clearLastWrittenAuthJson: vi.fn(),
prepareForRateLimitFetch: vi.fn(
(): CodexRateLimitHomeResolution => ({ kind: 'ready', codexHomePath: null })
)
prepareForRateLimitFetch: vi.fn((): CodexRateLimitHomeResolution => ({
kind: 'ready',
codexHomePath: null
}))
}
}
@@ -191,13 +191,11 @@ describe('Codex state DB backfill recovery', () => {
const summary = await runCodexStateDbBackfillRecovery('/managed-home', controller.signal, {
spawnProcess: spawnProcess as never,
readStatus: vi.fn(
(): CodexStateDbBackfillStatus => ({
kind: 'incomplete',
stateDbPath: '/state.sqlite',
status: 'running'
})
),
readStatus: vi.fn((): CodexStateDbBackfillStatus => ({
kind: 'incomplete',
stateDbPath: '/state.sqlite',
status: 'running'
})),
terminate,
sleep,
now: () => now
@@ -270,15 +268,14 @@ describe('Codex state DB backfill recovery', () => {
new AbortController().signal,
{
spawnProcess: spawnProcess as never,
readStatus: vi.fn(
(): CodexStateDbBackfillStatus =>
spawnProcess.mock.calls.length >= 3
? { kind: 'complete', stateDbPath: '/state.sqlite' }
: {
kind: 'incomplete',
stateDbPath: '/state.sqlite',
status: 'running'
}
readStatus: vi.fn((): CodexStateDbBackfillStatus =>
spawnProcess.mock.calls.length >= 3
? { kind: 'complete', stateDbPath: '/state.sqlite' }
: {
kind: 'incomplete',
stateDbPath: '/state.sqlite',
status: 'running'
}
),
terminate: terminate as never,
sleep,
@@ -328,11 +325,10 @@ describe('Codex state DB backfill recovery', () => {
await expect(
runCodexStateDbBackfillRecovery('/managed-home', new AbortController().signal, {
spawnProcess: spawnProcess as never,
readStatus: vi.fn(
(): CodexStateDbBackfillStatus =>
spawnCount >= 2
? { kind: 'complete', stateDbPath: '/state.sqlite' }
: { kind: 'incomplete', stateDbPath: '/state.sqlite', status: 'running' }
readStatus: vi.fn((): CodexStateDbBackfillStatus =>
spawnCount >= 2
? { kind: 'complete', stateDbPath: '/state.sqlite' }
: { kind: 'incomplete', stateDbPath: '/state.sqlite', status: 'running' }
),
terminate,
sleep: vi.fn(async (ms: number) => {
@@ -427,11 +423,10 @@ describe('Codex state DB backfill recovery', () => {
}
return child
})
const readStatus = vi.fn(
(): CodexStateDbBackfillStatus =>
spawnCount >= 2
? { kind: 'complete', stateDbPath: '/state.sqlite' }
: { kind: 'incomplete', stateDbPath: '/state.sqlite', status: 'running' }
const readStatus = vi.fn((): CodexStateDbBackfillStatus =>
spawnCount >= 2
? { kind: 'complete', stateDbPath: '/state.sqlite' }
: { kind: 'incomplete', stateDbPath: '/state.sqlite', status: 'running' }
)
await expect(
@@ -13,15 +13,13 @@ function makeBackend(): {
const resolveDeviceId = vi.fn(async () => {
throw new Error('shutdown AVD cannot resolve before boot')
})
const startSession = vi.fn(
async (): Promise<EmulatorSessionInfo> => ({
deviceUdid: 'emulator-5554',
streamUrl: 'scrcpy://emulator-5554',
wsUrl: '',
streamCodec: 'h264',
backend: 'android'
})
)
const startSession = vi.fn(async (): Promise<EmulatorSessionInfo> => ({
deviceUdid: 'emulator-5554',
streamUrl: 'scrcpy://emulator-5554',
wsUrl: '',
streamCodec: 'h264',
backend: 'android'
}))
const stopHelperForDevice = vi.fn(async () => {})
const shutdownDevice = vi.fn(async () => {})
const backend: EmulatorBackend = {
+31 -37
View File
@@ -149,19 +149,17 @@ export async function getPRComments(
if (!pullRequest) {
console.warn('Review threads response missing pullRequest; keeping REST results')
}
const graphQLIssueComments = (pullRequest?.comments?.nodes ?? []).map(
(c): PRComment => ({
id: c.databaseId,
author: c.author?.login ?? 'ghost',
authorAvatarUrl: c.author?.avatarUrl ?? '',
body: c.body ?? '',
createdAt: c.createdAt,
url: c.url,
isBot: c.author?.__typename === 'Bot',
reactionSubjectId: c.id,
reactions: mapGraphQLReactionGroups(c.reactionGroups)
})
)
const graphQLIssueComments = (pullRequest?.comments?.nodes ?? []).map((c): PRComment => ({
id: c.databaseId,
author: c.author?.login ?? 'ghost',
authorAvatarUrl: c.author?.avatarUrl ?? '',
body: c.body ?? '',
createdAt: c.createdAt,
url: c.url,
isBot: c.author?.__typename === 'Bot',
reactionSubjectId: c.id,
reactions: mapGraphQLReactionGroups(c.reactionGroups)
}))
if (graphQLIssueComments.length > 0) {
issueComments = graphQLIssueComments
}
@@ -169,19 +167,17 @@ export async function getPRComments(
graphQLReviewSummaries = pullRequest
? (pullRequest.reviews?.nodes ?? [])
.filter((review) => review.body?.trim())
.map(
(review): PRComment => ({
id: review.databaseId,
author: review.author?.login ?? 'ghost',
authorAvatarUrl: review.author?.avatarUrl ?? '',
body: review.body,
createdAt: review.createdAt,
url: review.url,
isBot: review.author?.__typename === 'Bot',
reactionSubjectId: review.id,
reactions: mapGraphQLReactionGroups(review.reactionGroups)
})
)
.map((review): PRComment => ({
id: review.databaseId,
author: review.author?.login ?? 'ghost',
authorAvatarUrl: review.author?.avatarUrl ?? '',
body: review.body,
createdAt: review.createdAt,
url: review.url,
isBot: review.author?.__typename === 'Bot',
reactionSubjectId: review.id,
reactions: mapGraphQLReactionGroups(review.reactionGroups)
}))
: undefined
const threads = pullRequest?.reviewThreads?.nodes ?? []
@@ -228,17 +224,15 @@ export async function getPRComments(
} else if (reviewsResult.status === 'fulfilled') {
reviewSummaries = (JSON.parse(reviewsResult.value.stdout) as RESTReview[])
.filter((r) => r.body?.trim())
.map(
(r): PRComment => ({
id: r.id,
author: r.user?.login ?? 'ghost',
authorAvatarUrl: r.user?.avatar_url ?? '',
body: r.body,
createdAt: r.submitted_at,
url: r.html_url,
isBot: r.user?.type === 'Bot'
})
)
.map((r): PRComment => ({
id: r.id,
author: r.user?.login ?? 'ghost',
authorAvatarUrl: r.user?.avatar_url ?? '',
body: r.body,
createdAt: r.submitted_at,
url: r.html_url,
isBot: r.user?.type === 'Bot'
}))
} else {
console.warn('Failed to fetch review summaries:', reviewsResult.reason)
}
+8 -10
View File
@@ -238,16 +238,14 @@ export async function getIssueBodyAndComments(
}[]
assignees?: { login: string }[]
}
const comments = (data.comments ?? []).map(
(comment, index): PRComment => ({
id: index,
author: comment.author?.login ?? 'ghost',
authorAvatarUrl: '',
body: comment.body ?? '',
createdAt: comment.createdAt,
url: comment.url ?? ''
})
)
const comments = (data.comments ?? []).map((comment, index): PRComment => ({
id: index,
author: comment.author?.login ?? 'ghost',
authorAvatarUrl: '',
body: comment.body ?? '',
createdAt: comment.createdAt,
url: comment.url ?? ''
}))
return {
body: data.body ?? '',
comments,
@@ -8,10 +8,10 @@ import {
describe('queueWatcherEvents', () => {
function events(count: number): WatcherEvent[] {
return Array.from(
{ length: count },
(_, index): WatcherEvent => ({ type: 'update', path: `/repo/file-${index}.ts` })
)
return Array.from({ length: count }, (_, index): WatcherEvent => ({
type: 'update',
path: `/repo/file-${index}.ts`
}))
}
it('keeps precise events while the batch remains under the overflow limit', () => {
@@ -73,10 +73,10 @@ describe('local filesystem watcher large batches', () => {
{ worktreePath }
)
const events = Array.from(
{ length: 200_000 },
(_, index): WatcherEvent => ({ type: 'delete', path: join(worktreePath, `file-${index}`) })
)
const events = Array.from({ length: 200_000 }, (_, index): WatcherEvent => ({
type: 'delete',
path: join(worktreePath, `file-${index}`)
}))
expect(() => watcherCallback?.(null, events)).not.toThrow()
await closeAllWatchers()
@@ -97,13 +97,10 @@ describe('local filesystem watcher large batches', () => {
await handlers['fs:watchWorktree']({ sender }, { worktreePath })
watcherCallback?.(
null,
Array.from(
{ length: 5_001 },
(_, index): WatcherEvent => ({
type: 'update',
path: join(worktreePath, `file-${index}.txt`)
})
)
Array.from({ length: 5_001 }, (_, index): WatcherEvent => ({
type: 'update',
path: join(worktreePath, `file-${index}.txt`)
}))
)
await vi.advanceTimersByTimeAsync(150)
@@ -107,13 +107,10 @@ describe('remote filesystem watcher batching', () => {
await handlers['fs:watchWorktree']({ sender }, WATCH_ARGS)
watchCallbacks[0](
Array.from(
{ length: 6_000 },
(_unused, index): FsChangeEvent => ({
kind: 'update',
absolutePath: `${WORKTREE_PATH}/file-${index}.ts`
})
)
Array.from({ length: 6_000 }, (_unused, index): FsChangeEvent => ({
kind: 'update',
absolutePath: `${WORKTREE_PATH}/file-${index}.ts`
}))
)
await vi.advanceTimersByTimeAsync(150)
+6 -10
View File
@@ -169,17 +169,13 @@ export function registerOrcaProfileHandlers(
store: Store,
options: RegisterOrcaProfileHandlersOptions = {}
): void {
ipcMain.handle(
'orcaProfiles:list',
(): OrcaProfileListResult => ({
...getOrcaProfileListState(),
multiProfileUi: isMultiProfileUiEnabled()
})
)
ipcMain.handle('orcaProfiles:list', (): OrcaProfileListResult => ({
...getOrcaProfileListState(),
multiProfileUi: isMultiProfileUiEnabled()
}))
ipcMain.handle(
'orcaProfiles:authStatus',
(): OrcaProfileAuthStatus => getCurrentOrcaProfileAuthStatus(getProfileUserDataPath())
ipcMain.handle('orcaProfiles:authStatus', (): OrcaProfileAuthStatus =>
getCurrentOrcaProfileAuthStatus(getProfileUserDataPath())
)
ipcMain.handle(
+2 -3
View File
@@ -81,9 +81,8 @@ export function registerPetHandlers(): void {
}
})
ipcMain.handle(
'pet:importPetBundle',
async (event): Promise<CustomPet | null> => importPetBundle(event)
ipcMain.handle('pet:importPetBundle', async (event): Promise<CustomPet | null> =>
importPetBundle(event)
)
ipcMain.handle(
@@ -182,13 +182,10 @@ describe('createRemoteWatcherEventBatch', () => {
for (let i = 0; i < 3; i++) {
batch.push(
Array.from(
{ length: 50 },
(_unused, index): FsChangeEvent => ({
kind: 'update',
absolutePath: `${ROOT}/wave-${i}-${index}.ts`
})
)
Array.from({ length: 50 }, (_unused, index): FsChangeEvent => ({
kind: 'update',
absolutePath: `${ROOT}/wave-${i}-${index}.ts`
}))
)
}
vi.advanceTimersByTime(150)
@@ -107,7 +107,7 @@ export class SshPtyModelAdmissionPressure {
if (options.disposed) {
return
}
for (let index = 0; index < this.entries.length; ) {
for (let index = 0; index < this.entries.length;) {
const entry = this.entries[index]!
const hasEarlierEntryForPty = this.entries
.slice(0, index)
@@ -447,16 +447,13 @@ describe('workspace cleanup broad scan opt-in', () => {
it('batches fleet progress instead of emitting one IPC payload per row', async () => {
const worktrees = [
GIT_WORKTREES[0],
...Array.from(
{ length: 200 },
(_, index): GitWorktreeInfo => ({
path: `/repo-batch-${index}`,
head: `head-${index}`,
branch: `refs/heads/batch-${index}`,
isBare: false,
isMainWorktree: false
})
)
...Array.from({ length: 200 }, (_, index): GitWorktreeInfo => ({
path: `/repo-batch-${index}`,
head: `head-${index}`,
branch: `refs/heads/batch-${index}`,
isBare: false,
isMainWorktree: false
}))
]
listRepoWorktreesMock.mockResolvedValue(worktrees)
const onProgress = vi.fn()
+9 -12
View File
@@ -767,18 +767,15 @@ describe('workspace cleanup scan', () => {
})
it('summarizes large diff-note lists without hitting argument limits', async () => {
const diffComments = Array.from(
{ length: 150_000 },
(_, index): DiffComment => ({
id: `comment-${index}`,
worktreeId: 'repo-1::/repo-feature',
filePath: 'src/file.ts',
lineNumber: 12,
body: 'Follow up before deleting',
createdAt: NOW - index,
side: 'modified'
})
)
const diffComments = Array.from({ length: 150_000 }, (_, index): DiffComment => ({
id: `comment-${index}`,
worktreeId: 'repo-1::/repo-feature',
filePath: 'src/file.ts',
lineNumber: 12,
body: 'Follow up before deleting',
createdAt: NOW - index,
side: 'modified'
}))
const result = await scanWorkspaceCleanup(
makeStore({
+2 -4
View File
@@ -127,10 +127,8 @@ export function registerWorkspaceCleanupHandlers(
return true
})
ipcMain.handle(
'workspaceCleanup:getCachedScan',
(): Promise<WorkspaceCleanupScanResult | null> =>
readWorkspaceCleanupScanSnapshot(snapshotDirectory)
ipcMain.handle('workspaceCleanup:getCachedScan', (): Promise<WorkspaceCleanupScanResult | null> =>
readWorkspaceCleanupScanSnapshot(snapshotDirectory)
)
ipcMain.handle('workspaceCleanup:dismiss', (_event, args: WorkspaceCleanupDismissArgs) => {
+2 -4
View File
@@ -114,10 +114,8 @@ export function registerWorkspaceSpaceHandlers(store: Store): void {
return inFlightScan.promise
})
ipcMain.handle(
'workspaceSpace:getCachedAnalysis',
(): Promise<WorkspaceSpaceAnalysis | null> =>
readWorkspaceSpaceAnalysisSnapshot(snapshotDirectory)
ipcMain.handle('workspaceSpace:getCachedAnalysis', (): Promise<WorkspaceSpaceAnalysis | null> =>
readWorkspaceSpaceAnalysisSnapshot(snapshotDirectory)
)
ipcMain.handle('workspaceSpace:cancel', async (): Promise<boolean> => {
+1 -1
View File
@@ -25,7 +25,7 @@ export function escapeMarkdownLinkDestination(url: string): string | null {
}
let encoded = ''
for (let i = 0; i < url.length; ) {
for (let i = 0; i < url.length;) {
const char = url[i] ?? ''
if (char === '%') {
const hex = url.slice(i + 1, i + 3)
@@ -161,7 +161,9 @@ describe('readNativeChatTranscriptCached', () => {
await utimes(fileA, when, when)
await utimes(fileC, when, when)
const readText = (result: Awaited<ReturnType<typeof readNativeChatTranscriptCached>>): string =>
const readText = (
result: Awaited<ReturnType<typeof readNativeChatTranscriptCached>>
): string =>
'messages' in result
? result.messages
.flatMap((message) => message.blocks)
+19 -21
View File
@@ -150,25 +150,23 @@ export function buildOpenCodeUsageRecentSessions(
filteredSessions: OpenCodeUsageSession[],
limit = 10
): OpenCodeUsageSessionRow[] {
return filteredSessions.slice(0, limit).map(
(session): OpenCodeUsageSessionRow => ({
sessionId: session.sessionId,
lastActiveAt: session.lastTimestamp,
durationMinutes: Math.max(
0,
Math.round(
(new Date(session.lastTimestamp).getTime() - new Date(session.firstTimestamp).getTime()) /
60_000
)
),
projectLabel: session.primaryProjectLabel,
model: session.primaryModel,
events: session.eventCount,
inputTokens: session.totalInputTokens,
cachedInputTokens: session.totalCachedInputTokens,
outputTokens: session.totalOutputTokens,
reasoningOutputTokens: session.totalReasoningOutputTokens,
totalTokens: session.totalTokens
})
)
return filteredSessions.slice(0, limit).map((session): OpenCodeUsageSessionRow => ({
sessionId: session.sessionId,
lastActiveAt: session.lastTimestamp,
durationMinutes: Math.max(
0,
Math.round(
(new Date(session.lastTimestamp).getTime() - new Date(session.firstTimestamp).getTime()) /
60_000
)
),
projectLabel: session.primaryProjectLabel,
model: session.primaryModel,
events: session.eventCount,
inputTokens: session.totalInputTokens,
cachedInputTokens: session.totalCachedInputTokens,
outputTokens: session.totalOutputTokens,
reasoningOutputTokens: session.totalReasoningOutputTokens,
totalTokens: session.totalTokens
}))
}
@@ -338,7 +338,7 @@ describe('getPiAgentStatusExtensionSource', () => {
await vi.waitFor(() => expect(harness.fetchMock).toHaveBeenCalledTimes(2))
const payloads = harness.fetchMock.mock.calls.map(
([_, init]) => JSON.parse(String(init?.body)).payload
([_event, init]) => JSON.parse(String(init?.body)).payload
)
expect(payloads).toEqual([
{ hook_event_name: 'session_start' },
@@ -391,7 +391,7 @@ describe('getPiAgentStatusExtensionSource', () => {
await vi.waitFor(() => expect(harness.fetchMock).toHaveBeenCalledTimes(3))
expect(
harness.fetchMock.mock.calls.map(([_, init]) => JSON.parse(String(init?.body)).payload)
harness.fetchMock.mock.calls.map(([_event, init]) => JSON.parse(String(init?.body)).payload)
).toEqual([
{ hook_event_name: 'agent_start', session_id: 'omp-session-8' },
{
+24 -30
View File
@@ -1938,16 +1938,14 @@ export class RateLimitService {
allowPtyFallback: this.shouldAllowCodexPtyFallback(),
signal
})
).catch(
(err): ProviderRateLimits => ({
provider: 'codex',
session: null,
weekly: null,
updatedAt: Date.now(),
error: err instanceof Error ? err.message : 'Unknown error',
status: 'error'
})
)
).catch((err): ProviderRateLimits => ({
provider: 'codex',
session: null,
weekly: null,
updatedAt: Date.now(),
error: err instanceof Error ? err.message : 'Unknown error',
status: 'error'
}))
if (signal.aborted) {
return
@@ -2008,16 +2006,14 @@ export class RateLimitService {
allowUsagePanelSupplement: this.shouldAllowClaudeUsagePanelSupplement(),
networkProxySettings: this.networkProxySettingsResolver?.(),
signal
}).catch(
(err): ProviderRateLimits => ({
provider: 'claude',
session: null,
weekly: null,
updatedAt: Date.now(),
error: err instanceof Error ? err.message : 'Unknown error',
status: 'error'
})
)
}).catch((err): ProviderRateLimits => ({
provider: 'claude',
session: null,
weekly: null,
updatedAt: Date.now(),
error: err instanceof Error ? err.message : 'Unknown error',
status: 'error'
}))
if (signal.aborted) {
return
@@ -2060,16 +2056,14 @@ export class RateLimitService {
const grok = await fetchGrokRateLimits({
signal,
authReadResult: grokAuthReadResult
}).catch(
(err): ProviderRateLimits => ({
provider: 'grok',
session: null,
weekly: null,
updatedAt: Date.now(),
error: err instanceof Error ? err.message : 'Unknown error',
status: 'error'
})
)
}).catch((err): ProviderRateLimits => ({
provider: 'grok',
session: null,
weekly: null,
updatedAt: Date.now(),
error: err instanceof Error ? err.message : 'Unknown error',
status: 'error'
}))
if (signal.aborted) {
return
+10 -14
View File
@@ -6067,22 +6067,18 @@ export class OrcaRuntimeService {
)
const worktrees = (await this.listResolvedWorktrees())
.filter((worktree) => repos.has(getRepoIdFromWorktreeId(worktree.id)))
.map(
(worktree): SkillSshWorkspaceAuthority => ({
kind: 'worktree',
id: worktree.id,
path: worktree.path
})
)
.map((worktree): SkillSshWorkspaceAuthority => ({
kind: 'worktree',
id: worktree.id,
path: worktree.path
}))
const folders = this.listFolderWorkspaces()
.filter((folder) => folder.connectionId === connectionId)
.map(
(folder): SkillSshWorkspaceAuthority => ({
kind: 'folder',
id: folder.id,
path: folder.folderPath
})
)
.map((folder): SkillSshWorkspaceAuthority => ({
kind: 'folder',
id: folder.id,
path: folder.folderPath
}))
return [...worktrees, ...folders]
}
@@ -34,7 +34,7 @@ export function exceedsTerminalStreamChunkBytes(data: string): boolean {
return false
}
let byteLength = 0
for (let start = 0; start < data.length; ) {
for (let start = 0; start < data.length;) {
let end = Math.min(start + TERMINAL_STREAM_BYTE_PROBE_CODE_UNITS, data.length)
const high = data.charCodeAt(end - 1)
const low = data.charCodeAt(end)
+8 -10
View File
@@ -92,16 +92,14 @@ export const nativeSkillInstallFilesystem: SkillInstallFilesystem = {
inspectPaths: async (paths) =>
new Map(
await runSkillCandidateTasks(
paths.map(
(path) => async (): Promise<[string, SkillPathInspection]> => [
path,
{
kind: statKind(await lstat(path).catch(() => null)),
realpath: await realpath(path).catch(() => null),
mtimeMs: (await stat(path).catch(() => null))?.mtimeMs ?? null
}
]
)
paths.map((path) => async (): Promise<[string, SkillPathInspection]> => [
path,
{
kind: statKind(await lstat(path).catch(() => null)),
realpath: await realpath(path).catch(() => null),
mtimeMs: (await stat(path).catch(() => null))?.mtimeMs ?? null
}
])
)
)
}
@@ -654,7 +654,10 @@ describe('PtyHandler negotiated source publication', () => {
expect(mockPtySpawn).toHaveBeenCalledOnce()
expect(
responseResult(replacementWrites.find((buffer) => responseResult(buffer, 4))!, 4)
responseResult(
replacementWrites.find((buffer) => responseResult(buffer, 4))!,
4
)
).toMatchObject({
id: 'pty-1',
incarnationId: expect.any(String),
@@ -96,34 +96,32 @@ export function usePersistedUIWriter(): void {
const persistedUIReady = useAppStore((s) => s.persistedUIReady)
const activeView = useAppStore((s) => s.activeView)
const ui = useAppStore(
useShallow(
(s): PersistedUIWriteBaseline => ({
sidebarWidth: s.sidebarWidth,
rightSidebarOpen: s.rightSidebarOpen,
rightSidebarTab: s.rightSidebarTab,
rightSidebarExplorerView: s.rightSidebarExplorerView,
rightSidebarWidth: s.rightSidebarWidth,
markdownTocPanelWidth: s.markdownTocPanelWidth,
combinedDiffFileTreeWidth: s.combinedDiffFileTreeWidth,
groupBy: s.groupBy,
sortBy: s.sortBy,
projectOrderBy: s.projectOrderBy,
showSleepingWorkspaces: s.showSleepingWorkspaces,
hideDefaultBranchWorkspace: s.hideDefaultBranchWorkspace,
hideAutomationGeneratedWorkspaces: s.hideAutomationGeneratedWorkspaces,
hideCliCreatedWorkspaces: s.hideCliCreatedWorkspaces,
hideDetachedHeadWorkspaces: s.hideDetachedHeadWorkspaces,
hideWorkspacesFromOtherDevices: s.hideWorkspacesFromOtherDevices,
alwaysShowDefaultBranchWorkspace: s.alwaysShowDefaultBranchWorkspace,
showDotfilesByWorktree: s.showDotfilesByWorktree,
filterRepoIds: s.filterRepoIds,
// Why: dashboard auto-acks (fire on focus/visibility) and the in-memory ack cleanup
// paths in agent-status.ts (close/dismiss) flow to disk through map identity changes.
// Without persisting, agent rows that survive restart come back bold even when the
// user had already visited them.
acknowledgedAgentsByPaneKey: s.acknowledgedAgentsByPaneKey
})
)
useShallow((s): PersistedUIWriteBaseline => ({
sidebarWidth: s.sidebarWidth,
rightSidebarOpen: s.rightSidebarOpen,
rightSidebarTab: s.rightSidebarTab,
rightSidebarExplorerView: s.rightSidebarExplorerView,
rightSidebarWidth: s.rightSidebarWidth,
markdownTocPanelWidth: s.markdownTocPanelWidth,
combinedDiffFileTreeWidth: s.combinedDiffFileTreeWidth,
groupBy: s.groupBy,
sortBy: s.sortBy,
projectOrderBy: s.projectOrderBy,
showSleepingWorkspaces: s.showSleepingWorkspaces,
hideDefaultBranchWorkspace: s.hideDefaultBranchWorkspace,
hideAutomationGeneratedWorkspaces: s.hideAutomationGeneratedWorkspaces,
hideCliCreatedWorkspaces: s.hideCliCreatedWorkspaces,
hideDetachedHeadWorkspaces: s.hideDetachedHeadWorkspaces,
hideWorkspacesFromOtherDevices: s.hideWorkspacesFromOtherDevices,
alwaysShowDefaultBranchWorkspace: s.alwaysShowDefaultBranchWorkspace,
showDotfilesByWorktree: s.showDotfilesByWorktree,
filterRepoIds: s.filterRepoIds,
// Why: dashboard auto-acks (fire on focus/visibility) and the in-memory ack cleanup
// paths in agent-status.ts (close/dismiss) flow to disk through map identity changes.
// Without persisting, agent rows that survive restart come back bold even when the
// user had already visited them.
acknowledgedAgentsByPaneKey: s.acknowledgedAgentsByPaneKey
}))
)
useEffect(() => {
// The baseline holds the values this client last saw persisted (newest
+2 -2
View File
@@ -758,8 +758,8 @@ export default function TaskPage(): React.JSX.Element {
// Hard guarantee (K4): always overlay pending after reconcile so list
// fetch clobbers never paint unprotected coordinator fields.
setPages((current) =>
reconcileTaskPagePagesWithWorkItemsCache(current, selectedWorkItemsCacheEntries).map((page) =>
page ? (overlayPendingOnTaskPagePages([page])[0] ?? []) : null
reconcileTaskPagePagesWithWorkItemsCache(current, selectedWorkItemsCacheEntries).map(
(page) => (page ? (overlayPendingOnTaskPagePages([page])[0] ?? []) : null)
)
)
}, [githubMode, selectedWorkItemsCacheEntries, taskSource, setPages])
@@ -2022,13 +2022,11 @@ function WorktreeJumpPaletteContent({
fetchLinearIssue: state.fetchLinearIssue
})
.catch(() => null)
.then(
(issue): CmdJLinearIssuePreview => ({
...pendingPreview,
issue,
loading: false
})
)
.then((issue): CmdJLinearIssuePreview => ({
...pendingPreview,
issue,
loading: false
}))
linearIssueLookupRef.current = { query: createWorktreeName, promise }
void promise.then((preview) => {
if (linearIssueLookupGenerationRef.current === generation) {
@@ -2077,13 +2075,11 @@ function WorktreeJumpPaletteContent({
sourceContext
})
.catch(() => null)
.then(
(item): CmdJGitHubWorkItemPreview => ({
...pendingPreview,
item: item ?? null,
loading: false
})
)
.then((item): CmdJGitHubWorkItemPreview => ({
...pendingPreview,
item: item ?? null,
loading: false
}))
githubLookupRef.current = { query: createWorktreeName, promise }
void promise.then((preview) => {
if (githubLookupGenerationRef.current === generation) {
@@ -89,7 +89,7 @@ describe('automation run output snapshot queue equivalence', () => {
const reference = createShiftReferenceBuffer()
const candidate = createAutomationRunOutputSnapshotBuffer()
let chunkCount = 0
for (let offset = 0; offset < source.length; ) {
for (let offset = 0; offset < source.length;) {
const chunkLength = 1 + (random() % 73)
const chunk = source.slice(offset, offset + chunkLength)
reference.append(chunk)
@@ -35,7 +35,7 @@ function inlineText(
// scanning only the bounded text we will actually retain.
let normalized = ''
let pendingSpace = false
for (let index = 0; index < content.length && normalized.length < maxLength; ) {
for (let index = 0; index < content.length && normalized.length < maxLength;) {
const code = content.charCodeAt(index)
if (isInlineWhitespaceCode(code)) {
if (code === 13 && content.charCodeAt(index + 1) === 10) {
@@ -14,9 +14,10 @@ const mocks = vi.hoisted(() => ({
onSnapshotRequested: vi.fn(),
getPopoutOpen: vi.fn(async () => false),
publishSnapshot: vi.fn(async (_snapshot: DashboardSnapshot) => undefined),
buildDashboardSnapshot: vi.fn(
(_state: unknown, now: number): DashboardSnapshot => ({ generatedAt: now, cards: [] })
),
buildDashboardSnapshot: vi.fn((_state: unknown, now: number): DashboardSnapshot => ({
generatedAt: now,
cards: []
})),
offRevealAgent: vi.fn(),
offAckAgent: vi.fn(),
offPopoutOpenChanged: vi.fn(),
@@ -27,24 +27,20 @@ export function getIssueConversationEntries(
timelineItems: GitHubIssueTimelineItem[]
): IssueConversationEntry[] {
return [
...comments.map(
(comment, index): IssueConversationEntry => ({
kind: 'comment',
id: `comment:${comment.id}`,
createdAt: comment.createdAt,
comment,
index
})
),
...timelineItems.map(
(activity, index): IssueConversationEntry => ({
kind: 'activity',
id: `activity:${activity.id}`,
createdAt: activity.createdAt,
activity,
index: comments.length + index
})
)
...comments.map((comment, index): IssueConversationEntry => ({
kind: 'comment',
id: `comment:${comment.id}`,
createdAt: comment.createdAt,
comment,
index
})),
...timelineItems.map((activity, index): IssueConversationEntry => ({
kind: 'activity',
id: `activity:${activity.id}`,
createdAt: activity.createdAt,
activity,
index: comments.length + index
}))
].sort((a, b) => {
const diff = getTimelineSortValue(a.createdAt) - getTimelineSortValue(b.createdAt)
return diff === 0 ? a.index - b.index : diff
@@ -25,14 +25,12 @@ export function projectStructuredAgentSessionMessages(
...projectStructuredItemsToNativeChat(items),
...optimistic
.filter((entry) => !journalled.has(agentJournalSubmissionKey(entry.clientMessageId)))
.map(
(entry): NativeChatMessage => ({
id: agentJournalSubmissionKey(entry.clientMessageId),
role: 'user',
source: 'transcript',
timestamp: entry.queuedAt,
blocks: entry.body.blocks
})
)
.map((entry): NativeChatMessage => ({
id: agentJournalSubmissionKey(entry.clientMessageId),
role: 'user',
source: 'transcript',
timestamp: entry.queuedAt,
blocks: entry.body.blocks
}))
]
}
@@ -23,16 +23,14 @@ function completed(conclusion: string): PRCheckDetail {
function gitLabJobs(...statuses: string[]): PRCheckDetail[] {
return gitLabPipelineJobsToPRChecks(
statuses.map(
(status, index): GitLabPipelineJob => ({
id: index,
name: status,
stage: 'deploy',
status,
webUrl: '',
duration: null
})
)
statuses.map((status, index): GitLabPipelineJob => ({
id: index,
name: status,
stage: 'deploy',
status,
webUrl: '',
duration: null
}))
)
}
@@ -6,16 +6,14 @@ import { useAppStore } from '@/store'
function cacheWithChildren(paths: string[]): DirCache {
return {
children: paths.map(
(path): TreeNode => ({
name: path.split(/[\\/]/).at(-1) ?? path,
path,
relativePath: path,
isDirectory: false,
depth: 0,
operationOwner: { kind: 'local' }
})
),
children: paths.map((path): TreeNode => ({
name: path.split(/[\\/]/).at(-1) ?? path,
path,
relativePath: path,
isDirectory: false,
depth: 0,
operationOwner: { kind: 'local' }
})),
loading: false,
operationOwner: { kind: 'local' }
}
@@ -24,11 +24,9 @@ beforeEach(() => {
Object.assign(window, {
api: {
developerPermissions: {
getStatus: vi.fn(
async (): Promise<DeveloperPermissionState[]> => [
{ id: 'full-disk-access', status: 'denied' }
]
),
getStatus: vi.fn(async (): Promise<DeveloperPermissionState[]> => [
{ id: 'full-disk-access', status: 'denied' }
]),
request: vi.fn(async ({ id }: { id: string }) => ({
id,
status: 'unknown',
@@ -90,12 +90,10 @@ export function McpConfigSection({ repo }: McpConfigSectionProps): React.JSX.Ele
)
const missingInspections = useMemo(
() =>
MCP_CONFIG_CANDIDATES.map(
(candidate): LoadedMcpConfigInspection => ({
...inspectMcpConfigContent(candidate, null),
absolutePath: joinPath(targetRootPath, candidate.relativePath)
})
),
MCP_CONFIG_CANDIDATES.map((candidate): LoadedMcpConfigInspection => ({
...inspectMcpConfigContent(candidate, null),
absolutePath: joinPath(targetRootPath, candidate.relativePath)
})),
[targetRootPath]
)
const serverCount = useMemo(() => countServers(configs), [configs])
@@ -3,81 +3,77 @@ import { createLocalizedCatalog } from '@/i18n/localized-catalog'
import { translate } from '@/i18n/i18n'
import { translateSearchKeyword } from './settings-search-keywords'
export const getLeftSidebarAppearanceEntry = createLocalizedCatalog(
(): SettingsSearchEntry => ({
title: translate(
'auto.components.settings.appearance.search.leftSidebarAppearance.title',
'Left Sidebar Appearance'
export const getLeftSidebarAppearanceEntry = createLocalizedCatalog((): SettingsSearchEntry => ({
title: translate(
'auto.components.settings.appearance.search.leftSidebarAppearance.title',
'Left Sidebar Appearance'
),
description: translate(
'auto.components.settings.appearance.search.leftSidebarAppearance.description',
'Make the left sidebar match your terminal, stay default, or use a tint.'
),
keywords: [
...translateSearchKeyword('auto.components.settings.appearance.search.5bff6a2ef0', 'sidebar'),
...translateSearchKeyword(
'auto.components.settings.appearance.search.leftSidebarAppearance.project',
'project'
),
description: translate(
'auto.components.settings.appearance.search.leftSidebarAppearance.description',
'Make the left sidebar match your terminal, stay default, or use a tint.'
...translateSearchKeyword(
'auto.components.settings.appearance.search.leftSidebarAppearance.terminal',
'terminal'
),
keywords: [
...translateSearchKeyword('auto.components.settings.appearance.search.5bff6a2ef0', 'sidebar'),
...translateSearchKeyword(
'auto.components.settings.appearance.search.leftSidebarAppearance.project',
'project'
),
...translateSearchKeyword(
'auto.components.settings.appearance.search.leftSidebarAppearance.terminal',
'terminal'
),
...translateSearchKeyword(
'auto.components.settings.appearance.search.leftSidebarAppearance.background',
'background'
),
...translateSearchKeyword(
'auto.components.settings.appearance.search.leftSidebarAppearance.tint',
'tint'
)
]
})
)
...translateSearchKeyword(
'auto.components.settings.appearance.search.leftSidebarAppearance.background',
'background'
),
...translateSearchKeyword(
'auto.components.settings.appearance.search.leftSidebarAppearance.tint',
'tint'
)
]
}))
export const getWorkspaceCardLayoutEntry = createLocalizedCatalog(
(): SettingsSearchEntry => ({
title: translate(
'auto.components.settings.appearance.search.workspaceCardLayout.title',
'Workspace Card Layout'
export const getWorkspaceCardLayoutEntry = createLocalizedCatalog((): SettingsSearchEntry => ({
title: translate(
'auto.components.settings.appearance.search.workspaceCardLayout.title',
'Workspace Card Layout'
),
description: translate(
'auto.components.settings.appearance.search.workspaceCardLayout.description',
'Workspace cards can use compact or detailed layouts.'
),
keywords: [
...translateSearchKeyword(
'auto.components.settings.appearance.search.workspaceCardLayout.compact',
'compact'
),
description: translate(
'auto.components.settings.appearance.search.workspaceCardLayout.description',
'Workspace cards can use compact or detailed layouts.'
...translateSearchKeyword(
'auto.components.settings.appearance.search.workspaceCardLayout.compactDisplay',
'compact display'
),
keywords: [
...translateSearchKeyword(
'auto.components.settings.appearance.search.workspaceCardLayout.compact',
'compact'
),
...translateSearchKeyword(
'auto.components.settings.appearance.search.workspaceCardLayout.compactDisplay',
'compact display'
),
...translateSearchKeyword(
'auto.components.settings.appearance.search.workspaceCardLayout.workspaceCards',
'workspace cards'
),
...translateSearchKeyword(
'auto.components.settings.appearance.search.workspaceCardLayout.worktreeCards',
'worktree cards'
),
...translateSearchKeyword('auto.components.settings.appearance.search.5bff6a2ef0', 'sidebar'),
...translateSearchKeyword(
'auto.components.settings.appearance.search.workspaceCardLayout.cardLayout',
'card layout'
),
...translateSearchKeyword(
'auto.components.settings.appearance.search.workspaceCardLayout.workspaceOptions',
'workspace options'
),
...translateSearchKeyword(
'auto.components.settings.appearance.search.workspaceCardLayout.detailed',
'detailed'
)
]
})
)
...translateSearchKeyword(
'auto.components.settings.appearance.search.workspaceCardLayout.workspaceCards',
'workspace cards'
),
...translateSearchKeyword(
'auto.components.settings.appearance.search.workspaceCardLayout.worktreeCards',
'worktree cards'
),
...translateSearchKeyword('auto.components.settings.appearance.search.5bff6a2ef0', 'sidebar'),
...translateSearchKeyword(
'auto.components.settings.appearance.search.workspaceCardLayout.cardLayout',
'card layout'
),
...translateSearchKeyword(
'auto.components.settings.appearance.search.workspaceCardLayout.workspaceOptions',
'workspace options'
),
...translateSearchKeyword(
'auto.components.settings.appearance.search.workspaceCardLayout.detailed',
'detailed'
)
]
}))
export const getShowPinnedWorktreesInGroupsEntry = createLocalizedCatalog(
(): SettingsSearchEntry => ({
@@ -3,36 +3,31 @@ import { translate } from '@/i18n/i18n'
import { translateSearchKeyword } from './settings-search-keywords'
import { createLocalizedCatalog } from '@/i18n/localized-catalog'
export const getEphemeralVmsSearchEntry = createLocalizedCatalog(
(): SettingsSearchEntry => ({
title: translate('auto.components.settings.ephemeralVms.search.cloudVmTitle', 'Cloud VM'),
description: translate(
'auto.components.settings.ephemeralVms.search.description',
'Learn how repo-owned recipes give each workspace its own on-demand, disposable environment.'
export const getEphemeralVmsSearchEntry = createLocalizedCatalog((): SettingsSearchEntry => ({
title: translate('auto.components.settings.ephemeralVms.search.cloudVmTitle', 'Cloud VM'),
description: translate(
'auto.components.settings.ephemeralVms.search.description',
'Learn how repo-owned recipes give each workspace its own on-demand, disposable environment.'
),
keywords: [
...translateSearchKeyword(
'auto.components.settings.experimental.search.0d24759f14',
'experimental'
),
keywords: [
...translateSearchKeyword(
'auto.components.settings.experimental.search.0d24759f14',
'experimental'
),
...translateSearchKeyword('auto.components.settings.ephemeralVms.search.keywordVm', 'vm'),
...translateSearchKeyword(
'auto.components.settings.ephemeralVms.search.keywordSandbox',
'sandbox'
),
...translateSearchKeyword(
'auto.components.settings.ephemeralVms.search.keywordCloud',
'cloud'
),
...translateSearchKeyword(
'auto.components.settings.ephemeralVms.search.keywordRecipe',
'recipe'
),
...translateSearchKeyword(
'auto.components.settings.ephemeralVms.search.keywordEphemeral',
'ephemeral'
)
],
targetSectionId: 'ephemeral-vms'
})
)
...translateSearchKeyword('auto.components.settings.ephemeralVms.search.keywordVm', 'vm'),
...translateSearchKeyword(
'auto.components.settings.ephemeralVms.search.keywordSandbox',
'sandbox'
),
...translateSearchKeyword('auto.components.settings.ephemeralVms.search.keywordCloud', 'cloud'),
...translateSearchKeyword(
'auto.components.settings.ephemeralVms.search.keywordRecipe',
'recipe'
),
...translateSearchKeyword(
'auto.components.settings.ephemeralVms.search.keywordEphemeral',
'ephemeral'
)
],
targetSectionId: 'ephemeral-vms'
}))
@@ -4,63 +4,46 @@ import { translate } from '@/i18n/i18n'
import { translateSearchKeyword } from './settings-search-keywords'
import { createLocalizedCatalog } from '@/i18n/localized-catalog'
export const getMobileOverviewSearchEntry = createLocalizedCatalog(
(): SettingsSearchEntry => ({
title: translate('auto.components.settings.mobile.settings.search.ffd52a96e4', 'Mobile'),
description: translate(
'auto.components.settings.mobile.settings.search.671eb4173c',
'Control terminals and agents from your phone.'
export const getMobileOverviewSearchEntry = createLocalizedCatalog((): SettingsSearchEntry => ({
title: translate('auto.components.settings.mobile.settings.search.ffd52a96e4', 'Mobile'),
description: translate(
'auto.components.settings.mobile.settings.search.671eb4173c',
'Control terminals and agents from your phone.'
),
keywords: [
...translateSearchKeyword(
'auto.components.settings.mobile.settings.search.f213400800',
'mobile'
),
keywords: [
...translateSearchKeyword(
'auto.components.settings.mobile.settings.search.f213400800',
'mobile'
),
...translateSearchKeyword(
'auto.components.settings.mobile.settings.search.f4ed142753',
'phone'
),
...translateSearchKeyword(
'auto.components.settings.mobile.settings.search.5d5af8e041',
'iphone'
),
...translateSearchKeyword(
'auto.components.settings.mobile.settings.search.cf2c93b479',
'pair'
),
...translateSearchKeyword('auto.components.settings.mobile.settings.search.87816d1c59', 'qr'),
...translateSearchKeyword(
'auto.components.settings.mobile.settings.search.59b1d75fd1',
'code'
),
...translateSearchKeyword(
'auto.components.settings.mobile.settings.search.0b7e585cb9',
'scan'
),
...translateSearchKeyword(
'auto.components.settings.mobile.settings.search.7e801801ac',
'remote'
),
...translateSearchKeyword(
'auto.components.settings.mobile.settings.search.e4f4daea0e',
'relay'
),
...translateSearchKeyword(
'auto.components.settings.mobile.settings.search.a7eececc1d',
'android'
),
...translateSearchKeyword(
'auto.components.settings.mobile.settings.search.6bfa001752',
'apk'
),
...translateSearchKeyword(
'auto.components.settings.mobile.settings.search.8d4ba0ef09',
'beta'
),
...translateSearchKeyword('auto.components.settings.mobile.settings.search.b730ff7049', 'app')
]
})
)
...translateSearchKeyword(
'auto.components.settings.mobile.settings.search.f4ed142753',
'phone'
),
...translateSearchKeyword(
'auto.components.settings.mobile.settings.search.5d5af8e041',
'iphone'
),
...translateSearchKeyword('auto.components.settings.mobile.settings.search.cf2c93b479', 'pair'),
...translateSearchKeyword('auto.components.settings.mobile.settings.search.87816d1c59', 'qr'),
...translateSearchKeyword('auto.components.settings.mobile.settings.search.59b1d75fd1', 'code'),
...translateSearchKeyword('auto.components.settings.mobile.settings.search.0b7e585cb9', 'scan'),
...translateSearchKeyword(
'auto.components.settings.mobile.settings.search.7e801801ac',
'remote'
),
...translateSearchKeyword(
'auto.components.settings.mobile.settings.search.e4f4daea0e',
'relay'
),
...translateSearchKeyword(
'auto.components.settings.mobile.settings.search.a7eececc1d',
'android'
),
...translateSearchKeyword('auto.components.settings.mobile.settings.search.6bfa001752', 'apk'),
...translateSearchKeyword('auto.components.settings.mobile.settings.search.8d4ba0ef09', 'beta'),
...translateSearchKeyword('auto.components.settings.mobile.settings.search.b730ff7049', 'app')
]
}))
export const getMobileSidebarShortcutSearchEntry = createLocalizedCatalog(
(): SettingsSearchEntry => ({
@@ -145,13 +145,11 @@ export function rankSettingsSearchItems<T>(
}
return items
.map(
(item, index): SettingsSearchRankCandidate<T> => ({
item,
index,
score: scoreSettingsSearch(query, getEntries(item))
})
)
.map((item, index): SettingsSearchRankCandidate<T> => ({
item,
index,
score: scoreSettingsSearch(query, getEntries(item))
}))
.filter((candidate) => candidate.score > SETTINGS_SEARCH_NO_MATCH_SCORE)
.sort((a, b) => b.score - a.score || a.index - b.index)
.map(({ item, score }) => ({ item, score }))
@@ -211,15 +211,13 @@ export const getLinearDisplayProperties = createLocalizedCatalog(
}
)
export const getLinearPriorityLabels = createLocalizedCatalog(
(): Record<number, string> => ({
0: translate('auto.components.TaskPage.713179dfdc', 'No priority'),
1: translate('auto.components.TaskPage.f373ab1a4f', 'Urgent'),
2: translate('auto.components.TaskPage.345b169f1f', 'High'),
3: translate('auto.components.TaskPage.7fd59c18d8', 'Medium'),
4: translate('auto.components.TaskPage.69591944e7', 'Low')
})
)
export const getLinearPriorityLabels = createLocalizedCatalog((): Record<number, string> => ({
0: translate('auto.components.TaskPage.713179dfdc', 'No priority'),
1: translate('auto.components.TaskPage.f373ab1a4f', 'Urgent'),
2: translate('auto.components.TaskPage.345b169f1f', 'High'),
3: translate('auto.components.TaskPage.7fd59c18d8', 'Medium'),
4: translate('auto.components.TaskPage.69591944e7', 'Low')
}))
export function getLinearPriorityLabel(priority: number): string {
return getLinearPriorityLabels()[priority] ?? `P${priority}`
@@ -82,8 +82,8 @@ export function useTaskPageGitHubSourceBanners({
// Hard guarantee (K4): always overlay pending after reconcile so list
// fetch clobbers never paint unprotected coordinator fields.
setPages((current) =>
reconcileTaskPagePagesWithWorkItemsCache(current, selectedWorkItemsCacheEntries).map((page) =>
page ? (overlayPendingOnTaskPagePages([page])[0] ?? []) : null
reconcileTaskPagePagesWithWorkItemsCache(current, selectedWorkItemsCacheEntries).map(
(page) => (page ? (overlayPendingOnTaskPagePages([page])[0] ?? []) : null)
)
)
}, [githubMode, selectedWorkItemsCacheEntries, taskSource, setPages])
@@ -21,10 +21,7 @@ import {
selectColdParkedTerminalTabs
} from './terminal-hidden-view-parking'
import type { ParkVerdictFlipRecord } from './terminal-park-verdict-flip-telemetry'
import {
haveSameTerminalTabIds,
useTerminalParkVerdictPin
} from './use-terminal-park-verdict-pin'
import { haveSameTerminalTabIds, useTerminalParkVerdictPin } from './use-terminal-park-verdict-pin'
import { withholdUnparkableTerminalTabs } from './terminal-cold-park-withheld-tabs'
import { getTerminalParkingPolicyOverrides } from './terminal-parking-e2e-overrides'
import {
@@ -225,9 +225,8 @@ describe('createRuntimeClientEventsSync', () => {
it('backs off exponentially with a cap while an environment keeps failing', async () => {
vi.useFakeTimers()
try {
const subscribe = vi.fn(
(): Promise<RuntimeClientEventSubscriptionHandle> =>
Promise.reject(new Error('unreachable'))
const subscribe = vi.fn((): Promise<RuntimeClientEventSubscriptionHandle> =>
Promise.reject(new Error('unreachable'))
)
const sync = createRuntimeClientEventsSync({
getDesiredEnvironmentIds: () => ['A'],
@@ -266,9 +265,8 @@ describe('createRuntimeClientEventsSync', () => {
it('applies jitter below the full backoff delay', async () => {
vi.useFakeTimers()
try {
const subscribe = vi.fn(
(): Promise<RuntimeClientEventSubscriptionHandle> =>
Promise.reject(new Error('unreachable'))
const subscribe = vi.fn((): Promise<RuntimeClientEventSubscriptionHandle> =>
Promise.reject(new Error('unreachable'))
)
const sync = createRuntimeClientEventsSync({
getDesiredEnvironmentIds: () => ['A'],
@@ -344,9 +342,8 @@ describe('createRuntimeClientEventsSync', () => {
vi.useFakeTimers()
try {
let subscriptionKey = 'A:1'
const subscribe = vi.fn(
(): Promise<RuntimeClientEventSubscriptionHandle> =>
Promise.reject(new Error('unreachable'))
const subscribe = vi.fn((): Promise<RuntimeClientEventSubscriptionHandle> =>
Promise.reject(new Error('unreachable'))
)
const sync = createRuntimeClientEventsSync({
getDesiredEnvironmentIds: () => ['A'],
@@ -379,9 +376,8 @@ describe('createRuntimeClientEventsSync', () => {
it('an external sync retries a waiting environment immediately (recovery path)', async () => {
vi.useFakeTimers()
try {
const subscribe = vi.fn(
(): Promise<RuntimeClientEventSubscriptionHandle> =>
Promise.reject(new Error('unreachable'))
const subscribe = vi.fn((): Promise<RuntimeClientEventSubscriptionHandle> =>
Promise.reject(new Error('unreachable'))
)
const sync = createRuntimeClientEventsSync({
getDesiredEnvironmentIds: () => ['A'],
@@ -107,18 +107,16 @@ describe('useIpcEvents agent status snapshot integration', () => {
expandedLeafId: null
}
}
const snapshot = cases.map(
(entry, index): AgentStatusSetData => ({
paneKey: makePaneKey(entry.tabId, entry.leafId),
worktreeId: entry.payloadWorktreeId,
...(entry.connectionId ? { connectionId: entry.connectionId } : {}),
state: 'working',
prompt: `routing case ${index}`,
agentType: 'claude',
receivedAt: 1_700_000_001_000 + index,
stateStartedAt: 1_700_000_001_000 + index
})
)
const snapshot = cases.map((entry, index): AgentStatusSetData => ({
paneKey: makePaneKey(entry.tabId, entry.leafId),
worktreeId: entry.payloadWorktreeId,
...(entry.connectionId ? { connectionId: entry.connectionId } : {}),
state: 'working',
prompt: `routing case ${index}`,
agentType: 'claude',
receivedAt: 1_700_000_001_000 + index,
stateStartedAt: 1_700_000_001_000 + index
}))
const localRepo = { ...TEST_REPO, id: 'repo-routing-local', connectionId: null }
const sshRepo = { ...TEST_REPO, id: 'repo-routing-ssh', connectionId: 'ssh-live' }
const store = createTestStore()
@@ -486,17 +486,15 @@ describe('useIpcEvents agent status snapshot integration', () => {
return tabId
}
})
const snapshot = leafIds.map(
(leafId, index): AgentStatusSetData => ({
paneKey: makePaneKey(tabId, leafId),
worktreeId,
state: 'working',
prompt: `indexed prompt ${index}`,
agentType: 'claude',
receivedAt: 1_700_000_000_000 + index,
stateStartedAt: 1_700_000_000_000 + index
})
)
const snapshot = leafIds.map((leafId, index): AgentStatusSetData => ({
paneKey: makePaneKey(tabId, leafId),
worktreeId,
state: 'working',
prompt: `indexed prompt ${index}`,
agentType: 'claude',
receivedAt: 1_700_000_000_000 + index,
stateStartedAt: 1_700_000_000_000 + index
}))
let resolveSnapshot!: (entries: AgentStatusSetData[]) => void
const getSnapshot = vi.fn(
() =>
@@ -64,14 +64,12 @@ function transport(
getUpdaterStatus: vi.fn(async () => availableSnapshot),
check: vi.fn(async () => availableSnapshot),
download: vi.fn(async () => availableSnapshot),
install: vi.fn(
async (): Promise<RemoteServerUpdateInstallResult> => ({
accepted: true,
fromVersion: '1.4.0',
targetVersion: '1.5.0',
runtimeId: 'runtime-old'
})
),
install: vi.fn(async (): Promise<RemoteServerUpdateInstallResult> => ({
accepted: true,
fromVersion: '1.4.0',
targetVersion: '1.5.0',
runtimeId: 'runtime-old'
})),
wait: vi.fn(async (milliseconds) => {
clock += milliseconds
}),
+10 -10
View File
@@ -1326,8 +1326,8 @@ export const createBrowserSlice: StateCreator<AppState, [], [], BrowserSlice> =
},
browserTabsByWorktree: {
...s.browserTabsByWorktree,
[workspace.worktreeId]: (s.browserTabsByWorktree[workspace.worktreeId] ?? []).map((tab) =>
tab.id === workspaceId ? nextWorkspace : tab
[workspace.worktreeId]: (s.browserTabsByWorktree[workspace.worktreeId] ?? []).map(
(tab) => (tab.id === workspaceId ? nextWorkspace : tab)
)
},
pendingAddressBarFocusByPageId: shouldFocusAddressBar
@@ -1409,8 +1409,8 @@ export const createBrowserSlice: StateCreator<AppState, [], [], BrowserSlice> =
},
browserTabsByWorktree: {
...s.browserTabsByWorktree,
[workspace.worktreeId]: (s.browserTabsByWorktree[workspace.worktreeId] ?? []).map((tab) =>
tab.id === workspace.id ? nextWorkspace : tab
[workspace.worktreeId]: (s.browserTabsByWorktree[workspace.worktreeId] ?? []).map(
(tab) => (tab.id === workspace.id ? nextWorkspace : tab)
)
},
recentlyClosedBrowserPagesByWorkspace: {
@@ -1509,8 +1509,8 @@ export const createBrowserSlice: StateCreator<AppState, [], [], BrowserSlice> =
return {
browserTabsByWorktree: {
...s.browserTabsByWorktree,
[workspace.worktreeId]: (s.browserTabsByWorktree[workspace.worktreeId] ?? []).map((tab) =>
tab.id === workspaceId ? nextWorkspace : tab
[workspace.worktreeId]: (s.browserTabsByWorktree[workspace.worktreeId] ?? []).map(
(tab) => (tab.id === workspaceId ? nextWorkspace : tab)
)
}
}
@@ -1707,8 +1707,8 @@ export const createBrowserSlice: StateCreator<AppState, [], [], BrowserSlice> =
if (!browserWorkspaceMirrorFieldsEqual(workspace, nextWorkspace)) {
nextState.browserTabsByWorktree = {
...s.browserTabsByWorktree,
[workspace.worktreeId]: (s.browserTabsByWorktree[workspace.worktreeId] ?? []).map((tab) =>
tab.id === workspace.id ? nextWorkspace : tab
[workspace.worktreeId]: (s.browserTabsByWorktree[workspace.worktreeId] ?? []).map(
(tab) => (tab.id === workspace.id ? nextWorkspace : tab)
)
}
}
@@ -1804,8 +1804,8 @@ export const createBrowserSlice: StateCreator<AppState, [], [], BrowserSlice> =
},
browserTabsByWorktree: {
...s.browserTabsByWorktree,
[workspace.worktreeId]: (s.browserTabsByWorktree[workspace.worktreeId] ?? []).map((tab) =>
tab.id === workspace.id ? nextWorkspace : tab
[workspace.worktreeId]: (s.browserTabsByWorktree[workspace.worktreeId] ?? []).map(
(tab) => (tab.id === workspace.id ? nextWorkspace : tab)
)
},
...(shouldClearAnnotations
@@ -49,7 +49,9 @@ export async function listWorktreeLineageForRuntime(
lineage?: Record<string, WorktreeLineage>
workspaceLineage?: Record<string, WorkspaceLineage>
}
const normalizeLineageResponse = (value: Record<string, WorktreeLineage> | LineageListResponse) =>
const normalizeLineageResponse = (
value: Record<string, WorktreeLineage> | LineageListResponse
) =>
Object.hasOwn(value, 'lineage') || Object.hasOwn(value, 'workspaceLineage')
? {
worktreeLineageById: (value as LineageListResponse).lineage ?? {},
@@ -528,14 +528,13 @@ describe('web runtime environment identity', () => {
it('replaces API closures on reinstall while retaining the runtime client singleton', async () => {
let clientCount = 0
const call = vi.fn(
(method: string): Promise<RuntimeRpcResponse<unknown>> =>
Promise.resolve({
id: method,
ok: true,
result: { method },
_meta: { runtimeId: 'runtime-a' }
})
const call = vi.fn((method: string): Promise<RuntimeRpcResponse<unknown>> =>
Promise.resolve({
id: method,
ok: true,
result: { method },
_meta: { runtimeId: 'runtime-a' }
})
)
vi.doMock('./web-runtime-client', () => ({
WebRuntimeClient: class {
@@ -24,11 +24,10 @@ describe('mapSettledWithConcurrency', () => {
expect(peak).toBe(limit)
expect(results).toEqual(
items.map(
(item): PromiseSettledResult<string> =>
item % 97 === 0
? { status: 'rejected', reason: `rejected-${item}` }
: { status: 'fulfilled', value: `fulfilled-${item}` }
items.map((item): PromiseSettledResult<string> =>
item % 97 === 0
? { status: 'rejected', reason: `rejected-${item}` }
: { status: 'fulfilled', value: `fulfilled-${item}` }
)
)
})
+1 -1
View File
@@ -28,7 +28,7 @@ function jpegWithMetadata(
extraSegments = 0
): Buffer {
const parts = [Buffer.from([0xff, 0xd8])]
for (let written = 0; written < metadataBytes; ) {
for (let written = 0; written < metadataBytes;) {
// A JPEG segment length field is 16 bits, so real files chain many segments to carry a profile.
const size = Math.min(65_533, metadataBytes - written)
const header = Buffer.alloc(4)
+14 -20
View File
@@ -57,12 +57,10 @@ export async function getWorktreeTabs(
}
const state = store.getState()
return (state.tabsByWorktree[worktreeId] ?? []).map(
(tab): TerminalTabSummary => ({
id: tab.id,
title: tab.customTitle || tab.title
})
)
return (state.tabsByWorktree[worktreeId] ?? []).map((tab): TerminalTabSummary => ({
id: tab.id,
title: tab.customTitle || tab.title
}))
}, worktreeId)
}
@@ -116,13 +114,11 @@ export async function getBrowserTabs(
}
const state = store.getState()
return (state.browserTabsByWorktree[worktreeId] ?? []).map(
(tab): BrowserTabSummary => ({
id: tab.id,
url: tab.url,
title: tab.title
})
)
return (state.browserTabsByWorktree[worktreeId] ?? []).map((tab): BrowserTabSummary => ({
id: tab.id,
url: tab.url,
title: tab.title
}))
}, worktreeId)
}
@@ -140,13 +136,11 @@ export async function getOpenFiles(
const state = store.getState()
return state.openFiles
.filter((file) => file.worktreeId === worktreeId)
.map(
(file): ExplorerFileSummary => ({
id: file.id,
filePath: file.filePath,
relativePath: file.relativePath
})
)
.map((file): ExplorerFileSummary => ({
id: file.id,
filePath: file.filePath,
relativePath: file.relativePath
}))
}, worktreeId)
}
@@ -166,7 +166,7 @@ export async function replayRecordedImeDomTrace(
const samples: ReplayedCompositionSample[] = []
let compositionOpen = false
for (let index = 0; index < trace.dom.length; ) {
for (let index = 0; index < trace.dom.length;) {
const group = nextRecordedEventGroup(trace.dom, index)
const recorded = group[0]
await dispatchRecordedEvents(page, group)