diff --git a/.circleci/config.yml b/.circleci/config.yml index 41d5e1fdc..3c836c967 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -21,9 +21,6 @@ jobs: # Add steps to the job # See: https://circleci.com/docs/2.0/configuration-reference/#steps steps: - - run: - name: Install pnpm - command: sudo npm install -g corepack@latest && sudo corepack enable - checkout - restore_cache: # See the configuration reference documentation for more details on using restore_cache and save_cache steps diff --git a/CLAUDE.md b/CLAUDE.md index 5e314906f..8e716399b 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -1,165 +1,78 @@ -# OpenFn Kit +# CLAUDE.md -This monorepo contains the core packages that power OpenFn's workflow automation platform. OpenFn is a Digital Public Good trusted by NGOs and governments in 40+ countries to automate data integration workflows. +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. -## Architecture +OpenFn kit is the pnpm monorepo behind OpenFn's workflow automation: the CLI, the Runtime that executes jobs, and the Worker that runs jobs in production for Lightning (OpenFn's web platform). -The repository has three main packages: **CLI**, **Runtime**, and **Worker**. The CLI and Worker are both frontends for executing workflows - the CLI for local development, the Worker for production execution via Lightning (the web platform). Both wrap the Runtime as their execution engine. The Worker uses engine-multi to wrap the Runtime for multi-process execution. +## How the pieces fit -## Core Packages +- **@openfn/runtime** executes a workflow plan in a sandboxed Node VM. A workflow is a graph of steps (jobs) joined by conditional edges. A job is an array of operations, each a function from state to state. State is never mutated between jobs. +- **@openfn/compiler** turns job DSL into a standard ES module that imports from its adaptor (an npm package such as `@openfn/language-http`) and exports the operations array. +- **@openfn/cli** is the local frontend. It compiles jobs itself and calls the runtime in-process. +- **@openfn/ws-worker** is the production frontend. It is stateless: it claims runs from Lightning over websockets and reports events back, and Lightning owns all persistence. It never imports the compiler. It hands plans to **@openfn/engine-multi**, which compiles and runs each one in a worker thread inside a child process. +- **@openfn/project** models local projects and workspaces (`Workspace`, `Project`, YAML parsing, diffs, version hashes). The CLI's `project` handlers in `packages/cli/src/projects/` are thin layers over it, and this is the most actively developed area of the repo. Sync with Lightning uses its v2 endpoint. +- Supporting: `lexicon` (shared types), `logger`, `lightning-mock` (fake Lightning for worker tests), `deploy` and `describe-package` (both being phased out). -- **[@openfn/cli](packages/cli)** - Command-line interface for local development. Run, test, compile, and deploy workflows. -- **[@openfn/runtime](packages/runtime)** - Core execution engine. Safely executes jobs in a sandboxed VM environment. -- **[@openfn/ws-worker](packages/ws-worker)** - WebSocket worker connecting Lightning to the Runtime. Stateless server that pulls runs from Lightning's queue. See [.claude/event-processor.md](.claude/event-processor.md) for event processing details. -- **[@openfn/engine-multi](packages/engine-multi)** - Multi-process runtime wrapper used by ws-worker for concurrent workflow execution. -- **[@openfn/compiler](packages/compiler)** - Transforms OpenFn job DSL into executable JavaScript modules. +Every internal dependency is `workspace:*` and resolves to the dependency's built `dist/`, not its `src/`. engine-multi also runs its worker processes from `dist/`. -## Supporting Packages +## Commands -- **@openfn/lexicon** - Shared TypeScript types -- **@openfn/logger** - Structured logging utilities -- **@openfn/describe-package** - TypeScript analysis for adaptor docs (to be phased out) -- **@openfn/deploy** - Deployment logic for Lightning (soon to be deprecated) -- **@openfn/project** - Models and understands local OpenFn projects -- **@openfn/lightning-mock** - Mock Lightning server for testing - -## AI Assistant - -- Keep responses terse and do not over-explain. Users will ask for more guidance if they need it. -- Always present users a short action plan and ask for confirmation before doing it -- Keep the human in the loop at all times. Stop regularly and check for guidance. - -## Key Concepts - -**Workflows** are sequences of **jobs** that process data through steps. Each **job** is an array of **operations** (functions that transform state). State flows between jobs based on conditional edges. - -**Adaptors** are npm packages (e.g., `@openfn/language-http`) providing operations for specific systems. The CLI auto-installs them as needed. - -The **Compiler** transforms job DSL code into standard ES modules with imports and operation arrays. - -## Working with Projects - -A **workspace** holds one or more local **projects** that sync with Lightning. The CLI `project` subcommand (package: `@openfn/project`) is the most actively-developed area of the repo; handlers live in `packages/cli/src/projects/`. Sync uses Lightning's v2 endpoint. +Node is pinned in `.tool-versions` (use `asdf`), and pnpm switches itself to the version pinned in `packageManager` (install any pnpm with `npm install -g pnpm`; corepack no longer ships with Node). ```bash -openfn project list # List projects in the current workspace -openfn project pull [project] # Pull from Lightning to the filesystem (fetch + checkout) -openfn project fetch [project] # Download project state without expanding it -openfn project checkout # Switch the active project in the workspace -openfn project deploy [project] # Deploy the checked-out project to Lightning -openfn project clean # Delete the workflows folder and re-checkout the active project -openfn project version [workflow] # Show the version hash of a workflow +pnpm install +pnpm build # all packages +pnpm --filter @openfn/cli build # one package +pnpm test # all package tests +pnpm test:types # tsc per package +pnpm format / pnpm test:format # prettier write / check (there is no eslint) +pnpm _typesync # after changing dependencies ``` -New subcommands follow the existing pattern in `packages/cli/src/projects/` (`list.ts` is the simplest reference). - -## Development Setup - -### Prerequisites - -- Node.js 24 (pinned in `.tool-versions`; `package.json` engines still allows `>=18`). Use `asdf`. -- pnpm (enable with `corepack enable`) - -### Common Commands +Tests use ava with the shared root `ava.config.js`, which runs `test/**/*test.ts` straight from `src/` via `@swc-node/register`. Because workspace deps come from `dist/`, run `pnpm build` first when a test crosses packages or uses engine-multi. When unsure, build. ```bash -# Root -pnpm install # Install dependencies -pnpm build # Build all packages -pnpm test # Run all tests -pnpm format # Format all packages with Prettier -pnpm changeset # Add a changeset for your PR - -# CLI -cd packages/cli -pnpm openfn test # Run from source -pnpm install:global # Install as 'openfnx' for testing - -# Worker -cd packages/ws-worker -pnpm start # Connect to localhost:4000 -pnpm start -l mock # Use mock Lightning -pnpm start --no-loop # Disable auto-fetch -curl -X POST http://localhost:2222/claim # Manual claim +cd packages/project +pnpm ava test/util/config.test.ts # one file +pnpm ava test/util/config.test.ts -m "name*" # tests matching a title ``` -### Environment Variables - -**CLI:** -- `OPENFN_REPO_DIR` - CLI adaptor storage -- `OPENFN_ADAPTORS_REPO` - Local adaptors monorepo path -- `OPENFN_API_KEY` - API key for Lightning deployment -- `OPENFN_ENDPOINT` - Lightning URL (default: app.openfn.org) - -**Worker:** -- `WORKER_SECRET` - Worker authentication secret -- Many other `WORKER_*` vars (capacity, port, backoff, max payload, Sentry DSN, …) — see `packages/ws-worker/src/util/cli.ts`. - -## Repository Structure - -``` -packages/ -├── cli/ # CLI entry: cli.ts, commands.ts, projects/, options.ts -├── runtime/ # Runtime entry: index.ts, runtime.ts, modules/linker -├── ws-worker/ # Worker entry: start.ts, server.ts, api/, events/ -├── compiler/ # Job DSL compiler -├── engine-multi/ # Multi-process wrapper -├── lexicon/ # Shared TypeScript types -└── logger/ # Logging utilities -``` - -## Testing & Releases - -```bash -pnpm test # All tests -pnpm test:types # Type checking -pnpm test:integration # Integration tests -cd packages/cli && pnpm test:watch # Watch mode -``` +ws-worker and engine-multi run with `--serial`; keep new tests there compatible with that. -## Testing Best Practice +### Running things locally -- Ensure tests are valuable before generating them. Focus on what's important. -- Treat tests as documentation: they should show how the function is expected to work -- Keep tests focuses: test one thing in each test -- This repo contains extensive testing: check for similar patterns in the same package before improvising +- **CLI**: `cd packages/cli && pnpm openfn ` runs the built `dist/`, so rebuild (or `pnpm build:watch`) after changes. `pnpm install:global` from root installs a global `openfnx` for testing; remove it with `npm uninstall -g @openfn/clix`. +- **Worker**: `cd packages/ws-worker && pnpm start` connects to Lightning at `localhost:4000`. `-l mock` uses the mock Lightning, `--mock` uses a mock engine, and `--no-loop` stops auto-claiming so you can trigger claims with `curl -X POST http://localhost:2222/claim`. Options and their `WORKER_*` env vars are in `packages/ws-worker/src/util/cli.ts`. +- CLI env vars (`OPENFN_API_KEY`, `OPENFN_ENDPOINT`, `OPENFN_REPO_DIR`, `OPENFN_ADAPTORS_REPO`, and others) are defined in `packages/cli/src/options.ts` and `packages/cli/src/projects/options.ts`. -## Additional Documentation +### Integration tests -**Changesets**: Run `pnpm changeset` when submitting PRs. Releases publish automatically to npm on merge to main. +These live in `integration-tests/` (`cli`, `execute`, `worker`, `legacy-deploy`) and run against built packages. Always `pnpm build` first. -Changeset release notes must be a **single, short, high-level sentence** - vague is fine (e.g. `added new "compile-test" command to the CLI` or `Tighten guards against shell injection vectors`). Do not list files, functions, or implementation detail. For breaking changes only, you may add a short migration guide after the sentence. See the package `CHANGELOG.md` files for the house style. +- `pnpm test:integration` from root runs them all. +- In `integration-tests/cli`, `pnpm test:dev` uses the local `packages/cli/dist`. Plain `pnpm test` expects a globally installed `openfn`, which is how CI runs it: `pnpm pack:local` then install the tarball globally. -The [.claude](.claude) folder contains detailed guides: +## Adding a CLI command -- **[event-processor.md](.claude/event-processor.md)** - Worker event processing deep-dive (ordering, batching) — companion to `packages/ws-worker/CLAUDE.md` -- **[yaml-formats.md](.claude/yaml-formats.md)** - v1 vs v2 project YAML formats: structure, detection logic, and conversion paths -- **[unit-testing-jobs.md](.claude/unit-testing-jobs.md)** - How to compile job for unit-testing +Commands are yargs modules registered in `packages/cli/src/cli.ts`. Each module calls `ensure('', ...)` (`util/command-builders.ts`) to set `argv.command`, and `packages/cli/src/commands.ts` dispatches that string to a handler. A new `project` subcommand needs all three of: -Key packages also carry their own `CLAUDE.md` (runtime, engine-multi, ws-worker), auto-loaded when you work in them. +1. a yargs module added in `packages/cli/src/projects/command.ts`; +2. the handler exported from `packages/cli/src/projects/index.ts`; +3. an entry in the `handlers` map and the `CommandList` union in `commands.ts`. -## Code Standards +`packages/cli/src/projects/list.ts` is the simplest example to copy. -- **Formatting**: Use Prettier (`pnpm format`) -- **TypeScript**: Required for all new code -- **TypeSync**: Run `pnpm _typesync` after modifying dependencies -- **Tests**: Each package's tests run against its own `src/` via `@swc-node/register` (no build of the package under test needed). BUT workspace `@openfn/*` deps resolve to their built `dist/`, and `engine-multi` runs its worker processes from `dist/` — so run `pnpm build` first when tests cross packages or use the engine. When unsure, build. -- **Independence**: Keep packages loosely coupled where possible +## Changesets and releases -## Architecture Principles +Every PR that changes a published package needs a changeset (`pnpm changeset`). The release note is a **single, short, high-level sentence**, and vague is fine (e.g. `added new "compile-test" command to the CLI`). Leave out files, functions and implementation detail. Breaking changes may add a short migration guide after the sentence. The package `CHANGELOG.md` files show the house style. -- **Separation of Concerns**: CLI and Worker are frontends; Runtime is the shared execution backend -- **Sandboxing**: Runtime uses Node's VM module for isolation -- **State Immutability**: State cannot be mutated between jobs -- **Portability**: Compiled jobs are standard ES modules -- **Zero Persistence (Worker)**: Worker is stateless; Lightning handles persistence -- **Multi-Process Isolation**: Worker uses engine-multi for concurrent workflow execution +Releases are prepared by hand on a release branch: run `pnpm changeset version`, check the changelogs, run `pnpm install`, and commit. Merging to main then publishes to npm and builds the worker Docker image. A brand-new package must be published once first with `pnpm publish:new`; see `README.md`. -## Contributing +## Further guides -1. Make changes -2. Run `pnpm test` -3. Add changeset: `pnpm changeset` -4. Open PR at https://github.com/openfn/kit +Read these before working in the matching area: -**Resources**: [docs.openfn.org](https://docs.openfn.org) | [app.openfn.org](https://app.openfn.org) | [github.com/openfn/kit](https://github.com/openfn/kit) +- [.claude/event-processor.md](.claude/event-processor.md): how the worker orders and batches events sent to Lightning. +- [.claude/yaml-formats.md](.claude/yaml-formats.md): v1 vs v2 project YAML, how each is detected, and how they convert. +- [.claude/unit-testing-jobs.md](.claude/unit-testing-jobs.md): compiling a job so it can be unit tested. +- `packages/runtime`, `packages/engine-multi` and `packages/ws-worker` each have their own `CLAUDE.md`, loaded automatically when you work there. diff --git a/Dockerfile b/Dockerfile index 4b6db835a..27bca2850 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,9 +1,9 @@ FROM node:24-alpine AS base ENV PNPM_HOME="/pnpm" ENV PATH="$PNPM_HOME:$PATH" -RUN corepack enable COPY . /app WORKDIR /app +RUN npm install -g pnpm # TODO: use prod optimized build? ---------------------------------------------- # FROM base AS build diff --git a/README.md b/README.md index 42e1e85ba..f83586595 100644 --- a/README.md +++ b/README.md @@ -39,9 +39,9 @@ We use [`pnpm`](https://pnpm.io/installation), a fast, disk space efficient pack ## Installing -This repo uses node corepack to ensure pnpm v8 is used +Install pnpm globally. When run inside this repo, pnpm reads the `packageManager` field in `package.json` and switches itself to the pinned version. -- `$ corepack enable` +- `$ npm install -g pnpm` - `$ pnpm install` - `$ pnpm build` @@ -127,7 +127,7 @@ This repo uses `typesync` to ensure that all packages have an appropriate `@type This must be run MANUALLY (See https://github.com/OpenFn/kit/issues/333) -On every add, update and remove. you should do `pnpm run typesync` from the repo root. +On every add, update and remove. you should do `pnpm _typesync` from the repo root. Note that @types packages only synchronise with the major and minor versions of a package. So for `@types/x@major.minor.patch`, `major` and `minor` refer to the versions of the corresponding package `x`, and `patch` is the version number of the actual types package. diff --git a/package.json b/package.json index f3d638003..3febabd3b 100644 --- a/package.json +++ b/package.json @@ -3,6 +3,18 @@ "version": "1.0.0", "private": true, "description": "Packages to support OpenFn v2", + "devEngines": { + "runtime": { + "name": "node", + "version": "26.x", + "onFail": "warn" + }, + "packageManager": { + "name": "pnpm", + "version": "12.14.0", + "onFail": "download" + } + }, "scripts": { "build": "pnpm run clean && pnpm -r --filter=./packages/* run build", "clean:local": "rimraf dist/**/*", @@ -40,6 +52,5 @@ "semver": "^7.7.4", "tar-stream": "^3.1.8", "yargs": "^17.7.2" - }, - "packageManager": "pnpm@12.6.0+sha512.3ef68f951cb111ac204b4a5a16f0b2ddf0da56a96e0413e81d855d9f0b55ef926714709028e1cd00c405c2c5fb7b9e8ec4dc46777c805d0373c2f2ff00fd20ec" + } } diff --git a/packages/ws-worker/README.md b/packages/ws-worker/README.md index b11b611eb..0bd17d0a3 100644 --- a/packages/ws-worker/README.md +++ b/packages/ws-worker/README.md @@ -109,7 +109,7 @@ You can start a dev server (which rebuilds on save) by running: pnpm start:watch ``` -This will wrap a real runtime engine into the server. It will rebuild when the Worker Engine code changes (although you'll have to `pnpm build:watch` in `runtime-manager`). This will use the repo at `WORKER_REPO_DIR` (or a default path in /tmp) +This will wrap a real runtime engine into the server. It will rebuild when the Worker Engine code changes (although you'll have to `pnpm build:watch` in `engine-multi`). This will use the repo at `WORKER_REPO_DIR` (or a default path in /tmp) ### Disabling auto-fetch diff --git a/packages/ws-worker/package.json b/packages/ws-worker/package.json index 1d31e658a..9a07513dc 100644 --- a/packages/ws-worker/package.json +++ b/packages/ws-worker/package.json @@ -14,7 +14,7 @@ "build:watch": "pnpm build --watch", "start": "node --loader @swc-node/register/esm src/start.ts", "start:prod": "node dist/start.js", - "start:watch": "nodemon -e ts,js --watch ../runtime-manager/dist --watch ./src --exec 'pnpm start'", + "start:watch": "nodemon -e ts,js --watch ../engine-multi/dist --watch ./src --exec 'pnpm start'", "pack": "pnpm pack --pack-destination ../../dist" }, "bin": { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 4a741c902..e9436f991 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -7,153 +7,153 @@ importers: configDependencies: {} packageManagerDependencies: pnpm: - specifier: 12.6.0 - version: 12.6.0 + specifier: 12.14.0 + version: 12.14.0 packages: - '@pnpm/exe.android-arm64@12.6.0': - resolution: {integrity: sha512-kviIHft9h02q+7N2In7tSL9T/HRUSGwYmU74YPtsWU5ee7vgqPyC0JT6RRX6miW+NxX1CvHgQxg69qq1qTLJYQ==} + '@pnpm/exe.android-arm64@12.14.0': + resolution: {integrity: sha512-+iSh7x21C3A2hqc+Z0ZmbKTcn6YNlzrXM142PsnQH/dLj0DYxFzoBvc6XAnL/yfQ5nnH2ebBiRj/zVxr61fZbQ==} cpu: [arm64] os: [android] - '@pnpm/exe.android-x64@12.6.0': - resolution: {integrity: sha512-CT8aJKLq2mtZFE71pr4E5Z2xHL8uGnRGr+NclDqsXlVF4SVcQ2QAs14mWi0C8gjT4hbmi+Q0lJRRIkMAWfjjng==} + '@pnpm/exe.android-x64@12.14.0': + resolution: {integrity: sha512-qT+0LqEr2wBVaxcG2T8cX/R8SSRz2Rvpp8nRR4fh8tnGUZRch87gFmsHUAoSQh7w6j1h0qTjrA384j4xi8frvw==} cpu: [x64] os: [android] - '@pnpm/exe.darwin-arm64@12.6.0': - resolution: {integrity: sha512-rafpVkjzugKBMxSvGQd5wK1x5eOTkD/+lcJIFHeQhvd+BJ8kDisOOvwhQDrpGd4vd2Fx+hhW0P2Ptt638OlhFg==} + '@pnpm/exe.darwin-arm64@12.14.0': + resolution: {integrity: sha512-tnrdUB8ecJoehuKKqi1YHCBVl61xtJ9XVGcx5EviC6fWO4DeGI8GtXrjvJxDBM3nuVjJeWistgsUp/N142x4sw==} cpu: [arm64] os: [darwin] - '@pnpm/exe.darwin-x64@12.6.0': - resolution: {integrity: sha512-72Jpuv1m24gI8zUNcaylYpBWEhBzz1VPhnDIU2GYM2eRP+KsOqVLwV78i+JrihI39zY2NNXmaN4eAKX1inpaDQ==} + '@pnpm/exe.darwin-x64@12.14.0': + resolution: {integrity: sha512-vlBfGkruqQRsEHTW43cPwpYd7QlbIJ//cvpAdb3bVXkI8SgTPoXhCnc05m+ZNiPrrEkBsX/t7KHw9aXpkzPm3Q==} cpu: [x64] os: [darwin] - '@pnpm/exe.freebsd-x64@12.6.0': - resolution: {integrity: sha512-LON4QgNy1w/XF4uySZIyC/5hEB0oGdelXsY9tSKqstER+2j2X2oHz67skD11RRd/HWFRtMr64shQZ4I9ZoZ0zg==} + '@pnpm/exe.freebsd-x64@12.14.0': + resolution: {integrity: sha512-Qg5rxBrGYl6Tfso+EyygPf84fY1Fzy55E/0or+iuYKtnf0vc0MlHJfVIlT7pBukMRntQHRik7hUi0Z4s7AlJsw==} cpu: [x64] os: [freebsd] - '@pnpm/exe.linux-arm64-musl@12.6.0': - resolution: {integrity: sha512-BdDpX+DeaMUc5x6WNcE6FkmFy36NwrBbBvwsZU737Zt3u1fTY+iKFPchjEQNCM4rT6q6xvF2oN3ZwExGsJCkxQ==} + '@pnpm/exe.linux-arm64-musl@12.14.0': + resolution: {integrity: sha512-DRIe4yQkXBGA/PhVJdzlbnllxBdAtnMMvTVLLcGpsK5FvJz9kxD2Hyxtn68ovmNkVX06f6p45cQwfm3wx2jn1A==} cpu: [arm64] os: [linux] libc: [musl] - '@pnpm/exe.linux-arm64@12.6.0': - resolution: {integrity: sha512-8h2sNoIhHDpHDYqZZCh9PXr6krqW10btb0GHVGuw710muDHlFAHMtUG2ogmaHge6zJG1xgY4Y7mwX5g/LWvrYg==} + '@pnpm/exe.linux-arm64@12.14.0': + resolution: {integrity: sha512-7joGShZ44Nk3WpNU+60JoOPjCXlgxhJAq11S2UiVtwCUDgTer1yTPPfxGW8pxaD6046actYLIYDbZNlubHWs0A==} cpu: [arm64] os: [linux] libc: [glibc] - '@pnpm/exe.linux-ppc64@12.6.0': - resolution: {integrity: sha512-ld6xgcEhFCFrsVsJhbmdmR714PnsEspO/Ij8w0/D7OSiz2hYGu3fZd5tKRxOI5m6H6Gl0/RRFAPncTHbsgXVjQ==} + '@pnpm/exe.linux-ppc64@12.14.0': + resolution: {integrity: sha512-gSoryn7ySdXd//gjgf3MvvA8ZerJayaSbuMZMtAWq4vb2/wlVEgpl0Kvqt54y58TRj533Qjq2txKgnxd4JyoAQ==} cpu: [ppc64] os: [linux] libc: [glibc] - '@pnpm/exe.linux-riscv64@12.6.0': - resolution: {integrity: sha512-HIbImydoC3J8NFt+8MXfhTCf5rO6NjCMyinSAHac0VmV8uCHw+kbQkyAzxV84rzz9ZOzmBOnj0b1N461UIYGsw==} + '@pnpm/exe.linux-riscv64@12.14.0': + resolution: {integrity: sha512-EMjew1H9WqQ7pL+tYqCPwiuB+0PeCiJRV7fyWeuFw0wwYUajFBjcaPO3IGAVu9sdmJDU+e+HYv/Zey6aKae0Vw==} cpu: [riscv64] os: [linux] libc: [glibc] - '@pnpm/exe.linux-s390x@12.6.0': - resolution: {integrity: sha512-DjSqT7+BZ/lWcDHwNMuzsRVfyxUimh+D54Xw4tSWbdVVQhtWtNMUyI93LVnwCmsoEpar2gC3SFeAgywx37svKQ==} + '@pnpm/exe.linux-s390x@12.14.0': + resolution: {integrity: sha512-shYOj/SFoXD35fHe0pWr2JofwSXulC0BnEIXLj2QokDi0EF//AfKsui35yKIkTEl+s2VJybc3PO4iJNhKIj5Qw==} cpu: [s390x] os: [linux] libc: [glibc] - '@pnpm/exe.linux-x64-musl@12.6.0': - resolution: {integrity: sha512-31lKeGPmRE6xfV6I3VjaEGVFRei14pl/zgoFDK4w+UkbJqOuNl2Ht3O1GuqNIg3Gl14qTEb4kZRAYFHXifDx9A==} + '@pnpm/exe.linux-x64-musl@12.14.0': + resolution: {integrity: sha512-btZiZ2Ot0llKK1ndSfA5i3IRX7/S0VrmzseNH/BJ4c+Cady+S81H6vvU1zByggHMyqQhC8OgxO5PiIY7D9bH0Q==} cpu: [x64] os: [linux] libc: [musl] - '@pnpm/exe.linux-x64@12.6.0': - resolution: {integrity: sha512-qFWBneHJAJ73W4whtbaFOL1M/7DBC6ILHXuxc7ZPtEhfPuT1zeZiGrmKHoMAfJA+mcm6xhOFljqVTUS+00Jabw==} + '@pnpm/exe.linux-x64@12.14.0': + resolution: {integrity: sha512-F6K8e/jWxiuEYJaQtRRUG9ynBSTEHa+t7Lf86MKuOO5UA7WVVMbi+oB8nY6iKW++ncWS2yG6T9faXZGxqNsfoQ==} cpu: [x64] os: [linux] libc: [glibc] - '@pnpm/exe.win32-arm64@12.6.0': - resolution: {integrity: sha512-OhfefXEEykZlslSUhR8PPRe6MVPV3Oink/dVfIecE5velpc7j80cZYsHlaDrtRDcm3TPwQHkaRW1SJ1efX9oFg==} + '@pnpm/exe.win32-arm64@12.14.0': + resolution: {integrity: sha512-DOjlkVB6TtTKeAAe0hNZXn5S7YqESmo1Z6SGbR4BZNQ4isRg31XVHjX2RFTbY8gnZq68IwzyLmPqlEjMmYxofg==} cpu: [arm64] os: [win32] - '@pnpm/exe.win32-x64@12.6.0': - resolution: {integrity: sha512-L2tuyrD2+Imgxs3VK/ST/2L3xD6vDP0ktJQxM0TaGw7TbAQEMq+RMc8iK6Ew7Id579uzjJe8jSfJID2ZGsOHCA==} + '@pnpm/exe.win32-x64@12.14.0': + resolution: {integrity: sha512-/LSX6mew/sLf08XqcjemuklNKf1K/Ftpgj4//hK/HKzI2dKbmxDB27a/2OaQ5a0O3/3OFzlssXDziZsi+yVBwQ==} cpu: [x64] os: [win32] - pnpm@12.6.0: - resolution: {integrity: sha512-PvaPlRyxEawgS0paFvCy3fDaVqluBBPoHYVdnwtV75JnFHCQKOHNAMQFwsX7e56OxNxGd3yAXQNzwvL/AP0g7A==} + pnpm@12.14.0: + resolution: {integrity: sha512-wYum2HmT09Fky16JSPMrLAbuhUSH4GzY2GeBNC+z5btGNDZwNHEehoArqpw3vqkGzhkprQjXCITJfYAd8TOJpg==} engines: {node: '>=18.*'} hasBin: true snapshots: - '@pnpm/exe.android-arm64@12.6.0': + '@pnpm/exe.android-arm64@12.14.0': optional: true - '@pnpm/exe.android-x64@12.6.0': + '@pnpm/exe.android-x64@12.14.0': optional: true - '@pnpm/exe.darwin-arm64@12.6.0': + '@pnpm/exe.darwin-arm64@12.14.0': optional: true - '@pnpm/exe.darwin-x64@12.6.0': + '@pnpm/exe.darwin-x64@12.14.0': optional: true - '@pnpm/exe.freebsd-x64@12.6.0': + '@pnpm/exe.freebsd-x64@12.14.0': optional: true - '@pnpm/exe.linux-arm64-musl@12.6.0': + '@pnpm/exe.linux-arm64-musl@12.14.0': optional: true - '@pnpm/exe.linux-arm64@12.6.0': + '@pnpm/exe.linux-arm64@12.14.0': optional: true - '@pnpm/exe.linux-ppc64@12.6.0': + '@pnpm/exe.linux-ppc64@12.14.0': optional: true - '@pnpm/exe.linux-riscv64@12.6.0': + '@pnpm/exe.linux-riscv64@12.14.0': optional: true - '@pnpm/exe.linux-s390x@12.6.0': + '@pnpm/exe.linux-s390x@12.14.0': optional: true - '@pnpm/exe.linux-x64-musl@12.6.0': + '@pnpm/exe.linux-x64-musl@12.14.0': optional: true - '@pnpm/exe.linux-x64@12.6.0': + '@pnpm/exe.linux-x64@12.14.0': optional: true - '@pnpm/exe.win32-arm64@12.6.0': + '@pnpm/exe.win32-arm64@12.14.0': optional: true - '@pnpm/exe.win32-x64@12.6.0': + '@pnpm/exe.win32-x64@12.14.0': optional: true - pnpm@12.6.0: + pnpm@12.14.0: optionalDependencies: - '@pnpm/exe.android-arm64': 12.6.0 - '@pnpm/exe.android-x64': 12.6.0 - '@pnpm/exe.darwin-arm64': 12.6.0 - '@pnpm/exe.darwin-x64': 12.6.0 - '@pnpm/exe.freebsd-x64': 12.6.0 - '@pnpm/exe.linux-arm64': 12.6.0 - '@pnpm/exe.linux-arm64-musl': 12.6.0 - '@pnpm/exe.linux-ppc64': 12.6.0 - '@pnpm/exe.linux-riscv64': 12.6.0 - '@pnpm/exe.linux-s390x': 12.6.0 - '@pnpm/exe.linux-x64': 12.6.0 - '@pnpm/exe.linux-x64-musl': 12.6.0 - '@pnpm/exe.win32-arm64': 12.6.0 - '@pnpm/exe.win32-x64': 12.6.0 + '@pnpm/exe.android-arm64': 12.14.0 + '@pnpm/exe.android-x64': 12.14.0 + '@pnpm/exe.darwin-arm64': 12.14.0 + '@pnpm/exe.darwin-x64': 12.14.0 + '@pnpm/exe.freebsd-x64': 12.14.0 + '@pnpm/exe.linux-arm64': 12.14.0 + '@pnpm/exe.linux-arm64-musl': 12.14.0 + '@pnpm/exe.linux-ppc64': 12.14.0 + '@pnpm/exe.linux-riscv64': 12.14.0 + '@pnpm/exe.linux-s390x': 12.14.0 + '@pnpm/exe.linux-x64': 12.14.0 + '@pnpm/exe.linux-x64-musl': 12.14.0 + '@pnpm/exe.win32-arm64': 12.14.0 + '@pnpm/exe.win32-x64': 12.14.0 --- lockfileVersion: '9.0'