From 28f706fd9e7fcb165b24f67c596b5f253baabc6a Mon Sep 17 00:00:00 2001 From: Hannes Lenke Date: Thu, 15 Oct 2026 16:39:28 -0400 Subject: [PATCH 1/4] build(cli): bundle the CLI with esbuild and keep only 3 runtime deps MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit EXPERIMENTAL prototype, opened as a discardable draft PR — see the PR description for measurements, trade-offs and sequencing notes. - tsc output and 39 runtime dependencies are replaced by esbuild-bundled entries under dist/bundle/ (per-command entries + shared chunks, so commands stay lazy), reducing runtime deps to oxc-parser, @typescript-eslint/typescript-estree and jiti (none of which can be bundled: native binding, user-project resolution, runtime self-requires). - @oclif/core and the two oclif plugins move to devDependencies and are folded into the bundle; plugin-help was fully shadowed already. - bin/run.cjs enables Node's V8 compile cache (best effort, old-syntax safe for the version preflight). - New packageRoot() util anchors package-relative paths (ai-context, assets) that used to depend on module depth in dist/. - New startup-budget CI check (scripts/startup-check.mjs) fails the lint job if --version p50 exceeds 400ms (currently ~50ms). --- .github/workflows/test.yml | 5 + eslint.config.mjs | 3 + packages/cli/bin/launch.cjs | 20 +- packages/cli/bin/run.cjs | 14 + packages/cli/constructs.js | 2 +- packages/cli/package.json | 93 +++-- packages/cli/scripts/bundle.mjs | 108 +++++ packages/cli/scripts/startup-check.mjs | 52 +++ packages/cli/src/__tests__/node-floor.spec.ts | 22 +- packages/cli/src/cli.ts | 24 ++ packages/cli/src/commands/skills/index.ts | 11 +- .../src/constructs/internal/declaring-file.ts | 12 +- .../onboarding/__tests__/boilerplate.spec.ts | 6 + .../__tests__/detect-project.spec.ts | 7 + .../cli/src/helpers/onboarding/boilerplate.ts | 13 +- .../src/helpers/onboarding/template-prompt.ts | 9 +- packages/cli/src/hooks/check-update.ts | 9 + packages/cli/src/runtimes/snapshot.ts | 8 +- .../cli/src/services/__tests__/skills.spec.ts | 6 + packages/cli/src/services/package-root.ts | 42 ++ packages/cli/src/services/skills.ts | 7 +- pnpm-lock.yaml | 395 +++++++++++++++--- 22 files changed, 722 insertions(+), 146 deletions(-) create mode 100644 packages/cli/scripts/bundle.mjs create mode 100644 packages/cli/scripts/startup-check.mjs create mode 100644 packages/cli/src/cli.ts create mode 100644 packages/cli/src/hooks/check-update.ts create mode 100644 packages/cli/src/services/package-root.ts diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 3f8232311..9d0da007d 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -92,6 +92,11 @@ jobs: - run: pnpm install --frozen-lockfile # Test that the packaging works as well - run: pnpm -r pack + # Startup-time budget: catches new import-time work (e.g. a dependency + # doing real work at module load) that would otherwise silently slow + # every invocation without failing any test. Generous ceiling — this is + # a regression alarm, not a benchmark. + - run: pnpm --filter checkly run startup:check - run: pnpm run lint # --------------------------------------------------------------------------- diff --git a/eslint.config.mjs b/eslint.config.mjs index 91f9e698e..65c9db97b 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -52,6 +52,9 @@ export default defineConfig([ '**/syntax-error*', 'examples/*', 'benchmarks/*', + // Scratch space for agents (benchmarks, screenshots, attachments); + // gitignored and not part of any package. + '**/.context/', '**/*fixtures/', ]), { diff --git a/packages/cli/bin/launch.cjs b/packages/cli/bin/launch.cjs index b941940a1..53d424036 100644 --- a/packages/cli/bin/launch.cjs +++ b/packages/cli/bin/launch.cjs @@ -1,16 +1,14 @@ 'use strict' // Required by ./run.cjs only after the Node version preflight has passed. -// Everything is loaded with dynamic import() so this stays a CommonJS module: -// require() of the ESM dist or @oclif/core would throw -// ERR_REQUIRE_ASYNC_MODULE if any module in the graph ever adopted top-level -// await. Loading dotenv before @oclif/core also means .env values are visible -// to env vars read at import time (e.g. DEBUG, FORCE_COLOR). +// The CLI is the esbuild bundle at dist/bundle/cli.js (see scripts/bundle.mjs): +// it includes @oclif/core, all commands and every pure-JS dependency. Loading +// it with dynamic import() keeps this file CommonJS. oclif later dynamic-imports +// the same bundle path to resolve commands, which the Node module cache serves +// from this load, so there is exactly one instance of every module. External +// dependencies resolved at runtime (oxc-parser, typescript-estree) are looked +// up from this package's node_modules exactly as before. void (async () => { - const { loadDotenvFile } = await import('../dist/services/load-dotenv.js') - await loadDotenvFile() - - const { execute, settings } = await import('@oclif/core') - settings.enableAutoTranspile = false - await execute({ dir: __dirname }) + const { default: runChecklyCli } = await import('../dist/bundle/cli.js') + await runChecklyCli() })() diff --git a/packages/cli/bin/run.cjs b/packages/cli/bin/run.cjs index 81079376b..7d0b27a2b 100755 --- a/packages/cli/bin/run.cjs +++ b/packages/cli/bin/run.cjs @@ -29,4 +29,18 @@ if (!skipRequested && isCheckableNodeRuntime && belowMinimumVersion(currentVersi process.exit(1) } +// Cache V8 bytecode for the CLI bundle across runs (Node >= 22.8), so warm +// runs skip re-parsing the bundle entirely. Best effort: a no-op when the +// runtime does not provide it or the cache directory is not writable. +// Old-syntax only (var, no optional chaining): like the rest of this file, +// it must parse on runtimes old enough to need the version message above. +/* eslint-disable no-var */ +try { + var nodeModule = require('node:module') + if (nodeModule && typeof nodeModule.enableCompileCache === 'function') { + nodeModule.enableCompileCache() + } +// eslint-disable-next-line no-empty +} catch (err) {} /* eslint-enable no-var */ + require('./launch.cjs') diff --git a/packages/cli/constructs.js b/packages/cli/constructs.js index 90387eaf7..eaba85477 100644 --- a/packages/cli/constructs.js +++ b/packages/cli/constructs.js @@ -1,2 +1,2 @@ // eslint-disable-next-line -module.exports = require('./dist').constructs +module.exports = require('./dist/bundle/index.js').constructs diff --git a/packages/cli/package.json b/packages/cli/package.json index 552d14476..1c4b2f2b3 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -3,13 +3,30 @@ "version": "0.0.1-dev", "type": "module", "description": "Checkly CLI", - "main": "dist/index.js", + "main": "dist/bundle/index.js", "types": "dist/index.d.ts", "exports": { - ".": "./dist/index.js", - "./constructs": "./dist/constructs/index.js", - "./loader": "./dist/loader/index.js", - "./util": "./dist/util/index.js" + ".": { + "import": "./dist/bundle/index.js", + "require": "./dist/bundle/index.js", + "types": "./dist/index.d.ts" + }, + "./package.json": "./package.json", + "./constructs": { + "import": "./dist/bundle/constructs.js", + "require": "./dist/bundle/constructs.js", + "types": "./dist/constructs/index.d.ts" + }, + "./loader": { + "import": "./dist/bundle/loader.js", + "require": "./dist/bundle/loader.js", + "types": "./dist/loader/index.d.ts" + }, + "./util": { + "import": "./dist/bundle/util.js", + "require": "./dist/bundle/util.js", + "types": "./dist/util/index.d.ts" + } }, "engines": { "node": ">=22.13.0" @@ -20,7 +37,9 @@ "clean": "pnpm run clean:dist && pnpm run clean:gen", "prepack": "pnpm exec oclif manifest", "prepare:ai-context": "cross-env CHECKLY_SKIP_AUTH=1 CHECKLY_E2E_CLI_VERSION=99.0.0 ./bin/run.cjs import plan --root gen --debug-import-plan-input-file ./src/ai-context/context.fixtures.json && jiti ./scripts/prepare-ai-context.ts", - "prepare:dist": "tsc --build", + "bundle": "node scripts/bundle.mjs", + "startup:check": "node scripts/startup-check.mjs", + "prepare:dist": "tsc --build && pnpm run bundle", "prepare": "pnpm run clean && pnpm run prepare:dist && pnpm run prepare:ai-context", "test": "pnpm pack && pnpm run test:types && vitest --run", "test:types": "tsc -p tsconfig.type-tests.json --noEmit", @@ -40,6 +59,9 @@ "files": [ "/bin", "/dist", + "!/dist/**/*.js", + "!/dist/**/*.js.map", + "/dist/bundle", "/assets", "/constructs.js", "/constructs.d.ts", @@ -47,7 +69,7 @@ ], "oclif": { "bin": "checkly", - "commands": "./dist/commands", + "commands": "./dist/bundle/commands", "topicSeparator": " ", "additionalHelpFlags": [ "-h" @@ -56,13 +78,10 @@ "-v", "version" ], - "plugins": [ - "@oclif/plugin-help", - "@oclif/plugin-warn-if-update-available" - ], "hooks": { - "command_not_found": "./dist/hooks/command-not-found", - "finally": "./dist/hooks/parse-error" + "init": "./dist/bundle/hooks/check-update.js", + "command_not_found": "./dist/bundle/hooks/command-not-found.js", + "finally": "./dist/bundle/hooks/parse-error.js" }, "warn-if-update-available": { "timeoutInDays": 30, @@ -106,16 +125,29 @@ "description": "Inspect recorded test sessions." } }, - "helpClass": "./dist/help/help-extension.js" + "helpClass": "./dist/bundle/help/help-extension.js" }, "bin": { "checkly": "./bin/run.cjs" }, "homepage": "https://github.com/checkly/checkly-cli#readme", "dependencies": { + "jiti": "^2.7.0", + "oxc-parser": "0.153.0" + }, + "devDependencies": { "@oclif/core": "^5.1.7", - "@oclif/plugin-help": "^7.0.4", "@oclif/plugin-warn-if-update-available": "^4.0.3", + "@playwright/test": "^1.64.0", + "@types/archiver": "^8.0.0", + "@types/debug": "^4.1.13", + "@types/luxon": "^3.7.6", + "@types/node": "^22.19.17", + "@types/prompts": "^2.4.9", + "@types/semver": "^7.8.0", + "@types/ws": "^8.18.2", + "@typescript-eslint/types": "^8.71.1", + "@typescript-eslint/typescript-estree": "^8.71.1", "acorn": "^8.19.0", "acorn-walk": "^8.3.5", "archiver": "^8.0.0", @@ -124,15 +156,17 @@ "chalk": "^6.0.1", "ci-info": "^4.4.0", "conf": "^15.1.0", + "config": "^5.0.1", + "cross-env": "^10.1.0", "debug": "^4.4.3", "dotenv": "^18.0.7", + "esbuild": "^0.28.2", "execa": "^10.1.0", "git-repo-info": "^2.1.1", "glob": "^13.0.6", "http-proxy-agent": "^9.1.0", "https-proxy-agent": "^9.1.0", "indent-string": "^5.0.0", - "jiti": "^2.7.0", "json-stream-stringify": "^3.1.7", "json5": "^2.2.3", "jwt-decode": "^4.0.0", @@ -140,36 +174,21 @@ "luxon": "^3.7.2", "minimatch": "^10.2.6", "mqtt": "^5.16.0", + "nanoid": "^6.0.2", + "oclif": "^6.0.8", "open": "^11.0.4", - "oxc-parser": "0.153.0", "p-queue": "^9.3.4", "prompts": "^2.4.2", "proxy-from-env": "^2.1.0", "recast": "^0.24.0", + "rimraf": "^6.1.3", "semver": "^7.8.5", "socks-proxy-agent": "^10.1.0", "string-width": "^8.3.0", - "uuid": "^14.0.3", - "yaml": "^2.9.1" - }, - "devDependencies": { - "@playwright/test": "^1.64.0", - "@types/archiver": "^8.0.0", - "@types/debug": "^4.1.13", - "@types/luxon": "^3.7.6", - "@types/node": "^22.19.17", - "@types/prompts": "^2.4.9", - "@types/semver": "^7.8.0", - "@types/ws": "^8.18.2", - "@typescript-eslint/types": "^8.71.1", - "@typescript-eslint/typescript-estree": "^8.71.1", - "config": "^5.0.1", - "cross-env": "^10.1.0", - "nanoid": "^6.0.2", - "oclif": "^6.0.8", - "rimraf": "^6.1.3", "tar": "^7.5.22", "typescript": "^6.0.3", - "vitest": "^3.2.7" + "uuid": "^14.0.3", + "vitest": "^3.2.7", + "yaml": "^2.9.1" } } diff --git a/packages/cli/scripts/bundle.mjs b/packages/cli/scripts/bundle.mjs new file mode 100644 index 000000000..fb96f0a79 --- /dev/null +++ b/packages/cli/scripts/bundle.mjs @@ -0,0 +1,108 @@ +#!/usr/bin/env node +/** + * Bundles the compiled tsc output in dist/ into dist/bundle/ (a Shopify-style + * bundle, adapted for lazy command loading): + * + * - One ESM entry per oclif command (mirroring dist/commands/**), plus small + * entries for the CLI bootstrap, hooks, the help class and the public API + * surface. esbuild code splitting puts shared modules in dist/bundle/chunks, + * so a command entry only loads the chunks it actually uses — a run of + * `checkly env ls` never evaluates the mqtt or archiver graphs. + * - oclif discovers commands with its default pattern strategy from + * dist/bundle/commands (see oclif.commands in package.json), exactly as it + * did from dist/commands before bundling. Loading stays lazy: no command + * module is evaluated until one is actually needed. + * + * Only native or resolution-sensitive dependencies stay external: + * - oxc-parser: Rust native bindings resolved per platform at runtime. + * - @typescript-eslint/typescript-estree: a peer-dependent parser that + * resolves the *user's project's* TypeScript via createRequire, so it must + * stay an installed runtime dependency. + * - jiti: lazy-requires sibling files from its own package at runtime + * (e.g. dist/babel.cjs), which cannot be satisfied from a bundle. + * - typescript: never bundled (peer of the above, resolved from the user's + * project when needed). + */ +import { build } from 'esbuild' +import { readdirSync, rmSync, mkdirSync } from 'node:fs' +import path from 'node:path' +import { fileURLToPath } from 'node:url' + +const __dirname = path.dirname(fileURLToPath(import.meta.url)) +const pkgRoot = path.resolve(__dirname, '..') +const outDir = path.join(pkgRoot, 'dist', 'bundle') + +function walk (dir, base = dir) { + const entries = [] + for (const entry of readdirSync(dir, { withFileTypes: true })) { + if (entry.isDirectory()) { + if (entry.name === '__tests__') continue + entries.push(...walk(path.join(dir, entry.name), base)) + } else if (entry.name.endsWith('.js') && !entry.name.endsWith('.d.js') && !entry.name.endsWith('.js.map')) { + entries.push(path.join(dir, entry.name)) + } + } + return entries +} + +const commandFiles = walk(path.join(pkgRoot, 'dist', 'commands')) + +const entryPoints = [ + // The CLI bootstrap that bin/launch.cjs imports (dotenv + oclif execute). + { in: 'dist/cli.js', out: 'cli' }, + // Hooks and the help class, wired up by oclif.hooks / oclif.helpClass in + // package.json. + { in: 'dist/hooks/command-not-found.js', out: 'hooks/command-not-found' }, + { in: 'dist/hooks/parse-error.js', out: 'hooks/parse-error' }, + { in: 'dist/hooks/check-update.js', out: 'hooks/check-update' }, + { in: 'dist/help/help-extension.js', out: 'help/help-extension' }, + // The public API surface (package.json "exports"). + { in: 'dist/index.js', out: 'index' }, + { in: 'dist/constructs/index.js', out: 'constructs' }, + { in: 'dist/loader/index.js', out: 'loader' }, + { in: 'dist/util/index.js', out: 'util' }, + // One entry per command, mirroring the dist/commands layout so oclif's + // pattern strategy derives the same command IDs as before bundling. + ...commandFiles.map(file => ({ + in: path.relative(pkgRoot, file), + out: path.join('commands', path.relative(path.join(pkgRoot, 'dist', 'commands'), file).replace(/\.js$/, '')), + })), +] + +rmSync(outDir, { recursive: true, force: true }) +mkdirSync(outDir, { recursive: true }) + +const result = await build({ + absWorkingDir: pkgRoot, + entryPoints, + bundle: true, + format: 'esm', + platform: 'node', + target: 'node22.13', + splitting: true, + outdir: 'dist/bundle', + // Shared code goes to dist/bundle/chunks/ so oclif's command glob over + // dist/bundle/commands only ever sees command entries. + chunkNames: 'chunks/[name]-[hash]', + // Bundled CJS dependencies (e.g. supports-color via debug) call require() + // for node builtins at runtime. esbuild's ESM output can only resolve those + // when a require function exists in scope; this banner supplies one. + banner: { + js: [ + 'import { createRequire as __bannerCreateRequire } from \'node:module\'', + 'const require = __bannerCreateRequire(import.meta.url)', + ].join('\n'), + }, + external: ['oxc-parser', '@typescript-eslint/typescript-estree', 'jiti', 'typescript'], + metafile: true, + logLevel: 'warning', +}) + +let commandEntriesCount = 0 +let bytes = 0 +for (const [file, meta] of Object.entries(result.metafile.outputs)) { + bytes += meta.bytes + if (file.includes('/commands/')) commandEntriesCount++ +} +// eslint-disable-next-line no-console +console.log(`Bundle: ${entryPoints.length} entries (${commandEntriesCount} commands), ${Object.keys(result.metafile.outputs).length} files, ${(bytes / 1e6).toFixed(1)} MB`) diff --git a/packages/cli/scripts/startup-check.mjs b/packages/cli/scripts/startup-check.mjs new file mode 100644 index 000000000..c7f694422 --- /dev/null +++ b/packages/cli/scripts/startup-check.mjs @@ -0,0 +1,52 @@ +#!/usr/bin/env node +/** + * Startup budget check for CI. + * + * Startup performance regresses silently: any dependency that does real work + * at module load (or an accidental eager import in a command entry's chunk + * graph) adds cost to every invocation, forever, without failing any test. + * This script turns today's startup time into an enforced ceiling. + * + * The budget is deliberately generous (local p50 is ~50ms, CI machines are + * slower and noisier): it is a regression alarm, not a benchmark. + */ +import { spawnSync } from 'node:child_process' +import { existsSync } from 'node:fs' +import path from 'node:path' +import { fileURLToPath } from 'node:url' + +const __dirname = path.dirname(fileURLToPath(import.meta.url)) +const pkgRoot = path.resolve(__dirname, '..') +const runCjs = path.join(pkgRoot, 'bin', 'run.cjs') + +const RUNS = 20 +const WARMUP = 5 +const P50_BUDGET_MS = 400 + +if (!existsSync(path.join(pkgRoot, 'dist', 'bundle'))) { + // eslint-disable-next-line no-console + console.error('dist/bundle is missing — run `pnpm --filter checkly run prepare` first') + process.exit(1) +} + +function runOnce () { + const t0 = performance.now() + const result = spawnSync(process.execPath, [runCjs, '--version'], { encoding: 'utf8' }) + if (result.status !== 0) { + throw new Error(`--version exited with ${result.status}: ${result.stderr}`) + } + return performance.now() - t0 +} + +for (let i = 0; i < WARMUP; i++) runOnce() +const samples = [] +for (let i = 0; i < RUNS; i++) samples.push(runOnce()) +samples.sort((a, b) => a - b) +const p50 = samples[Math.floor(samples.length / 2)] +// eslint-disable-next-line no-console +console.log(`checkly --version p50 over ${RUNS} runs: ${p50.toFixed(1)}ms (budget ${P50_BUDGET_MS}ms)`) +if (p50 > P50_BUDGET_MS) { + // eslint-disable-next-line no-console + console.error(`Startup budget exceeded: p50 ${p50.toFixed(1)}ms > ${P50_BUDGET_MS}ms. Something probably added import-time work — check which chunks the command entries pull in (scripts/bundle.mjs) and what evaluates at module load.`) + process.exit(1) +} diff --git a/packages/cli/src/__tests__/node-floor.spec.ts b/packages/cli/src/__tests__/node-floor.spec.ts index 33b9b06f3..029487a73 100644 --- a/packages/cli/src/__tests__/node-floor.spec.ts +++ b/packages/cli/src/__tests__/node-floor.spec.ts @@ -70,22 +70,30 @@ describe('Node version floor', () => { })).not.toThrow() }) - it('requires only dependency-free siblings before the version check', () => { + it('requires only the preflight, a Node builtin and the launcher before the version check', () => { // Requiring anything outside bin/ from the entry would evaluate code that - // unsupported runtimes may not be able to load. + // unsupported runtimes may not be able to load. The node:module builtin + // (for the V8 compile cache) is safe: it ships with the runtime. const binRun = stripLineComments(readBin('run.cjs')) const requires = [...binRun.matchAll(/require\(([^)]*)\)/g)].map(match => match[1]) - expect(requires).toEqual(['\'./check-node-version.cjs\'', '\'./launch.cjs\'']) + expect(requires).toEqual(['\'./check-node-version.cjs\'', '\'node:module\'', '\'./launch.cjs\'']) expect(stripLineComments(readBin('check-node-version.cjs'))).not.toMatch(/\brequire\(/) }) it('loads the CLI only via dynamic import after the version check', () => { const launch = readBin('launch.cjs') - // The dotenv loading step is otherwise unasserted (the spawn tests pass - // without it), and require() of the ESM dist or @oclif/core would break - // if their graphs ever adopted top-level await. - expect(launch).toMatch(/await import\('\.\.\/dist\/services\/load-dotenv\.js'\)/) + // require() of the ESM bundle would break if its graph ever adopted + // top-level await; dynamic import() keeps the launcher CommonJS. + expect(launch).toMatch(/await import\('\.\.\/dist\/bundle\/cli\.js'\)/) expect(stripLineComments(launch)).not.toMatch(/\brequire\(/) + // The dotenv step moved inside the bundle entry; keep it ordered before + // @oclif/core so .env values are visible to env vars read at import + // time (e.g. DEBUG, FORCE_COLOR). + const cliEntry = fs.readFileSync(path.join(packageDir, 'src', 'cli.ts'), 'utf8') + const dotenv = cliEntry.indexOf('import(\'./services/load-dotenv.js\')') + const oclif = cliEntry.indexOf('import(\'@oclif/core\')') + expect(dotenv).toBeGreaterThan(-1) + expect(oclif).toBeGreaterThan(dotenv) }) function runBinWithPatchedVersions ( diff --git a/packages/cli/src/cli.ts b/packages/cli/src/cli.ts new file mode 100644 index 000000000..43a2640ce --- /dev/null +++ b/packages/cli/src/cli.ts @@ -0,0 +1,24 @@ +/** + * The bundled CLI bootstrap entry: bin/run.cjs → bin/launch.cjs → this module + * (compiled and esbuild-bundled to dist/bundle/cli.js). + * + * Commands are discovered by oclif's default pattern strategy from the + * per-command bundles in dist/bundle/commands (see oclif.commands in + * package.json), so — exactly as before bundling — no command module is + * evaluated until one is actually needed. This entry deliberately imports + * nothing beyond dotenv and oclif itself. + */ +export default async function runChecklyCli (): Promise { + const { loadDotenvFile } = await import('./services/load-dotenv.js') + await loadDotenvFile() + + // @oclif/core ships CommonJS. Node's import() interop surfaces its + // getter-based named exports at runtime, but inside the esbuild bundle the + // dynamic import resolves to a namespace where only `default` (the + // module.exports object) is statically known, so resolve through it and + // fall back for unbundled runs. + const imported = await import('@oclif/core') + const { execute, settings } = ((imported as unknown as { default?: typeof imported }).default) ?? imported + settings.enableAutoTranspile = false + await execute({ dir: import.meta.url }) +} diff --git a/packages/cli/src/commands/skills/index.ts b/packages/cli/src/commands/skills/index.ts index a4fd117ef..210e8d979 100644 --- a/packages/cli/src/commands/skills/index.ts +++ b/packages/cli/src/commands/skills/index.ts @@ -1,14 +1,15 @@ import { Args } from '@oclif/core' import { readFile, readdir } from 'fs/promises' -import { join, dirname } from 'path' -import { fileURLToPath } from 'node:url' +import { join } from 'path' import { ACTIONS, SKILL } from '../../ai-context/context.js' +import { packageRoot } from '../../services/package-root.js' import { BaseCommand } from '../baseCommand.js' -const __dirname = dirname(fileURLToPath(import.meta.url)) - -const REFERENCES_DIR = join(__dirname, '../../ai-context/skills-command/references') +// Served by the `checkly skills [action] [reference]` command. Anchored at +// the package root (not this module's own depth) so the path also resolves +// when the CLI runs from the esbuild bundle in dist/bundle/. +const REFERENCES_DIR = join(packageRoot(), 'dist/ai-context/skills-command/references') function referenceShortId (actionId: string, referenceId: string): string { return referenceId.replace(`${actionId}-`, '') diff --git a/packages/cli/src/constructs/internal/declaring-file.ts b/packages/cli/src/constructs/internal/declaring-file.ts index 5bfbc4626..25b9888ce 100644 --- a/packages/cli/src/constructs/internal/declaring-file.ts +++ b/packages/cli/src/constructs/internal/declaring-file.ts @@ -1,6 +1,8 @@ import path from 'node:path' import { fileURLToPath } from 'node:url' +import { packageRoot } from '../../services/package-root.js' + /** * Finds the user file that declares a construct by looking at the call * stack of the construct's constructor. @@ -45,11 +47,13 @@ import { fileURLToPath } from 'node:url' */ /** - * The directory holding the CLI's own code: `dist/` in the published package, - * `src/` when running from source. Frames under it belong to the CLI, not to - * the user's project. + * The CLI's own package root: everything under it — the esbuild bundle in + * dist/bundle/, the compiled tsc output in dist/, or TypeScript sources under + * src/ during development — belongs to the CLI, not to the user's project. + * Frames under it are therefore internal and skipped when searching for the + * file that declared a construct. */ -const OWN_ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..', '..') +const OWN_ROOT = packageRoot() /** * Frames to capture. The CLI's own constructor chain is at most five frames diff --git a/packages/cli/src/helpers/onboarding/__tests__/boilerplate.spec.ts b/packages/cli/src/helpers/onboarding/__tests__/boilerplate.spec.ts index b0b722f6e..0cae2e3a3 100644 --- a/packages/cli/src/helpers/onboarding/__tests__/boilerplate.spec.ts +++ b/packages/cli/src/helpers/onboarding/__tests__/boilerplate.spec.ts @@ -7,6 +7,12 @@ vi.mock('fs', () => ({ cpSync: vi.fn(), })) +// boilerplate.ts resolves its template locations from package-root, which +// needs the real fs; this spec replaces fs wholesale, so pin the root too. +vi.mock('../../../services/package-root.js', () => ({ + packageRoot: vi.fn(() => '/checkly-package-root'), +})) + vi.mock('child_process', () => ({ execSync: vi.fn(), })) diff --git a/packages/cli/src/helpers/onboarding/__tests__/detect-project.spec.ts b/packages/cli/src/helpers/onboarding/__tests__/detect-project.spec.ts index fc90f0a18..25166331d 100644 --- a/packages/cli/src/helpers/onboarding/__tests__/detect-project.spec.ts +++ b/packages/cli/src/helpers/onboarding/__tests__/detect-project.spec.ts @@ -4,6 +4,13 @@ vi.mock('fs', () => ({ existsSync: vi.fn(), })) +// skills.ts (imported for platform targets) resolves file locations from +// package-root, which needs the real fs; this spec replaces fs wholesale, +// so pin the root too. +vi.mock('../../../services/package-root.js', () => ({ + packageRoot: vi.fn(() => '/checkly-package-root'), +})) + vi.mock('../../../services/util', () => ({ findPlaywrightConfigPath: vi.fn(), })) diff --git a/packages/cli/src/helpers/onboarding/boilerplate.ts b/packages/cli/src/helpers/onboarding/boilerplate.ts index 2e1db14f3..437f5f61a 100644 --- a/packages/cli/src/helpers/onboarding/boilerplate.ts +++ b/packages/cli/src/helpers/onboarding/boilerplate.ts @@ -1,20 +1,19 @@ import { existsSync, readFileSync, writeFileSync, cpSync } from 'fs' import { execSync } from 'child_process' -import { join, dirname } from 'path' +import { join } from 'path' import chalk from 'chalk' import prompts from 'prompts' -import { fileURLToPath } from 'node:url' +import { packageRoot } from '../../services/package-root.js' import { detectPackageManager } from '../../services/check-parser/package-files/package-manager.js' import { makeOnCancel, successMessage } from './prompts-helpers.js' import { getRepoUrlFromGit } from '../../services/util.js' import { quote } from '../../sourcegen/string.js' -const __dirname = dirname(fileURLToPath(import.meta.url)) - -// Path resolves at runtime from dist/helpers/onboarding/ to dist/ai-context/onboarding-boilerplate/ -const CONFIG_TEMPLATE_PATH = join(__dirname, '../../ai-context/onboarding-boilerplate/checkly-config-template.ts') -const BOILERPLATE_CHECKS_PATH = join(__dirname, '../../ai-context/onboarding-boilerplate/__checks__') +// Anchored at the package root (not this module's own depth) so the path also +// resolves when the CLI runs from the esbuild bundle in dist/bundle/. +const CONFIG_TEMPLATE_PATH = join(packageRoot(), 'dist/ai-context/onboarding-boilerplate/checkly-config-template.ts') +const BOILERPLATE_CHECKS_PATH = join(packageRoot(), 'dist/ai-context/onboarding-boilerplate/__checks__') export interface DepsInstallOptions { skipPrompts?: boolean diff --git a/packages/cli/src/helpers/onboarding/template-prompt.ts b/packages/cli/src/helpers/onboarding/template-prompt.ts index 2e16e59e8..b34db415e 100644 --- a/packages/cli/src/helpers/onboarding/template-prompt.ts +++ b/packages/cli/src/helpers/onboarding/template-prompt.ts @@ -1,10 +1,11 @@ import { readFile } from 'fs/promises' -import { join, dirname } from 'path' -import { fileURLToPath } from 'node:url' +import { join } from 'path' -const __dirname = dirname(fileURLToPath(import.meta.url)) +import { packageRoot } from '../../services/package-root.js' -const PROMPTS_DIR = join(__dirname, '../../ai-context/onboarding-prompts') +// Anchored at the package root (not this module's own depth) so the path also +// resolves when the CLI runs from the esbuild bundle in dist/bundle/. +const PROMPTS_DIR = join(packageRoot(), 'dist/ai-context/onboarding-prompts') export type PromptVariables = Record diff --git a/packages/cli/src/hooks/check-update.ts b/packages/cli/src/hooks/check-update.ts new file mode 100644 index 000000000..adfdf1b46 --- /dev/null +++ b/packages/cli/src/hooks/check-update.ts @@ -0,0 +1,9 @@ +import checkUpdate from '../../node_modules/@oclif/plugin-warn-if-update-available/lib/hooks/init/check-update.js' + +// The warn-if-update-available init hook is registered directly (see +// oclif.hooks in package.json) rather than loaded as an oclif plugin, because +// plugin packages are not installed at runtime — @oclif/core and this hook +// are bundled in as devDependencies. The package's `exports` map blocks +// subpath imports, so this resolves the file directly through the +// workspace's node_modules at build time only; esbuild then inlines it. +export default checkUpdate diff --git a/packages/cli/src/runtimes/snapshot.ts b/packages/cli/src/runtimes/snapshot.ts index 1a4678905..309015086 100644 --- a/packages/cli/src/runtimes/snapshot.ts +++ b/packages/cli/src/runtimes/snapshot.ts @@ -1,14 +1,14 @@ import fs from 'node:fs/promises' import path from 'node:path' -import { fileURLToPath } from 'node:url' +import { packageRoot } from '../services/package-root.js' import { Runtime } from './runtime.js' -const __dirname = path.dirname(fileURLToPath(import.meta.url)) - const SNAPSHOT_DATE = '20260130' -const ASSETS_PATH = path.join(__dirname, '..', '..', 'assets') +// Anchored at the package root (not this module's own depth) so the path also +// resolves when the CLI runs from the esbuild bundle in dist/bundle/. +const ASSETS_PATH = path.join(packageRoot(), 'assets') export async function loadSnapshot (): Promise { const data = await fs.readFile(path.join( diff --git a/packages/cli/src/services/__tests__/skills.spec.ts b/packages/cli/src/services/__tests__/skills.spec.ts index acc2722c2..79df64305 100644 --- a/packages/cli/src/services/__tests__/skills.spec.ts +++ b/packages/cli/src/services/__tests__/skills.spec.ts @@ -10,6 +10,12 @@ vi.mock('fs', () => ({ existsSync: vi.fn(), })) +// skills.ts resolves its file locations from package-root, which needs the +// real fs; this spec replaces fs wholesale, so pin the root too. +vi.mock('../package-root.js', () => ({ + packageRoot: vi.fn(() => '/checkly-package-root'), +})) + import { existsSync } from 'fs' import { mkdir, readFile, writeFile } from 'fs/promises' import { join } from 'path' diff --git a/packages/cli/src/services/package-root.ts b/packages/cli/src/services/package-root.ts new file mode 100644 index 000000000..36e05c9f5 --- /dev/null +++ b/packages/cli/src/services/package-root.ts @@ -0,0 +1,42 @@ +import { existsSync, readFileSync } from 'node:fs' +import path from 'node:path' +import { fileURLToPath } from 'node:url' + +let cachedRoot: string | undefined + +function findRoot (start: string): string { + let dir = start + while (true) { + const candidate = path.join(dir, 'package.json') + if (existsSync(candidate)) { + try { + if (JSON.parse(readFileSync(candidate, 'utf8')).name === 'checkly') { + return dir + } + } catch { + // An unreadable package.json is not ours — keep walking up. + } + } + const parent = path.dirname(dir) + if (parent === dir) { + throw new Error(`Could not locate the checkly package root starting from ${start}`) + } + dir = parent + } +} + +/** + * The checkly CLI's own package root, found by walking up from this module. + * + * Unlike a fixed number of `..` segments, this works no matter where the + * module physically lives: the esbuild bundle in dist/bundle/, compiled tsc + * output anywhere in dist/, TypeScript sources under src/ during development, + * or a pnpm-style install where the package is a symlink target. + * + * Used to anchor paths to package assets (dist/ai-context, assets) that used + * to be computed relative to the compiled module's own depth. + */ +export function packageRoot (): string { + cachedRoot ??= findRoot(path.dirname(fileURLToPath(import.meta.url))) + return cachedRoot +} diff --git a/packages/cli/src/services/skills.ts b/packages/cli/src/services/skills.ts index 83c525489..d0ff3f6c1 100644 --- a/packages/cli/src/services/skills.ts +++ b/packages/cli/src/services/skills.ts @@ -1,13 +1,12 @@ import chalk from 'chalk' import { existsSync } from 'fs' import { mkdir, readFile, writeFile } from 'fs/promises' -import { join, dirname } from 'path' +import { join } from 'path' import prompts from 'prompts' -import { fileURLToPath } from 'node:url' -const __dirname = dirname(fileURLToPath(import.meta.url)) +import { packageRoot } from './package-root.js' -export const SKILL_FILE_PATH = join(__dirname, '../ai-context/public-skills/checkly/SKILL.md') +export const SKILL_FILE_PATH = join(packageRoot(), 'dist/ai-context/public-skills/checkly/SKILL.md') const SKILL_FILENAME = 'SKILL.md' export const PLATFORM_TARGETS: Record = { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 5ee790b73..69e8e84a0 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -41,15 +41,46 @@ importers: packages/cli: dependencies: + '@typescript-eslint/typescript-estree': + specifier: ^8.71.1 + version: 8.71.1(typescript@6.0.3) + jiti: + specifier: ^2.7.0 + version: 2.7.0 + oxc-parser: + specifier: 0.153.0 + version: 0.153.0 + devDependencies: '@oclif/core': specifier: ^5.1.7 version: 5.1.7 - '@oclif/plugin-help': - specifier: ^7.0.4 - version: 7.0.4 '@oclif/plugin-warn-if-update-available': specifier: ^4.0.3 version: 4.0.3 + '@playwright/test': + specifier: ^1.64.0 + version: 1.64.0 + '@types/archiver': + specifier: ^8.0.0 + version: 8.0.0 + '@types/debug': + specifier: ^4.1.13 + version: 4.1.13 + '@types/luxon': + specifier: ^3.7.6 + version: 3.7.6 + '@types/node': + specifier: ^22.19.17 + version: 22.19.18 + '@types/prompts': + specifier: ^2.4.9 + version: 2.4.9 + '@types/semver': + specifier: ^7.8.0 + version: 7.8.0 + '@types/ws': + specifier: ^8.18.2 + version: 8.18.2 acorn: specifier: ^8.19.0 version: 8.19.0 @@ -74,12 +105,21 @@ importers: conf: specifier: ^15.1.0 version: 15.1.0 + config: + specifier: ^5.0.1 + version: 5.0.1 + cross-env: + specifier: ^10.1.0 + version: 10.1.0 debug: specifier: ^4.4.3 version: 4.4.3(supports-color@8.1.1) dotenv: specifier: ^18.0.7 version: 18.0.7 + esbuild: + specifier: ^0.28.2 + version: 0.28.2 execa: specifier: ^10.1.0 version: 10.1.0 @@ -98,9 +138,6 @@ importers: indent-string: specifier: ^5.0.0 version: 5.0.0 - jiti: - specifier: ^2.7.0 - version: 2.7.0 json-stream-stringify: specifier: ^3.1.7 version: 3.1.7 @@ -122,12 +159,15 @@ importers: mqtt: specifier: ^5.16.0 version: 5.16.0 + nanoid: + specifier: ^6.0.2 + version: 6.0.2 + oclif: + specifier: ^6.0.8 + version: 6.0.8(@types/node@22.19.18) open: specifier: ^11.0.4 version: 11.0.4 - oxc-parser: - specifier: 0.153.0 - version: 0.153.0 p-queue: specifier: ^9.3.4 version: 9.3.4 @@ -140,6 +180,9 @@ importers: recast: specifier: ^0.24.0 version: 0.24.0 + rimraf: + specifier: ^6.1.3 + version: 6.1.3 semver: specifier: ^7.8.5 version: 7.8.5 @@ -149,67 +192,21 @@ importers: string-width: specifier: ^8.3.0 version: 8.3.0 - uuid: - specifier: ^14.0.3 - version: 14.0.3 - yaml: - specifier: ^2.9.1 - version: 2.9.1 - devDependencies: - '@playwright/test': - specifier: ^1.64.0 - version: 1.64.0 - '@types/archiver': - specifier: ^8.0.0 - version: 8.0.0 - '@types/debug': - specifier: ^4.1.13 - version: 4.1.13 - '@types/luxon': - specifier: ^3.7.6 - version: 3.7.6 - '@types/node': - specifier: ^22.19.17 - version: 22.19.18 - '@types/prompts': - specifier: ^2.4.9 - version: 2.4.9 - '@types/semver': - specifier: ^7.8.0 - version: 7.8.0 - '@types/ws': - specifier: ^8.18.2 - version: 8.18.2 - '@typescript-eslint/types': - specifier: ^8.71.1 - version: 8.71.1 - '@typescript-eslint/typescript-estree': - specifier: ^8.71.1 - version: 8.71.1(typescript@6.0.3) - config: - specifier: ^5.0.1 - version: 5.0.1 - cross-env: - specifier: ^10.1.0 - version: 10.1.0 - nanoid: - specifier: ^6.0.2 - version: 6.0.2 - oclif: - specifier: ^6.0.8 - version: 6.0.8(@types/node@22.19.18) - rimraf: - specifier: ^6.1.3 - version: 6.1.3 tar: specifier: ^7.5.22 version: 7.5.22 typescript: specifier: ^6.0.3 version: 6.0.3 + uuid: + specifier: ^14.0.3 + version: 14.0.3 vitest: specifier: ^3.2.7 version: 3.2.7(@types/debug@4.1.13)(@types/node@22.19.18)(jiti@2.7.0)(yaml@2.9.1) + yaml: + specifier: ^2.9.1 + version: 2.9.1 packages/create-cli: dependencies: @@ -533,156 +530,312 @@ packages: cpu: [ppc64] os: [aix] + '@esbuild/aix-ppc64@0.28.2': + resolution: {integrity: sha512-XExcO+dvLKvVtNTibSTBej1NCAbaGhWn9Ww1ZPx80qsahhPFe/8jgWP0IchNe0F3HwkU7n8ejhH8bjonqht8mQ==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] + '@esbuild/android-arm64@0.27.7': resolution: {integrity: sha512-62dPZHpIXzvChfvfLJow3q5dDtiNMkwiRzPylSCfriLvZeq0a1bWChrGx/BbUbPwOrsWKMn8idSllklzBy+dgQ==} engines: {node: '>=18'} cpu: [arm64] os: [android] + '@esbuild/android-arm64@0.28.2': + resolution: {integrity: sha512-5YfKeeI8qWfBZIX+u2xZC3Zlb3Os/gLS2sbEKM+I4ZOcsWmHS2WLysCcQZDAFRslDUU5Oiq44gf6PYN1vGwG5A==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] + '@esbuild/android-arm@0.27.7': resolution: {integrity: sha512-jbPXvB4Yj2yBV7HUfE2KHe4GJX51QplCN1pGbYjvsyCZbQmies29EoJbkEc+vYuU5o45AfQn37vZlyXy4YJ8RQ==} engines: {node: '>=18'} cpu: [arm] os: [android] + '@esbuild/android-arm@0.28.2': + resolution: {integrity: sha512-kXXoiPVVGQcnIYGOeaovwOURpniDBpSq4A03qkQ+BMQqtGG6HYap3xne9C1O1yo4TR3qxlCX5IqqmX6fFo2Lqg==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] + '@esbuild/android-x64@0.27.7': resolution: {integrity: sha512-x5VpMODneVDb70PYV2VQOmIUUiBtY3D3mPBG8NxVk5CogneYhkR7MmM3yR/uMdITLrC1ml/NV1rj4bMJuy9MCg==} engines: {node: '>=18'} cpu: [x64] os: [android] + '@esbuild/android-x64@0.28.2': + resolution: {integrity: sha512-O387ite7SzUyCcy3JQX4P4bLtEA7bLLkx+esve5JHnyYfNTxcVpXZo9jhdB0lTKN44gztELTdU7nS8Nr16Fs1Q==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] + '@esbuild/darwin-arm64@0.27.7': resolution: {integrity: sha512-5lckdqeuBPlKUwvoCXIgI2D9/ABmPq3Rdp7IfL70393YgaASt7tbju3Ac+ePVi3KDH6N2RqePfHnXkaDtY9fkw==} engines: {node: '>=18'} cpu: [arm64] os: [darwin] + '@esbuild/darwin-arm64@0.28.2': + resolution: {integrity: sha512-n4KqkOQrraxHJcgjM1RvwbigfQKIKJVpM7xp+KsxiyUSrRdIXnt73VhrPAx0fV44hgfmIVKjxMN9J1t5jySVkw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] + '@esbuild/darwin-x64@0.27.7': resolution: {integrity: sha512-rYnXrKcXuT7Z+WL5K980jVFdvVKhCHhUwid+dDYQpH+qu+TefcomiMAJpIiC2EM3Rjtq0sO3StMV/+3w3MyyqQ==} engines: {node: '>=18'} cpu: [x64] os: [darwin] + '@esbuild/darwin-x64@0.28.2': + resolution: {integrity: sha512-uq6suIWYP37qzGddBKPw5QEQPi6HiLGsO7UmkpfyaYNQ3D+rN6w6WfwH+nuqcGXWvawGwxOEroO4YGnFh95azw==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] + '@esbuild/freebsd-arm64@0.27.7': resolution: {integrity: sha512-B48PqeCsEgOtzME2GbNM2roU29AMTuOIN91dsMO30t+Ydis3z/3Ngoj5hhnsOSSwNzS+6JppqWsuhTp6E82l2w==} engines: {node: '>=18'} cpu: [arm64] os: [freebsd] + '@esbuild/freebsd-arm64@0.28.2': + resolution: {integrity: sha512-n+I0BTSRIoy+d6RPKnEVwql5UwBJolytvY4mAOIEJorKlqgPII8ix6slVVrfZ5Tnj7glIZvloylbB/EJPMWEXw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] + '@esbuild/freebsd-x64@0.27.7': resolution: {integrity: sha512-jOBDK5XEjA4m5IJK3bpAQF9/Lelu/Z9ZcdhTRLf4cajlB+8VEhFFRjWgfy3M1O4rO2GQ/b2dLwCUGpiF/eATNQ==} engines: {node: '>=18'} cpu: [x64] os: [freebsd] + '@esbuild/freebsd-x64@0.28.2': + resolution: {integrity: sha512-78XJTJkvPs0kz2w61301PJjXl4g7q3JqiYMZ/M/yVI73EHBrCRTgkhu9oqG7vPqq+a/yadEW8aD+agKlk5xrmg==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] + '@esbuild/linux-arm64@0.27.7': resolution: {integrity: sha512-RZPHBoxXuNnPQO9rvjh5jdkRmVizktkT7TCDkDmQ0W2SwHInKCAV95GRuvdSvA7w4VMwfCjUiPwDi0ZO6Nfe9A==} engines: {node: '>=18'} cpu: [arm64] os: [linux] + '@esbuild/linux-arm64@0.28.2': + resolution: {integrity: sha512-pW4AC0P3it8c7do9MVM4p51FzHzdM/TZrerurgRcHJ2WTa1VQ1CIq18xncfpBJw4ojkiZZrKW2yIBWBP92j6Ug==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] + '@esbuild/linux-arm@0.27.7': resolution: {integrity: sha512-RkT/YXYBTSULo3+af8Ib0ykH8u2MBh57o7q/DAs3lTJlyVQkgQvlrPTnjIzzRPQyavxtPtfg0EopvDyIt0j1rA==} engines: {node: '>=18'} cpu: [arm] os: [linux] + '@esbuild/linux-arm@0.28.2': + resolution: {integrity: sha512-XlDnu2q5yoqems+xay6wSAcg9DDD7K9RLKZEBOMZm3ckNpJBvOX20tSfby8KfrrhINDyv9V2YVZKY/SpoGJI8w==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] + '@esbuild/linux-ia32@0.27.7': resolution: {integrity: sha512-GA48aKNkyQDbd3KtkplYWT102C5sn/EZTY4XROkxONgruHPU72l+gW+FfF8tf2cFjeHaRbWpOYa/uRBz/Xq1Pg==} engines: {node: '>=18'} cpu: [ia32] os: [linux] + '@esbuild/linux-ia32@0.28.2': + resolution: {integrity: sha512-CYbnj78HsIeA+DhgUKgFCfvNsTHFhMMrinUrMZpDXJXKN8T3XViTZ/+wtHeVxEWY8ewSzTFN+nRmSwO2tZaLUQ==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] + '@esbuild/linux-loong64@0.27.7': resolution: {integrity: sha512-a4POruNM2oWsD4WKvBSEKGIiWQF8fZOAsycHOt6JBpZ+JN2n2JH9WAv56SOyu9X5IqAjqSIPTaJkqN8F7XOQ5Q==} engines: {node: '>=18'} cpu: [loong64] os: [linux] + '@esbuild/linux-loong64@0.28.2': + resolution: {integrity: sha512-buwkd8nsph4R+ajRvw0qM5Hja/TXQow3ptzWO2EbG/cqcIkHloRrdlBtQlshyYGTNFvfkfJ5tpPLVkY4DtsPfQ==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] + '@esbuild/linux-mips64el@0.27.7': resolution: {integrity: sha512-KabT5I6StirGfIz0FMgl1I+R1H73Gp0ofL9A3nG3i/cYFJzKHhouBV5VWK1CSgKvVaG4q1RNpCTR2LuTVB3fIw==} engines: {node: '>=18'} cpu: [mips64el] os: [linux] + '@esbuild/linux-mips64el@0.28.2': + resolution: {integrity: sha512-ZVykbDyk7519VwiNb9Lcj9m8XM6v5V9uKPvrEMkkEedVewf+0itkhahp4HDpgERXhwLRpWFypsGbG/J8s0QjJA==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] + '@esbuild/linux-ppc64@0.27.7': resolution: {integrity: sha512-gRsL4x6wsGHGRqhtI+ifpN/vpOFTQtnbsupUF5R5YTAg+y/lKelYR1hXbnBdzDjGbMYjVJLJTd2OFmMewAgwlQ==} engines: {node: '>=18'} cpu: [ppc64] os: [linux] + '@esbuild/linux-ppc64@0.28.2': + resolution: {integrity: sha512-CAXl+Dtd9UUuJd8pKKdwh6MLm3MUMiqMPmhZ3tTSXPqfyQ3vDl6R5hZdZ/kYojK4ofXtdfSv1tFq8XzWx3heNQ==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] + '@esbuild/linux-riscv64@0.27.7': resolution: {integrity: sha512-hL25LbxO1QOngGzu2U5xeXtxXcW+/GvMN3ejANqXkxZ/opySAZMrc+9LY/WyjAan41unrR3YrmtTsUpwT66InQ==} engines: {node: '>=18'} cpu: [riscv64] os: [linux] + '@esbuild/linux-riscv64@0.28.2': + resolution: {integrity: sha512-GeXCej4IQtU1B+QlDV8W/RRvbzI3O/Stss+/bCXv4lZls5WGRtu2a+3JkA3i4qIUlMXpcHebWpF8AkJhATowuA==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] + '@esbuild/linux-s390x@0.27.7': resolution: {integrity: sha512-2k8go8Ycu1Kb46vEelhu1vqEP+UeRVj2zY1pSuPdgvbd5ykAw82Lrro28vXUrRmzEsUV0NzCf54yARIK8r0fdw==} engines: {node: '>=18'} cpu: [s390x] os: [linux] + '@esbuild/linux-s390x@0.28.2': + resolution: {integrity: sha512-3H1weTYZPxt/WOhByszQZybS9w5lKzUn1FDMsgEChbHWQwHYQQRfBxgCcZvPhjHfKyJjIievvMmEUawJrdY9Dg==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] + '@esbuild/linux-x64@0.27.7': resolution: {integrity: sha512-hzznmADPt+OmsYzw1EE33ccA+HPdIqiCRq7cQeL1Jlq2gb1+OyWBkMCrYGBJ+sxVzve2ZJEVeePbLM2iEIZSxA==} engines: {node: '>=18'} cpu: [x64] os: [linux] + '@esbuild/linux-x64@0.28.2': + resolution: {integrity: sha512-4xTZr1FUmSoQW4XIWmit3tzQrUTZM+N3P0XV8xROKYF50XfI7xeO90+1bZvNwxIufQ9hDQVRJH5YhgPVF8A/HQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] + '@esbuild/netbsd-arm64@0.27.7': resolution: {integrity: sha512-b6pqtrQdigZBwZxAn1UpazEisvwaIDvdbMbmrly7cDTMFnw/+3lVxxCTGOrkPVnsYIosJJXAsILG9XcQS+Yu6w==} engines: {node: '>=18'} cpu: [arm64] os: [netbsd] + '@esbuild/netbsd-arm64@0.28.2': + resolution: {integrity: sha512-sSATRjPeDBg3pdgHoQfoYBob11Kk1FGa9lui5RIHZCoCkJa9QKlvl3/vKz2usCmYYjs7ymJR/2Nnsqe+Hjt5nw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [netbsd] + '@esbuild/netbsd-x64@0.27.7': resolution: {integrity: sha512-OfatkLojr6U+WN5EDYuoQhtM+1xco+/6FSzJJnuWiUw5eVcicbyK3dq5EeV/QHT1uy6GoDhGbFpprUiHUYggrw==} engines: {node: '>=18'} cpu: [x64] os: [netbsd] + '@esbuild/netbsd-x64@0.28.2': + resolution: {integrity: sha512-lqnzCV+mM0gIADaKihiCg6ifgfU2L3h5E33rNQBN1Y4MaVGnzryzmvvf7UHxprpQdE8hpqLolJ9Rl+SkIRDpyw==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] + '@esbuild/openbsd-arm64@0.27.7': resolution: {integrity: sha512-AFuojMQTxAz75Fo8idVcqoQWEHIXFRbOc1TrVcFSgCZtQfSdc1RXgB3tjOn/krRHENUB4j00bfGjyl2mJrU37A==} engines: {node: '>=18'} cpu: [arm64] os: [openbsd] + '@esbuild/openbsd-arm64@0.28.2': + resolution: {integrity: sha512-AL2qJILH7lNjrDmCQDvdxMfAUIv8KMNZOvrwAQ8i8//ntL9FflhOyMJ8OZSMBb8/AWXe3/5v5S20y3zCoZWKoQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + '@esbuild/openbsd-x64@0.27.7': resolution: {integrity: sha512-+A1NJmfM8WNDv5CLVQYJ5PshuRm/4cI6WMZRg1by1GwPIQPCTs1GLEUHwiiQGT5zDdyLiRM/l1G0Pv54gvtKIg==} engines: {node: '>=18'} cpu: [x64] os: [openbsd] + '@esbuild/openbsd-x64@0.28.2': + resolution: {integrity: sha512-QtiuPytchRyC4rwUKhexJdQKvDuZ6hWloi3igqPQNUJCS1/v9EiO3UTOXR6A3FoMo4fnAKbWJdqaIwhOzh8qEw==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] + '@esbuild/openharmony-arm64@0.27.7': resolution: {integrity: sha512-+KrvYb/C8zA9CU/g0sR6w2RBw7IGc5J2BPnc3dYc5VJxHCSF1yNMxTV5LQ7GuKteQXZtspjFbiuW5/dOj7H4Yw==} engines: {node: '>=18'} cpu: [arm64] os: [openharmony] + '@esbuild/openharmony-arm64@0.28.2': + resolution: {integrity: sha512-WkhYDmpTjLvGlScA1rwjRUmhl4k8oXR3cIbtqWmELgU/dFeHHlEllxDvdWcNJV9rbzCexB5vz8gtNewWLgCT7Q==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openharmony] + '@esbuild/sunos-x64@0.27.7': resolution: {integrity: sha512-ikktIhFBzQNt/QDyOL580ti9+5mL/YZeUPKU2ivGtGjdTYoqz6jObj6nOMfhASpS4GU4Q/Clh1QtxWAvcYKamA==} engines: {node: '>=18'} cpu: [x64] os: [sunos] + '@esbuild/sunos-x64@0.28.2': + resolution: {integrity: sha512-GPMSkTOtMnv2U2F8gxe4Io6qmVs+YKyp832Etqqxr0hFngmXQ3rzwytelm3GIn7T4VviRUlf3sOgBOiTdvaf7g==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + '@esbuild/win32-arm64@0.27.7': resolution: {integrity: sha512-7yRhbHvPqSpRUV7Q20VuDwbjW5kIMwTHpptuUzV+AA46kiPze5Z7qgt6CLCK3pWFrHeNfDd1VKgyP4O+ng17CA==} engines: {node: '>=18'} cpu: [arm64] os: [win32] + '@esbuild/win32-arm64@0.28.2': + resolution: {integrity: sha512-PIhhEkE9uPBleRBrQEJpUn7MBnibZzbGzYWPmY3x+YoVg/95zbjB4CxPPOQ8l5tYYM4mMaCthF8/1DIfBQQyWQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + '@esbuild/win32-ia32@0.27.7': resolution: {integrity: sha512-SmwKXe6VHIyZYbBLJrhOoCJRB/Z1tckzmgTLfFYOfpMAx63BJEaL9ExI8x7v0oAO3Zh6D/Oi1gVxEYr5oUCFhw==} engines: {node: '>=18'} cpu: [ia32] os: [win32] + '@esbuild/win32-ia32@0.28.2': + resolution: {integrity: sha512-YmJbfTlvU7Sdn9BB+4PRES4oB6pxgS37MAONj+hBr/cpXS1aBPKXxNnDbu+QCWPj0o9dgyxeq79g6c5P8KeuYA==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] + '@esbuild/win32-x64@0.27.7': resolution: {integrity: sha512-56hiAJPhwQ1R4i+21FVF7V8kSD5zZTdHcVuRFMW0hn753vVfQN8xlx4uOPT4xoGH0Z/oVATuR82AiqSTDIpaHg==} engines: {node: '>=18'} cpu: [x64] os: [win32] + '@esbuild/win32-x64@0.28.2': + resolution: {integrity: sha512-5ebpxr3nWMzrL/rnUI755Jkuee0bHL/Gq0WTF9lvcpv73wAp5eu8MfBUgWK9bhWvZjj7yX8etf/8tI8Ney695g==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + '@eslint-community/eslint-utils@4.9.1': resolution: {integrity: sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -1387,6 +1540,10 @@ packages: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.1.0' + '@typescript-eslint/types@8.59.2': + resolution: {integrity: sha512-e82GVOE8Ps3E++Egvb6Y3Dw0S10u8NkQ9KXmtRhCWJJ8kDhOJTvtMAWnFL16kB1583goCWXsr0NieKCZMs2/0Q==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@typescript-eslint/types@8.71.1': resolution: {integrity: sha512-ybYnPTUwg3VQQOFEiBPLs8Jxl1ry2vXdn1kVKguomBbvxpetdu3MKTNDqFNUrlG8ylP9MpZosmXMFYlGQHk1oQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -1935,6 +2092,11 @@ packages: engines: {node: '>=18'} hasBin: true + esbuild@0.28.2: + resolution: {integrity: sha512-HKVLS8dvII+xoKW9kmqxbRKrnWEXfJJr/FZhhJmiqIB0e053QNYFqOBouTMO/k5sID4MvCiUCvv8b9M4h32wIA==} + engines: {node: '>=18'} + hasBin: true + escalade@3.2.0: resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} engines: {node: '>=6'} @@ -3796,81 +3958,159 @@ snapshots: '@esbuild/aix-ppc64@0.27.7': optional: true + '@esbuild/aix-ppc64@0.28.2': + optional: true + '@esbuild/android-arm64@0.27.7': optional: true + '@esbuild/android-arm64@0.28.2': + optional: true + '@esbuild/android-arm@0.27.7': optional: true + '@esbuild/android-arm@0.28.2': + optional: true + '@esbuild/android-x64@0.27.7': optional: true + '@esbuild/android-x64@0.28.2': + optional: true + '@esbuild/darwin-arm64@0.27.7': optional: true + '@esbuild/darwin-arm64@0.28.2': + optional: true + '@esbuild/darwin-x64@0.27.7': optional: true + '@esbuild/darwin-x64@0.28.2': + optional: true + '@esbuild/freebsd-arm64@0.27.7': optional: true + '@esbuild/freebsd-arm64@0.28.2': + optional: true + '@esbuild/freebsd-x64@0.27.7': optional: true + '@esbuild/freebsd-x64@0.28.2': + optional: true + '@esbuild/linux-arm64@0.27.7': optional: true + '@esbuild/linux-arm64@0.28.2': + optional: true + '@esbuild/linux-arm@0.27.7': optional: true + '@esbuild/linux-arm@0.28.2': + optional: true + '@esbuild/linux-ia32@0.27.7': optional: true + '@esbuild/linux-ia32@0.28.2': + optional: true + '@esbuild/linux-loong64@0.27.7': optional: true + '@esbuild/linux-loong64@0.28.2': + optional: true + '@esbuild/linux-mips64el@0.27.7': optional: true + '@esbuild/linux-mips64el@0.28.2': + optional: true + '@esbuild/linux-ppc64@0.27.7': optional: true + '@esbuild/linux-ppc64@0.28.2': + optional: true + '@esbuild/linux-riscv64@0.27.7': optional: true + '@esbuild/linux-riscv64@0.28.2': + optional: true + '@esbuild/linux-s390x@0.27.7': optional: true + '@esbuild/linux-s390x@0.28.2': + optional: true + '@esbuild/linux-x64@0.27.7': optional: true + '@esbuild/linux-x64@0.28.2': + optional: true + '@esbuild/netbsd-arm64@0.27.7': optional: true + '@esbuild/netbsd-arm64@0.28.2': + optional: true + '@esbuild/netbsd-x64@0.27.7': optional: true + '@esbuild/netbsd-x64@0.28.2': + optional: true + '@esbuild/openbsd-arm64@0.27.7': optional: true + '@esbuild/openbsd-arm64@0.28.2': + optional: true + '@esbuild/openbsd-x64@0.27.7': optional: true + '@esbuild/openbsd-x64@0.28.2': + optional: true + '@esbuild/openharmony-arm64@0.27.7': optional: true + '@esbuild/openharmony-arm64@0.28.2': + optional: true + '@esbuild/sunos-x64@0.27.7': optional: true + '@esbuild/sunos-x64@0.28.2': + optional: true + '@esbuild/win32-arm64@0.27.7': optional: true + '@esbuild/win32-arm64@0.28.2': + optional: true + '@esbuild/win32-ia32@0.27.7': optional: true + '@esbuild/win32-ia32@0.28.2': + optional: true + '@esbuild/win32-x64@0.27.7': optional: true + '@esbuild/win32-x64@0.28.2': + optional: true + '@eslint-community/eslint-utils@4.9.1(eslint@10.12.0(jiti@2.7.0))': dependencies: eslint: 10.12.0(jiti@2.7.0) @@ -4377,7 +4617,7 @@ snapshots: '@stylistic/eslint-plugin@5.10.0(eslint@10.12.0(jiti@2.7.0))': dependencies: '@eslint-community/eslint-utils': 4.9.1(eslint@10.12.0(jiti@2.7.0)) - '@typescript-eslint/types': 8.71.1 + '@typescript-eslint/types': 8.59.2 eslint: 10.12.0(jiti@2.7.0) eslint-visitor-keys: 4.2.1 espree: 10.4.0 @@ -4509,6 +4749,8 @@ snapshots: transitivePeerDependencies: - supports-color + '@typescript-eslint/types@8.59.2': {} + '@typescript-eslint/types@8.71.1': {} '@typescript-eslint/typescript-estree@8.71.1(typescript@6.0.3)': @@ -5099,6 +5341,35 @@ snapshots: '@esbuild/win32-ia32': 0.27.7 '@esbuild/win32-x64': 0.27.7 + esbuild@0.28.2: + optionalDependencies: + '@esbuild/aix-ppc64': 0.28.2 + '@esbuild/android-arm': 0.28.2 + '@esbuild/android-arm64': 0.28.2 + '@esbuild/android-x64': 0.28.2 + '@esbuild/darwin-arm64': 0.28.2 + '@esbuild/darwin-x64': 0.28.2 + '@esbuild/freebsd-arm64': 0.28.2 + '@esbuild/freebsd-x64': 0.28.2 + '@esbuild/linux-arm': 0.28.2 + '@esbuild/linux-arm64': 0.28.2 + '@esbuild/linux-ia32': 0.28.2 + '@esbuild/linux-loong64': 0.28.2 + '@esbuild/linux-mips64el': 0.28.2 + '@esbuild/linux-ppc64': 0.28.2 + '@esbuild/linux-riscv64': 0.28.2 + '@esbuild/linux-s390x': 0.28.2 + '@esbuild/linux-x64': 0.28.2 + '@esbuild/netbsd-arm64': 0.28.2 + '@esbuild/netbsd-x64': 0.28.2 + '@esbuild/openbsd-arm64': 0.28.2 + '@esbuild/openbsd-x64': 0.28.2 + '@esbuild/openharmony-arm64': 0.28.2 + '@esbuild/sunos-x64': 0.28.2 + '@esbuild/win32-arm64': 0.28.2 + '@esbuild/win32-ia32': 0.28.2 + '@esbuild/win32-x64': 0.28.2 + escalade@3.2.0: {} escape-string-regexp@4.0.0: {} From fa15d8b282cecb524a6020f932125e028f3ad294 Mon Sep 17 00:00:00 2001 From: Hannes Lenke Date: Thu, 15 Oct 2026 17:06:27 -0400 Subject: [PATCH 2/4] build(cli): keep runtime class names in the esbuild bundle MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The deploy preview prints construct.constructor.name, and error messages and write-back checks name construct classes too. Without keepNames, esbuild renames classes whose name collides with their export binding in chunk scope (ApiCheck = class _ApiCheck), so the packed CLI rendered '_ApiCheck' where main renders 'ApiCheck' — caught by the deploy e2e on CI (unit tests run from source and never saw it). Also move the exports 'types' conditions first, where esbuild expects them, silencing build warnings. --- packages/cli/package.json | 16 ++++++++-------- packages/cli/scripts/bundle.mjs | 7 +++++++ 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/packages/cli/package.json b/packages/cli/package.json index 1c4b2f2b3..2ac9c7f84 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -7,25 +7,25 @@ "types": "dist/index.d.ts", "exports": { ".": { + "types": "./dist/index.d.ts", "import": "./dist/bundle/index.js", - "require": "./dist/bundle/index.js", - "types": "./dist/index.d.ts" + "require": "./dist/bundle/index.js" }, "./package.json": "./package.json", "./constructs": { + "types": "./dist/constructs/index.d.ts", "import": "./dist/bundle/constructs.js", - "require": "./dist/bundle/constructs.js", - "types": "./dist/constructs/index.d.ts" + "require": "./dist/bundle/constructs.js" }, "./loader": { + "types": "./dist/loader/index.d.ts", "import": "./dist/bundle/loader.js", - "require": "./dist/bundle/loader.js", - "types": "./dist/loader/index.d.ts" + "require": "./dist/bundle/loader.js" }, "./util": { + "types": "./dist/util/index.d.ts", "import": "./dist/bundle/util.js", - "require": "./dist/bundle/util.js", - "types": "./dist/util/index.d.ts" + "require": "./dist/bundle/util.js" } }, "engines": { diff --git a/packages/cli/scripts/bundle.mjs b/packages/cli/scripts/bundle.mjs index fb96f0a79..038c1fdac 100644 --- a/packages/cli/scripts/bundle.mjs +++ b/packages/cli/scripts/bundle.mjs @@ -84,6 +84,13 @@ const result = await build({ // Shared code goes to dist/bundle/chunks/ so oclif's command glob over // dist/bundle/commands only ever sees command entries. chunkNames: 'chunks/[name]-[hash]', + // Runtime code relies on Function.name: the deploy preview prints + // construct.constructor.name (e.g. "ApiCheck"), and error messages and + // write-back checks name construct classes too. Without keepNames, esbuild + // renames classes whose name collides with their export binding in chunk + // scope (ApiCheck = class _ApiCheck), which leaks the renamed identifier + // into user-visible output. keepNames restores the source names. + keepNames: true, // Bundled CJS dependencies (e.g. supports-color via debug) call require() // for node builtins at runtime. esbuild's ESM output can only resolve those // when a require function exists in scope; this banner supplies one. From c2b578edb0b6007f453b39d417818136f61e81a3 Mon Sep 17 00:00:00 2001 From: Hannes Lenke Date: Thu, 15 Oct 2026 17:24:01 -0400 Subject: [PATCH 3/4] build(cli): minify the esbuild bundle Roughly halves the bundle (7.4 MB -> 3.5 MB, tarball 1.69 -> 1.32 MB gzipped, within 8% of the unbundled main tarball). keepNames keeps class and function names readable in stack traces; only local identifiers are mangled. Sourcemaps stay unshipped: split-bundle maps weigh ~13 MB and Node only applies them with --enable-source-maps anyway. --- packages/cli/scripts/bundle.mjs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/packages/cli/scripts/bundle.mjs b/packages/cli/scripts/bundle.mjs index 038c1fdac..88b14df87 100644 --- a/packages/cli/scripts/bundle.mjs +++ b/packages/cli/scripts/bundle.mjs @@ -91,6 +91,12 @@ const result = await build({ // scope (ApiCheck = class _ApiCheck), which leaks the renamed identifier // into user-visible output. keepNames restores the source names. keepNames: true, + // Minify: roughly halves the bundle (7.4 MB -> 3.5 MB, tarball 1.69 -> + // 1.32 MB gz) and keepNames keeps class and function names readable in + // stack traces; only local identifiers are mangled. Sourcemaps are not + // shipped: the split-bundle maps weigh ~13 MB, and Node only applies + // sourceMappingURL with --enable-source-maps anyway. + minify: true, // Bundled CJS dependencies (e.g. supports-color via debug) call require() // for node builtins at runtime. esbuild's ESM output can only resolve those // when a require function exists in scope; this banner supplies one. From 98434fbc2a9566180e0ca9ef3cdd36c4a0da6221 Mon Sep 17 00:00:00 2001 From: Hannes Lenke Date: Fri, 16 Oct 2026 14:11:33 -0400 Subject: [PATCH 4/4] build(cli): drop typescript-estree from the bundle externals after #1543 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit #1543 moved write-back and preview parsing to oxc-parser and made @typescript-eslint/typescript-estree a devDependency (reference parser of ts-parser-parity.spec.ts only). No runtime imports remain, so the bundle no longer needs it external: runtime dependencies are down to jiti and oxc-parser, and installs no longer pull the ~24 MB typescript peer — node_modules drops from 42 MB/18 packages to 12 MB/5 packages. Also regenerates the lockfile after the rebase onto main. --- packages/cli/scripts/bundle.mjs | 7 ++----- pnpm-lock.yaml | 17 +++++++---------- 2 files changed, 9 insertions(+), 15 deletions(-) diff --git a/packages/cli/scripts/bundle.mjs b/packages/cli/scripts/bundle.mjs index 88b14df87..c7e0ce294 100644 --- a/packages/cli/scripts/bundle.mjs +++ b/packages/cli/scripts/bundle.mjs @@ -15,13 +15,10 @@ * * Only native or resolution-sensitive dependencies stay external: * - oxc-parser: Rust native bindings resolved per platform at runtime. - * - @typescript-eslint/typescript-estree: a peer-dependent parser that - * resolves the *user's project's* TypeScript via createRequire, so it must - * stay an installed runtime dependency. * - jiti: lazy-requires sibling files from its own package at runtime * (e.g. dist/babel.cjs), which cannot be satisfied from a bundle. - * - typescript: never bundled (peer of the above, resolved from the user's - * project when needed). + * - typescript: never bundled (only resolved from a user's project, if at + * all, since write-back moved to oxc-parser). */ import { build } from 'esbuild' import { readdirSync, rmSync, mkdirSync } from 'node:fs' diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 69e8e84a0..2e5524682 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -41,9 +41,6 @@ importers: packages/cli: dependencies: - '@typescript-eslint/typescript-estree': - specifier: ^8.71.1 - version: 8.71.1(typescript@6.0.3) jiti: specifier: ^2.7.0 version: 2.7.0 @@ -81,6 +78,12 @@ importers: '@types/ws': specifier: ^8.18.2 version: 8.18.2 + '@typescript-eslint/types': + specifier: ^8.71.1 + version: 8.71.1 + '@typescript-eslint/typescript-estree': + specifier: ^8.71.1 + version: 8.71.1(typescript@6.0.3) acorn: specifier: ^8.19.0 version: 8.19.0 @@ -1540,10 +1543,6 @@ packages: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/types@8.59.2': - resolution: {integrity: sha512-e82GVOE8Ps3E++Egvb6Y3Dw0S10u8NkQ9KXmtRhCWJJ8kDhOJTvtMAWnFL16kB1583goCWXsr0NieKCZMs2/0Q==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/types@8.71.1': resolution: {integrity: sha512-ybYnPTUwg3VQQOFEiBPLs8Jxl1ry2vXdn1kVKguomBbvxpetdu3MKTNDqFNUrlG8ylP9MpZosmXMFYlGQHk1oQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -4617,7 +4616,7 @@ snapshots: '@stylistic/eslint-plugin@5.10.0(eslint@10.12.0(jiti@2.7.0))': dependencies: '@eslint-community/eslint-utils': 4.9.1(eslint@10.12.0(jiti@2.7.0)) - '@typescript-eslint/types': 8.59.2 + '@typescript-eslint/types': 8.71.1 eslint: 10.12.0(jiti@2.7.0) eslint-visitor-keys: 4.2.1 espree: 10.4.0 @@ -4749,8 +4748,6 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/types@8.59.2': {} - '@typescript-eslint/types@8.71.1': {} '@typescript-eslint/typescript-estree@8.71.1(typescript@6.0.3)':