diff --git a/packages/cli-kit/package.json b/packages/cli-kit/package.json index daa30b9eab2..47105b5096d 100644 --- a/packages/cli-kit/package.json +++ b/packages/cli-kit/package.json @@ -115,6 +115,7 @@ "@opentelemetry/exporter-metrics-otlp-http": "0.57.0", "@opentelemetry/resources": "1.30.1", "@opentelemetry/sdk-metrics": "1.30.1", + "@vercel/detect-agent": "1.2.5", "ajv": "8.20.0", "ansi-escapes": "6.2.1", "archiver": "5.3.2", diff --git a/packages/cli-kit/src/private/node/analytics.ts b/packages/cli-kit/src/private/node/analytics.ts index 0e0b5df491d..38d2a6dd418 100644 --- a/packages/cli-kit/src/private/node/analytics.ts +++ b/packages/cli-kit/src/private/node/analytics.ts @@ -1,12 +1,20 @@ import {getLastSeenAuthMethod} from './session.js' import {getAutoUpgradeEnabled} from './conf-store.js' +import {detectedAgentEnvironmentVariables} from './context/agent.js' import {hashString} from '../../public/node/crypto.js' import {getPackageManager, packageManagerFromUserAgent} from '../../public/node/node-package-manager.js' import BaseCommand from '../../public/node/base-command.js' import {CommandContent} from '../../public/node/hooks/prerun.js' import * as metadata from '../../public/node/metadata.js' import {platformAndArch} from '../../public/node/os.js' -import {ciPlatform, cloudEnvironment, macAddress} from '../../public/node/context/local.js' +import { + alwaysLogAnalytics, + alwaysLogMetrics, + analyticsDisabled, + ciPlatform, + cloudEnvironment, + macAddress, +} from '../../public/node/context/local.js' import {cwd} from '../../public/node/path.js' import {currentProcessIsGlobal, inferPackageManagerForGlobalCLI} from '../../public/node/is-global.js' import {isWsl} from '../../public/node/system.js' @@ -115,14 +123,27 @@ export async function getEnvironmentData(config: Interfaces.Config): Promise allowedShopifyEnvironmentVariableNames.has(key)), +async function getShopifyEnvironmentVariables(env: NodeJS.ProcessEnv = process.env) { + const declaredVariables = Object.fromEntries( + Object.entries(env).filter(([key]) => allowedShopifyEnvironmentVariableNames.has(key)), ) + + // An `alwaysLog*` override still sends the event, so this can't be `analyticsDisabled()` alone. + if (monorailAnalyticsSkipped() && metricAnalyticsSkipped()) return declaredVariables + + return {...declaredVariables, ...(await detectedAgentEnvironmentVariables(env))} +} + +export function monorailAnalyticsSkipped(): boolean { + return !alwaysLogAnalytics() && analyticsDisabled() +} + +export function metricAnalyticsSkipped(): boolean { + return !alwaysLogMetrics() && analyticsDisabled() } function getPluginNames(config: Interfaces.Config) { diff --git a/packages/cli-kit/src/private/node/context/agent.test.ts b/packages/cli-kit/src/private/node/context/agent.test.ts new file mode 100644 index 00000000000..66105ba03a7 --- /dev/null +++ b/packages/cli-kit/src/private/node/context/agent.test.ts @@ -0,0 +1,236 @@ +import {detectedAgentEnvironmentVariables} from './agent.js' +import {determineAgent, type KnownAgentNames} from '@vercel/detect-agent' +import {afterEach, describe, expect, test, vi} from 'vitest' + +vi.mock('@vercel/detect-agent') +vi.mock('../../../public/node/output.js') + +const {determineAgent: realDetermineAgent} = + await vi.importActual('@vercel/detect-agent') + +function agentDetected(name: string) { + vi.mocked(determineAgent).mockResolvedValue({isAgent: true, agent: {name: name as KnownAgentNames}}) +} + +function noAgentDetected() { + vi.mocked(determineAgent).mockResolvedValue({isAgent: false, agent: undefined}) +} + +const declaredAgentVariableNames = ['SHOPIFY_CLI_AGENT_INFO', 'SHOPIFY_CLI_AGENT_IDS'] + +const legacyAgentVariableNames = [ + 'SHOPIFY_CLI_AGENT', + 'SHOPIFY_CLI_AGENT_VERSION', + 'SHOPIFY_CLI_AGENT_RUN_ID', + 'SHOPIFY_CLI_AGENT_SESSION_ID', + 'SHOPIFY_CLI_AGENT_PROVIDER', +] + +const agentVariableNamesReadByTheDependency = [ + 'AI_AGENT', + 'CURSOR_TRACE_ID', + 'CURSOR_AGENT', + 'CURSOR_EXTENSION_HOST_ROLE', + 'GEMINI_CLI', + 'CODEX_SANDBOX', + 'CODEX_CI', + 'CODEX_THREAD_ID', + 'ANTIGRAVITY_AGENT', + 'AUGMENT_AGENT', + 'OPENCODE_CLIENT', + 'CLAUDECODE', + 'CLAUDE_CODE', + 'CLAUDE_CODE_IS_COWORK', + 'REPL_ID', + 'COPILOT_MODEL', + 'COPILOT_ALLOW_ALL', + 'COPILOT_GITHUB_TOKEN', +] + +function stubDeclaredAgentVariablesEmpty() { + declaredAgentVariableNames.forEach((variableName) => vi.stubEnv(variableName, undefined)) +} + +// This host is often itself an agent session, and `AI_AGENT` outranks the rest of what the dependency reads. +function useRealDetectionWithCleanEnvironment() { + vi.mocked(determineAgent).mockImplementation(realDetermineAgent) + stubDeclaredAgentVariablesEmpty() + agentVariableNamesReadByTheDependency.forEach((variableName) => vi.stubEnv(variableName, undefined)) +} + +describe('detectedAgentEnvironmentVariables', () => { + afterEach(() => { + vi.unstubAllEnvs() + }) + + test('reports nothing when SHOPIFY_CLI_AGENT_INFO was declared, so a guess cannot clobber it', async () => { + agentDetected('claude') + + const got = await detectedAgentEnvironmentVariables({ + SHOPIFY_CLI_AGENT_INFO: 'n:shopify-ai-toolkit|v:1.0.0|p:anthropic|m:claude-opus-5', + }) + + expect(got).toEqual({}) + }) + + test('reports nothing when SHOPIFY_CLI_AGENT_IDS was declared', async () => { + agentDetected('claude') + + const got = await detectedAgentEnvironmentVariables({SHOPIFY_CLI_AGENT_IDS: 's:session-id|r:run-id'}) + + expect(got).toEqual({}) + }) + + test('leaves a declared SHOPIFY_CLI_AGENT_INFO value untouched', async () => { + agentDetected('claude') + const env = {SHOPIFY_CLI_AGENT_INFO: 'n:shopify-ai-toolkit|v:1.0.0'} + + await detectedAgentEnvironmentVariables(env) + + expect(env).toEqual({SHOPIFY_CLI_AGENT_INFO: 'n:shopify-ai-toolkit|v:1.0.0'}) + }) + + test.each(legacyAgentVariableNames)( + 'reports the detected agent when only the legacy %s was declared', + async (declaredVariableName) => { + agentDetected('devin') + + const got = await detectedAgentEnvironmentVariables({[declaredVariableName]: 'declared-by-the-producer'}) + + expect(got).toEqual({SHOPIFY_CLI_AGENT_INFO: 'n:devin', SHOPIFY_CLI_AGENT_DETECTED: 'true'}) + }, + ) + + test('reports the detected agent when only SHOPIFY_INVOKED_BY was declared', async () => { + agentDetected('devin') + + const got = await detectedAgentEnvironmentVariables({SHOPIFY_INVOKED_BY: 'shopify-ai-toolkit'}) + + expect(got).toEqual({SHOPIFY_CLI_AGENT_INFO: 'n:devin', SHOPIFY_CLI_AGENT_DETECTED: 'true'}) + }) + + test.each([ + ['undefined', undefined], + ['empty', ''], + ['whitespace-only', ' '], + ])('treats a %s declaration as absent and reports the detected agent', async (_description, declaredValue) => { + agentDetected('devin') + + const got = await detectedAgentEnvironmentVariables({ + SHOPIFY_CLI_AGENT_INFO: declaredValue, + SHOPIFY_CLI_AGENT_IDS: declaredValue, + }) + + expect(got).toEqual({SHOPIFY_CLI_AGENT_INFO: 'n:devin', SHOPIFY_CLI_AGENT_DETECTED: 'true'}) + }) + + test('reports the detected agent and a marker when nothing was declared', async () => { + agentDetected('devin') + + const got = await detectedAgentEnvironmentVariables({}) + + expect(got).toEqual({SHOPIFY_CLI_AGENT_INFO: 'n:devin', SHOPIFY_CLI_AGENT_DETECTED: 'true'}) + }) + + test('reports nothing when no agent is detected', async () => { + noAgentDetected() + + const got = await detectedAgentEnvironmentVariables({}) + + expect(got).toEqual({}) + }) + + test.each([ + ['claude', 'claude-code'], + ['gemini', 'gemini-cli'], + ])('reports the detected name %s using the toolkit name %s', async (detectedName, expectedName) => { + agentDetected(detectedName) + + const got = await detectedAgentEnvironmentVariables({}) + + expect(got).toEqual({SHOPIFY_CLI_AGENT_INFO: `n:${expectedName}`, SHOPIFY_CLI_AGENT_DETECTED: 'true'}) + }) + + test.each([ + ['a known name needing no translation', 'cursor'], + ['an arbitrary AI_AGENT pass-through value', 'claude-code_2-1-267_agent'], + ])('reports %s verbatim', async (_description, detectedName) => { + agentDetected(detectedName) + + const got = await detectedAgentEnvironmentVariables({}) + + expect(got).toEqual({SHOPIFY_CLI_AGENT_INFO: `n:${detectedName}`, SHOPIFY_CLI_AGENT_DETECTED: 'true'}) + }) + + test('strips the tag separator from the detected name so it cannot inject tags', async () => { + agentDetected('devin|v:9.9.9') + + const got = await detectedAgentEnvironmentVariables({}) + + expect(got).toEqual({SHOPIFY_CLI_AGENT_INFO: 'n:devinv:9.9.9', SHOPIFY_CLI_AGENT_DETECTED: 'true'}) + }) + + test.each([ + ['whitespace-only', ' '], + ['nothing but the tag separator', '|'], + ])('reports nothing when the detected name is %s', async (_description, detectedName) => { + agentDetected(detectedName) + + const got = await detectedAgentEnvironmentVariables({}) + + expect(got).toEqual({}) + }) + + test('reports nothing when detection fails', async () => { + vi.mocked(determineAgent).mockRejectedValue(new Error('EACCES: permission denied, stat /opt/.devin')) + + const got = await detectedAgentEnvironmentVariables({}) + + expect(got).toEqual({}) + }) + + test('does not mutate process.env when reporting a detected agent', async () => { + agentDetected('claude') + stubDeclaredAgentVariablesEmpty() + const environmentBefore = {...process.env} + + const got = await detectedAgentEnvironmentVariables() + + expect(got).toEqual({SHOPIFY_CLI_AGENT_INFO: 'n:claude-code', SHOPIFY_CLI_AGENT_DETECTED: 'true'}) + expect({...process.env}).toEqual(environmentBefore) + }) + + describe('against the real dependency', () => { + test('reports an arbitrary AI_AGENT value verbatim', async () => { + useRealDetectionWithCleanEnvironment() + vi.stubEnv('AI_AGENT', 'claude-code_2-1-267_agent') + + const got = await detectedAgentEnvironmentVariables() + + expect(got).toEqual({ + SHOPIFY_CLI_AGENT_INFO: 'n:claude-code_2-1-267_agent', + SHOPIFY_CLI_AGENT_DETECTED: 'true', + }) + }) + + // The dependency reports bare `claude`; only driving it for real proves the map matches its vocabulary. + test('reports a CLAUDECODE environment using the toolkit name', async () => { + useRealDetectionWithCleanEnvironment() + vi.stubEnv('CLAUDECODE', '1') + + const got = await detectedAgentEnvironmentVariables() + + expect(got).toEqual({SHOPIFY_CLI_AGENT_INFO: 'n:claude-code', SHOPIFY_CLI_AGENT_DETECTED: 'true'}) + }) + + test('reports nothing when a declaration exists, whatever the dependency would detect', async () => { + useRealDetectionWithCleanEnvironment() + vi.stubEnv('CLAUDECODE', '1') + vi.stubEnv('SHOPIFY_CLI_AGENT_IDS', 's:session-id') + + const got = await detectedAgentEnvironmentVariables() + + expect(got).toEqual({}) + }) + }) +}) diff --git a/packages/cli-kit/src/private/node/context/agent.ts b/packages/cli-kit/src/private/node/context/agent.ts new file mode 100644 index 00000000000..d911dd857ae --- /dev/null +++ b/packages/cli-kit/src/private/node/context/agent.ts @@ -0,0 +1,43 @@ +import {outputDebug} from '../../../public/node/output.js' +import {determineAgent} from '@vercel/detect-agent' + +const toolkitAgentNamesByDetectedName: {[detectedName: string]: string} = { + claude: 'claude-code', + gemini: 'gemini-cli', +} + +const explicitAgentVariableNames = ['SHOPIFY_CLI_AGENT_INFO', 'SHOPIFY_CLI_AGENT_IDS'] + +function hasExplicitAgentAttribution(env: NodeJS.ProcessEnv): boolean { + return explicitAgentVariableNames.some((variableName) => (env[variableName] ?? '').trim() !== '') +} + +export async function detectedAgentEnvironmentVariables( + env: NodeJS.ProcessEnv = process.env, +): Promise { + // Emitting while a declaration exists would clobber the producer's whole packed value, not just the name. + if (hasExplicitAgentAttribution(env)) return {} + + try { + const detection = await determineAgent() + if (!detection.isAgent) return {} + + // `|` separates tags, so a name containing one could otherwise inject tags nothing detected. + const detectedName = detection.agent.name.replaceAll('|', '').trim() + if (detectedName === '') return {} + + return { + SHOPIFY_CLI_AGENT_INFO: `n:${toolkitAgentNamesByDetectedName[detectedName] ?? detectedName}`, + SHOPIFY_CLI_AGENT_DETECTED: 'true', + } + + // eslint-disable-next-line no-catch-all/no-catch-all + } catch (error) { + let message = 'Unable to detect which AI agent is running the CLI' + if (error instanceof Error) { + message = message.concat(`: ${error.message}`) + } + outputDebug(message) + return {} + } +} diff --git a/packages/cli-kit/src/public/node/analytics.test.ts b/packages/cli-kit/src/public/node/analytics.test.ts index ea764c23fcc..cc020f82965 100644 --- a/packages/cli-kit/src/public/node/analytics.test.ts +++ b/packages/cli-kit/src/public/node/analytics.test.ts @@ -8,6 +8,8 @@ import { } from './analytics.js' import * as os from './os.js' import { + alwaysLogAnalytics, + alwaysLogMetrics, analyticsDisabled, ciPlatform, cloudEnvironment, @@ -28,9 +30,17 @@ import * as store from '../../private/node/analytics/storage.js' import {startAnalytics} from '../../private/node/analytics.js' import {CLI_KIT_VERSION} from '../common/version.js' import {setLastSeenAuthMethod, setLastSeenUserIdAfterAuth} from '../../private/node/session.js' +import {determineAgent} from '@vercel/detect-agent' import {test, expect, describe, vi, beforeEach, afterEach, MockedFunction} from 'vitest' import type BaseCommand from './base-command.js' +// `mockResolvedValue` would be wiped by `mockReset: true`, silently forcing every test onto the detection error path. +vi.mock('@vercel/detect-agent', () => { + return { + determineAgent: vi.fn(async () => ({isAgent: false, agent: undefined})), + } +}) + vi.mock('./context/local.js') vi.mock('./os.js') vi.mock('../../store.js') @@ -42,6 +52,11 @@ vi.mock('./cli.js') vi.mock('./error-handler.js') vi.mock('./system.js') +function stubDeclaredAgentVariablesEmpty(): void { + const declaredVariableNames = ['SHOPIFY_CLI_AGENT_INFO', 'SHOPIFY_CLI_AGENT_IDS'] + declaredVariableNames.forEach((variableName) => vi.stubEnv(variableName, undefined)) +} + function restoreEnvVariable(key: string, value: string | undefined): void { if (value === undefined) { delete process.env[key] @@ -73,6 +88,7 @@ describe('event tracking', () => { afterEach(() => { vi.useRealTimers() + vi.unstubAllEnvs() }) async function inProjectWithFile(file: string, execute: (args: string[]) => Promise): Promise { @@ -626,6 +642,133 @@ describe('event tracking', () => { } }) + test('adds detected agent variables when explicit attribution is missing', async () => { + stubDeclaredAgentVariablesEmpty() + vi.mocked(determineAgent).mockResolvedValueOnce({ + isAgent: true, + agent: {name: 'claude'}, + }) + + await inProjectWithFile('package.json', async (args) => { + const commandContent = {command: 'dev', topic: 'app'} + await startAnalytics({commandContent, args, currentTime: currentDate.getTime() - 100}) + + // When + const config = { + runHook: vi.fn().mockResolvedValue({successes: [], failures: []}), + plugins: [], + } as any + await reportAnalyticsEvent({config, exitMode: 'ok'}) + await sendReportedAnalyticsPayload() + + // Then + const sensitivePayload = publishEventMock.mock.calls[0]![2] + expect(publishEventMock).toHaveBeenCalledOnce() + + const shopifyVars = JSON.parse(sensitivePayload.env_shopify_variables as string) + expect(shopifyVars).toHaveProperty('SHOPIFY_CLI_AGENT_INFO', 'n:claude-code') + expect(shopifyVars).toHaveProperty('SHOPIFY_CLI_AGENT_DETECTED', 'true') + }) + }) + + test('does not add a detected agent to the payload when only SHOPIFY_CLI_AGENT_INFO is declared', async () => { + stubDeclaredAgentVariablesEmpty() + vi.stubEnv('SHOPIFY_CLI_AGENT_INFO', 'n:shopify-ai-toolkit|v:1.0.0|p:anthropic|m:claude-opus-5') + vi.mocked(determineAgent).mockResolvedValueOnce({isAgent: true, agent: {name: 'claude'}}) + + await inProjectWithFile('package.json', async (args) => { + const commandContent = {command: 'dev', topic: 'app'} + await startAnalytics({commandContent, args, currentTime: currentDate.getTime() - 100}) + + // When + const config = { + runHook: vi.fn().mockResolvedValue({successes: [], failures: []}), + plugins: [], + } as any + await reportAnalyticsEvent({config, exitMode: 'ok'}) + await sendReportedAnalyticsPayload() + + // Then + const sensitivePayload = publishEventMock.mock.calls[0]![2] + const shopifyVars = JSON.parse(sensitivePayload.env_shopify_variables as string) + expect(shopifyVars).toHaveProperty( + 'SHOPIFY_CLI_AGENT_INFO', + 'n:shopify-ai-toolkit|v:1.0.0|p:anthropic|m:claude-opus-5', + ) + expect(shopifyVars).not.toHaveProperty('SHOPIFY_CLI_AGENT_DETECTED') + }) + }) + + test('does not fail telemetry if determineAgent throws an error', async () => { + stubDeclaredAgentVariablesEmpty() + vi.mocked(determineAgent).mockRejectedValueOnce(new Error('EACCES: permission denied')) + + await inProjectWithFile('package.json', async (args) => { + const commandContent = {command: 'dev', topic: 'app'} + await startAnalytics({commandContent, args, currentTime: currentDate.getTime() - 100}) + + // When + const config = { + runHook: vi.fn().mockResolvedValue({successes: [], failures: []}), + plugins: [], + } as any + await reportAnalyticsEvent({config, exitMode: 'ok'}) + await sendReportedAnalyticsPayload() + + // Then + const sensitivePayload = publishEventMock.mock.calls[0]![2] + expect(publishEventMock).toHaveBeenCalledOnce() + + const shopifyVars = JSON.parse(sensitivePayload.env_shopify_variables as string) + expect(shopifyVars).not.toHaveProperty('SHOPIFY_CLI_AGENT_INFO') + expect(shopifyVars).not.toHaveProperty('SHOPIFY_CLI_AGENT_DETECTED') + }) + }) + + test('does not detect an agent when analytics are disabled', async () => { + await inProjectWithFile('package.json', async (args) => { + // Given + vi.mocked(analyticsDisabled).mockReturnValue(true) + const commandContent = {command: 'dev', topic: 'app'} + await startAnalytics({commandContent, args, currentTime: currentDate.getTime() - 100}) + + // When + const config = { + runHook: vi.fn().mockResolvedValue({successes: [], failures: []}), + plugins: [], + } as any + await reportAnalyticsEvent({config, exitMode: 'ok'}) + + // Then + expect(publishMonorailEvent).not.toHaveBeenCalled() + expect(determineAgent).not.toHaveBeenCalled() + }) + }) + + test.each([ + ['alwaysLogAnalytics', alwaysLogAnalytics], + ['alwaysLogMetrics', alwaysLogMetrics], + ])('still detects an agent when analytics are disabled but %s is on', async (_description, override) => { + await inProjectWithFile('package.json', async (args) => { + // Given + vi.mocked(analyticsDisabled).mockReturnValue(true) + vi.mocked(override).mockReturnValue(true) + stubDeclaredAgentVariablesEmpty() + const commandContent = {command: 'dev', topic: 'app'} + await startAnalytics({commandContent, args, currentTime: currentDate.getTime() - 100}) + + // When + const config = { + runHook: vi.fn().mockResolvedValue({successes: [], failures: []}), + plugins: [], + } as any + await reportAnalyticsEvent({config, exitMode: 'ok'}) + + // Then + expect(determineAgent).toHaveBeenCalledOnce() + }) + }) + test('does nothing when analytics are disabled', async () => { await inProjectWithFile('package.json', async (args) => { // Given diff --git a/packages/cli-kit/src/public/node/analytics.ts b/packages/cli-kit/src/public/node/analytics.ts index 574783f4af5..a9b168ec752 100644 --- a/packages/cli-kit/src/public/node/analytics.ts +++ b/packages/cli-kit/src/public/node/analytics.ts @@ -1,4 +1,4 @@ -import {alwaysLogAnalytics, alwaysLogMetrics, analyticsDisabled, ciPlatform, isShopify} from './context/local.js' +import {ciPlatform, isShopify} from './context/local.js' import * as metadata from './metadata.js' import {publishMonorailEvent, MONORAIL_COMMAND_TOPIC, type Schemas} from './monorail.js' import {fanoutHooks} from './plugins.js' @@ -12,7 +12,12 @@ import { compileData as storageCompileData, RuntimeData, } from '../../private/node/analytics/storage.js' -import {getEnvironmentData, getSensitiveEnvironmentData} from '../../private/node/analytics.js' +import { + getEnvironmentData, + getSensitiveEnvironmentData, + metricAnalyticsSkipped, + monorailAnalyticsSkipped, +} from '../../private/node/analytics.js' import {CLI_KIT_VERSION} from '../common/version.js' import {recordMetrics} from '../../private/node/otel-metrics.js' import {runWithRateLimit} from '../../private/node/conf-store.js' @@ -127,8 +132,8 @@ export async function reportAnalyticsEvent(options: ReportAnalyticsEventOptions) return } - const skipMonorailAnalytics = !alwaysLogAnalytics() && analyticsDisabled() - const skipMetricAnalytics = !alwaysLogMetrics() && analyticsDisabled() + const skipMonorailAnalytics = monorailAnalyticsSkipped() + const skipMetricAnalytics = metricAnalyticsSkipped() if (skipMonorailAnalytics && skipMetricAnalytics) { outputDebug(outputContent`Skipping command analytics, payload: ${outputToken.json(payload)}`) return diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 669d33d5bf2..4c68ae7959f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -352,6 +352,9 @@ importers: '@shopify/toml-patch': specifier: 0.3.0 version: 0.3.0 + '@vercel/detect-agent': + specifier: 1.2.5 + version: 1.2.5 ajv: specifier: 8.20.0 version: 8.20.0 @@ -853,48 +856,56 @@ packages: engines: {node: '>= 10'} cpu: [arm64] os: [linux] + libc: [glibc] '@ast-grep/napi-linux-arm64-gnu@0.43.0': resolution: {integrity: sha512-yJSRPxwwrvVW94J2rtaatcixSAGWcSaHNbAh6soXD6HXgq6I7uMc+cyMnJstFL789yd6Pu3QIhTlpD9VY0oYhw==, tarball: https://registry.npmjs.org/@ast-grep/napi-linux-arm64-gnu/-/napi-linux-arm64-gnu-0.43.0.tgz} engines: {node: '>= 10'} cpu: [arm64] os: [linux] + libc: [glibc] '@ast-grep/napi-linux-arm64-musl@0.34.1': resolution: {integrity: sha512-IXdqwTbkdqHrcuQb448Qzd82QdTqVFe/f0sSkFYQTic8P2qNzmiHsVnxgEFsQPPbe09BVAoZ885j3OnaNfcDYA==, tarball: https://registry.npmjs.org/@ast-grep/napi-linux-arm64-musl/-/napi-linux-arm64-musl-0.34.1.tgz} engines: {node: '>= 10'} cpu: [arm64] os: [linux] + libc: [musl] '@ast-grep/napi-linux-arm64-musl@0.43.0': resolution: {integrity: sha512-mknXLDsf66HvT/JEl18ZQSvR7/qWgWfqh3eHuVRqD2lE6cKBDXRnAzx9ZNZkUnL2Z5ph54Yk8dKVu09k45cegA==, tarball: https://registry.npmjs.org/@ast-grep/napi-linux-arm64-musl/-/napi-linux-arm64-musl-0.43.0.tgz} engines: {node: '>= 10'} cpu: [arm64] os: [linux] + libc: [musl] '@ast-grep/napi-linux-x64-gnu@0.34.1': resolution: {integrity: sha512-on4LyIeN/zN7SIh8zr5v+NTzVu3kXm2mG28ib1Qe9GVcf35dz52ckf7bilulayKSa2MHZWAXMjuc6NYMiNEw+w==, tarball: https://registry.npmjs.org/@ast-grep/napi-linux-x64-gnu/-/napi-linux-x64-gnu-0.34.1.tgz} engines: {node: '>= 10'} cpu: [x64] os: [linux] + libc: [glibc] '@ast-grep/napi-linux-x64-gnu@0.43.0': resolution: {integrity: sha512-KM6M5KKFsHG9Y7VKCKnMsWQQ1sYwj/SPdyr91SKp66AeFJ5xMtXb13WVQ3Joe9NEsi84dzzOBIJgMddz+UMvQw==, tarball: https://registry.npmjs.org/@ast-grep/napi-linux-x64-gnu/-/napi-linux-x64-gnu-0.43.0.tgz} engines: {node: '>= 10'} cpu: [x64] os: [linux] + libc: [glibc] '@ast-grep/napi-linux-x64-musl@0.34.1': resolution: {integrity: sha512-l1R5L9LOp0jTPjs8C+LUndZOA8cRw7PFlvoVxVbi2jCfcns00dqatSYc4yA/ke6ng2K0LSxjoV/jS8tefve0sA==, tarball: https://registry.npmjs.org/@ast-grep/napi-linux-x64-musl/-/napi-linux-x64-musl-0.34.1.tgz} engines: {node: '>= 10'} cpu: [x64] os: [linux] + libc: [musl] '@ast-grep/napi-linux-x64-musl@0.43.0': resolution: {integrity: sha512-NfjI74m7CEEOsLi7ZkYwcxY10CfKIHPHRrr9aqMulmnrC4FGvxQMk1qpDrTqkjmEd8LdZt3PsPrmBa8AZCErew==, tarball: https://registry.npmjs.org/@ast-grep/napi-linux-x64-musl/-/napi-linux-x64-musl-0.43.0.tgz} engines: {node: '>= 10'} cpu: [x64] os: [linux] + libc: [musl] '@ast-grep/napi-win32-arm64-msvc@0.34.1': resolution: {integrity: sha512-eVsdMtnY7jmN2xQjYY9gaqIxRHA44+QYivlP1uLbg8w3P4YlZWTFgOJ7aa357Hg/257mjeQCpodCkr0lGRsSYQ==, tarball: https://registry.npmjs.org/@ast-grep/napi-win32-arm64-msvc/-/napi-win32-arm64-msvc-0.34.1.tgz} @@ -2998,21 +3009,25 @@ packages: resolution: {integrity: sha512-CfzWaS+b32lI/inlYPv1ZAK9CWTWFHzT7TPThvOHML65nrgFl8cQ4Z4FeGdyCbHu2NoG3vR1E36O2tPI2/DLGg==, tarball: https://registry.npmjs.org/@nx/nx-linux-arm64-gnu/-/nx-linux-arm64-gnu-22.7.7.tgz} cpu: [arm64] os: [linux] + libc: [glibc] '@nx/nx-linux-arm64-musl@22.7.7': resolution: {integrity: sha512-53QFuODMEHc1gobCT2WOmYz89DZtEIuLphirdIgnXkkPBTdrP77LPbJUXMRXCMKr90BQaSWhTX+J/ubANRE8og==, tarball: https://registry.npmjs.org/@nx/nx-linux-arm64-musl/-/nx-linux-arm64-musl-22.7.7.tgz} cpu: [arm64] os: [linux] + libc: [musl] '@nx/nx-linux-x64-gnu@22.7.7': resolution: {integrity: sha512-unzmqGIDXGzujo1ZtbrMj2e5D5ldQ1feZmqDPhvO4casK2d96jpT8LtgIILpVDUfhLjl+By185gb0ArrWTsyKw==, tarball: https://registry.npmjs.org/@nx/nx-linux-x64-gnu/-/nx-linux-x64-gnu-22.7.7.tgz} cpu: [x64] os: [linux] + libc: [glibc] '@nx/nx-linux-x64-musl@22.7.7': resolution: {integrity: sha512-oTjMGuM105ok8aH5rlg2YP0Kgkjg0VfUj1exwp49S70gGBJ0r8v5rEtJwOSdCf1WTHuEh0xi66Y/b1S0khF8dg==, tarball: https://registry.npmjs.org/@nx/nx-linux-x64-musl/-/nx-linux-x64-musl-22.7.7.tgz} cpu: [x64] os: [linux] + libc: [musl] '@nx/nx-win32-arm64-msvc@22.7.7': resolution: {integrity: sha512-K741meG/l48TPPeDqnhYTV7pP+1ljjZ+0DRJBxMrPFIu8qKE3Abko/7NKWmWRjcSXJvtxvYkgG3wZds4N2Bhow==, tarball: https://registry.npmjs.org/@nx/nx-win32-arm64-msvc/-/nx-win32-arm64-msvc-22.7.7.tgz} @@ -3318,41 +3333,49 @@ packages: resolution: {integrity: sha512-0bJnmYFp62JdZ4nVMDUZ/C58BCZOCcqgKtnUlp7L9Ojf/czIN+3j72YlLPeWLkzlr6SlYvIQA4SGV/HyO0d+qg==, tarball: https://registry.npmjs.org/@oxc-resolver/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-11.20.0.tgz} cpu: [arm64] os: [linux] + libc: [glibc] '@oxc-resolver/binding-linux-arm64-musl@11.20.0': resolution: {integrity: sha512-wKHHzPKZo7Ufhv/Bt6yxT7FOgnIgW4gwXcJUipkShGp68W3wGVqvr1Sr0fY65lN0Oy6y41+g2kIDvkgZaMMUkw==, tarball: https://registry.npmjs.org/@oxc-resolver/binding-linux-arm64-musl/-/binding-linux-arm64-musl-11.20.0.tgz} cpu: [arm64] os: [linux] + libc: [musl] '@oxc-resolver/binding-linux-ppc64-gnu@11.20.0': resolution: {integrity: sha512-RN8goF7Ie0B79L4i4G6OeBocTgSC56vJbQ65VJje+oXnldVpLnOU7j/AQ/dP94TcCS+Yh6WG8u3Qt4ETteXFNQ==, tarball: https://registry.npmjs.org/@oxc-resolver/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-11.20.0.tgz} cpu: [ppc64] os: [linux] + libc: [glibc] '@oxc-resolver/binding-linux-riscv64-gnu@11.20.0': resolution: {integrity: sha512-5l1yU6/xQEqLZRzxqmMxJfWPslpwCmBsdDGaBvABPehxquCXDC7dd7oraNdKSJUMDXSM7VvVj8H2D2FTjU7oWw==, tarball: https://registry.npmjs.org/@oxc-resolver/binding-linux-riscv64-gnu/-/binding-linux-riscv64-gnu-11.20.0.tgz} cpu: [riscv64] os: [linux] + libc: [glibc] '@oxc-resolver/binding-linux-riscv64-musl@11.20.0': resolution: {integrity: sha512-xHEvkbgz6UC+A3JOyDQy76LkUaxsNSfIr3/GV8slwZsnuooJiIB34gzJfsyvR4JdCYNUUPsRJc/w/oWkODu+hg==, tarball: https://registry.npmjs.org/@oxc-resolver/binding-linux-riscv64-musl/-/binding-linux-riscv64-musl-11.20.0.tgz} cpu: [riscv64] os: [linux] + libc: [musl] '@oxc-resolver/binding-linux-s390x-gnu@11.20.0': resolution: {integrity: sha512-aWPDUUmSeyHvlW+SoEUd+JIJsQhVhu6a5tBpDRMu058naPAchTgAVGCFy35zjbnFlt0i8hLWziff6HX0D3LU4g==, tarball: https://registry.npmjs.org/@oxc-resolver/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-11.20.0.tgz} cpu: [s390x] os: [linux] + libc: [glibc] '@oxc-resolver/binding-linux-x64-gnu@11.20.0': resolution: {integrity: sha512-x2YeSimvhJjKLVD8KSu8f/rqU1potcdEMkApIPJqjZWN7c2Fpt4g2X32WDg1p+XDAmyT7nuQGe0vnhvXeLbH+g==, tarball: https://registry.npmjs.org/@oxc-resolver/binding-linux-x64-gnu/-/binding-linux-x64-gnu-11.20.0.tgz} cpu: [x64] os: [linux] + libc: [glibc] '@oxc-resolver/binding-linux-x64-musl@11.20.0': resolution: {integrity: sha512-kcRLEIxpZefeYfLChjpgFf3ilBzRDZ+yobMrpRsQlSrxuFGtm3U6PMU7AaEpMqo3NfDGVyJJseAjnRLzMFHjwQ==, tarball: https://registry.npmjs.org/@oxc-resolver/binding-linux-x64-musl/-/binding-linux-x64-musl-11.20.0.tgz} cpu: [x64] os: [linux] + libc: [musl] '@oxc-resolver/binding-openharmony-arm64@11.20.0': resolution: {integrity: sha512-HHcfnApSZGtKhTiHqe8OZruOZe5XuFQH5/E0Yhj3u8fnFvzkM4/k6WjacUf4SvA0SPEAbfbgYmVPuo0VX/fIBQ==, tarball: https://registry.npmjs.org/@oxc-resolver/binding-openharmony-arm64/-/binding-openharmony-arm64-11.20.0.tgz} @@ -3403,36 +3426,42 @@ packages: engines: {node: '>= 10.0.0'} cpu: [arm] os: [linux] + libc: [glibc] '@parcel/watcher-linux-arm-musl@2.5.6': resolution: {integrity: sha512-Ve3gUCG57nuUUSyjBq/MAM0CzArtuIOxsBdQ+ftz6ho8n7s1i9E1Nmk/xmP323r2YL0SONs1EuwqBp2u1k5fxg==, tarball: https://registry.npmjs.org/@parcel/watcher-linux-arm-musl/-/watcher-linux-arm-musl-2.5.6.tgz} engines: {node: '>= 10.0.0'} cpu: [arm] os: [linux] + libc: [musl] '@parcel/watcher-linux-arm64-glibc@2.5.6': resolution: {integrity: sha512-f2g/DT3NhGPdBmMWYoxixqYr3v/UXcmLOYy16Bx0TM20Tchduwr4EaCbmxh1321TABqPGDpS8D/ggOTaljijOA==, tarball: https://registry.npmjs.org/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.5.6.tgz} engines: {node: '>= 10.0.0'} cpu: [arm64] os: [linux] + libc: [glibc] '@parcel/watcher-linux-arm64-musl@2.5.6': resolution: {integrity: sha512-qb6naMDGlbCwdhLj6hgoVKJl2odL34z2sqkC7Z6kzir8b5W65WYDpLB6R06KabvZdgoHI/zxke4b3zR0wAbDTA==, tarball: https://registry.npmjs.org/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.5.6.tgz} engines: {node: '>= 10.0.0'} cpu: [arm64] os: [linux] + libc: [musl] '@parcel/watcher-linux-x64-glibc@2.5.6': resolution: {integrity: sha512-kbT5wvNQlx7NaGjzPFu8nVIW1rWqV780O7ZtkjuWaPUgpv2NMFpjYERVi0UYj1msZNyCzGlaCWEtzc+exjMGbQ==, tarball: https://registry.npmjs.org/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.5.6.tgz} engines: {node: '>= 10.0.0'} cpu: [x64] os: [linux] + libc: [glibc] '@parcel/watcher-linux-x64-musl@2.5.6': resolution: {integrity: sha512-1JRFeC+h7RdXwldHzTsmdtYR/Ku8SylLgTU/reMuqdVD7CtLwf0VR1FqeprZ0eHQkO0vqsbvFLXUmYm/uNKJBg==, tarball: https://registry.npmjs.org/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.5.6.tgz} engines: {node: '>= 10.0.0'} cpu: [x64] os: [linux] + libc: [musl] '@parcel/watcher-win32-arm64@2.5.6': resolution: {integrity: sha512-3ukyebjc6eGlw9yRt678DxVF7rjXatWiHvTXqphZLvo7aC5NdEgFufVwjFfY51ijYEWpXbqF5jtrK275z52D4Q==, tarball: https://registry.npmjs.org/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.5.6.tgz} @@ -3556,66 +3585,79 @@ packages: resolution: {integrity: sha512-t4ONHboXi/3E0rT6OZl1pKbl2Vgxf9vJfWgmUoCEVQVxhW6Cw/c8I6hbbu7DAvgp82RKiH7TpLwxnJeKv2pbsw==, tarball: https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.59.0.tgz} cpu: [arm] os: [linux] + libc: [glibc] '@rollup/rollup-linux-arm-musleabihf@4.59.0': resolution: {integrity: sha512-CikFT7aYPA2ufMD086cVORBYGHffBo4K8MQ4uPS/ZnY54GKj36i196u8U+aDVT2LX4eSMbyHtyOh7D7Zvk2VvA==, tarball: https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.59.0.tgz} cpu: [arm] os: [linux] + libc: [musl] '@rollup/rollup-linux-arm64-gnu@4.59.0': resolution: {integrity: sha512-jYgUGk5aLd1nUb1CtQ8E+t5JhLc9x5WdBKew9ZgAXg7DBk0ZHErLHdXM24rfX+bKrFe+Xp5YuJo54I5HFjGDAA==, tarball: https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.59.0.tgz} cpu: [arm64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-arm64-musl@4.59.0': resolution: {integrity: sha512-peZRVEdnFWZ5Bh2KeumKG9ty7aCXzzEsHShOZEFiCQlDEepP1dpUl/SrUNXNg13UmZl+gzVDPsiCwnV1uI0RUA==, tarball: https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.59.0.tgz} cpu: [arm64] os: [linux] + libc: [musl] '@rollup/rollup-linux-loong64-gnu@4.59.0': resolution: {integrity: sha512-gbUSW/97f7+r4gHy3Jlup8zDG190AuodsWnNiXErp9mT90iCy9NKKU0Xwx5k8VlRAIV2uU9CsMnEFg/xXaOfXg==, tarball: https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.59.0.tgz} cpu: [loong64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-loong64-musl@4.59.0': resolution: {integrity: sha512-yTRONe79E+o0FWFijasoTjtzG9EBedFXJMl888NBEDCDV9I2wGbFFfJQQe63OijbFCUZqxpHz1GzpbtSFikJ4Q==, tarball: https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.59.0.tgz} cpu: [loong64] os: [linux] + libc: [musl] '@rollup/rollup-linux-ppc64-gnu@4.59.0': resolution: {integrity: sha512-sw1o3tfyk12k3OEpRddF68a1unZ5VCN7zoTNtSn2KndUE+ea3m3ROOKRCZxEpmT9nsGnogpFP9x6mnLTCaoLkA==, tarball: https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.59.0.tgz} cpu: [ppc64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-ppc64-musl@4.59.0': resolution: {integrity: sha512-+2kLtQ4xT3AiIxkzFVFXfsmlZiG5FXYW7ZyIIvGA7Bdeuh9Z0aN4hVyXS/G1E9bTP/vqszNIN/pUKCk/BTHsKA==, tarball: https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.59.0.tgz} cpu: [ppc64] os: [linux] + libc: [musl] '@rollup/rollup-linux-riscv64-gnu@4.59.0': resolution: {integrity: sha512-NDYMpsXYJJaj+I7UdwIuHHNxXZ/b/N2hR15NyH3m2qAtb/hHPA4g4SuuvrdxetTdndfj9b1WOmy73kcPRoERUg==, tarball: https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.59.0.tgz} cpu: [riscv64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-riscv64-musl@4.59.0': resolution: {integrity: sha512-nLckB8WOqHIf1bhymk+oHxvM9D3tyPndZH8i8+35p/1YiVoVswPid2yLzgX7ZJP0KQvnkhM4H6QZ5m0LzbyIAg==, tarball: https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.59.0.tgz} cpu: [riscv64] os: [linux] + libc: [musl] '@rollup/rollup-linux-s390x-gnu@4.59.0': resolution: {integrity: sha512-oF87Ie3uAIvORFBpwnCvUzdeYUqi2wY6jRFWJAy1qus/udHFYIkplYRW+wo+GRUP4sKzYdmE1Y3+rY5Gc4ZO+w==, tarball: https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.59.0.tgz} cpu: [s390x] os: [linux] + libc: [glibc] '@rollup/rollup-linux-x64-gnu@4.59.0': resolution: {integrity: sha512-3AHmtQq/ppNuUspKAlvA8HtLybkDflkMuLK4DPo77DfthRb71V84/c4MlWJXixZz4uruIH4uaa07IqoAkG64fg==, tarball: https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.59.0.tgz} cpu: [x64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-x64-musl@4.59.0': resolution: {integrity: sha512-2UdiwS/9cTAx7qIUZB/fWtToJwvt0Vbo0zmnYt7ED35KPg13Q0ym1g442THLC7VyI6JfYTP4PiSOWyoMdV2/xg==, tarball: https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.59.0.tgz} cpu: [x64] os: [linux] + libc: [musl] '@rollup/rollup-openbsd-x64@4.59.0': resolution: {integrity: sha512-M3bLRAVk6GOwFlPTIxVBSYKUaqfLrn8l0psKinkCFxl4lQvOSz8ZrKDz2gxcBwHFpci0B6rttydI4IpS4IS/jQ==, tarball: https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.59.0.tgz} @@ -4124,41 +4166,49 @@ packages: resolution: {integrity: sha512-34gw7PjDGB9JgePJEmhEqBhWvCiiWCuXsL9hYphDF7crW7UgI05gyBAi6MF58uGcMOiOqSJ2ybEeCvHcq0BCmQ==, tarball: https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-gnu/-/resolver-binding-linux-arm64-gnu-1.11.1.tgz} cpu: [arm64] os: [linux] + libc: [glibc] '@unrs/resolver-binding-linux-arm64-musl@1.11.1': resolution: {integrity: sha512-RyMIx6Uf53hhOtJDIamSbTskA99sPHS96wxVE/bJtePJJtpdKGXO1wY90oRdXuYOGOTuqjT8ACccMc4K6QmT3w==, tarball: https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-musl/-/resolver-binding-linux-arm64-musl-1.11.1.tgz} cpu: [arm64] os: [linux] + libc: [musl] '@unrs/resolver-binding-linux-ppc64-gnu@1.11.1': resolution: {integrity: sha512-D8Vae74A4/a+mZH0FbOkFJL9DSK2R6TFPC9M+jCWYia/q2einCubX10pecpDiTmkJVUH+y8K3BZClycD8nCShA==, tarball: https://registry.npmjs.org/@unrs/resolver-binding-linux-ppc64-gnu/-/resolver-binding-linux-ppc64-gnu-1.11.1.tgz} cpu: [ppc64] os: [linux] + libc: [glibc] '@unrs/resolver-binding-linux-riscv64-gnu@1.11.1': resolution: {integrity: sha512-frxL4OrzOWVVsOc96+V3aqTIQl1O2TjgExV4EKgRY09AJ9leZpEg8Ak9phadbuX0BA4k8U5qtvMSQQGGmaJqcQ==, tarball: https://registry.npmjs.org/@unrs/resolver-binding-linux-riscv64-gnu/-/resolver-binding-linux-riscv64-gnu-1.11.1.tgz} cpu: [riscv64] os: [linux] + libc: [glibc] '@unrs/resolver-binding-linux-riscv64-musl@1.11.1': resolution: {integrity: sha512-mJ5vuDaIZ+l/acv01sHoXfpnyrNKOk/3aDoEdLO/Xtn9HuZlDD6jKxHlkN8ZhWyLJsRBxfv9GYM2utQ1SChKew==, tarball: https://registry.npmjs.org/@unrs/resolver-binding-linux-riscv64-musl/-/resolver-binding-linux-riscv64-musl-1.11.1.tgz} cpu: [riscv64] os: [linux] + libc: [musl] '@unrs/resolver-binding-linux-s390x-gnu@1.11.1': resolution: {integrity: sha512-kELo8ebBVtb9sA7rMe1Cph4QHreByhaZ2QEADd9NzIQsYNQpt9UkM9iqr2lhGr5afh885d/cB5QeTXSbZHTYPg==, tarball: https://registry.npmjs.org/@unrs/resolver-binding-linux-s390x-gnu/-/resolver-binding-linux-s390x-gnu-1.11.1.tgz} cpu: [s390x] os: [linux] + libc: [glibc] '@unrs/resolver-binding-linux-x64-gnu@1.11.1': resolution: {integrity: sha512-C3ZAHugKgovV5YvAMsxhq0gtXuwESUKc5MhEtjBpLoHPLYM+iuwSj3lflFwK3DPm68660rZ7G8BMcwSro7hD5w==, tarball: https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-gnu/-/resolver-binding-linux-x64-gnu-1.11.1.tgz} cpu: [x64] os: [linux] + libc: [glibc] '@unrs/resolver-binding-linux-x64-musl@1.11.1': resolution: {integrity: sha512-rV0YSoyhK2nZ4vEswT/QwqzqQXw5I6CjoaYMOX0TqBlWhojUf8P94mvI7nuJTeaCkkds3QE4+zS8Ko+GdXuZtA==, tarball: https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-musl/-/resolver-binding-linux-x64-musl-1.11.1.tgz} cpu: [x64] os: [linux] + libc: [musl] '@unrs/resolver-binding-wasm32-wasi@1.11.1': resolution: {integrity: sha512-5u4RkfxJm+Ng7IWgkzi3qrFOvLvQYnPBmjmZQ8+szTK/b31fQCnleNl1GgEt7nIsZRIf5PLhPwT0WM+q45x/UQ==, tarball: https://registry.npmjs.org/@unrs/resolver-binding-wasm32-wasi/-/resolver-binding-wasm32-wasi-1.11.1.tgz} @@ -4180,6 +4230,10 @@ packages: cpu: [x64] os: [win32] + '@vercel/detect-agent@1.2.5': + resolution: {integrity: sha512-0krENrjuitlW8s6TJu0MlqCevyCU7K7JK63jZAf7xZ6n17tx+vUEwzHT3sTxawtwZxaW21hu+oFUpoOrm49FsQ==, tarball: https://registry.npmjs.org/@vercel/detect-agent/-/detect-agent-1.2.5.tgz} + engines: {node: '>=14'} + '@vitejs/plugin-react@5.2.0': resolution: {integrity: sha512-YmKkfhOAi3wsB1PhJq5Scj3GXMn3WvtQ/JC0xoopuHoXSdmtdStOpFrYaT1kie2YgFBcIe64ROzMYRjCrYOdYw==, tarball: https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-5.2.0.tgz} engines: {node: ^20.19.0 || >=22.12.0} @@ -13057,6 +13111,8 @@ snapshots: '@unrs/resolver-binding-win32-x64-msvc@1.11.1': optional: true + '@vercel/detect-agent@1.2.5': {} + '@vitejs/plugin-react@5.2.0(vite@6.4.3(@types/node@26.1.1)(jiti@2.6.1)(sass@1.100.0)(tsx@4.23.1)(yaml@2.9.0))': dependencies: '@babel/core': 7.29.0