diff --git a/.changeset/ninety-pets-argue.md b/.changeset/ninety-pets-argue.md new file mode 100644 index 00000000..2df704f8 --- /dev/null +++ b/.changeset/ninety-pets-argue.md @@ -0,0 +1,5 @@ +--- +"@proofkit/cli": patch +--- + +Publish prebuilt CLI binaries and cut install-time runtime deps so `npx` and `pnpm dlx` flows avoid dependency build approvals. diff --git a/.github/workflows/continuous-release.yml b/.github/workflows/continuous-release.yml index bf07c3b5..de2c460b 100644 --- a/.github/workflows/continuous-release.yml +++ b/.github/workflows/continuous-release.yml @@ -59,6 +59,11 @@ jobs: node-version: 22 cache: "pnpm" + - name: Setup Bun + uses: oven-sh/setup-bun@v2 + with: + bun-version: 1.3.11 + - name: Install dependencies run: pnpm install --frozen-lockfile diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 60a0aedb..c6daa90d 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -79,6 +79,11 @@ jobs: node-version: 22 cache: "pnpm" + - name: Setup Bun + uses: oven-sh/setup-bun@v2 + with: + bun-version: 1.3.13 + - name: Install Dependencies run: pnpm install --frozen-lockfile @@ -156,6 +161,11 @@ jobs: cache: "pnpm" registry-url: "https://registry.npmjs.org" + - name: Setup Bun + uses: oven-sh/setup-bun@v2 + with: + bun-version: 1.3.11 + - name: Install Dependencies run: pnpm install --frozen-lockfile diff --git a/.gitignore b/.gitignore index 3a547efc..afbe87ca 100644 --- a/.gitignore +++ b/.gitignore @@ -75,6 +75,10 @@ public/dist .turbo packages/fmdapi/test/typegen/* packages/typegen/schema/metadata.xml +packages/cli/bin/proofkit-* +!packages/cli/bin/proofkit.cjs +packages/cli/.*.bun-build +packages/cli/src/generated/ # FM ADD-ON BUILD ARTIFACTS fm-addon/stage/ diff --git a/packages/cli/bin/proofkit.cjs b/packages/cli/bin/proofkit.cjs new file mode 100644 index 00000000..d5922b0a --- /dev/null +++ b/packages/cli/bin/proofkit.cjs @@ -0,0 +1,59 @@ +#!/usr/bin/env node +"use strict"; + +const { existsSync } = require("node:fs"); +const path = require("node:path"); +const { spawnSync } = require("node:child_process"); + +const BINARIES = { + darwin: { + arm64: "proofkit-darwin-arm64", + x64: "proofkit-darwin-x64", + }, + linux: { + arm64: "proofkit-linux-arm64", + x64: "proofkit-linux-x64", + }, + win32: { + arm64: "proofkit-windows-arm64.exe", + x64: "proofkit-windows-x64.exe", + }, +}; + +function run(command, args) { + const result = spawnSync(command, args, { + stdio: "inherit", + env: { + ...process.env, + PROOFKIT_PKG_ROOT: path.resolve(__dirname, ".."), + }, + }); + + if (result.error) { + throw result.error; + } + + if (typeof result.status === "number") { + process.exit(result.status); + } + + process.exit(1); +} + +if (process.env.PROOFKIT_DISABLE_BUNDLED_BINARY !== "1") { + const binaryName = BINARIES[process.platform]?.[process.arch]; + if (binaryName) { + const binaryPath = path.join(__dirname, binaryName); + if (existsSync(binaryPath)) { + run(binaryPath, process.argv.slice(2)); + } + } +} + +const fallbackPath = path.join(__dirname, "..", "dist", "index.js"); +if (existsSync(fallbackPath)) { + run(process.execPath, [fallbackPath, ...process.argv.slice(2)]); +} + +console.error(`No ProofKit executable found for ${process.platform}-${process.arch}.`); +process.exit(1); diff --git a/packages/cli/package.json b/packages/cli/package.json index 7d0e4d32..99cfe69a 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -25,9 +25,10 @@ } }, "bin": { - "proofkit": "dist/index.js" + "proofkit": "bin/proofkit.cjs" }, "files": [ + "bin", "dist", "template", "README.md", @@ -39,11 +40,12 @@ "node": "^20.0.0 || ^22.0.0" }, "scripts": { - "typecheck": "tsc", - "build": "NODE_ENV=production tsdown && publint --strict", - "prepublishOnly": "pnpm build", + "typecheck": "node ./scripts/write-cli-version.mjs && tsc", + "build": "node ./scripts/write-cli-version.mjs && NODE_ENV=production tsdown && publint --strict", + "build:binaries": "node ./scripts/write-cli-version.mjs && node ./scripts/build-binaries.mjs", + "prepublishOnly": "pnpm build && pnpm build:binaries", "dev": "tsdown --watch", - "clean": "rm -rf dist .turbo node_modules", + "clean": "rm -rf dist .turbo node_modules bin/proofkit-* bin/*.exe", "start": "node dist/index.js", "lint": "biome check . --write", "lint:summary": "biome check . --reporter=summary", @@ -51,10 +53,10 @@ "pub:beta": "NODE_ENV=production pnpm build && npm publish --tag beta --access public", "pub:next": "NODE_ENV=production pnpm build && npm publish --tag next --access public", "pub:release": "NODE_ENV=production pnpm build && npm publish --access public", - "test": "pnpm build && vitest run", + "test": "pnpm build && node ./scripts/build-current-binary.mjs && PROOFKIT_DISABLE_BUNDLED_BINARY=1 vitest run", "test:smoke": "PROOFKIT_RUN_SMOKE_TESTS=1 vitest run --config vitest.smoke.config.ts" }, - "dependencies": { + "devDependencies": { "@better-fetch/fetch": "1.1.17", "@clack/core": "^0.3.5", "@clack/prompts": "^0.11.0", @@ -86,11 +88,8 @@ "randomstring": "^1.3.1", "semver": "^7.7.3", "shadcn": "^2.10.0", - "sort-package-json": "^2.15.1", "ts-morph": "^26.0.0", - "type-fest": "^3.13.1" - }, - "devDependencies": { + "type-fest": "^3.13.1", "@auth/drizzle-adapter": "^1.11.1", "@auth/prisma-adapter": "^1.6.0", "@biomejs/biome": "2.3.11", diff --git a/packages/cli/scripts/build-binaries.mjs b/packages/cli/scripts/build-binaries.mjs new file mode 100644 index 00000000..df6aa844 --- /dev/null +++ b/packages/cli/scripts/build-binaries.mjs @@ -0,0 +1,96 @@ +import { spawnSync } from "node:child_process"; +import { chmodSync, existsSync, mkdirSync, readdirSync, rmSync } from "node:fs"; +import path from "node:path"; +import { fileURLToPath } from "node:url"; + +const __dirname = path.dirname(fileURLToPath(import.meta.url)); +const packageRoot = path.resolve(__dirname, ".."); +const binDir = path.join(packageRoot, "bin"); +const entrypoint = path.join(packageRoot, "src", "index.ts"); + +const targets = [ + { target: "bun-darwin-arm64", file: "proofkit-darwin-arm64" }, + { target: "bun-darwin-x64", file: "proofkit-darwin-x64" }, + { target: "bun-linux-arm64", file: "proofkit-linux-arm64" }, + { target: "bun-linux-x64", file: "proofkit-linux-x64" }, + { target: "bun-windows-arm64", file: "proofkit-windows-arm64.exe" }, + { target: "bun-windows-x64", file: "proofkit-windows-x64.exe" }, +]; +const validTargets = new Set(targets.map((config) => config.target)); +const requestedTargetsEnv = process.env.PROOFKIT_BINARY_TARGETS ?? ""; + +const selectedTargets = new Set( + requestedTargetsEnv + .split(",") + .map((target) => target.trim()) + .filter(Boolean), +); +const filteredSelectedTargets = new Set([...selectedTargets].filter((target) => validTargets.has(target))); + +if (selectedTargets.size > 0 && filteredSelectedTargets.size === 0) { + console.error( + `No valid binary targets in PROOFKIT_BINARY_TARGETS="${requestedTargetsEnv}". Valid targets: ${targets + .map((config) => config.target) + .join(", ")}`, + ); + process.exit(1); +} + +mkdirSync(binDir, { recursive: true }); +for (const file of readdirSync(binDir)) { + if (file === "proofkit.cjs") { + continue; + } + rmSync(path.join(binDir, file), { recursive: true, force: true }); +} + +let builtCount = 0; +for (const config of targets) { + if (filteredSelectedTargets.size > 0 && !filteredSelectedTargets.has(config.target)) { + continue; + } + + const outfile = path.join(binDir, config.file); + const result = spawnSync( + "bun", + [ + "build", + "--compile", + `--target=${config.target}`, + "--no-compile-autoload-dotenv", + "--no-compile-autoload-bunfig", + "--no-compile-autoload-tsconfig", + "--no-compile-autoload-package-json", + entrypoint, + `--outfile=${outfile}`, + ], + { + cwd: packageRoot, + stdio: "inherit", + env: process.env, + }, + ); + + if (result.error) { + throw result.error; + } + + if (result.status !== 0) { + process.exit(result.status ?? 1); + } + + if (existsSync(outfile) && !outfile.endsWith(".exe")) { + chmodSync(outfile, 0o755); + } + + builtCount += 1; +} + +if (builtCount === 0) { + console.error( + `No binary targets selected from PROOFKIT_BINARY_TARGETS="${requestedTargetsEnv}". Valid targets: ${targets + .map((config) => config.target) + .join(", ")}`, + ); + process.exit(1); +} diff --git a/packages/cli/scripts/build-current-binary.mjs b/packages/cli/scripts/build-current-binary.mjs new file mode 100644 index 00000000..9411c431 --- /dev/null +++ b/packages/cli/scripts/build-current-binary.mjs @@ -0,0 +1,22 @@ +import { spawnSync } from "node:child_process"; +import path from "node:path"; +import { fileURLToPath } from "node:url"; + +const __dirname = path.dirname(fileURLToPath(import.meta.url)); +const packageRoot = path.resolve(__dirname, ".."); +const target = `bun-${process.platform}-${process.arch}`; + +const result = spawnSync("node", ["./scripts/build-binaries.mjs"], { + cwd: packageRoot, + stdio: "inherit", + env: { + ...process.env, + PROOFKIT_BINARY_TARGETS: target, + }, +}); + +if (result.error) { + throw result.error; +} + +process.exit(result.status ?? 1); diff --git a/packages/cli/scripts/write-cli-version.mjs b/packages/cli/scripts/write-cli-version.mjs new file mode 100644 index 00000000..55829f82 --- /dev/null +++ b/packages/cli/scripts/write-cli-version.mjs @@ -0,0 +1,27 @@ +import { mkdirSync, readFileSync, writeFileSync } from "node:fs"; +import path from "node:path"; +import { fileURLToPath } from "node:url"; + +const __dirname = path.dirname(fileURLToPath(import.meta.url)); +const packageRoot = path.resolve(__dirname, ".."); +const readVersion = (packagePath) => { + const packageJson = JSON.parse(readFileSync(packagePath, "utf8")); + return packageJson.version ?? "0.0.0-private"; +}; + +const outputPath = path.join(packageRoot, "src", "generated", "package-versions.ts"); +const content = [ + `export const CLI_VERSION = ${JSON.stringify(readVersion(path.join(packageRoot, "package.json")))} as const;`, + `export const FMDAPI_VERSION = ${JSON.stringify(readVersion(path.join(packageRoot, "..", "fmdapi", "package.json")))} as const;`, + `export const BETTER_AUTH_VERSION = ${JSON.stringify( + readVersion(path.join(packageRoot, "..", "better-auth", "package.json")), + )} as const;`, + `export const WEBVIEWER_VERSION = ${JSON.stringify( + readVersion(path.join(packageRoot, "..", "webviewer", "package.json")), + )} as const;`, + `export const TYPEGEN_VERSION = ${JSON.stringify(readVersion(path.join(packageRoot, "..", "typegen", "package.json")))} as const;`, + "", +].join("\n"); + +mkdirSync(path.dirname(outputPath), { recursive: true }); +writeFileSync(outputPath, content, "utf8"); diff --git a/packages/cli/src/consts.ts b/packages/cli/src/consts.ts index 508d6046..be8a4ef5 100644 --- a/packages/cli/src/consts.ts +++ b/packages/cli/src/consts.ts @@ -4,7 +4,7 @@ import { fileURLToPath } from "node:url"; const __filename = fileURLToPath(import.meta.url); const distPath = path.dirname(__filename); -export const PKG_ROOT = path.join(distPath, "../"); +export const PKG_ROOT = process.env.PROOFKIT_PKG_ROOT ?? path.join(distPath, "../"); export const DEFAULT_APP_NAME = "my-proofkit-app"; export const cliName = "proofkit"; diff --git a/packages/cli/src/core/doctor.ts b/packages/cli/src/core/doctor.ts index 85409221..159cbcf8 100644 --- a/packages/cli/src/core/doctor.ts +++ b/packages/cli/src/core/doctor.ts @@ -1,7 +1,7 @@ import path from "node:path"; import { parse as parseDotenv } from "dotenv"; import { Effect } from "effect"; -import { parse as parseJsonc } from "jsonc-parser"; +import { parse as parseJsonc } from "jsonc-parser/lib/esm/main.js"; import { DOCS_URL } from "~/consts.js"; import { CliContext, ConsoleService, FileSystemService } from "~/core/context.js"; diff --git a/packages/cli/src/core/executeInitPlan.ts b/packages/cli/src/core/executeInitPlan.ts index 7228a53e..b51d4f04 100644 --- a/packages/cli/src/core/executeInitPlan.ts +++ b/packages/cli/src/core/executeInitPlan.ts @@ -2,7 +2,6 @@ import path from "node:path"; import { Chalk } from "chalk"; import { Cause, Effect, Exit } from "effect"; import { getOrUndefined } from "effect/Option"; -import sortPackageJson from "sort-package-json"; import { AGENT_INSTRUCTIONS } from "~/consts.js"; import { @@ -21,6 +20,7 @@ import { DirectoryConflictError, FileSystemError, isCliError, UserCancelledError import { applyPackageJsonMutations } from "~/core/planInit.js"; import type { InitPlan } from "~/core/types.js"; import { normalizeImportAlias, replaceTextInFiles, updateTypegenConfig } from "~/utils/projectFiles.js"; +import { sortPackageJson } from "~/utils/sortPackageJson.js"; const AGENT_METADATA_DIRS = new Set([".agents", ".claude", ".clawed", ".clinerules", ".cursor", ".windsurf"]); const IMPORT_ALIAS_WILDCARD_REGEX = /\*/g; @@ -358,6 +358,14 @@ export const executeInitPlan = (plan: InitPlan) => } if (plan.tasks.runInstall) { + if (plan.request.packageManager === "pnpm") { + yield* processService.run("pnpm", ["self-update", "11"], { + cwd: plan.targetDir, + stdout: "pipe", + stderr: "pipe", + }); + } + let installArgs: string[] = ["install"]; if (plan.request.packageManager === "yarn") { installArgs = []; diff --git a/packages/cli/src/core/planInit.ts b/packages/cli/src/core/planInit.ts index c9ef3d99..9beb3701 100644 --- a/packages/cli/src/core/planInit.ts +++ b/packages/cli/src/core/planInit.ts @@ -12,14 +12,6 @@ import { import { formatPackageManagerCommand, getScaffoldVersion, getTemplatePackageCommand } from "~/utils/projectFiles.js"; import { getNodeMajorVersion } from "~/utils/versioning.js"; -const PNPM_BUILD_POLICY = { - "@parcel/watcher": false, - esbuild: true, - "msgpackr-extract": false, - msw: false, - sharp: false, -} as const; - function getPackageManagerMajorVersion(version?: string) { if (!version) { return undefined; @@ -29,10 +21,17 @@ function getPackageManagerMajorVersion(version?: string) { return Number.isFinite(major) ? major : undefined; } -function createPnpmWorkspaceFileContent(policy: Record) { +function createPnpmWorkspaceFileContent() { return [ - "allowBuilds:", - ...Object.entries(policy).map(([packageName, allowed]) => ` ${JSON.stringify(packageName)}: ${allowed}`), + "# This setting defines where in the repo your apps/packages that need installed dependancies exist. This of this as a list of paths to your package.json files. ", + "packages:", + ' - "."', + "", + "trustPolicy: no-downgrade", + "", + "trustPolicyIgnoreAfter: 43200", + "", + "blockExoticSubdeps: true", "", ].join("\n"); } @@ -141,7 +140,7 @@ export function planInit( ? [ { path: path.join(targetDir, "pnpm-workspace.yaml"), - content: createPnpmWorkspaceFileContent(PNPM_BUILD_POLICY), + content: createPnpmWorkspaceFileContent(), }, ] : []), diff --git a/packages/cli/src/generators/fmdapi.ts b/packages/cli/src/generators/fmdapi.ts index 27e54ab0..27602c99 100644 --- a/packages/cli/src/generators/fmdapi.ts +++ b/packages/cli/src/generators/fmdapi.ts @@ -3,7 +3,7 @@ import { generateTypedClients } from "@proofkit/typegen"; import type { typegenConfigSingle } from "@proofkit/typegen/config"; import { config as dotenvConfig } from "dotenv"; import fs from "fs-extra"; -import { applyEdits, modify, parse as parseJsonc } from "jsonc-parser"; +import { applyEdits, modify, parse as parseJsonc } from "jsonc-parser/lib/esm/main.js"; import { SyntaxKind } from "ts-morph"; import type { z } from "zod/v4"; diff --git a/packages/cli/src/index.ts b/packages/cli/src/index.ts index 1049831f..36069496 100644 --- a/packages/cli/src/index.ts +++ b/packages/cli/src/index.ts @@ -1,5 +1,5 @@ #!/usr/bin/env node -import { readFileSync, realpathSync } from "node:fs"; +import { realpathSync } from "node:fs"; import path from "node:path"; import { fileURLToPath } from "node:url"; import { optional as optionalArg, text as textArg, withDescription as withArgDescription } from "@effect/cli/Args"; @@ -37,6 +37,7 @@ import { planInit } from "~/core/planInit.js"; import { runPrompt } from "~/core/prompt.js"; import { resolveInitRequest } from "~/core/resolveInitRequest.js"; import type { CliFlags } from "~/core/types.js"; +import { CLI_VERSION } from "~/generated/package-versions.js"; import { makeLiveLayer } from "~/services/live.js"; import { resolveNonInteractiveMode } from "~/utils/nonInteractive.js"; import { intro } from "~/utils/prompts.js"; @@ -52,13 +53,7 @@ const defaultCliFlags: CliFlags = { }; function getCliVersion() { - try { - const packageJsonUrl = new URL("../package.json", import.meta.url); - const packageJson = JSON.parse(readFileSync(fileURLToPath(packageJsonUrl), "utf8")) as { version?: string }; - return packageJson.version ?? "0.0.0-private"; - } catch { - return "0.0.0-private"; - } + return CLI_VERSION; } export const runInit = (name?: string, rawFlags?: Partial) => diff --git a/packages/cli/src/utils/addPackageDependency.ts b/packages/cli/src/utils/addPackageDependency.ts index c2d139e7..304d9f2a 100644 --- a/packages/cli/src/utils/addPackageDependency.ts +++ b/packages/cli/src/utils/addPackageDependency.ts @@ -1,10 +1,10 @@ import path from "node:path"; import fs from "fs-extra"; -import sortPackageJson from "sort-package-json"; import type { PackageJson } from "type-fest"; import { type AvailableDependencies, dependencyVersionMap } from "~/installers/dependencyVersionMap.js"; import { state } from "~/state.js"; +import { sortPackageJson } from "~/utils/sortPackageJson.js"; export const addPackageDependency = (opts: { dependencies: AvailableDependencies[]; diff --git a/packages/cli/src/utils/getProofKitVersion.ts b/packages/cli/src/utils/getProofKitVersion.ts index f9f30086..b13920f6 100644 --- a/packages/cli/src/utils/getProofKitVersion.ts +++ b/packages/cli/src/utils/getProofKitVersion.ts @@ -1,25 +1,17 @@ -import path from "node:path"; -import fs from "fs-extra"; -import type { PackageJson } from "type-fest"; - -import { PKG_ROOT } from "~/consts.js"; +import { + BETTER_AUTH_VERSION, + CLI_VERSION, + FMDAPI_VERSION, + TYPEGEN_VERSION, + WEBVIEWER_VERSION, +} from "~/generated/package-versions.js"; export const getVersion = () => { - const packageJsonPath = path.join(PKG_ROOT, "package.json"); - - const packageJsonContent = fs.readJSONSync(packageJsonPath) as PackageJson; - - return packageJsonContent.version ?? "1.0.0"; -}; - -const readSiblingPackageVersion = (packagePath: string) => { - const packageJsonPath = path.resolve(PKG_ROOT, "..", packagePath, "package.json"); - const packageJsonContent = fs.readJSONSync(packageJsonPath) as PackageJson; - return packageJsonContent.version ?? "1.0.0"; + return CLI_VERSION; }; export const getFmdapiVersion = () => { - return typeof __FMDAPI_VERSION__ === "undefined" ? readSiblingPackageVersion("fmdapi") : __FMDAPI_VERSION__; + return FMDAPI_VERSION; }; export const getNodeMajorVersion = () => { @@ -32,17 +24,15 @@ export const getNodeMajorVersion = () => { }; export const getProofkitBetterAuthVersion = () => { - return typeof __BETTER_AUTH_VERSION__ === "undefined" - ? readSiblingPackageVersion("better-auth") - : __BETTER_AUTH_VERSION__; + return BETTER_AUTH_VERSION; }; export const getProofkitWebviewerVersion = () => { - return typeof __WEBVIEWER_VERSION__ === "undefined" ? readSiblingPackageVersion("webviewer") : __WEBVIEWER_VERSION__; + return WEBVIEWER_VERSION; }; export const getTypegenVersion = () => { - return typeof __TYPEGEN_VERSION__ === "undefined" ? readSiblingPackageVersion("typegen") : __TYPEGEN_VERSION__; + return TYPEGEN_VERSION; }; export const getProofkitDependencyVersion = (version: string) => `^${version}`; diff --git a/packages/cli/src/utils/projectFiles.ts b/packages/cli/src/utils/projectFiles.ts index 557bc717..4d3c817c 100644 --- a/packages/cli/src/utils/projectFiles.ts +++ b/packages/cli/src/utils/projectFiles.ts @@ -1,6 +1,6 @@ import { readFileSync } from "node:fs"; import path from "node:path"; -import { applyEdits, modify, parse as parseJsonc } from "jsonc-parser"; +import { applyEdits, modify, parse as parseJsonc } from "jsonc-parser/lib/esm/main.js"; import { PKG_ROOT } from "~/consts.js"; import type { FileMakerEnvNames } from "~/core/types.js"; import type { PackageManager } from "~/utils/packageManager.js"; diff --git a/packages/cli/src/utils/sortPackageJson.ts b/packages/cli/src/utils/sortPackageJson.ts new file mode 100644 index 00000000..08ee9eb7 --- /dev/null +++ b/packages/cli/src/utils/sortPackageJson.ts @@ -0,0 +1,85 @@ +const ROOT_KEY_ORDER = [ + "name", + "version", + "private", + "description", + "keywords", + "homepage", + "bugs", + "repository", + "license", + "author", + "contributors", + "funding", + "type", + "packageManager", + "engines", + "bin", + "exports", + "main", + "module", + "types", + "files", + "scripts", + "dependencies", + "devDependencies", + "peerDependencies", + "peerDependenciesMeta", + "optionalDependencies", + "bundledDependencies", + "resolutions", + "overrides", + "pnpm", + "lint-staged", +] as const; + +const ROOT_KEY_POSITION = new Map(ROOT_KEY_ORDER.map((key, index) => [key, index])); +const SORTED_OBJECT_KEYS = new Set([ + "scripts", + "dependencies", + "devDependencies", + "peerDependencies", + "peerDependenciesMeta", + "optionalDependencies", + "bundledDependencies", + "resolutions", + "overrides", +]); + +function compareRootKeys(left: string, right: string) { + const leftIndex = ROOT_KEY_POSITION.get(left); + const rightIndex = ROOT_KEY_POSITION.get(right); + + if (leftIndex !== undefined && rightIndex !== undefined) { + return leftIndex - rightIndex; + } + + if (leftIndex !== undefined) { + return -1; + } + + if (rightIndex !== undefined) { + return 1; + } + + return left.localeCompare(right); +} + +function sortRecord(value: Record) { + return Object.fromEntries(Object.entries(value).sort(([left], [right]) => left.localeCompare(right))); +} + +export function sortPackageJson>(packageJson: T): T { + const sortedEntries = Object.entries(packageJson).sort(([left], [right]) => compareRootKeys(left, right)); + const sortedPackageJson = Object.fromEntries( + sortedEntries.map(([key, value]) => { + if (SORTED_OBJECT_KEYS.has(key) && value && typeof value === "object" && !Array.isArray(value)) { + return [key, sortRecord(value as Record)]; + } + + return [key, value]; + }), + ); + + return sortedPackageJson as T; +} diff --git a/packages/cli/template/nextjs-shadcn/src/app/navigation.tsx b/packages/cli/template/nextjs-shadcn/src/app/navigation.tsx index 887073db..4091f1c5 100644 --- a/packages/cli/template/nextjs-shadcn/src/app/navigation.tsx +++ b/packages/cli/template/nextjs-shadcn/src/app/navigation.tsx @@ -1,4 +1,4 @@ -import { type ProofKitRoute } from "@proofkit/cli"; +import { type ProofKitRoute } from "./proofkit-route"; export const primaryRoutes: ProofKitRoute[] = [ { diff --git a/packages/cli/template/nextjs-shadcn/src/app/proofkit-route.ts b/packages/cli/template/nextjs-shadcn/src/app/proofkit-route.ts new file mode 100644 index 00000000..a370053c --- /dev/null +++ b/packages/cli/template/nextjs-shadcn/src/app/proofkit-route.ts @@ -0,0 +1,19 @@ +import type React from "react"; + +interface RouteLink { + label: string; + type: "link"; + href: string; + icon?: React.ReactNode; + exactMatch?: boolean; +} + +interface RouteFunction { + label: string; + type: "function"; + icon?: React.ReactNode; + onClick: () => void; + exactMatch?: boolean; +} + +export type ProofKitRoute = RouteLink | RouteFunction; diff --git a/packages/cli/template/nextjs-shadcn/src/components/AppShell/internal/HeaderNavLink.tsx b/packages/cli/template/nextjs-shadcn/src/components/AppShell/internal/HeaderNavLink.tsx index 06ce2676..8e106d85 100644 --- a/packages/cli/template/nextjs-shadcn/src/components/AppShell/internal/HeaderNavLink.tsx +++ b/packages/cli/template/nextjs-shadcn/src/components/AppShell/internal/HeaderNavLink.tsx @@ -1,9 +1,9 @@ "use client"; -import { type ProofKitRoute } from "@proofkit/cli"; import { usePathname } from "next/navigation"; import React from "react"; +import { type ProofKitRoute } from "@/app/proofkit-route"; import classes from "./Header.module.css"; export default function HeaderNavLink(route: ProofKitRoute) { diff --git a/packages/cli/tests/browser-apps.smoke.test.ts b/packages/cli/tests/browser-apps.smoke.test.ts index ec666762..846dedd3 100644 --- a/packages/cli/tests/browser-apps.smoke.test.ts +++ b/packages/cli/tests/browser-apps.smoke.test.ts @@ -28,7 +28,7 @@ describeWhenSmokeEnvPresent("External integration smoke tests (non-interactive C } const testDir = join(tmpdir(), "proofkit-cli-tests"); - const cliPath = join(__dirname, "..", "dist", "index.js"); + const cliPath = join(__dirname, "..", "bin", "proofkit.cjs"); const projectName = "test-fm-project"; const projectDir = join(testDir, projectName); diff --git a/packages/cli/tests/cli.test.ts b/packages/cli/tests/cli.test.ts index bd22003d..2195a9d7 100644 --- a/packages/cli/tests/cli.test.ts +++ b/packages/cli/tests/cli.test.ts @@ -7,7 +7,7 @@ import { describe, expect, it } from "vitest"; const __dirname = path.dirname(fileURLToPath(import.meta.url)); const packageDir = path.join(__dirname, ".."); -const distEntry = path.join(packageDir, "dist/index.js"); +const distEntry = path.join(packageDir, "bin/proofkit.cjs"); describe("proofkit CLI", () => { it("shows kebab-case init flags in help", () => { diff --git a/packages/cli/tests/executor.test.ts b/packages/cli/tests/executor.test.ts index b4099aeb..1d929745 100644 --- a/packages/cli/tests/executor.test.ts +++ b/packages/cli/tests/executor.test.ts @@ -61,7 +61,7 @@ describe("executeInitPlan command paths", () => { await Effect.runPromise(executeInitPlan(plan).pipe(makeTestLayer({ cwd, packageManager: "pnpm", tracker }))); - expect(tracker.commands).toEqual(["pnpm install"]); + expect(tracker.commands).toEqual(["pnpm self-update 11", "pnpm install"]); expect(tracker.filemakerBootstraps).toBe(1); expect(tracker.codegens).toBe(1); expect(tracker.gitInits).toBe(1); @@ -73,7 +73,9 @@ describe("executeInitPlan command paths", () => { expect(envFile).toContain("FM_DATABASE=Contacts.fmp12"); expect(typegenConfig).toContain("API_Contacts"); expect(typegenConfig).toContain("Contacts"); - expect(pnpmWorkspaceFile).toContain(' "esbuild": true'); + expect(pnpmWorkspaceFile).toContain("trustPolicy: no-downgrade"); + expect(pnpmWorkspaceFile).toContain("trustPolicyIgnoreAfter: 43200"); + expect(pnpmWorkspaceFile).toContain("blockExoticSubdeps: true"); }); it("supports force overwrite for an existing directory", async () => { @@ -346,7 +348,7 @@ describe("executeInitPlan command paths", () => { appType: "browser", ui: "shadcn", dataSource: "none", - packageManager: "pnpm", + packageManager: "npm", noInstall: false, noGit: true, force: false, @@ -367,11 +369,11 @@ describe("executeInitPlan command paths", () => { executeInitPlan(plan).pipe( makeTestLayer({ cwd, - packageManager: "pnpm", + packageManager: "npm", failures: { processRun: new ExternalCommandError({ message: "install failed", - command: "pnpm", + command: "npm", args: ["install"], cwd, }), @@ -382,7 +384,7 @@ describe("executeInitPlan command paths", () => { ).toMatchObject( new ExternalCommandError({ message: "install failed", - command: "pnpm", + command: "npm", args: ["install"], cwd, }), diff --git a/packages/cli/tests/init-non-interactive-failures.test.ts b/packages/cli/tests/init-non-interactive-failures.test.ts index f0979458..b5f2c554 100644 --- a/packages/cli/tests/init-non-interactive-failures.test.ts +++ b/packages/cli/tests/init-non-interactive-failures.test.ts @@ -22,7 +22,7 @@ function toText(value: string | Buffer | undefined) { describe("Init Non-Interactive Failure Paths", () => { const testDir = join(__dirname, "..", "..", "tmp", "init-failure-tests"); - const cliPath = join(__dirname, "..", "dist", "index.js"); + const cliPath = join(__dirname, "..", "bin", "proofkit.cjs"); const expectedTypegenVersion = `^${ JSON.parse(readFileSync(join(__dirname, "..", "..", "typegen", "package.json"), "utf-8")).version }`; diff --git a/packages/cli/tests/init-scaffold-contract.test.ts b/packages/cli/tests/init-scaffold-contract.test.ts index 59b34344..3821b35d 100644 --- a/packages/cli/tests/init-scaffold-contract.test.ts +++ b/packages/cli/tests/init-scaffold-contract.test.ts @@ -1,7 +1,7 @@ import { execFileSync } from "node:child_process"; import { existsSync, mkdirSync, readFileSync, rmSync } from "node:fs"; import { join } from "node:path"; -import { parse as parseJsonc } from "jsonc-parser"; +import { parse as parseJsonc } from "jsonc-parser/lib/esm/main.js"; import { beforeEach, describe, expect, it } from "vitest"; interface PackageJsonShape { @@ -23,7 +23,7 @@ interface ProofkitSettings { dataSources?: unknown[]; } -const cliPath = join(__dirname, "..", "dist", "index.js"); +const cliPath = join(__dirname, "..", "bin", "proofkit.cjs"); const testDir = join(__dirname, "..", "..", "tmp", "cli-contract-tests"); const browserProjectName = "contract-browser-project"; const webviewerProjectName = "contract-webviewer-project"; @@ -166,10 +166,11 @@ describe("Init scaffold contract tests", () => { expect(readFileSync(join(browserProjectDir, "CLAUDE.md"), "utf-8")).toBe("@AGENTS.md\n"); expect(readFileSync(join(browserProjectDir, ".cursorignore"), "utf-8")).toBe("CLAUDE.md\n"); const pnpmWorkspaceText = readFileSync(join(browserProjectDir, "pnpm-workspace.yaml"), "utf-8"); - expect(pnpmWorkspaceText).toContain(' "esbuild": true'); - expect(pnpmWorkspaceText).toContain(' "msw": false'); - expect(pnpmWorkspaceText).toContain(' "@parcel/watcher": false'); - expect(pnpmWorkspaceText).toContain(' "sharp": false'); + expect(pnpmWorkspaceText).toContain("packages:"); + expect(pnpmWorkspaceText).toContain(' - "."'); + expect(pnpmWorkspaceText).toContain("trustPolicy: no-downgrade"); + expect(pnpmWorkspaceText).toContain("trustPolicyIgnoreAfter: 43200"); + expect(pnpmWorkspaceText).toContain("blockExoticSubdeps: true"); const pkgManager = getPackageManagerName(packageJson); expect(outputSuggestsCommand(normalizedOutput, formatRunCommand(pkgManager, "typegen"))).toBe(false); @@ -244,10 +245,11 @@ describe("Init scaffold contract tests", () => { expect(uploadScriptText).toContain("const deployment = await deployHtml({"); expect(uploadScriptText).toContain("Deployed via FM MCP bridge."); expect(filemakerHelperText).toContain('scriptName = "deploy_html"'); - expect(pnpmWorkspaceText).toContain(' "esbuild": true'); - expect(pnpmWorkspaceText).toContain(' "msw": false'); - expect(pnpmWorkspaceText).toContain(' "@parcel/watcher": false'); - expect(pnpmWorkspaceText).toContain(' "sharp": false'); + expect(pnpmWorkspaceText).toContain("packages:"); + expect(pnpmWorkspaceText).toContain(' - "."'); + expect(pnpmWorkspaceText).toContain("trustPolicy: no-downgrade"); + expect(pnpmWorkspaceText).toContain("trustPolicyIgnoreAfter: 43200"); + expect(pnpmWorkspaceText).toContain("blockExoticSubdeps: true"); // Compile-equivalent smoke checks without external installs. expect(checkNodeSyntax(webviewerProjectDir, "scripts/upload.js")).toBe(true); diff --git a/packages/cli/tests/planner.test.ts b/packages/cli/tests/planner.test.ts index 2bf652c2..8d248ce9 100644 --- a/packages/cli/tests/planner.test.ts +++ b/packages/cli/tests/planner.test.ts @@ -35,12 +35,15 @@ describe("planInit", () => { expect(plan.writes).toContainEqual({ path: path.resolve("/tmp/workspace", "demo-app", "pnpm-workspace.yaml"), content: [ - "allowBuilds:", - ' "@parcel/watcher": false', - ' "esbuild": true', - ' "msgpackr-extract": false', - ' "msw": false', - ' "sharp": false', + "# This setting defines where in the repo your apps/packages that need installed dependancies exist. This of this as a list of paths to your package.json files. ", + "packages:", + ' - "."', + "", + "trustPolicy: no-downgrade", + "", + "trustPolicyIgnoreAfter: 43200", + "", + "blockExoticSubdeps: true", "", ].join("\n"), }); @@ -68,12 +71,15 @@ describe("planInit", () => { expect(plan.writes).toContainEqual({ path: path.resolve("/tmp/workspace", "demo-app", "pnpm-workspace.yaml"), content: [ - "allowBuilds:", - ' "@parcel/watcher": false', - ' "esbuild": true', - ' "msgpackr-extract": false', - ' "msw": false', - ' "sharp": false', + "# This setting defines where in the repo your apps/packages that need installed dependancies exist. This of this as a list of paths to your package.json files. ", + "packages:", + ' - "."', + "", + "trustPolicy: no-downgrade", + "", + "trustPolicyIgnoreAfter: 43200", + "", + "blockExoticSubdeps: true", "", ].join("\n"), }); diff --git a/packages/cli/tests/webviewer-apps.test.ts b/packages/cli/tests/webviewer-apps.test.ts index bca4dcd3..a3a222ea 100644 --- a/packages/cli/tests/webviewer-apps.test.ts +++ b/packages/cli/tests/webviewer-apps.test.ts @@ -10,7 +10,7 @@ const expectedTypegenVersion = `^${ describe("Web Viewer CLI Tests", () => { const testDir = join(__dirname, "..", "..", "tmp", "cli-tests"); - const cliPath = join(__dirname, "..", "dist", "index.js"); + const cliPath = join(__dirname, "..", "bin", "proofkit.cjs"); const projectName = "test-webviewer-project"; const projectDir = join(testDir, projectName); diff --git a/packages/cli/tsdown.config.ts b/packages/cli/tsdown.config.ts index 9f9ed81b..0cb69d19 100644 --- a/packages/cli/tsdown.config.ts +++ b/packages/cli/tsdown.config.ts @@ -1,32 +1,7 @@ -import path from "node:path"; -import { fileURLToPath } from "node:url"; -import fsExtra from "fs-extra"; import { defineConfig } from "tsdown"; -const { readJSONSync } = fsExtra; -const __dirname = path.dirname(fileURLToPath(import.meta.url)); const isDev = process.env.npm_lifecycle_event === "dev"; -const readPackageVersion = (packagePath: string) => { - const packageJsonPath = path.join(__dirname, "..", packagePath, "package.json"); - const packageJson = readJSONSync(packageJsonPath); - if (!packageJson.version) { - throw new Error(`No version found in ${packageJsonPath}`); - } - return packageJson.version; -}; - -const FMDAPI_VERSION = readPackageVersion("fmdapi"); -const BETTER_AUTH_VERSION = readPackageVersion("better-auth"); -const WEBVIEWER_VERSION = readPackageVersion("webviewer"); -const TYPEGEN_VERSION = readPackageVersion("typegen"); -const versionDefines = { - __FMDAPI_VERSION__: JSON.stringify(FMDAPI_VERSION), - __BETTER_AUTH_VERSION__: JSON.stringify(BETTER_AUTH_VERSION), - __WEBVIEWER_VERSION__: JSON.stringify(WEBVIEWER_VERSION), - __TYPEGEN_VERSION__: JSON.stringify(TYPEGEN_VERSION), -}; - export default defineConfig({ clean: true, entry: ["src/index.ts"], @@ -35,16 +10,4 @@ export default defineConfig({ target: "esnext", outDir: "dist", nodeProtocol: false, - plugins: [ - { - name: "proofkit-version-defines", - transform(code) { - let nextCode = code; - for (const [name, value] of Object.entries(versionDefines)) { - nextCode = nextCode.replaceAll(name, value); - } - return nextCode === code ? null : { code: nextCode, map: null }; - }, - }, - ], }); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d607724e..35936df1 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -267,10 +267,19 @@ importers: version: 4.0.17(@opentelemetry/api@1.9.1)(@types/node@25.0.6)(@vitest/ui@3.2.4)(happy-dom@20.1.0)(jiti@2.6.1)(lightningcss@1.30.2)(msw@2.12.7(@types/node@25.0.6)(typescript@5.9.3))(tsx@4.21.0)(yaml@2.8.2) packages/cli: - dependencies: + devDependencies: + '@auth/drizzle-adapter': + specifier: ^1.11.1 + version: 1.11.1 + '@auth/prisma-adapter': + specifier: ^1.6.0 + version: 1.6.0(@prisma/client@5.22.0(prisma@5.22.0)) '@better-fetch/fetch': specifier: 1.1.17 version: 1.1.17 + '@biomejs/biome': + specifier: 2.3.11 + version: 2.3.11 '@clack/core': specifier: ^0.3.5 version: 0.3.5 @@ -295,91 +304,6 @@ importers: '@inquirer/prompts': specifier: ^8.3.2 version: 8.3.2(@types/node@22.19.5) - '@proofkit/fmdapi': - specifier: workspace:* - version: link:../fmdapi - '@proofkit/typegen': - specifier: workspace:* - version: link:../typegen - '@types/glob': - specifier: ^8.1.0 - version: 8.1.0 - axios: - specifier: ^1.13.2 - version: 1.13.2 - chalk: - specifier: 5.4.1 - version: 5.4.1 - commander: - specifier: ^14.0.2 - version: 14.0.2 - dotenv: - specifier: ^16.6.1 - version: 16.6.1 - effect: - specifier: ^3.20.0 - version: 3.20.0 - es-toolkit: - specifier: ^1.43.0 - version: 1.43.0 - execa: - specifier: ^9.6.1 - version: 9.6.1 - fast-glob: - specifier: ^3.3.3 - version: 3.3.3 - fs-extra: - specifier: ^11.3.3 - version: 11.3.3 - glob: - specifier: ^11.1.0 - version: 11.1.0 - gradient-string: - specifier: ^2.0.2 - version: 2.0.2 - handlebars: - specifier: ^4.7.8 - version: 4.7.8 - jiti: - specifier: ^1.21.7 - version: 1.21.7 - jsonc-parser: - specifier: ^3.3.1 - version: 3.3.1 - open: - specifier: ^10.2.0 - version: 10.2.0 - ora: - specifier: 6.3.1 - version: 6.3.1 - randomstring: - specifier: ^1.3.1 - version: 1.3.1 - semver: - specifier: ^7.7.3 - version: 7.7.3 - shadcn: - specifier: ^2.10.0 - version: 2.10.0(@types/node@22.19.5)(hono@4.12.18)(typescript@5.9.3) - sort-package-json: - specifier: ^2.15.1 - version: 2.15.1 - ts-morph: - specifier: ^26.0.0 - version: 26.0.0 - type-fest: - specifier: ^3.13.1 - version: 3.13.1 - devDependencies: - '@auth/drizzle-adapter': - specifier: ^1.11.1 - version: 1.11.1 - '@auth/prisma-adapter': - specifier: ^1.6.0 - version: 1.6.0(@prisma/client@5.22.0(prisma@5.22.0)) - '@biomejs/biome': - specifier: 2.3.11 - version: 2.3.11 '@libsql/client': specifier: ^0.6.2 version: 0.6.2 @@ -392,6 +316,12 @@ importers: '@prisma/client': specifier: ^5.22.0 version: 5.22.0(prisma@5.22.0) + '@proofkit/fmdapi': + specifier: workspace:* + version: link:../fmdapi + '@proofkit/typegen': + specifier: workspace:* + version: link:../typegen '@rollup/plugin-replace': specifier: ^6.0.3 version: 6.0.3(rollup@4.55.1) @@ -419,6 +349,9 @@ importers: '@types/fs-extra': specifier: ^11.0.4 version: 11.0.4 + '@types/glob': + specifier: ^8.1.0 + version: 8.1.0 '@types/gradient-string': specifier: ^1.1.6 version: 1.1.6 @@ -437,12 +370,54 @@ importers: '@vitest/coverage-v8': specifier: ^2.1.9 version: 2.1.9(vitest@4.0.17(@opentelemetry/api@1.9.1)(@types/node@22.19.5)(happy-dom@20.1.0)(jiti@1.21.7)(lightningcss@1.30.2)(msw@2.12.7(@types/node@22.19.5)(typescript@5.9.3))(tsx@4.21.0)(yaml@2.8.2)) + axios: + specifier: ^1.13.2 + version: 1.13.2 + chalk: + specifier: 5.4.1 + version: 5.4.1 + commander: + specifier: ^14.0.2 + version: 14.0.2 + dotenv: + specifier: ^16.6.1 + version: 16.6.1 drizzle-kit: specifier: ^0.21.4 version: 0.21.4 drizzle-orm: specifier: ^0.30.10 version: 0.30.10(@libsql/client@0.6.2)(@opentelemetry/api@1.9.1)(@planetscale/database@1.19.0)(@types/react@19.2.7)(kysely@0.28.12)(mysql2@3.16.0)(postgres@3.4.8)(react@19.2.3) + effect: + specifier: ^3.20.0 + version: 3.20.0 + es-toolkit: + specifier: ^1.43.0 + version: 1.43.0 + execa: + specifier: ^9.6.1 + version: 9.6.1 + fast-glob: + specifier: ^3.3.3 + version: 3.3.3 + fs-extra: + specifier: ^11.3.3 + version: 11.3.3 + glob: + specifier: ^11.1.0 + version: 11.1.0 + gradient-string: + specifier: ^2.0.2 + version: 2.0.2 + handlebars: + specifier: ^4.7.8 + version: 4.7.8 + jiti: + specifier: ^1.21.7 + version: 1.21.7 + jsonc-parser: + specifier: ^3.3.1 + version: 3.3.1 mysql2: specifier: ^3.16.0 version: 3.16.0 @@ -452,6 +427,12 @@ importers: next-auth: specifier: ^4.24.13 version: 4.24.13(next@16.1.1(@opentelemetry/api@1.9.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + open: + specifier: ^10.2.0 + version: 10.2.0 + ora: + specifier: 6.3.1 + version: 6.3.1 postgres: specifier: ^3.4.8 version: 3.4.8 @@ -461,21 +442,36 @@ importers: publint: specifier: ^0.3.16 version: 0.3.16 + randomstring: + specifier: ^1.3.1 + version: 1.3.1 react: specifier: 19.2.3 version: 19.2.3 react-dom: specifier: 19.2.3 version: 19.2.3(react@19.2.3) + semver: + specifier: ^7.7.3 + version: 7.7.3 + shadcn: + specifier: ^2.10.0 + version: 2.10.0(@types/node@22.19.5)(hono@4.12.18)(typescript@5.9.3) superjson: specifier: ^2.2.6 version: 2.2.6 tailwindcss: specifier: ^4.1.18 version: 4.1.18 + ts-morph: + specifier: ^26.0.0 + version: 26.0.0 tsdown: specifier: ^0.14.2 version: 0.14.2(oxc-resolver@11.16.2(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0))(publint@0.3.16)(typescript@5.9.3) + type-fest: + specifier: ^3.13.1 + version: 3.13.1 typescript: specifier: ^5.9.3 version: 5.9.3 @@ -5694,10 +5690,6 @@ packages: resolution: {integrity: sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==} engines: {node: '>=8'} - detect-indent@7.0.2: - resolution: {integrity: sha512-y+8xyqdGLL+6sh0tVeHcfP/QDd8gUgbasolJJpY7NgeQGSZ739bDtSiaiDgtoicy+mtYB81dKLxO9xRhCyIB3A==} - engines: {node: '>=12.20'} - detect-libc@2.0.2: resolution: {integrity: sha512-UX6sGumvvqSaXgdKGUsgZWqcUyIXZ/vZTrlRT/iobiKhGL0zL4d3osHj3uqllWJK+i+sixDS/3COVEOFbupFyw==} engines: {node: '>=8'} @@ -5706,10 +5698,6 @@ packages: resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} engines: {node: '>=8'} - detect-newline@4.0.1: - resolution: {integrity: sha512-qE3Veg1YXzGHQhlA6jzebZN2qVf6NX+A7m7qlhCGG30dJixrAQhYOsJjsnBjJkCSmuOPpCk30145fr8FV0bzog==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - detect-node-es@1.1.0: resolution: {integrity: sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==} @@ -6398,10 +6386,6 @@ packages: resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} engines: {node: '>= 0.4'} - get-stdin@9.0.0: - resolution: {integrity: sha512-dVKBjfWisLAicarI2Sf+JuBE/DghV4UzNAVe9yhEJuzeREd3JhOTE9cUaJTeSa77fsbQUK3pcOpJfM59+VKZaA==} - engines: {node: '>=12'} - get-stream@6.0.1: resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==} engines: {node: '>=10'} @@ -6417,9 +6401,6 @@ packages: resolution: {integrity: sha512-L5bGsVkxJbJgdnwyuheIunkGatUF/zssUoxxjACCseZYAVbaqdh9Tsmmlkl8vYan09H7sbvKt4pS8GqKLBrEzA==} hasBin: true - git-hooks-list@3.2.0: - resolution: {integrity: sha512-ZHG9a1gEhUMX1TvGrLdyWb9kDopCBbTnI8z4JgRMYxsijWipgjSEYoPWqBuIB0DnRnvqlQSEeVmzpeuPm7NdFQ==} - github-slugger@2.0.0: resolution: {integrity: sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw==} @@ -8516,13 +8497,6 @@ packages: react: ^18.0.0 || ^19.0.0 || ^19.0.0-rc react-dom: ^18.0.0 || ^19.0.0 || ^19.0.0-rc - sort-object-keys@1.1.3: - resolution: {integrity: sha512-855pvK+VkU7PaKYPc+Jjnmt4EzejQHyhhF33q31qG8x7maDzkeFhAAThdCYay11CISO+qAMwjOBP+fPZe0IPyg==} - - sort-package-json@2.15.1: - resolution: {integrity: sha512-9x9+o8krTT2saA9liI4BljNjwAbvUnWf11Wq+i/iZt8nl2UGYnf3TH5uBydE7VALmP7AGwlfszuEeL8BDyb0YA==} - hasBin: true - source-map-js@1.2.1: resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} engines: {node: '>=0.10.0'} @@ -14133,14 +14107,10 @@ snapshots: detect-indent@6.1.0: {} - detect-indent@7.0.2: {} - detect-libc@2.0.2: {} detect-libc@2.1.2: {} - detect-newline@4.0.1: {} - detect-node-es@1.1.0: {} devlop@1.1.0: @@ -14954,8 +14924,6 @@ snapshots: dunder-proto: 1.0.1 es-object-atoms: 1.1.1 - get-stdin@9.0.0: {} - get-stream@6.0.1: {} get-stream@9.0.1: @@ -14976,8 +14944,6 @@ snapshots: nypm: 0.6.2 pathe: 2.0.3 - git-hooks-list@3.2.0: {} - github-slugger@2.0.0: {} glob-parent@5.1.2: @@ -17735,19 +17701,6 @@ snapshots: react: 19.2.3 react-dom: 19.2.3(react@19.2.3) - sort-object-keys@1.1.3: {} - - sort-package-json@2.15.1: - dependencies: - detect-indent: 7.0.2 - detect-newline: 4.0.1 - get-stdin: 9.0.0 - git-hooks-list: 3.2.0 - is-plain-obj: 4.1.0 - semver: 7.7.3 - sort-object-keys: 1.1.3 - tinyglobby: 0.2.15 - source-map-js@1.2.1: {} source-map-support@0.5.21: