chore(quality): ratchet Oxlint, React Doctor, and Zustand performance (#11034)
* chore(quality): ratchet lint and Zustand performance * fix(ci): stabilize React peer lock snapshot * fix(ci): isolate PR diff and React Doctor CLI
This commit is contained in:
parent
9a8e21a47e
commit
12ef12c55b
|
|
@ -24,6 +24,7 @@ jobs:
|
|||
- name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
fetch-depth: 0
|
||||
persist-credentials: false
|
||||
|
||||
- uses: ./.github/actions/install-node-dependencies
|
||||
|
|
@ -34,6 +35,15 @@ jobs:
|
|||
- name: Check switch exhaustiveness
|
||||
run: pnpm run lint:switch-exhaustiveness
|
||||
|
||||
- name: Enforce changed-code quality
|
||||
run: pnpm run check:code-quality:changed -- "${{ github.event.pull_request.base.sha }}"
|
||||
|
||||
- name: Enforce React Doctor on changed lines
|
||||
run: pnpm run check:react-doctor:changed -- "${{ github.event.pull_request.base.sha }}"
|
||||
|
||||
- name: Check Zustand selector fan-out budget
|
||||
run: pnpm run check:zustand-selector-fanout
|
||||
|
||||
- name: Check styled scrollbars
|
||||
run: pnpm check:styled-scrollbars
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,12 @@
|
|||
{
|
||||
"$schema": "./node_modules/oxlint/configuration_schema.json",
|
||||
"plugins": ["typescript", "react", "react-hooks", "react-perf", "unicorn"],
|
||||
"jsPlugins": [
|
||||
{
|
||||
"name": "mobile-pairing",
|
||||
"specifier": "./config/oxlint-plugins/mobile-pairing-qrcode-import.mjs"
|
||||
}
|
||||
],
|
||||
"categories": {
|
||||
"correctness": "error"
|
||||
},
|
||||
|
|
@ -57,15 +63,11 @@
|
|||
"name": "@linear/sdk",
|
||||
"allowTypeImports": true,
|
||||
"message": "Value-importing @linear/sdk hoists its ~2.6MB CJS bundle into the eager top-level require block and defeats the lazy loader. Use `import type` plus loadLinearSdk() from src/main/linear/linear-sdk.ts."
|
||||
},
|
||||
{
|
||||
"name": "qrcode",
|
||||
"allowTypeImports": true,
|
||||
"message": "qrcode is only reachable from mobile pairing; a static import parses it at launch for everyone. Use `import type` plus `await import('qrcode')` at the call site."
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"mobile-pairing/no-eager-qrcode-import": "error",
|
||||
"no-useless-return": "error",
|
||||
"prefer-template": "error",
|
||||
"unicorn/consistent-empty-array-spread": "error",
|
||||
|
|
|
|||
|
|
@ -0,0 +1,22 @@
|
|||
{
|
||||
"$schema": "../node_modules/oxlint/configuration_schema.json",
|
||||
"plugins": ["typescript"],
|
||||
"categories": {
|
||||
"correctness": "off",
|
||||
"suspicious": "off",
|
||||
"pedantic": "off",
|
||||
"perf": "off",
|
||||
"style": "off",
|
||||
"restriction": "off",
|
||||
"nursery": "off"
|
||||
},
|
||||
"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"
|
||||
},
|
||||
"ignorePatterns": ["**/node_modules", "**/dist", "**/out"]
|
||||
}
|
||||
|
|
@ -0,0 +1,71 @@
|
|||
{
|
||||
"$schema": "../node_modules/oxlint/configuration_schema.json",
|
||||
"plugins": ["import", "jsx-a11y", "promise", "react", "react-hooks", "typescript", "vitest"],
|
||||
"categories": {
|
||||
"correctness": "off",
|
||||
"suspicious": "off",
|
||||
"pedantic": "off",
|
||||
"perf": "off",
|
||||
"style": "off",
|
||||
"restriction": "off",
|
||||
"nursery": "off"
|
||||
},
|
||||
"options": {
|
||||
"reportUnusedDisableDirectives": "warn"
|
||||
},
|
||||
"jsPlugins": [
|
||||
{
|
||||
"name": "app-store-performance",
|
||||
"specifier": "./oxlint-plugins/app-store-performance.mjs"
|
||||
}
|
||||
],
|
||||
"rules": {
|
||||
"app-store-performance/require-selector": "warn",
|
||||
"app-store-performance/no-identity-selector": "warn",
|
||||
"app-store-performance/no-fresh-selector-result": "warn",
|
||||
"import/export": "warn",
|
||||
"import/named": "warn",
|
||||
"import/namespace": "warn",
|
||||
"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"
|
||||
},
|
||||
"overrides": [
|
||||
{
|
||||
"files": ["src/renderer/src/**/*.{ts,tsx}"],
|
||||
"rules": {
|
||||
"jsx-a11y/alt-text": "warn",
|
||||
"jsx-a11y/anchor-has-content": "warn",
|
||||
"jsx-a11y/aria-props": "warn",
|
||||
"jsx-a11y/aria-role": "warn",
|
||||
"jsx-a11y/click-events-have-key-events": "warn"
|
||||
}
|
||||
},
|
||||
{
|
||||
"files": ["**/*.{test,spec}.{ts,tsx}", "tests/**/*.{ts,tsx}"],
|
||||
"rules": {
|
||||
"vitest/no-conditional-tests": "warn",
|
||||
"vitest/no-focused-tests": "warn",
|
||||
"vitest/no-identical-title": "warn",
|
||||
"vitest/valid-expect": "warn",
|
||||
"vitest/valid-title": "warn"
|
||||
}
|
||||
},
|
||||
{
|
||||
"files": ["mobile/**/*.{ts,tsx}"],
|
||||
"rules": {
|
||||
"react-hooks/exhaustive-deps": "warn"
|
||||
}
|
||||
}
|
||||
],
|
||||
"ignorePatterns": ["**/node_modules", "**/dist", "**/out"]
|
||||
}
|
||||
|
|
@ -0,0 +1,244 @@
|
|||
const ALLOCATING_METHODS = new Set([
|
||||
'filter',
|
||||
'flat',
|
||||
'flatMap',
|
||||
'map',
|
||||
'toReversed',
|
||||
'toSorted',
|
||||
'toSpliced',
|
||||
'with'
|
||||
])
|
||||
|
||||
function identifierName(node) {
|
||||
return node?.type === 'Identifier' ? node.name : null
|
||||
}
|
||||
|
||||
function propertyName(node) {
|
||||
if (node?.type !== 'MemberExpression') {
|
||||
return null
|
||||
}
|
||||
if (!node.computed) {
|
||||
return identifierName(node.property)
|
||||
}
|
||||
return node.property?.type === 'Literal' && typeof node.property.value === 'string'
|
||||
? node.property.value
|
||||
: null
|
||||
}
|
||||
|
||||
function returnedExpressions(selector) {
|
||||
if (selector?.type !== 'ArrowFunctionExpression' && selector?.type !== 'FunctionExpression') {
|
||||
return []
|
||||
}
|
||||
if (selector.body.type !== 'BlockStatement') {
|
||||
return [selector.body]
|
||||
}
|
||||
const expressions = []
|
||||
const visit = (node) => {
|
||||
if (!node || typeof node !== 'object') {
|
||||
return
|
||||
}
|
||||
if (
|
||||
node !== selector.body &&
|
||||
['ArrowFunctionExpression', 'FunctionDeclaration', 'FunctionExpression'].includes(node.type)
|
||||
) {
|
||||
return
|
||||
}
|
||||
if (node.type === 'ReturnStatement') {
|
||||
if (node.argument) {
|
||||
expressions.push(node.argument)
|
||||
}
|
||||
return
|
||||
}
|
||||
for (const [key, child] of Object.entries(node)) {
|
||||
if (key === 'parent') {
|
||||
continue
|
||||
}
|
||||
if (Array.isArray(child)) {
|
||||
child.forEach(visit)
|
||||
} else {
|
||||
visit(child)
|
||||
}
|
||||
}
|
||||
}
|
||||
visit(selector.body)
|
||||
return expressions
|
||||
}
|
||||
|
||||
function unwrapShallowSelector(selector, shallowHooks) {
|
||||
if (
|
||||
selector?.type === 'CallExpression' &&
|
||||
selector.callee.type === 'Identifier' &&
|
||||
shallowHooks.has(selector.callee.name)
|
||||
) {
|
||||
return { selector: selector.arguments[0], shallow: true }
|
||||
}
|
||||
return { selector, shallow: false }
|
||||
}
|
||||
|
||||
function isIdentitySelector(selector) {
|
||||
if (selector?.type !== 'ArrowFunctionExpression' && selector?.type !== 'FunctionExpression') {
|
||||
return false
|
||||
}
|
||||
const parameter = selector.params[0]
|
||||
if (parameter?.type !== 'Identifier') {
|
||||
return false
|
||||
}
|
||||
return returnedExpressions(selector).some(
|
||||
(expression) => expression.type === 'Identifier' && expression.name === parameter.name
|
||||
)
|
||||
}
|
||||
|
||||
function isAllocatingExpression(expression) {
|
||||
if (expression?.type === 'ConditionalExpression') {
|
||||
return (
|
||||
isAllocatingExpression(expression.consequent) || isAllocatingExpression(expression.alternate)
|
||||
)
|
||||
}
|
||||
if (expression?.type === 'LogicalExpression') {
|
||||
return isAllocatingExpression(expression.left) || isAllocatingExpression(expression.right)
|
||||
}
|
||||
if (
|
||||
expression?.type === 'ArrayExpression' ||
|
||||
expression?.type === 'ObjectExpression' ||
|
||||
expression?.type === 'NewExpression'
|
||||
) {
|
||||
return true
|
||||
}
|
||||
if (expression?.type !== 'CallExpression') {
|
||||
return false
|
||||
}
|
||||
const method = propertyName(expression.callee)
|
||||
if (method && ALLOCATING_METHODS.has(method)) {
|
||||
return true
|
||||
}
|
||||
const callee = expression.callee
|
||||
return (
|
||||
callee.type === 'MemberExpression' &&
|
||||
identifierName(callee.object) === 'Object' &&
|
||||
['assign', 'create', 'entries', 'fromEntries', 'keys', 'values'].includes(propertyName(callee))
|
||||
)
|
||||
}
|
||||
|
||||
function importedLocalName(specifier, importedName) {
|
||||
if (specifier.type !== 'ImportSpecifier' || identifierName(specifier.imported) !== importedName) {
|
||||
return null
|
||||
}
|
||||
return identifierName(specifier.local)
|
||||
}
|
||||
|
||||
function createRuleState() {
|
||||
return {
|
||||
appStoreHooks: new Set(),
|
||||
shallowHooks: new Set()
|
||||
}
|
||||
}
|
||||
|
||||
function recordImports(node, state) {
|
||||
if (node.source?.value === 'zustand/react/shallow') {
|
||||
for (const specifier of node.specifiers) {
|
||||
const localName = importedLocalName(specifier, 'useShallow')
|
||||
if (localName) {
|
||||
state.shallowHooks.add(localName)
|
||||
}
|
||||
}
|
||||
}
|
||||
for (const specifier of node.specifiers) {
|
||||
const localName = importedLocalName(specifier, 'useAppStore')
|
||||
if (localName) {
|
||||
state.appStoreHooks.add(localName)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function isAppStoreCall(node, state) {
|
||||
return (
|
||||
node.callee.type === 'Identifier' &&
|
||||
state.appStoreHooks.has(node.callee.name) &&
|
||||
node.optional !== true
|
||||
)
|
||||
}
|
||||
|
||||
function requireSelectorRule() {
|
||||
const state = createRuleState()
|
||||
return {
|
||||
ImportDeclaration(node) {
|
||||
recordImports(node, state)
|
||||
},
|
||||
CallExpression(node) {
|
||||
if (isAppStoreCall(node, state) && node.arguments.length === 0) {
|
||||
this.report({
|
||||
node,
|
||||
message:
|
||||
'Pass a selector to useAppStore so the component does not rerender for every store write.'
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function noIdentitySelectorRule() {
|
||||
const state = createRuleState()
|
||||
return {
|
||||
ImportDeclaration(node) {
|
||||
recordImports(node, state)
|
||||
},
|
||||
CallExpression(node) {
|
||||
if (!isAppStoreCall(node, state)) {
|
||||
return
|
||||
}
|
||||
const { selector } = unwrapShallowSelector(node.arguments[0], state.shallowHooks)
|
||||
if (isIdentitySelector(selector)) {
|
||||
this.report({
|
||||
node: selector,
|
||||
message:
|
||||
'Select the smallest required fields instead of subscribing to the entire app store.'
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function noFreshSelectorResultRule() {
|
||||
const state = createRuleState()
|
||||
return {
|
||||
ImportDeclaration(node) {
|
||||
recordImports(node, state)
|
||||
},
|
||||
CallExpression(node) {
|
||||
if (!isAppStoreCall(node, state)) {
|
||||
return
|
||||
}
|
||||
const { selector, shallow } = unwrapShallowSelector(node.arguments[0], state.shallowHooks)
|
||||
if (shallow) {
|
||||
return
|
||||
}
|
||||
const freshResult = returnedExpressions(selector).find(isAllocatingExpression)
|
||||
if (freshResult) {
|
||||
this.report({
|
||||
node: freshResult,
|
||||
message:
|
||||
'This selector returns a fresh reference on every store write; select a stable field, cache the result, or use useShallow.'
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function bindContext(createVisitors) {
|
||||
return (context) => {
|
||||
const visitors = createVisitors()
|
||||
for (const [nodeType, visit] of Object.entries(visitors)) {
|
||||
visitors[nodeType] = visit.bind(context)
|
||||
}
|
||||
return visitors
|
||||
}
|
||||
}
|
||||
|
||||
export default {
|
||||
meta: { name: 'app-store-performance' },
|
||||
rules: {
|
||||
'require-selector': { create: bindContext(requireSelectorRule) },
|
||||
'no-identity-selector': { create: bindContext(noIdentitySelectorRule) },
|
||||
'no-fresh-selector-result': { create: bindContext(noFreshSelectorResultRule) }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
const MESSAGE =
|
||||
"qrcode is only reachable from mobile pairing. Use `import type` plus `await import('qrcode')` so startup does not parse its bundle."
|
||||
|
||||
function hasRuntimeImport(node) {
|
||||
if (node.importKind === 'type') {
|
||||
return false
|
||||
}
|
||||
return (
|
||||
node.specifiers.length === 0 ||
|
||||
node.specifiers.some((specifier) => specifier.importKind !== 'type')
|
||||
)
|
||||
}
|
||||
|
||||
export default {
|
||||
meta: { name: 'mobile-pairing' },
|
||||
rules: {
|
||||
'no-eager-qrcode-import': {
|
||||
create(context) {
|
||||
return {
|
||||
ImportDeclaration(node) {
|
||||
if (node.source?.value === 'qrcode' && hasRuntimeImport(node)) {
|
||||
context.report({ node, message: MESSAGE })
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -12,9 +12,18 @@
|
|||
},
|
||||
"jsPlugins": [{ "name": "react-doctor", "specifier": "oxlint-plugin-react-doctor" }],
|
||||
"rules": {
|
||||
"react-doctor/effect-needs-cleanup": "warn",
|
||||
"react-doctor/no-array-index-as-key": "warn",
|
||||
"react-doctor/no-adjust-state-on-prop-change": "warn",
|
||||
"react-doctor/no-create-store-in-render": "warn",
|
||||
"react-doctor/no-derived-state-effect": "warn",
|
||||
"react-doctor/no-initialize-state": "warn"
|
||||
"react-doctor/no-initialize-state": "warn",
|
||||
"react-doctor/no-side-effect-in-state-updater-function": "warn",
|
||||
"react-doctor/no-unstable-nested-components": "warn",
|
||||
"react-doctor/zustand-no-fresh-selector-result": "warn",
|
||||
"react-doctor/zustand-no-get-during-initialization": "warn",
|
||||
"react-doctor/zustand-no-mutating-state": "warn",
|
||||
"react-doctor/zustand-no-whole-store-destructure": "warn"
|
||||
},
|
||||
"ignorePatterns": ["**/node_modules", "**/dist", "**/out"]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,76 @@
|
|||
import { spawnSync } from 'node:child_process'
|
||||
import { mkdtempSync, writeFileSync } from 'node:fs'
|
||||
import { tmpdir } from 'node:os'
|
||||
import path from 'node:path'
|
||||
import { describe, expect, it } from 'vitest'
|
||||
|
||||
const pluginPath = path.resolve('config/oxlint-plugins/app-store-performance.mjs')
|
||||
const oxlintPath = path.resolve(
|
||||
process.platform === 'win32' ? 'node_modules/.bin/oxlint.cmd' : 'node_modules/.bin/oxlint'
|
||||
)
|
||||
|
||||
function lintSource(source) {
|
||||
const directory = mkdtempSync(path.join(tmpdir(), 'orca-app-store-lint-'))
|
||||
const sourcePath = path.join(directory, 'sample.tsx')
|
||||
const configPath = path.join(directory, 'oxlint.json')
|
||||
writeFileSync(sourcePath, source)
|
||||
writeFileSync(
|
||||
configPath,
|
||||
JSON.stringify({
|
||||
categories: {
|
||||
correctness: 'off'
|
||||
},
|
||||
jsPlugins: [{ name: 'app-store-performance', specifier: pluginPath }],
|
||||
rules: {
|
||||
'app-store-performance/require-selector': 'warn',
|
||||
'app-store-performance/no-identity-selector': 'warn',
|
||||
'app-store-performance/no-fresh-selector-result': 'warn'
|
||||
}
|
||||
})
|
||||
)
|
||||
const result = spawnSync(oxlintPath, ['--config', configPath, '--format', 'json', sourcePath], {
|
||||
encoding: 'utf8'
|
||||
})
|
||||
if (result.error) {
|
||||
throw result.error
|
||||
}
|
||||
expect(result.status).toBe(0)
|
||||
return JSON.parse(result.stdout).diagnostics
|
||||
}
|
||||
|
||||
describe('app store performance Oxlint plugin', () => {
|
||||
it('reports whole-store and fresh-reference subscriptions', () => {
|
||||
const diagnostics = lintSource(`
|
||||
import { useAppStore as useStore } from '@/store'
|
||||
const WholeStore = () => useStore()
|
||||
const Identity = () => useStore((state) => state)
|
||||
const Fresh = () => useStore((state) => ({ active: state.active }))
|
||||
const Conditional = () => useStore((state) => state.active ? state.items : [])
|
||||
const Nested = () => useStore((state) => {
|
||||
if (state.active) return state.items.filter(Boolean)
|
||||
return state.items
|
||||
})
|
||||
`)
|
||||
|
||||
expect(diagnostics.map((diagnostic) => diagnostic.code)).toEqual([
|
||||
'app-store-performance(require-selector)',
|
||||
'app-store-performance(no-identity-selector)',
|
||||
'app-store-performance(no-fresh-selector-result)',
|
||||
'app-store-performance(no-fresh-selector-result)',
|
||||
'app-store-performance(no-fresh-selector-result)'
|
||||
])
|
||||
})
|
||||
|
||||
it('allows focused, cached, and useShallow selectors', () => {
|
||||
const diagnostics = lintSource(`
|
||||
import { useAppStore } from '@/store'
|
||||
import { useShallow as shallow } from 'zustand/react/shallow'
|
||||
const selectActive = (state) => state.active
|
||||
const Focused = () => useAppStore(selectActive)
|
||||
const Cached = () => useAppStore((state) => state.cachedProjection)
|
||||
const Shallow = () => useAppStore(shallow((state) => ({ active: state.active })))
|
||||
`)
|
||||
|
||||
expect(diagnostics).toEqual([])
|
||||
})
|
||||
})
|
||||
|
|
@ -0,0 +1,225 @@
|
|||
import { execFileSync, spawnSync } from 'node:child_process'
|
||||
import { existsSync, readFileSync } from 'node:fs'
|
||||
import path from 'node:path'
|
||||
import process from 'node:process'
|
||||
import { pathToFileURL } from 'node:url'
|
||||
import { resolvePullRequestDiffBase } from './git-pull-request-diff-base.mjs'
|
||||
|
||||
const SOURCE_FILE_PATTERN = /\.(?:[cm]?[jt]sx?)$/
|
||||
const OXLINT_SCANS = [
|
||||
{
|
||||
label: 'code quality',
|
||||
args: [
|
||||
'--config',
|
||||
'config/oxlint-code-quality.json',
|
||||
'--report-unused-disable-directives-severity',
|
||||
'warn'
|
||||
]
|
||||
},
|
||||
{
|
||||
label: 'type-aware code quality',
|
||||
args: ['--type-aware', '--config', 'config/oxlint-code-quality-type-aware.json']
|
||||
},
|
||||
{
|
||||
label: 'React Doctor',
|
||||
args: ['--config', 'config/oxlint-react-doctor.json']
|
||||
}
|
||||
]
|
||||
|
||||
export function parseAddedLineRanges(diff) {
|
||||
const ranges = []
|
||||
const hunkPattern = /^@@ -\d+(?:,\d+)? \+(\d+)(?:,(\d+))? @@/
|
||||
for (const line of diff.split(/\r?\n/)) {
|
||||
const match = hunkPattern.exec(line)
|
||||
if (!match) {
|
||||
continue
|
||||
}
|
||||
const start = Number.parseInt(match[1], 10)
|
||||
const count = match[2] === undefined ? 1 : Number.parseInt(match[2], 10)
|
||||
if (count > 0) {
|
||||
ranges.push({ start, end: start + count - 1 })
|
||||
}
|
||||
}
|
||||
return ranges
|
||||
}
|
||||
|
||||
export function overlapsAddedLines(startLine, endLine, ranges) {
|
||||
return ranges.some((range) => startLine <= range.end && endLine >= range.start)
|
||||
}
|
||||
|
||||
function runGit(root, args, options = {}) {
|
||||
return execFileSync('git', args, {
|
||||
cwd: root,
|
||||
encoding: options.encoding ?? 'utf8',
|
||||
maxBuffer: 64 * 1024 * 1024
|
||||
})
|
||||
}
|
||||
|
||||
function splitNullDelimited(output) {
|
||||
return output.split('\0').filter(Boolean)
|
||||
}
|
||||
|
||||
function resolveBase(root, requestedBase) {
|
||||
for (const candidate of [
|
||||
requestedBase,
|
||||
process.env.ORCA_CODE_QUALITY_BASE,
|
||||
'origin/main',
|
||||
'main'
|
||||
]) {
|
||||
if (!candidate) {
|
||||
continue
|
||||
}
|
||||
const result = spawnSync('git', ['rev-parse', '--verify', `${candidate}^{commit}`], {
|
||||
cwd: root,
|
||||
stdio: 'ignore'
|
||||
})
|
||||
if (result.status === 0) {
|
||||
return candidate
|
||||
}
|
||||
}
|
||||
throw new Error('Pass the pull request base SHA or make origin/main available locally.')
|
||||
}
|
||||
|
||||
export function collectAddedLineRanges(root, requestedBase) {
|
||||
const base = resolveBase(root, requestedBase)
|
||||
const mergeBase = runGit(root, ['merge-base', base, 'HEAD']).trim()
|
||||
const comparisonBase = resolvePullRequestDiffBase(root, mergeBase)
|
||||
const changedFiles = splitNullDelimited(
|
||||
runGit(root, ['diff', '--name-only', '-z', '--diff-filter=ACMRTUB', comparisonBase, '--'])
|
||||
)
|
||||
const untrackedFiles = splitNullDelimited(
|
||||
runGit(root, ['ls-files', '--others', '--exclude-standard', '-z'])
|
||||
)
|
||||
const rangesByFile = new Map()
|
||||
|
||||
for (const file of changedFiles) {
|
||||
if (!SOURCE_FILE_PATTERN.test(file) || !existsSync(path.join(root, file))) {
|
||||
continue
|
||||
}
|
||||
const diff = runGit(root, ['diff', '--unified=0', '--no-color', comparisonBase, '--', file])
|
||||
const ranges = parseAddedLineRanges(diff)
|
||||
if (ranges.length > 0) {
|
||||
rangesByFile.set(file, ranges)
|
||||
}
|
||||
}
|
||||
|
||||
for (const file of untrackedFiles) {
|
||||
const absolutePath = path.join(root, file)
|
||||
if (!SOURCE_FILE_PATTERN.test(file) || !existsSync(absolutePath)) {
|
||||
continue
|
||||
}
|
||||
const lineCount = readFileSync(absolutePath, 'utf8').split(/\r?\n/).length
|
||||
rangesByFile.set(file, [{ start: 1, end: lineCount }])
|
||||
}
|
||||
return { base, comparisonBase, rangesByFile }
|
||||
}
|
||||
|
||||
function parseOxlintOutput(stdout, label) {
|
||||
const start = stdout.indexOf('{')
|
||||
const end = stdout.lastIndexOf('}')
|
||||
if (start === -1 || end === -1) {
|
||||
throw new Error(`${label} did not return Oxlint JSON output.`)
|
||||
}
|
||||
return JSON.parse(stdout.slice(start, end + 1))
|
||||
}
|
||||
|
||||
function normalizedDiagnosticPath(root, filename) {
|
||||
const absolutePath = path.isAbsolute(filename) ? filename : path.join(root, filename)
|
||||
return path.relative(root, absolutePath).split(path.sep).join('/')
|
||||
}
|
||||
|
||||
function diagnosticLineRange(root, filename, span) {
|
||||
const startLine = span.line
|
||||
if (!Number.isInteger(startLine)) {
|
||||
return null
|
||||
}
|
||||
if (!Number.isInteger(span.offset) || !Number.isInteger(span.length) || span.length === 0) {
|
||||
return { start: startLine, end: startLine }
|
||||
}
|
||||
const absolutePath = path.isAbsolute(filename) ? filename : path.join(root, filename)
|
||||
const source = readFileSync(absolutePath)
|
||||
const highlighted = source.subarray(span.offset, span.offset + span.length).toString('utf8')
|
||||
return { start: startLine, end: startLine + (highlighted.match(/\n/g)?.length ?? 0) }
|
||||
}
|
||||
|
||||
export function diagnosticTouchesAddedLines(diagnostic, rangesByFile, root = process.cwd()) {
|
||||
const file = normalizedDiagnosticPath(root, diagnostic.filename)
|
||||
const ranges = rangesByFile.get(file)
|
||||
if (!ranges) {
|
||||
return false
|
||||
}
|
||||
return (diagnostic.labels ?? []).some((label) => {
|
||||
const lineRange = diagnosticLineRange(root, diagnostic.filename, label.span)
|
||||
return lineRange !== null && overlapsAddedLines(lineRange.start, lineRange.end, ranges)
|
||||
})
|
||||
}
|
||||
|
||||
function annotationValue(value) {
|
||||
return String(value).replaceAll('%', '%25').replaceAll('\r', '%0D').replaceAll('\n', '%0A')
|
||||
}
|
||||
|
||||
function printDiagnostic(diagnostic, root) {
|
||||
const file = normalizedDiagnosticPath(root, diagnostic.filename)
|
||||
const line = diagnostic.labels?.[0]?.span?.line ?? 1
|
||||
const code = diagnostic.code ?? 'oxlint'
|
||||
console.error(
|
||||
`::error file=${annotationValue(file)},line=${line},title=${annotationValue(code)}::${annotationValue(diagnostic.message)}`
|
||||
)
|
||||
console.error(`${file}:${line} ${code}: ${diagnostic.message}`)
|
||||
}
|
||||
|
||||
function runOxlintScan(root, scan, files) {
|
||||
const pnpm = process.platform === 'win32' ? 'pnpm.cmd' : 'pnpm'
|
||||
const result = spawnSync(pnpm, ['exec', 'oxlint', ...scan.args, '--format', 'json', ...files], {
|
||||
cwd: root,
|
||||
encoding: 'utf8',
|
||||
maxBuffer: 128 * 1024 * 1024
|
||||
})
|
||||
if (result.error) {
|
||||
throw result.error
|
||||
}
|
||||
if (!result.stdout.trim()) {
|
||||
process.stderr.write(result.stderr)
|
||||
throw new Error(`${scan.label} failed before producing diagnostics.`)
|
||||
}
|
||||
return parseOxlintOutput(result.stdout, scan.label).diagnostics ?? []
|
||||
}
|
||||
|
||||
export function main(
|
||||
root = process.cwd(),
|
||||
requestedBase = process.argv.slice(2).find((argument) => argument !== '--')
|
||||
) {
|
||||
const { base, comparisonBase, rangesByFile } = collectAddedLineRanges(root, requestedBase)
|
||||
const files = [...rangesByFile.keys()]
|
||||
if (files.length === 0) {
|
||||
console.log(`Changed-code quality gate: no changed JavaScript or TypeScript since ${base}.`)
|
||||
return 0
|
||||
}
|
||||
|
||||
let failures = 0
|
||||
for (const scan of OXLINT_SCANS) {
|
||||
const diagnostics = runOxlintScan(root, scan, files).filter((diagnostic) =>
|
||||
diagnosticTouchesAddedLines(diagnostic, rangesByFile, root)
|
||||
)
|
||||
for (const diagnostic of diagnostics) {
|
||||
printDiagnostic(diagnostic, root)
|
||||
}
|
||||
failures += diagnostics.length
|
||||
console.log(
|
||||
`${scan.label}: ${diagnostics.length} new finding(s) across ${files.length} changed file(s).`
|
||||
)
|
||||
}
|
||||
|
||||
if (failures > 0) {
|
||||
console.error(
|
||||
`Changed-code quality gate failed with ${failures} finding(s) since ${comparisonBase.slice(0, 12)}.`
|
||||
)
|
||||
return 1
|
||||
}
|
||||
console.log(`Changed-code quality gate passed since ${comparisonBase.slice(0, 12)}.`)
|
||||
return 0
|
||||
}
|
||||
|
||||
if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {
|
||||
process.exit(main())
|
||||
}
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
import { describe, expect, it } from 'vitest'
|
||||
import {
|
||||
diagnosticTouchesAddedLines,
|
||||
overlapsAddedLines,
|
||||
parseAddedLineRanges
|
||||
} from './check-changed-code-quality.mjs'
|
||||
|
||||
describe('changed-code quality line matching', () => {
|
||||
it('parses added and replaced hunk ranges while ignoring deletions', () => {
|
||||
const ranges = parseAddedLineRanges(
|
||||
['@@ -10,2 +10,3 @@', '@@ -20 +21 @@', '@@ -40,4 +42,0 @@', '@@ -50 +48,2 @@'].join('\n')
|
||||
)
|
||||
|
||||
expect(ranges).toEqual([
|
||||
{ start: 10, end: 12 },
|
||||
{ start: 21, end: 21 },
|
||||
{ start: 48, end: 49 }
|
||||
])
|
||||
})
|
||||
|
||||
it('matches diagnostics that overlap any added line', () => {
|
||||
const ranges = [
|
||||
{ start: 5, end: 7 },
|
||||
{ start: 12, end: 12 }
|
||||
]
|
||||
|
||||
expect(overlapsAddedLines(3, 5, ranges)).toBe(true)
|
||||
expect(overlapsAddedLines(8, 11, ranges)).toBe(false)
|
||||
expect(overlapsAddedLines(12, 14, ranges)).toBe(true)
|
||||
})
|
||||
|
||||
it('normalizes absolute diagnostic paths before matching', () => {
|
||||
const root = process.cwd()
|
||||
const file = 'config/scripts/check-changed-code-quality.test.mjs'
|
||||
const diagnostic = {
|
||||
filename: `${root}/${file}`,
|
||||
labels: [{ span: { line: 24 } }]
|
||||
}
|
||||
|
||||
expect(
|
||||
diagnosticTouchesAddedLines(diagnostic, new Map([[file, [{ start: 24, end: 24 }]]]), root)
|
||||
).toBe(true)
|
||||
})
|
||||
})
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
import { spawnSync } from 'node:child_process'
|
||||
import process from 'node:process'
|
||||
import { resolvePullRequestDiffBase } from './git-pull-request-diff-base.mjs'
|
||||
|
||||
const requestedBase =
|
||||
process.argv.slice(2).find((argument) => argument !== '--') ??
|
||||
process.env.ORCA_CODE_QUALITY_BASE ??
|
||||
'origin/main'
|
||||
const base = resolvePullRequestDiffBase(process.cwd(), requestedBase)
|
||||
const pnpm = process.platform === 'win32' ? 'pnpm.cmd' : 'pnpm'
|
||||
const result = spawnSync(
|
||||
pnpm,
|
||||
[
|
||||
'dlx',
|
||||
'react-doctor@0.9.1',
|
||||
'.',
|
||||
'--yes',
|
||||
'--scope',
|
||||
'lines',
|
||||
'--base',
|
||||
base,
|
||||
'--include-untracked',
|
||||
'--no-dead-code',
|
||||
'--no-supply-chain',
|
||||
'--no-telemetry',
|
||||
'--blocking',
|
||||
'error'
|
||||
],
|
||||
{ stdio: 'inherit' }
|
||||
)
|
||||
|
||||
if (result.error) {
|
||||
throw result.error
|
||||
}
|
||||
process.exit(result.status ?? 1)
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
import { execFileSync } from 'node:child_process'
|
||||
import process from 'node:process'
|
||||
|
||||
export function selectPullRequestDiffBase(requestedBase, headParents, eventName) {
|
||||
if (eventName === 'pull_request' && headParents.length >= 2) {
|
||||
return headParents[0]
|
||||
}
|
||||
return requestedBase
|
||||
}
|
||||
|
||||
export function resolvePullRequestDiffBase(
|
||||
root,
|
||||
requestedBase,
|
||||
eventName = process.env.GITHUB_EVENT_NAME
|
||||
) {
|
||||
const [, ...headParents] = execFileSync('git', ['rev-list', '--parents', '-n', '1', 'HEAD'], {
|
||||
cwd: root,
|
||||
encoding: 'utf8'
|
||||
})
|
||||
.trim()
|
||||
.split(/\s+/)
|
||||
return selectPullRequestDiffBase(requestedBase, headParents, eventName)
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
import { describe, expect, it } from 'vitest'
|
||||
import { selectPullRequestDiffBase } from './git-pull-request-diff-base.mjs'
|
||||
|
||||
describe('pull request diff base selection', () => {
|
||||
it('uses the merge commit first parent for pull request checkouts', () => {
|
||||
expect(
|
||||
selectPullRequestDiffBase('event-base', ['current-base', 'pull-request-head'], 'pull_request')
|
||||
).toBe('current-base')
|
||||
})
|
||||
|
||||
it('keeps the requested base outside synthetic pull request merges', () => {
|
||||
expect(selectPullRequestDiffBase('requested-base', ['parent'], 'pull_request')).toBe(
|
||||
'requested-base'
|
||||
)
|
||||
expect(selectPullRequestDiffBase('requested-base', ['parent', 'other'], 'push')).toBe(
|
||||
'requested-base'
|
||||
)
|
||||
})
|
||||
})
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
import { spawnSync } from 'node:child_process'
|
||||
import { mkdtempSync, writeFileSync } from 'node:fs'
|
||||
import { tmpdir } from 'node:os'
|
||||
import path from 'node:path'
|
||||
import { describe, expect, it } from 'vitest'
|
||||
|
||||
const pluginPath = path.resolve('config/oxlint-plugins/mobile-pairing-qrcode-import.mjs')
|
||||
const oxlintPath = path.resolve(
|
||||
process.platform === 'win32' ? 'node_modules/.bin/oxlint.cmd' : 'node_modules/.bin/oxlint'
|
||||
)
|
||||
|
||||
function lintSource(source) {
|
||||
const directory = mkdtempSync(path.join(tmpdir(), 'orca-qrcode-import-lint-'))
|
||||
const sourcePath = path.join(directory, 'sample.ts')
|
||||
const configPath = path.join(directory, 'oxlint.json')
|
||||
writeFileSync(sourcePath, source)
|
||||
writeFileSync(
|
||||
configPath,
|
||||
JSON.stringify({
|
||||
categories: { correctness: 'off' },
|
||||
jsPlugins: [{ name: 'mobile-pairing', specifier: pluginPath }],
|
||||
rules: { 'mobile-pairing/no-eager-qrcode-import': 'error' }
|
||||
})
|
||||
)
|
||||
const result = spawnSync(oxlintPath, ['--config', configPath, '--format', 'json', sourcePath], {
|
||||
encoding: 'utf8'
|
||||
})
|
||||
if (result.error) {
|
||||
throw result.error
|
||||
}
|
||||
return JSON.parse(result.stdout).diagnostics
|
||||
}
|
||||
|
||||
describe('mobile pairing qrcode import rule', () => {
|
||||
it('rejects eager runtime imports', () => {
|
||||
const diagnostics = lintSource("import QRCode from 'qrcode'\nvoid QRCode")
|
||||
|
||||
expect(diagnostics.map((diagnostic) => diagnostic.code)).toEqual([
|
||||
'mobile-pairing(no-eager-qrcode-import)'
|
||||
])
|
||||
})
|
||||
|
||||
it('allows type-only and lazy imports', () => {
|
||||
expect(lintSource("import type QRCode from 'qrcode'\nlet qr: typeof QRCode")).toEqual([])
|
||||
expect(lintSource("const QRCode = await import('qrcode')\nvoid QRCode")).toEqual([])
|
||||
})
|
||||
})
|
||||
|
|
@ -0,0 +1,81 @@
|
|||
#!/usr/bin/env node
|
||||
import { performance } from 'node:perf_hooks'
|
||||
import process from 'node:process'
|
||||
import { createStore } from 'zustand/vanilla'
|
||||
|
||||
const SUBSCRIBERS = Number.parseInt(process.env.ORCA_ZUSTAND_BENCH_SUBSCRIBERS ?? '2500', 10)
|
||||
const WRITES = Number.parseInt(process.env.ORCA_ZUSTAND_BENCH_WRITES ?? '2000', 10)
|
||||
const MAX_MILLISECONDS_PER_WRITE = Number.parseFloat(
|
||||
process.env.ORCA_ZUSTAND_BENCH_MAX_MS_PER_WRITE ?? '5'
|
||||
)
|
||||
|
||||
for (const [name, value] of [
|
||||
['ORCA_ZUSTAND_BENCH_SUBSCRIBERS', SUBSCRIBERS],
|
||||
['ORCA_ZUSTAND_BENCH_WRITES', WRITES],
|
||||
['ORCA_ZUSTAND_BENCH_MAX_MS_PER_WRITE', MAX_MILLISECONDS_PER_WRITE]
|
||||
]) {
|
||||
if (!Number.isFinite(value) || value <= 0) {
|
||||
throw new Error(`${name} must be positive, received ${value}`)
|
||||
}
|
||||
}
|
||||
|
||||
function measureRound() {
|
||||
const stableProjection = Object.freeze({ activeRepoId: 'repo-1' })
|
||||
const store = createStore(() => ({ unrelatedWrite: 0, stableProjection }))
|
||||
let selectorRuns = 0
|
||||
let renderInvalidations = 0
|
||||
const unsubscribe = Array.from({ length: SUBSCRIBERS }, () => {
|
||||
let previous = store.getState().stableProjection
|
||||
return store.subscribe((state) => {
|
||||
selectorRuns += 1
|
||||
const next = state.stableProjection
|
||||
if (!Object.is(previous, next)) {
|
||||
renderInvalidations += 1
|
||||
}
|
||||
previous = next
|
||||
})
|
||||
})
|
||||
|
||||
const start = performance.now()
|
||||
for (let index = 1; index <= WRITES; index += 1) {
|
||||
store.setState({ unrelatedWrite: index })
|
||||
}
|
||||
const elapsed = performance.now() - start
|
||||
for (const release of unsubscribe) {
|
||||
release()
|
||||
}
|
||||
return { elapsed, selectorRuns, renderInvalidations }
|
||||
}
|
||||
|
||||
measureRound()
|
||||
const rounds = Array.from({ length: 5 }, measureRound).sort(
|
||||
(left, right) => left.elapsed - right.elapsed
|
||||
)
|
||||
const median = rounds[2]
|
||||
const expectedSelectorRuns = SUBSCRIBERS * WRITES
|
||||
const millisecondsPerWrite = median.elapsed / WRITES
|
||||
|
||||
if (median.selectorRuns !== expectedSelectorRuns) {
|
||||
throw new Error(
|
||||
`Expected ${expectedSelectorRuns} selector runs, observed ${median.selectorRuns}; update the fan-out model.`
|
||||
)
|
||||
}
|
||||
if (median.renderInvalidations !== 0) {
|
||||
throw new Error(
|
||||
`${median.renderInvalidations} unrelated writes changed a stable selector result.`
|
||||
)
|
||||
}
|
||||
|
||||
console.log(
|
||||
`Zustand fan-out: ${SUBSCRIBERS} subscribers × ${WRITES} unrelated writes = ${expectedSelectorRuns.toLocaleString()} selector runs`
|
||||
)
|
||||
console.log(
|
||||
`Median ${median.elapsed.toFixed(2)} ms total, ${millisecondsPerWrite.toFixed(4)} ms/write, 0 render invalidations`
|
||||
)
|
||||
|
||||
if (process.argv.includes('--check') && millisecondsPerWrite > MAX_MILLISECONDS_PER_WRITE) {
|
||||
console.error(
|
||||
`Zustand fan-out exceeded ${MAX_MILLISECONDS_PER_WRITE.toFixed(2)} ms/write. Inspect selector work and store subscription growth.`
|
||||
)
|
||||
process.exit(1)
|
||||
}
|
||||
17
package.json
17
package.json
|
|
@ -12,6 +12,14 @@
|
|||
"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",
|
||||
"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: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",
|
||||
"check:zustand-selector-fanout": "node config/scripts/zustand-selector-fanout-benchmark.mjs --check",
|
||||
"doctor": "pnpm dlx react-doctor@0.9.1 . --no-telemetry",
|
||||
"lint:react-doctor": "oxlint --config config/oxlint-react-doctor.json",
|
||||
"lint:react-doctor:changed": "node config/scripts/lint-react-doctor-changed.mjs",
|
||||
"lint:switch-exhaustiveness": "oxlint --type-aware --config config/oxlint-switch-exhaustiveness.json src/main src/preload src/shared src/relay src/cli src/renderer/src config tests --quiet",
|
||||
|
|
@ -104,6 +112,7 @@
|
|||
"bench:startup": "pnpm run ensure:electron-runtime && node tools/benchmarks/startup-time-bench.mjs",
|
||||
"bench:daemon-coldstart": "pnpm run ensure:electron-runtime && node tools/benchmarks/daemon-coldstart-bench.mjs",
|
||||
"bench:main-thread-jank": "pnpm run ensure:electron-runtime && node tools/benchmarks/main-thread-jank-bench.mjs",
|
||||
"bench:zustand-selector-fanout": "node config/scripts/zustand-selector-fanout-benchmark.mjs",
|
||||
"bench:multi-workspace-typing": "pnpm run ensure:electron-runtime && node config/scripts/run-multi-workspace-typing-bench.mjs",
|
||||
"bench:cold-park-reveal": "pnpm run ensure:electron-runtime && node tools/benchmarks/terminal-cold-park-reveal-bench.mjs",
|
||||
"bench:cold-park-resource": "pnpm run ensure:electron-runtime && node tools/benchmarks/terminal-cold-park-resource-bench.mjs",
|
||||
|
|
@ -197,9 +206,9 @@
|
|||
"mermaid": "^11.15.0",
|
||||
"monaco-editor": "^0.55.1",
|
||||
"oxfmt": "^0.52.0",
|
||||
"oxlint": "^1.71.0",
|
||||
"oxlint-plugin-react-doctor": "0.2.10",
|
||||
"oxlint-tsgolint": "0.23.0",
|
||||
"oxlint": "^1.75.0",
|
||||
"oxlint-plugin-react-doctor": "0.9.1",
|
||||
"oxlint-tsgolint": "7.0.2001",
|
||||
"pdfjs-dist": "^5.7.284",
|
||||
"pngjs": "^7.0.0",
|
||||
"radix-ui": "^1.6.2",
|
||||
|
|
@ -230,7 +239,7 @@
|
|||
"vitest": "^4.1.5",
|
||||
"vscode-oniguruma": "^2.0.1",
|
||||
"vscode-textmate": "^9.3.2",
|
||||
"zustand": "^5.0.13"
|
||||
"zustand": "^5.0.14"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"sherpa-onnx-darwin-arm64": "1.12.37",
|
||||
|
|
|
|||
484
pnpm-lock.yaml
484
pnpm-lock.yaml
|
|
@ -286,14 +286,14 @@ importers:
|
|||
specifier: ^0.52.0
|
||||
version: 0.52.0
|
||||
oxlint:
|
||||
specifier: ^1.71.0
|
||||
version: 1.71.0(oxlint-tsgolint@0.23.0)
|
||||
specifier: ^1.75.0
|
||||
version: 1.75.0(oxlint-tsgolint@7.0.2001)
|
||||
oxlint-plugin-react-doctor:
|
||||
specifier: 0.2.10
|
||||
version: 0.2.10
|
||||
specifier: 0.9.1
|
||||
version: 0.9.1
|
||||
oxlint-tsgolint:
|
||||
specifier: 0.23.0
|
||||
version: 0.23.0
|
||||
specifier: 7.0.2001
|
||||
version: 7.0.2001
|
||||
pdfjs-dist:
|
||||
specifier: ^5.7.284
|
||||
version: 5.7.284
|
||||
|
|
@ -377,7 +377,7 @@ importers:
|
|||
version: rolldown-vite@7.3.1(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2)(@types/node@25.9.5)(jiti@2.7.0)(yaml@2.8.4)
|
||||
vitest:
|
||||
specifier: ^4.1.5
|
||||
version: 4.1.5(@types/node@25.9.5)(happy-dom@20.9.0)(msw@2.14.3(@types/node@25.9.5)(typescript@7.0.2))(rolldown-vite@7.3.1(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2)(@types/node@25.9.5)(jiti@2.7.0)(yaml@2.8.4))
|
||||
version: 4.1.5(@opentelemetry/api@1.9.1)(@types/node@25.9.5)(happy-dom@20.9.0)(msw@2.14.3(@types/node@25.9.5)(typescript@7.0.2))(rolldown-vite@7.3.1(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2)(@types/node@25.9.5)(jiti@2.7.0)(yaml@2.8.4))
|
||||
vscode-oniguruma:
|
||||
specifier: ^2.0.1
|
||||
version: 2.0.1
|
||||
|
|
@ -385,8 +385,8 @@ importers:
|
|||
specifier: ^9.3.2
|
||||
version: 9.3.2
|
||||
zustand:
|
||||
specifier: ^5.0.13
|
||||
version: 5.0.13(@types/react@19.2.17)(react@19.2.7)(use-sync-external-store@1.6.0(react@19.2.7))
|
||||
specifier: ^5.0.14
|
||||
version: 5.0.14(@types/react@19.2.17)(react@19.2.7)(use-sync-external-store@1.6.0(react@19.2.7))
|
||||
optionalDependencies:
|
||||
sherpa-onnx-darwin-arm64:
|
||||
specifier: 1.12.37
|
||||
|
|
@ -1079,6 +1079,137 @@ packages:
|
|||
'@open-draft/until@2.1.0':
|
||||
resolution: {integrity: sha512-U69T3ItWHvLwGg5eJ0n3I62nWuE6ilHlmz7zM0npLBRvPRd7e6NYmg54vvRtP5mZG7kZqZCFVdsTWo7BPtBujg==}
|
||||
|
||||
'@opentelemetry/api@1.9.1':
|
||||
resolution: {integrity: sha512-gLyJlPHPZYdAk1JENA9LeHejZe1Ti77/pTeFm/nMXmQH/HFZlcS/O2XJB+L8fkbrNSqhdtlvjBVjxwUYanNH5Q==}
|
||||
engines: {node: '>=8.0.0'}
|
||||
|
||||
'@oxc-parser/binding-android-arm-eabi@0.141.0':
|
||||
resolution: {integrity: sha512-jk7086MFvR/T4DG9IY7MKBVt1PMxvSZoz/TvnifodvS0pjghVwJHRttnAExhlwdMOgHv1TmLdENnbNpYk2zjvA==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [arm]
|
||||
os: [android]
|
||||
|
||||
'@oxc-parser/binding-android-arm64@0.141.0':
|
||||
resolution: {integrity: sha512-a4XDQ27ZT7e7zwAlxJDTiCA7IBGWDuy2+MhFq85Of7XlBSmpkfcBFml11q0Zx6f7RMuI0B4xCtt2ytBS4yOptg==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [arm64]
|
||||
os: [android]
|
||||
|
||||
'@oxc-parser/binding-darwin-arm64@0.141.0':
|
||||
resolution: {integrity: sha512-m/kVk6rzYmBeHYnz+1Y5fod00AVTTxMbC71azFfm/zjx1j9XxwKtA0+VfkKuVMC8rbghb9TtfevnuWZa9OuPEg==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [arm64]
|
||||
os: [darwin]
|
||||
|
||||
'@oxc-parser/binding-darwin-x64@0.141.0':
|
||||
resolution: {integrity: sha512-o0X+6KZlfucWU/v5oKRQPwdFXsXAjW8jmpo/Gpw/qyKsbKtlfkHoeH9Bjp/m13TwjewvJnCkwF0DWzgpC4HjTQ==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [x64]
|
||||
os: [darwin]
|
||||
|
||||
'@oxc-parser/binding-freebsd-x64@0.141.0':
|
||||
resolution: {integrity: sha512-W5KbTnNkTMMMylqj6dYqnsXvkmESVPodPKYLJ5zdzIPdl9fUJtolkpUeSzYEbGGYB4a4A4avl3EePnZ/wLIdJg==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [x64]
|
||||
os: [freebsd]
|
||||
|
||||
'@oxc-parser/binding-linux-arm-gnueabihf@0.141.0':
|
||||
resolution: {integrity: sha512-g3dtbJa8zeOGK36Sr9cQavsdi5H/ie2hVjrSjIxsNAR1qZA40ZYVXnfdfoMAlq8CmB9qFL1yhsSCUHeNmdmt8w==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [arm]
|
||||
os: [linux]
|
||||
|
||||
'@oxc-parser/binding-linux-arm-musleabihf@0.141.0':
|
||||
resolution: {integrity: sha512-e6hwQqd+3lvP13G2jxvFpoA7dzHcFLN+Mq47JCVMtdNHbbyBRo756JCtbbJH6ca8inTfyqZoqBmS3vhQlzAK2w==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [arm]
|
||||
os: [linux]
|
||||
|
||||
'@oxc-parser/binding-linux-arm64-gnu@0.141.0':
|
||||
resolution: {integrity: sha512-vXz2BLAuypA+4MLyBg94pzEo6THVnzYnCtAjXoihIIQo0t2pnp/AmW+SH1EI+4VbuJnC//KplIJ5yyaCGua4jA==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@oxc-parser/binding-linux-arm64-musl@0.141.0':
|
||||
resolution: {integrity: sha512-jMkS/EztNW34HKsXIaT/SoHcmtocq/vWhwFOVduF9kduuuRIVwfwQ6uxzIO+qPKSXdd2TXt54of0BJ2zFMXnmw==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@oxc-parser/binding-linux-ppc64-gnu@0.141.0':
|
||||
resolution: {integrity: sha512-vo+MR+n3zQJ6Mq92hiP084NZcgDv5iJlVR02gMf28neMvVT1tKVm7VeiW/DxhdqOi3QLeaXIk9cUcLL1qrkngw==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [ppc64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@oxc-parser/binding-linux-riscv64-gnu@0.141.0':
|
||||
resolution: {integrity: sha512-oh80w+7RuiO5gBp9Jnoa/H8Qlt3JsHL2MkW+0dwEdlDMdslVZX/YsekSK6EeyEenY66/mhCfypsNATQ7Ph3qlQ==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [riscv64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@oxc-parser/binding-linux-riscv64-musl@0.141.0':
|
||||
resolution: {integrity: sha512-LOyEmFA8sCnYbEXP1+iQvCC/P1YXHMA/t6x1Ksp0Y9VwhLFsiBJFzV1zIxrOIE2LKaGGhDjQ29xq9cbq6omDXA==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [riscv64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@oxc-parser/binding-linux-s390x-gnu@0.141.0':
|
||||
resolution: {integrity: sha512-3wnwk/l1CvszVE5TJR1wSl/zSEfydRqrNhn6s7Vr9IzSJpUQIroqVsIoPARHRFA+FQwkxAFDAHDAasa7v8OobQ==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [s390x]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@oxc-parser/binding-linux-x64-gnu@0.141.0':
|
||||
resolution: {integrity: sha512-qtyQVAAebFq57B2tifTlel3TgGqUtsYNI/e+p6aya9rN9lOZVTDvr215fGYSA9XWooxzMxDiVxkBLk2jQHbsOQ==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@oxc-parser/binding-linux-x64-musl@0.141.0':
|
||||
resolution: {integrity: sha512-SkGV1nKw40roEc94pv5EaaeH2ay14G6+roe8Q0wIUC1LcEKxzKW921h7+ZuZX0D3q2Mb/7aSFmxEVqnko3lPRw==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@oxc-parser/binding-openharmony-arm64@0.141.0':
|
||||
resolution: {integrity: sha512-cVgDM7n8QziQqOaP5hNgUYfMG7S/ZeuPxFWXnnHRv7rh025COk0rfQ6eEdKG3j/GaUuyvNZN4ifF1J8KmuXLLA==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [arm64]
|
||||
os: [openharmony]
|
||||
|
||||
'@oxc-parser/binding-wasm32-wasi@0.141.0':
|
||||
resolution: {integrity: sha512-HggH++Fkn3OilBn+bs3jpgIFQa34oMAyUUHy0vpGum+gt1Eb5nyLc8dNU/RAPSw6lsLrx7ncKtHSZE+3Sp0l2g==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [wasm32]
|
||||
|
||||
'@oxc-parser/binding-win32-arm64-msvc@0.141.0':
|
||||
resolution: {integrity: sha512-KLSEH9GwgbrqbJOjtGHt9STw96s+78yDzp7IDN8Lno+7Ut9sNBfZ4jYZIz4mD50qmWUjoOI7i9I6UENbhNbMZQ==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [arm64]
|
||||
os: [win32]
|
||||
|
||||
'@oxc-parser/binding-win32-ia32-msvc@0.141.0':
|
||||
resolution: {integrity: sha512-9UVWUOOCI/1YkiSSNjg2zyBJYM9E/t1A/8GNobd48JDn/fQ6mzxcVO3H08jb3rAaW/B1VBf8eCORTvSsO9T08g==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [ia32]
|
||||
os: [win32]
|
||||
|
||||
'@oxc-parser/binding-win32-x64-msvc@0.141.0':
|
||||
resolution: {integrity: sha512-HI/wsvbWT5RHHw5c37D0fEgeTd8/1Q4OJs5jUmEBc17VZFG6SsCIe4barq7NsAPPks/JW+3ayi3Rp+PQI5h4Kg==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [x64]
|
||||
os: [win32]
|
||||
|
||||
'@oxc-project/runtime@0.101.0':
|
||||
resolution: {integrity: sha512-t3qpfVZIqSiLQ5Kqt/MC4Ge/WCOGrrcagAdzTcDaggupjiGxUx4nJF2v6wUCXWSzWHn5Ns7XLv13fCJEwCOERQ==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
|
|
@ -1086,6 +1217,9 @@ packages:
|
|||
'@oxc-project/types@0.101.0':
|
||||
resolution: {integrity: sha512-nuFhqlUzJX+gVIPPfuE6xurd4lST3mdcWOhyK/rZO0B9XWMKm79SuszIQEnSMmmDhq1DC8WWVYGVd+6F93o1gQ==}
|
||||
|
||||
'@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==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
|
|
@ -1208,154 +1342,154 @@ packages:
|
|||
cpu: [x64]
|
||||
os: [win32]
|
||||
|
||||
'@oxlint-tsgolint/darwin-arm64@0.23.0':
|
||||
resolution: {integrity: sha512-gOs9PVr2wEg4ox9z0aJo+RKhhImW86YL5N6yav8BK/rgPsIrwN/igSZ+pbRr723NFvUNKde9fgMhRA6JrXAOZw==}
|
||||
'@oxlint-tsgolint/darwin-arm64@7.0.2001':
|
||||
resolution: {integrity: sha512-CUJEdbSZ54+Xy9OXqOhWLTKZKV0BBiV7C2i/ygyVmXtkUNXx5YCzN8DpSSshTAKktoL7S+tnQ/ftFG/i7X896w==}
|
||||
cpu: [arm64]
|
||||
os: [darwin]
|
||||
|
||||
'@oxlint-tsgolint/darwin-x64@0.23.0':
|
||||
resolution: {integrity: sha512-kjJ8B+7n4tB9VJdxS5A9GdJt6/bYpzbu4lXp2uO1S3sRmCB5gDEABlGoiePNApRWaW+xqL4b4xgiE727jSLhuA==}
|
||||
'@oxlint-tsgolint/darwin-x64@7.0.2001':
|
||||
resolution: {integrity: sha512-pXfBb5BqONCcgrXQNUZWXgiYmRSWJzd97S8i41VVOh6ut0tyo+cJ5FKFpczDHxiVNfj/3e7c9B4MtztNdpIVCw==}
|
||||
cpu: [x64]
|
||||
os: [darwin]
|
||||
|
||||
'@oxlint-tsgolint/linux-arm64@0.23.0':
|
||||
resolution: {integrity: sha512-6dCZuKNu135seMXilkRk9SpCx6i1XgmiipYGalLij5WVRX6ZYS8c4xI7preN/zv9fCXhsQclTIMDu2Y/cytTjw==}
|
||||
'@oxlint-tsgolint/linux-arm64@7.0.2001':
|
||||
resolution: {integrity: sha512-roP7zujb/QDPzDwEKsFFpzNHHy91/Y7oX9vQXk78ekyZtcQj1QXDIMH33gjDdHBfRl4K9pZ36xhRgrP4Zr+R8A==}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
|
||||
'@oxlint-tsgolint/linux-x64@0.23.0':
|
||||
resolution: {integrity: sha512-3bdilnyA7kmSTjK27rvjIjSxL5SIg3wt7vwNiRkouWB83ytssyKnuGvxSYJxgMEmFpSutzaBzcCUM2jDtPGcgA==}
|
||||
'@oxlint-tsgolint/linux-x64@7.0.2001':
|
||||
resolution: {integrity: sha512-UDezNqdECVmngu2TPnjaS1YoAmcTaBoI5lV9vk3VahBxoi+I5r9k3iJTT7qZoYWOXTD/7T7bNcwRgrocR6BscQ==}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
|
||||
'@oxlint-tsgolint/win32-arm64@0.23.0':
|
||||
resolution: {integrity: sha512-j+OEp44SVYiQ+ZD+uttsX7u6L9SvmbbQ77SO1pSFCcJlsVMeCk8qZsjhKfGKuT/jIA+ipOJMVs/+pqUfObBWNw==}
|
||||
'@oxlint-tsgolint/win32-arm64@7.0.2001':
|
||||
resolution: {integrity: sha512-uJZhqB6pdXLuN+AD1F5082byyQti/NPmJA77GtcFlmT2HzRelqbNls3SaIqxpjdFgvSBF9g0yOKGBkGFg7kX8Q==}
|
||||
cpu: [arm64]
|
||||
os: [win32]
|
||||
|
||||
'@oxlint-tsgolint/win32-x64@0.23.0':
|
||||
resolution: {integrity: sha512-5MyjFuqf+g8OUPJBSGWHJtmoWnzFJYyOg4To9WMQshZYEWig/vtu7JtJ03VWnzHv9LJkAUeApY0gVCOywFR/iQ==}
|
||||
'@oxlint-tsgolint/win32-x64@7.0.2001':
|
||||
resolution: {integrity: sha512-FkDRm8hx9OwzGQqyWG1tO5QrTLRApff9DzSgpz9QZau37BR8d1VYKOxMLGf6shPZntJFoTwIIJYT68VndYDCog==}
|
||||
cpu: [x64]
|
||||
os: [win32]
|
||||
|
||||
'@oxlint/binding-android-arm-eabi@1.71.0':
|
||||
resolution: {integrity: sha512-ImGmd1njEg4FEJH03jhRnveEegtO3czCtfptvaHivKAZQIYATbVFBrrzbaYMYv0oJioTnxZAZVSyV+oL7W8S2g==}
|
||||
'@oxlint/binding-android-arm-eabi@1.75.0':
|
||||
resolution: {integrity: sha512-lutovtFzJqlRaqpZrCqSSGaHZzl9nIxxpjLzhSRLunN6dCLylj0uzlCyQGaQDIys7rrv8kVXiFO+R4Zpn0bX7g==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [arm]
|
||||
os: [android]
|
||||
|
||||
'@oxlint/binding-android-arm64@1.71.0':
|
||||
resolution: {integrity: sha512-4A5BEexBrwY1YFF8Kiq/lp/wQPRG79G3BWIE1FuWaM5MvmpYSd+7ZySVcKkHdwo0UDzdQGddp6pD9mpctMqLnw==}
|
||||
'@oxlint/binding-android-arm64@1.75.0':
|
||||
resolution: {integrity: sha512-hXI0hDgHkw4w5nfru72aG7y+2iQJmC4waH/KV6H/hbgA6yAP5jYNx0P9yug15Hs0tWl/+mda3Jjn/2gmDT48tw==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [arm64]
|
||||
os: [android]
|
||||
|
||||
'@oxlint/binding-darwin-arm64@1.71.0':
|
||||
resolution: {integrity: sha512-9wJA9GJulLwS2usU3CEisI/ESDO1n1z9eyTCvApMDrAkbJ1ve0mORgTMjcWWsKxkzkeZ2N/Gpra5IQE7x8tYgQ==}
|
||||
'@oxlint/binding-darwin-arm64@1.75.0':
|
||||
resolution: {integrity: sha512-D91BWbK/dMYfCcrghspPIuKs2D9LF4Z/OabVSQjw1AO6PWxArD7teDA48bm0ySFqWDaPVqmQRl5GMWNglTXyrQ==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [arm64]
|
||||
os: [darwin]
|
||||
|
||||
'@oxlint/binding-darwin-x64@1.71.0':
|
||||
resolution: {integrity: sha512-PlLCjS06V0PeJMAJwzjrExw1sYNW9Gch3JtNlcwwZDXGlTYDuwHNN89zYH8LTXFfgkVtsYvs2nv0FqrzyuFDzg==}
|
||||
'@oxlint/binding-darwin-x64@1.75.0':
|
||||
resolution: {integrity: sha512-02mpwzf12BonZ6PT0TuQoomvEh2kVl2WGBIKWezCyToIS+rYkQZ6GXnARBAl9A4Ovm2V+Xe7M4KretyqmmcnJQ==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [x64]
|
||||
os: [darwin]
|
||||
|
||||
'@oxlint/binding-freebsd-x64@1.71.0':
|
||||
resolution: {integrity: sha512-Lhil7bWre0ncxbUoDoxfS0JzpTz17BRQKW7iwoAUY8GJ66+WwJEfYPCFJ1P0WgVZR5/O/b3Q2pENlHOjeXLOGQ==}
|
||||
'@oxlint/binding-freebsd-x64@1.75.0':
|
||||
resolution: {integrity: sha512-qZJgLnDaBsiL5YESx2t/TZ8eXkL9fEkKoXEdzegROhlz9A0lgyGnZ0dAzJrh7LJAHQl2K9RdRueN2s/9N7+odg==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [x64]
|
||||
os: [freebsd]
|
||||
|
||||
'@oxlint/binding-linux-arm-gnueabihf@1.71.0':
|
||||
resolution: {integrity: sha512-Oo9/L58PYD3RC0x05d2upAPLllHytTjHQGsnC06P6Ynn7jKkp5mdImQxXdJ3+FnBaKspNpGogzgVsi6g872LiA==}
|
||||
'@oxlint/binding-linux-arm-gnueabihf@1.75.0':
|
||||
resolution: {integrity: sha512-7XlaWA5BJD3XpCfrEqjEe6Zseeb14S7QGa304XfwKignRaKQ+eIj775BQ7nIslggWickl4IsPUFqJ+/gAyNHVg==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [arm]
|
||||
os: [linux]
|
||||
|
||||
'@oxlint/binding-linux-arm-musleabihf@1.71.0':
|
||||
resolution: {integrity: sha512-mSHfyfgJrEbyIR29ejaeS50BdPk+GoNPlC1dckpDiUZbJAIel68sjSMdOt4WY0/gva+ECC7FNITQkxMJU+vSBw==}
|
||||
'@oxlint/binding-linux-arm-musleabihf@1.75.0':
|
||||
resolution: {integrity: sha512-av6Tpv8yrcMMMOadOqENBhlsLRcGFXXwoQ0hzHhsmS9FJ4Wioy8we427GbcMe2XTxmL2e60T67H1Dyr3up+tAA==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [arm]
|
||||
os: [linux]
|
||||
|
||||
'@oxlint/binding-linux-arm64-gnu@1.71.0':
|
||||
resolution: {integrity: sha512-n9yY4M2tiy3aij4AqtlnspzpfdpeT5JQfK2/w2d8oyp5W0FRwOb1dIeX99nORNcxGr08iD9bH8N5XFz3I2iy8w==}
|
||||
'@oxlint/binding-linux-arm64-gnu@1.75.0':
|
||||
resolution: {integrity: sha512-WcUhd8fHT5plrA14lANevl+hOl815mVI5t2hU21oFWrZKFXIVV/Sr4rWQV0NzSvzBupbMLNc5ErEA6Ehxh5jMg==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@oxlint/binding-linux-arm64-musl@1.71.0':
|
||||
resolution: {integrity: sha512-fJZrs5sDZtTaPIOiemRQQmo82Ezy+vOGXemPc4Ok7iVVsYsFa7SlW6Z5XN819VfsqBHRm3NJ3rTdnR8+bJYJdQ==}
|
||||
'@oxlint/binding-linux-arm64-musl@1.75.0':
|
||||
resolution: {integrity: sha512-UWzp5wRHFe/ESO3+eEaxXsTkYTGLYjnTsi/I5neEacXSItQ6WNleapfOAeA4x2b8nyhJ4uQxqvtv9pHv8kWJtQ==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@oxlint/binding-linux-ppc64-gnu@1.71.0':
|
||||
resolution: {integrity: sha512-cwl7VKGERIy9p+G+AvZdfy/06q0aHXaTt/mMRReC751iuNYJgqKjB7NydXSS30nBT9vtr2tunciOtrR4fD6FUA==}
|
||||
'@oxlint/binding-linux-ppc64-gnu@1.75.0':
|
||||
resolution: {integrity: sha512-XEVRwGMLKCUKrvhLAz4F6AIh8MJrQVdSZtAmPpRZt9tGPsUnamPOcl3dS/ZQzJnar/Ymgc//+xho0L60Emzuxg==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [ppc64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@oxlint/binding-linux-riscv64-gnu@1.71.0':
|
||||
resolution: {integrity: sha512-eZ8ieVXvzGi8jr7+ybQGPK2STw3mldfxZlgA2738iflfB/rzA69sE6m5rDRpQaxC7dpm745Enlh1Tod0QAk9Gg==}
|
||||
'@oxlint/binding-linux-riscv64-gnu@1.75.0':
|
||||
resolution: {integrity: sha512-mAG4DUXqfLC8cTjMD2kt3jDmVzFREYtDyeLNdLdsCcBc4Zbl2EMuiFektGBilQwkNjYnMvCqJs55U+Hyb+b+jw==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [riscv64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@oxlint/binding-linux-riscv64-musl@1.71.0':
|
||||
resolution: {integrity: sha512-puMDbQYe6+NXwfMusojoA7CXGn2b3utukmd23PQqc1E3XhVCwyZ+FueSMzDYeNgDV2dUfIVXAAKZBcFDeCL6sA==}
|
||||
'@oxlint/binding-linux-riscv64-musl@1.75.0':
|
||||
resolution: {integrity: sha512-95hrAvriAlI+pekSomTFIn0+bawMDlDwTNVmdjsFusTHyL2JWh7TWvRNG/Lkim72uN8OiCcO9wcaC6omLP5E3w==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [riscv64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@oxlint/binding-linux-s390x-gnu@1.71.0':
|
||||
resolution: {integrity: sha512-4NJLxBs1ujISCt3L/1FcywLs73PWtJuw+piD6feK2V6h6OS6P7xu9/sWt1DTRLibe6QCzmfZzmM/2HPORoV/Lg==}
|
||||
'@oxlint/binding-linux-s390x-gnu@1.75.0':
|
||||
resolution: {integrity: sha512-4b6f2+FrtruAESrCqIKcrarzfrSx+wk2QNcp+RT91/Prc+pMQMAfyZ1rG1c3tFQNl8Bc616tx40uNXyxNBRPbQ==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [s390x]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@oxlint/binding-linux-x64-gnu@1.71.0':
|
||||
resolution: {integrity: sha512-cFDaiR8L3430qp88tfZnvFlt3KotFhR/DlbIL0nHOMMYiG/9Wy4l+6f7t8G8pTa9bd8Lt8+M0y/qjRQ/xcB74g==}
|
||||
'@oxlint/binding-linux-x64-gnu@1.75.0':
|
||||
resolution: {integrity: sha512-nshAhrUvXFUWOvqQ2soIw7HFNWvpvEV4o0cYSqPtzLiPF5gKyYTDOOTJ6Rn8g8K/iGvPIrbDA4v8+5MvnjJrrg==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@oxlint/binding-linux-x64-musl@1.71.0':
|
||||
resolution: {integrity: sha512-orfixdt76KlpNly9z0PkWBBNfwjKz+JFVLP/7wnVchlKNU9Dpt9InU/ZggeSej6fC7qwHmHNOGlhLnQXcYoGuA==}
|
||||
'@oxlint/binding-linux-x64-musl@1.75.0':
|
||||
resolution: {integrity: sha512-e4jNxLKnxLC6sYBQRxrI2pgIIxnmMtF8U/VwNYcjTT/CLS+spH624cYVnj07bTKwaEWT37/e025isOs6j/0xqA==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@oxlint/binding-openharmony-arm64@1.71.0':
|
||||
resolution: {integrity: sha512-9emQu2lAp6yhPB3XuI+++vR+l/o6JR1X+EpxwcumPdQXBWXEPAsquPGL7l158EqU8SebQMXTUa/S5zN98juyHw==}
|
||||
'@oxlint/binding-openharmony-arm64@1.75.0':
|
||||
resolution: {integrity: sha512-hZ2lH+1qLf/DiEP9UWuQTK2JWj/BgvMB4jhIV4SmNU1wfEiYYX4TynQyAZXx0j9X4qRYizAL042SKaV+8ynh4w==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [arm64]
|
||||
os: [openharmony]
|
||||
|
||||
'@oxlint/binding-win32-arm64-msvc@1.71.0':
|
||||
resolution: {integrity: sha512-bd5kI8spYwTm3BILDtGhi73zoup5dw8MlPQNT8YB3BD5UIsjNe3K9/4ctrzQMX4SZMoK5HgzVLkLJzacEXB7fA==}
|
||||
'@oxlint/binding-win32-arm64-msvc@1.75.0':
|
||||
resolution: {integrity: sha512-Ilj6PNzGDS3bCU0MSJH7Msh0NhH+T/mRp2shwg+q+GHeVlPwP5LEboW96aW+3kVKFk6zYZy1Xi5pZkqZh6X8KQ==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [arm64]
|
||||
os: [win32]
|
||||
|
||||
'@oxlint/binding-win32-ia32-msvc@1.71.0':
|
||||
resolution: {integrity: sha512-W4HvOHGzVLHcrmFu+bMrJlho+/yrlX5ZNdJZqGe8MEldkQG+RHYhxxad9P4jvWAYFmIqUA5i9DQ8QsJqSU9GIw==}
|
||||
'@oxlint/binding-win32-ia32-msvc@1.75.0':
|
||||
resolution: {integrity: sha512-QVit2nOEOiPhkmsrksPSkoGCdnZRNkspt8fwoYyP09te1VEbnSj4LAxua4rc8FKTmWkySVe05j8iz9GXYfF1AQ==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [ia32]
|
||||
os: [win32]
|
||||
|
||||
'@oxlint/binding-win32-x64-msvc@1.71.0':
|
||||
resolution: {integrity: sha512-D2kyEIPHk/G/wiZLnwTVC/sVst+T/lKldVOjAFpgTIBUAOlry72e5OiapDbDBF4LfJLkN5ypJb/8Eu6yJzkveQ==}
|
||||
'@oxlint/binding-win32-x64-msvc@1.75.0':
|
||||
resolution: {integrity: sha512-DSxnNkBUAYARPwJtR12Ig3deWr8w0H997xP6jy33i+e0SyYJw8FKuz4+cZtpmPEhQmvlPJE3X/2vNxDmLkd/rA==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [x64]
|
||||
os: [win32]
|
||||
|
|
@ -5135,6 +5269,10 @@ packages:
|
|||
outvariant@1.4.3:
|
||||
resolution: {integrity: sha512-+Sl2UErvtsoajRDKCE5/dBz4DIvHXQQnAxtQTF04OJxY0+DyZXSo5P5Bb7XYWOh81syohlYL24hbDwxedPUJCA==}
|
||||
|
||||
oxc-parser@0.141.0:
|
||||
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==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
|
|
@ -5148,20 +5286,20 @@ packages:
|
|||
vite-plus:
|
||||
optional: true
|
||||
|
||||
oxlint-plugin-react-doctor@0.2.10:
|
||||
resolution: {integrity: sha512-n36QdOLz4k9EEWod+vhki9/h29x/PL4nS91nWSk6AIr7HAL+rc6fkwUcVLgg3NhUVlaL/VOfYiIm4cVxyIIdGg==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
oxlint-plugin-react-doctor@0.9.1:
|
||||
resolution: {integrity: sha512-yCW8USbiuszbVsUMN4fL1iU7mRu3Ae3w96+k/xqCyWvW6bF6DzCMtLy5N/w6WLRX78iQsWxVqW/SEgzRBXLfsA==}
|
||||
engines: {node: ^20.19.0 || >=22.13.0}
|
||||
|
||||
oxlint-tsgolint@0.23.0:
|
||||
resolution: {integrity: sha512-3mBv3CoPbh8dFbzfDGIWa2ytZjn2v+3EX4aKRXjIhsoGFzG8GCjfRirz3rwZf1wYbZzsNLTSgpw8VjQuWdp/jA==}
|
||||
oxlint-tsgolint@7.0.2001:
|
||||
resolution: {integrity: sha512-KjK/XLcXr1DSyonKhsuFqJRiuKqcyG9j3LJ8nkOsrLzGvodBPqzHOKauy10asLMDI0sUpvb+1sxlzff3udZvfg==}
|
||||
hasBin: true
|
||||
|
||||
oxlint@1.71.0:
|
||||
resolution: {integrity: sha512-U1m1X+C0vDj7DC1e13IoZULzEcPczE7UOMTs8VlZGHUEIUaSTZKo5qkPsQEfzpgnQ29Pea/w3Xntk62UCecxZw==}
|
||||
oxlint@1.75.0:
|
||||
resolution: {integrity: sha512-m9WzjRcRYA/uqIZDa9tclrieoPJ/ln1QYTKdFx6NUOs8uY5DiHlIwRQoCrHT6OM6O3ww3l2skY5gO7G7ZphE7g==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
hasBin: true
|
||||
peerDependencies:
|
||||
oxlint-tsgolint: '>=0.22.1'
|
||||
oxlint-tsgolint: '>=7.0.2001'
|
||||
vite-plus: '*'
|
||||
peerDependenciesMeta:
|
||||
oxlint-tsgolint:
|
||||
|
|
@ -6432,8 +6570,8 @@ packages:
|
|||
zod@4.4.3:
|
||||
resolution: {integrity: sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==}
|
||||
|
||||
zustand@5.0.13:
|
||||
resolution: {integrity: sha512-efI2tVaVQPqtOh114loML/Z80Y4NP3yc+Ff0fYiZJPauNeWZeIp/bRFD7I9bfmCOYBh/PHxlglQ9+wvlwnPikQ==}
|
||||
zustand@5.0.14:
|
||||
resolution: {integrity: sha512-/8tAspM5LMPr28b3fwLYrtdj77ECpfZviaP75CMTnwO8ISyaE4GDIG/9rDDYq/cH9D2Xw2A2RXglLInmVBQB/g==}
|
||||
engines: {node: '>=12.20.0'}
|
||||
peerDependencies:
|
||||
'@types/react': '>=18.0.0'
|
||||
|
|
@ -7159,10 +7297,79 @@ snapshots:
|
|||
'@open-draft/until@2.1.0':
|
||||
optional: true
|
||||
|
||||
'@opentelemetry/api@1.9.1':
|
||||
optional: true
|
||||
|
||||
'@oxc-parser/binding-android-arm-eabi@0.141.0':
|
||||
optional: true
|
||||
|
||||
'@oxc-parser/binding-android-arm64@0.141.0':
|
||||
optional: true
|
||||
|
||||
'@oxc-parser/binding-darwin-arm64@0.141.0':
|
||||
optional: true
|
||||
|
||||
'@oxc-parser/binding-darwin-x64@0.141.0':
|
||||
optional: true
|
||||
|
||||
'@oxc-parser/binding-freebsd-x64@0.141.0':
|
||||
optional: true
|
||||
|
||||
'@oxc-parser/binding-linux-arm-gnueabihf@0.141.0':
|
||||
optional: true
|
||||
|
||||
'@oxc-parser/binding-linux-arm-musleabihf@0.141.0':
|
||||
optional: true
|
||||
|
||||
'@oxc-parser/binding-linux-arm64-gnu@0.141.0':
|
||||
optional: true
|
||||
|
||||
'@oxc-parser/binding-linux-arm64-musl@0.141.0':
|
||||
optional: true
|
||||
|
||||
'@oxc-parser/binding-linux-ppc64-gnu@0.141.0':
|
||||
optional: true
|
||||
|
||||
'@oxc-parser/binding-linux-riscv64-gnu@0.141.0':
|
||||
optional: true
|
||||
|
||||
'@oxc-parser/binding-linux-riscv64-musl@0.141.0':
|
||||
optional: true
|
||||
|
||||
'@oxc-parser/binding-linux-s390x-gnu@0.141.0':
|
||||
optional: true
|
||||
|
||||
'@oxc-parser/binding-linux-x64-gnu@0.141.0':
|
||||
optional: true
|
||||
|
||||
'@oxc-parser/binding-linux-x64-musl@0.141.0':
|
||||
optional: true
|
||||
|
||||
'@oxc-parser/binding-openharmony-arm64@0.141.0':
|
||||
optional: true
|
||||
|
||||
'@oxc-parser/binding-wasm32-wasi@0.141.0':
|
||||
dependencies:
|
||||
'@emnapi/core': 1.11.2
|
||||
'@emnapi/runtime': 1.11.2
|
||||
'@napi-rs/wasm-runtime': 1.1.6(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2)
|
||||
optional: true
|
||||
|
||||
'@oxc-parser/binding-win32-arm64-msvc@0.141.0':
|
||||
optional: true
|
||||
|
||||
'@oxc-parser/binding-win32-ia32-msvc@0.141.0':
|
||||
optional: true
|
||||
|
||||
'@oxc-parser/binding-win32-x64-msvc@0.141.0':
|
||||
optional: true
|
||||
|
||||
'@oxc-project/runtime@0.101.0': {}
|
||||
|
||||
'@oxc-project/types@0.101.0': {}
|
||||
|
||||
'@oxc-project/types@0.141.0': {}
|
||||
|
||||
'@oxfmt/binding-android-arm-eabi@0.52.0':
|
||||
optional: true
|
||||
|
||||
|
|
@ -7220,79 +7427,79 @@ snapshots:
|
|||
'@oxfmt/binding-win32-x64-msvc@0.52.0':
|
||||
optional: true
|
||||
|
||||
'@oxlint-tsgolint/darwin-arm64@0.23.0':
|
||||
'@oxlint-tsgolint/darwin-arm64@7.0.2001':
|
||||
optional: true
|
||||
|
||||
'@oxlint-tsgolint/darwin-x64@0.23.0':
|
||||
'@oxlint-tsgolint/darwin-x64@7.0.2001':
|
||||
optional: true
|
||||
|
||||
'@oxlint-tsgolint/linux-arm64@0.23.0':
|
||||
'@oxlint-tsgolint/linux-arm64@7.0.2001':
|
||||
optional: true
|
||||
|
||||
'@oxlint-tsgolint/linux-x64@0.23.0':
|
||||
'@oxlint-tsgolint/linux-x64@7.0.2001':
|
||||
optional: true
|
||||
|
||||
'@oxlint-tsgolint/win32-arm64@0.23.0':
|
||||
'@oxlint-tsgolint/win32-arm64@7.0.2001':
|
||||
optional: true
|
||||
|
||||
'@oxlint-tsgolint/win32-x64@0.23.0':
|
||||
'@oxlint-tsgolint/win32-x64@7.0.2001':
|
||||
optional: true
|
||||
|
||||
'@oxlint/binding-android-arm-eabi@1.71.0':
|
||||
'@oxlint/binding-android-arm-eabi@1.75.0':
|
||||
optional: true
|
||||
|
||||
'@oxlint/binding-android-arm64@1.71.0':
|
||||
'@oxlint/binding-android-arm64@1.75.0':
|
||||
optional: true
|
||||
|
||||
'@oxlint/binding-darwin-arm64@1.71.0':
|
||||
'@oxlint/binding-darwin-arm64@1.75.0':
|
||||
optional: true
|
||||
|
||||
'@oxlint/binding-darwin-x64@1.71.0':
|
||||
'@oxlint/binding-darwin-x64@1.75.0':
|
||||
optional: true
|
||||
|
||||
'@oxlint/binding-freebsd-x64@1.71.0':
|
||||
'@oxlint/binding-freebsd-x64@1.75.0':
|
||||
optional: true
|
||||
|
||||
'@oxlint/binding-linux-arm-gnueabihf@1.71.0':
|
||||
'@oxlint/binding-linux-arm-gnueabihf@1.75.0':
|
||||
optional: true
|
||||
|
||||
'@oxlint/binding-linux-arm-musleabihf@1.71.0':
|
||||
'@oxlint/binding-linux-arm-musleabihf@1.75.0':
|
||||
optional: true
|
||||
|
||||
'@oxlint/binding-linux-arm64-gnu@1.71.0':
|
||||
'@oxlint/binding-linux-arm64-gnu@1.75.0':
|
||||
optional: true
|
||||
|
||||
'@oxlint/binding-linux-arm64-musl@1.71.0':
|
||||
'@oxlint/binding-linux-arm64-musl@1.75.0':
|
||||
optional: true
|
||||
|
||||
'@oxlint/binding-linux-ppc64-gnu@1.71.0':
|
||||
'@oxlint/binding-linux-ppc64-gnu@1.75.0':
|
||||
optional: true
|
||||
|
||||
'@oxlint/binding-linux-riscv64-gnu@1.71.0':
|
||||
'@oxlint/binding-linux-riscv64-gnu@1.75.0':
|
||||
optional: true
|
||||
|
||||
'@oxlint/binding-linux-riscv64-musl@1.71.0':
|
||||
'@oxlint/binding-linux-riscv64-musl@1.75.0':
|
||||
optional: true
|
||||
|
||||
'@oxlint/binding-linux-s390x-gnu@1.71.0':
|
||||
'@oxlint/binding-linux-s390x-gnu@1.75.0':
|
||||
optional: true
|
||||
|
||||
'@oxlint/binding-linux-x64-gnu@1.71.0':
|
||||
'@oxlint/binding-linux-x64-gnu@1.75.0':
|
||||
optional: true
|
||||
|
||||
'@oxlint/binding-linux-x64-musl@1.71.0':
|
||||
'@oxlint/binding-linux-x64-musl@1.75.0':
|
||||
optional: true
|
||||
|
||||
'@oxlint/binding-openharmony-arm64@1.71.0':
|
||||
'@oxlint/binding-openharmony-arm64@1.75.0':
|
||||
optional: true
|
||||
|
||||
'@oxlint/binding-win32-arm64-msvc@1.71.0':
|
||||
'@oxlint/binding-win32-arm64-msvc@1.75.0':
|
||||
optional: true
|
||||
|
||||
'@oxlint/binding-win32-ia32-msvc@1.71.0':
|
||||
'@oxlint/binding-win32-ia32-msvc@1.75.0':
|
||||
optional: true
|
||||
|
||||
'@oxlint/binding-win32-x64-msvc@1.71.0':
|
||||
'@oxlint/binding-win32-x64-msvc@1.75.0':
|
||||
optional: true
|
||||
|
||||
'@parcel/watcher-android-arm64@2.5.6':
|
||||
|
|
@ -11417,6 +11624,31 @@ snapshots:
|
|||
outvariant@1.4.3:
|
||||
optional: true
|
||||
|
||||
oxc-parser@0.141.0:
|
||||
dependencies:
|
||||
'@oxc-project/types': 0.141.0
|
||||
optionalDependencies:
|
||||
'@oxc-parser/binding-android-arm-eabi': 0.141.0
|
||||
'@oxc-parser/binding-android-arm64': 0.141.0
|
||||
'@oxc-parser/binding-darwin-arm64': 0.141.0
|
||||
'@oxc-parser/binding-darwin-x64': 0.141.0
|
||||
'@oxc-parser/binding-freebsd-x64': 0.141.0
|
||||
'@oxc-parser/binding-linux-arm-gnueabihf': 0.141.0
|
||||
'@oxc-parser/binding-linux-arm-musleabihf': 0.141.0
|
||||
'@oxc-parser/binding-linux-arm64-gnu': 0.141.0
|
||||
'@oxc-parser/binding-linux-arm64-musl': 0.141.0
|
||||
'@oxc-parser/binding-linux-ppc64-gnu': 0.141.0
|
||||
'@oxc-parser/binding-linux-riscv64-gnu': 0.141.0
|
||||
'@oxc-parser/binding-linux-riscv64-musl': 0.141.0
|
||||
'@oxc-parser/binding-linux-s390x-gnu': 0.141.0
|
||||
'@oxc-parser/binding-linux-x64-gnu': 0.141.0
|
||||
'@oxc-parser/binding-linux-x64-musl': 0.141.0
|
||||
'@oxc-parser/binding-openharmony-arm64': 0.141.0
|
||||
'@oxc-parser/binding-wasm32-wasi': 0.141.0
|
||||
'@oxc-parser/binding-win32-arm64-msvc': 0.141.0
|
||||
'@oxc-parser/binding-win32-ia32-msvc': 0.141.0
|
||||
'@oxc-parser/binding-win32-x64-msvc': 0.141.0
|
||||
|
||||
oxfmt@0.52.0:
|
||||
dependencies:
|
||||
tinypool: 2.1.0
|
||||
|
|
@ -11441,43 +11673,44 @@ snapshots:
|
|||
'@oxfmt/binding-win32-ia32-msvc': 0.52.0
|
||||
'@oxfmt/binding-win32-x64-msvc': 0.52.0
|
||||
|
||||
oxlint-plugin-react-doctor@0.2.10:
|
||||
oxlint-plugin-react-doctor@0.9.1:
|
||||
dependencies:
|
||||
'@typescript-eslint/types': 8.60.0
|
||||
eslint-scope: 9.1.2
|
||||
eslint-visitor-keys: 5.0.1
|
||||
oxc-parser: 0.141.0
|
||||
|
||||
oxlint-tsgolint@0.23.0:
|
||||
oxlint-tsgolint@7.0.2001:
|
||||
optionalDependencies:
|
||||
'@oxlint-tsgolint/darwin-arm64': 0.23.0
|
||||
'@oxlint-tsgolint/darwin-x64': 0.23.0
|
||||
'@oxlint-tsgolint/linux-arm64': 0.23.0
|
||||
'@oxlint-tsgolint/linux-x64': 0.23.0
|
||||
'@oxlint-tsgolint/win32-arm64': 0.23.0
|
||||
'@oxlint-tsgolint/win32-x64': 0.23.0
|
||||
'@oxlint-tsgolint/darwin-arm64': 7.0.2001
|
||||
'@oxlint-tsgolint/darwin-x64': 7.0.2001
|
||||
'@oxlint-tsgolint/linux-arm64': 7.0.2001
|
||||
'@oxlint-tsgolint/linux-x64': 7.0.2001
|
||||
'@oxlint-tsgolint/win32-arm64': 7.0.2001
|
||||
'@oxlint-tsgolint/win32-x64': 7.0.2001
|
||||
|
||||
oxlint@1.71.0(oxlint-tsgolint@0.23.0):
|
||||
oxlint@1.75.0(oxlint-tsgolint@7.0.2001):
|
||||
optionalDependencies:
|
||||
'@oxlint/binding-android-arm-eabi': 1.71.0
|
||||
'@oxlint/binding-android-arm64': 1.71.0
|
||||
'@oxlint/binding-darwin-arm64': 1.71.0
|
||||
'@oxlint/binding-darwin-x64': 1.71.0
|
||||
'@oxlint/binding-freebsd-x64': 1.71.0
|
||||
'@oxlint/binding-linux-arm-gnueabihf': 1.71.0
|
||||
'@oxlint/binding-linux-arm-musleabihf': 1.71.0
|
||||
'@oxlint/binding-linux-arm64-gnu': 1.71.0
|
||||
'@oxlint/binding-linux-arm64-musl': 1.71.0
|
||||
'@oxlint/binding-linux-ppc64-gnu': 1.71.0
|
||||
'@oxlint/binding-linux-riscv64-gnu': 1.71.0
|
||||
'@oxlint/binding-linux-riscv64-musl': 1.71.0
|
||||
'@oxlint/binding-linux-s390x-gnu': 1.71.0
|
||||
'@oxlint/binding-linux-x64-gnu': 1.71.0
|
||||
'@oxlint/binding-linux-x64-musl': 1.71.0
|
||||
'@oxlint/binding-openharmony-arm64': 1.71.0
|
||||
'@oxlint/binding-win32-arm64-msvc': 1.71.0
|
||||
'@oxlint/binding-win32-ia32-msvc': 1.71.0
|
||||
'@oxlint/binding-win32-x64-msvc': 1.71.0
|
||||
oxlint-tsgolint: 0.23.0
|
||||
'@oxlint/binding-android-arm-eabi': 1.75.0
|
||||
'@oxlint/binding-android-arm64': 1.75.0
|
||||
'@oxlint/binding-darwin-arm64': 1.75.0
|
||||
'@oxlint/binding-darwin-x64': 1.75.0
|
||||
'@oxlint/binding-freebsd-x64': 1.75.0
|
||||
'@oxlint/binding-linux-arm-gnueabihf': 1.75.0
|
||||
'@oxlint/binding-linux-arm-musleabihf': 1.75.0
|
||||
'@oxlint/binding-linux-arm64-gnu': 1.75.0
|
||||
'@oxlint/binding-linux-arm64-musl': 1.75.0
|
||||
'@oxlint/binding-linux-ppc64-gnu': 1.75.0
|
||||
'@oxlint/binding-linux-riscv64-gnu': 1.75.0
|
||||
'@oxlint/binding-linux-riscv64-musl': 1.75.0
|
||||
'@oxlint/binding-linux-s390x-gnu': 1.75.0
|
||||
'@oxlint/binding-linux-x64-gnu': 1.75.0
|
||||
'@oxlint/binding-linux-x64-musl': 1.75.0
|
||||
'@oxlint/binding-openharmony-arm64': 1.75.0
|
||||
'@oxlint/binding-win32-arm64-msvc': 1.75.0
|
||||
'@oxlint/binding-win32-ia32-msvc': 1.75.0
|
||||
'@oxlint/binding-win32-x64-msvc': 1.75.0
|
||||
oxlint-tsgolint: 7.0.2001
|
||||
|
||||
p-cancelable@2.1.1: {}
|
||||
|
||||
|
|
@ -12713,7 +12946,7 @@ snapshots:
|
|||
'@types/unist': 3.0.3
|
||||
vfile-message: 4.0.3
|
||||
|
||||
vitest@4.1.5(@types/node@25.9.5)(happy-dom@20.9.0)(msw@2.14.3(@types/node@25.9.5)(typescript@7.0.2))(rolldown-vite@7.3.1(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2)(@types/node@25.9.5)(jiti@2.7.0)(yaml@2.8.4)):
|
||||
vitest@4.1.5(@opentelemetry/api@1.9.1)(@types/node@25.9.5)(happy-dom@20.9.0)(msw@2.14.3(@types/node@25.9.5)(typescript@7.0.2))(rolldown-vite@7.3.1(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2)(@types/node@25.9.5)(jiti@2.7.0)(yaml@2.8.4)):
|
||||
dependencies:
|
||||
'@vitest/expect': 4.1.5
|
||||
'@vitest/mocker': 4.1.5(msw@2.14.3(@types/node@25.9.5)(typescript@7.0.2))(rolldown-vite@7.3.1(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2)(@types/node@25.9.5)(jiti@2.7.0)(yaml@2.8.4))
|
||||
|
|
@ -12736,6 +12969,7 @@ snapshots:
|
|||
vite: rolldown-vite@7.3.1(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2)(@types/node@25.9.5)(jiti@2.7.0)(yaml@2.8.4)
|
||||
why-is-node-running: 2.3.0
|
||||
optionalDependencies:
|
||||
'@opentelemetry/api': 1.9.1
|
||||
'@types/node': 25.9.5
|
||||
happy-dom: 20.9.0
|
||||
transitivePeerDependencies:
|
||||
|
|
@ -12877,7 +13111,7 @@ snapshots:
|
|||
|
||||
zod@4.4.3: {}
|
||||
|
||||
zustand@5.0.13(@types/react@19.2.17)(react@19.2.7)(use-sync-external-store@1.6.0(react@19.2.7)):
|
||||
zustand@5.0.14(@types/react@19.2.17)(react@19.2.7)(use-sync-external-store@1.6.0(react@19.2.7)):
|
||||
optionalDependencies:
|
||||
'@types/react': 19.2.17
|
||||
react: 19.2.7
|
||||
|
|
|
|||
|
|
@ -1114,14 +1114,15 @@ const WorktreeCard = React.memo(function WorktreeCard({
|
|||
},
|
||||
[hoverReview, openTaskPage, repo]
|
||||
)
|
||||
const hoverReviewProvider = hoverReview?.provider
|
||||
const hasExplicitLinkedReview =
|
||||
(hoverReview?.provider === 'github' && worktree.linkedPR !== null) ||
|
||||
(hoverReview?.provider === 'gitlab' && linkedGitLabMR !== null) ||
|
||||
(hoverReview?.provider === 'bitbucket' && linkedBitbucketPR !== null) ||
|
||||
(hoverReview?.provider === 'azure-devops' && linkedAzureDevOpsPR !== null) ||
|
||||
(hoverReview?.provider === 'gitea' && linkedGiteaPR !== null)
|
||||
(hoverReviewProvider === 'github' && worktree.linkedPR !== null) ||
|
||||
(hoverReviewProvider === 'gitlab' && linkedGitLabMR !== null) ||
|
||||
(hoverReviewProvider === 'bitbucket' && linkedBitbucketPR !== null) ||
|
||||
(hoverReviewProvider === 'azure-devops' && linkedAzureDevOpsPR !== null) ||
|
||||
(hoverReviewProvider === 'gitea' && linkedGiteaPR !== null)
|
||||
const handleUnlinkReview = useCallback(() => {
|
||||
switch (hoverReview?.provider) {
|
||||
switch (hoverReviewProvider) {
|
||||
case 'github':
|
||||
void updateWorktreeMeta(worktree.id, { linkedPR: null })
|
||||
return
|
||||
|
|
@ -1136,12 +1137,12 @@ const WorktreeCard = React.memo(function WorktreeCard({
|
|||
return
|
||||
case 'gitea':
|
||||
void updateWorktreeMeta(worktree.id, { linkedGiteaPR: null })
|
||||
return
|
||||
break
|
||||
case 'unsupported':
|
||||
case undefined:
|
||||
break
|
||||
}
|
||||
}, [hoverReview?.provider, updateWorktreeMeta, worktree.id])
|
||||
}, [hoverReviewProvider, updateWorktreeMeta, worktree.id])
|
||||
const handleOpenLinearIssueInOrca = useCallback(
|
||||
(e: React.MouseEvent) => {
|
||||
e.stopPropagation()
|
||||
|
|
|
|||
Loading…
Reference in New Issue