mirror of
https://github.com/trycua/computer.git
synced 2026-02-22 14:29:26 -06:00
Organize ts libs, add global workspace
This commit is contained in:
13
.vscode/computer-ts.code-workspace
vendored
13
.vscode/computer-ts.code-workspace
vendored
@@ -1,13 +0,0 @@
|
||||
{
|
||||
"folders": [
|
||||
{
|
||||
"name": "computer-ts",
|
||||
"path": "../libs/typescript/computer"
|
||||
}
|
||||
],
|
||||
"extensions": {
|
||||
"recommendations": [
|
||||
"biomejs.biome",
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
{
|
||||
"folders": [
|
||||
{
|
||||
"name": "core-ts",
|
||||
"path": "../libs/typescript/core"
|
||||
"name": "libs-ts",
|
||||
"path": "../libs/typescript"
|
||||
}
|
||||
],
|
||||
"extensions": {
|
||||
5
libs/typescript/.gitignore
vendored
Normal file
5
libs/typescript/.gitignore
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
node_modules
|
||||
|
||||
*.log
|
||||
.DS_Store
|
||||
.eslintcache
|
||||
@@ -38,6 +38,7 @@
|
||||
"prepublishOnly": "pnpm run build"
|
||||
},
|
||||
"dependencies": {
|
||||
"@cua/core": "link:../core",
|
||||
"pino": "^9.7.0",
|
||||
"ws": "^8.18.0"
|
||||
},
|
||||
|
||||
3
libs/typescript/computer/pnpm-lock.yaml
generated
3
libs/typescript/computer/pnpm-lock.yaml
generated
@@ -8,6 +8,9 @@ importers:
|
||||
|
||||
.:
|
||||
dependencies:
|
||||
'@cua/core':
|
||||
specifier: link:../core
|
||||
version: link:../core
|
||||
pino:
|
||||
specifier: ^9.7.0
|
||||
version: 9.7.0
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
onlyBuiltDependencies:
|
||||
- "@biomejs/biome"
|
||||
- sharp
|
||||
@@ -1,3 +1,4 @@
|
||||
import { Telemetry } from "@cua/core";
|
||||
import type { OSType } from "../../types";
|
||||
import type { BaseComputerConfig, Display, VMProviderType } from "../types";
|
||||
import pino from "pino";
|
||||
@@ -11,10 +12,18 @@ export abstract class BaseComputer {
|
||||
protected name: string;
|
||||
protected osType: OSType;
|
||||
protected vmProvider?: VMProviderType;
|
||||
protected telemetry: Telemetry
|
||||
|
||||
constructor(config: BaseComputerConfig) {
|
||||
this.name = config.name;
|
||||
this.osType = config.osType;
|
||||
this.telemetry = new Telemetry();
|
||||
this.telemetry.recordEvent('module_init', {
|
||||
module: "computer",
|
||||
version: process.env.npm_package_version,
|
||||
node_version: process.version,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,86 +0,0 @@
|
||||
{
|
||||
"$schema": "https://biomejs.dev/schemas/1.9.4/schema.json",
|
||||
"vcs": {
|
||||
"enabled": false,
|
||||
"clientKind": "git",
|
||||
"useIgnoreFile": false
|
||||
},
|
||||
"files": {
|
||||
"ignoreUnknown": false,
|
||||
"ignore": [
|
||||
"dist",
|
||||
"node_modules"
|
||||
]
|
||||
},
|
||||
"formatter": {
|
||||
"enabled": true,
|
||||
"useEditorconfig": true,
|
||||
"formatWithErrors": false,
|
||||
"indentStyle": "space",
|
||||
"indentWidth": 2,
|
||||
"lineEnding": "lf",
|
||||
"lineWidth": 80,
|
||||
"attributePosition": "auto",
|
||||
"bracketSpacing": true
|
||||
},
|
||||
"organizeImports": {
|
||||
"enabled": true
|
||||
},
|
||||
"linter": {
|
||||
"enabled": true,
|
||||
"rules": {
|
||||
"recommended": true,
|
||||
"style": {
|
||||
"useSelfClosingElements": "warn",
|
||||
"noUnusedTemplateLiteral": "warn",
|
||||
"noNonNullAssertion": "off"
|
||||
},
|
||||
"a11y": {
|
||||
"useMediaCaption": "off",
|
||||
"useKeyWithClickEvents": "warn",
|
||||
"useKeyWithMouseEvents": "warn",
|
||||
"noSvgWithoutTitle": "off",
|
||||
"useButtonType": "warn",
|
||||
"noAutofocus": "off"
|
||||
},
|
||||
"suspicious": {
|
||||
"noArrayIndexKey": "off"
|
||||
},
|
||||
"correctness": {
|
||||
"noUnusedVariables": "warn",
|
||||
"noUnusedFunctionParameters": "warn",
|
||||
"noUnusedImports": "warn"
|
||||
},
|
||||
"complexity": {
|
||||
"useOptionalChain": "info"
|
||||
},
|
||||
"nursery": {
|
||||
"useSortedClasses": {
|
||||
"level": "warn",
|
||||
"fix": "safe",
|
||||
"options": {
|
||||
"attributes": [
|
||||
"className"
|
||||
],
|
||||
"functions": [
|
||||
"cn"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"javascript": {
|
||||
"formatter": {
|
||||
"jsxQuoteStyle": "double",
|
||||
"quoteProperties": "asNeeded",
|
||||
"trailingCommas": "es5",
|
||||
"semicolons": "always",
|
||||
"arrowParentheses": "always",
|
||||
"bracketSameLine": false,
|
||||
"quoteStyle": "single",
|
||||
"attributePosition": "auto",
|
||||
"bracketSpacing": true
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -38,7 +38,10 @@
|
||||
"prepublishOnly": "pnpm run build"
|
||||
},
|
||||
"dependencies": {
|
||||
"pino": "^9.7.0"
|
||||
"@types/uuid": "^10.0.0",
|
||||
"pino": "^9.7.0",
|
||||
"posthog-node": "^5.1.1",
|
||||
"uuid": "^11.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@biomejs/biome": "^1.9.4",
|
||||
|
||||
5501
libs/typescript/core/pnpm-lock.yaml
generated
5501
libs/typescript/core/pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@@ -1,3 +1,7 @@
|
||||
export const myFunction = () => {
|
||||
return 'Hello, world!'
|
||||
}
|
||||
/**
|
||||
* This module provides the core telemetry functionality for CUA libraries.
|
||||
*
|
||||
* It provides a low-overhead way to collect anonymous usage data.
|
||||
*/
|
||||
|
||||
export * from './telemetry';
|
||||
|
||||
1
libs/typescript/core/src/telemetry/clients/index.ts
Normal file
1
libs/typescript/core/src/telemetry/clients/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export * from "./posthog";
|
||||
309
libs/typescript/core/src/telemetry/clients/posthog.ts
Normal file
309
libs/typescript/core/src/telemetry/clients/posthog.ts
Normal file
@@ -0,0 +1,309 @@
|
||||
/**
|
||||
* Telemetry client using PostHog for collecting anonymous usage data.
|
||||
*/
|
||||
|
||||
import { PostHog } from 'posthog-node';
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
import * as fs from 'node:fs';
|
||||
import * as path from 'node:path';
|
||||
import * as os from 'node:os';
|
||||
import { pino } from 'pino';
|
||||
const logger = pino({ name: 'core.telemetry' });
|
||||
|
||||
// Controls how frequently telemetry will be sent (percentage)
|
||||
export const TELEMETRY_SAMPLE_RATE = 100; // 100% sampling rate
|
||||
|
||||
// Public PostHog config for anonymous telemetry
|
||||
// These values are intentionally public and meant for anonymous telemetry only
|
||||
// https://posthog.com/docs/product-analytics/troubleshooting#is-it-ok-for-my-api-key-to-be-exposed-and-public
|
||||
export const PUBLIC_POSTHOG_API_KEY =
|
||||
'phc_eSkLnbLxsnYFaXksif1ksbrNzYlJShr35miFLDppF14';
|
||||
export const PUBLIC_POSTHOG_HOST = 'https://eu.i.posthog.com';
|
||||
|
||||
export class PostHogTelemetryClient {
|
||||
private config: {
|
||||
enabled: boolean;
|
||||
sampleRate: number;
|
||||
posthog: { apiKey: string; host: string };
|
||||
};
|
||||
private installationId: string;
|
||||
private initialized = false;
|
||||
private queuedEvents: {
|
||||
name: string;
|
||||
properties: Record<string, unknown>;
|
||||
timestamp: number;
|
||||
}[] = [];
|
||||
private startTime: number; // seconds
|
||||
private posthogClient?: PostHog;
|
||||
private counters: Record<string, number> = {};
|
||||
|
||||
constructor() {
|
||||
// set up config
|
||||
this.config = {
|
||||
enabled: true,
|
||||
sampleRate: TELEMETRY_SAMPLE_RATE,
|
||||
posthog: { apiKey: PUBLIC_POSTHOG_API_KEY, host: PUBLIC_POSTHOG_HOST },
|
||||
};
|
||||
// Check for multiple environment variables that can disable telemetry:
|
||||
// CUA_TELEMETRY=off to disable telemetry (legacy way)
|
||||
// CUA_TELEMETRY_DISABLED=1 to disable telemetry (new, more explicit way)
|
||||
const telemetryDisabled =
|
||||
process.env.CUA_TELEMETRY?.toLowerCase() === 'off' ||
|
||||
['1', 'true', 'yes', 'on'].includes(
|
||||
process.env.CUA_TELEMETRY_DISABLED?.toLowerCase() || ''
|
||||
);
|
||||
|
||||
this.config.enabled = !telemetryDisabled;
|
||||
this.config.sampleRate = Number.parseFloat(
|
||||
process.env.CUA_TELEMETRY_SAMPLE_RATE || String(TELEMETRY_SAMPLE_RATE)
|
||||
);
|
||||
// init client
|
||||
this.installationId = this._getOrCreateInstallationId();
|
||||
this.startTime = Date.now() / 1000; // Convert to seconds
|
||||
|
||||
// Log telemetry status on startup
|
||||
if (this.config.enabled) {
|
||||
logger.info(`Telemetry enabled (sampling at ${this.config.sampleRate}%)`);
|
||||
// Initialize PostHog client if config is available
|
||||
this._initializePosthog();
|
||||
} else {
|
||||
logger.info('Telemetry disabled');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get or create a random installation ID.
|
||||
* This ID is not tied to any personal information.
|
||||
*/
|
||||
private _getOrCreateInstallationId(): string {
|
||||
const homeDir = os.homedir();
|
||||
const idFile = path.join(homeDir, '.cua', 'installation_id');
|
||||
|
||||
try {
|
||||
if (fs.existsSync(idFile)) {
|
||||
return fs.readFileSync(idFile, 'utf-8').trim();
|
||||
}
|
||||
} catch (error) {
|
||||
logger.debug(`Failed to read installation ID: ${error}`);
|
||||
}
|
||||
|
||||
// Create new ID if not exists
|
||||
const newId = uuidv4();
|
||||
try {
|
||||
const dir = path.dirname(idFile);
|
||||
if (!fs.existsSync(dir)) {
|
||||
fs.mkdirSync(dir, { recursive: true });
|
||||
}
|
||||
fs.writeFileSync(idFile, newId);
|
||||
return newId;
|
||||
} catch (error) {
|
||||
logger.debug(`Failed to write installation ID: ${error}`);
|
||||
}
|
||||
|
||||
// Fallback to in-memory ID if file operations fail
|
||||
return newId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the PostHog client with configuration.
|
||||
*/
|
||||
private _initializePosthog(): boolean {
|
||||
if (this.initialized) {
|
||||
return true;
|
||||
}
|
||||
|
||||
try {
|
||||
this.posthogClient = new PostHog(this.config.posthog.apiKey, {
|
||||
host: this.config.posthog.host,
|
||||
flushAt: 20, // Number of events to batch before sending
|
||||
flushInterval: 30000, // Send events every 30 seconds
|
||||
});
|
||||
this.initialized = true;
|
||||
logger.debug('PostHog client initialized successfully');
|
||||
|
||||
// Process any queued events
|
||||
this._processQueuedEvents();
|
||||
return true;
|
||||
} catch (error) {
|
||||
logger.error(`Failed to initialize PostHog client: ${error}`);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Process any events that were queued before initialization.
|
||||
*/
|
||||
private _processQueuedEvents(): void {
|
||||
if (!this.posthogClient || this.queuedEvents.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (const event of this.queuedEvents) {
|
||||
this._captureEvent(event.name, event.properties);
|
||||
}
|
||||
this.queuedEvents = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Capture an event with PostHog.
|
||||
*/
|
||||
private _captureEvent(
|
||||
eventName: string,
|
||||
properties?: Record<string, unknown>
|
||||
): void {
|
||||
if (!this.posthogClient) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// Add standard properties
|
||||
const eventProperties = {
|
||||
...properties,
|
||||
version: process.env.npm_package_version || 'unknown',
|
||||
platform: process.platform,
|
||||
node_version: process.version,
|
||||
is_ci: this._isCI,
|
||||
};
|
||||
|
||||
this.posthogClient.capture({
|
||||
distinctId: this.installationId,
|
||||
event: eventName,
|
||||
properties: eventProperties,
|
||||
});
|
||||
} catch (error) {
|
||||
logger.debug(`Failed to capture event: ${error}`);
|
||||
}
|
||||
}
|
||||
|
||||
private get _isCI(): boolean {
|
||||
/**
|
||||
* Detect if running in CI environment.
|
||||
*/
|
||||
return !!(
|
||||
process.env.CI ||
|
||||
process.env.CONTINUOUS_INTEGRATION ||
|
||||
process.env.GITHUB_ACTIONS ||
|
||||
process.env.GITLAB_CI ||
|
||||
process.env.CIRCLECI ||
|
||||
process.env.TRAVIS ||
|
||||
process.env.JENKINS_URL
|
||||
);
|
||||
}
|
||||
|
||||
increment(counterName: string, value = 1) {
|
||||
/**
|
||||
* Increment a named counter.
|
||||
*/
|
||||
if (!this.config.enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(counterName in this.counters)) {
|
||||
this.counters[counterName] = 0;
|
||||
}
|
||||
this.counters[counterName] += value;
|
||||
}
|
||||
|
||||
recordEvent(eventName: string, properties?: Record<string, unknown>): void {
|
||||
/**
|
||||
* Record an event with optional properties.
|
||||
*/
|
||||
if (!this.config.enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Increment counter for this event type
|
||||
const counterKey = `event:${eventName}`;
|
||||
this.increment(counterKey);
|
||||
|
||||
// Apply sampling
|
||||
if (Math.random() * 100 > this.config.sampleRate) {
|
||||
return;
|
||||
}
|
||||
|
||||
const event = {
|
||||
name: eventName,
|
||||
properties: properties || {},
|
||||
timestamp: Date.now() / 1000,
|
||||
};
|
||||
|
||||
if (this.initialized && this.posthogClient) {
|
||||
this._captureEvent(eventName, properties);
|
||||
} else {
|
||||
// Queue event if not initialized
|
||||
this.queuedEvents.push(event);
|
||||
// Try to initialize again
|
||||
if (this.config.enabled && !this.initialized) {
|
||||
this._initializePosthog();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Flush any pending events to PostHog.
|
||||
*/
|
||||
async flush(): Promise<boolean> {
|
||||
if (!this.config.enabled || !this.posthogClient) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
// Send counter data as a single event
|
||||
if (Object.keys(this.counters).length > 0) {
|
||||
this._captureEvent('telemetry_counters', {
|
||||
counters: { ...this.counters },
|
||||
duration: Date.now() / 1000 - this.startTime,
|
||||
});
|
||||
}
|
||||
|
||||
await this.posthogClient.flush();
|
||||
logger.debug('Telemetry flushed successfully');
|
||||
|
||||
// Clear counters after sending
|
||||
this.counters = {};
|
||||
return true;
|
||||
} catch (error) {
|
||||
logger.debug(`Failed to flush telemetry: ${error}`);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
enable(): void {
|
||||
/**
|
||||
* Enable telemetry collection.
|
||||
*/
|
||||
this.config.enabled = true;
|
||||
logger.info('Telemetry enabled');
|
||||
if (!this.initialized) {
|
||||
this._initializePosthog();
|
||||
}
|
||||
}
|
||||
|
||||
async disable(): Promise<void> {
|
||||
/**
|
||||
* Disable telemetry collection.
|
||||
*/
|
||||
this.config.enabled = false;
|
||||
await this.posthogClient?.disable();
|
||||
logger.info('Telemetry disabled');
|
||||
}
|
||||
|
||||
get enabled(): boolean {
|
||||
/**
|
||||
* Check if telemetry is enabled.
|
||||
*/
|
||||
return this.config.enabled;
|
||||
}
|
||||
|
||||
async shutdown(): Promise<void> {
|
||||
/**
|
||||
* Shutdown the telemetry client and flush any pending events.
|
||||
*/
|
||||
if (this.posthogClient) {
|
||||
await this.flush();
|
||||
await this.posthogClient.shutdown();
|
||||
this.initialized = false;
|
||||
this.posthogClient = undefined;
|
||||
}
|
||||
}
|
||||
}
|
||||
7
libs/typescript/core/src/telemetry/index.ts
Normal file
7
libs/typescript/core/src/telemetry/index.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
/**
|
||||
* This module provides the core telemetry functionality for CUA libraries.
|
||||
*
|
||||
* It provides a low-overhead way to collect anonymous usage data.
|
||||
*/
|
||||
|
||||
export { PostHogTelemetryClient as Telemetry } from './clients';
|
||||
@@ -1,6 +0,0 @@
|
||||
import { expect, test } from 'vitest'
|
||||
import { myFunction } from '../src'
|
||||
|
||||
test('myFunction', () => {
|
||||
expect(myFunction()).toBe('Hello, world!')
|
||||
})
|
||||
30
libs/typescript/core/tests/telemetry.test.ts
Normal file
30
libs/typescript/core/tests/telemetry.test.ts
Normal file
@@ -0,0 +1,30 @@
|
||||
import { describe, it, expect, beforeEach } from 'vitest';
|
||||
import { Telemetry } from '../src/';
|
||||
|
||||
describe('Telemetry', () => {
|
||||
let telemetry: Telemetry;
|
||||
beforeEach(() => {
|
||||
process.env.CUA_TELEMETRY = '';
|
||||
process.env.CUA_TELEMETRY_DISABLED = '';
|
||||
telemetry = new Telemetry();
|
||||
});
|
||||
describe('telemetry.enabled', () => {
|
||||
it('should return false when CUA_TELEMETRY is off', () => {
|
||||
process.env.CUA_TELEMETRY = 'off';
|
||||
telemetry = new Telemetry();
|
||||
expect(telemetry.enabled).toBe(false);
|
||||
});
|
||||
|
||||
it('should return true when CUA_TELEMETRY is not set', () => {
|
||||
process.env.CUA_TELEMETRY = '';
|
||||
telemetry = new Telemetry();
|
||||
expect(telemetry.enabled).toBe(true);
|
||||
});
|
||||
|
||||
it('should return false if CUA_TELEMETRY_DISABLED is 1', () => {
|
||||
process.env.CUA_TELEMETRY_DISABLED = '1';
|
||||
telemetry = new Telemetry();
|
||||
expect(telemetry.enabled).toBe(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
21
libs/typescript/package.json
Normal file
21
libs/typescript/package.json
Normal file
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"name": "cua-ts",
|
||||
"version": "1.0.0",
|
||||
"description": "The c/ua typescript libs.",
|
||||
"keywords": [],
|
||||
"author": "c/ua",
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"lint": "biome lint .",
|
||||
"lint:fix": "biome lint --fix ."
|
||||
},
|
||||
"packageManager": "pnpm@10.6.5",
|
||||
"devDependencies": {
|
||||
"@biomejs/biome": "^1.9.4"
|
||||
},
|
||||
"pnpm": {
|
||||
"onlyBuiltDependencies": [
|
||||
"@biomejs/biome"
|
||||
]
|
||||
}
|
||||
}
|
||||
105
libs/typescript/pnpm-lock.yaml
generated
Normal file
105
libs/typescript/pnpm-lock.yaml
generated
Normal file
@@ -0,0 +1,105 @@
|
||||
lockfileVersion: '9.0'
|
||||
|
||||
settings:
|
||||
autoInstallPeers: true
|
||||
excludeLinksFromLockfile: false
|
||||
|
||||
importers:
|
||||
|
||||
.:
|
||||
devDependencies:
|
||||
'@biomejs/biome':
|
||||
specifier: ^1.9.4
|
||||
version: 1.9.4
|
||||
|
||||
packages:
|
||||
|
||||
'@biomejs/biome@1.9.4':
|
||||
resolution: {integrity: sha512-1rkd7G70+o9KkTn5KLmDYXihGoTaIGO9PIIN2ZB7UJxFrWw04CZHPYiMRjYsaDvVV7hP1dYNRLxSANLaBFGpog==}
|
||||
engines: {node: '>=14.21.3'}
|
||||
hasBin: true
|
||||
|
||||
'@biomejs/cli-darwin-arm64@1.9.4':
|
||||
resolution: {integrity: sha512-bFBsPWrNvkdKrNCYeAp+xo2HecOGPAy9WyNyB/jKnnedgzl4W4Hb9ZMzYNbf8dMCGmUdSavlYHiR01QaYR58cw==}
|
||||
engines: {node: '>=14.21.3'}
|
||||
cpu: [arm64]
|
||||
os: [darwin]
|
||||
|
||||
'@biomejs/cli-darwin-x64@1.9.4':
|
||||
resolution: {integrity: sha512-ngYBh/+bEedqkSevPVhLP4QfVPCpb+4BBe2p7Xs32dBgs7rh9nY2AIYUL6BgLw1JVXV8GlpKmb/hNiuIxfPfZg==}
|
||||
engines: {node: '>=14.21.3'}
|
||||
cpu: [x64]
|
||||
os: [darwin]
|
||||
|
||||
'@biomejs/cli-linux-arm64-musl@1.9.4':
|
||||
resolution: {integrity: sha512-v665Ct9WCRjGa8+kTr0CzApU0+XXtRgwmzIf1SeKSGAv+2scAlW6JR5PMFo6FzqqZ64Po79cKODKf3/AAmECqA==}
|
||||
engines: {node: '>=14.21.3'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
|
||||
'@biomejs/cli-linux-arm64@1.9.4':
|
||||
resolution: {integrity: sha512-fJIW0+LYujdjUgJJuwesP4EjIBl/N/TcOX3IvIHJQNsAqvV2CHIogsmA94BPG6jZATS4Hi+xv4SkBBQSt1N4/g==}
|
||||
engines: {node: '>=14.21.3'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
|
||||
'@biomejs/cli-linux-x64-musl@1.9.4':
|
||||
resolution: {integrity: sha512-gEhi/jSBhZ2m6wjV530Yy8+fNqG8PAinM3oV7CyO+6c3CEh16Eizm21uHVsyVBEB6RIM8JHIl6AGYCv6Q6Q9Tg==}
|
||||
engines: {node: '>=14.21.3'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
|
||||
'@biomejs/cli-linux-x64@1.9.4':
|
||||
resolution: {integrity: sha512-lRCJv/Vi3Vlwmbd6K+oQ0KhLHMAysN8lXoCI7XeHlxaajk06u7G+UsFSO01NAs5iYuWKmVZjmiOzJ0OJmGsMwg==}
|
||||
engines: {node: '>=14.21.3'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
|
||||
'@biomejs/cli-win32-arm64@1.9.4':
|
||||
resolution: {integrity: sha512-tlbhLk+WXZmgwoIKwHIHEBZUwxml7bRJgk0X2sPyNR3S93cdRq6XulAZRQJ17FYGGzWne0fgrXBKpl7l4M87Hg==}
|
||||
engines: {node: '>=14.21.3'}
|
||||
cpu: [arm64]
|
||||
os: [win32]
|
||||
|
||||
'@biomejs/cli-win32-x64@1.9.4':
|
||||
resolution: {integrity: sha512-8Y5wMhVIPaWe6jw2H+KlEm4wP/f7EW3810ZLmDlrEEy5KvBsb9ECEfu/kMWD484ijfQ8+nIi0giMgu9g1UAuuA==}
|
||||
engines: {node: '>=14.21.3'}
|
||||
cpu: [x64]
|
||||
os: [win32]
|
||||
|
||||
snapshots:
|
||||
|
||||
'@biomejs/biome@1.9.4':
|
||||
optionalDependencies:
|
||||
'@biomejs/cli-darwin-arm64': 1.9.4
|
||||
'@biomejs/cli-darwin-x64': 1.9.4
|
||||
'@biomejs/cli-linux-arm64': 1.9.4
|
||||
'@biomejs/cli-linux-arm64-musl': 1.9.4
|
||||
'@biomejs/cli-linux-x64': 1.9.4
|
||||
'@biomejs/cli-linux-x64-musl': 1.9.4
|
||||
'@biomejs/cli-win32-arm64': 1.9.4
|
||||
'@biomejs/cli-win32-x64': 1.9.4
|
||||
|
||||
'@biomejs/cli-darwin-arm64@1.9.4':
|
||||
optional: true
|
||||
|
||||
'@biomejs/cli-darwin-x64@1.9.4':
|
||||
optional: true
|
||||
|
||||
'@biomejs/cli-linux-arm64-musl@1.9.4':
|
||||
optional: true
|
||||
|
||||
'@biomejs/cli-linux-arm64@1.9.4':
|
||||
optional: true
|
||||
|
||||
'@biomejs/cli-linux-x64-musl@1.9.4':
|
||||
optional: true
|
||||
|
||||
'@biomejs/cli-linux-x64@1.9.4':
|
||||
optional: true
|
||||
|
||||
'@biomejs/cli-win32-arm64@1.9.4':
|
||||
optional: true
|
||||
|
||||
'@biomejs/cli-win32-x64@1.9.4':
|
||||
optional: true
|
||||
Reference in New Issue
Block a user