diff --git a/.github/workflows/__shared-ci.yml b/.github/workflows/__shared-ci.yml
index a164873..873a59a 100644
--- a/.github/workflows/__shared-ci.yml
+++ b/.github/workflows/__shared-ci.yml
@@ -6,6 +6,21 @@ on:
permissions: {}
jobs:
+ test-release:
+ name: Test release preparation and recovery
+ runs-on: ubuntu-latest
+ permissions:
+ contents: read
+ steps:
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
+ with:
+ persist-credentials: false
+ - uses: $/actions/setup-node
+ with:
+ working-directory: tests/release
+ - run: npm test
+ working-directory: tests/release
+
linter:
uses: hoverkraft-tech/ci-github-common/.github/workflows/linter.yml@44f6108cef0e9884ea7735f3d62932c2310745d4 # 0.39.1
permissions:
@@ -65,6 +80,7 @@ jobs:
needs: linter
uses: $/.github/workflows/__test-workflow-continuous-integration.yml
permissions:
+ actions: read
attestations: write
contents: read
packages: write
diff --git a/.github/workflows/__test-workflow-continuous-integration.yml b/.github/workflows/__test-workflow-continuous-integration.yml
index eff95a0..60d909a 100644
--- a/.github/workflows/__test-workflow-continuous-integration.yml
+++ b/.github/workflows/__test-workflow-continuous-integration.yml
@@ -10,6 +10,7 @@ jobs:
name: Act - Run the continuous integration workflow (without container)
uses: $/.github/workflows/continuous-integration.yml
permissions:
+ actions: read
contents: read
id-token: write
packages: read
@@ -17,6 +18,7 @@ jobs:
security-events: write
with:
working-directory: tests/npm
+ packages: '[{"name":"test-for-ci-with-npm","version":"0.1.0","directory":".","slug":"test-for-ci-with-npm"}]'
code-ql: |
{
"languages": "javascript-typescript",
@@ -31,6 +33,9 @@ jobs:
name: Assert - Ensure build artifact has been uploaded (without container)
runs-on: ubuntu-latest
needs: act-without-container
+ permissions:
+ actions: read
+ contents: read
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
@@ -43,11 +48,26 @@ jobs:
- name: Check the build artifacts
run: test -f tests/npm/dist/test.txt
+ - name: Download the packaged CI output
+ uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
+ with:
+ artifact-ids: ${{ fromJSON(needs.act-without-container.outputs.package-artifacts)[0].artifact-id }}
+ path: ${{ runner.temp }}/ci-package
+ skip-decompress: true
+
+ - name: Verify the tarball contains the tested build output
+ env:
+ ARTIFACT_NAME: ${{ fromJSON(needs.act-without-container.outputs.package-artifacts)[0].artifact-name }}
+ run: |
+ tar -xOf "$RUNNER_TEMP/ci-package/$ARTIFACT_NAME" package/dist/test.txt > "$RUNNER_TEMP/packaged-build.txt"
+ cmp tests/npm/dist/test.txt "$RUNNER_TEMP/packaged-build.txt"
+
act-without-container-and-github-reports:
# jscpd:ignore-start
name: Act - Run the continuous integration workflow (without container and GitHub reports)
uses: $/.github/workflows/continuous-integration.yml
permissions:
+ actions: read
contents: read
id-token: write
packages: read
@@ -94,6 +114,7 @@ jobs:
uses: $/.github/workflows/continuous-integration.yml
needs: arrange-with-container
permissions:
+ actions: read
contents: read
id-token: write
packages: read
@@ -130,6 +151,7 @@ jobs:
uses: $/.github/workflows/continuous-integration.yml
needs: arrange-with-container
permissions:
+ actions: read
contents: read
id-token: write
packages: read
diff --git a/.github/workflows/continuous-integration.md b/.github/workflows/continuous-integration.md
index 89a49e8..71cd33d 100644
--- a/.github/workflows/continuous-integration.md
+++ b/.github/workflows/continuous-integration.md
@@ -3,7 +3,7 @@
# GitHub Reusable Workflow: Node.js Continuous Integration
-

+
---
@@ -16,7 +16,6 @@
[](http://choosealicense.com/licenses/mit/)
[](https://img.shields.io/github/stars/hoverkraft-tech/ci-github-nodejs?style=social)
[](https://github.com/hoverkraft-tech/ci-github-nodejs/blob/main/CONTRIBUTING.md)
-
@@ -34,9 +33,11 @@ Workflow to performs continuous integration steps against a Node.js project:
- Linting
- Build
- Test
+- Optional npm packaging for publication from the same commit
### Permissions
+- **`actions`**: `read`
- **`contents`**: `read`
- **`id-token`**: `write`
- **`packages`**: `read`
@@ -253,6 +254,10 @@ jobs:
| | | | | |
| | Example: | | | |
| | {
"commands": [
"build",
"generate-artifacts"
],
"env": {
"CUSTOM_ENV_VAR": "value"
},
"artifact": [
"dist/",
"packages/package-a/build/"
]
} | | | |
+| **`packages`** | Optional JSON package list from prepare-release, with name, version, directory and slug. | **false** | **string** | - |
+| | Packages the build output after checks pass and returns immutable tarball artifact IDs. | | | |
+| | Requires checks, a build artifact, GitHub-hosted Ubuntu runners and no container. | | | |
+| | Leave empty for ordinary CI without release packaging. | | | |
| **`checks`** | Optional flag to enable check steps. | **false** | **boolean** | `true` |
| **`lint`** | Whether to enable linting. | **false** | **string** | `true` |
| | Set to `null` or empty to disable. | | | |
@@ -395,9 +400,10 @@ When specified, steps will execute inside this container instead of checking out
## Outputs
-| **Output** | **Description** |
-| ----------------------- | --------------------------------------------------------- |
-| **`build-artifact-id`** | ID of the build artifact) uploaded during the build step. |
+| **Output** | **Description** |
+| ----------------------- | ------------------------------------------------------------------------------------------------------- |
+| **`package-artifacts`** | JSON package artifact list for the release workflow in this same run. Empty when packaging is disabled. |
+| **`build-artifact-id`** | ID of the build artifact) uploaded during the build step. |
diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml
index a46535d..1b07286 100644
--- a/.github/workflows/continuous-integration.yml
+++ b/.github/workflows/continuous-integration.yml
@@ -4,6 +4,7 @@
# - Linting
# - Build
# - Test
+# - Optional npm packaging for publication from the same commit
name: Node.js Continuous Integration
@@ -46,6 +47,14 @@ on:
type: string
required: false
default: "build"
+ packages:
+ description: |
+ Optional JSON package list from prepare-release, with name, version, directory and slug.
+ Packages the build output after checks pass and returns immutable tarball artifact IDs.
+ Requires checks, a build artifact, GitHub-hosted Ubuntu runners and no container.
+ Leave empty for ordinary CI without release packaging.
+ type: string
+ default: ""
checks:
description: "Optional flag to enable check steps."
type: boolean
@@ -188,6 +197,9 @@ on:
Defaults to `GITHUB_TOKEN` if not provided.
required: false
outputs:
+ package-artifacts:
+ description: JSON package artifact list for the release workflow in this same run. Empty when packaging is disabled.
+ value: ${{ jobs.package-artifacts.outputs.packages }}
build-artifact-id:
description: "ID of the build artifact) uploaded during the build step."
value: ${{ jobs.build.outputs.artifact-id }}
@@ -208,6 +220,18 @@ jobs:
container-username: ${{ steps.parse.outputs.container-username }}
path-mapping: ${{ steps.parse.outputs.path-mapping }}
steps:
+ - name: Validate packaging configuration
+ if: inputs.packages != ''
+ uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
+ env:
+ CHECKS: ${{ inputs.checks }}
+ CONTAINER: ${{ inputs.container }}
+ RUNS_ON: ${{ inputs.runs-on }}
+ with:
+ script: |
+ if (process.env.CHECKS !== 'true' || process.env.CONTAINER || JSON.stringify(JSON.parse(process.env.RUNS_ON)) !== '["ubuntu-latest"]') {
+ core.setFailed('Release packaging requires checks, runs-on: ["ubuntu-latest"] and no container.');
+ }
- id: parse
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
env:
@@ -606,3 +630,46 @@ jobs:
report-file: ${{ steps.prepare-test-options.outputs.report-file }}
path-mapping: ${{ needs.prepare.outputs.path-mapping || '' }}
github-token: ${{ secrets.github-token || github.token }}
+
+ package:
+ name: 📦 Package ${{ matrix.package.name }}
+ needs: [prepare, setup, build, lint, test, code-ql, dependency-review]
+ if: >-
+ ${{ !cancelled() && inputs.packages != '' && needs.build.result == 'success'
+ && !contains(needs.*.result, 'failure') && !contains(needs.*.result, 'cancelled') }}
+ runs-on: ubuntu-latest
+ permissions:
+ contents: read
+ packages: read
+ actions: read
+ strategy:
+ fail-fast: false
+ matrix:
+ package: ${{ fromJSON(inputs.packages) }}
+ steps:
+ - name: Require build output
+ env:
+ BUILD_ARTIFACT_ID: ${{ needs.build.outputs.artifact-id }}
+ run: test -n "$BUILD_ARTIFACT_ID"
+ - uses: $/actions/package
+ with:
+ working-directory: ${{ inputs.working-directory }}
+ package-directory: ${{ matrix.package.directory }}
+ build-artifact-id: ${{ needs.build.outputs.artifact-id }}
+ build-artifact-path: /
+ artifact-name: npm-${{ matrix.package.slug }}-${{ github.run_id }}-${{ github.run_attempt }}
+
+ package-artifacts:
+ name: 📦 Collect package artifact IDs
+ needs: package
+ if: ${{ !cancelled() && needs.package.result == 'success' }}
+ runs-on: ubuntu-latest
+ permissions:
+ actions: read
+ outputs:
+ packages: ${{ steps.artifacts.outputs.packages }}
+ steps:
+ - id: artifacts
+ uses: $/actions/package-artifacts
+ with:
+ packages: ${{ inputs.packages }}
diff --git a/.github/workflows/prepare-release.md b/.github/workflows/prepare-release.md
new file mode 100644
index 0000000..2a5bd43
--- /dev/null
+++ b/.github/workflows/prepare-release.md
@@ -0,0 +1,96 @@
+
+
+# GitHub Reusable Workflow: Prepare Node.js Release
+
+
+

+
+
+---
+
+
+
+
+[](https://github.com/hoverkraft-tech/ci-github-nodejs/releases)
+[](http://choosealicense.com/licenses/mit/)
+[](https://img.shields.io/github/stars/hoverkraft-tech/ci-github-nodejs?style=social)
+[](https://github.com/hoverkraft-tech/ci-github-nodejs/blob/main/CONTRIBUTING.md)
+
+
+
+
+## Overview
+
+Prepare a Node.js release version and changelog without building or publishing.
+Dispatches the calling workflow at the prepared tag; that run can invoke CI and publication.
+See [the release guide](../../docs/usage/releases.md).
+
+### Permissions
+
+- **`actions`**: `write`
+- **`contents`**: `write`
+- **`pull-requests`**: `read`
+
+
+
+
+## Inputs
+
+### Workflow Call Inputs
+
+| **Input** | **Description** | **Required** | **Type** | **Default** |
+| ----------------------- | ---------------------------------------------------------------------------------------------------------- | ------------ | ---------- | ----------- |
+| **`versioning`** | Tool applying the HoverKraft release plan, npm for a single package or lerna for fixed-version workspaces. | **false** | **string** | `npm` |
+| **`working-directory`** | Project directory relative to the caller repository root. | **false** | **string** | `.` |
+| **`environment`** | GitHub environment permitting release preparation on the default branch and release tags. | **false** | **string** | `release` |
+
+
+
+
+## Secrets
+
+| **Secret** | **Description** | **Required** |
+| ------------------ | ----------------------------------------------------------------------------------------------------------------------------------------- | ------------ |
+| **`github-token`** | Optional token for pushing release commits and dispatching the caller at the tag. Its identity must be permitted by branch and tag rules. | **false** |
+
+
+
+
+## Outputs
+
+| **Output** | **Description** |
+| -------------- | -------------------------------------------------------------------------------------------------- |
+| **`status`** | no-changes, dispatched, released or ready. Only ready should start CI and publication in this run. |
+| **`tag`** | Prepared release tag. |
+| **`packages`** | JSON package list for the CI workflow's packages input. Available when status is ready. |
+
+
+
+
+## Contributing
+
+Contributions are welcome! Please see the [contributing guidelines](https://github.com/hoverkraft-tech/ci-github-nodejs/blob/main/CONTRIBUTING.md) for more details.
+
+
+
+
+
+
+## License
+
+This project is licensed under the MIT License.
+
+SPDX-License-Identifier: MIT
+
+Copyright © 2026 hoverkraft-tech
+
+For more details, see the [license](http://choosealicense.com/licenses/mit/).
+
+
+
+
+---
+
+This documentation was automatically generated by [CI Dokumentor](https://github.com/hoverkraft-tech/ci-dokumentor).
+
+
diff --git a/.github/workflows/prepare-release.yml b/.github/workflows/prepare-release.yml
new file mode 100644
index 0000000..d1428ea
--- /dev/null
+++ b/.github/workflows/prepare-release.yml
@@ -0,0 +1,63 @@
+# Prepare a Node.js release version and changelog without building or publishing.
+# Dispatches the calling workflow at the prepared tag; that run can invoke CI and publication.
+# See [the release guide](../../docs/usage/releases.md).
+name: Prepare Node.js Release
+
+on:
+ workflow_call:
+ inputs:
+ versioning:
+ description: Tool applying the HoverKraft release plan, npm for a single package or lerna for fixed-version workspaces.
+ type: string
+ default: npm
+ working-directory:
+ description: Project directory relative to the caller repository root.
+ type: string
+ default: .
+ environment:
+ description: GitHub environment permitting release preparation on the default branch and release tags.
+ type: string
+ default: release
+ secrets:
+ github-token:
+ description: Optional token for pushing release commits and dispatching the caller at the tag. Its identity must be permitted by branch and tag rules.
+ required: false
+ outputs:
+ status:
+ description: no-changes, dispatched, released or ready. Only ready should start CI and publication in this run.
+ value: ${{ jobs.prepare.outputs.status }}
+ tag:
+ description: Prepared release tag.
+ value: ${{ jobs.prepare.outputs.tag }}
+ packages:
+ description: JSON package list for the CI workflow's packages input. Available when status is ready.
+ value: ${{ jobs.prepare.outputs.packages }}
+
+permissions: {}
+
+concurrency:
+ group: node-release-prepare-${{ github.repository }}-${{ inputs.working-directory }}
+ cancel-in-progress: false
+
+jobs:
+ prepare:
+ name: Prepare release
+ runs-on: ubuntu-latest
+ timeout-minutes: 20
+ environment: ${{ inputs.environment }}
+ permissions:
+ actions: write
+ contents: write
+ pull-requests: read
+ outputs:
+ status: ${{ steps.prepare.outputs.status }}
+ tag: ${{ steps.prepare.outputs.tag }}
+ packages: ${{ steps.prepare.outputs.packages }}
+ published: ${{ steps.prepare.outputs.published }}
+ steps:
+ - id: prepare
+ uses: $/actions/release/prepare
+ with:
+ versioning: ${{ inputs.versioning }}
+ working-directory: ${{ inputs.working-directory }}
+ github-token: ${{ secrets.github-token || github.token }}
diff --git a/.github/workflows/release.md b/.github/workflows/release.md
index 267919b..cb7c1f6 100644
--- a/.github/workflows/release.md
+++ b/.github/workflows/release.md
@@ -1,261 +1,98 @@
-# Release a Node.js package
-
-Publish a package to npm and attach the same tarball to a GitHub release:
-
-**Plan version → Run CI → Package build output → Publish to npm → Create GitHub release**
-
-The workflow below releases a single package from the repository root using stable versions such as `1.2.3`.
-It sets the version during packaging. If your build reads the package version or you commit version changes,
-use [Commit the version before building](#commit-the-version-before-building).
-
-## Set up
-
-1. Configure [release labels and version rules](https://github.com/hoverkraft-tech/ci-github-publish/blob/1.0.3/.github/workflows/prepare-release.md).
- These determine the version and release notes.
-2. Check the package's `package.json`: set `name`, `files`, and `repository.url`, and ensure `private` is not `true`.
-3. Configure [npm trusted publishing](../../actions/publish/README.md#npm-trusted-publishing) for your repository and workflow filename, `release.yml`.
- The example uses GitHub-hosted runners and `id-token: write`; no npm token is needed.
- For a new npm package, publish its first version before configuring the trusted publisher.
-4. Save the workflow below as `.github/workflows/release.yml` in your project. Before running it:
- - Replace every `` with the **same `ci-github-nodejs` commit containing `actions/publish`**.
- The `ci-github-publish` actions are already pinned to `1.0.3`.
- - Set the `build`, `lint:ci`, and `test:ci` script names and the `dist/` output path to match your project.
- See [CI options](continuous-integration.md) if you need a different setup.
-
-## Workflow
-
-```yaml
-name: Release
-
-on:
- schedule:
- - cron: "25 8 * * 1"
- workflow_dispatch:
- inputs:
- force:
- description: Release even when no relevant changes are detected
- type: boolean
- required: false
- default: false
-
-permissions: {}
-
-concurrency:
- group: release-${{ github.repository }}
- cancel-in-progress: false
-
-jobs:
- plan:
- if: github.ref_name == github.event.repository.default_branch
- runs-on: ubuntu-latest
- permissions:
- contents: read
- pull-requests: read
- outputs:
- should-release: ${{ steps.plan.outputs.has-changes == 'true' || (github.event_name == 'workflow_dispatch' && inputs.force) }}
- tag: ${{ steps.plan.outputs.tag }}
- version: ${{ steps.version.outputs.version }}
- steps:
- - name: Plan release
- id: plan
- uses: hoverkraft-tech/ci-github-publish/actions/release/plan@ea6682de88070c254dac619a6623a242a6d57cd3 # 1.0.3
-
- - id: version
- uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
- env:
- RELEASE_TAG: ${{ steps.plan.outputs.tag }}
- with:
- script: |
- // This example uses tags such as v1.2.3 or 1.2.3.
- const version = process.env.RELEASE_TAG.replace(/^v/, '');
- if (!/^\d+\.\d+\.\d+$/.test(version)) {
- return core.setFailed('Expected a stable SemVer tag; adapt the mapping for prereleases or monorepos');
- }
- core.setOutput('version', version);
-
- ci:
- needs: plan
- if: needs.plan.outputs.should-release == 'true'
- uses: hoverkraft-tech/ci-github-nodejs/.github/workflows/continuous-integration.yml@
- permissions:
- contents: read
- packages: read
- pull-requests: write
- id-token: write
- security-events: write
- with:
- build: '{"commands":["build"],"artifact":{"paths":["dist/"]}}'
- lint: '{"command":"lint:ci"}'
- test: '{"command":"test:ci"}'
-
- release:
- needs: [plan, ci]
- if: needs.plan.outputs.should-release == 'true'
- runs-on: ubuntu-latest
- permissions:
- actions: read
- contents: write
- pull-requests: read
- id-token: write
- steps:
- - name: Package build output
- id: package
- uses: hoverkraft-tech/ci-github-nodejs/actions/package@
- with:
- version: ${{ needs.plan.outputs.version }}
- build-artifact-id: ${{ needs.ci.outputs.build-artifact-id }}
- # The reusable CI workflow preserves absolute paths in build artifacts.
- build-artifact-path: /
-
- # Add any package smoke tests before publishing.
- - name: Check package publishing
- uses: hoverkraft-tech/ci-github-nodejs/actions/publish@
- with:
- package-tarball-artifact-id: ${{ steps.package.outputs.package-tarball-artifact-id }}
- dry-run: "true"
- provenance: "false"
-
- # Wrap the raw .tgz in a ZIP artifact for release/create.
- - id: release-assets
- uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
- with:
- name: release-assets
- path: ${{ steps.package.outputs.package-tarball-path }}
- if-no-files-found: error
-
- - id: publish-package
- name: Publish package
- uses: hoverkraft-tech/ci-github-nodejs/actions/publish@
- with:
- package-tarball-artifact-id: ${{ steps.package.outputs.package-tarball-artifact-id }}
- tag: latest
-
- - name: Create GitHub release
- uses: hoverkraft-tech/ci-github-publish/actions/release/create@ea6682de88070c254dac619a6623a242a6d57cd3 # 1.0.3
- with:
- tag: ${{ needs.plan.outputs.tag }}
- target-sha: ${{ github.sha }}
- release-artifact-id: ${{ steps.release-assets.outputs.artifact-id }}
- publish: "true"
-```
-
-[Package](../../actions/package/README.md) checks out the source, installs dependencies, restores the CI build output,
-and creates the tarball. [Publish](../../actions/publish/README.md) publishes that tarball.
-The package version is changed locally; it is not committed. GitHub's source archive therefore keeps the version from the source commit.
-If `package.json` already contains the planned version, omit the Package action's `version` input.
-
-## Generate the changelog
-
-`release/create` generates the GitHub release notes with Release Drafter from the merged pull requests since the previous matching release.
-No separate changelog command is needed for the workflow above. `release/plan` calculates the version without creating a release.
-
-Use the [prepare-release workflow](https://github.com/hoverkraft-tech/ci-github-publish/blob/1.0.3/.github/workflows/prepare-release.md)
-to label pull requests from their Conventional Commit titles. Its default rules select a major version for breaking changes,
-a minor version for features, and a patch version for other changes. Check the labels before merging.
-To customize categories, version rules, or the release-note template, add `.github/release-config.yml`.
-For monorepos, use the same `working-directory` and `include-paths` values in `release/plan` and `release/create`;
-an existing repository configuration takes precedence over those generated defaults.
-
-### Add an AI summary
-
-Store the provider credential as the `OPENAI_API_KEY` Actions secret, then add these entries to the **Create GitHub release** step.
-Merge `changelog-summary` into its existing `with` mapping:
-
-```yaml
-env:
- OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
-with:
- changelog-summary: |
- {
- "llmAuth": ${{ toJSON(env.OPENAI_API_KEY) }},
- "llmProvider": "openai"
- }
-```
-
-The action drafts the changelog, generates a release summary and breaking-change section, and prepends them to the full changelog before publishing.
-The summary also uses GitHub evidence, so keep `contents: write` and `pull-requests: read` on the release job.
-Use `toJSON` to encode the credential safely. Omit `changelog-summary` to publish the generated notes without an AI summary.
-See [summarizer inputs](https://github.com/hoverkraft-tech/ci-github-publish/blob/1.0.3/actions/release/summarize-changelog/README.md)
-for `llmModel`, `llmConfig`, and custom summary templates.
-
-To review the notes before publication, set `publish: "false"`, review the draft, then publish it with `release/update`.
-If summary generation fails, the action does not publish the GitHub release. The npm package may already be published;
-follow [Recover a failed release](#recover-a-failed-release) instead of rerunning npm publication.
-
-### Keep a changelog in the repository
-
-Release notes are stored in the GitHub release body; these actions do not write or commit `CHANGELOG.md`.
-If the source archive or npm tarball must contain it, generate and review the changelog on the release branch,
-commit it with the version update, and build from that merged commit as described in [Commit the version before building](#commit-the-version-before-building).
-Keep the planned tag fixed through preparation and publication.
-
-## Run a release
-
-In **Actions → Release → Run workflow**, select the default branch. The workflow also runs every Monday at 08:25 UTC.
-Releases are serialized so two runs cannot publish the same package concurrently.
-
-| Situation | Result |
-| ---------------------------------------------- | ---------------------------------------------------------------------------------- |
-| Relevant changes since the last GitHub release | Plan the next version, run CI, and release. |
-| No relevant changes | Skip CI and publishing successfully. |
-| Manual run with `force` checked | Release the planned version even without changes; CI must still pass. |
-| No previous matching GitHub release | Plan the first GitHub release. Registry authentication must already be configured. |
-
-The dry run checks the tarball with `npm publish --dry-run`. It does not verify registry credentials or trusted publishing access.
-For a first trial without publishing, keep the dry-run step and remove the **Publish package** and **Create GitHub release** steps.
-
-## Commit the version before building
-
-Use this when the build embeds the version or the released source must include updated version files or a changelog:
-
-1. Plan the version with `release/plan`, using the same no-change and `force` rules as the workflow above.
-2. Update the version on a release branch, for example with `npm version 1.2.3 --no-git-tag-version`.
- Commit the package manifest, lockfile, changelog, and any generated version files through a pull request.
-3. After merging, run CI and packaging **from the merged commit**. Omit the Package action's `version` input; the version is already in `package.json`.
-4. Publish the tarball, then create the GitHub release with the planned `tag` and merged commit as `target-sha`.
-
-Keep the planned tag throughout this process; do not calculate another version after merging.
-If you use a second workflow for publication, read the committed version instead of calling `release/plan` again,
-and skip it when that version is already released.
-
-The Package action performs its own checkout of the workflow's source ref.
-Checking out the merged commit in an earlier step does not change that ref: start the packaging workflow at the merged commit.
-See the [release preparation example](https://github.com/hoverkraft-tech/ci-github-publish/blob/1.0.3/.github/workflows/release.md#example-3-validate-source-update-files-create-release-artifacts-and-release)
-for automating the pull request and merge.
-
-## Other setups
-
-- **GitHub Packages or registry tokens:** use the [authentication examples](../../actions/publish/README.md#registry-tokens-and-github-packages).
- The `github-token` input only authenticates artifact downloads; registry credentials use `NODE_AUTH_TOKEN`.
-- **Prereleases:** set `prerelease: "true"` on `release/plan` and `release/create`, and `tag: next` on both Publish steps.
- Update the version conversion to accept your full prerelease version, such as `1.2.3-rc.1`.
- The npm distribution tag (`next`) is separate from the Git release tag (`v1.2.3-rc.1`).
-- **Monorepos:** scope CI and both release actions with `working-directory`.
- For Package, set `working-directory` to the dependency installation root and `package-directory` to the package's relative path.
- Convert prefixed Git tags such as `my-package/v1.2.3` to npm versions, and use a separate concurrency group and artifact name per package.
-- **Drafts and signing:** create a draft with `publish: "false"`, then use `release/update` to attach assets and publish after npm publication succeeds.
- See the [draft release example](https://github.com/hoverkraft-tech/ci-github-publish/blob/1.0.3/.github/workflows/release.md#example-2-validate-source-create-release-artifacts-and-release).
- Use `release/delete` with `draft-only: "true"` to clean up a temporary draft on failure **only if the npm package has not been published**.
+
-## Recover a failed release
+# GitHub Reusable Workflow: Node.js Release
-Check the registry before retrying: an npm package version cannot be overwritten, and a failed run may still have published it.
+
+

+
-| Where it failed | What to do |
-| ------------------------------------------------- | ------------------------------------------------------------------------ |
-| Before npm publication | Fix the failure and rerun the workflow. |
-| npm published, but GitHub release creation failed | Run only release creation with the original tag, source SHA, and assets. |
-| npm published, but a draft was not finalized | Keep the draft and retry `release/update`. |
-
-After npm publication, do not rerun the whole release job or plan a new version to finish the same release.
-Deleting a draft does not undo npm publication.
-
-## Migrate from the reusable release workflow
-
-Replace calls to `ci-github-nodejs/.github/workflows/release.yml` with a job that uses [the Publish action](../../actions/publish/README.md#usage):
+---
-- Move `runs-on` and permissions to the caller job.
-- Move the publishing inputs to the action step, quoting `provenance` and `dry-run` as `"true"` or `"false"`.
-- Move the optional `github-token` secret to the action's `github-token` input.
+
+
-Use the workflow above when you also need version planning, CI, and a GitHub release.
+[](https://github.com/hoverkraft-tech/ci-github-nodejs/releases)
+[](http://choosealicense.com/licenses/mit/)
+[](https://img.shields.io/github/stars/hoverkraft-tech/ci-github-nodejs?style=social)
+[](https://github.com/hoverkraft-tech/ci-github-nodejs/blob/main/CONTRIBUTING.md)
+
+
+
+
+## Overview
+
+Publish CI-produced npm tarballs and finalize a GitHub release without rebuilding.
+Call after successful CI on the prepared tag, passing its package-artifacts output.
+See [the release guide](../../docs/usage/releases.md) for preparation, CI and recovery.
+
+### Permissions
+
+- **`actions`**: `read`
+- **`contents`**: `write`
+- **`id-token`**: `write`
+- **`pull-requests`**: `read`
+
+
+
+
+## Inputs
+
+### Workflow Call Inputs
+
+| **Input** | **Description** | **Required** | **Type** | **Default** |
+| ----------------------- | ----------------------------------------------------------------------------------------------------------------------------- | ------------ | ----------- | ----------- |
+| **`package-artifacts`** | JSON package artifact list from successful CI in this same workflow run and at this release tag's commit. | **true** | **string** | - |
+| **`working-directory`** | Project directory relative to the caller repository root, matching release preparation and CI. | **false** | **string** | `.` |
+| **`ai-summary`** | Generate an OpenAI summary before npm publication. Requires OPENAI_API_KEY; failures stop publication. | **false** | **boolean** | `false` |
+| **`environment`** | GitHub environment for AI and npm publishing. Configure npm trusted publishing for this environment and the calling workflow. | **false** | **string** | `release` |
+
+
+
+
+## Secrets
+
+| **Secret** | **Description** | **Required** |
+| -------------------- | ---------------------------------------------------- | ------------ |
+| **`OPENAI_API_KEY`** | OpenAI API key, required when ai-summary is enabled. | **false** |
+
+
+
+
+## Outputs
+
+| **Output** | **Description** |
+| ----------------- | ------------------------------------------------------------------- |
+| **`status`** | published after all npm packages and GitHub release assets succeed. |
+| **`tag`** | Published release tag. |
+| **`release-url`** | Published GitHub release URL. |
+
+
+
+
+## Contributing
+
+Contributions are welcome! Please see the [contributing guidelines](https://github.com/hoverkraft-tech/ci-github-nodejs/blob/main/CONTRIBUTING.md) for more details.
+
+
+
+
+
+
+## License
+
+This project is licensed under the MIT License.
+
+SPDX-License-Identifier: MIT
+
+Copyright © 2026 hoverkraft-tech
+
+For more details, see the [license](http://choosealicense.com/licenses/mit/).
+
+
+
+
+---
+
+This documentation was automatically generated by [CI Dokumentor](https://github.com/hoverkraft-tech/ci-dokumentor).
+
+
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
new file mode 100644
index 0000000..f56a257
--- /dev/null
+++ b/.github/workflows/release.yml
@@ -0,0 +1,175 @@
+# Publish CI-produced npm tarballs and finalize a GitHub release without rebuilding.
+# Call after successful CI on the prepared tag, passing its package-artifacts output.
+# See [the release guide](../../docs/usage/releases.md) for preparation, CI and recovery.
+name: Node.js Release
+
+on:
+ workflow_call:
+ inputs:
+ package-artifacts:
+ description: JSON package artifact list from successful CI in this same workflow run and at this release tag's commit.
+ type: string
+ required: true
+ working-directory:
+ description: Project directory relative to the caller repository root, matching release preparation and CI.
+ type: string
+ default: .
+ ai-summary:
+ description: Generate an OpenAI summary before npm publication. Requires OPENAI_API_KEY; failures stop publication.
+ type: boolean
+ default: false
+ environment:
+ description: GitHub environment for AI and npm publishing. Configure npm trusted publishing for this environment and the calling workflow.
+ type: string
+ default: release
+ secrets:
+ OPENAI_API_KEY:
+ description: OpenAI API key, required when ai-summary is enabled.
+ required: false
+ outputs:
+ status:
+ description: published after all npm packages and GitHub release assets succeed.
+ value: ${{ jobs.publish.outputs.status }}
+ tag:
+ description: Published release tag.
+ value: ${{ jobs.verify.outputs.tag }}
+ release-url:
+ description: Published GitHub release URL.
+ value: ${{ jobs.publish.outputs.url }}
+
+permissions: {}
+
+concurrency:
+ group: node-release-publish-${{ github.repository }}-${{ inputs.working-directory }}
+ cancel-in-progress: false
+
+jobs:
+ verify:
+ name: Verify CI artifacts
+ runs-on: ubuntu-latest
+ timeout-minutes: 10
+ environment: ${{ inputs.environment }}
+ permissions:
+ actions: read
+ contents: read
+ outputs:
+ tag: ${{ steps.verify.outputs.tag }}
+ packages: ${{ steps.verify.outputs.packages }}
+ published: ${{ steps.verify.outputs.published }}
+ steps:
+ - name: Validate AI configuration
+ if: inputs.ai-summary
+ env:
+ OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
+ run: |
+ if [ -z "$OPENAI_API_KEY" ]; then
+ echo "OPENAI_API_KEY is required when ai-summary is enabled." >&2
+ exit 1
+ fi
+ - id: verify
+ uses: $/actions/release/verify
+ with:
+ package-artifacts: ${{ inputs.package-artifacts }}
+ working-directory: ${{ inputs.working-directory }}
+
+ draft:
+ name: Draft release notes
+ needs: verify
+ runs-on: ubuntu-latest
+ timeout-minutes: 20
+ environment: ${{ inputs.environment }}
+ permissions:
+ contents: write
+ pull-requests: read
+ steps:
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
+ with:
+ persist-credentials: false
+ - name: Create draft and optional AI summary
+ if: needs.verify.outputs.published != 'true'
+ uses: hoverkraft-tech/ci-github-publish/actions/release/create@ea6682de88070c254dac619a6623a242a6d57cd3 # 1.0.3
+ env:
+ OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
+ with:
+ tag: ${{ needs.verify.outputs.tag }}
+ target-sha: ${{ github.sha }}
+ working-directory: ${{ inputs.working-directory != '.' && inputs.working-directory || '' }}
+ publish: "false"
+ changelog-summary: ${{ inputs.ai-summary && format('{{"llmAuth":{0},"llmProvider":"openai"}}', toJSON(env.OPENAI_API_KEY)) || '' }}
+
+ packages:
+ name: Publish ${{ matrix.package.name }}
+ needs: [verify, draft]
+ runs-on: ubuntu-latest
+ timeout-minutes: 30
+ environment: ${{ inputs.environment }}
+ permissions:
+ actions: read
+ contents: read
+ id-token: write
+ strategy:
+ fail-fast: false
+ matrix:
+ package: ${{ fromJSON(needs.verify.outputs.packages) }}
+ steps:
+ - name: Download the CI package tarball
+ uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
+ with:
+ artifact-ids: ${{ matrix.package.artifact-id }}
+ path: ${{ runner.temp }}/ci-package
+ skip-decompress: true
+ - id: registry
+ uses: $/actions/release/restore-package
+ with:
+ name: ${{ matrix.package.name }}
+ version: ${{ matrix.package.version }}
+ tarball-path: ${{ runner.temp }}/ci-package/${{ matrix.package.artifact-name }}
+ - name: Validate publication
+ uses: $/actions/publish
+ with:
+ package-tarball-artifact-id: ${{ matrix.package.artifact-id }}
+ dry-run: "true"
+ provenance: "false"
+ - name: Publish missing npm version
+ if: steps.registry.outputs.published != 'true'
+ uses: $/actions/publish
+ with:
+ package-tarball-artifact-id: ${{ matrix.package.artifact-id }}
+ tag: latest
+ - name: Prepare release asset
+ env:
+ PACKAGE_TARBALL: ${{ runner.temp }}/ci-package/${{ matrix.package.artifact-name }}
+ ASSET_NAME: ${{ matrix.package.slug }}-${{ matrix.package.version }}.tgz
+ run: |
+ mkdir -p "$RUNNER_TEMP/release-assets"
+ cp "$PACKAGE_TARBALL" "$RUNNER_TEMP/release-assets/$ASSET_NAME"
+ - uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
+ with:
+ name: release-assets-${{ matrix.package.slug }}
+ path: ${{ runner.temp }}/release-assets/*.tgz
+ overwrite: true
+ if-no-files-found: error
+
+ publish:
+ name: Publish GitHub release
+ needs: [verify, packages]
+ runs-on: ubuntu-latest
+ timeout-minutes: 15
+ environment: ${{ inputs.environment }}
+ permissions:
+ contents: write
+ actions: read
+ outputs:
+ url: ${{ steps.finalize.outputs.url }}
+ status: ${{ steps.finalize.outcome == 'success' && 'published' || '' }}
+ steps:
+ - uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
+ with:
+ pattern: release-assets-*
+ merge-multiple: true
+ path: ${{ runner.temp }}/release-assets
+ - id: finalize
+ uses: $/actions/release/finalize
+ with:
+ tag: ${{ needs.verify.outputs.tag }}
+ asset-directory: ${{ runner.temp }}/release-assets
diff --git a/README.md b/README.md
index 007f1a3..01ce3ff 100644
--- a/README.md
+++ b/README.md
@@ -39,6 +39,12 @@ _Actions for continuous integration steps: build, lint, and test._
#### - [Publish](actions/publish/README.md)
+### Release Actions
+
+- [Prepare a release](actions/release/prepare/README.md)
+- [Restore a published package](actions/release/restore-package/README.md)
+- [Finalize a release](actions/release/finalize/README.md)
+
### Dependencies
_Actions dedicated to caching and validating Node.js dependencies._
@@ -63,7 +69,10 @@ _Actions focused on discovering and preparing the Node.js environment._
### Release
-- [Release](.github/workflows/release.md) — guide to Node.js project releases using `ci-github-publish` release actions and the package/publish actions.
+- [Release packages](docs/usage/releases.md) — single-package and Lerna releases with preparation, CI and publication.
+- [Preparation workflow reference](.github/workflows/prepare-release.md) — version planning and tagged source.
+- [Release workflow reference](.github/workflows/release.md) — inputs, secrets and outputs.
+- [Custom release pipelines](docs/usage/custom-releases.md) — compose the package, publish and GitHub release actions.
## Contributing
diff --git a/actions/package-artifacts/PackageArtifacts.js b/actions/package-artifacts/PackageArtifacts.js
new file mode 100644
index 0000000..7fa3c96
--- /dev/null
+++ b/actions/package-artifacts/PackageArtifacts.js
@@ -0,0 +1,104 @@
+const path = require("node:path");
+
+class PackageArtifacts {
+ constructor({ github, context }) {
+ this.github = github;
+ this.context = context;
+ }
+
+ parse(input) {
+ const packages = JSON.parse(input);
+ if (!Array.isArray(packages) || !packages.length || packages.length > 256)
+ throw new Error(
+ "Expected a nonempty package array with at most 256 entries.",
+ );
+ for (const item of packages) {
+ if (
+ !item ||
+ typeof item.name !== "string" ||
+ !/^(?:@[a-z0-9-]+\/)?[a-z0-9][a-z0-9._-]*$/.test(item.name) ||
+ item.slug !== item.name.replace(/^@/, "").replace("/", "-") ||
+ typeof item.version !== "string" ||
+ !/^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)$/.test(item.version) ||
+ typeof item.directory !== "string" ||
+ !item.directory ||
+ path.isAbsolute(item.directory) ||
+ item.directory.split(/[\\/]/).includes("..")
+ )
+ throw new Error(
+ "Expected valid package names, slugs, stable versions and relative directories.",
+ );
+ }
+ if (new Set(packages.map((item) => item.slug)).size !== packages.length)
+ throw new Error("Package slugs must be unique.");
+ return packages;
+ }
+
+ matches(artifact, item) {
+ const prefix = `npm-${item.slug}-${this.context.runId}-`;
+ return (
+ artifact.name.startsWith(prefix) &&
+ /^[1-9]\d*\.tgz$/.test(artifact.name.slice(prefix.length))
+ );
+ }
+
+ validateArtifact(artifact, item) {
+ if (
+ !this.matches(artifact, item) ||
+ artifact.expired ||
+ artifact.workflow_run?.id !== this.context.runId
+ )
+ throw new Error(
+ `Package ${item.name} must use an unexpired CI artifact from this run.`,
+ );
+ }
+
+ async collect(input) {
+ const packages = this.parse(input);
+ const artifacts = await this.github.paginate(
+ this.github.rest.actions.listWorkflowRunArtifacts,
+ {
+ ...this.context.repo,
+ run_id: this.context.runId,
+ per_page: 100,
+ },
+ );
+ return packages.map((item) => {
+ // Successful matrix jobs from earlier attempts remain valid on a failed-job rerun.
+ const artifact = artifacts
+ .filter((candidate) => this.matches(candidate, item))
+ .sort((a, b) => b.id - a.id)[0];
+ if (!artifact) throw new Error(`No CI tarball found for ${item.name}.`);
+ this.validateArtifact(artifact, item);
+ return {
+ ...item,
+ "artifact-id": artifact.id,
+ "artifact-name": artifact.name,
+ };
+ });
+ }
+
+ async verify(input, version) {
+ const packages = this.parse(input);
+ for (const item of packages) {
+ if (item.version !== version)
+ throw new Error(
+ "CI package version must match the prepared release tag.",
+ );
+ if (!Number.isSafeInteger(item["artifact-id"]) || item["artifact-id"] < 1)
+ throw new Error("Expected a positive CI artifact ID.");
+ const { data: artifact } = await this.github.rest.actions.getArtifact({
+ ...this.context.repo,
+ artifact_id: item["artifact-id"],
+ });
+ this.validateArtifact(artifact, item);
+ if (artifact.workflow_run.head_sha !== this.context.sha)
+ throw new Error("CI artifact must come from this prepared commit.");
+ if (item["artifact-name"] !== artifact.name)
+ throw new Error("CI artifact filename does not match its ID.");
+ }
+ return packages;
+ }
+}
+
+module.exports = { PackageArtifacts };
diff --git a/actions/package-artifacts/README.md b/actions/package-artifacts/README.md
new file mode 100644
index 0000000..d44d220
--- /dev/null
+++ b/actions/package-artifacts/README.md
@@ -0,0 +1,76 @@
+
+
+#  GitHub Action: Collect npm package artifacts
+
+
+

+
+
+---
+
+
+
+
+[](https://github.com/marketplace/actions/collect-npm-package-artifacts)
+[](https://github.com/hoverkraft-tech/ci-github-nodejs/releases)
+[](http://choosealicense.com/licenses/mit/)
+[](https://img.shields.io/github/stars/hoverkraft-tech/ci-github-nodejs?style=social)
+[](https://github.com/hoverkraft-tech/ci-github-nodejs/blob/main/CONTRIBUTING.md)
+
+
+
+
+## Overview
+
+Collect immutable tarball artifact IDs after CI packaging, including successful matrix jobs from earlier attempts of the same run.
+
+
+
+
+## Inputs
+
+| **Input** | **Description** | **Required** | **Default** |
+| -------------- | -------------------------------------------------------------------------------------- | ------------ | ----------- |
+| **`packages`** | JSON list of packages with name, version, directory and slug from release preparation. | **true** | - |
+
+
+
+
+
+
+## Outputs
+
+| **Output** | **Description** |
+| -------------- | ----------------------------------------------------------------------------------------- |
+| **`packages`** | JSON package list with artifact-id and artifact-name, verified against this workflow run. |
+
+
+
+
+## Contributing
+
+Contributions are welcome! Please see the [contributing guidelines](https://github.com/hoverkraft-tech/ci-github-nodejs/blob/main/CONTRIBUTING.md) for more details.
+
+
+
+
+
+
+## License
+
+This project is licensed under the MIT License.
+
+SPDX-License-Identifier: MIT
+
+Copyright © 2026 hoverkraft
+
+For more details, see the [license](http://choosealicense.com/licenses/mit/).
+
+
+
+
+---
+
+This documentation was automatically generated by [CI Dokumentor](https://github.com/hoverkraft-tech/ci-dokumentor).
+
+
diff --git a/actions/package-artifacts/action.yml b/actions/package-artifacts/action.yml
new file mode 100644
index 0000000..9e98dcc
--- /dev/null
+++ b/actions/package-artifacts/action.yml
@@ -0,0 +1,26 @@
+name: Collect npm package artifacts
+description: Collect immutable tarball artifact IDs after CI packaging, including successful matrix jobs from earlier attempts of the same run.
+author: hoverkraft
+branding:
+ icon: package
+ color: blue
+inputs:
+ packages:
+ description: JSON list of packages with name, version, directory and slug from release preparation.
+ required: true
+outputs:
+ packages:
+ description: JSON package list with artifact-id and artifact-name, verified against this workflow run.
+ value: ${{ steps.collect.outputs.packages }}
+runs:
+ using: composite
+ steps:
+ - id: collect
+ uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
+ env:
+ ACTION_PATH: ${{ github.action_path }}
+ PACKAGES: ${{ inputs.packages }}
+ with:
+ script: |
+ const { PackageArtifacts } = require(`${process.env.ACTION_PATH}/PackageArtifacts.js`);
+ core.setOutput('packages', await new PackageArtifacts({ github, context }).collect(process.env.PACKAGES));
diff --git a/actions/release/ReleaseArtifacts.js b/actions/release/ReleaseArtifacts.js
new file mode 100644
index 0000000..a102ef1
--- /dev/null
+++ b/actions/release/ReleaseArtifacts.js
@@ -0,0 +1,110 @@
+const { createHash } = require("node:crypto");
+const fs = require("node:fs");
+const { execFileSync } = require("node:child_process");
+const path = require("node:path");
+
+class ReleaseArtifacts {
+ constructor(fetchPackage = fetch) {
+ this.fetchPackage = fetchPackage;
+ }
+
+ static async findRelease(github, repo, tag) {
+ try {
+ const { data } = await github.rest.repos.getReleaseByTag({
+ ...repo,
+ tag,
+ });
+ return data;
+ } catch (error) {
+ if (error.status !== 404) throw error;
+ const releases = await github.paginate(github.rest.repos.listReleases, {
+ ...repo,
+ per_page: 100,
+ });
+ return releases.find((release) => release.tag_name === tag);
+ }
+ }
+
+ static verifyTarball({ name, version, tarballPath }) {
+ const manifest = JSON.parse(
+ execFileSync("tar", ["-xOf", tarballPath, "package/package.json"], {
+ encoding: "utf8",
+ }),
+ );
+ if (
+ manifest.name !== name ||
+ manifest.version !== version ||
+ manifest.private
+ )
+ throw new Error(
+ "CI tarball must contain the expected public package and release version.",
+ );
+ }
+
+ async restorePackage({ name, version, tarballPath }) {
+ const response = await this.fetchPackage(
+ `https://registry.npmjs.org/${encodeURIComponent(name)}/${encodeURIComponent(version)}`,
+ );
+ if (response.status === 404) return false;
+ if (!response.ok)
+ throw new Error(`npm registry lookup failed: HTTP ${response.status}`);
+ const metadata = await response.json();
+ if (metadata.name !== name || metadata.version !== version)
+ throw new Error("npm registry returned an unexpected package version.");
+ const url = new URL(metadata.dist.tarball);
+ if (url.origin !== "https://registry.npmjs.org")
+ throw new Error(
+ "Published package tarball must come from the npm registry.",
+ );
+ const tarballResponse = await this.fetchPackage(url.href);
+ if (!tarballResponse.ok)
+ throw new Error(
+ `npm tarball download failed: HTTP ${tarballResponse.status}`,
+ );
+ const tarball = Buffer.from(await tarballResponse.arrayBuffer());
+ const integrity = `sha512-${createHash("sha512").update(tarball).digest("base64")}`;
+ if (metadata.dist.integrity !== integrity)
+ throw new Error(
+ "Published package tarball failed integrity verification.",
+ );
+ fs.writeFileSync(tarballPath, tarball);
+ return true;
+ }
+
+ async prepareAssets({ github, repo, tag, directory }) {
+ const release = await ReleaseArtifacts.findRelease(github, repo, tag);
+ if (!release) throw new Error(`No release found for ${tag}.`);
+ const assets = await github.paginate(github.rest.repos.listReleaseAssets, {
+ ...repo,
+ release_id: release.id,
+ per_page: 100,
+ });
+ const files = fs
+ .readdirSync(directory)
+ .filter((name) => name.endsWith(".tgz"));
+ if (!files.length)
+ throw new Error("No package tarballs available to attach.");
+ const missing = [];
+ for (const name of files) {
+ const data = fs.readFileSync(path.join(directory, name));
+ const digest = `sha256:${createHash("sha256").update(data).digest("hex")}`;
+ const existing = assets.find((asset) => asset.name === name);
+ if (existing) {
+ if (existing.digest !== digest)
+ throw new Error(
+ `Release asset ${name} has a different or unavailable digest.`,
+ );
+ continue;
+ }
+ if (!release.draft)
+ throw new Error(`Published release is missing expected asset ${name}.`);
+ missing.push({ name, data });
+ }
+ const pendingDirectory = fs.mkdtempSync(path.join(directory, "pending-"));
+ for (const { name, data } of missing)
+ fs.writeFileSync(path.join(pendingDirectory, name), data);
+ return { release, pendingDirectory, hasAssets: missing.length > 0 };
+ }
+}
+
+module.exports = { ReleaseArtifacts };
diff --git a/actions/release/ReleaseProject.js b/actions/release/ReleaseProject.js
new file mode 100644
index 0000000..af3d868
--- /dev/null
+++ b/actions/release/ReleaseProject.js
@@ -0,0 +1,308 @@
+const fs = require("node:fs");
+const path = require("node:path");
+const { execFileSync } = require("node:child_process");
+
+class ReleaseProject {
+ constructor({
+ workspace,
+ workingDirectory = ".",
+ versioning = "npm",
+ github,
+ context,
+ }) {
+ this.workspace = fs.realpathSync(workspace);
+ this.directory = fs.realpathSync(path.resolve(workspace, workingDirectory));
+ this.relativeDirectory = path.relative(this.workspace, this.directory);
+ if (
+ this.relativeDirectory.startsWith("..") ||
+ path.isAbsolute(this.relativeDirectory)
+ ) {
+ throw new Error(
+ "Release working directory must be inside the repository.",
+ );
+ }
+ if (!["lerna", "npm"].includes(versioning)) {
+ throw new Error("versioning must be npm or lerna.");
+ }
+ this.versioning = versioning;
+ this.github = github;
+ this.context = context;
+ const manifest = this.readJson("package.json");
+ if (versioning === "npm" && (manifest.workspaces || manifest.private)) {
+ throw new Error(
+ "npm mode requires one public package; use lerna for fixed-version workspaces.",
+ );
+ }
+ this.version();
+ }
+
+ readJson(file) {
+ return JSON.parse(fs.readFileSync(path.join(this.directory, file), "utf8"));
+ }
+
+ run(command, args) {
+ return execFileSync(command, args, {
+ cwd: this.directory,
+ encoding: "utf8",
+ stdio: ["ignore", "pipe", "pipe"],
+ env: { ...process.env, CI: "true" },
+ }).trim();
+ }
+
+ git(...args) {
+ return this.run("git", args);
+ }
+
+ version() {
+ const { version } = this.readJson(
+ this.versioning === "lerna" ? "lerna.json" : "package.json",
+ );
+ if (
+ typeof version !== "string" ||
+ !/^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)$/.test(version)
+ ) {
+ throw new Error(
+ "Releases require a stable version; independent Lerna versions and prereleases are not supported.",
+ );
+ }
+ return version;
+ }
+
+ packages(tag) {
+ const version = this.version();
+ if (this.versionFromTag(tag) !== version)
+ throw new Error("Release tag must match the committed package version.");
+ const candidates =
+ this.versioning === "lerna"
+ ? JSON.parse(
+ this.run("npm", [
+ "exec",
+ "--no",
+ "--",
+ "lerna",
+ "list",
+ "--all",
+ "--json",
+ "--loglevel",
+ "silent",
+ ]),
+ )
+ : [{ ...this.readJson("package.json"), location: this.directory }];
+ const packages = candidates
+ .filter((item) => !item.private && item.version === version)
+ .map((item) => {
+ if (
+ typeof item.name !== "string" ||
+ !/^(?:@[a-z0-9-]+\/)?[a-z0-9][a-z0-9._-]*$/.test(item.name)
+ ) {
+ throw new Error("Release packages must have valid npm names.");
+ }
+ const directory = path.relative(
+ this.directory,
+ fs.realpathSync(item.location),
+ );
+ if (directory.startsWith("..") || path.isAbsolute(directory))
+ throw new Error("Package is outside the release working directory.");
+ return {
+ name: item.name,
+ version,
+ directory: directory || ".",
+ slug: item.name.replace(/^@/, "").replace("/", "-"),
+ };
+ });
+ if (
+ !packages.length ||
+ new Set(packages.map((item) => item.slug)).size !== packages.length
+ ) {
+ throw new Error(
+ "Expected uniquely named public packages at the release version.",
+ );
+ }
+ return packages;
+ }
+
+ tagCommit(tag) {
+ try {
+ return this.git("rev-parse", "--verify", `${tag}^{commit}`);
+ } catch {
+ return undefined;
+ }
+ }
+
+ versionFromTag(tag) {
+ return ReleaseProject.versionFromTag(
+ tag,
+ this.directory,
+ this.relativeDirectory,
+ );
+ }
+
+ static versionFromTag(tag, directory, relativeDirectory) {
+ const slug = path
+ .basename(directory)
+ .toLowerCase()
+ .replace(/[^a-z0-9]+/g, "-")
+ .replace(/^-+|-+$/g, "");
+ const prefixes = ["", "v", ...(relativeDirectory ? [`${slug}-`] : [])];
+ const version = prefixes
+ .map((prefix) => (tag.startsWith(prefix) ? tag.slice(prefix.length) : ""))
+ .find((candidate) =>
+ /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)$/.test(candidate),
+ );
+ if (!version)
+ throw new Error(
+ "Expected a stable version tag, optionally prefixed with v or the project directory slug.",
+ );
+ return version;
+ }
+
+ currentTag() {
+ if (this.context.ref.startsWith("refs/tags/"))
+ return this.context.ref.slice("refs/tags/".length);
+ if (
+ this.context.ref !==
+ `refs/heads/${this.context.payload.repository.default_branch}`
+ ) {
+ throw new Error(
+ "Run releases from the default branch or an existing release tag.",
+ );
+ }
+ const tags = this.git("tag", "--points-at", this.context.sha)
+ .split("\n")
+ .filter((tag) => {
+ try {
+ return this.versionFromTag(tag) === this.version();
+ } catch {
+ return false;
+ }
+ });
+ if (tags.length > 1)
+ throw new Error(
+ "Several release tags match this commit; resume the intended tag explicitly.",
+ );
+ return tags[0];
+ }
+
+ prepareVersion({ tag, body }) {
+ const version = this.versionFromTag(tag);
+ const current = this.version();
+ const previousParts = current.split(".").map(BigInt);
+ const parts = version.split(".").map(BigInt);
+ const difference = parts
+ .map((part, index) => part - previousParts[index])
+ .find((part) => part !== 0n);
+ if (!difference || difference < 0n)
+ throw new Error(
+ "Planned version must be newer than the committed version; reconcile the release history and configuration.",
+ );
+ if (this.tagCommit(tag))
+ throw new Error(`Existing tag ${tag} must not be overwritten.`);
+ if (typeof body !== "string" || !body.trim())
+ throw new Error(
+ "Upstream release notes are required before preparing source files.",
+ );
+ const branch = this.context.payload.repository.default_branch;
+ this.git("switch", "--force-create", branch, this.context.sha);
+ if (this.git("status", "--porcelain"))
+ throw new Error(
+ "Release source must be clean before applying the planned version.",
+ );
+ this.git("config", "user.name", "github-actions[bot]");
+ this.git(
+ "config",
+ "user.email",
+ "41898282+github-actions[bot]@users.noreply.github.com",
+ );
+ if (this.versioning === "lerna") {
+ this.run("npm", [
+ "exec",
+ "--no",
+ "--",
+ "lerna",
+ "version",
+ version,
+ "--conventional-commits",
+ "--tag-version-prefix",
+ tag.slice(0, -version.length),
+ "--no-git-tag-version",
+ "--no-push",
+ "--yes",
+ ]);
+ if (this.version() === current) return { status: "no-changes" };
+ } else {
+ this.run("npm", [
+ "version",
+ version,
+ "--no-git-tag-version",
+ "--ignore-scripts",
+ ]);
+ }
+ if (this.version() !== version)
+ throw new Error("Version preparation did not apply the planned version.");
+ const changelog = path.join(this.directory, "CHANGELOG.md");
+ const previous = fs.existsSync(changelog)
+ ? fs.readFileSync(changelog, "utf8").replace(/^# Changelog\s*/i, "")
+ : "";
+ fs.writeFileSync(
+ changelog,
+ `# Changelog\n\n## ${tag}\n\n${body.trim()}\n\n${previous}`,
+ );
+ this.git("add", "--all", "--", ".");
+ this.git("commit", "-m", `chore(release): ${tag}`);
+ this.git("tag", tag);
+ this.git(
+ "push",
+ "--atomic",
+ "origin",
+ `HEAD:refs/heads/${branch}`,
+ `refs/tags/${tag}`,
+ );
+ return { tag };
+ }
+
+ async prepare({ workflowRef, findRelease, plan }) {
+ const { ref, payload, repo } = this.context;
+ if (ref.startsWith("refs/tags/")) {
+ const tag = ref.slice("refs/tags/".length);
+ const packages = this.packages(tag);
+ const release = await findRelease(this.github, repo, tag);
+ return {
+ status: "ready",
+ tag,
+ packages,
+ published: Boolean(release && !release.draft),
+ };
+ }
+ if (ref !== `refs/heads/${payload.repository.default_branch}`) {
+ throw new Error(
+ "Run releases from the default branch or an existing release tag.",
+ );
+ }
+ const currentTag = this.currentTag();
+ if (!currentTag && !plan)
+ throw new Error("An upstream release plan is required.");
+ if (!currentTag && !plan.hasChanges) return { status: "no-changes" };
+ const result = currentTag ? { tag: currentTag } : this.prepareVersion(plan);
+ if (!result.tag) return result;
+ const release = await findRelease(this.github, repo, result.tag);
+ if (release && !release.draft) {
+ return { ...result, status: "released", url: release.html_url };
+ }
+ const prefix = `${repo.owner}/${repo.repo}/`;
+ const workflow = workflowRef.startsWith(prefix)
+ ? workflowRef.slice(prefix.length).split("@")[0]
+ : "";
+ if (!/^\.github\/workflows\/[^/]+\.ya?ml$/.test(workflow))
+ throw new Error(
+ "Cannot determine the caller workflow for publication dispatch.",
+ );
+ await this.github.rest.actions.createWorkflowDispatch({
+ ...repo,
+ workflow_id: workflow,
+ ref: result.tag,
+ });
+ return { ...result, status: "dispatched" };
+ }
+}
+
+module.exports = { ReleaseProject };
diff --git a/actions/release/finalize/README.md b/actions/release/finalize/README.md
new file mode 100644
index 0000000..1d3dee4
--- /dev/null
+++ b/actions/release/finalize/README.md
@@ -0,0 +1,78 @@
+
+
+#  GitHub Action: Finalize Node.js release
+
+
+

+
+
+---
+
+
+
+
+[](https://github.com/marketplace/actions/finalize-node.js-release)
+[](https://github.com/hoverkraft-tech/ci-github-nodejs/releases)
+[](http://choosealicense.com/licenses/mit/)
+[](https://img.shields.io/github/stars/hoverkraft-tech/ci-github-nodejs?style=social)
+[](https://github.com/hoverkraft-tech/ci-github-nodejs/blob/main/CONTRIBUTING.md)
+
+
+
+
+## Overview
+
+Verify published npm tarballs against existing assets, then upload missing assets and publish the draft with HoverKraft release/update.
+
+
+
+
+## Inputs
+
+| **Input** | **Description** | **Required** | **Default** |
+| --------------------- | ------------------------------------------------ | ------------ | --------------------- |
+| **`tag`** | Committed release tag. | **true** | - |
+| **`asset-directory`** | Directory containing the published npm tarballs. | **true** | - |
+| **`github-token`** | Token with contents write permissions. | **false** | `${{ github.token }}` |
+
+
+
+
+
+
+## Outputs
+
+| **Output** | **Description** |
+| ---------- | ----------------------------- |
+| **`url`** | Published GitHub release URL. |
+
+
+
+
+## Contributing
+
+Contributions are welcome! Please see the [contributing guidelines](https://github.com/hoverkraft-tech/ci-github-nodejs/blob/main/CONTRIBUTING.md) for more details.
+
+
+
+
+
+
+## License
+
+This project is licensed under the MIT License.
+
+SPDX-License-Identifier: MIT
+
+Copyright © 2026 hoverkraft
+
+For more details, see the [license](http://choosealicense.com/licenses/mit/).
+
+
+
+
+---
+
+This documentation was automatically generated by [CI Dokumentor](https://github.com/hoverkraft-tech/ci-dokumentor).
+
+
diff --git a/actions/release/finalize/action.yml b/actions/release/finalize/action.yml
new file mode 100644
index 0000000..a446056
--- /dev/null
+++ b/actions/release/finalize/action.yml
@@ -0,0 +1,52 @@
+name: Finalize Node.js release
+description: Verify published npm tarballs against existing assets, then upload missing assets and publish the draft with HoverKraft release/update.
+author: hoverkraft
+branding:
+ icon: tag
+ color: blue
+inputs:
+ tag:
+ description: Committed release tag.
+ required: true
+ asset-directory:
+ description: Directory containing the published npm tarballs.
+ required: true
+ github-token:
+ description: Token with contents write permissions.
+ default: ${{ github.token }}
+outputs:
+ url:
+ description: Published GitHub release URL.
+ value: ${{ steps.assets.outputs.url }}
+runs:
+ using: composite
+ steps:
+ - id: assets
+ uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
+ env:
+ ACTION_PATH: ${{ github.action_path }}
+ RELEASE_TAG: ${{ inputs.tag }}
+ ASSET_DIRECTORY: ${{ inputs.asset-directory }}
+ with:
+ github-token: ${{ inputs.github-token }}
+ script: |
+ const { ReleaseArtifacts } = require(`${process.env.ACTION_PATH}/../ReleaseArtifacts.js`);
+ const { release, pendingDirectory, hasAssets } = await new ReleaseArtifacts().prepareAssets({ github, repo: context.repo, tag: process.env.RELEASE_TAG, directory: process.env.ASSET_DIRECTORY });
+ core.setOutput('url', release.html_url);
+ core.setOutput('published', String(!release.draft));
+ core.setOutput('pending-directory', pendingDirectory);
+ core.setOutput('has-assets', String(hasAssets));
+ - id: pending-assets
+ if: steps.assets.outputs.has-assets == 'true'
+ uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
+ with:
+ name: release-pending-assets-${{ github.run_id }}-${{ github.run_attempt }}
+ path: ${{ steps.assets.outputs.pending-directory }}/*.tgz
+ if-no-files-found: error
+ - uses: hoverkraft-tech/ci-github-publish/actions/release/update@ea6682de88070c254dac619a6623a242a6d57cd3 # 1.0.3
+ if: steps.assets.outputs.published != 'true'
+ with:
+ tag: ${{ inputs.tag }}
+ publish: "true"
+ release-artifact-id: ${{ steps.pending-assets.outputs.artifact-id }}
+ github-token: ${{ inputs.github-token }}
diff --git a/actions/release/prepare/README.md b/actions/release/prepare/README.md
new file mode 100644
index 0000000..fc784aa
--- /dev/null
+++ b/actions/release/prepare/README.md
@@ -0,0 +1,81 @@
+
+
+#  GitHub Action: Prepare Node.js release
+
+
+

+
+
+---
+
+
+
+
+[](https://github.com/marketplace/actions/prepare-node.js-release)
+[](https://github.com/hoverkraft-tech/ci-github-nodejs/releases)
+[](http://choosealicense.com/licenses/mit/)
+[](https://img.shields.io/github/stars/hoverkraft-tech/ci-github-nodejs?style=social)
+[](https://github.com/hoverkraft-tech/ci-github-nodejs/blob/main/CONTRIBUTING.md)
+
+
+
+
+## Overview
+
+Plan with HoverKraft, apply the version and changelog with npm or Lerna, and dispatch publication from the committed tag.
+
+
+
+
+## Inputs
+
+| **Input** | **Description** | **Required** | **Default** |
+| ----------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- | ------------ | --------------------- |
+| **`versioning`** | Tool applying the HoverKraft release plan, npm for one package or lerna for fixed-version workspaces. | **false** | `npm` |
+| **`working-directory`** | Project directory relative to the caller repository root. | **false** | `.` |
+| **`github-token`** | Token with contents and actions write and pull-requests read permissions. Its identity must be allowed to push release commits and tags. | **false** | `${{ github.token }}` |
+
+
+
+
+
+
+## Outputs
+
+| **Output** | **Description** |
+| --------------- | ------------------------------------------------------------------------------------------------------- |
+| **`status`** | One of no-changes, dispatched, ready or released. Only ready should start CI, followed by publication. |
+| **`tag`** | Stable release tag, empty when preparation has no release to publish. |
+| **`packages`** | JSON array of public packages at the committed release version, with name, version, directory and slug. |
+| **`published`** | Whether the tag already has a published GitHub release. |
+
+
+
+
+## Contributing
+
+Contributions are welcome! Please see the [contributing guidelines](https://github.com/hoverkraft-tech/ci-github-nodejs/blob/main/CONTRIBUTING.md) for more details.
+
+
+
+
+
+
+## License
+
+This project is licensed under the MIT License.
+
+SPDX-License-Identifier: MIT
+
+Copyright © 2026 hoverkraft
+
+For more details, see the [license](http://choosealicense.com/licenses/mit/).
+
+
+
+
+---
+
+This documentation was automatically generated by [CI Dokumentor](https://github.com/hoverkraft-tech/ci-dokumentor).
+
+
diff --git a/actions/release/prepare/action.yml b/actions/release/prepare/action.yml
new file mode 100644
index 0000000..b31fdf3
--- /dev/null
+++ b/actions/release/prepare/action.yml
@@ -0,0 +1,113 @@
+name: Prepare Node.js release
+description: Plan with HoverKraft, apply the version and changelog with npm or Lerna, and dispatch publication from the committed tag.
+author: hoverkraft
+branding:
+ icon: git-commit
+ color: blue
+inputs:
+ versioning:
+ description: Tool applying the HoverKraft release plan, npm for one package or lerna for fixed-version workspaces.
+ default: npm
+ working-directory:
+ description: Project directory relative to the caller repository root.
+ default: .
+ github-token:
+ description: Token with contents and actions write and pull-requests read permissions. Its identity must be allowed to push release commits and tags.
+ default: ${{ github.token }}
+outputs:
+ status:
+ description: One of no-changes, dispatched, ready or released. Only ready should start CI, followed by publication.
+ value: ${{ steps.prepare.outputs.status }}
+ tag:
+ description: Stable release tag, empty when preparation has no release to publish.
+ value: ${{ steps.prepare.outputs.tag }}
+ packages:
+ description: JSON array of public packages at the committed release version, with name, version, directory and slug.
+ value: ${{ steps.prepare.outputs.packages }}
+ published:
+ description: Whether the tag already has a published GitHub release.
+ value: ${{ steps.prepare.outputs.published }}
+runs:
+ using: composite
+ steps:
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
+ with:
+ fetch-depth: 0
+ token: ${{ inputs.github-token }}
+ # The preparation step pushes version commits and tags atomically.
+ persist-credentials: true
+ - name: Validate release project
+ id: inspect
+ uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
+ env:
+ ACTION_PATH: ${{ github.action_path }}
+ WORKING_DIRECTORY: ${{ inputs.working-directory }}
+ VERSIONING: ${{ inputs.versioning }}
+ with:
+ script: |
+ const { ReleaseProject } = require(`${process.env.ACTION_PATH}/../ReleaseProject.js`);
+ const project = new ReleaseProject({ workspace: process.env.GITHUB_WORKSPACE, workingDirectory: process.env.WORKING_DIRECTORY, versioning: process.env.VERSIONING, github, context });
+ core.setOutput('needs-plan', String(!project.currentTag()));
+ - name: Plan release with HoverKraft
+ id: plan
+ if: steps.inspect.outputs.needs-plan == 'true'
+ uses: hoverkraft-tech/ci-github-publish/actions/release/plan@ea6682de88070c254dac619a6623a242a6d57cd3 # 1.0.3
+ with:
+ github-token: ${{ inputs.github-token }}
+ target-sha: ${{ github.sha }}
+ working-directory: ${{ inputs.working-directory != '.' && inputs.working-directory || '' }}
+ - name: Restore source checkout for version preparation
+ if: steps.plan.outputs.has-changes == 'true'
+ uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
+ with:
+ fetch-depth: 0
+ token: ${{ inputs.github-token }}
+ persist-credentials: true
+ - uses: $/actions/setup-node
+ if: steps.plan.outputs.has-changes == 'true' || inputs.versioning == 'lerna' && steps.inspect.outputs.needs-plan != 'true'
+ with:
+ working-directory: ${{ inputs.working-directory }}
+ - id: configuration
+ if: steps.plan.outputs.has-changes == 'true'
+ uses: hoverkraft-tech/ci-github-publish/actions/release/get-configuration@ea6682de88070c254dac619a6623a242a6d57cd3 # 1.0.3
+ with:
+ working-directory: ${{ inputs.working-directory != '.' && inputs.working-directory || '' }}
+ - name: Render the planned changelog without creating release state
+ id: notes
+ if: steps.plan.outputs.has-changes == 'true'
+ uses: hoverkraft-tech/ci-github-publish/actions/release/prepare@ea6682de88070c254dac619a6623a242a6d57cd3 # 1.0.3
+ with:
+ config-name: file:${{ steps.configuration.outputs.config-path }}
+ token: ${{ inputs.github-token }}
+ dry-run: "true"
+ tag: ${{ steps.plan.outputs.tag }}
+ commitish: ${{ github.sha }} # codespell:ignore commitish
+ - name: Prepare release source
+ id: prepare
+ uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
+ env:
+ ACTION_PATH: ${{ github.action_path }}
+ WORKING_DIRECTORY: ${{ inputs.working-directory }}
+ VERSIONING: ${{ inputs.versioning }}
+ CALLER_WORKFLOW_REF: ${{ github.workflow_ref }}
+ PLANNED_TAG: ${{ steps.plan.outputs.tag }}
+ HAS_CHANGES: ${{ steps.plan.outputs.has-changes }}
+ CHANGELOG: ${{ steps.notes.outputs.body }}
+ with:
+ github-token: ${{ inputs.github-token }}
+ script: |
+ const { ReleaseProject } = require(`${process.env.ACTION_PATH}/../ReleaseProject.js`);
+ const { ReleaseArtifacts } = require(`${process.env.ACTION_PATH}/../ReleaseArtifacts.js`);
+ const project = new ReleaseProject({ workspace: process.env.GITHUB_WORKSPACE, workingDirectory: process.env.WORKING_DIRECTORY, versioning: process.env.VERSIONING, github, context });
+ const plan = { tag: process.env.PLANNED_TAG, hasChanges: process.env.HAS_CHANGES === 'true', body: process.env.CHANGELOG };
+ const result = await project.prepare({ workflowRef: process.env.CALLER_WORKFLOW_REF, findRelease: ReleaseArtifacts.findRelease, plan });
+ for (const [name, value] of Object.entries(result)) core.setOutput(name, value);
+ core.setOutput('packages', result.packages || []);
+ core.setOutput('published', String(Boolean(result.published)));
+ const messages = {
+ 'no-changes': 'No changes to release.',
+ dispatched: `Publication dispatched for ${result.tag}. Follow the new workflow run for that tag.`,
+ ready: `Ready for CI on committed release ${result.tag}.`,
+ released: `${result.tag} is already released.`,
+ };
+ await core.summary.addRaw(messages[result.status]).write();
diff --git a/actions/release/restore-package/README.md b/actions/release/restore-package/README.md
new file mode 100644
index 0000000..b7c6f55
--- /dev/null
+++ b/actions/release/restore-package/README.md
@@ -0,0 +1,78 @@
+
+
+#  GitHub Action: Restore published Node.js package
+
+
+

+
+
+---
+
+
+
+
+[](https://github.com/marketplace/actions/restore-published-node.js-package)
+[](https://github.com/hoverkraft-tech/ci-github-nodejs/releases)
+[](http://choosealicense.com/licenses/mit/)
+[](https://img.shields.io/github/stars/hoverkraft-tech/ci-github-nodejs?style=social)
+[](https://github.com/hoverkraft-tech/ci-github-nodejs/blob/main/CONTRIBUTING.md)
+
+
+
+
+## Overview
+
+Validate a CI tarball, check an exact npm version and restore its original tarball with integrity verification when resuming publication.
+
+
+
+
+## Inputs
+
+| **Input** | **Description** | **Required** | **Default** |
+| ------------------ | ---------------------------------------------------------------------------- | ------------ | ----------- |
+| **`name`** | Expected npm package name. | **true** | - |
+| **`version`** | Expected committed package version. | **true** | - |
+| **`tarball-path`** | Local tarball path to replace with the original published bytes on recovery. | **true** | - |
+
+
+
+
+
+
+## Outputs
+
+| **Output** | **Description** |
+| --------------- | ----------------------------------------------------------------------------- |
+| **`published`** | Whether the exact version already exists on npm and its tarball was restored. |
+
+
+
+
+## Contributing
+
+Contributions are welcome! Please see the [contributing guidelines](https://github.com/hoverkraft-tech/ci-github-nodejs/blob/main/CONTRIBUTING.md) for more details.
+
+
+
+
+
+
+## License
+
+This project is licensed under the MIT License.
+
+SPDX-License-Identifier: MIT
+
+Copyright © 2026 hoverkraft
+
+For more details, see the [license](http://choosealicense.com/licenses/mit/).
+
+
+
+
+---
+
+This documentation was automatically generated by [CI Dokumentor](https://github.com/hoverkraft-tech/ci-dokumentor).
+
+
diff --git a/actions/release/restore-package/action.yml b/actions/release/restore-package/action.yml
new file mode 100644
index 0000000..a191917
--- /dev/null
+++ b/actions/release/restore-package/action.yml
@@ -0,0 +1,37 @@
+name: Restore published Node.js package
+description: Validate a CI tarball, check an exact npm version and restore its original tarball with integrity verification when resuming publication.
+author: hoverkraft
+branding:
+ icon: package
+ color: blue
+inputs:
+ name:
+ description: Expected npm package name.
+ required: true
+ version:
+ description: Expected committed package version.
+ required: true
+ tarball-path:
+ description: Local tarball path to replace with the original published bytes on recovery.
+ required: true
+outputs:
+ published:
+ description: Whether the exact version already exists on npm and its tarball was restored.
+ value: ${{ steps.restore.outputs.published }}
+runs:
+ using: composite
+ steps:
+ - id: restore
+ uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
+ env:
+ ACTION_PATH: ${{ github.action_path }}
+ PACKAGE_NAME: ${{ inputs.name }}
+ PACKAGE_VERSION: ${{ inputs.version }}
+ TARBALL_PATH: ${{ inputs.tarball-path }}
+ with:
+ script: |
+ const { ReleaseArtifacts } = require(`${process.env.ACTION_PATH}/../ReleaseArtifacts.js`);
+ const options = { name: process.env.PACKAGE_NAME, version: process.env.PACKAGE_VERSION, tarballPath: process.env.TARBALL_PATH };
+ ReleaseArtifacts.verifyTarball(options);
+ const published = await new ReleaseArtifacts().restorePackage(options);
+ core.setOutput('published', String(published));
diff --git a/actions/release/verify/README.md b/actions/release/verify/README.md
new file mode 100644
index 0000000..1b6cf72
--- /dev/null
+++ b/actions/release/verify/README.md
@@ -0,0 +1,79 @@
+
+
+#  GitHub Action: Verify release package artifacts
+
+
+

+
+
+---
+
+
+
+
+[](https://github.com/marketplace/actions/verify-release-package-artifacts)
+[](https://github.com/hoverkraft-tech/ci-github-nodejs/releases)
+[](http://choosealicense.com/licenses/mit/)
+[](https://img.shields.io/github/stars/hoverkraft-tech/ci-github-nodejs?style=social)
+[](https://github.com/hoverkraft-tech/ci-github-nodejs/blob/main/CONTRIBUTING.md)
+
+
+
+
+## Overview
+
+Require CI tarballs from this tag, workflow run and source commit before creating release state.
+
+
+
+
+## Inputs
+
+| **Input** | **Description** | **Required** | **Default** |
+| ----------------------- | -------------------------------------------------------------------------------- | ------------ | ----------- |
+| **`package-artifacts`** | JSON package artifact list from the CI workflow. | **true** | - |
+| **`working-directory`** | Project directory relative to the repository root, matching release preparation. | **false** | `.` |
+
+
+
+
+
+
+## Outputs
+
+| **Output** | **Description** |
+| --------------- | ----------------------------------------------------------------------------- |
+| **`packages`** | Verified package artifact list for publication. |
+| **`tag`** | Release tag from this workflow's immutable source ref. |
+| **`published`** | Whether the GitHub release is already public and its notes must be preserved. |
+
+
+
+
+## Contributing
+
+Contributions are welcome! Please see the [contributing guidelines](https://github.com/hoverkraft-tech/ci-github-nodejs/blob/main/CONTRIBUTING.md) for more details.
+
+
+
+
+
+
+## License
+
+This project is licensed under the MIT License.
+
+SPDX-License-Identifier: MIT
+
+Copyright © 2026 hoverkraft
+
+For more details, see the [license](http://choosealicense.com/licenses/mit/).
+
+
+
+
+---
+
+This documentation was automatically generated by [CI Dokumentor](https://github.com/hoverkraft-tech/ci-dokumentor).
+
+
diff --git a/actions/release/verify/action.yml b/actions/release/verify/action.yml
new file mode 100644
index 0000000..66f0be7
--- /dev/null
+++ b/actions/release/verify/action.yml
@@ -0,0 +1,49 @@
+name: Verify release package artifacts
+description: Require CI tarballs from this tag, workflow run and source commit before creating release state.
+author: hoverkraft
+branding:
+ icon: check-circle
+ color: blue
+inputs:
+ package-artifacts:
+ description: JSON package artifact list from the CI workflow.
+ required: true
+ working-directory:
+ description: Project directory relative to the repository root, matching release preparation.
+ default: .
+outputs:
+ packages:
+ description: Verified package artifact list for publication.
+ value: ${{ steps.verify.outputs.packages }}
+ tag:
+ description: Release tag from this workflow's immutable source ref.
+ value: ${{ steps.verify.outputs.tag }}
+ published:
+ description: Whether the GitHub release is already public and its notes must be preserved.
+ value: ${{ steps.verify.outputs.published }}
+runs:
+ using: composite
+ steps:
+ - id: verify
+ uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
+ env:
+ ACTION_PATH: ${{ github.action_path }}
+ PACKAGES: ${{ inputs.package-artifacts }}
+ WORKING_DIRECTORY: ${{ inputs.working-directory }}
+ with:
+ script: |
+ const path = require('node:path');
+ const { PackageArtifacts } = require(`${process.env.ACTION_PATH}/../../package-artifacts/PackageArtifacts.js`);
+ const { ReleaseProject } = require(`${process.env.ACTION_PATH}/../ReleaseProject.js`);
+ const { ReleaseArtifacts } = require(`${process.env.ACTION_PATH}/../ReleaseArtifacts.js`);
+ if (!context.ref.startsWith('refs/tags/')) throw new Error('Publish from the prepared release tag.');
+ const tag = context.ref.slice('refs/tags/'.length);
+ const directory = path.resolve(process.env.GITHUB_WORKSPACE, process.env.WORKING_DIRECTORY);
+ const relativeDirectory = path.relative(process.env.GITHUB_WORKSPACE, directory);
+ if (relativeDirectory.startsWith('..') || path.isAbsolute(relativeDirectory)) throw new Error('Release directory must be inside the repository.');
+ const version = ReleaseProject.versionFromTag(tag, directory, relativeDirectory);
+ const packages = await new PackageArtifacts({ github, context }).verify(process.env.PACKAGES, version);
+ const release = await ReleaseArtifacts.findRelease(github, context.repo, tag);
+ core.setOutput('packages', packages);
+ core.setOutput('tag', tag);
+ core.setOutput('published', String(Boolean(release && !release.draft)));
diff --git a/docs/README.md b/docs/README.md
new file mode 100644
index 0000000..a5bcdae
--- /dev/null
+++ b/docs/README.md
@@ -0,0 +1,9 @@
+# Documentation
+
+- [Release a single package or Lerna workspaces](usage/releases.md)
+- [Compose a custom release pipeline](usage/custom-releases.md)
+- [Validate release automation](development/release-tests.md)
+- [Release orchestration decision](adr/0001-release-orchestration.md)
+- [Separation of CI and release](adr/0002-separate-ci-from-release.md)
+- [HoverKraft release planning and publication](adr/0003-hoverkraft-release-actions.md)
+- [CI produces release artifacts](adr/0004-ci-produces-release-artifacts.md)
diff --git a/docs/adr/0001-release-orchestration.md b/docs/adr/0001-release-orchestration.md
new file mode 100644
index 0000000..081955f
--- /dev/null
+++ b/docs/adr/0001-release-orchestration.md
@@ -0,0 +1,65 @@
+# ADR 0001: Shared Node.js release orchestration
+
+- Status: accepted
+- Date: 2026-10-29
+
+The decision to run CI inside release is superseded by
+[ADR 0002](0002-separate-ci-from-release.md). The version planning and release PR
+decisions are superseded by [ADR 0003](0003-hoverkraft-release-actions.md).
+The other decisions remain accepted.
+
+## Context
+
+The Package and Publish actions handle a single tarball. Consumers still need
+to prepare versions, select workspaces, start CI at the versioned source and
+recover partial releases. Reactionable's first integration added custom scripts
+for those responsibilities. A single-package consumer, reactionable-cli, uses
+Release Please and has a different source preparation policy.
+
+The Node.js release guide at commit
+`b7eadcff0bdbd690f4688e7ce3f31d7ba0e39865` documents composition of the actions,
+including committing versions before building and targeted recovery. The former
+reusable publish workflow was removed in 0.25; the new workflow covers source
+preparation and the complete release lifecycle instead of restoring that interface.
+
+## Decision
+
+Provide an optional reusable Release workflow, retaining the composable actions.
+Consumers own triggers, build options, credentials, environment rules and optional
+documentation deployment. HoverKraft owns preparation, publication and recovery.
+
+Support one public package through Release Please and fixed-version workspaces
+through the consumer's installed Lerna. Keep preparation policies explicit:
+Release Please requires a merged release PR; Lerna pushes versions directly.
+Both infer versions from Conventional Commits without a user-supplied version.
+
+Use Release Please's PR creation action with GitHub release creation disabled.
+Detect merged pending release PRs explicitly, tag their merge commits and mark
+them released only after npm and GitHub publication succeed. Release Please v5.0.0
+was verified on the decision date; its breaking change is the Node 24 runtime.
+
+Dispatch the caller workflow at the resulting tag using `GITHUB_TOKEN` or an
+explicit token. The Package action performs its own checkout, so starting a new
+run ensures CI, package manifests, source archives and provenance use that commit.
+The workflow serializes both runs and reports when publication has been dispatched.
+
+Preserve successful npm publishes on retry. Restore their original tarballs,
+verify registry integrity and never replace conflicting GitHub assets. Keep
+published release notes intact. Reuse the existing release create/update actions
+for AI notes and final publication. Do not introduce a second SemVer engine.
+
+## Consequences
+
+Consumers need no release scripts. The single-package path retains a review step;
+the Lerna path requires branch rules that permit its atomic push. An app token is
+needed when release PR creation must trigger normal PR CI. Neither mode bypasses
+repository protection rules.
+
+Preparation success and publication success belong to separate runs. A tag can
+remain after CI or service failure, and npm publication is not atomic across
+packages. Recovery operates on the original tag and package versions.
+
+The initial scope is stable public npm packages on GitHub.com hosted Linux
+runners. Independent workspace versions, custom registries and prereleases remain
+available through custom composition. New consumer pins require the upstream
+workflow implementation to be available on GitHub.
diff --git a/docs/adr/0002-separate-ci-from-release.md b/docs/adr/0002-separate-ci-from-release.md
new file mode 100644
index 0000000..d43ed6f
--- /dev/null
+++ b/docs/adr/0002-separate-ci-from-release.md
@@ -0,0 +1,39 @@
+# ADR 0002: Separate CI checks from release publication
+
+- Status: accepted; build ownership and orchestration partially superseded by
+ [ADR 0004](0004-ci-produces-release-artifacts.md)
+- Date: 2026-10-31
+- Partially supersedes: [ADR 0001](0001-release-orchestration.md)
+
+## Context
+
+ADR 0001 made the release workflow invoke the full continuous-integration
+workflow. That coupled publication to lint, test, coverage and security settings,
+repeated checks already owned by consumer CI, and required unrelated permissions.
+
+Building release artifacts still depends on release preparation: compiled output
+can embed the package version, and packaging and provenance must use the tagged
+source. Reusing a pre-version CI artifact would break that relationship.
+
+## Decision
+
+Keep linting, tests, coverage and security analysis in independent consumer CI.
+Remove their inputs and the nested CI invocation from the release workflow.
+Keep a dedicated build job that delegates compilation to the existing Build
+action. A small release build action translates the release build configuration
+and preserves artifact paths for packaging and documentation deployment.
+
+Release retains version preparation, tagged builds, changelogs, optional AI notes,
+publication and recovery. Consumers retain CI policy and release environment
+rules. The release workflow does not query or wait for CI status.
+
+## Consequences
+
+CI changes no longer change the release workflow's validation settings. The build
+job needs only contents and packages read permissions. A release build is not
+proof that tests passed on the tag; consumers must enforce their own checks.
+This matters for Lerna's generated version commit, which is pushed directly.
+
+Artifact output and recovery contracts remain unchanged. A failed release build
+stops publication, and retries rebuild the original tag. Manual and scheduled
+triggers and automatic Conventional Commit version selection remain unchanged.
diff --git a/docs/adr/0003-hoverkraft-release-actions.md b/docs/adr/0003-hoverkraft-release-actions.md
new file mode 100644
index 0000000..528a605
--- /dev/null
+++ b/docs/adr/0003-hoverkraft-release-actions.md
@@ -0,0 +1,52 @@
+# ADR 0003: Use HoverKraft release actions for planning and publication
+
+- Status: accepted; build ownership and orchestration partially superseded by
+ [ADR 0004](0004-ci-produces-release-artifacts.md)
+- Date: 2026-10-31
+- Partially supersedes: [ADR 0001](0001-release-orchestration.md)
+
+## Context
+
+Release Please added a separate release policy and PR lifecycle for single
+packages. Lerna independently selected monorepo versions. HoverKraft already
+provides shared release planning, changelog rendering, AI notes and publication.
+
+The `ci-github-publish` stable release 1.0.3, commit
+`ea6682de88070c254dac619a6623a242a6d57cd3`, was checked on this date.
+Its `release/plan` returns change detection and the planned tag. Its internal
+`release/prepare` helper can render notes for an explicit tag without writing a
+release. `release/update` uploads provided assets without overwriting existing
+names and publishes only after those uploads succeed.
+
+## Decision
+
+Use `release/plan` as the version authority for both single packages and Lerna
+workspaces. Keep npm and Lerna as tools that apply the exact planned version to
+manifests and lockfiles. Lerna also maintains workspace dependencies and package
+changelogs. Remove Release Please, release PR detection and its pending labels.
+
+Use `release/get-configuration` and the pinned `release/prepare` helper in dry-run
+mode to render the planned changelog before committing source files. This is the
+one direct use of the internal helper: the public planner's outputs do not expose
+the rendered notes. Pass the planned tag explicitly; do not calculate a second
+release identity. Preserve older root changelog entries.
+
+Push the version commit and tag atomically in both modes. Retain explicit tag
+dispatch, build and npm publication. Use `release/create` for the draft and its
+optional AI summary. Verify existing asset digests and stage only missing files;
+let `release/update` upload those files and publish the draft.
+
+## Consequences
+
+Manual and scheduled releases share the same preparation policy. Both require
+branch rules permitting the release commit. Neither mode creates or auto-merges
+a release PR. CI remains independent as decided in ADR 0002.
+
+Root changelogs and release notes use HoverKraft's configuration. The initial
+interface supports stable bare, v-prefixed and directory-scoped version tags.
+Existing release history must be consistent with committed versions. Older or
+equal plans, existing tags and concurrent branch updates stop preparation.
+
+Retries use the original tag without planning again. Already published npm bytes
+and GitHub assets remain protected. No additional release planner or npm runtime
+dependency is introduced by the Node.js workflow.
diff --git a/docs/adr/0004-ci-produces-release-artifacts.md b/docs/adr/0004-ci-produces-release-artifacts.md
new file mode 100644
index 0000000..46c0dec
--- /dev/null
+++ b/docs/adr/0004-ci-produces-release-artifacts.md
@@ -0,0 +1,49 @@
+# ADR 0004: CI produces the artifacts consumed by release
+
+- Status: accepted
+- Date: 2026-10-31
+- Partially supersedes: [ADR 0002](0002-separate-ci-from-release.md) and
+ [ADR 0003](0003-hoverkraft-release-actions.md)
+
+## Context
+
+ADR 0002 separated validation from publication but left compilation and packaging
+inside release. This duplicated build ownership and did not prove that CI checked
+the generated version commit. Artifacts from before version preparation can embed
+an old version, so simply reusing the preceding branch build is insufficient.
+
+## Decision
+
+Expose preparation and publication as separate reusable workflows. The caller
+connects preparation, its existing CI configuration, and publication through `needs`.
+Preparation retains HoverKraft's planner, npm/Lerna version application, atomic push
+and explicit dispatch at the resulting tag. It never builds the project.
+
+CI owns compilation, tests and optional packaging on that exact tagged commit. Add
+an optional package list input and an artifact list output to the existing CI
+workflow. Packaging runs only after all enabled checks succeed. Ordinary CI leaves
+packaging disabled. Consumers with a shared CI wrapper forward these two values
+instead of duplicating build and test settings.
+
+Publication consumes immutable CI tarball IDs from the same run and source SHA.
+Verify artifact metadata, tag versions and tarball manifests before npm publication.
+Keep HoverKraft draft creation, AI summaries, asset upload and final publication.
+Remove the release build helper and its configuration surface.
+
+## Consequences
+
+One caller serializes the complete pipeline; reusable workflow concurrency groups
+remain distinct. The publication job depends on successful CI. Artifact metadata
+checks alone cannot prove that tests passed, so that dependency is part of the caller
+contract. Cross-run lookup and polling are deliberately excluded.
+
+A failed-job rerun reuses successful CI artifacts, including successful matrix jobs
+from earlier attempts of the same run. A new dispatch at the original tag reruns CI.
+Expired artifacts fail explicitly. Existing npm bytes and GitHub assets retain the
+integrity and retry protections from ADR 0003. Documentation deploys from CI's build
+artifact after publication succeeds.
+
+The initial packaging path supports the existing default Ubuntu runner and restored
+build artifacts, not container-backed CI. This avoids promising path restoration
+across incompatible runner layouts. Manual and scheduled triggers and automatic
+Conventional Commit versions are unchanged.
diff --git a/docs/development/release-tests.md b/docs/development/release-tests.md
new file mode 100644
index 0000000..c36278b
--- /dev/null
+++ b/docs/development/release-tests.md
@@ -0,0 +1,30 @@
+# Validate release automation
+
+Install the test dependencies and run the release suite:
+
+```sh
+npm ci --prefix tests/release
+npm test --prefix tests/release
+```
+
+Artifact handoff tests check exact run and commit identity, package versions,
+missing and expired artifacts, partial matrix reruns, and tarball manifests.
+The suite uses temporary local Git repositories and offline npm commands. It
+executes npm and the installed Lerna with planned versions, checks dependent
+package and lockfile changes, and
+tests no-change behavior, tag collisions and concurrent branch pushes. A single
+package fixture applies a release plan, builds a CLI, packs it, installs
+the tarball and executes its entry point.
+
+Registry and GitHub responses are mocked for partial publication, integrity
+failures, draft lookup and staging missing assets for HoverKraft upload. Release
+plans and rendered notes are supplied as upstream action outputs; this suite does
+not duplicate HoverKraft's version calculation tests. Tests do not call
+OpenAI, publish packages or create remote releases. The suite runs in the shared
+CI workflow. The continuous-integration workflow test also enables packaging,
+downloads the returned raw artifact ID and compares its compiled file with the
+original CI build output. It does not publish a package.
+
+Run `make lint` for repository linting. Generate changed action and workflow
+readmes with the existing CI Dokumentor tool used by `release-actions.yml`; edit
+metadata rather than generated files. The user guide lives in `docs/usage/`.
diff --git a/docs/usage/custom-releases.md b/docs/usage/custom-releases.md
new file mode 100644
index 0000000..94d39ad
--- /dev/null
+++ b/docs/usage/custom-releases.md
@@ -0,0 +1,58 @@
+# Compose a custom release pipeline
+
+Use [the shared release workflows](releases.md) for single npm packages and
+fixed-version Lerna workspaces. For custom registries or packaging rules, compose
+the existing actions while keeping preparation, CI and publication separate.
+
+## Preparation
+
+Use HoverKraft [`release/plan`](https://github.com/hoverkraft-tech/ci-github-publish/tree/1.0.3/actions/release/plan)
+for version selection. Commit version, lockfile and changelog updates before CI
+builds the source, especially when compiled files embed the version. Keep the planned
+tag fixed throughout the pipeline. The [Node.js preparation action](../../actions/release/prepare/README.md)
+handles this for npm and fixed-version Lerna projects and dispatches the caller at the tag.
+
+## CI artifacts
+
+Run the [CI workflow](../../.github/workflows/continuous-integration.md) against the
+prepared commit. Its optional `packages` input delegates packaging to the
+[Package action](../../actions/package/README.md) after checks pass. It returns
+`package-artifacts` for publication and `build-artifact-id` for documentation deployment.
+
+If you own the packaging jobs, the Package action accepts a build artifact ID and
+package directory. It checks out the workflow's source ref, installs dependencies,
+restores build output, and runs `npm pack`. Start that workflow at the prepared tag;
+an earlier step checking out a different ref does not change Package's own checkout.
+Leave its `version` input empty when versions are already committed. Run any tarball
+smoke tests in CI before making artifacts available to publication.
+
+## Publication
+
+Keep publication dependent on successful CI. The [Publish action](../../actions/publish/README.md)
+consumes one CI tarball artifact ID and never packages the project. A dry run validates
+`npm publish` inputs, but does not prove registry authentication or trusted publishing.
+See its [authentication guide](../../actions/publish/README.md#registry-tokens-and-github-packages)
+for registries beyond npmjs.org.
+
+Use HoverKraft [`release/create`](https://github.com/hoverkraft-tech/ci-github-publish/tree/1.0.3/actions/release/create)
+to draft notes and optional AI summaries before npm publication. Pass the prepared
+tag and source SHA. Set `publish: "false"` until all packages and assets succeed.
+Use [`release/update`](https://github.com/hoverkraft-tech/ci-github-publish/tree/1.0.3/actions/release/update)
+to attach assets and publish the draft. Those actions expect ZIP artifacts for release
+assets; the Package action's raw `.tgz` must be wrapped with `upload-artifact` using
+its default archive mode.
+
+The [shared publication workflow](../../.github/workflows/release.md) already performs
+these steps for npmjs.org, including exact artifact identity checks, AI summaries and
+safe retries. It accepts only artifacts from CI in the same run and at the same tag.
+
+## Recovery
+
+npm publication across several packages cannot be atomic. Check exact package
+versions before retrying; published versions cannot be overwritten. Restore original
+published bytes for release assets, verify integrity and existing asset digests, and
+upload only missing assets. Do not delete a draft to undo an npm publication.
+
+The [release recovery guide](releases.md#run-and-resume-releases) describes this behavior
+for the shared workflow. Custom pipelines own equivalent recovery rules. Keep the
+original tag and source identity when finishing a partial release.
diff --git a/docs/usage/examples/reactionable-cli.yml b/docs/usage/examples/reactionable-cli.yml
new file mode 100644
index 0000000..8b53f52
--- /dev/null
+++ b/docs/usage/examples/reactionable-cli.yml
@@ -0,0 +1,87 @@
+# Replace with a published ci-github-nodejs commit containing these workflows.
+name: Release
+
+on:
+ workflow_dispatch:
+ schedule:
+ - cron: "25 8 * * 1"
+
+permissions: {}
+
+concurrency:
+ group: release-${{ github.repository }}
+ cancel-in-progress: false
+
+jobs:
+ prepare:
+ uses: hoverkraft-tech/ci-github-nodejs/.github/workflows/prepare-release.yml@
+ permissions:
+ actions: write
+ contents: write
+ pull-requests: read
+ with:
+ environment: github-pages
+
+ ci:
+ needs: prepare
+ if: needs.prepare.outputs.status == 'ready'
+ uses: hoverkraft-tech/ci-github-nodejs/.github/workflows/continuous-integration.yml@
+ permissions:
+ actions: read
+ contents: read
+ packages: read
+ pull-requests: write
+ security-events: write
+ id-token: write
+ with:
+ packages: ${{ needs.prepare.outputs.packages }}
+ build: |
+ {"commands":["build","build:doc"],"artifact":["dist","build"]}
+ test: '{"coverage":"codecov"}'
+
+ release:
+ needs: ci
+ uses: hoverkraft-tech/ci-github-nodejs/.github/workflows/release.yml@
+ permissions:
+ actions: read
+ contents: write
+ pull-requests: read
+ id-token: write
+ with:
+ package-artifacts: ${{ needs.ci.outputs.package-artifacts }}
+ environment: github-pages
+ ai-summary: true
+ secrets:
+ OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
+
+ pages:
+ name: Deploy documentation
+ needs: [ci, release]
+ if: needs.release.outputs.status == 'published'
+ runs-on: ubuntu-latest
+ permissions:
+ contents: read
+ pages: write
+ id-token: write
+ environment:
+ name: github-pages
+ url: ${{ steps.deployment.outputs.url }}
+ outputs:
+ url: ${{ steps.deployment.outputs.url }}
+ steps:
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
+ with:
+ persist-credentials: false
+ - id: deployment
+ uses: hoverkraft-tech/ci-github-publish/actions/deploy/github-pages@ea6682de88070c254dac619a6623a242a6d57cd3 # 1.0.3
+ with:
+ build-artifact-id: ${{ needs.ci.outputs.build-artifact-id }}
+ build-path: build/docs
+
+ deploy-checks:
+ needs: pages
+ uses: hoverkraft-tech/ci-github-publish/.github/workflows/deploy-checks.yml@ea6682de88070c254dac619a6623a242a6d57cd3 # 1.0.3
+ permissions:
+ contents: read
+ with:
+ url: ${{ needs.pages.outputs.url }}
diff --git a/docs/usage/examples/reactionable.yml b/docs/usage/examples/reactionable.yml
new file mode 100644
index 0000000..6740598
--- /dev/null
+++ b/docs/usage/examples/reactionable.yml
@@ -0,0 +1,80 @@
+# Replace with a published ci-github-nodejs commit containing these workflows.
+name: Release
+
+on:
+ workflow_dispatch:
+ schedule:
+ - cron: "25 8 * * 1"
+
+permissions: {}
+
+concurrency:
+ group: release-${{ github.repository }}
+ cancel-in-progress: false
+
+jobs:
+ prepare:
+ uses: hoverkraft-tech/ci-github-nodejs/.github/workflows/prepare-release.yml@
+ permissions:
+ actions: write
+ contents: write
+ pull-requests: read
+ with:
+ versioning: lerna
+ environment: github-pages
+
+ ci:
+ needs: prepare
+ if: needs.prepare.outputs.status == 'ready'
+ uses: hoverkraft-tech/ci-github-nodejs/.github/workflows/continuous-integration.yml@
+ permissions:
+ actions: read
+ contents: read
+ packages: read
+ pull-requests: write
+ security-events: write
+ id-token: write
+ with:
+ packages: ${{ needs.prepare.outputs.packages }}
+ build: |
+ {"commands":["build:ci","storybook:build","docs:build"],"artifact":["packages/**/lib","build","packages/**/docs"]}
+ test: '{"coverage":"codecov"}'
+
+ release:
+ needs: ci
+ uses: hoverkraft-tech/ci-github-nodejs/.github/workflows/release.yml@
+ permissions:
+ actions: read
+ contents: write
+ pull-requests: read
+ id-token: write
+ with:
+ package-artifacts: ${{ needs.ci.outputs.package-artifacts }}
+ environment: github-pages
+ ai-summary: true
+ secrets:
+ OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
+
+ pages:
+ name: Deploy documentation
+ needs: [ci, release]
+ if: needs.release.outputs.status == 'published'
+ runs-on: ubuntu-latest
+ permissions:
+ contents: read
+ pages: write
+ id-token: write
+ environment:
+ name: github-pages
+ url: ${{ steps.deployment.outputs.url }}
+ outputs:
+ url: ${{ steps.deployment.outputs.url }}
+ steps:
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
+ with:
+ persist-credentials: false
+ - id: deployment
+ uses: hoverkraft-tech/ci-github-publish/actions/deploy/github-pages@ea6682de88070c254dac619a6623a242a6d57cd3 # 1.0.3
+ with:
+ build-artifact-id: ${{ needs.ci.outputs.build-artifact-id }}
+ build-path: build/storybook
diff --git a/docs/usage/releases.md b/docs/usage/releases.md
new file mode 100644
index 0000000..a88503d
--- /dev/null
+++ b/docs/usage/releases.md
@@ -0,0 +1,152 @@
+# Release a single package or Lerna workspaces
+
+Connect three reusable workflows: **prepare → CI → publish**. The caller owns the
+manual and scheduled triggers. Consumers need no versioning or publication scripts.
+
+- [Prepare release](../../.github/workflows/prepare-release.md) uses HoverKraft's
+ Conventional Commit release plan, commits versions and changelogs, and atomically
+ pushes the version commit and tag. It dispatches the caller at that tag.
+- [Continuous integration](../../.github/workflows/continuous-integration.md) builds,
+ tests and packages the prepared commit. Use the same CI configuration as pull requests.
+- [Release](../../.github/workflows/release.md) consumes those CI tarballs, generates
+ release notes and an optional AI summary, publishes npm packages, and finalizes the
+ GitHub release. It does not build or pack the project.
+
+The tag run is essential: artifacts built before version preparation can contain the
+old version. All three workflows run against the prepared commit during publication.
+
+## Set up
+
+1. Keep the package's stable version and existing GitHub release history aligned.
+ HoverKraft selects the next version from that history and Conventional Commits.
+ A plan older than or equal to the committed version fails instead of guessing a
+ replacement. Configure `.github/release-config.yml` when needed; repository
+ configuration takes precedence over generated defaults.
+2. Configure [npm trusted publishing](../../actions/publish/README.md#npm-trusted-publishing)
+ for your repository, caller workflow filename and environment. Publish a new
+ package's first version before configuring its trusted publisher. Publication
+ uses GitHub-hosted runners with `id-token: write`.
+3. Permit the preparation identity to push release commits and tags under your branch
+ and tag rules. Preparation defaults to `GITHUB_TOKEN`; optionally pass
+ `github-token` to `prepare-release.yml`. The token does not bypass repository rules.
+4. Allow the chosen environment on the default branch and release tags. Set
+ `OPENAI_API_KEY` and pass it to publication when enabling `ai-summary`.
+5. Copy a caller example and replace `` with the same supported
+ `ci-github-nodejs` commit throughout:
+ - [Single npm package with documentation deployment](examples/reactionable-cli.yml)
+ - [Fixed-version Lerna workspaces with documentation deployment](examples/reactionable.yml)
+
+The minimal connection between the jobs is:
+
+```yaml
+jobs:
+ prepare:
+ uses: hoverkraft-tech/ci-github-nodejs/.github/workflows/prepare-release.yml@
+ permissions:
+ actions: write
+ contents: write
+ pull-requests: read
+
+ ci:
+ needs: prepare
+ if: needs.prepare.outputs.status == 'ready'
+ uses: hoverkraft-tech/ci-github-nodejs/.github/workflows/continuous-integration.yml@
+ permissions:
+ actions: read
+ contents: read
+ packages: read
+ pull-requests: write
+ security-events: write
+ id-token: write
+ with:
+ packages: ${{ needs.prepare.outputs.packages }}
+ build: '{"commands":["build"],"artifact":["dist"]}'
+
+ release:
+ needs: ci
+ uses: hoverkraft-tech/ci-github-nodejs/.github/workflows/release.yml@
+ permissions:
+ actions: read
+ contents: write
+ pull-requests: read
+ id-token: write
+ with:
+ package-artifacts: ${{ needs.ci.outputs.package-artifacts }}
+```
+
+Add `workflow_dispatch`, your schedule, `permissions: {}` and a caller concurrency
+group such as `release-${{ github.repository }}` with `cancel-in-progress: false`.
+Use a different group from either reusable workflow. This serializes the whole
+pipeline, including CI. If your repository already has a shared CI wrapper, forward
+its optional `packages` input and `package-artifacts` output instead of copying build
+and test settings into the release caller. Ordinary CI leaves `packages` empty.
+
+## Versioning and packaging
+
+Preparation defaults to `versioning: npm` for a single public package. npm applies
+the exact planned version to the manifest and lockfile without running version scripts.
+For fixed-version workspaces, set `versioning: lerna` on **prepare** and install
+Lerna in the project. Lerna applies the exact planned version, updates internal
+dependency ranges and lockfiles, and uses `--conventional-commits` for package
+changelogs. It does not select another version. Independent versions and prereleases
+are unsupported. The root `CHANGELOG.md` receives HoverKraft's rendered notes.
+
+Only public workspaces at the new version are packaged; unchanged packages can keep
+their previous versions. If Lerna reports no changed packages, preparation creates no
+commit, tag or publication run. If the default branch advances during preparation,
+the atomic push fails without publishing the new tag. Existing tags are never overwritten.
+
+Set matching `working-directory` values on all three workflows for nested projects.
+The planner supports bare stable tags, `v`-prefixed tags and directory-slug prefixes
+for nested projects. The committed version must match the selected tag.
+
+CI packaging requires `checks: true`, a build artifact, the default
+`runs-on: '["ubuntu-latest"]'`, and no container. Configure the build artifact to
+include the compiled package files and any documentation you deploy. Packaging runs
+after all enabled checks succeed, restores the build output and runs `npm pack`.
+Package lifecycle scripts therefore run in CI. Publication never installs project
+dependencies or invokes its build or packaging scripts.
+
+CI returns immutable tarball IDs. Publication verifies that each artifact belongs to
+this run and commit, then checks the tarball's package name and version before npm
+publication. Cross-run artifact reuse is unsupported. A caller must keep `release`
+dependent on successful CI; artifact metadata alone is not proof that checks passed.
+
+## Run and resume releases
+
+Run the caller from the default branch or wait for its schedule. Preparation reports:
+
+| Status | Meaning |
+| ------------ | --------------------------------------------------- |
+| `no-changes` | No release needed; CI and publication are skipped. |
+| `dispatched` | Follow the new caller run at the prepared tag. |
+| `released` | This version already has a public GitHub release. |
+| `ready` | This tag run can start CI, followed by publication. |
+
+Publication reports `published` only after all npm packages and release assets
+succeed. Preparation success alone does not mean publication succeeded.
+
+AI generation runs before npm publication. The draft becomes public only after every
+package and asset succeeds. Review AI summaries for accuracy; published releases
+keep their notes on retries. Asset upload and final publication use HoverKraft
+`release/update`.
+
+For a failed publication job, rerun failed jobs: successful CI tarballs from earlier
+attempts of the same run are reused without rebuilding. Expired or deleted artifacts
+fail rather than falling back to another run. To run CI again and resume the same
+release, dispatch the **caller** at its original tag:
+
+```sh
+gh workflow run release.yml --ref v1.2.3
+```
+
+A tag run never plans another version. Already published npm versions are skipped,
+and their original tarballs are restored with SHA-512 verification for GitHub assets.
+Existing assets are reused only when SHA-256 digests match. Conflicts or unavailable
+digests fail instead of replacing assets. Partial npm publication remains possible;
+registry errors stop recovery, and only an absent version permits publication.
+If source needs changing, make a new commit and release. Do not move a release tag.
+
+For documentation deployment, require `release.outputs.status == 'published'` and
+consume **CI's** `build-artifact-id`. The publication workflow returns `status`,
+`tag` and `release-url`; documentation remains an independent caller job.
diff --git a/tests/release/artifacts.test.js b/tests/release/artifacts.test.js
new file mode 100644
index 0000000..59dd627
--- /dev/null
+++ b/tests/release/artifacts.test.js
@@ -0,0 +1,220 @@
+const assert = require("node:assert/strict");
+const { createHash } = require("node:crypto");
+const fs = require("node:fs");
+const os = require("node:os");
+const path = require("node:path");
+const { test } = require("node:test");
+const {
+ ReleaseArtifacts,
+} = require("../../actions/release/ReleaseArtifacts.js");
+const restorePackage = (inputs, fetchPackage) =>
+ new ReleaseArtifacts(fetchPackage).restorePackage(inputs);
+
+function directory(t) {
+ const root = fs.mkdtempSync(path.join(os.tmpdir(), "nodejs-release-assets-"));
+ t.after(() => fs.rmSync(root, { recursive: true, force: true }));
+ return root;
+}
+
+test("finds drafts when the release-by-tag endpoint does not return them", async () => {
+ const draft = { id: 1, tag_name: "v1.2.0", draft: true };
+ const github = {
+ rest: {
+ repos: {
+ getReleaseByTag: async () => {
+ throw Object.assign(new Error("Not found"), { status: 404 });
+ },
+ },
+ },
+ paginate: async () => [draft],
+ };
+ assert.equal(await ReleaseArtifacts.findRelease(github, {}, "v1.2.0"), draft);
+ assert.equal(
+ await ReleaseArtifacts.findRelease(github, {}, "v1.3.0"),
+ undefined,
+ );
+ github.rest.repos.getReleaseByTag = async () => {
+ throw Object.assign(new Error("Forbidden"), { status: 403 });
+ };
+ await assert.rejects(
+ ReleaseArtifacts.findRelease(github, {}, "v1.2.0"),
+ /Forbidden/,
+ );
+});
+
+function registryFixture(t) {
+ const root = directory(t);
+ const tarballPath = path.join(root, "package.tgz");
+ fs.writeFileSync(tarballPath, "new build");
+ const published = Buffer.from("the exact bytes published to npm");
+ const metadata = {
+ name: "@example/core",
+ version: "1.2.0",
+ dist: {
+ tarball: "https://registry.npmjs.org/@example/core/-/core-1.2.0.tgz",
+ integrity: `sha512-${createHash("sha512").update(published).digest("base64")}`,
+ },
+ };
+ return {
+ tarballPath,
+ published,
+ metadata,
+ inputs: { name: metadata.name, version: metadata.version, tarballPath },
+ };
+}
+
+test("allows publication only when the npm version is absent", async (t) => {
+ const f = registryFixture(t);
+ assert.equal(
+ await restorePackage(
+ f.inputs,
+ async () => new Response(null, { status: 404 }),
+ ),
+ false,
+ );
+ assert.equal(fs.readFileSync(f.tarballPath, "utf8"), "new build");
+ await assert.rejects(
+ restorePackage(f.inputs, async () => new Response(null, { status: 503 })),
+ /HTTP 503/,
+ );
+});
+
+test("recovers the original npm tarball for an already published version", async (t) => {
+ const f = registryFixture(t);
+ const requested = [];
+ const published = await restorePackage(f.inputs, async (url) => {
+ requested.push(url);
+ return requested.length === 1
+ ? Response.json(f.metadata)
+ : new Response(f.published);
+ });
+ assert.equal(published, true);
+ assert.deepEqual(fs.readFileSync(f.tarballPath), f.published);
+ assert.deepEqual(requested, [
+ "https://registry.npmjs.org/%40example%2Fcore/1.2.0",
+ f.metadata.dist.tarball,
+ ]);
+});
+
+test("rejects corrupted tarballs without replacing the package file", async (t) => {
+ const f = registryFixture(t);
+ let requests = 0;
+ await assert.rejects(
+ restorePackage(f.inputs, async () =>
+ ++requests === 1 ? Response.json(f.metadata) : new Response("corrupt"),
+ ),
+ /integrity verification/,
+ );
+ assert.equal(fs.readFileSync(f.tarballPath, "utf8"), "new build");
+});
+
+test("rejects unexpected registry identities, download hosts, and failed downloads", async (t) => {
+ const f = registryFixture(t);
+ await assert.rejects(
+ restorePackage(f.inputs, async () =>
+ Response.json({ ...f.metadata, version: "9.0.0" }),
+ ),
+ /unexpected package version/,
+ );
+ await assert.rejects(
+ restorePackage(f.inputs, async () =>
+ Response.json({
+ ...f.metadata,
+ dist: { tarball: "https://example.invalid/package.tgz" },
+ }),
+ ),
+ /npm registry/,
+ );
+ let requests = 0;
+ await assert.rejects(
+ restorePackage(f.inputs, async () =>
+ ++requests === 1
+ ? Response.json(f.metadata)
+ : new Response(null, { status: 503 }),
+ ),
+ /download failed/,
+ );
+});
+
+function assetsFixture(t) {
+ const root = directory(t);
+ const data = Buffer.from("published package");
+ fs.writeFileSync(path.join(root, "example-core-1.2.0.tgz"), data);
+ const release = { id: 1, draft: true };
+ const assets = [];
+ const github = {
+ rest: {
+ repos: {
+ getReleaseByTag: async () => ({ data: release }),
+ },
+ },
+ paginate: async () => assets,
+ };
+ return {
+ release,
+ assets,
+ data,
+ args: {
+ github,
+ repo: { owner: "example", repo: "project" },
+ tag: "v1.2.0",
+ directory: root,
+ },
+ };
+}
+
+test("stages only missing package bytes for HoverKraft upload and skips identical assets", async (t) => {
+ const f = assetsFixture(t);
+ const result = await new ReleaseArtifacts().prepareAssets(f.args);
+ assert.equal(result.hasAssets, true);
+ assert.deepEqual(
+ fs.readFileSync(
+ path.join(result.pendingDirectory, "example-core-1.2.0.tgz"),
+ ),
+ f.data,
+ );
+ f.assets.push({
+ name: "example-core-1.2.0.tgz",
+ digest: `sha256:${createHash("sha256").update(f.data).digest("hex")}`,
+ });
+ const retry = await new ReleaseArtifacts().prepareAssets(f.args);
+ assert.equal(retry.hasAssets, false);
+ assert.deepEqual(fs.readdirSync(retry.pendingDirectory), []);
+ f.release.draft = false;
+ assert.equal(
+ (await new ReleaseArtifacts().prepareAssets(f.args)).hasAssets,
+ false,
+ );
+});
+
+test("does not overwrite mismatched assets or modify an incomplete published release", async (t) => {
+ const f = assetsFixture(t);
+ f.assets.push({ name: "example-core-1.2.0.tgz", digest: "sha256:different" });
+ await assert.rejects(
+ new ReleaseArtifacts().prepareAssets(f.args),
+ /different or unavailable digest/,
+ );
+ f.assets.length = 0;
+ f.release.draft = false;
+ await assert.rejects(
+ new ReleaseArtifacts().prepareAssets(f.args),
+ /missing expected asset/,
+ );
+});
+
+test("partial asset recovery passes only missing tarballs to the uploader", async (t) => {
+ const f = assetsFixture(t);
+ const name = "example-cli-1.2.0.tgz";
+ fs.writeFileSync(path.join(f.args.directory, name), "second package");
+ f.assets.push({
+ name: "example-core-1.2.0.tgz",
+ digest: `sha256:${createHash("sha256").update(f.data).digest("hex")}`,
+ });
+ const result = await new ReleaseArtifacts().prepareAssets(f.args);
+ assert.equal(result.hasAssets, true);
+ assert.deepEqual(fs.readdirSync(result.pendingDirectory), [name]);
+ assert.equal(
+ fs.readFileSync(path.join(result.pendingDirectory, name), "utf8"),
+ "second package",
+ );
+});
diff --git a/tests/release/package-artifacts.test.js b/tests/release/package-artifacts.test.js
new file mode 100644
index 0000000..67f8511
--- /dev/null
+++ b/tests/release/package-artifacts.test.js
@@ -0,0 +1,160 @@
+const assert = require("node:assert/strict");
+const { test } = require("node:test");
+const fs = require("node:fs");
+const os = require("node:os");
+const path = require("node:path");
+const { execFileSync } = require("node:child_process");
+const {
+ PackageArtifacts,
+} = require("../../actions/package-artifacts/PackageArtifacts.js");
+const {
+ ReleaseArtifacts,
+} = require("../../actions/release/ReleaseArtifacts.js");
+
+const context = {
+ repo: { owner: "example", repo: "project" },
+ runId: 42,
+ sha: "prepared-commit",
+};
+const item = {
+ name: "@example/cli",
+ slug: "example-cli",
+ version: "1.2.3",
+ directory: ".",
+};
+const artifact = (id, attempt = 1, overrides = {}) => ({
+ id,
+ name: `npm-example-cli-42-${attempt}.tgz`,
+ expired: false,
+ workflow_run: { id: 42, head_sha: context.sha },
+ ...overrides,
+});
+const collector = (artifacts) =>
+ new PackageArtifacts({
+ context,
+ github: {
+ paginate: async () => artifacts,
+ rest: {
+ actions: {
+ listWorkflowRunArtifacts() {},
+ getArtifact: async ({ artifact_id }) => ({
+ data: artifacts.find((entry) => entry.id === artifact_id),
+ }),
+ },
+ },
+ },
+ });
+
+test("collects exact CI artifact IDs and filenames for publication", async () => {
+ const result = await collector([artifact(10)]).collect(
+ JSON.stringify([item]),
+ );
+ assert.deepEqual(result, [
+ { ...item, "artifact-id": 10, "artifact-name": "npm-example-cli-42-1.tgz" },
+ ]);
+ assert.deepEqual(
+ await collector([artifact(10)]).verify(JSON.stringify(result), "1.2.3"),
+ result,
+ );
+});
+
+test("failed-job reruns combine successful packages from different attempts", async () => {
+ const other = {
+ ...item,
+ name: "other",
+ slug: "other",
+ directory: "packages/other",
+ };
+ const result = await collector([
+ artifact(10),
+ artifact(20, 2),
+ artifact(30, 1, { name: "npm-other-42-1.tgz" }),
+ ]).collect(JSON.stringify([item, other]));
+ assert.deepEqual(
+ result.map((entry) => entry["artifact-id"]),
+ [20, 30],
+ );
+});
+
+test("fails when any package is missing, expired or from another run", async () => {
+ for (const artifacts of [
+ [],
+ [artifact(10, 1, { expired: true })],
+ [artifact(10, 1, { workflow_run: { id: 41, head_sha: context.sha } })],
+ [artifact(10, 1, { workflow_run: undefined })],
+ ]) {
+ await assert.rejects(
+ collector(artifacts).collect(JSON.stringify([item])),
+ /CI tarball|CI artifact/,
+ );
+ }
+});
+
+test("rejects ambiguous names, unsafe paths, invalid versions and invalid package lists", () => {
+ const service = collector([]);
+ for (const packages of [
+ [],
+ {},
+ [null],
+ [item, item],
+ [{ ...item, slug: "wrong" }],
+ [{ ...item, name: "../bad" }],
+ [{ ...item, directory: "../outside" }],
+ [{ ...item, directory: "/tmp" }],
+ [{ ...item, version: "1.2.3-beta" }],
+ ]) {
+ assert.throws(
+ () => service.parse(JSON.stringify(packages)),
+ /Expected|unique/,
+ );
+ }
+});
+
+test("publication rejects changed artifact IDs, filenames, source commits and release versions", async () => {
+ const service = collector([artifact(10)]);
+ const [valid] = await service.collect(JSON.stringify([item]));
+ for (const entry of [
+ { ...valid, version: "1.2.2" },
+ { ...valid, "artifact-id": "10" },
+ { ...valid, "artifact-name": "other.tgz" },
+ ]) {
+ await assert.rejects(
+ service.verify(JSON.stringify([entry]), "1.2.3"),
+ /version|artifact/,
+ );
+ }
+ await assert.rejects(
+ collector([
+ artifact(10, 1, { workflow_run: { id: 42, head_sha: "old" } }),
+ ]).verify(JSON.stringify([valid]), "1.2.3"),
+ /prepared commit/,
+ );
+});
+
+test("checks the packaged manifest without executing package lifecycle scripts", (t) => {
+ const directory = fs.mkdtempSync(path.join(os.tmpdir(), "ci-tarball-"));
+ t.after(() => fs.rmSync(directory, { recursive: true, force: true }));
+ fs.mkdirSync(path.join(directory, "package"));
+ const tarballPath = path.join(directory, "package.tgz");
+ for (const manifest of [
+ { name: item.name, version: item.version },
+ { name: "wrong", version: item.version },
+ { name: item.name, version: "1.2.2" },
+ { name: item.name, version: item.version, private: true },
+ ]) {
+ fs.writeFileSync(
+ path.join(directory, "package/package.json"),
+ JSON.stringify({ ...manifest, scripts: { prepublishOnly: "exit 1" } }),
+ );
+ execFileSync("tar", ["-czf", tarballPath, "package"], { cwd: directory });
+ const verify = () =>
+ ReleaseArtifacts.verifyTarball({ ...item, tarballPath });
+ if (
+ manifest.name === item.name &&
+ manifest.version === item.version &&
+ !manifest.private
+ )
+ assert.doesNotThrow(verify);
+ else assert.throws(verify, /expected public package/);
+ }
+});
diff --git a/tests/release/package-lock.json b/tests/release/package-lock.json
new file mode 100644
index 0000000..90f9ebb
--- /dev/null
+++ b/tests/release/package-lock.json
@@ -0,0 +1,5499 @@
+{
+ "name": "nodejs-release-tests",
+ "lockfileVersion": 3,
+ "requires": true,
+ "packages": {
+ "": {
+ "name": "nodejs-release-tests",
+ "devDependencies": {
+ "lerna": "10.1.1"
+ }
+ },
+ "node_modules/@babel/code-frame": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.7.tgz",
+ "integrity": "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-validator-identifier": "^7.29.7",
+ "js-tokens": "^4.0.0",
+ "picocolors": "^1.1.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-validator-identifier": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz",
+ "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@clack/core": {
+ "version": "1.4.3",
+ "resolved": "https://registry.npmjs.org/@clack/core/-/core-1.4.3.tgz",
+ "integrity": "sha512-/kr3UWNtdJfxZtPgDqUOmG2pvwlmcLGheex5yiZKdwbzZJxhV+HMNR9QNmyY5cGwTNV6LrR7Jtp+KjhUAP1qBQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "fast-wrap-ansi": "^0.2.0",
+ "sisteransi": "^1.0.5"
+ },
+ "engines": {
+ "node": ">= 20.12.0"
+ }
+ },
+ "node_modules/@clack/prompts": {
+ "version": "1.7.0",
+ "resolved": "https://registry.npmjs.org/@clack/prompts/-/prompts-1.7.0.tgz",
+ "integrity": "sha512-y7/yvZ2TPAnR9+jnc00klvNNLkJiXFFrQA/hlLCcxA9a2A4zQIOimyFQ9XfwYKiGD1fb5GY8vbKIIgO8d5Tb2A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@clack/core": "1.4.3",
+ "fast-string-width": "^3.0.2",
+ "fast-wrap-ansi": "^0.2.0",
+ "sisteransi": "^1.0.5"
+ },
+ "engines": {
+ "node": ">= 20.12.0"
+ }
+ },
+ "node_modules/@conventional-changelog/template": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/@conventional-changelog/template/-/template-1.4.0.tgz",
+ "integrity": "sha512-aalGyl7dbB5PArRebDIX43ZvBlXrYm9uWzGJ26t+4SzJVPsOuvfILGGbw5X4yX7i50YEmJ8zvbiWnqH/AAnZqg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=22"
+ }
+ },
+ "node_modules/@emnapi/core": {
+ "version": "1.4.5",
+ "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.4.5.tgz",
+ "integrity": "sha512-XsLw1dEOpkSX/WucdqUhPWP7hDxSvZiY+fsUC14h+FtQ2Ifni4znbBt8punRX+Uj2JG/uDb8nEHVKvrVlvdZ5Q==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@emnapi/wasi-threads": "1.0.4",
+ "tslib": "^2.4.0"
+ }
+ },
+ "node_modules/@emnapi/runtime": {
+ "version": "1.4.5",
+ "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.4.5.tgz",
+ "integrity": "sha512-++LApOtY0pEEz1zrd9vy1/zXVaVJJ/EbAF3u0fXIzPJEDtnITsBGbbK0EkM72amhl/R5b+5xx0Y/QhcVOpuulg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "tslib": "^2.4.0"
+ }
+ },
+ "node_modules/@emnapi/wasi-threads": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.0.4.tgz",
+ "integrity": "sha512-PJR+bOmMOPH8AtcTGAyYNiuJ3/Fcoj2XN/gBEWzDIKh254XO+mM9XoXHk5GNEhodxeMznbg7BlRojVbKN+gC6g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "tslib": "^2.4.0"
+ }
+ },
+ "node_modules/@gar/promise-retry": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/@gar/promise-retry/-/promise-retry-1.0.3.tgz",
+ "integrity": "sha512-GmzA9ckNokPypTg10pgpeHNQe7ph+iIKKmhKu3Ob9ANkswreCx7R3cKmY781K8QK3AqVL3xVh9A42JvIAbkkSA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "^20.17.0 || >=22.9.0"
+ }
+ },
+ "node_modules/@inquirer/ansi": {
+ "version": "2.0.10",
+ "resolved": "https://registry.npmjs.org/@inquirer/ansi/-/ansi-2.0.10.tgz",
+ "integrity": "sha512-dwrc+1aqVZpHNkNDswXGtn1typ+Pxpo5FHZRyBw1le7onEJUkPUkYOY1FIFC1LvFMYUqqLuWBwElhAmencL7MQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=23.5.0 || ^22.13.0 || ^20.17.0"
+ }
+ },
+ "node_modules/@inquirer/checkbox": {
+ "version": "5.2.8",
+ "resolved": "https://registry.npmjs.org/@inquirer/checkbox/-/checkbox-5.2.8.tgz",
+ "integrity": "sha512-NY/S1EalQhlonqhwwsarrcnkH7s9ByQuvjWYdk1jB2Gb9EPQJjKkhCTWjM3yQ0UpHaLm1XbIL89b+32G8rhO5w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@inquirer/ansi": "^2.0.10",
+ "@inquirer/core": "^12.0.6",
+ "@inquirer/figures": "^2.0.10",
+ "@inquirer/type": "4.2.1"
+ },
+ "engines": {
+ "node": ">=23.5.0 || ^22.13.0 || ^20.17.0"
+ },
+ "peerDependencies": {
+ "@types/node": ">=18"
+ },
+ "peerDependenciesMeta": {
+ "@types/node": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@inquirer/checkbox/node_modules/@inquirer/type": {
+ "version": "4.2.1",
+ "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-4.2.1.tgz",
+ "integrity": "sha512-lDkPsnv5M5CcYB2T1qTc3dobNTPkVr4DU3Ic2Q6SW8/qVRHgvzdRdmVZ6YqG9Ag1aJTeMsLU0s0WPRh3CZWDQQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=23.5.0 || ^22.13.0 || ^20.17.0"
+ },
+ "peerDependencies": {
+ "@types/node": ">=18"
+ },
+ "peerDependenciesMeta": {
+ "@types/node": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@inquirer/confirm": {
+ "version": "6.3.5",
+ "resolved": "https://registry.npmjs.org/@inquirer/confirm/-/confirm-6.3.5.tgz",
+ "integrity": "sha512-BJ59BOyURiZiAxdr9AuRu38/k+rV+DcTIM2fUF/c/BXrab6H8zMZTTOl3LgkSJH96Xob2vOJxDiBkHiz32Xx2w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@inquirer/core": "^12.0.6",
+ "@inquirer/type": "4.2.1"
+ },
+ "engines": {
+ "node": ">=23.5.0 || ^22.13.0 || ^20.17.0"
+ },
+ "peerDependencies": {
+ "@types/node": ">=18"
+ },
+ "peerDependenciesMeta": {
+ "@types/node": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@inquirer/confirm/node_modules/@inquirer/type": {
+ "version": "4.2.1",
+ "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-4.2.1.tgz",
+ "integrity": "sha512-lDkPsnv5M5CcYB2T1qTc3dobNTPkVr4DU3Ic2Q6SW8/qVRHgvzdRdmVZ6YqG9Ag1aJTeMsLU0s0WPRh3CZWDQQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=23.5.0 || ^22.13.0 || ^20.17.0"
+ },
+ "peerDependencies": {
+ "@types/node": ">=18"
+ },
+ "peerDependenciesMeta": {
+ "@types/node": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@inquirer/core": {
+ "version": "12.0.6",
+ "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-12.0.6.tgz",
+ "integrity": "sha512-5yxn2LsJ8Tu4ei2a+yNkmFRhM/cb+JMEsEs/AW6CCOnBnpMy4IjYiPMFyHtYq8weOmlTyqqCx40y0DsD7OsEPw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@inquirer/ansi": "^2.0.10",
+ "@inquirer/figures": "^2.0.10",
+ "@inquirer/type": "4.2.1",
+ "cli-width": "^4.1.0",
+ "fast-wrap-ansi": "^0.2.0",
+ "mute-stream": "^3.0.0",
+ "signal-exit": "^4.1.0"
+ },
+ "engines": {
+ "node": ">=23.5.0 || ^22.13.0 || ^20.17.0"
+ },
+ "peerDependencies": {
+ "@types/node": ">=18"
+ },
+ "peerDependenciesMeta": {
+ "@types/node": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@inquirer/core/node_modules/@inquirer/type": {
+ "version": "4.2.1",
+ "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-4.2.1.tgz",
+ "integrity": "sha512-lDkPsnv5M5CcYB2T1qTc3dobNTPkVr4DU3Ic2Q6SW8/qVRHgvzdRdmVZ6YqG9Ag1aJTeMsLU0s0WPRh3CZWDQQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=23.5.0 || ^22.13.0 || ^20.17.0"
+ },
+ "peerDependencies": {
+ "@types/node": ">=18"
+ },
+ "peerDependenciesMeta": {
+ "@types/node": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@inquirer/editor": {
+ "version": "5.3.6",
+ "resolved": "https://registry.npmjs.org/@inquirer/editor/-/editor-5.3.6.tgz",
+ "integrity": "sha512-Z5SOeRC5VNkINfKN4rY8BSaYKb3GYi8iSEqZZRqogsE2GhBBToQ0Xw25SbI+4bcatLzU009mZ5d9EuJNiJuUCg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@inquirer/core": "^12.0.6",
+ "@inquirer/external-editor": "^3.0.7",
+ "@inquirer/type": "4.2.1"
+ },
+ "engines": {
+ "node": ">=23.5.0 || ^22.13.0 || ^20.17.0"
+ },
+ "peerDependencies": {
+ "@types/node": ">=18"
+ },
+ "peerDependenciesMeta": {
+ "@types/node": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@inquirer/editor/node_modules/@inquirer/type": {
+ "version": "4.2.1",
+ "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-4.2.1.tgz",
+ "integrity": "sha512-lDkPsnv5M5CcYB2T1qTc3dobNTPkVr4DU3Ic2Q6SW8/qVRHgvzdRdmVZ6YqG9Ag1aJTeMsLU0s0WPRh3CZWDQQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=23.5.0 || ^22.13.0 || ^20.17.0"
+ },
+ "peerDependencies": {
+ "@types/node": ">=18"
+ },
+ "peerDependenciesMeta": {
+ "@types/node": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@inquirer/expand": {
+ "version": "5.1.8",
+ "resolved": "https://registry.npmjs.org/@inquirer/expand/-/expand-5.1.8.tgz",
+ "integrity": "sha512-dMEnTkpLqzM/sbILwL7QJgx9iX5hoEM8+bh6shgwd9mYJamdOnth7y2mMaFd08Glj9AXEFKllWcGYyBqnJsHrA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@inquirer/core": "^12.0.6",
+ "@inquirer/type": "4.2.1"
+ },
+ "engines": {
+ "node": ">=23.5.0 || ^22.13.0 || ^20.17.0"
+ },
+ "peerDependencies": {
+ "@types/node": ">=18"
+ },
+ "peerDependenciesMeta": {
+ "@types/node": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@inquirer/expand/node_modules/@inquirer/type": {
+ "version": "4.2.1",
+ "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-4.2.1.tgz",
+ "integrity": "sha512-lDkPsnv5M5CcYB2T1qTc3dobNTPkVr4DU3Ic2Q6SW8/qVRHgvzdRdmVZ6YqG9Ag1aJTeMsLU0s0WPRh3CZWDQQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=23.5.0 || ^22.13.0 || ^20.17.0"
+ },
+ "peerDependencies": {
+ "@types/node": ">=18"
+ },
+ "peerDependenciesMeta": {
+ "@types/node": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@inquirer/external-editor": {
+ "version": "3.0.7",
+ "resolved": "https://registry.npmjs.org/@inquirer/external-editor/-/external-editor-3.0.7.tgz",
+ "integrity": "sha512-enNqTJpojgISCG+a5acjnfJ02hcRTFUBVm8uXiCY40PRPZtSzFnNLskOTU+kDUUEODYma90syxuea1rRtUFh0Q==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "chardet": "^2.1.1",
+ "iconv-lite": "^0.7.2"
+ },
+ "engines": {
+ "node": ">=23.5.0 || ^22.13.0 || ^20.17.0"
+ },
+ "peerDependencies": {
+ "@types/node": ">=18"
+ },
+ "peerDependenciesMeta": {
+ "@types/node": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@inquirer/figures": {
+ "version": "2.0.10",
+ "resolved": "https://registry.npmjs.org/@inquirer/figures/-/figures-2.0.10.tgz",
+ "integrity": "sha512-51elrUJV3jZpvD0ygz8+U10Kc6+Lzqln+/tYmnbhy6jo5oXpE6hMCcv+OTBC0enwJXsb3JIuT3VtEinRNCSK2A==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=23.5.0 || ^22.13.0 || ^20.17.0"
+ }
+ },
+ "node_modules/@inquirer/input": {
+ "version": "5.1.9",
+ "resolved": "https://registry.npmjs.org/@inquirer/input/-/input-5.1.9.tgz",
+ "integrity": "sha512-2Vd5T7lTxfgJMpAd3aOu6bQpbUnCU7tBgvTQIZkP/7juJzmRmTM2t5XfOCuirFduWLTSJI/WZp32Cq1E01TVeg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@inquirer/core": "^12.0.6",
+ "@inquirer/type": "4.2.1"
+ },
+ "engines": {
+ "node": ">=23.5.0 || ^22.13.0 || ^20.17.0"
+ },
+ "peerDependencies": {
+ "@types/node": ">=18"
+ },
+ "peerDependenciesMeta": {
+ "@types/node": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@inquirer/input/node_modules/@inquirer/type": {
+ "version": "4.2.1",
+ "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-4.2.1.tgz",
+ "integrity": "sha512-lDkPsnv5M5CcYB2T1qTc3dobNTPkVr4DU3Ic2Q6SW8/qVRHgvzdRdmVZ6YqG9Ag1aJTeMsLU0s0WPRh3CZWDQQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=23.5.0 || ^22.13.0 || ^20.17.0"
+ },
+ "peerDependencies": {
+ "@types/node": ">=18"
+ },
+ "peerDependenciesMeta": {
+ "@types/node": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@inquirer/number": {
+ "version": "4.2.6",
+ "resolved": "https://registry.npmjs.org/@inquirer/number/-/number-4.2.6.tgz",
+ "integrity": "sha512-22LnGGCDm1M/pKXxxF8n6ppr/1IztdsxqeqeBRUMTTNnJTkjIBiAkewiDM4u/gjtazj/FvZS+nk9AbO/vEcBFQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@inquirer/core": "^12.0.6",
+ "@inquirer/type": "4.2.1"
+ },
+ "engines": {
+ "node": ">=23.5.0 || ^22.13.0 || ^20.17.0"
+ },
+ "peerDependencies": {
+ "@types/node": ">=18"
+ },
+ "peerDependenciesMeta": {
+ "@types/node": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@inquirer/number/node_modules/@inquirer/type": {
+ "version": "4.2.1",
+ "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-4.2.1.tgz",
+ "integrity": "sha512-lDkPsnv5M5CcYB2T1qTc3dobNTPkVr4DU3Ic2Q6SW8/qVRHgvzdRdmVZ6YqG9Ag1aJTeMsLU0s0WPRh3CZWDQQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=23.5.0 || ^22.13.0 || ^20.17.0"
+ },
+ "peerDependencies": {
+ "@types/node": ">=18"
+ },
+ "peerDependenciesMeta": {
+ "@types/node": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@inquirer/password": {
+ "version": "5.2.5",
+ "resolved": "https://registry.npmjs.org/@inquirer/password/-/password-5.2.5.tgz",
+ "integrity": "sha512-0v0wLQA4uhWbybmdH6oPl7ooxCiymNylkvi2gCSc+mA5ZQB6QoJLVhoHq12T82lhozpp9fpMJnJkC1nJrU/A+A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@inquirer/ansi": "^2.0.10",
+ "@inquirer/core": "^12.0.6",
+ "@inquirer/type": "4.2.1"
+ },
+ "engines": {
+ "node": ">=23.5.0 || ^22.13.0 || ^20.17.0"
+ },
+ "peerDependencies": {
+ "@types/node": ">=18"
+ },
+ "peerDependenciesMeta": {
+ "@types/node": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@inquirer/password/node_modules/@inquirer/type": {
+ "version": "4.2.1",
+ "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-4.2.1.tgz",
+ "integrity": "sha512-lDkPsnv5M5CcYB2T1qTc3dobNTPkVr4DU3Ic2Q6SW8/qVRHgvzdRdmVZ6YqG9Ag1aJTeMsLU0s0WPRh3CZWDQQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=23.5.0 || ^22.13.0 || ^20.17.0"
+ },
+ "peerDependencies": {
+ "@types/node": ">=18"
+ },
+ "peerDependenciesMeta": {
+ "@types/node": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@inquirer/prompts": {
+ "version": "8.7.5",
+ "resolved": "https://registry.npmjs.org/@inquirer/prompts/-/prompts-8.7.5.tgz",
+ "integrity": "sha512-l/IWwC+QhOyXgxkZloOh+n5quGzc1m5ZawyzBmoizCZaxbJeLRdS3pStoqg/JVInJRXaG5aHMhjK6H6oYiBC9A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@inquirer/checkbox": "^5.2.8",
+ "@inquirer/confirm": "^6.3.5",
+ "@inquirer/editor": "^5.3.6",
+ "@inquirer/expand": "^5.1.8",
+ "@inquirer/input": "^5.1.9",
+ "@inquirer/number": "^4.2.6",
+ "@inquirer/password": "^5.2.5",
+ "@inquirer/rawlist": "^5.3.8",
+ "@inquirer/search": "^4.3.6",
+ "@inquirer/select": "^5.2.8"
+ },
+ "engines": {
+ "node": ">=23.5.0 || ^22.13.0 || ^20.17.0"
+ },
+ "peerDependencies": {
+ "@types/node": ">=18"
+ },
+ "peerDependenciesMeta": {
+ "@types/node": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@inquirer/rawlist": {
+ "version": "5.3.8",
+ "resolved": "https://registry.npmjs.org/@inquirer/rawlist/-/rawlist-5.3.8.tgz",
+ "integrity": "sha512-h+6Y4pPvYvuRbksn1kIBdD9tCYD+E468W5sIcVfLmoLP5IasnY0r33N+r+46ej/P8b2PCREjyKR+MnnfPGdTzg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@inquirer/core": "^12.0.6",
+ "@inquirer/type": "4.2.1"
+ },
+ "engines": {
+ "node": ">=23.5.0 || ^22.13.0 || ^20.17.0"
+ },
+ "peerDependencies": {
+ "@types/node": ">=18"
+ },
+ "peerDependenciesMeta": {
+ "@types/node": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@inquirer/rawlist/node_modules/@inquirer/type": {
+ "version": "4.2.1",
+ "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-4.2.1.tgz",
+ "integrity": "sha512-lDkPsnv5M5CcYB2T1qTc3dobNTPkVr4DU3Ic2Q6SW8/qVRHgvzdRdmVZ6YqG9Ag1aJTeMsLU0s0WPRh3CZWDQQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=23.5.0 || ^22.13.0 || ^20.17.0"
+ },
+ "peerDependencies": {
+ "@types/node": ">=18"
+ },
+ "peerDependenciesMeta": {
+ "@types/node": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@inquirer/search": {
+ "version": "4.3.6",
+ "resolved": "https://registry.npmjs.org/@inquirer/search/-/search-4.3.6.tgz",
+ "integrity": "sha512-JZj9ttkIvuaFQIc2oxsyqC1ad05WL02ku6W/INVKTCzNaVq1KkhP3AfTRC0m7OWlKZyw+EWwPBFZfYiG9jF6Yw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@inquirer/core": "^12.0.6",
+ "@inquirer/figures": "^2.0.10",
+ "@inquirer/type": "4.2.1"
+ },
+ "engines": {
+ "node": ">=23.5.0 || ^22.13.0 || ^20.17.0"
+ },
+ "peerDependencies": {
+ "@types/node": ">=18"
+ },
+ "peerDependenciesMeta": {
+ "@types/node": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@inquirer/search/node_modules/@inquirer/type": {
+ "version": "4.2.1",
+ "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-4.2.1.tgz",
+ "integrity": "sha512-lDkPsnv5M5CcYB2T1qTc3dobNTPkVr4DU3Ic2Q6SW8/qVRHgvzdRdmVZ6YqG9Ag1aJTeMsLU0s0WPRh3CZWDQQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=23.5.0 || ^22.13.0 || ^20.17.0"
+ },
+ "peerDependencies": {
+ "@types/node": ">=18"
+ },
+ "peerDependenciesMeta": {
+ "@types/node": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@inquirer/select": {
+ "version": "5.2.8",
+ "resolved": "https://registry.npmjs.org/@inquirer/select/-/select-5.2.8.tgz",
+ "integrity": "sha512-BklkkAAOpjdCfuQw5fVGcDuhKxA7T1iBpn6b2JUvDDdkIsO3Ftlg+WnWUCVpkUBFagL2o036OFW+xL4lC9wIPw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@inquirer/ansi": "^2.0.10",
+ "@inquirer/core": "^12.0.6",
+ "@inquirer/figures": "^2.0.10",
+ "@inquirer/type": "4.2.1"
+ },
+ "engines": {
+ "node": ">=23.5.0 || ^22.13.0 || ^20.17.0"
+ },
+ "peerDependencies": {
+ "@types/node": ">=18"
+ },
+ "peerDependenciesMeta": {
+ "@types/node": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@inquirer/select/node_modules/@inquirer/type": {
+ "version": "4.2.1",
+ "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-4.2.1.tgz",
+ "integrity": "sha512-lDkPsnv5M5CcYB2T1qTc3dobNTPkVr4DU3Ic2Q6SW8/qVRHgvzdRdmVZ6YqG9Ag1aJTeMsLU0s0WPRh3CZWDQQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=23.5.0 || ^22.13.0 || ^20.17.0"
+ },
+ "peerDependencies": {
+ "@types/node": ">=18"
+ },
+ "peerDependenciesMeta": {
+ "@types/node": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@inquirer/type": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-4.1.1.tgz",
+ "integrity": "sha512-yJoHYrMnxIsJZCY+0Vb66Dy3he3kL3e2wOBKhoSwWWAzZAY82emlxwgprCtp6yRixvNRNq9ztfRWQYPNr3Go7A==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=23.5.0 || ^22.13.0 || ^20.17.0"
+ },
+ "peerDependencies": {
+ "@types/node": ">=18"
+ },
+ "peerDependenciesMeta": {
+ "@types/node": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@isaacs/fs-minipass": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz",
+ "integrity": "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "minipass": "^7.0.4"
+ },
+ "engines": {
+ "node": ">=18.0.0"
+ }
+ },
+ "node_modules/@isaacs/string-locale-compare": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/@isaacs/string-locale-compare/-/string-locale-compare-1.1.0.tgz",
+ "integrity": "sha512-SQ7Kzhh9+D+ZW9MA0zkYv3VXhIDNx+LzM6EJ+/65I3QY+enU6Itte7E5XX7EWrqLW2FN4n06GWzBnPoC3th2aQ==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/@jest/diff-sequences": {
+ "version": "30.0.1",
+ "resolved": "https://registry.npmjs.org/@jest/diff-sequences/-/diff-sequences-30.0.1.tgz",
+ "integrity": "sha512-n5H8QLDJ47QqbCNn5SuFjCRDrOLEZ0h8vAHCK5RL9Ls7Xa8AQLa/YxAc9UjFqoEDM48muwtBGjtMY5cr0PLDCw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
+ }
+ },
+ "node_modules/@napi-rs/wasm-runtime": {
+ "version": "0.2.4",
+ "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.4.tgz",
+ "integrity": "sha512-9zESzOO5aDByvhIAsOy9TbpZ0Ur2AJbUI7UT73kcUTS2mxAMHOBaa1st/jAymNoCtvrit99kkzT1FZuXVcgfIQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@emnapi/core": "^1.1.0",
+ "@emnapi/runtime": "^1.1.0",
+ "@tybys/wasm-util": "^0.9.0"
+ }
+ },
+ "node_modules/@npmcli/agent": {
+ "version": "5.0.2",
+ "resolved": "https://registry.npmjs.org/@npmcli/agent/-/agent-5.0.2.tgz",
+ "integrity": "sha512-EkzGmEsgbQ1rqWkRJe2P0oQHx/ylZozDUNPMXCklLuSFL3GY+QyEfBUjhjCsgGXzh4OGpnHvkboSQgczjP/jJg==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "agent-base": "^9.0.0",
+ "http-proxy-agent": "^9.0.0",
+ "https-proxy-agent": "^9.0.0",
+ "lru-cache": "^11.2.1",
+ "socks-proxy-agent": "^10.0.0"
+ },
+ "engines": {
+ "node": "^22.22.2 || ^24.15.0 || >=26.0.0"
+ }
+ },
+ "node_modules/@npmcli/arborist": {
+ "version": "10.0.3",
+ "resolved": "https://registry.npmjs.org/@npmcli/arborist/-/arborist-10.0.3.tgz",
+ "integrity": "sha512-QuGpR01YV/4RuJ+5S0W5qh4uljQygmk7b50Jkx+zLErOMMUpKhpbLu/TqQlKfsvuR3SOwXIn3ht+G4bcxrv1WA==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "@gar/promise-retry": "^1.0.0",
+ "@isaacs/string-locale-compare": "^1.1.0",
+ "@npmcli/fs": "^6.0.0",
+ "@npmcli/installed-package-contents": "^5.0.0",
+ "@npmcli/map-workspaces": "^6.0.0",
+ "@npmcli/metavuln-calculator": "^10.0.0",
+ "@npmcli/name-from-folder": "^5.0.0",
+ "@npmcli/node-gyp": "^6.0.0",
+ "@npmcli/package-json": "^8.0.0",
+ "@npmcli/query": "^5.0.0",
+ "@npmcli/redact": "^5.0.0",
+ "@npmcli/run-script": "^11.0.0",
+ "bin-links": "^7.0.0",
+ "cacache": "^21.0.1",
+ "common-ancestor-path": "^2.0.0",
+ "diff": "^8.0.2",
+ "hosted-git-info": "^10.1.1",
+ "json-stringify-nice": "^1.1.4",
+ "lru-cache": "^11.2.1",
+ "minimatch": "^10.0.3",
+ "nopt": "^10.0.1",
+ "npm-install-checks": "^9.0.0",
+ "npm-package-arg": "^14.0.0",
+ "npm-pick-manifest": "^12.0.0",
+ "npm-registry-fetch": "^20.0.1",
+ "pacote": "^22.0.0",
+ "parse-conflict-json": "^6.0.0",
+ "proc-log": "^7.0.0",
+ "proggy": "^4.0.0",
+ "promise-all-reject-late": "^1.0.0",
+ "promise-call-limit": "^3.0.1",
+ "semver": "^7.3.7",
+ "ssri": "^14.0.0",
+ "treeverse": "^3.0.0",
+ "validate-npm-package-name": "^8.0.0",
+ "walk-up-path": "^4.0.0"
+ },
+ "bin": {
+ "arborist": "bin/index.js"
+ },
+ "engines": {
+ "node": "^22.22.2 || ^24.15.0 || >=26.0.0"
+ }
+ },
+ "node_modules/@npmcli/fs": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-6.0.0.tgz",
+ "integrity": "sha512-AheOs4swKka/XLtht6xxJDPezlQ7K2IYQ9Y8lST4JLDjnralnWuMM9AE2CdVcgQJ5omrXhsRzM7F7aYmeZBvKQ==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "semver": "^7.3.5"
+ },
+ "engines": {
+ "node": "^22.22.2 || ^24.15.0 || >=26.0.0"
+ }
+ },
+ "node_modules/@npmcli/git": {
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/@npmcli/git/-/git-8.0.0.tgz",
+ "integrity": "sha512-5P1oo+TbxZNAiiMBtpzHA8QyEGh5D69LYLexNWJEDXLdxnAZvT/SLitGJBXxjtCE4ftAcFOS/Tu2185MeIjooQ==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "@gar/promise-retry": "^1.0.0",
+ "@npmcli/promise-spawn": "^10.0.0",
+ "ini": "^7.0.0",
+ "lru-cache": "^11.2.1",
+ "npm-pick-manifest": "^12.0.0",
+ "proc-log": "^7.0.0",
+ "semver": "^7.3.5",
+ "which": "^7.0.0"
+ },
+ "engines": {
+ "node": "^22.22.2 || ^24.15.0 || >=26.0.0"
+ }
+ },
+ "node_modules/@npmcli/installed-package-contents": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/@npmcli/installed-package-contents/-/installed-package-contents-5.0.0.tgz",
+ "integrity": "sha512-6Ay12sf2Lh7U1ifvnS1mq7TZFeh/rXHMXye+kV7jQrANIubaoVcleeh4HdFumxhsRYwm9OaHycB5lYmSwGrcIQ==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "npm-bundled": "^6.0.0",
+ "npm-normalize-package-bin": "^6.0.0"
+ },
+ "bin": {
+ "installed-package-contents": "bin/index.js"
+ },
+ "engines": {
+ "node": "^22.22.2 || ^24.15.0 || >=26.0.0"
+ }
+ },
+ "node_modules/@npmcli/map-workspaces": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/@npmcli/map-workspaces/-/map-workspaces-6.0.0.tgz",
+ "integrity": "sha512-Dsex7XBea0BoFRbfALMbNuaNqeI3kbZJxiBMQhFvPUNluv0yEeKMd5FLIXy0NCsOuGMYQkLa+i219CadnoqLbg==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "@npmcli/name-from-folder": "^5.0.0",
+ "@npmcli/package-json": "^8.0.0",
+ "glob": "^13.0.0",
+ "minimatch": "^10.0.3"
+ },
+ "engines": {
+ "node": "^22.22.2 || ^24.15.0 || >=26.0.0"
+ }
+ },
+ "node_modules/@npmcli/metavuln-calculator": {
+ "version": "10.0.0",
+ "resolved": "https://registry.npmjs.org/@npmcli/metavuln-calculator/-/metavuln-calculator-10.0.0.tgz",
+ "integrity": "sha512-fC56lpGOae+unrFx6hoiWeWa0/4q+bLhOQTSrB65qcy+Zm34i1OdBcevAQFJJdUB/3i9uXw7PjdrrRjt0KSKXw==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "cacache": "^21.0.1",
+ "json-parse-even-better-errors": "^6.0.0",
+ "pacote": "^22.0.0",
+ "proc-log": "^7.0.0",
+ "semver": "^7.3.5"
+ },
+ "engines": {
+ "node": "^22.22.2 || ^24.15.0 || >=26.0.0"
+ }
+ },
+ "node_modules/@npmcli/name-from-folder": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/@npmcli/name-from-folder/-/name-from-folder-5.0.0.tgz",
+ "integrity": "sha512-Mua2i5asmOn4sGGAsANS9Guamo7sgUd4BihhQWzlNGz6l/Ki23CzC2oGe4I94r2k/39ImCjDLbyu/rSJr/SXoA==",
+ "dev": true,
+ "license": "ISC",
+ "engines": {
+ "node": "^22.22.2 || ^24.15.0 || >=26.0.0"
+ }
+ },
+ "node_modules/@npmcli/node-gyp": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/@npmcli/node-gyp/-/node-gyp-6.0.0.tgz",
+ "integrity": "sha512-MFakpea4pcZNlHSTbMi15HK8RY8zl2UpgDtxhZCWOer+KRN3x7HFIMk/fKpOMgR55L4LIcA2qn8IHeyABhIFtw==",
+ "dev": true,
+ "license": "ISC",
+ "engines": {
+ "node": "^22.22.2 || ^24.15.0 || >=26.0.0"
+ }
+ },
+ "node_modules/@npmcli/package-json": {
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/@npmcli/package-json/-/package-json-8.0.0.tgz",
+ "integrity": "sha512-agNZzYQ18MR0wKp3Emg1q5QbcC8CXigYp3Z3CvB0Sax9Ge9aF4cVyyuSG+5SbACSrZUKTvMjVULWiE1RJA38wg==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "@npmcli/git": "^8.0.0",
+ "glob": "^13.0.0",
+ "hosted-git-info": "^10.1.1",
+ "json-parse-even-better-errors": "^6.0.0",
+ "proc-log": "^7.0.0",
+ "semver": "^7.5.3",
+ "spdx-expression-parse": "^4.0.0"
+ },
+ "engines": {
+ "node": "^22.22.2 || ^24.15.0 || >=26.0.0"
+ }
+ },
+ "node_modules/@npmcli/promise-spawn": {
+ "version": "10.0.1",
+ "resolved": "https://registry.npmjs.org/@npmcli/promise-spawn/-/promise-spawn-10.0.1.tgz",
+ "integrity": "sha512-IstFcKAoEIZ7olS9iTwBsyNOZkIturafO2da9ocSP3LifRlm1+sxuo8IVM5phg5sNe0tNYLT0ZqCBRTLNzz0AA==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "which": "^7.0.0"
+ },
+ "engines": {
+ "node": "^22.22.2 || ^24.15.0 || >=26.0.0"
+ }
+ },
+ "node_modules/@npmcli/query": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/@npmcli/query/-/query-5.0.0.tgz",
+ "integrity": "sha512-8TZWfTQOsODpLqo9SVhVjHovmKXNpevHU0gO9e+y4V4fRIOneiXy0u0sMP9LmS71XivrEWfZWg50ReH4WRT4aQ==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "postcss-selector-parser": "^7.0.0"
+ },
+ "engines": {
+ "node": "^20.17.0 || >=22.9.0"
+ }
+ },
+ "node_modules/@npmcli/redact": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/@npmcli/redact/-/redact-5.0.0.tgz",
+ "integrity": "sha512-3zcN5Q3yEmeyxXBzqB6fXPQFzYa2ROsGFSr69W0ArXIAGJqxl/aFECOVPD2kbkYPm0U/EHxFKgclK3UA9WQg5A==",
+ "dev": true,
+ "license": "ISC",
+ "engines": {
+ "node": "^22.22.2 || ^24.15.0 || >=26.0.0"
+ }
+ },
+ "node_modules/@npmcli/run-script": {
+ "version": "11.0.0",
+ "resolved": "https://registry.npmjs.org/@npmcli/run-script/-/run-script-11.0.0.tgz",
+ "integrity": "sha512-leBRl6F5F0TvWut8m1/aZcMTUHi2vXjKeMJ/Ik1lW7Q7Yy16Dhtkklu+cEqQww1p1NeLnUNzV3+uwpzqRcy9vw==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "@npmcli/node-gyp": "^6.0.0",
+ "@npmcli/package-json": "^8.0.0",
+ "@npmcli/promise-spawn": "^10.0.0",
+ "node-gyp": "^13.0.0",
+ "proc-log": "^7.0.0"
+ },
+ "engines": {
+ "node": "^22.22.2 || ^24.15.0 || >=26.0.0"
+ }
+ },
+ "node_modules/@nx/devkit": {
+ "version": "23.3.1",
+ "resolved": "https://registry.npmjs.org/@nx/devkit/-/devkit-23.3.1.tgz",
+ "integrity": "sha512-Cw6YISZUjit22Trfo/p6rnrNklIKHYgRyp2IyOgr0i9naDgO3Ufllib9D/v0SInwX2zKevaWJWMyreqVvHRU0w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ejs": "5.0.1",
+ "minimatch": "10.2.5",
+ "semver": "^7.6.3",
+ "tslib": "^2.3.0",
+ "yargs-parser": "21.1.1"
+ },
+ "peerDependencies": {
+ "nx": ">= 22 <= 24 || ^23.0.0-0"
+ }
+ },
+ "node_modules/@nx/devkit/node_modules/minimatch": {
+ "version": "10.2.5",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz",
+ "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==",
+ "dev": true,
+ "license": "BlueOak-1.0.0",
+ "dependencies": {
+ "brace-expansion": "^5.0.5"
+ },
+ "engines": {
+ "node": "18 || 20 || >=22"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/@nx/nx-darwin-arm64": {
+ "version": "23.3.1",
+ "resolved": "https://registry.npmjs.org/@nx/nx-darwin-arm64/-/nx-darwin-arm64-23.3.1.tgz",
+ "integrity": "sha512-T3KOTrUIdWaqlIIMyusbpKHujXTumoltkYwBjqjw9Py6Fb3c8Eb7uvWVW6dP8ODknqr9oEcTlk+C8Nid+bunAQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ]
+ },
+ "node_modules/@nx/nx-darwin-x64": {
+ "version": "23.3.1",
+ "resolved": "https://registry.npmjs.org/@nx/nx-darwin-x64/-/nx-darwin-x64-23.3.1.tgz",
+ "integrity": "sha512-GnbMF9xEGIdUI/7KoQdcTILWmRUrMLbbFi3CO8KgKcA1Be7eaoeKdgBQoCQ2yF7r7DyQOR1PXp7sF3s7gqUATQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ]
+ },
+ "node_modules/@nx/nx-freebsd-x64": {
+ "version": "23.3.1",
+ "resolved": "https://registry.npmjs.org/@nx/nx-freebsd-x64/-/nx-freebsd-x64-23.3.1.tgz",
+ "integrity": "sha512-RzLx1pVL/MQQ/fSreMFIufAfsrj/TpD1+69n5kBcr3An2FaqKdQ6BhKLWRlAeOSKq6Su75Y0la8e2AU5zlmdpw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ]
+ },
+ "node_modules/@nx/nx-linux-arm-gnueabihf": {
+ "version": "23.3.1",
+ "resolved": "https://registry.npmjs.org/@nx/nx-linux-arm-gnueabihf/-/nx-linux-arm-gnueabihf-23.3.1.tgz",
+ "integrity": "sha512-/K7ig9xL4FMO2eQovTSLtk4QR7d0phbKoWf1wYQZ2r0ZrHNo2gPYmS8wU0Ci4d6oSiqa2fdeHKVDtEvWldTBaQ==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@nx/nx-linux-arm64-gnu": {
+ "version": "23.3.1",
+ "resolved": "https://registry.npmjs.org/@nx/nx-linux-arm64-gnu/-/nx-linux-arm64-gnu-23.3.1.tgz",
+ "integrity": "sha512-Uj3xl5aLXUV6EQ/vWbZBqMqZO9K58CxRIsMTISC1+LxjvGnf4uUL73ObTi3K1eih3f1CVCGsU95LF3Kf6T2Frw==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "libc": [
+ "glibc"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@nx/nx-linux-arm64-musl": {
+ "version": "23.3.1",
+ "resolved": "https://registry.npmjs.org/@nx/nx-linux-arm64-musl/-/nx-linux-arm64-musl-23.3.1.tgz",
+ "integrity": "sha512-woeNHutXYgiWU0SQnvKQ4VNgVbqwy1uer6bS0HF2RbfN80HglsjhtzTAUZY2pZiWBLbHcHZwTNmDGTAXSNMLAw==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "libc": [
+ "musl"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@nx/nx-linux-x64-gnu": {
+ "version": "23.3.1",
+ "resolved": "https://registry.npmjs.org/@nx/nx-linux-x64-gnu/-/nx-linux-x64-gnu-23.3.1.tgz",
+ "integrity": "sha512-GckqfXo7BAIrcR07CoI0IM06h1wbUim+4AyUYosokrI4Gx1zHZFRwrE3vpPrMpSKVVYZD7BGQp2bhZBPvgGaxg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "libc": [
+ "glibc"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@nx/nx-linux-x64-musl": {
+ "version": "23.3.1",
+ "resolved": "https://registry.npmjs.org/@nx/nx-linux-x64-musl/-/nx-linux-x64-musl-23.3.1.tgz",
+ "integrity": "sha512-QjOj5S/X39OxVykltLFSvNxaZtnI9uRk0Uqfyt69kOrZn+/Ap2SM/bT70Xqn8PFxj5hfA0viI2vU1AlOM4JQxg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "libc": [
+ "musl"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@nx/nx-win32-arm64-msvc": {
+ "version": "23.3.1",
+ "resolved": "https://registry.npmjs.org/@nx/nx-win32-arm64-msvc/-/nx-win32-arm64-msvc-23.3.1.tgz",
+ "integrity": "sha512-Jf5kc3zhek8Fz06DaMxaJTJxgNJIN2tddE8yxt+XaIHtulmW+MMjy6Z91QPKPf9iZA70N+oT9vwgvYPmOsdO8w==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ]
+ },
+ "node_modules/@nx/nx-win32-x64-msvc": {
+ "version": "23.3.1",
+ "resolved": "https://registry.npmjs.org/@nx/nx-win32-x64-msvc/-/nx-win32-x64-msvc-23.3.1.tgz",
+ "integrity": "sha512-RKQ5t6u4fgOWQyVt61y5Jn/xzXCYxqXOKz2okDbuWccBShQddF8jsqRaLMZDlGT5d8CJTLIso8Y9BiY12/7x7g==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ]
+ },
+ "node_modules/@octokit/auth-token": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-6.0.0.tgz",
+ "integrity": "sha512-P4YJBPdPSpWTQ1NU4XYdvHvXJJDxM6YwpS0FZHRgP7YFkdVxsWcpWGy/NVqlAA7PcPCnMacXlRm1y2PFZRWL/w==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 20"
+ }
+ },
+ "node_modules/@octokit/core": {
+ "version": "7.0.8",
+ "resolved": "https://registry.npmjs.org/@octokit/core/-/core-7.0.8.tgz",
+ "integrity": "sha512-L7y8eYc+AwxGr2PWI4WFt1VG4TiJ66c26BD16mXpYIlXxG0SMigM1+m4aTSlYyBr5BlQsGAlz8uDCoZN4SEMcg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@octokit/auth-token": "^6.0.0",
+ "@octokit/graphql": "^9.0.5",
+ "@octokit/request": "^10.0.16",
+ "@octokit/request-error": "^7.1.2",
+ "@octokit/types": "^18.0.0",
+ "before-after-hook": "^4.0.0",
+ "universal-user-agent": "^7.0.0"
+ },
+ "engines": {
+ "node": ">= 20"
+ }
+ },
+ "node_modules/@octokit/endpoint": {
+ "version": "11.0.5",
+ "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-11.0.5.tgz",
+ "integrity": "sha512-iXa654H3yFafF/ieHkukfbgWo2rmXD2ceD0ZOtrPhw1bc3FDch1d9N/TNs0FQ1/cIbwb7kspUX8jzIs8nzb9DQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@octokit/types": "^18.0.0",
+ "universal-user-agent": "^7.0.2"
+ },
+ "engines": {
+ "node": ">= 20"
+ }
+ },
+ "node_modules/@octokit/graphql": {
+ "version": "9.0.5",
+ "resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-9.0.5.tgz",
+ "integrity": "sha512-bt/hm03LeU6Vy7FwTrkkC9p3XGT/lBwClglMqxBSe5/q0E5CdJTXeAqEI0vlw89/LF/G6tryTIH8HirZ3prMVg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@octokit/request": "^10.0.16",
+ "@octokit/types": "^18.0.0",
+ "universal-user-agent": "^7.0.0"
+ },
+ "engines": {
+ "node": ">= 20"
+ }
+ },
+ "node_modules/@octokit/openapi-types": {
+ "version": "29.0.1",
+ "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-29.0.1.tgz",
+ "integrity": "sha512-9qWOMFNxxLokERcms42rU0PTLqQmVs7g5E41TI4mCOxmpFayD1rfC7XxOL55cG9MBZLFlC31BrR37myMKardwg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@octokit/plugin-enterprise-rest": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/@octokit/plugin-enterprise-rest/-/plugin-enterprise-rest-6.0.1.tgz",
+ "integrity": "sha512-93uGjlhUD+iNg1iWhUENAtJata6w5nE+V4urXOAlIXdco6xNZtUSfYY8dzp3Udy74aqO/B5UZL80x/YMa5PKRw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@octokit/plugin-paginate-rest": {
+ "version": "14.0.0",
+ "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-14.0.0.tgz",
+ "integrity": "sha512-fNVRE7ufJiAA3XUrha2omTA39M6IXIc6GIZLvlbsm8QOQCYvpq/LkMNGyFlB1d8hTDzsAXa3OKtybdMAYsV/fw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@octokit/types": "^16.0.0"
+ },
+ "engines": {
+ "node": ">= 20"
+ },
+ "peerDependencies": {
+ "@octokit/core": ">=6"
+ }
+ },
+ "node_modules/@octokit/plugin-paginate-rest/node_modules/@octokit/openapi-types": {
+ "version": "27.0.0",
+ "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-27.0.0.tgz",
+ "integrity": "sha512-whrdktVs1h6gtR+09+QsNk2+FO+49j6ga1c55YZudfEG+oKJVvJLQi3zkOm5JjiUXAagWK2tI2kTGKJ2Ys7MGA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@octokit/plugin-paginate-rest/node_modules/@octokit/types": {
+ "version": "16.0.0",
+ "resolved": "https://registry.npmjs.org/@octokit/types/-/types-16.0.0.tgz",
+ "integrity": "sha512-sKq+9r1Mm4efXW1FCk7hFSeJo4QKreL/tTbR0rz/qx/r1Oa2VV83LTA/H/MuCOX7uCIJmQVRKBcbmWoySjAnSg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@octokit/openapi-types": "^27.0.0"
+ }
+ },
+ "node_modules/@octokit/plugin-request-log": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/@octokit/plugin-request-log/-/plugin-request-log-6.0.0.tgz",
+ "integrity": "sha512-UkOzeEN3W91/eBq9sPZNQ7sUBvYCqYbrrD8gTbBuGtHEuycE4/awMXcYvx6sVYo7LypPhmQwwpUe4Yyu4QZN5Q==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 20"
+ },
+ "peerDependencies": {
+ "@octokit/core": ">=6"
+ }
+ },
+ "node_modules/@octokit/plugin-rest-endpoint-methods": {
+ "version": "17.0.0",
+ "resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-17.0.0.tgz",
+ "integrity": "sha512-B5yCyIlOJFPqUUeiD0cnBJwWJO8lkJs5d8+ze9QDP6SvfiXSz1BF+91+0MeI1d2yxgOhU/O+CvtiZ9jSkHhFAw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@octokit/types": "^16.0.0"
+ },
+ "engines": {
+ "node": ">= 20"
+ },
+ "peerDependencies": {
+ "@octokit/core": ">=6"
+ }
+ },
+ "node_modules/@octokit/plugin-rest-endpoint-methods/node_modules/@octokit/openapi-types": {
+ "version": "27.0.0",
+ "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-27.0.0.tgz",
+ "integrity": "sha512-whrdktVs1h6gtR+09+QsNk2+FO+49j6ga1c55YZudfEG+oKJVvJLQi3zkOm5JjiUXAagWK2tI2kTGKJ2Ys7MGA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@octokit/plugin-rest-endpoint-methods/node_modules/@octokit/types": {
+ "version": "16.0.0",
+ "resolved": "https://registry.npmjs.org/@octokit/types/-/types-16.0.0.tgz",
+ "integrity": "sha512-sKq+9r1Mm4efXW1FCk7hFSeJo4QKreL/tTbR0rz/qx/r1Oa2VV83LTA/H/MuCOX7uCIJmQVRKBcbmWoySjAnSg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@octokit/openapi-types": "^27.0.0"
+ }
+ },
+ "node_modules/@octokit/request": {
+ "version": "10.0.16",
+ "resolved": "https://registry.npmjs.org/@octokit/request/-/request-10.0.16.tgz",
+ "integrity": "sha512-A0zWGjHzISIb+9ccG8s0dq7LKO5zVpJLRICjgUb+sJxEWqn8RUHB1rD3AE51+PECvXHIxqZ1VVvs4fHTSD9nUQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@octokit/endpoint": "^11.0.5",
+ "@octokit/request-error": "^7.1.2",
+ "@octokit/types": "^18.0.0",
+ "content-type": "^3.0.0",
+ "json-with-bigint": "^3.5.12",
+ "universal-user-agent": "^7.0.2"
+ },
+ "engines": {
+ "node": ">= 20"
+ }
+ },
+ "node_modules/@octokit/request-error": {
+ "version": "7.1.2",
+ "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-7.1.2.tgz",
+ "integrity": "sha512-XZRuT3xZ84D3gYErI1DZvhJ33dCWVV6uzBtWkaBB4TvA/L6eOeTZodxLFVB44bBEEo3vEx7y00UfX1tBLrtLRg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@octokit/types": "^18.0.0"
+ },
+ "engines": {
+ "node": ">= 20"
+ }
+ },
+ "node_modules/@octokit/rest": {
+ "version": "22.0.1",
+ "resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-22.0.1.tgz",
+ "integrity": "sha512-Jzbhzl3CEexhnivb1iQ0KJ7s5vvjMWcmRtq5aUsKmKDrRW6z3r84ngmiFKFvpZjpiU/9/S6ITPFRpn5s/3uQJw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@octokit/core": "^7.0.6",
+ "@octokit/plugin-paginate-rest": "^14.0.0",
+ "@octokit/plugin-request-log": "^6.0.0",
+ "@octokit/plugin-rest-endpoint-methods": "^17.0.0"
+ },
+ "engines": {
+ "node": ">= 20"
+ }
+ },
+ "node_modules/@octokit/types": {
+ "version": "18.0.0",
+ "resolved": "https://registry.npmjs.org/@octokit/types/-/types-18.0.0.tgz",
+ "integrity": "sha512-l6bAF43PNxkJp6g+W4PjoUSSkxHomXw2nOum5CTftJz1NlV3vu93NImgOYtLf6CbBUb5j+fiuzW0PPQ5JTSvZA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@octokit/openapi-types": "^29.0.1"
+ }
+ },
+ "node_modules/@sec-ant/readable-stream": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/@sec-ant/readable-stream/-/readable-stream-0.4.1.tgz",
+ "integrity": "sha512-831qok9r2t8AlxLko40y2ebgSDhenenCatLVeW/uBtnHPyhHOvG0C7TvfgecV+wHzIm5KUICgzmVpWS+IMEAeg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@sigstore/bundle": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/@sigstore/bundle/-/bundle-5.0.0.tgz",
+ "integrity": "sha512-wefjygudENbzbQMks1t5u34EP0fFoD0XvaEP7DOUP/sXKvogzEJYFw5E6pegGyp3onGWzVEYKVa3bNZWyTYX+A==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@sigstore/protobuf-specs": "^0.5.0"
+ },
+ "engines": {
+ "node": "^22.22.2 || ^24.15.0 || >=26.0.0"
+ }
+ },
+ "node_modules/@sigstore/core": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/@sigstore/core/-/core-4.0.1.tgz",
+ "integrity": "sha512-9v5hRjujn5NXq8o7XFEUgLyAtdr5Iisb4pzM05u3K61IS5q3hP3luWAndk0RkPPLTUFoTbg7Vb84UQ1ZQeajWQ==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": "^22.22.2 || ^24.15.0 || >=26.0.0"
+ }
+ },
+ "node_modules/@sigstore/protobuf-specs": {
+ "version": "0.5.2",
+ "resolved": "https://registry.npmjs.org/@sigstore/protobuf-specs/-/protobuf-specs-0.5.2.tgz",
+ "integrity": "sha512-SQqvFMt4V78fdjcDdYX6HbiVSOR4QK3ZgwCa2KOsopAgPIHy1rU5UDUmzLl02r5oyyaYcYHR1hpwDRk/yUe+Mw==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": "^18.17.0 || >=20.5.0"
+ }
+ },
+ "node_modules/@sigstore/sign": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/@sigstore/sign/-/sign-5.0.0.tgz",
+ "integrity": "sha512-DSFivqz9/i5AkwZ5fq0YdjaJlc4o1WeS2Zffon0kqtChx0vy4W9NOjkEet9bF2vkzOufX72eVH8kZBIGtcBp1w==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@gar/promise-retry": "^1.0.2",
+ "@sigstore/bundle": "^5.0.0",
+ "@sigstore/core": "^4.0.0",
+ "@sigstore/protobuf-specs": "^0.5.0",
+ "make-fetch-happen": "^16.0.0",
+ "proc-log": "^7.0.0"
+ },
+ "engines": {
+ "node": "^22.22.2 || ^24.15.0 || >=26.0.0"
+ }
+ },
+ "node_modules/@sigstore/tuf": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/@sigstore/tuf/-/tuf-5.0.0.tgz",
+ "integrity": "sha512-Zyqg9tcHps3uRAlKHLNmsW4ohsUZAjb9G+31r7lg0ICh/JOcadzmJsIRdjKljlRHpaR0K4aJ2kXXIdywdcdMlA==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@sigstore/protobuf-specs": "^0.5.0",
+ "tuf-js": "^6.0.0"
+ },
+ "engines": {
+ "node": "^22.22.2 || ^24.15.0 || >=26.0.0"
+ }
+ },
+ "node_modules/@sigstore/verify": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/@sigstore/verify/-/verify-4.1.2.tgz",
+ "integrity": "sha512-BfD9eLrz3A/DG58aSgfgZYmIR6V9Yw96QVN/frtu2bEH7ctSTk2TDvHU12un3JsDPBTqTNkqkIkucjxljpOFqQ==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@sigstore/bundle": "^5.0.0",
+ "@sigstore/core": "^4.0.1",
+ "@sigstore/protobuf-specs": "^0.5.0"
+ },
+ "engines": {
+ "node": "^22.22.2 || ^24.15.0 || >=26.0.0"
+ }
+ },
+ "node_modules/@simple-libs/child-process-utils": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/@simple-libs/child-process-utils/-/child-process-utils-2.0.0.tgz",
+ "integrity": "sha512-dvNoRKLijXnD0XoJAz94pbNuB5GQgDr55UhpSPhffDkTT0Cmcqh9jSCOtwfT2d4H6MI9E7c4SgtMuJXZ6F3c6A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@simple-libs/stream-utils": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=22"
+ },
+ "funding": {
+ "url": "https://ko-fi.com/dangreen"
+ }
+ },
+ "node_modules/@simple-libs/hosted-git-info": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/@simple-libs/hosted-git-info/-/hosted-git-info-2.0.0.tgz",
+ "integrity": "sha512-55XwK/GYgV58PuN8lZFhI1qRxdKoMLJocXl/yM1EPqazFDmM4QWY7q6BxPCPDNKTNunj794DSD4h0H7SrqUdMg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=22"
+ },
+ "funding": {
+ "url": "https://ko-fi.com/dangreen"
+ }
+ },
+ "node_modules/@simple-libs/normalize-package-data": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/@simple-libs/normalize-package-data/-/normalize-package-data-1.0.0.tgz",
+ "integrity": "sha512-/EOmFBekV9tGee8gac/k+5Ox3twkypNqh5TfxA9vTkmcJkjm6f1xqrlstDNOrEhTvnYyVtU6Du2ZhY/IV1+9GA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@simple-libs/hosted-git-info": "^2.0.0",
+ "semver": "^7.8.5"
+ },
+ "engines": {
+ "node": ">=22"
+ },
+ "funding": {
+ "url": "https://ko-fi.com/dangreen"
+ }
+ },
+ "node_modules/@simple-libs/stream-utils": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/@simple-libs/stream-utils/-/stream-utils-2.0.0.tgz",
+ "integrity": "sha512-fCTuZK4QBa+39Oz9l4OGfJfz+GpwCp3AqO7Zch3to99xHPgstVsRFpeQ8LNd2o1Gv8raL2mCFwiaHh7bFSp5DQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=22"
+ },
+ "funding": {
+ "url": "https://ko-fi.com/dangreen"
+ }
+ },
+ "node_modules/@sindresorhus/merge-streams": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-4.0.0.tgz",
+ "integrity": "sha512-tlqY9xq5ukxTUZBmoOp+m61cqwQD5pHJtFY3Mn8CA8ps6yghLH/Hw8UPdqg4OLmFW3IFlcXnQNmo/dh8HzXYIQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/@tufjs/canonical-json": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/@tufjs/canonical-json/-/canonical-json-2.0.0.tgz",
+ "integrity": "sha512-yVtV8zsdo8qFHe+/3kw81dSLyF7D576A5cCFCi4X7B39tWT7SekaEFUnvnWJHz+9qO7qJTah1JbrDjWKqFtdWA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "^16.14.0 || >=18.0.0"
+ }
+ },
+ "node_modules/@tufjs/models": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/@tufjs/models/-/models-5.0.1.tgz",
+ "integrity": "sha512-wacy5twbJk36R0dTcGE3qmPNNH095bFselAYNrVCzf0Byd0t3+Qzk3+3gn/rHGP10FuHBVk4swg4aczr1c2z/g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@tufjs/canonical-json": "2.0.0",
+ "minimatch": "^10.2.6"
+ },
+ "engines": {
+ "node": "^22.22.2 || ^24.15.0 || >=26.0.0"
+ }
+ },
+ "node_modules/@tybys/wasm-util": {
+ "version": "0.9.0",
+ "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.9.0.tgz",
+ "integrity": "sha512-6+7nlbMVX/PVDCwaIQ8nTOPveOcFLSt8GcXdx8hD0bt39uWxYT88uXzqTd4fTvqta7oeUJqudepapKNt2DYJFw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "tslib": "^2.4.0"
+ }
+ },
+ "node_modules/@types/parse-path": {
+ "version": "7.0.3",
+ "resolved": "https://registry.npmjs.org/@types/parse-path/-/parse-path-7.0.3.tgz",
+ "integrity": "sha512-LriObC2+KYZD3FzCrgWGv/qufdUy4eXrxcLgQMfYXgPbLIecKIsVBaQgUPmxSSLcjmYbDTQbMgr6qr6l/eb7Bg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@yarnpkg/lockfile": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz",
+ "integrity": "sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ==",
+ "dev": true,
+ "license": "BSD-2-Clause"
+ },
+ "node_modules/@zkochan/js-yaml": {
+ "version": "0.0.7",
+ "resolved": "https://registry.npmjs.org/@zkochan/js-yaml/-/js-yaml-0.0.7.tgz",
+ "integrity": "sha512-nrUSn7hzt7J6JWgWGz78ZYI8wj+gdIJdk0Ynjpp8l+trkn58Uqsf6RYrYkEK+3X18EX+TNdtJI0WxAtc+L84SQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "argparse": "^2.0.1"
+ },
+ "bin": {
+ "js-yaml": "bin/js-yaml.js"
+ }
+ },
+ "node_modules/abbrev": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-5.0.0.tgz",
+ "integrity": "sha512-/XrFJgzQQQHpti1raDJC6m4ws6aNktmjBlhk8Fdlk7LwCEuDoieEJJY9OFHjfiFJFFRM2tK+Ky/IsfbbmlMu1w==",
+ "dev": true,
+ "license": "ISC",
+ "engines": {
+ "node": "^22.22.2 || ^24.15.0 || >=26.0.0"
+ }
+ },
+ "node_modules/agent-base": {
+ "version": "9.0.0",
+ "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-9.0.0.tgz",
+ "integrity": "sha512-TQf59BsZnytt8GdJKLPfUZ54g/iaUL2OWDSFCCvMOhsHduDQxO8xC4PNeyIkVcA5KwL2phPSv0douC0fgWzmnA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 20"
+ }
+ },
+ "node_modules/ansi-regex": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+ "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/ansi-styles": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "color-convert": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+ }
+ },
+ "node_modules/argparse": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
+ "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
+ "dev": true,
+ "license": "Python-2.0"
+ },
+ "node_modules/argue-cli": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/argue-cli/-/argue-cli-3.2.0.tgz",
+ "integrity": "sha512-VipTB0gXgGIFO2Rg9yEVN5wLt2AurJcZqDbgmYSwPwsykhLrQhs240/bfceev4w68lI8JshoOJIk9uW7tFzROw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=22"
+ },
+ "funding": {
+ "url": "https://ko-fi.com/dangreen"
+ }
+ },
+ "node_modules/balanced-match": {
+ "version": "4.0.4",
+ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz",
+ "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "18 || 20 || >=22"
+ }
+ },
+ "node_modules/base64-js": {
+ "version": "1.5.1",
+ "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
+ "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "license": "MIT"
+ },
+ "node_modules/before-after-hook": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-4.0.0.tgz",
+ "integrity": "sha512-q6tR3RPqIB1pMiTRMFcZwuG5T8vwp+vUvEG0vuI6B+Rikh5BfPp2fQ82c925FOs+b0lcFQ8CFrL+KbilfZFhOQ==",
+ "dev": true,
+ "license": "Apache-2.0"
+ },
+ "node_modules/bin-links": {
+ "version": "7.0.1",
+ "resolved": "https://registry.npmjs.org/bin-links/-/bin-links-7.0.1.tgz",
+ "integrity": "sha512-lgxd7FtxW02eSuafotQOGEQf1iGfDExMz2BRaL+e1tU5xTLx+vvSVA5oHIO6B1tR91LDKcWqYGsktUHdFMtHHQ==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "cmd-shim": "^9.0.0",
+ "npm-normalize-package-bin": "^6.0.0",
+ "proc-log": "^7.0.0",
+ "read-cmd-shim": "^7.0.0",
+ "write-file-atomic": "^8.0.0"
+ },
+ "engines": {
+ "node": "^22.22.2 || ^24.15.0 || >=26.0.0"
+ }
+ },
+ "node_modules/bl": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz",
+ "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "buffer": "^5.5.0",
+ "inherits": "^2.0.4",
+ "readable-stream": "^3.4.0"
+ }
+ },
+ "node_modules/brace-expansion": {
+ "version": "5.0.12",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.12.tgz",
+ "integrity": "sha512-YovQ3rzhaLMIrDjNDMkNS01tea93qhEhG5xy8f6+R0l+dw3Ki+5sCoIoI942iuLZTHWogWktgwVDhU09iNEimQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "balanced-match": "^4.0.2"
+ },
+ "engines": {
+ "node": "20 || >=22"
+ }
+ },
+ "node_modules/buffer": {
+ "version": "5.7.1",
+ "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz",
+ "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "base64-js": "^1.3.1",
+ "ieee754": "^1.1.13"
+ }
+ },
+ "node_modules/bundle-name": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/bundle-name/-/bundle-name-4.1.0.tgz",
+ "integrity": "sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "run-applescript": "^7.0.0"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/cacache": {
+ "version": "21.0.1",
+ "resolved": "https://registry.npmjs.org/cacache/-/cacache-21.0.1.tgz",
+ "integrity": "sha512-pTwz/uj3Jyp6WXdJ6fWhR+7LVxVs6RyroQSn7KJwHsSxXuyGSp0pcMVcwSwTpCFq1X2YG8QBe0W+vN+cr0SwzA==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "@npmcli/fs": "^6.0.0",
+ "fs-minipass": "^3.0.0",
+ "glob": "^13.0.0",
+ "lru-cache": "^11.1.0",
+ "minipass": "^7.0.3",
+ "minipass-collect": "^2.0.1",
+ "minipass-flush": "^1.0.5",
+ "minipass-pipeline": "^1.2.4",
+ "p-map": "^7.0.2",
+ "ssri": "^14.0.0"
+ },
+ "engines": {
+ "node": "^22.22.2 || ^24.15.0 || >=26.0.0"
+ }
+ },
+ "node_modules/callsites": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
+ "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/chalk": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+ "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ansi-styles": "^4.1.0",
+ "supports-color": "^7.1.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/chalk?sponsor=1"
+ }
+ },
+ "node_modules/chardet": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/chardet/-/chardet-2.2.0.tgz",
+ "integrity": "sha512-rddelWYNPRrXq6PtNEN2S3f6t9ILzvqaN5pVgi4kqt9jHQaXIial9PznB5iSPVlQSLNaaH22ItWz3EJtQ10+OA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/chownr": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/chownr/-/chownr-3.0.0.tgz",
+ "integrity": "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==",
+ "dev": true,
+ "license": "BlueOak-1.0.0",
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/ci-info": {
+ "version": "4.4.0",
+ "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.4.0.tgz",
+ "integrity": "sha512-77PSwercCZU2Fc4sX94eF8k8Pxte6JAwL4/ICZLFjJLqegs7kCuAsqqj/70NQF6TvDpgFjkubQB2FW2ZZddvQg==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/sibiraj-s"
+ }
+ ],
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/cli-cursor": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz",
+ "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "restore-cursor": "^3.1.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/cli-spinners": {
+ "version": "2.6.1",
+ "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.6.1.tgz",
+ "integrity": "sha512-x/5fWmGMnbKQAaNwN+UZlV79qBLM9JFnJuJ03gIi5whrob0xV0ofNVHy9DhwGdsMJQc2OKv0oGmLzvaqvAVv+g==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/cli-width": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-4.1.0.tgz",
+ "integrity": "sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==",
+ "dev": true,
+ "license": "ISC",
+ "engines": {
+ "node": ">= 12"
+ }
+ },
+ "node_modules/cliui": {
+ "version": "8.0.1",
+ "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz",
+ "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "string-width": "^4.2.0",
+ "strip-ansi": "^6.0.1",
+ "wrap-ansi": "^7.0.0"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/cliui/node_modules/string-width": {
+ "version": "4.2.3",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
+ "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "emoji-regex": "^8.0.0",
+ "is-fullwidth-code-point": "^3.0.0",
+ "strip-ansi": "^6.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/clone": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz",
+ "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.8"
+ }
+ },
+ "node_modules/cmd-shim": {
+ "version": "9.0.2",
+ "resolved": "https://registry.npmjs.org/cmd-shim/-/cmd-shim-9.0.2.tgz",
+ "integrity": "sha512-xVHoI+wNrM4tDB9iC1idf/8D0tYnVimlBp/5zHW+x1sGjjRD69NvR9th3Z1JAYGN/BTW4he6aZFYV6kzy+k+jw==",
+ "dev": true,
+ "license": "ISC",
+ "engines": {
+ "node": "^22.22.2 || ^24.15.0 || >=26.0.0"
+ }
+ },
+ "node_modules/color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "color-name": "~1.1.4"
+ },
+ "engines": {
+ "node": ">=7.0.0"
+ }
+ },
+ "node_modules/color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/columnify": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/columnify/-/columnify-1.6.0.tgz",
+ "integrity": "sha512-lomjuFZKfM6MSAnV9aCZC9sc0qGbmZdfygNv+nCpqVkSKdCxCklLtd16O0EILGkImHw9ZpHkAnHaB+8Zxq5W6Q==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "strip-ansi": "^6.0.1",
+ "wcwidth": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=8.0.0"
+ }
+ },
+ "node_modules/common-ancestor-path": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/common-ancestor-path/-/common-ancestor-path-2.0.0.tgz",
+ "integrity": "sha512-dnN3ibLeoRf2HNC+OlCiNc5d2zxbLJXOtiZUudNFSXZrNSydxcCsSpRzXwfu7BBWCIfHPw+xTayeBvJCP/D8Ng==",
+ "dev": true,
+ "license": "BlueOak-1.0.0",
+ "engines": {
+ "node": ">= 18"
+ }
+ },
+ "node_modules/content-type": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/content-type/-/content-type-3.1.1.tgz",
+ "integrity": "sha512-GW4qUsfFo59d0HbUibDlWv5wPz+vAAcaTWbKIuKCf0JkC7wWkSyf8f13IpXn5JkeMlB2P8iTSSIjwXljorg2vA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=22"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/express"
+ }
+ },
+ "node_modules/conventional-changelog": {
+ "version": "8.1.3",
+ "resolved": "https://registry.npmjs.org/conventional-changelog/-/conventional-changelog-8.1.3.tgz",
+ "integrity": "sha512-fOMwLCxm46znJKPB08jLxl1FD8SOZOQHktlzCVhvhhVUfq0KgQSryoYXsRRHs1aRlZPR1/QK5wztnY8sBNC2AA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@conventional-changelog/git-client": "^3.1.2",
+ "@simple-libs/hosted-git-info": "^2.0.0",
+ "@simple-libs/normalize-package-data": "^1.0.0",
+ "argue-cli": "^3.1.0",
+ "conventional-changelog-preset-loader": "^6.0.1",
+ "conventional-changelog-writer": "^9.2.1",
+ "conventional-commits-filter": "^6.0.1",
+ "conventional-commits-parser": "^7.1.2",
+ "fd-package-json": "^2.0.0"
+ },
+ "bin": {
+ "conventional-changelog": "dist/cli/index.js"
+ },
+ "engines": {
+ "node": ">=22"
+ }
+ },
+ "node_modules/conventional-changelog-angular": {
+ "version": "9.4.0",
+ "resolved": "https://registry.npmjs.org/conventional-changelog-angular/-/conventional-changelog-angular-9.4.0.tgz",
+ "integrity": "sha512-HdxRxuS8bBXVIuo4V82gvSwAXT0vYQUizrjs/izmPg5JdDstr8v8I5hduGL3iQbG+o310dUDxC4+LetuS5hu9w==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "@conventional-changelog/template": "^1.4.0"
+ },
+ "engines": {
+ "node": ">=22"
+ }
+ },
+ "node_modules/conventional-changelog-preset-loader": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/conventional-changelog-preset-loader/-/conventional-changelog-preset-loader-6.0.1.tgz",
+ "integrity": "sha512-GZ8E3RQzXQb3JFy0pKl8oeSf7ENIhvAMvJr+PlWkavZOesLHHdhkfNJ4SvW35eo1Fu2+EyVxWQ1tVvtzAG2iWg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=22"
+ }
+ },
+ "node_modules/conventional-changelog-writer": {
+ "version": "9.3.0",
+ "resolved": "https://registry.npmjs.org/conventional-changelog-writer/-/conventional-changelog-writer-9.3.0.tgz",
+ "integrity": "sha512-lxiECDlvy880e7JIYAtAhxg0wD/CGCVbZCdeua5aOlQVFTEd39zAeOzwK22i/FO4xnEOURK1gbUTETNEYW7zxQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@conventional-changelog/template": "^1.4.0",
+ "@simple-libs/stream-utils": "^2.0.0",
+ "argue-cli": "^3.1.0",
+ "conventional-commits-filter": "^6.0.1",
+ "verkit": "^0.5.0"
+ },
+ "bin": {
+ "conventional-changelog-writer": "dist/cli/index.js"
+ },
+ "engines": {
+ "node": ">=22"
+ }
+ },
+ "node_modules/conventional-changelog/node_modules/@conventional-changelog/git-client": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/@conventional-changelog/git-client/-/git-client-3.2.0.tgz",
+ "integrity": "sha512-sD/E0vzpkoDz/dqM1Hhv0ihC4KBw6RXjefeO8SG1XrX+wGkMxe1pKeedkKDPCtr2JjuhbuS9aJNgOvnT8hbeBw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@simple-libs/child-process-utils": "^2.0.0",
+ "@simple-libs/stream-utils": "^2.0.0",
+ "verkit": "^0.5.0"
+ },
+ "engines": {
+ "node": ">=22"
+ },
+ "peerDependencies": {
+ "conventional-commits-filter": "^6.0.1",
+ "conventional-commits-parser": "^7.1.3"
+ },
+ "peerDependenciesMeta": {
+ "conventional-commits-filter": {
+ "optional": true
+ },
+ "conventional-commits-parser": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/conventional-changelog/node_modules/conventional-commits-parser": {
+ "version": "7.1.3",
+ "resolved": "https://registry.npmjs.org/conventional-commits-parser/-/conventional-commits-parser-7.1.3.tgz",
+ "integrity": "sha512-Q9oWm1o9uy/oEsZQIraoFMZ4RuPD+79KgwWj6mJVP356tazolCB0piRLZ5Kz9te9p027uSEcUW+Gu44Eh+X79g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@simple-libs/stream-utils": "^2.0.0",
+ "argue-cli": "^3.1.0"
+ },
+ "bin": {
+ "conventional-commits-parser": "dist/cli/index.js"
+ },
+ "engines": {
+ "node": ">=22"
+ }
+ },
+ "node_modules/conventional-commits-filter": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/conventional-commits-filter/-/conventional-commits-filter-6.0.1.tgz",
+ "integrity": "sha512-cs+LadpH7Kpw0M3k8wurk+sOVVDAENA0iK4OBOrkL94j5lEVYRJ4j3zd2bhY9qgzyrPqthdcYT3axzRN7AliMg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=22"
+ }
+ },
+ "node_modules/conventional-commits-parser": {
+ "version": "7.1.2",
+ "resolved": "https://registry.npmjs.org/conventional-commits-parser/-/conventional-commits-parser-7.1.2.tgz",
+ "integrity": "sha512-O+x4N2yH+ijvqWlIyTHsXTAP+algNWgGbjY2duCe8w2vUMvUB95cLRslCPfTMQyLAKlet3bhZTdu6ozn4M+QJQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@simple-libs/stream-utils": "^2.0.0",
+ "argue-cli": "^3.1.0"
+ },
+ "bin": {
+ "conventional-commits-parser": "dist/cli/index.js"
+ },
+ "engines": {
+ "node": ">=22"
+ }
+ },
+ "node_modules/conventional-recommended-bump": {
+ "version": "12.1.0",
+ "resolved": "https://registry.npmjs.org/conventional-recommended-bump/-/conventional-recommended-bump-12.1.0.tgz",
+ "integrity": "sha512-HTNG3kEZXOOfKwrEx54ljURU9bG4nVPQzXMyCSeUcA/PE8EpNpQNujSrbXNBI8QZyN35zM+pVw+FuQk4KqHSHg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@conventional-changelog/git-client": "^3.1.0",
+ "argue-cli": "^3.1.0",
+ "conventional-changelog-preset-loader": "^6.0.1",
+ "conventional-commits-filter": "^6.0.1",
+ "conventional-commits-parser": "^7.1.0"
+ },
+ "bin": {
+ "conventional-recommended-bump": "dist/cli/index.js"
+ },
+ "engines": {
+ "node": ">=22"
+ }
+ },
+ "node_modules/conventional-recommended-bump/node_modules/@conventional-changelog/git-client": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/@conventional-changelog/git-client/-/git-client-3.2.0.tgz",
+ "integrity": "sha512-sD/E0vzpkoDz/dqM1Hhv0ihC4KBw6RXjefeO8SG1XrX+wGkMxe1pKeedkKDPCtr2JjuhbuS9aJNgOvnT8hbeBw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@simple-libs/child-process-utils": "^2.0.0",
+ "@simple-libs/stream-utils": "^2.0.0",
+ "verkit": "^0.5.0"
+ },
+ "engines": {
+ "node": ">=22"
+ },
+ "peerDependencies": {
+ "conventional-commits-filter": "^6.0.1",
+ "conventional-commits-parser": "^7.1.3"
+ },
+ "peerDependenciesMeta": {
+ "conventional-commits-filter": {
+ "optional": true
+ },
+ "conventional-commits-parser": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/conventional-recommended-bump/node_modules/conventional-commits-parser": {
+ "version": "7.1.3",
+ "resolved": "https://registry.npmjs.org/conventional-commits-parser/-/conventional-commits-parser-7.1.3.tgz",
+ "integrity": "sha512-Q9oWm1o9uy/oEsZQIraoFMZ4RuPD+79KgwWj6mJVP356tazolCB0piRLZ5Kz9te9p027uSEcUW+Gu44Eh+X79g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@simple-libs/stream-utils": "^2.0.0",
+ "argue-cli": "^3.1.0"
+ },
+ "bin": {
+ "conventional-commits-parser": "dist/cli/index.js"
+ },
+ "engines": {
+ "node": ">=22"
+ }
+ },
+ "node_modules/cosmiconfig": {
+ "version": "9.0.2",
+ "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-9.0.2.tgz",
+ "integrity": "sha512-gtTZxTDau1wL7Y7zifc2dd8jHSK/k6BTx/2Xp/BpdlAdnlYWFVt7qhJqgwi7637yRwRQ3qL4ZidbB4I8tA5VOg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "env-paths": "^2.2.1",
+ "import-fresh": "^3.3.0",
+ "js-yaml": "^4.1.0",
+ "parse-json": "^5.2.0"
+ },
+ "engines": {
+ "node": ">=14"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/d-fischer"
+ },
+ "peerDependencies": {
+ "typescript": ">=4.9.5"
+ },
+ "peerDependenciesMeta": {
+ "typescript": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/cosmiconfig/node_modules/js-yaml": {
+ "version": "4.3.2",
+ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.2.tgz",
+ "integrity": "sha512-SFNOvSJ+Dgf/9An904Yx+CgSlIPCkIpao4qo51lpee25TIRejdH3rhR4EZMGoNx3/TP3O+wzWuiTFl4sqbltzA==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/puzrin"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/nodeca"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "argparse": "^2.0.1"
+ },
+ "bin": {
+ "js-yaml": "bin/js-yaml.js"
+ }
+ },
+ "node_modules/cssesc": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz",
+ "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "cssesc": "bin/cssesc"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/debug": {
+ "version": "4.4.3",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
+ "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ms": "^2.1.3"
+ },
+ "engines": {
+ "node": ">=6.0"
+ },
+ "peerDependenciesMeta": {
+ "supports-color": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/dedent": {
+ "version": "1.7.2",
+ "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.7.2.tgz",
+ "integrity": "sha512-WzMx3mW98SN+zn3hgemf4OzdmyNhhhKz5Ay0pUfQiMQ3e1g+xmTJWp/pKdwKVXhdSkAEGIIzqeuWrL3mV/AXbA==",
+ "dev": true,
+ "license": "MIT",
+ "peerDependencies": {
+ "babel-plugin-macros": "^3.1.0"
+ },
+ "peerDependenciesMeta": {
+ "babel-plugin-macros": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/default-browser": {
+ "version": "5.2.1",
+ "resolved": "https://registry.npmjs.org/default-browser/-/default-browser-5.2.1.tgz",
+ "integrity": "sha512-WY/3TUME0x3KPYdRRxEJJvXRHV4PyPoUsxtZa78lwItwRQRHhd2U9xOscaT/YTf8uCXIAjeJOFBVEh/7FtD8Xg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "bundle-name": "^4.1.0",
+ "default-browser-id": "^5.0.0"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/default-browser-id": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/default-browser-id/-/default-browser-id-5.0.0.tgz",
+ "integrity": "sha512-A6p/pu/6fyBcA1TRz/GqWYPViplrftcW2gZC9q79ngNCKAeR/X3gcEdXQHl4KNXV+3wgIJ1CPkJQ3IHM6lcsyA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/defaults": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz",
+ "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "clone": "^1.0.2"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/define-lazy-prop": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz",
+ "integrity": "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/diff": {
+ "version": "8.0.4",
+ "resolved": "https://registry.npmjs.org/diff/-/diff-8.0.4.tgz",
+ "integrity": "sha512-DPi0FmjiSU5EvQV0++GFDOJ9ASQUVFh5kD+OzOnYdi7n3Wpm9hWWGfB/O2blfHcMVTL5WkQXSnRiK9makhrcnw==",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "engines": {
+ "node": ">=0.3.1"
+ }
+ },
+ "node_modules/dotenv": {
+ "version": "16.4.7",
+ "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.7.tgz",
+ "integrity": "sha512-47qPchRCykZC03FhkYAhrvwU4xDBFIj1QPqaarj6mdM/hgUzfPHcpkHJOn3mJAufFeeAxAzeGsr5X0M4k6fLZQ==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://dotenvx.com"
+ }
+ },
+ "node_modules/dotenv-expand": {
+ "version": "12.0.3",
+ "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-12.0.3.tgz",
+ "integrity": "sha512-uc47g4b+4k/M/SeaW1y4OApx+mtLWl92l5LMPP0GNXctZqELk+YGgOPIIC5elYmUH4OuoK3JLhuRUYegeySiFA==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "dotenv": "^16.4.5"
+ },
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://dotenvx.com"
+ }
+ },
+ "node_modules/ejs": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/ejs/-/ejs-5.0.1.tgz",
+ "integrity": "sha512-COqBPFMxuPTPspXl2DkVYaDS3HtrD1GpzOGkNTJ1IYkifq/r9h8SVEFrjA3D9/VJGOEoMQcrlhpntcSUrM8k6A==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "bin": {
+ "ejs": "bin/cli.js"
+ },
+ "engines": {
+ "node": ">=0.12.18"
+ }
+ },
+ "node_modules/emoji-regex": {
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
+ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/end-of-stream": {
+ "version": "1.4.5",
+ "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz",
+ "integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "once": "^1.4.0"
+ }
+ },
+ "node_modules/env-paths": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz",
+ "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/envinfo": {
+ "version": "7.21.0",
+ "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.21.0.tgz",
+ "integrity": "sha512-Lw7I8Zp5YKHFCXL7+Dz95g4CcbMEpgvqZNNq3AmlT5XAV6CgAAk6gyAMqn2zjw08K9BHfcNuKrMiCPLByGafow==",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "envinfo": "dist/cli.js"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/error-ex": {
+ "version": "1.3.4",
+ "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.4.tgz",
+ "integrity": "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "is-arrayish": "^0.2.1"
+ }
+ },
+ "node_modules/escalade": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz",
+ "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/escape-string-regexp": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
+ "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.8.0"
+ }
+ },
+ "node_modules/eventemitter3": {
+ "version": "5.0.4",
+ "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.4.tgz",
+ "integrity": "sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/execa": {
+ "version": "10.0.1",
+ "resolved": "https://registry.npmjs.org/execa/-/execa-10.0.1.tgz",
+ "integrity": "sha512-ge98qjkRK4IB7tL7Ju/6qmm5LHoH1eEMt5FNZrz3f4UIYhF28lggX20z3FaX1sgc67msLEn0N0BscOs29iuwyw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@sindresorhus/merge-streams": "^4.0.0",
+ "figures": "^6.1.0",
+ "get-stream": "^9.0.1",
+ "human-signals": "^8.0.1",
+ "is-plain-obj": "^4.1.0",
+ "is-stream": "^4.0.1",
+ "npm-run-path": "^6.0.0",
+ "pretty-ms": "^9.3.0",
+ "signal-exit": "^4.1.0",
+ "strip-final-newline": "^4.0.0",
+ "which-command": "^0.1.0",
+ "yoctocolors": "^2.1.2"
+ },
+ "engines": {
+ "node": ">=22"
+ },
+ "funding": {
+ "url": "https://github.com/sindresorhus/execa?sponsor=1"
+ }
+ },
+ "node_modules/exponential-backoff": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/exponential-backoff/-/exponential-backoff-3.1.3.tgz",
+ "integrity": "sha512-ZgEeZXj30q+I0EN+CbSSpIyPaJ5HVQD18Z1m+u1FXbAeT94mr1zw50q4q6jiiC447Nl/YTcIYSAftiGqetwXCA==",
+ "dev": true,
+ "license": "Apache-2.0"
+ },
+ "node_modules/fast-string-truncated-width": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/fast-string-truncated-width/-/fast-string-truncated-width-3.0.3.tgz",
+ "integrity": "sha512-0jjjIEL6+0jag3l2XWWizO64/aZVtpiGE3t0Zgqxv0DPuxiMjvB3M24fCyhZUO4KomJQPj3LTSUnDP3GpdwC0g==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/fast-string-width": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/fast-string-width/-/fast-string-width-3.0.2.tgz",
+ "integrity": "sha512-gX8LrtNEI5hq8DVUfRQMbr5lpaS4nMIWV+7XEbXk2b8kiQIizgnlr12B4dA3ZEx3308ze0O4Q1R+cHts8kyUJg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "fast-string-truncated-width": "^3.0.2"
+ }
+ },
+ "node_modules/fast-wrap-ansi": {
+ "version": "0.2.2",
+ "resolved": "https://registry.npmjs.org/fast-wrap-ansi/-/fast-wrap-ansi-0.2.2.tgz",
+ "integrity": "sha512-7F2Fl+TjRSenLqlU3UjSH0iyqopqoZIu7eZVpEirP2g1GtWa2G/ecEmBdgz31+Mxr+ELclgg6sokpSFIQiZ02Q==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "fast-string-width": "^3.0.2"
+ }
+ },
+ "node_modules/fd-package-json": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/fd-package-json/-/fd-package-json-2.0.0.tgz",
+ "integrity": "sha512-jKmm9YtsNXN789RS/0mSzOC1NUq9mkVd65vbSSVsKdjGvYXBuE4oWe2QOEoFeRmJg+lPuZxpmrfFclNhoRMneQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "walk-up-path": "^4.0.0"
+ }
+ },
+ "node_modules/fdir": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz",
+ "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=12.0.0"
+ },
+ "peerDependencies": {
+ "picomatch": "^3 || ^4"
+ },
+ "peerDependenciesMeta": {
+ "picomatch": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/figures": {
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/figures/-/figures-6.1.0.tgz",
+ "integrity": "sha512-d+l3qxjSesT4V7v2fh+QnmFnUWv9lSpjarhShNTgBOfA0ttejbQUAlHLitbjkoRiDulW0OPoQPYIGhIC8ohejg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "is-unicode-supported": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/find-up": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
+ "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "locate-path": "^5.0.0",
+ "path-exists": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/fs-constants": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz",
+ "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/fs-extra": {
+ "version": "11.4.1",
+ "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.4.1.tgz",
+ "integrity": "sha512-KYAb4c9BJQI6QqGKthV68OHe0badztdXJWKo0WtBA9IuCFPTKvE5ZdUBglP833aMjhaSPNO4A5j/EkzZtGlKjA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "graceful-fs": "^4.2.0",
+ "jsonfile": "^6.0.1",
+ "universalify": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=14.14"
+ }
+ },
+ "node_modules/fs-minipass": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-3.0.3.tgz",
+ "integrity": "sha512-XUBA9XClHbnJWSfBzjkm6RvPsyg3sryZt06BEQoXcF7EK/xpGaQYJgQKDJSUH5SGZ76Y7pFx1QBnXz09rU5Fbw==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "minipass": "^7.0.3"
+ },
+ "engines": {
+ "node": "^14.17.0 || ^16.13.0 || >=18.0.0"
+ }
+ },
+ "node_modules/get-caller-file": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
+ "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
+ "dev": true,
+ "license": "ISC",
+ "engines": {
+ "node": "6.* || 8.* || >= 10.*"
+ }
+ },
+ "node_modules/get-east-asian-width": {
+ "version": "1.7.0",
+ "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.7.0.tgz",
+ "integrity": "sha512-XjH1AECxf0giL2V1aU8vKyRR2ppRUb5c0EvT7zuJTokQ74bNo52zOtghqdWIqrhUD79fo3x0WfKZdOqxF6LG1Q==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/get-stream": {
+ "version": "9.0.1",
+ "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-9.0.1.tgz",
+ "integrity": "sha512-kVCxPF3vQM/N0B1PmoqVUqgHP+EeVjmZSQn+1oCRPxd2P21P2F19lIgbR3HBosbB1PUhOAoctJnfEn2GbN2eZA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@sec-ant/readable-stream": "^0.4.1",
+ "is-stream": "^4.0.1"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/git-up": {
+ "version": "8.1.1",
+ "resolved": "https://registry.npmjs.org/git-up/-/git-up-8.1.1.tgz",
+ "integrity": "sha512-FDenSF3fVqBYSaJoYy1KSc2wosx0gCvKP+c+PRBht7cAaiCeQlBtfBDX9vgnNOHmdePlSFITVcn4pFfcgNvx3g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "is-ssh": "^1.4.0",
+ "parse-url": "^9.2.0"
+ }
+ },
+ "node_modules/git-url-parse": {
+ "version": "16.1.0",
+ "resolved": "https://registry.npmjs.org/git-url-parse/-/git-url-parse-16.1.0.tgz",
+ "integrity": "sha512-cPLz4HuK86wClEW7iDdeAKcCVlWXmrLpb2L+G9goW0Z1dtpNS6BXXSOckUTlJT/LDQViE1QZKstNORzHsLnobw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "git-up": "^8.1.0"
+ }
+ },
+ "node_modules/glob": {
+ "version": "13.0.6",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-13.0.6.tgz",
+ "integrity": "sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw==",
+ "dev": true,
+ "license": "BlueOak-1.0.0",
+ "dependencies": {
+ "minimatch": "^10.2.2",
+ "minipass": "^7.1.3",
+ "path-scurry": "^2.0.2"
+ },
+ "engines": {
+ "node": "18 || 20 || >=22"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/graceful-fs": {
+ "version": "4.2.11",
+ "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
+ "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/handlebars": {
+ "version": "4.7.10",
+ "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.10.tgz",
+ "integrity": "sha512-P5VJMVM7qgBn6vjXMw8WG9uVI+ncf2pi72j4de4yz5ZULLj2RGqLYaKOYGsgyrViQ0tePOVlN1tDCCXXtFqXKg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "minimist": "^1.2.8",
+ "neo-async": "^2.6.2",
+ "source-map": "^0.6.1",
+ "wordwrap": "^1.0.0"
+ },
+ "bin": {
+ "handlebars": "bin/handlebars"
+ },
+ "engines": {
+ "node": ">=0.4.7"
+ },
+ "optionalDependencies": {
+ "uglify-js": "^3.1.4"
+ }
+ },
+ "node_modules/has-flag": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/hosted-git-info": {
+ "version": "10.1.1",
+ "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-10.1.1.tgz",
+ "integrity": "sha512-DeOnSPAvOndYKfw075gt8yZzQ7S2hNztw34zBTfhIzLhmBTswIBg5/y+pqu/VD5cYWm5goAFTusDmUEmKZ0PEQ==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "lru-cache": "^11.1.0"
+ },
+ "engines": {
+ "node": "^22.22.2 || ^24.15.0 || >=26.0.0"
+ }
+ },
+ "node_modules/http-cache-semantics": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.3.0.tgz",
+ "integrity": "sha512-M5t5LlJpS1UHMjvwRQVdFHvPISGeLAxNcrWuJkeGh0KxsqCHZ1O3NXZU/8x7cD0BDcGW8kapxMKTvwlqrNkHkA==",
+ "dev": true,
+ "license": "BSD-2-Clause"
+ },
+ "node_modules/http-proxy-agent": {
+ "version": "9.1.0",
+ "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-9.1.0.tgz",
+ "integrity": "sha512-2NxoveTT58mjYT4n3RPTEfCZGLMbidoO8XEieXfpSYxu+PQJ1qpx4ypwH6N+uF9twBPIvRRgvkvW5HUTYWENig==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "agent-base": "9.0.0",
+ "debug": "^4.3.4",
+ "proxy-agent-negotiate": "1.1.0"
+ },
+ "engines": {
+ "node": ">= 20"
+ }
+ },
+ "node_modules/https-proxy-agent": {
+ "version": "9.1.0",
+ "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-9.1.0.tgz",
+ "integrity": "sha512-ag87y7cJJ9/3+GxFr8Oy4O5faDsGRGnBGsJj/YjOSsSx/5eadKLYTMPlzuR6obgoCDDm0abAAZitXXQkMOPSpA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "agent-base": "9.0.0",
+ "debug": "^4.3.4",
+ "proxy-agent-negotiate": "1.1.0"
+ },
+ "engines": {
+ "node": ">= 20"
+ }
+ },
+ "node_modules/human-signals": {
+ "version": "8.0.1",
+ "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-8.0.1.tgz",
+ "integrity": "sha512-eKCa6bwnJhvxj14kZk5NCPc6Hb6BdsU9DZcOnmQKSnO1VKrfV0zCvtttPZUsBvjmNDn8rpcJfpwSYnHBjc95MQ==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": ">=18.18.0"
+ }
+ },
+ "node_modules/iconv-lite": {
+ "version": "0.7.3",
+ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.3.tgz",
+ "integrity": "sha512-IKXpvIzjnC9XTAUbVBcMfGS0EPaIXtW6v+zr+RRp+hqULEpo0owZax6wyRwPOJbWbzjYspQwusTsfVr0ifh4uQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "safer-buffer": ">= 2.1.2 < 3.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/express"
+ }
+ },
+ "node_modules/ieee754": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
+ "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "license": "BSD-3-Clause"
+ },
+ "node_modules/ignore": {
+ "version": "7.0.6",
+ "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.6.tgz",
+ "integrity": "sha512-BAg6QkE8W+TuQLrrw0Ugr7HegXduRuuj8/ti2kSOc+jz1dmx8/WNcjr6XGnq5YpDWxFwwaavqD0+jIUOKelTsw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 4"
+ }
+ },
+ "node_modules/ignore-walk": {
+ "version": "9.0.0",
+ "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-9.0.0.tgz",
+ "integrity": "sha512-tCBEZV2z2FNpIDl2vrhiWzIHzs4qOAuIDEO85eS02vZ3L1U3P56qpPL8GuGGAijDktAEaq2swMkO/Fmbo7YmfQ==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "minimatch": "^10.0.3"
+ },
+ "engines": {
+ "node": "^22.22.2 || ^24.15.0 || >=26.0.0"
+ }
+ },
+ "node_modules/import-fresh": {
+ "version": "3.3.1",
+ "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz",
+ "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "parent-module": "^1.0.0",
+ "resolve-from": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/import-local": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.2.0.tgz",
+ "integrity": "sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "pkg-dir": "^4.2.0",
+ "resolve-cwd": "^3.0.0"
+ },
+ "bin": {
+ "import-local-fixture": "fixtures/cli.js"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/inherits": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/ini": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/ini/-/ini-7.0.0.tgz",
+ "integrity": "sha512-ifK0CgjALofS5bkrcTy4RaQ9Vx2Knf/eLeIO+NaswQEpH1UblrtTSCIvN71qQDMq0PeQ/SSPojvEJp9vvvfr+w==",
+ "dev": true,
+ "license": "ISC",
+ "engines": {
+ "node": "^22.22.2 || ^24.15.0 || >=26.0.0"
+ }
+ },
+ "node_modules/init-package-json": {
+ "version": "9.0.0",
+ "resolved": "https://registry.npmjs.org/init-package-json/-/init-package-json-9.0.0.tgz",
+ "integrity": "sha512-aYDqz4jgX1plB2GDCFYStlOh67QXVpAIeNgDq8rRGVDYMvLE39yYlf8+CjYY2chVOVfqLsSIycFYznHWozZ9CA==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "@npmcli/package-json": "^8.0.0",
+ "npm-package-arg": "^14.0.0",
+ "promzard": "^4.0.0",
+ "read": "^6.0.0",
+ "semver": "^7.7.2",
+ "validate-npm-package-name": "^8.0.0"
+ },
+ "engines": {
+ "node": "^22.22.2 || ^24.15.0 || >=26.0.0"
+ }
+ },
+ "node_modules/inquirer": {
+ "version": "14.2.2",
+ "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-14.2.2.tgz",
+ "integrity": "sha512-WGerZIIb7mTtaFFskkD/P0europ8xBWf1OXACMiugzKPSmVzoqhcPSuSUzbzMch/t3rf1ncBT3v/0WU73cLqJQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@inquirer/ansi": "^2.0.8",
+ "@inquirer/core": "^12.0.3",
+ "@inquirer/prompts": "^8.7.2",
+ "@inquirer/type": "4.1.1",
+ "mute-stream": "^3.0.0",
+ "run-async": "^4.0.6"
+ },
+ "engines": {
+ "node": ">=23.5.0 || ^22.13.0 || ^20.17.0"
+ },
+ "peerDependencies": {
+ "@types/node": ">=18"
+ },
+ "peerDependenciesMeta": {
+ "@types/node": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/ip-address": {
+ "version": "10.7.5",
+ "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.7.5.tgz",
+ "integrity": "sha512-t2v0rkILYv9WXmSL7TpAaU3HXgaFYOPUcH3QHgwQ++gpJuH3bqyMy4Fvt/DJCTKwzH3Cf+bAp5W/mFL39KPLzA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 12"
+ }
+ },
+ "node_modules/is-arrayish": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
+ "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/is-docker": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz",
+ "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "is-docker": "cli.js"
+ },
+ "engines": {
+ "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/is-fullwidth-code-point": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
+ "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/is-inside-container": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz",
+ "integrity": "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "is-docker": "^3.0.0"
+ },
+ "bin": {
+ "is-inside-container": "cli.js"
+ },
+ "engines": {
+ "node": ">=14.16"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/is-interactive": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz",
+ "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/is-plain-obj": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz",
+ "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/is-ssh": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/is-ssh/-/is-ssh-1.4.1.tgz",
+ "integrity": "sha512-JNeu1wQsHjyHgn9NcWTaXq6zWSR6hqE0++zhfZlkFBbScNkyvxCdeV8sRkSBaeLKxmbpR21brail63ACNxJ0Tg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "protocols": "^2.0.1"
+ }
+ },
+ "node_modules/is-stream": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-4.0.1.tgz",
+ "integrity": "sha512-Dnz92NInDqYckGEUJv689RbRiTSEHCQ7wOVeALbkOz999YpqT46yMRIGtSNl2iCL1waAZSx40+h59NV/EwzV/A==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/is-unicode-supported": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-2.1.0.tgz",
+ "integrity": "sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/is-wsl": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-3.1.0.tgz",
+ "integrity": "sha512-UcVfVfaK4Sc4m7X3dUSoHoozQGBEFeDC+zVo06t98xe8CzHSZZBekNXH+tu0NalHolcJ/QAGqS46Hef7QXBIMw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "is-inside-container": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=16"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/isexe": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
+ "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/js-tokens": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
+ "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/js-yaml": {
+ "version": "5.4.2",
+ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-5.4.2.tgz",
+ "integrity": "sha512-m+aqu+LwO1O6sIopafj8HUVl5aawITwZQe/yHpMCKjaWBaA/d07B/QdMb3529REftiU+RMMHL3Vlsw3hON7vWg==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/puzrin"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/nodeca"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "argparse": "^2.0.1"
+ },
+ "bin": {
+ "js-yaml": "bin/js-yaml.mjs"
+ }
+ },
+ "node_modules/json-parse-even-better-errors": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-6.0.0.tgz",
+ "integrity": "sha512-2/8adwnK1/+Fdjyts4r6wSpfANWw8zdNhU9U/Llk59c6O+DjSisPWPykwoL8gZmocP9Dy64S7oie2g+Mia123A==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "^22.22.2 || ^24.15.0 || >=26.0.0"
+ }
+ },
+ "node_modules/json-stringify-nice": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/json-stringify-nice/-/json-stringify-nice-1.1.4.tgz",
+ "integrity": "sha512-5Z5RFW63yxReJ7vANgW6eZFGWaQvnPE3WNmZoOJrSkGju2etKA2L5rrOa1sm877TVTFt57A80BH1bArcmlLfPw==",
+ "dev": true,
+ "license": "ISC",
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/json-with-bigint": {
+ "version": "3.5.12",
+ "resolved": "https://registry.npmjs.org/json-with-bigint/-/json-with-bigint-3.5.12.tgz",
+ "integrity": "sha512-uwbF/wSSuOgC7qqlq27Xp5B6a2MHVug3t0idZdTqu0JnlFvgJuH7ju+KAk/J06C7GfhoYy2gnb9wz2INqcne7w==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/json5": {
+ "version": "2.2.3",
+ "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
+ "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "json5": "lib/cli.js"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/jsonc-parser": {
+ "version": "3.3.1",
+ "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.3.1.tgz",
+ "integrity": "sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/jsonfile": {
+ "version": "6.2.1",
+ "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.1.tgz",
+ "integrity": "sha512-zwOTdL3rFQ/lRdBnntKVOX6k5cKJwEc1HdilT71BWEu7J41gXIB2MRp+vxduPSwZJPWBxEzv4yH1wYLJGUHX4Q==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "universalify": "^2.0.0"
+ },
+ "optionalDependencies": {
+ "graceful-fs": "^4.1.6"
+ }
+ },
+ "node_modules/jsonparse": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz",
+ "integrity": "sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==",
+ "dev": true,
+ "engines": [
+ "node >= 0.2.0"
+ ],
+ "license": "MIT"
+ },
+ "node_modules/just-diff": {
+ "version": "6.0.2",
+ "resolved": "https://registry.npmjs.org/just-diff/-/just-diff-6.0.2.tgz",
+ "integrity": "sha512-S59eriX5u3/QhMNq3v/gm8Kd0w8OS6Tz2FS1NG4blv+z0MuQcBRJyFWjdovM0Rad4/P4aUPFtnkNjMjyMlMSYA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/just-diff-apply": {
+ "version": "5.5.0",
+ "resolved": "https://registry.npmjs.org/just-diff-apply/-/just-diff-apply-5.5.0.tgz",
+ "integrity": "sha512-OYTthRfSh55WOItVqwpefPtNt2VdKsq5AnAK6apdtR6yCH8pr0CmSr710J0Mf+WdQy7K/OzMy7K2MgAfdQURDw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/lerna": {
+ "version": "10.1.1",
+ "resolved": "https://registry.npmjs.org/lerna/-/lerna-10.1.1.tgz",
+ "integrity": "sha512-WDGaMGDGj5jV0n6Yx2zuBDWH0ym6toUE6w+maaPLqeMd3ncDRN+NJMcVWImVdUKCIHRk2Xk+X7QQkFXdHKsscA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@npmcli/arborist": "10.0.3",
+ "@npmcli/package-json": "8.0.0",
+ "@npmcli/run-script": "11.0.0",
+ "@nx/devkit": ">=23.1.0 < 24.0.0",
+ "@octokit/plugin-enterprise-rest": "6.0.1",
+ "@octokit/rest": "22.0.1",
+ "ci-info": "4.4.0",
+ "columnify": "1.6.0",
+ "conventional-changelog": "8.1.3",
+ "conventional-changelog-angular": "9.4.0",
+ "conventional-commits-filter": "6.0.1",
+ "conventional-commits-parser": "7.1.2",
+ "conventional-recommended-bump": "12.1.0",
+ "cosmiconfig": "9.0.2",
+ "dedent": "1.7.2",
+ "envinfo": "7.21.0",
+ "execa": "10.0.1",
+ "fs-extra": "^11.2.0",
+ "git-url-parse": "16.1.0",
+ "handlebars": "4.7.10",
+ "import-local": "3.2.0",
+ "ini": "^7.0.0",
+ "init-package-json": "9.0.0",
+ "inquirer": "14.2.2",
+ "js-yaml": "5.4.2",
+ "libnpmaccess": "11.0.0",
+ "libnpmpublish": "12.0.1",
+ "load-json-file": "7.0.1",
+ "make-fetch-happen": "16.0.1",
+ "minimatch": "10.2.6",
+ "npm-package-arg": "14.0.0",
+ "npm-packlist": "11.3.0",
+ "npm-registry-fetch": "20.0.1",
+ "nx": ">=23.1.0 < 24.0.0",
+ "p-map": "7.0.8",
+ "p-queue": "9.3.3",
+ "pacote": "22.0.0",
+ "semver": "7.8.5",
+ "signal-exit": "4.1.0",
+ "ssri": "14.0.0",
+ "string-width": "^8.0.0",
+ "tar": "7.5.22",
+ "tinyglobby": "0.2.17",
+ "validate-npm-package-name": "8.0.0",
+ "write-file-atomic": "8.0.0",
+ "yargs": "18.2.0"
+ },
+ "bin": {
+ "lerna": "dist/cli.js"
+ },
+ "engines": {
+ "node": "^22.22.2 || ^24.15.0 || ^26.0.0"
+ }
+ },
+ "node_modules/libnpmaccess": {
+ "version": "11.0.0",
+ "resolved": "https://registry.npmjs.org/libnpmaccess/-/libnpmaccess-11.0.0.tgz",
+ "integrity": "sha512-qku5OaTtCv7f4xq5lmZMh4H6pd9WRalww3WF4PEk/aFo1Bpi7/IRCzy28EQBvyrprhzZGifbpM378U4waB9/0Q==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "npm-package-arg": "^14.0.0",
+ "npm-registry-fetch": "^20.0.1"
+ },
+ "engines": {
+ "node": "^22.22.2 || ^24.15.0 || >=26.0.0"
+ }
+ },
+ "node_modules/libnpmpublish": {
+ "version": "12.0.1",
+ "resolved": "https://registry.npmjs.org/libnpmpublish/-/libnpmpublish-12.0.1.tgz",
+ "integrity": "sha512-gG32Hgikbb8mx+c+b2MKseuQcwKbiIl7wM4a5+scxuRtu/Q7L/fbywMyLD4naUfL0yexdKWzfi6kglMz6BGOWQ==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "@npmcli/package-json": "^8.0.0",
+ "ci-info": "^4.0.0",
+ "npm-package-arg": "^14.0.0",
+ "npm-registry-fetch": "^20.0.1",
+ "proc-log": "^7.0.0",
+ "semver": "^7.3.7",
+ "sigstore": "^5.0.0",
+ "ssri": "^14.0.0"
+ },
+ "engines": {
+ "node": "^22.22.2 || ^24.15.0 || >=26.0.0"
+ }
+ },
+ "node_modules/lines-and-columns": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-2.0.3.tgz",
+ "integrity": "sha512-cNOjgCnLB+FnvWWtyRTzmB3POJ+cXxTA81LoW7u8JdmhfXzriropYwpjShnz1QLLWsQwY7nIxoDmcPTwphDK9w==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+ }
+ },
+ "node_modules/load-json-file": {
+ "version": "7.0.1",
+ "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-7.0.1.tgz",
+ "integrity": "sha512-Gnxj3ev3mB5TkVBGad0JM6dmLiQL+o0t23JPBZ9sd+yvSLk05mFoqKBw5N8gbbkU4TNXyqCgIrl/VM17OgUIgQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/locate-path": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
+ "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "p-locate": "^4.1.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/log-symbols": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz",
+ "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "chalk": "^4.1.0",
+ "is-unicode-supported": "^0.1.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/log-symbols/node_modules/is-unicode-supported": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz",
+ "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/lru-cache": {
+ "version": "11.5.3",
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.3.tgz",
+ "integrity": "sha512-U4N8FgzmWxc8k1VH8Kr6lQg18U7Fjvby6wXHVRX/ZZ7IwWbRMgrRbP0Wrb5q5NVinryp4SQampHKdvtecItxUg==",
+ "dev": true,
+ "license": "BlueOak-1.0.0",
+ "engines": {
+ "node": "20 || >=22"
+ }
+ },
+ "node_modules/make-fetch-happen": {
+ "version": "16.0.1",
+ "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-16.0.1.tgz",
+ "integrity": "sha512-uUv1yxHzaKVVEPfcFeGSNov/Cehjv08ovlY8ImTljgL7Q+SiA0dAYLQ6SYVa2kkKqNj4Y3aZEI7xv2teadie0A==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "@gar/promise-retry": "^1.0.0",
+ "@npmcli/agent": "^5.0.0",
+ "@npmcli/redact": "^5.0.0",
+ "cacache": "^21.0.0",
+ "http-cache-semantics": "^4.1.1",
+ "minipass": "^7.0.2",
+ "minipass-fetch": "^6.0.0",
+ "minipass-flush": "^1.0.5",
+ "minipass-pipeline": "^1.2.4",
+ "negotiator": "^1.0.0",
+ "proc-log": "^7.0.0",
+ "ssri": "^14.0.0"
+ },
+ "engines": {
+ "node": "^22.22.2 || ^24.15.0 || >=26.0.0"
+ }
+ },
+ "node_modules/mimic-fn": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz",
+ "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/minimatch": {
+ "version": "10.2.6",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.6.tgz",
+ "integrity": "sha512-vpLQEs+VLCr1nU0BXS07maYoFwlDAH0gngQuuttxIwutDFEMHq2blX+8vpgxDdK3J1PwjCJiep77OitTZ4Ll1A==",
+ "dev": true,
+ "license": "BlueOak-1.0.0",
+ "dependencies": {
+ "brace-expansion": "^5.0.8"
+ },
+ "engines": {
+ "node": "18 || 20 || >=22"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/minimist": {
+ "version": "1.2.8",
+ "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
+ "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==",
+ "dev": true,
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/minipass": {
+ "version": "7.1.3",
+ "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz",
+ "integrity": "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==",
+ "dev": true,
+ "license": "BlueOak-1.0.0",
+ "engines": {
+ "node": ">=16 || 14 >=14.17"
+ }
+ },
+ "node_modules/minipass-collect": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-2.0.1.tgz",
+ "integrity": "sha512-D7V8PO9oaz7PWGLbCACuI1qEOsq7UKfLotx/C0Aet43fCUB/wfQ7DYeq2oR/svFJGYDHPr38SHATeaj/ZoKHKw==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "minipass": "^7.0.3"
+ },
+ "engines": {
+ "node": ">=16 || 14 >=14.17"
+ }
+ },
+ "node_modules/minipass-fetch": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-6.0.0.tgz",
+ "integrity": "sha512-AWI8bKapGmgx/J0E6IGYSKj8TiHebZkmKWSs8raPSw8KXwgEAJ+Bw3+LSdXHR6T/RHKAWCOYk2MiLrYluaUU6w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "minipass": "^7.0.3",
+ "minipass-sized": "^2.0.0",
+ "minizlib": "^3.0.1"
+ },
+ "engines": {
+ "node": "^22.22.2 || ^24.15.0 || >=26.0.0"
+ },
+ "optionalDependencies": {
+ "iconv-lite": "^0.7.2"
+ }
+ },
+ "node_modules/minipass-flush": {
+ "version": "1.0.7",
+ "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.7.tgz",
+ "integrity": "sha512-TbqTz9cUwWyHS2Dy89P3ocAGUGxKjjLuR9z8w4WUTGAVgEj17/4nhgo2Du56i0Fm3Pm30g4iA8Lcqctc76jCzA==",
+ "dev": true,
+ "license": "BlueOak-1.0.0",
+ "dependencies": {
+ "minipass": "^3.0.0"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/minipass-flush/node_modules/minipass": {
+ "version": "3.3.6",
+ "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz",
+ "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "yallist": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/minipass-flush/node_modules/yallist": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
+ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/minipass-pipeline": {
+ "version": "1.2.4",
+ "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz",
+ "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "minipass": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/minipass-pipeline/node_modules/minipass": {
+ "version": "3.3.6",
+ "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz",
+ "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "yallist": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/minipass-pipeline/node_modules/yallist": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
+ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/minipass-sized": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/minipass-sized/-/minipass-sized-2.0.0.tgz",
+ "integrity": "sha512-zSsHhto5BcUVM2m1LurnXY6M//cGhVaegT71OfOXoprxT6o780GZd792ea6FfrQkuU4usHZIUczAQMRUE2plzA==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "minipass": "^7.1.2"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/minizlib": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-3.1.0.tgz",
+ "integrity": "sha512-KZxYo1BUkWD2TVFLr0MQoM8vUUigWD3LlD83a/75BqC+4qE0Hb1Vo5v1FgcfaNXvfXzr+5EhQ6ing/CaBijTlw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "minipass": "^7.1.2"
+ },
+ "engines": {
+ "node": ">= 18"
+ }
+ },
+ "node_modules/ms": {
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/mute-stream": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-3.0.0.tgz",
+ "integrity": "sha512-dkEJPVvun4FryqBmZ5KhDo0K9iDXAwn08tMLDinNdRBNPcYEDiWYysLcc6k3mjTMlbP9KyylvRpd4wFtwrT9rw==",
+ "dev": true,
+ "license": "ISC",
+ "engines": {
+ "node": "^20.17.0 || >=22.9.0"
+ }
+ },
+ "node_modules/negotiator": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.1.0.tgz",
+ "integrity": "sha512-NMPBRMJgiQHjbd8phG3Vebdx4kZ1H121rbl5IkMqeOsahptB9BKo/d7oJ3zTXqTgagn2bWlNSXkh0QUGM31RYg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "content-type": "^2.1.0"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/express"
+ }
+ },
+ "node_modules/negotiator/node_modules/content-type": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/content-type/-/content-type-2.1.0.tgz",
+ "integrity": "sha512-mj7UPXE0jaqaOsukNZRUEfEi2AcL7C/vwmwcHV0O97eO1E1pxBZuyjlZrx5seTaNBg1U6+o35wpa35Qfcc+7ag==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/express"
+ }
+ },
+ "node_modules/neo-async": {
+ "version": "2.6.2",
+ "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz",
+ "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/node-gyp": {
+ "version": "13.1.0",
+ "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-13.1.0.tgz",
+ "integrity": "sha512-FpNzOLFACKG0oRBYbZ5WOeWD1EqRTIWX90MaRIWTO18lVYPx8fqIjrdS3pihjnCkSmgop6zVGkSqg1vXZLksuw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "env-paths": "^2.2.0",
+ "exponential-backoff": "^3.1.1",
+ "graceful-fs": "^4.2.6",
+ "nopt": "^10.0.0",
+ "proc-log": "^7.0.0",
+ "semver": "^7.3.5",
+ "tar": "^7.5.7",
+ "tinyglobby": "^0.2.12",
+ "undici": "^8.4.1",
+ "which": "^7.0.0"
+ },
+ "bin": {
+ "node-gyp": "bin/node-gyp.js"
+ },
+ "engines": {
+ "node": "^22.22.2 || ^24.15.0 || >=26.0.0"
+ }
+ },
+ "node_modules/nopt": {
+ "version": "10.0.1",
+ "resolved": "https://registry.npmjs.org/nopt/-/nopt-10.0.1.tgz",
+ "integrity": "sha512-df3sBr/6ax9hSGuC3CspvLlbnX8cP5L5nZwXF8cGN8l0zSWR6BvzmQ6jPUKjvo6+/xdpkNvEcucBNUdBeeV13g==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "abbrev": "^5.0.0"
+ },
+ "bin": {
+ "nopt": "bin/nopt.js"
+ },
+ "engines": {
+ "node": "^22.22.2 || ^24.15.0 || >=26.0.0"
+ }
+ },
+ "node_modules/npm-bundled": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-6.0.0.tgz",
+ "integrity": "sha512-EqdodKEW6pYM+dPxA66TZQfMEqVDiuzjDM9edSjuPI1mXUbUJwVxkgqMZSJvs8RTXz2CGq8HUol/AffTZX5g8w==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "npm-normalize-package-bin": "^6.0.0"
+ },
+ "engines": {
+ "node": "^22.22.2 || ^24.15.0 || >=26.0.0"
+ }
+ },
+ "node_modules/npm-install-checks": {
+ "version": "9.0.0",
+ "resolved": "https://registry.npmjs.org/npm-install-checks/-/npm-install-checks-9.0.0.tgz",
+ "integrity": "sha512-t05Izcgi7p15cpldqoiXYpjzlkTTvBw33sgjmL/JjcvtV0ydbm2O4iEXO8A6smqComu5FAQhUas86HTMQ6Z1Uw==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "semver": "^7.1.1"
+ },
+ "engines": {
+ "node": "^22.22.2 || ^24.15.0 || >=26.0.0"
+ }
+ },
+ "node_modules/npm-normalize-package-bin": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-6.0.0.tgz",
+ "integrity": "sha512-tdt4aFn9QamlhdN3HV2D2ccpBwO5/fyjjbXUxYA6uBjyekMZcZvDq0aSj9t5Jo+tih6AYFnt/cuIRn9013e0Uw==",
+ "dev": true,
+ "license": "ISC",
+ "engines": {
+ "node": "^22.22.2 || ^24.15.0 || >=26.0.0"
+ }
+ },
+ "node_modules/npm-package-arg": {
+ "version": "14.0.0",
+ "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-14.0.0.tgz",
+ "integrity": "sha512-69XQh3k+dtGa1p+7RaR57IuG3rCko96xr/nUfN4yDYBXbTYICiWcOpsFKLN2GtGE9cyIljE+f1exnaYt9MvM+Q==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "hosted-git-info": "^10.1.0",
+ "proc-log": "^7.0.0",
+ "semver": "^7.3.5",
+ "validate-npm-package-name": "^8.0.0"
+ },
+ "engines": {
+ "node": "^22.22.2 || ^24.15.0 || >=26.0.0"
+ }
+ },
+ "node_modules/npm-packlist": {
+ "version": "11.3.0",
+ "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-11.3.0.tgz",
+ "integrity": "sha512-cS1yVkyriZgQAbiK8PtwhZHEtsFOsKHsCg5Ww2ONckAvXIspgqd6o4WirOzvkupU24iMRZ4xtO4kb2iK2rbnag==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "glob": "^13.0.6",
+ "ignore-walk": "^9.0.0",
+ "proc-log": "^7.0.0"
+ },
+ "engines": {
+ "node": "^22.22.2 || ^24.15.0 || >=26.0.0"
+ }
+ },
+ "node_modules/npm-pick-manifest": {
+ "version": "12.0.0",
+ "resolved": "https://registry.npmjs.org/npm-pick-manifest/-/npm-pick-manifest-12.0.0.tgz",
+ "integrity": "sha512-8Fs3YLrnNOhrCdPNZy18MzNgVC58LTDAFzq1FdZO/p3BHeCC/coz+t4F5Pxabys8HJpyTUorMea26GkXsb4J/Q==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "npm-install-checks": "^9.0.0",
+ "npm-normalize-package-bin": "^6.0.0",
+ "npm-package-arg": "^14.0.0",
+ "semver": "^7.3.5"
+ },
+ "engines": {
+ "node": "^22.22.2 || ^24.15.0 || >=26.0.0"
+ }
+ },
+ "node_modules/npm-registry-fetch": {
+ "version": "20.0.1",
+ "resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-20.0.1.tgz",
+ "integrity": "sha512-vzc1svxw/kw1IRjFsLi6gaxe1Olqm88V0tIfu2u5raL0b1gChe6ZEXNkyUlKxUC7s/egt5NxZHkbY18tMKKLfQ==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "@npmcli/redact": "^5.0.0",
+ "jsonparse": "^1.3.1",
+ "make-fetch-happen": "^16.0.0",
+ "minipass": "^7.0.2",
+ "minipass-fetch": "^6.0.0",
+ "minizlib": "^3.0.1",
+ "npm-package-arg": "^14.0.0",
+ "proc-log": "^7.0.0"
+ },
+ "engines": {
+ "node": "^22.22.2 || ^24.15.0 || >=26.0.0"
+ }
+ },
+ "node_modules/npm-run-path": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-6.0.0.tgz",
+ "integrity": "sha512-9qny7Z9DsQU8Ou39ERsPU4OZQlSTP47ShQzuKZ6PRXpYLtIFgl/DEBYEXKlvcEa+9tHVcK8CF81Y2V72qaZhWA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "path-key": "^4.0.0",
+ "unicorn-magic": "^0.3.0"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/nx": {
+ "version": "23.3.1",
+ "resolved": "https://registry.npmjs.org/nx/-/nx-23.3.1.tgz",
+ "integrity": "sha512-dufPxsiUazuSejFYdtLAotKXeda9ufz3B9gVtsrvgxkjWjpAM23rOpIJoqZj3FFauig64lYsaMX+nX2hh+YhYQ==",
+ "dev": true,
+ "hasInstallScript": true,
+ "license": "MIT",
+ "dependencies": {
+ "@clack/core": "1.4.3",
+ "@clack/prompts": "1.7.0",
+ "@emnapi/core": "1.4.5",
+ "@emnapi/runtime": "1.4.5",
+ "@emnapi/wasi-threads": "1.0.4",
+ "@jest/diff-sequences": "30.0.1",
+ "@napi-rs/wasm-runtime": "0.2.4",
+ "@tybys/wasm-util": "0.9.0",
+ "@yarnpkg/lockfile": "1.1.0",
+ "@zkochan/js-yaml": "0.0.7",
+ "ansi-regex": "5.0.1",
+ "ansi-styles": "4.3.0",
+ "argparse": "2.0.1",
+ "balanced-match": "4.0.3",
+ "base64-js": "1.5.1",
+ "bl": "4.1.0",
+ "brace-expansion": "5.0.12",
+ "buffer": "5.7.1",
+ "bundle-name": "4.1.0",
+ "chalk": "4.1.2",
+ "cli-cursor": "3.1.0",
+ "cli-spinners": "2.6.1",
+ "cliui": "8.0.1",
+ "clone": "1.0.4",
+ "color-convert": "2.0.1",
+ "color-name": "1.1.4",
+ "default-browser": "5.2.1",
+ "default-browser-id": "5.0.0",
+ "defaults": "1.0.4",
+ "define-lazy-prop": "3.0.0",
+ "dotenv": "16.4.7",
+ "dotenv-expand": "12.0.3",
+ "ejs": "5.0.1",
+ "emoji-regex": "8.0.0",
+ "end-of-stream": "1.4.5",
+ "escalade": "3.2.0",
+ "escape-string-regexp": "1.0.5",
+ "fast-string-truncated-width": "3.0.3",
+ "fast-string-width": "3.0.2",
+ "fast-wrap-ansi": "0.2.0",
+ "figures": "3.2.0",
+ "fs-constants": "1.0.0",
+ "get-caller-file": "2.0.5",
+ "has-flag": "4.0.0",
+ "ieee754": "1.2.1",
+ "ignore": "7.0.6",
+ "inherits": "2.0.4",
+ "is-docker": "3.0.0",
+ "is-fullwidth-code-point": "3.0.0",
+ "is-inside-container": "1.0.0",
+ "is-interactive": "1.0.0",
+ "is-unicode-supported": "0.1.0",
+ "is-wsl": "3.1.0",
+ "isexe": "2.0.0",
+ "json5": "2.2.3",
+ "jsonc-parser": "3.3.1",
+ "lines-and-columns": "2.0.3",
+ "log-symbols": "4.1.0",
+ "mimic-fn": "2.1.0",
+ "minimatch": "10.2.5",
+ "minimist": "1.2.8",
+ "npm-run-path": "4.0.1",
+ "once": "1.4.0",
+ "onetime": "5.1.2",
+ "open": "10.1.0",
+ "ora": "5.4.1",
+ "path-key": "3.1.1",
+ "picocolors": "1.1.1",
+ "readable-stream": "3.6.2",
+ "require-directory": "2.1.1",
+ "resolve.exports": "2.0.3",
+ "restore-cursor": "3.1.0",
+ "run-applescript": "7.0.0",
+ "safe-buffer": "5.2.1",
+ "semver": "7.8.5",
+ "signal-exit": "3.0.7",
+ "sisteransi": "1.0.5",
+ "smol-toml": "1.9.0",
+ "string_decoder": "1.3.0",
+ "string-width": "4.2.3",
+ "strip-ansi": "6.0.1",
+ "strip-bom": "3.0.0",
+ "supports-color": "7.2.0",
+ "tar-stream": "2.2.0",
+ "tmp": "0.2.7",
+ "tsconfig-paths": "4.2.0",
+ "tslib": "2.8.1",
+ "undici": "7.29.0",
+ "util-deprecate": "1.0.2",
+ "wcwidth": "1.0.1",
+ "which": "3.0.1",
+ "wrap-ansi": "7.0.0",
+ "wrappy": "1.0.2",
+ "y18n": "5.0.8",
+ "yaml": "2.9.0",
+ "yargs": "17.7.2",
+ "yargs-parser": "21.1.1"
+ },
+ "bin": {
+ "nx": "dist/bin/nx.js",
+ "nx-cloud": "dist/bin/nx-cloud.js"
+ },
+ "optionalDependencies": {
+ "@nx/nx-darwin-arm64": "23.3.1",
+ "@nx/nx-darwin-x64": "23.3.1",
+ "@nx/nx-freebsd-x64": "23.3.1",
+ "@nx/nx-linux-arm-gnueabihf": "23.3.1",
+ "@nx/nx-linux-arm64-gnu": "23.3.1",
+ "@nx/nx-linux-arm64-musl": "23.3.1",
+ "@nx/nx-linux-x64-gnu": "23.3.1",
+ "@nx/nx-linux-x64-musl": "23.3.1",
+ "@nx/nx-win32-arm64-msvc": "23.3.1",
+ "@nx/nx-win32-x64-msvc": "23.3.1"
+ },
+ "peerDependencies": {
+ "@swc-node/register": "^1.11.1",
+ "@swc/core": "^1.15.8"
+ },
+ "peerDependenciesMeta": {
+ "@swc-node/register": {
+ "optional": true
+ },
+ "@swc/core": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/nx/node_modules/balanced-match": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.3.tgz",
+ "integrity": "sha512-1pHv8LX9CpKut1Zp4EXey7Z8OfH11ONNH6Dhi2WDUt31VVZFXZzKwXcysBgqSumFCmR+0dqjMK5v5JiFHzi0+g==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "20 || >=22"
+ }
+ },
+ "node_modules/nx/node_modules/fast-wrap-ansi": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/fast-wrap-ansi/-/fast-wrap-ansi-0.2.0.tgz",
+ "integrity": "sha512-rLV8JHxTyhVmFYhBJuMujcrHqOT2cnO5Zxj37qROj23CP39GXubJRBUFF0z8KFK77Uc0SukZUf7JZhsVEQ6n8w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "fast-string-width": "^3.0.2"
+ }
+ },
+ "node_modules/nx/node_modules/figures": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz",
+ "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "escape-string-regexp": "^1.0.5"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/nx/node_modules/is-unicode-supported": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz",
+ "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/nx/node_modules/minimatch": {
+ "version": "10.2.5",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz",
+ "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==",
+ "dev": true,
+ "license": "BlueOak-1.0.0",
+ "dependencies": {
+ "brace-expansion": "^5.0.5"
+ },
+ "engines": {
+ "node": "18 || 20 || >=22"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/nx/node_modules/npm-run-path": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz",
+ "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "path-key": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/nx/node_modules/path-key": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
+ "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/nx/node_modules/signal-exit": {
+ "version": "3.0.7",
+ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz",
+ "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/nx/node_modules/string-width": {
+ "version": "4.2.3",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
+ "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "emoji-regex": "^8.0.0",
+ "is-fullwidth-code-point": "^3.0.0",
+ "strip-ansi": "^6.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/nx/node_modules/undici": {
+ "version": "7.29.0",
+ "resolved": "https://registry.npmjs.org/undici/-/undici-7.29.0.tgz",
+ "integrity": "sha512-IDxfleLmmbSskfWSUATiN1nfn2rDuvnMOqb5CWR92iIfojA0Ud+ulOAAEQ57LPr9rWmsreUyf5lwyao+7GNNVw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=20.18.1"
+ }
+ },
+ "node_modules/nx/node_modules/which": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/which/-/which-3.0.1.tgz",
+ "integrity": "sha512-XA1b62dzQzLfaEOSQFTCOd5KFf/1VSzZo7/7TUjnya6u0vGGKzU96UQBZTAThCb2j4/xjBAyii1OhRLJEivHvg==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "isexe": "^2.0.0"
+ },
+ "bin": {
+ "node-which": "bin/which.js"
+ },
+ "engines": {
+ "node": "^14.17.0 || ^16.13.0 || >=18.0.0"
+ }
+ },
+ "node_modules/nx/node_modules/yargs": {
+ "version": "17.7.2",
+ "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz",
+ "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "cliui": "^8.0.1",
+ "escalade": "^3.1.1",
+ "get-caller-file": "^2.0.5",
+ "require-directory": "^2.1.1",
+ "string-width": "^4.2.3",
+ "y18n": "^5.0.5",
+ "yargs-parser": "^21.1.1"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/once": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
+ "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "wrappy": "1"
+ }
+ },
+ "node_modules/onetime": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz",
+ "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "mimic-fn": "^2.1.0"
+ },
+ "engines": {
+ "node": ">=6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/open": {
+ "version": "10.1.0",
+ "resolved": "https://registry.npmjs.org/open/-/open-10.1.0.tgz",
+ "integrity": "sha512-mnkeQ1qP5Ue2wd+aivTD3NHd/lZ96Lu0jgf0pwktLPtx6cTZiH7tyeGRRHs0zX0rbrahXPnXlUnbeXyaBBuIaw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "default-browser": "^5.2.1",
+ "define-lazy-prop": "^3.0.0",
+ "is-inside-container": "^1.0.0",
+ "is-wsl": "^3.1.0"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/ora": {
+ "version": "5.4.1",
+ "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz",
+ "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "bl": "^4.1.0",
+ "chalk": "^4.1.0",
+ "cli-cursor": "^3.1.0",
+ "cli-spinners": "^2.5.0",
+ "is-interactive": "^1.0.0",
+ "is-unicode-supported": "^0.1.0",
+ "log-symbols": "^4.1.0",
+ "strip-ansi": "^6.0.0",
+ "wcwidth": "^1.0.1"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/ora/node_modules/is-unicode-supported": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz",
+ "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/p-limit": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
+ "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "p-try": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/p-locate": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
+ "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "p-limit": "^2.2.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/p-map": {
+ "version": "7.0.8",
+ "resolved": "https://registry.npmjs.org/p-map/-/p-map-7.0.8.tgz",
+ "integrity": "sha512-MitaVsCuCFIvOLLPIU7NnfrZvS9H9h7kwMUkDo+T2pEISaJD48IV9S8iIdXB7PsvvdxyYcsSTTrr90XKsbulNw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/p-queue": {
+ "version": "9.3.3",
+ "resolved": "https://registry.npmjs.org/p-queue/-/p-queue-9.3.3.tgz",
+ "integrity": "sha512-NXAOdnEe5FsZJfT4oK84lE1Y5cFFdWlRuOo5tww8DyNMxyRXwn39fIkUtNLKppcPC+UYU/bXujNCUGDv01y7CA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "eventemitter3": "^5.0.4",
+ "p-timeout": "^7.0.0"
+ },
+ "engines": {
+ "node": ">=20"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/p-timeout": {
+ "version": "7.0.2",
+ "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-7.0.2.tgz",
+ "integrity": "sha512-prbX4Z3YszrFNgH+MW5Zoeq3baXrMtP/MQnFeET90UB/GtGcGDQ5Usg9OCy6ETjTTntOw1SL2z9fMPUppN3Guw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=20"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/p-try": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
+ "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/pacote": {
+ "version": "22.0.0",
+ "resolved": "https://registry.npmjs.org/pacote/-/pacote-22.0.0.tgz",
+ "integrity": "sha512-++VqeOZeL03uGM2MFLk96jGCSt1owBGkyFKoPr+trwNlZhCpjN2RrvwYxt8nTbs1wNMqSFYurq0TafVWkAIHig==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "@gar/promise-retry": "^1.0.0",
+ "@npmcli/git": "^8.0.0",
+ "@npmcli/installed-package-contents": "^5.0.0",
+ "@npmcli/package-json": "^8.0.0",
+ "@npmcli/promise-spawn": "^10.0.0",
+ "@npmcli/run-script": "^11.0.0",
+ "cacache": "^21.0.1",
+ "fs-minipass": "^3.0.0",
+ "minipass": "^7.0.2",
+ "npm-package-arg": "^14.0.0",
+ "npm-packlist": "^11.2.0",
+ "npm-pick-manifest": "^12.0.0",
+ "npm-registry-fetch": "^20.0.1",
+ "proc-log": "^7.0.0",
+ "sigstore": "^5.0.0",
+ "ssri": "^14.0.0",
+ "tar": "^7.4.3"
+ },
+ "bin": {
+ "pacote": "bin/index.js"
+ },
+ "engines": {
+ "node": "^22.22.2 || ^24.15.0 || >=26.0.0"
+ }
+ },
+ "node_modules/parent-module": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
+ "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "callsites": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/parse-conflict-json": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/parse-conflict-json/-/parse-conflict-json-6.0.0.tgz",
+ "integrity": "sha512-JIdsITvN0yVRpYxiip9DpCduYi75AryIDSCf6ez/Yul6PV46L0B/8SxSvLiMmWiUZKopLrD1BZgexxCfufoT9w==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "json-parse-even-better-errors": "^6.0.0",
+ "just-diff": "^6.0.0",
+ "just-diff-apply": "^5.2.0"
+ },
+ "engines": {
+ "node": "^22.22.2 || ^24.15.0 || >=26.0.0"
+ }
+ },
+ "node_modules/parse-json": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz",
+ "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/code-frame": "^7.0.0",
+ "error-ex": "^1.3.1",
+ "json-parse-even-better-errors": "^2.3.0",
+ "lines-and-columns": "^1.1.6"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/parse-json/node_modules/json-parse-even-better-errors": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz",
+ "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/parse-json/node_modules/lines-and-columns": {
+ "version": "1.2.4",
+ "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz",
+ "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/parse-ms": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/parse-ms/-/parse-ms-4.0.0.tgz",
+ "integrity": "sha512-TXfryirbmq34y8QBwgqCVLi+8oA3oWx2eAnSn62ITyEhEYaWRlVZ2DvMM9eZbMs/RfxPu/PK/aBLyGj4IrqMHw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/parse-path": {
+ "version": "7.1.0",
+ "resolved": "https://registry.npmjs.org/parse-path/-/parse-path-7.1.0.tgz",
+ "integrity": "sha512-EuCycjZtfPcjWk7KTksnJ5xPMvWGA/6i4zrLYhRG0hGvC3GPU/jGUj3Cy+ZR0v30duV3e23R95T1lE2+lsndSw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "protocols": "^2.0.0"
+ }
+ },
+ "node_modules/parse-url": {
+ "version": "9.2.0",
+ "resolved": "https://registry.npmjs.org/parse-url/-/parse-url-9.2.0.tgz",
+ "integrity": "sha512-bCgsFI+GeGWPAvAiUv63ZorMeif3/U0zaXABGJbOWt5OH2KCaPHF6S+0ok4aqM9RuIPGyZdx9tR9l13PsW4AYQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/parse-path": "^7.0.0",
+ "parse-path": "^7.0.0"
+ },
+ "engines": {
+ "node": ">=14.13.0"
+ }
+ },
+ "node_modules/path-exists": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
+ "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/path-key": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz",
+ "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/path-scurry": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.2.tgz",
+ "integrity": "sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==",
+ "dev": true,
+ "license": "BlueOak-1.0.0",
+ "dependencies": {
+ "lru-cache": "^11.0.0",
+ "minipass": "^7.1.2"
+ },
+ "engines": {
+ "node": "18 || 20 || >=22"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/picocolors": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
+ "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/picomatch": {
+ "version": "4.0.7",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.7.tgz",
+ "integrity": "sha512-qcJu88Q2IWqJsDD529JKMdwGm/dvInW4HvQnRwiH9JtihJvzGOscDtHE3x1pBKeUOTysQ8kVmLnJ2kJu7yhcGA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/jonschlinkert"
+ }
+ },
+ "node_modules/pkg-dir": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz",
+ "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "find-up": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/postcss-selector-parser": {
+ "version": "7.1.7",
+ "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.7.tgz",
+ "integrity": "sha512-wWBro/7hJ40ye6TPiXkUQoXKCw23xSsjriUvqd7Uls9Sso3oLiON1flc18cCdnjgCRXw4fBVqUJJeOdDTh3P3g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "cssesc": "^3.0.0",
+ "util-deprecate": "^1.0.2"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/pretty-ms": {
+ "version": "9.3.1",
+ "resolved": "https://registry.npmjs.org/pretty-ms/-/pretty-ms-9.3.1.tgz",
+ "integrity": "sha512-HzMy3Geq23nVALD/M2LliU+F+M+gVNsvkQWWqeBZ8HDiCgzo6YPJ/Omrmtq24EFrIsk0a3EkQGEd7bDOo+IhGA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "parse-ms": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/proc-log": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-7.0.0.tgz",
+ "integrity": "sha512-FYgfaA69XZ93zaXLoMNQ+ViDXGGBgR8aLh03txzcFhV+9xOXx7+8DLCULrKKpR9+GsH9ZfHm82aSUPpozX0Ztg==",
+ "dev": true,
+ "license": "ISC",
+ "engines": {
+ "node": "^22.22.2 || ^24.15.0 || >=26.0.0"
+ }
+ },
+ "node_modules/proggy": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/proggy/-/proggy-4.0.0.tgz",
+ "integrity": "sha512-MbA4R+WQT76ZBm/5JUpV9yqcJt92175+Y0Bodg3HgiXzrmKu7Ggq+bpn6y6wHH+gN9NcyKn3yg1+d47VaKwNAQ==",
+ "dev": true,
+ "license": "ISC",
+ "engines": {
+ "node": "^20.17.0 || >=22.9.0"
+ }
+ },
+ "node_modules/promise-all-reject-late": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/promise-all-reject-late/-/promise-all-reject-late-1.0.1.tgz",
+ "integrity": "sha512-vuf0Lf0lOxyQREH7GDIOUMLS7kz+gs8i6B+Yi8dC68a2sychGrHTJYghMBD6k7eUcH0H5P73EckCA48xijWqXw==",
+ "dev": true,
+ "license": "ISC",
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/promise-call-limit": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/promise-call-limit/-/promise-call-limit-3.0.2.tgz",
+ "integrity": "sha512-mRPQO2T1QQVw11E7+UdCJu7S61eJVWknzml9sC1heAdj1jxl0fWMBypIt9ZOcLFf8FkG995ZD7RnVk7HH72fZw==",
+ "dev": true,
+ "license": "ISC",
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/promzard": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/promzard/-/promzard-4.0.0.tgz",
+ "integrity": "sha512-zqf38XGznB+ECFHQPGt0RNQCh0YF+r5iac0EZloSQlEWDxt0vCS39PEtUShBJOZU0tcJ+USPvmnyGo+3CEFwcQ==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "read": "^6.0.0"
+ },
+ "engines": {
+ "node": "^22.22.2 || ^24.15.0 || >=26.0.0"
+ }
+ },
+ "node_modules/protocols": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/protocols/-/protocols-2.0.2.tgz",
+ "integrity": "sha512-hHVTzba3wboROl0/aWRRG9dMytgH6ow//STBZh43l/wQgmMhYhOFi0EHWAPtoCz9IAUymsyP0TSBHkhgMEGNnQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/proxy-agent-negotiate": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/proxy-agent-negotiate/-/proxy-agent-negotiate-1.1.0.tgz",
+ "integrity": "sha512-N8IBcM3UgCVzz2L2Lqv8DVntDnnC8/hiV4nEDUPkqq72TPUgYWjQc+bdZlBPZK9LzPAvOY//gAt0S0DApoOXWQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 20"
+ },
+ "peerDependencies": {
+ "kerberos": "^2.0.0"
+ },
+ "peerDependenciesMeta": {
+ "kerberos": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/read": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/read/-/read-6.0.0.tgz",
+ "integrity": "sha512-Tg/LaEke7h9SDbp0xJJj53oa4s1VPPySVnxQF9nUS9DgA25M/ZCLk7RVF1kHjytC87XbkgQKmQ/79+DQgEIqLA==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "mute-stream": "^4.0.0"
+ },
+ "engines": {
+ "node": "^22.22.2 || ^24.15.0 || >=26.0.0"
+ }
+ },
+ "node_modules/read-cmd-shim": {
+ "version": "7.0.1",
+ "resolved": "https://registry.npmjs.org/read-cmd-shim/-/read-cmd-shim-7.0.1.tgz",
+ "integrity": "sha512-GhAsW4iJS0xNqv8P6HocT3gb5HCKHtEBKLIN7fE2oWr27jGIEihu48lXyGGeexkbiLv1XAbwyXvgjYMfT81kZA==",
+ "dev": true,
+ "license": "ISC",
+ "engines": {
+ "node": "^22.22.2 || ^24.15.0 || >=26.0.0"
+ }
+ },
+ "node_modules/read/node_modules/mute-stream": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-4.0.0.tgz",
+ "integrity": "sha512-gSrprq0fJ3EiOErzjdIZrjysVVmJ4uu1QWfCDss5LypA5OXvrMje5Ym5z6V6RLyJ2eF87lasX7t6a0AnFvZblg==",
+ "dev": true,
+ "license": "ISC",
+ "engines": {
+ "node": "^22.22.2 || ^24.15.0 || >=26.0.0"
+ }
+ },
+ "node_modules/readable-stream": {
+ "version": "3.6.2",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
+ "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "inherits": "^2.0.3",
+ "string_decoder": "^1.1.1",
+ "util-deprecate": "^1.0.1"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/require-directory": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
+ "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/resolve-cwd": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz",
+ "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "resolve-from": "^5.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/resolve-cwd/node_modules/resolve-from": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz",
+ "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/resolve-from": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
+ "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/resolve.exports": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.3.tgz",
+ "integrity": "sha512-OcXjMsGdhL4XnbShKpAcSqPMzQoYkYyhbEaeSko47MjRP9NfEQMhZkXL1DoFlt9LWQn4YttrdnV6X2OiyzBi+A==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/restore-cursor": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz",
+ "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "onetime": "^5.1.0",
+ "signal-exit": "^3.0.2"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/restore-cursor/node_modules/signal-exit": {
+ "version": "3.0.7",
+ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz",
+ "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/run-applescript": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-7.0.0.tgz",
+ "integrity": "sha512-9by4Ij99JUr/MCFBUkDKLWK3G9HVXmabKz9U5MlIAIuvuzkiOicRYs8XJLxX+xahD+mLiiCYDqF9dKAgtzKP1A==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/run-async": {
+ "version": "4.0.6",
+ "resolved": "https://registry.npmjs.org/run-async/-/run-async-4.0.6.tgz",
+ "integrity": "sha512-IoDlSLTs3Yq593mb3ZoKWKXMNu3UpObxhgA/Xuid5p4bbfi2jdY1Hj0m1K+0/tEuQTxIGMhQDqGjKb7RuxGpAQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.12.0"
+ }
+ },
+ "node_modules/safe-buffer": {
+ "version": "5.2.1",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
+ "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "license": "MIT"
+ },
+ "node_modules/safer-buffer": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
+ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/semver": {
+ "version": "7.8.5",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz",
+ "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==",
+ "dev": true,
+ "license": "ISC",
+ "bin": {
+ "semver": "bin/semver.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/signal-exit": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz",
+ "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==",
+ "dev": true,
+ "license": "ISC",
+ "engines": {
+ "node": ">=14"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/sigstore": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/sigstore/-/sigstore-5.0.0.tgz",
+ "integrity": "sha512-hJqJfoG/e4qFQaauQL00c6J6FrHLBGKtkFvW3JbTSIEFOhLrSjdSM/gWd/yUOfYo/gsERehTXGC1VZWX+9X4Dg==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@sigstore/bundle": "^5.0.0",
+ "@sigstore/core": "^4.0.0",
+ "@sigstore/protobuf-specs": "^0.5.0",
+ "@sigstore/sign": "^5.0.0",
+ "@sigstore/tuf": "^5.0.0",
+ "@sigstore/verify": "^4.0.0"
+ },
+ "engines": {
+ "node": "^22.22.2 || ^24.15.0 || >=26.0.0"
+ }
+ },
+ "node_modules/sisteransi": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz",
+ "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/smart-buffer": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz",
+ "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 6.0.0",
+ "npm": ">= 3.0.0"
+ }
+ },
+ "node_modules/smol-toml": {
+ "version": "1.9.0",
+ "resolved": "https://registry.npmjs.org/smol-toml/-/smol-toml-1.9.0.tgz",
+ "integrity": "sha512-hpd+HLON7HdZXqYchMM/+LaTTbdK0AU3NngIJ4KVyWbY9bfQqdL9cD+4yf6dUoU2Ap4VsU0JkQi6FxAI1B2mXQ==",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "engines": {
+ "node": ">= 18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/cyyynthia"
+ }
+ },
+ "node_modules/socks": {
+ "version": "2.8.10",
+ "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.10.tgz",
+ "integrity": "sha512-e0VyvkVTwVYViNovRkZ9aodhxVlyoMn7eJhVUPxZ+eK9P/7CBkxvvsBOHqFPEH416726W8tLXXXjKwqgTErrCQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ip-address": "^10.1.1",
+ "smart-buffer": "^4.2.0"
+ },
+ "engines": {
+ "node": ">= 10.0.0",
+ "npm": ">= 3.0.0"
+ }
+ },
+ "node_modules/socks-proxy-agent": {
+ "version": "10.1.0",
+ "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-10.1.0.tgz",
+ "integrity": "sha512-WlMj/67cEJ6MDI1OcsnjuYKDNDoyPCCYZ249kuuXPiMDw9F8PXkVaQ7YWu3siTydfQ/4BEZcvGzu+aYvz7dDCQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "agent-base": "9.0.0",
+ "debug": "^4.3.4",
+ "socks": "^2.8.3"
+ },
+ "engines": {
+ "node": ">= 20"
+ }
+ },
+ "node_modules/source-map": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/spdx-exceptions": {
+ "version": "2.5.0",
+ "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz",
+ "integrity": "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==",
+ "dev": true,
+ "license": "CC-BY-3.0"
+ },
+ "node_modules/spdx-expression-parse": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-4.0.0.tgz",
+ "integrity": "sha512-Clya5JIij/7C6bRR22+tnGXbc4VKlibKSVj2iHvVeX5iMW7s1SIQlqu699JkODJJIhh/pUu8L0/VLh8xflD+LQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "spdx-exceptions": "^2.1.0",
+ "spdx-license-ids": "^3.0.0"
+ }
+ },
+ "node_modules/spdx-license-ids": {
+ "version": "3.0.24",
+ "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.24.tgz",
+ "integrity": "sha512-cLS9TtWkIQFyLkJ3/5aFQAOHOSKTlOs/7WDut/XPSdjom1fJhUdkepeJAKXa9Y05+FabHd0sti+Et559vDtkpQ==",
+ "dev": true,
+ "license": "CC0-1.0"
+ },
+ "node_modules/ssri": {
+ "version": "14.0.0",
+ "resolved": "https://registry.npmjs.org/ssri/-/ssri-14.0.0.tgz",
+ "integrity": "sha512-jQxKI0yx0ZnTKrqjKkLDV2DXkBQn3k49JVmVqDGcDwKDtGDbImD/GXsq04KD0VVzCQQ9wZJYal3RwR1GzWTSow==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "minipass": "^7.0.3"
+ },
+ "engines": {
+ "node": "^22.22.2 || ^24.15.0 || >=26.0.0"
+ }
+ },
+ "node_modules/string_decoder": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
+ "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "safe-buffer": "~5.2.0"
+ }
+ },
+ "node_modules/string-width": {
+ "version": "8.3.0",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-8.3.0.tgz",
+ "integrity": "sha512-ZbmZM0JCihQN91dWnxoipT2KOEyHqEyfRXUyjuRhW8b/xnqPDoq4gWEVApTVa9db2wN8mmoikgFBbjh71+cGeQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "get-east-asian-width": "^1.5.0",
+ "strip-ansi": "^7.1.2"
+ },
+ "engines": {
+ "node": ">=20"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/string-width/node_modules/ansi-regex": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.5.0.tgz",
+ "integrity": "sha512-zhvbbbdt1kbw7EJ9OQoxmQcuaNR9P5kTj7e/YdmOSU10aHWbycofJxA6jKfoEy3vlLdctOF9ZHaxLtmSm998wQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-regex?sponsor=1"
+ }
+ },
+ "node_modules/string-width/node_modules/strip-ansi": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz",
+ "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ansi-regex": "^6.2.2"
+ },
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/strip-ansi?sponsor=1"
+ }
+ },
+ "node_modules/strip-ansi": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+ "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ansi-regex": "^5.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/strip-bom": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz",
+ "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/strip-final-newline": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-4.0.0.tgz",
+ "integrity": "sha512-aulFJcD6YK8V1G7iRB5tigAP4TsHBZZrOV8pjV++zdUwmeV8uzbY7yn6h9MswN62adStNZFuCIx4haBnRuMDaw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/supports-color": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+ "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "has-flag": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/tar": {
+ "version": "7.5.22",
+ "resolved": "https://registry.npmjs.org/tar/-/tar-7.5.22.tgz",
+ "integrity": "sha512-MFO/QzvtAOmJbkhOaCTvbGcFN9L9b+JunIsDwaKljSOdcLMea3NJ1k9Usz/rjdfSXTq4dfzfeS7W4p4YOAAHeA==",
+ "dev": true,
+ "license": "BlueOak-1.0.0",
+ "dependencies": {
+ "@isaacs/fs-minipass": "^4.0.0",
+ "chownr": "^3.0.0",
+ "minipass": "^7.1.2",
+ "minizlib": "^3.1.0",
+ "yallist": "^5.0.0"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/tar-stream": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz",
+ "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "bl": "^4.0.3",
+ "end-of-stream": "^1.4.1",
+ "fs-constants": "^1.0.0",
+ "inherits": "^2.0.3",
+ "readable-stream": "^3.1.1"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/tinyglobby": {
+ "version": "0.2.17",
+ "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz",
+ "integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "fdir": "^6.5.0",
+ "picomatch": "^4.0.4"
+ },
+ "engines": {
+ "node": ">=12.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/SuperchupuDev"
+ }
+ },
+ "node_modules/tmp": {
+ "version": "0.2.7",
+ "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.7.tgz",
+ "integrity": "sha512-e0votIpp4Uo2AJYSzVHV6xCcawuiez3DzqDAbrTc3YxBkplN6e+dM13ZeIcZnDg/QpSuU2zfZ3rzwY8ukEnaXw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=14.14"
+ }
+ },
+ "node_modules/treeverse": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/treeverse/-/treeverse-3.0.0.tgz",
+ "integrity": "sha512-gcANaAnd2QDZFmHFEOF4k7uc1J/6a6z3DJMd/QwEyxLoKGiptJRwid582r7QIsFlFMIZ3SnxfS52S4hm2DHkuQ==",
+ "dev": true,
+ "license": "ISC",
+ "engines": {
+ "node": "^14.17.0 || ^16.13.0 || >=18.0.0"
+ }
+ },
+ "node_modules/tsconfig-paths": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-4.2.0.tgz",
+ "integrity": "sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "json5": "^2.2.2",
+ "minimist": "^1.2.6",
+ "strip-bom": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/tslib": {
+ "version": "2.8.1",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
+ "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
+ "dev": true,
+ "license": "0BSD"
+ },
+ "node_modules/tuf-js": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/tuf-js/-/tuf-js-6.0.1.tgz",
+ "integrity": "sha512-o59N1PU8xk0bBV3HpJ4jjwldIeze17yXW1XTv02CEEKdC3E/tnJDU3CPWDNT4IZpkx9Srv9v1DJZ+JTdo46THg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@gar/promise-retry": "^1.0.3",
+ "@tufjs/models": "5.0.1",
+ "debug": "^4.4.3"
+ },
+ "engines": {
+ "node": "^22.22.2 || ^24.15.0 || >=26.0.0"
+ }
+ },
+ "node_modules/uglify-js": {
+ "version": "3.19.3",
+ "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.19.3.tgz",
+ "integrity": "sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "optional": true,
+ "bin": {
+ "uglifyjs": "bin/uglifyjs"
+ },
+ "engines": {
+ "node": ">=0.8.0"
+ }
+ },
+ "node_modules/undici": {
+ "version": "8.12.3",
+ "resolved": "https://registry.npmjs.org/undici/-/undici-8.12.3.tgz",
+ "integrity": "sha512-+fdndUTwBP86cVjihTp21hZHo7d6oj1c/47XPA3lL8mM0XHs+C4EkcjmgRsFnFk2f/UONGDy9ItBItmXsLOQHw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=22.19.0"
+ }
+ },
+ "node_modules/unicorn-magic": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.3.0.tgz",
+ "integrity": "sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/universal-user-agent": {
+ "version": "7.0.3",
+ "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-7.0.3.tgz",
+ "integrity": "sha512-TmnEAEAsBJVZM/AADELsK76llnwcf9vMKuPz8JflO1frO8Lchitr0fNaN9d+Ap0BjKtqWqd/J17qeDnXh8CL2A==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/universalify": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz",
+ "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 10.0.0"
+ }
+ },
+ "node_modules/util-deprecate": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
+ "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/validate-npm-package-name": {
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-8.0.0.tgz",
+ "integrity": "sha512-SCv6OOV6Xj2/3cXy3dGmADluJTNcL3o7hZAglNPTe+WYuEuvxgJzxPrSDLZhF+CwyQOubqgecjMmTJGMVLWjYQ==",
+ "dev": true,
+ "license": "ISC",
+ "engines": {
+ "node": "^22.22.2 || ^24.15.0 || >=26.0.0"
+ }
+ },
+ "node_modules/verkit": {
+ "version": "0.5.0",
+ "resolved": "https://registry.npmjs.org/verkit/-/verkit-0.5.0.tgz",
+ "integrity": "sha512-u4J1hr6Y+C/hit34GwL3eIcUf3wngT8TlYUjK7tk0jxydKLAq3sYvifjdTDA6U3KCKRcQCQDGf/srjxfZF3l7g==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=18.12.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sxzz"
+ }
+ },
+ "node_modules/walk-up-path": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/walk-up-path/-/walk-up-path-4.0.0.tgz",
+ "integrity": "sha512-3hu+tD8YzSLGuFYtPRb48vdhKMi0KQV5sn+uWr8+7dMEq/2G/dtLrdDinkLjqq5TIbIBjYJ4Ax/n3YiaW7QM8A==",
+ "dev": true,
+ "license": "ISC",
+ "engines": {
+ "node": "20 || >=22"
+ }
+ },
+ "node_modules/wcwidth": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz",
+ "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "defaults": "^1.0.3"
+ }
+ },
+ "node_modules/which": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/which/-/which-7.0.0.tgz",
+ "integrity": "sha512-RancgH2dmbLdHl6LRhEqvklWMgl/Hdnun0Y90KhBOLkMefg8Qa7/Zel8Sm+8HEcP6DEjzsWzpkuBQEZok58isA==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "isexe": "^4.0.0"
+ },
+ "bin": {
+ "node-which": "bin/which.js"
+ },
+ "engines": {
+ "node": "^22.22.2 || ^24.15.0 || >=26.0.0"
+ }
+ },
+ "node_modules/which-command": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/which-command/-/which-command-0.1.0.tgz",
+ "integrity": "sha512-XZyoF5/5hZtXitIwzrU4NKK+Wtbb9aB9CezUEw2Q0wlYK8NUYQxC1rRXgNueYLtBAJwXIb+/tFVk4dozciNJMA==",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "which-command": "cli.js"
+ },
+ "engines": {
+ "node": ">=22"
+ },
+ "funding": {
+ "url": "https://github.com/sindresorhus/which-command?sponsor=1"
+ }
+ },
+ "node_modules/which/node_modules/isexe": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/isexe/-/isexe-4.0.0.tgz",
+ "integrity": "sha512-FFUtZMpoZ8RqHS3XeXEmHWLA4thH+ZxCv2lOiPIn1Xc7CxrqhWzNSDzD+/chS/zbYezmiwWLdQC09JdQKmthOw==",
+ "dev": true,
+ "license": "BlueOak-1.0.0",
+ "engines": {
+ "node": ">=20"
+ }
+ },
+ "node_modules/wordwrap": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz",
+ "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/wrap-ansi": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
+ "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ansi-styles": "^4.0.0",
+ "string-width": "^4.1.0",
+ "strip-ansi": "^6.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
+ }
+ },
+ "node_modules/wrap-ansi/node_modules/string-width": {
+ "version": "4.2.3",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
+ "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "emoji-regex": "^8.0.0",
+ "is-fullwidth-code-point": "^3.0.0",
+ "strip-ansi": "^6.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/wrappy": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
+ "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/write-file-atomic": {
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-8.0.0.tgz",
+ "integrity": "sha512-dYwyZredl67GyLLIHJnRM3h2PcOmN5SkcgC7eM5DPDEOEl6dLFqVrMg3F1Ea32usj4VSVZtd2H4MtKTNOf6nPg==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "signal-exit": "^4.0.1"
+ },
+ "engines": {
+ "node": "^22.22.2 || ^24.15.0 || >=26.0.0"
+ }
+ },
+ "node_modules/y18n": {
+ "version": "5.0.8",
+ "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
+ "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==",
+ "dev": true,
+ "license": "ISC",
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/yallist": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz",
+ "integrity": "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==",
+ "dev": true,
+ "license": "BlueOak-1.0.0",
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/yaml": {
+ "version": "2.9.0",
+ "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.9.0.tgz",
+ "integrity": "sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA==",
+ "dev": true,
+ "license": "ISC",
+ "bin": {
+ "yaml": "bin.mjs"
+ },
+ "engines": {
+ "node": ">= 14.6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/eemeli"
+ }
+ },
+ "node_modules/yargs": {
+ "version": "18.2.0",
+ "resolved": "https://registry.npmjs.org/yargs/-/yargs-18.2.0.tgz",
+ "integrity": "sha512-9OpKOLeaoNFecEp7P6iYbzze/5CqWoH7N3SMs/6y1XF4nMvFMspEGZzJ6uFi9MmQwXhyzqYoSEKO3tvA3Z/o2w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "cliui": "^9.0.1",
+ "escalade": "^3.1.1",
+ "get-caller-file": "^2.0.5",
+ "string-width": "^8.2.1",
+ "y18n": "^5.0.5",
+ "yargs-parser": "^22.0.0"
+ },
+ "engines": {
+ "node": "^20.19.0 || ^22.12.0 || >=23"
+ }
+ },
+ "node_modules/yargs-parser": {
+ "version": "21.1.1",
+ "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz",
+ "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==",
+ "dev": true,
+ "license": "ISC",
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/yargs/node_modules/ansi-regex": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.5.0.tgz",
+ "integrity": "sha512-zhvbbbdt1kbw7EJ9OQoxmQcuaNR9P5kTj7e/YdmOSU10aHWbycofJxA6jKfoEy3vlLdctOF9ZHaxLtmSm998wQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-regex?sponsor=1"
+ }
+ },
+ "node_modules/yargs/node_modules/ansi-styles": {
+ "version": "6.2.3",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz",
+ "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+ }
+ },
+ "node_modules/yargs/node_modules/cliui": {
+ "version": "9.0.1",
+ "resolved": "https://registry.npmjs.org/cliui/-/cliui-9.0.1.tgz",
+ "integrity": "sha512-k7ndgKhwoQveBL+/1tqGJYNz097I7WOvwbmmU2AR5+magtbjPWQTS1C5vzGkBC8Ym8UWRzfKUzUUqFLypY4Q+w==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "string-width": "^7.2.0",
+ "strip-ansi": "^7.1.0",
+ "wrap-ansi": "^9.0.0"
+ },
+ "engines": {
+ "node": ">=20"
+ }
+ },
+ "node_modules/yargs/node_modules/cliui/node_modules/string-width": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz",
+ "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "emoji-regex": "^10.3.0",
+ "get-east-asian-width": "^1.0.0",
+ "strip-ansi": "^7.1.0"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/yargs/node_modules/emoji-regex": {
+ "version": "10.6.0",
+ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz",
+ "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/yargs/node_modules/strip-ansi": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz",
+ "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ansi-regex": "^6.2.2"
+ },
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/strip-ansi?sponsor=1"
+ }
+ },
+ "node_modules/yargs/node_modules/wrap-ansi": {
+ "version": "9.0.2",
+ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.2.tgz",
+ "integrity": "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ansi-styles": "^6.2.1",
+ "string-width": "^7.0.0",
+ "strip-ansi": "^7.1.0"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
+ }
+ },
+ "node_modules/yargs/node_modules/wrap-ansi/node_modules/string-width": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz",
+ "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "emoji-regex": "^10.3.0",
+ "get-east-asian-width": "^1.0.0",
+ "strip-ansi": "^7.1.0"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/yargs/node_modules/yargs-parser": {
+ "version": "22.0.0",
+ "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-22.0.0.tgz",
+ "integrity": "sha512-rwu/ClNdSMpkSrUb+d6BRsSkLUq1fmfsY6TOpYzTwvwkg1/NRG85KBy3kq++A8LKQwX6lsu+aWad+2khvuXrqw==",
+ "dev": true,
+ "license": "ISC",
+ "engines": {
+ "node": "^20.19.0 || ^22.12.0 || >=23"
+ }
+ },
+ "node_modules/yoctocolors": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/yoctocolors/-/yoctocolors-2.2.0.tgz",
+ "integrity": "sha512-xYqdZFUK/VYazNl/oCDYN+3WloWQwMfZxBoiNt6qNyk+xfOdi598muWE42rNZFp1kNOiqW936q5RhUdnpqElSg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ }
+ }
+}
diff --git a/tests/release/package.json b/tests/release/package.json
new file mode 100644
index 0000000..5a885d0
--- /dev/null
+++ b/tests/release/package.json
@@ -0,0 +1,10 @@
+{
+ "name": "nodejs-release-tests",
+ "private": true,
+ "scripts": {
+ "test": "node --test *.test.js"
+ },
+ "devDependencies": {
+ "lerna": "10.1.1"
+ }
+}
diff --git a/tests/release/project.test.js b/tests/release/project.test.js
new file mode 100644
index 0000000..6f82f55
--- /dev/null
+++ b/tests/release/project.test.js
@@ -0,0 +1,457 @@
+const assert = require("node:assert/strict");
+const { execFileSync } = require("node:child_process");
+const fs = require("node:fs");
+const os = require("node:os");
+const path = require("node:path");
+const { test } = require("node:test");
+const { ReleaseProject } = require("../../actions/release/ReleaseProject.js");
+
+Object.assign(process.env, {
+ CI: "true",
+ NX_DAEMON: "false",
+ NX_ISOLATE_PLUGINS: "false",
+ GIT_CONFIG_GLOBAL: "/dev/null",
+ GIT_CONFIG_NOSYSTEM: "1",
+ npm_config_offline: "true",
+ npm_config_audit: "false",
+ npm_config_fund: "false",
+});
+
+function fixture(t, versioning = "npm") {
+ const root = fs.mkdtempSync(path.join(os.tmpdir(), "nodejs-release-"));
+ t.after(() => fs.rmSync(root, { recursive: true, force: true }));
+ const directory = path.join(root, "project");
+ const remote = path.join(root, "remote.git");
+ fs.mkdirSync(directory);
+ const run = (command, args, cwd = directory) =>
+ execFileSync(command, args, {
+ cwd,
+ encoding: "utf8",
+ stdio: "pipe",
+ }).trim();
+ const git = (...args) => run("git", args);
+ const write = (file, content) => {
+ fs.mkdirSync(path.dirname(path.join(directory, file)), { recursive: true });
+ fs.writeFileSync(path.join(directory, file), content);
+ };
+ const json = (file, value) =>
+ write(file, `${JSON.stringify(value, null, 2)}\n`);
+ const commit = (message) => {
+ git("add", ".");
+ git("commit", "-m", message);
+ return git("rev-parse", "HEAD");
+ };
+ git("init", "--bare", remote);
+ git("init", "-b", "main");
+ git("config", "user.name", "Release test");
+ git("config", "user.email", "test@example.invalid");
+ git("remote", "add", "origin", remote);
+ write(".gitignore", "node_modules/\n.nx/\ndist/\n*.tgz\n");
+ if (versioning === "lerna") {
+ json("package.json", {
+ name: "workspaces-test",
+ private: true,
+ workspaces: ["packages/*"],
+ });
+ json("lerna.json", { version: "1.0.0", npmClient: "npm" });
+ json("packages/core/package.json", {
+ name: "@example/core",
+ version: "1.0.0",
+ });
+ json("packages/ui/package.json", {
+ name: "@example/ui",
+ version: "1.0.0",
+ dependencies: { "@example/core": "^1.0.0" },
+ });
+ json("packages/private/package.json", {
+ name: "@example/private",
+ version: "1.0.0",
+ private: true,
+ });
+ write("packages/core/index.js", "module.exports = 1;\n");
+ run("npm", ["install", "--package-lock-only", "--ignore-scripts"]);
+ fs.symlinkSync(
+ path.join(__dirname, "node_modules"),
+ path.join(directory, "node_modules"),
+ "dir",
+ );
+ } else {
+ json("package.json", {
+ name: "@example/cli",
+ version: "1.0.0",
+ type: "module",
+ main: "dist/index.js",
+ bin: { "example-cli": "bin/example-cli" },
+ files: ["dist", "bin", "CHANGELOG.md"],
+ scripts: { build: "node build.js" },
+ });
+ write(
+ "bin/example-cli",
+ "#!/usr/bin/env node\nimport { version } from '../dist/index.js';\nconsole.log(version);\n",
+ );
+ fs.chmodSync(path.join(directory, "bin/example-cli"), 0o755);
+ write(
+ "build.js",
+ "import fs from 'node:fs';\nconst { version } = JSON.parse(fs.readFileSync('package.json'));\nfs.mkdirSync('dist', { recursive: true });\nfs.writeFileSync('dist/index.js', 'export const version = ' + JSON.stringify(version) + ';');\n",
+ );
+ run("npm", ["install", "--package-lock-only", "--ignore-scripts"]);
+ }
+ commit("chore: initial");
+ git("tag", "-a", "v1.0.0", "-m", "v1.0.0");
+ git("push", "origin", "main", "--tags");
+ const dispatches = [];
+ const github = {
+ rest: {
+ actions: {
+ createWorkflowDispatch: async (args) => dispatches.push(args),
+ },
+ },
+ };
+ const plan = {
+ tag: "v1.1.0",
+ hasChanges: true,
+ body: "### Features\n\n* Add a command.\n",
+ };
+ const context = {
+ repo: { owner: "example", repo: "project" },
+ payload: { repository: { default_branch: "main" } },
+ ref: "refs/heads/main",
+ sha: git("rev-parse", "HEAD"),
+ };
+ const project = new ReleaseProject({
+ workspace: directory,
+ versioning,
+ github,
+ context,
+ });
+ const prepare = () =>
+ project.prepare({
+ workflowRef:
+ "example/project/.github/workflows/release.yml@refs/heads/main",
+ findRelease: async () => undefined,
+ plan,
+ });
+ return {
+ root,
+ directory,
+ remote,
+ run,
+ git,
+ write,
+ json,
+ commit,
+ plan,
+ dispatches,
+ github,
+ context,
+ project,
+ prepare,
+ };
+}
+
+test("an unchanged upstream plan skips source preparation and publication", async (t) => {
+ const f = fixture(t);
+ f.write("README.md", "Documentation only.");
+ f.context.sha = f.commit("docs: describe setup");
+ f.plan.hasChanges = false;
+ assert.equal((await f.prepare()).status, "no-changes");
+ assert.equal(f.project.version(), "1.0.0");
+ assert.equal(f.dispatches.length, 0);
+});
+
+test("single package applies the HoverKraft plan and packs an executable CLI", async (t) => {
+ const f = fixture(t);
+ f.write("CHANGELOG.md", "# Changelog\n\n## v1.0.0\n\nExisting history.\n");
+ f.context.sha = f.commit("feat: add output");
+ f.git("push", "origin", "main");
+ assert.deepEqual(await f.prepare(), { tag: "v1.1.0", status: "dispatched" });
+ const releaseSha = f.project.tagCommit("v1.1.0");
+ assert.notEqual(releaseSha, f.context.sha);
+ assert.equal(
+ f.run("git", ["rev-parse", "refs/heads/main"], f.remote),
+ releaseSha,
+ );
+ assert.equal(
+ f.project.readJson("package-lock.json").packages[""].version,
+ "1.1.0",
+ );
+ const changelog = fs.readFileSync(
+ path.join(f.directory, "CHANGELOG.md"),
+ "utf8",
+ );
+ assert.ok(changelog.includes(f.plan.body.trim()));
+ assert.ok(changelog.includes("Existing history."));
+ assert.deepEqual(f.dispatches, [
+ {
+ owner: "example",
+ repo: "project",
+ workflow_id: ".github/workflows/release.yml",
+ ref: "v1.1.0",
+ },
+ ]);
+ f.context.ref = "refs/tags/v1.1.0";
+ f.context.sha = releaseSha;
+ const ready = await f.prepare();
+ assert.equal(ready.status, "ready");
+ assert.deepEqual(ready.packages, [
+ {
+ name: "@example/cli",
+ version: "1.1.0",
+ directory: ".",
+ slug: "example-cli",
+ },
+ ]);
+ f.run("npm", ["run", "build"]);
+ const [packed] = JSON.parse(
+ f.run("npm", ["pack", "--json", "--pack-destination", f.root]),
+ );
+ const files = packed.files.map((file) => file.path);
+ for (const file of [
+ "bin/example-cli",
+ "dist/index.js",
+ "CHANGELOG.md",
+ "package.json",
+ ])
+ assert.ok(files.includes(file));
+ const installed = path.join(f.root, "installed");
+ fs.mkdirSync(installed);
+ f.run(
+ "npm",
+ ["install", path.join(f.root, packed.filename), "--ignore-scripts"],
+ installed,
+ );
+ assert.equal(
+ f.run("node", [
+ path.join(installed, "node_modules/@example/cli/bin/example-cli"),
+ ]),
+ "1.1.0",
+ );
+});
+
+for (const mode of ["npm", "lerna"]) {
+ test(`${mode} preserves an existing tag when the planned version collides`, async (t) => {
+ const f = fixture(t, mode);
+ f.git("tag", "v1.1.0");
+ f.git("push", "origin", "refs/tags/v1.1.0");
+ const original = f.project.tagCommit("v1.1.0");
+ f.write(
+ mode === "lerna" ? "packages/core/index.js" : "feature.txt",
+ "new feature",
+ );
+ f.context.sha = f.commit("feat: add output");
+ f.git("push", "origin", "main");
+ await assert.rejects(f.prepare(), /Existing tag/);
+ assert.equal(f.project.tagCommit("v1.1.0"), original);
+ assert.equal(
+ f.run("git", ["rev-parse", "refs/heads/main"], f.remote),
+ f.context.sha,
+ );
+ assert.equal(f.dispatches.length, 0);
+ });
+
+ test(`${mode} applies a planned version without recomputing its increment`, async (t) => {
+ const f = fixture(t, mode);
+ f.write(
+ mode === "lerna" ? "packages/core/index.js" : "feature.txt",
+ "fixed output",
+ );
+ f.context.sha = f.commit("fix: correct output");
+ f.git("push", "origin", "main");
+ f.plan.tag = "3.2.1";
+ assert.equal((await f.prepare()).tag, "3.2.1");
+ assert.equal(f.project.version(), "3.2.1");
+ assert.equal(f.project.tagCommit("3.2.1"), f.git("rev-parse", "HEAD"));
+ });
+
+ test(`${mode} rejects invalid, older or missing plans before changing source`, async (t) => {
+ const f = fixture(t, mode);
+ f.write("feature.txt", "new feature");
+ f.context.sha = f.commit("feat: add output");
+ for (const tag of ["v0.9.0", "v1.0.0", "v1.0.1-rc.1", "latest"]) {
+ f.plan.tag = tag;
+ await assert.rejects(f.prepare(), /newer|stable version tag/);
+ assert.equal(f.git("rev-parse", "HEAD"), f.context.sha);
+ }
+ f.plan.tag = "v1.1.0";
+ f.plan.body = "";
+ await assert.rejects(f.prepare(), /release notes/);
+ await assert.rejects(f.project.prepare({}), /release plan/);
+ assert.equal(f.dispatches.length, 0);
+ });
+}
+
+for (const [message, version] of [
+ ["fix: correct output", "1.0.1"],
+ ["feat: add output", "1.1.0"],
+ ["feat: change output\n\nBREAKING CHANGE: output is now structured", "2.0.0"],
+]) {
+ test(`Lerna applies planned ${version}, updates dependent packages and resumes the tag`, async (t) => {
+ const f = fixture(t, "lerna");
+ f.write("packages/core/index.js", "module.exports = 2;\n");
+ f.context.sha = f.commit(message);
+ f.plan.tag = `v${version}`;
+ f.git("push", "origin", "main");
+ assert.deepEqual(await f.prepare(), {
+ tag: `v${version}`,
+ status: "dispatched",
+ });
+ assert.equal(f.project.readJson("lerna.json").version, version);
+ assert.equal(
+ f.project.readJson("packages/ui/package.json").dependencies[
+ "@example/core"
+ ],
+ `^${version}`,
+ );
+ assert.equal(
+ f.project.readJson("package-lock.json").packages["packages/core"].version,
+ version,
+ );
+ assert.match(
+ fs.readFileSync(
+ path.join(f.directory, "packages/core/CHANGELOG.md"),
+ "utf8",
+ ),
+ new RegExp(version.replaceAll(".", "\\.")),
+ );
+ f.context.sha = f.git("rev-parse", "HEAD");
+ f.context.ref = `refs/tags/v${version}`;
+ const ready = await f.prepare();
+ assert.equal(ready.status, "ready");
+ assert.deepEqual(ready.packages.map((item) => item.name).sort(), [
+ "@example/core",
+ "@example/ui",
+ ]);
+ assert.equal(f.git("rev-parse", "HEAD"), f.context.sha);
+ });
+}
+
+test("Lerna skips a commit that changes no packages", async (t) => {
+ const f = fixture(t, "lerna");
+ f.write("README.md", "Documentation only.");
+ f.context.sha = f.commit("docs: describe setup");
+ f.git("push", "origin", "main");
+ assert.equal((await f.prepare()).status, "no-changes");
+ assert.equal(f.dispatches.length, 0);
+});
+
+for (const mode of ["npm", "lerna"]) {
+ test(`${mode} rejects both commit and tag when the default branch advances`, async (t) => {
+ const f = fixture(t, mode);
+ f.write("packages/core/index.js", "module.exports = 2;\n");
+ f.context.sha = f.commit("feat: add output");
+ f.git("push", "origin", "main");
+ f.write("later.txt", "concurrent main commit");
+ const advanced = f.commit("docs: update main");
+ f.git("push", "origin", "main");
+ await assert.rejects(f.prepare());
+ assert.equal(
+ f.run("git", ["rev-parse", "refs/heads/main"], f.remote),
+ advanced,
+ );
+ assert.throws(() =>
+ f.run("git", ["rev-parse", "refs/tags/v1.1.0"], f.remote),
+ );
+ });
+}
+
+test("published releases skip dispatch and tag recovery preserves their notes", async (t) => {
+ const f = fixture(t, "lerna");
+ const release = { draft: false, html_url: "https://example.invalid/release" };
+ const result = await f.project.prepare({
+ workflowRef: "",
+ findRelease: async () => release,
+ });
+ assert.equal(result.status, "released");
+ assert.equal(f.dispatches.length, 0);
+ f.context.ref = "refs/tags/v1.0.0";
+ assert.equal(
+ (await f.project.prepare({ findRelease: async () => release })).published,
+ true,
+ );
+});
+
+test("branch recovery dispatches an unfinished tagged version without planning again", async (t) => {
+ const f = fixture(t);
+ f.write("feature.txt", "feature");
+ f.context.sha = f.commit("feat: add output");
+ f.git("push", "origin", "main");
+ await f.prepare();
+ f.context.sha = f.git("rev-parse", "HEAD");
+ const result = await f.project.prepare({
+ workflowRef: "example/project/.github/workflows/release.yml@main",
+ findRelease: async () => ({ draft: true }),
+ });
+ assert.equal(result.tag, "v1.1.0");
+ assert.equal(result.status, "dispatched");
+ assert.equal(f.dispatches.length, 2);
+});
+
+test("a nested npm project preserves the directory-scoped planned tag", async (t) => {
+ const f = fixture(t);
+ const nested = path.join(f.directory, "tools", "cli");
+ fs.mkdirSync(nested, { recursive: true });
+ for (const name of ["package.json", "package-lock.json", "build.js", "bin"]) {
+ fs.renameSync(path.join(f.directory, name), path.join(nested, name));
+ }
+ f.context.sha = f.commit("feat: relocate CLI");
+ f.git("push", "origin", "main");
+ const project = new ReleaseProject({
+ workspace: f.directory,
+ workingDirectory: "tools/cli",
+ github: f.github,
+ context: f.context,
+ });
+ const result = await project.prepare({
+ workflowRef: "example/project/.github/workflows/release.yml@main",
+ findRelease: async () => undefined,
+ plan: { ...f.plan, tag: "cli-1.1.0" },
+ });
+ assert.equal(result.tag, "cli-1.1.0");
+ assert.equal(project.version(), "1.1.0");
+ assert.equal(project.packages(result.tag)[0].directory, ".");
+ f.context.sha = f.git("rev-parse", "HEAD");
+ assert.equal(project.currentTag(), "cli-1.1.0");
+});
+
+test("ambiguous version tags require explicit tag recovery", (t) => {
+ const f = fixture(t);
+ f.git("tag", "1.0.0");
+ assert.throws(() => f.project.currentTag(), /Several release tags/);
+ f.context.ref = "refs/tags/1.0.0";
+ assert.equal(f.project.currentTag(), "1.0.0");
+});
+
+test("rejects unsupported layouts, versions, refs and mismatched tags", async (t) => {
+ const f = fixture(t);
+ assert.throws(
+ () => new ReleaseProject({ workspace: f.directory, versioning: "unknown" }),
+ /versioning/,
+ );
+ assert.throws(
+ () =>
+ new ReleaseProject({
+ workspace: f.directory,
+ workingDirectory: "..",
+ versioning: "npm",
+ }),
+ /inside/,
+ );
+ f.context.ref = "refs/heads/feature";
+ await assert.rejects(f.prepare(), /default branch/);
+ f.context.ref = "refs/tags/v9.0.0";
+ await assert.rejects(f.prepare(), /committed package version/);
+ f.json("package.json", { name: "private", private: true, version: "1.0.0" });
+ assert.throws(
+ () =>
+ new ReleaseProject({
+ workspace: f.directory,
+ versioning: "npm",
+ }),
+ /one public package/,
+ );
+ f.json("lerna.json", { version: "independent" });
+ assert.throws(
+ () => new ReleaseProject({ workspace: f.directory, versioning: "lerna" }),
+ /stable version/,
+ );
+});