diff --git a/.github/workflows/pr-title.yml b/.github/workflows/pr-title.yml new file mode 100644 index 00000000..6057734d --- /dev/null +++ b/.github/workflows/pr-title.yml @@ -0,0 +1,45 @@ +name: PR Title + +on: + workflow_dispatch: + inputs: + title: + description: PR title to validate + required: true + type: string + pull_request: + types: [opened, edited, synchronize, reopened, ready_for_review] + merge_group: + +permissions: + contents: read + pull-requests: read + +jobs: + pr-title: + name: pr-title + runs-on: ubuntu-latest + steps: + - name: Validate pull request title + if: github.event_name != 'merge_group' + env: + EVENT_NAME: ${{ github.event_name }} + PR_TITLE: ${{ github.event.pull_request.title }} + DISPATCH_TITLE: ${{ inputs.title }} + run: | + node <<'NODE' + const title = process.env.EVENT_NAME === 'workflow_dispatch' + ? process.env.DISPATCH_TITLE + : process.env.PR_TITLE; + const pattern = /^(feat|fix|docs|style|refactor|perf|test|build|ci|chore|revert|deps)(\([^)]+\))?!?: .+$/; + if (!title || !pattern.test(title)) { + console.error(`Invalid PR title: ${title || ''}`); + console.error('Expected Conventional Commit format, e.g. feat(renderer): add cursor support'); + process.exit(1); + } + console.log(`Valid PR title: ${title}`); + NODE + + - name: Merge queue title validation already completed + if: github.event_name == 'merge_group' + run: echo "Skipping merge_group; PR title was validated before entering the queue." diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 07a82d46..a9ed6e8e 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -1,34 +1,83 @@ name: publish on: + workflow_dispatch: + inputs: + tag: + description: Git tag to release, e.g. v0.5.0-rc.0 + required: true + type: string push: tags: - 'v*' workflow_run: workflows: ['ci'] - types: - - completed - branches: - - main + types: [completed] + branches: [main] permissions: - contents: write # Required for creating GitHub releases - id-token: write # Required for OIDC trusted publishing + contents: read + id-token: write jobs: - publish: - name: publish to npm + publish-stable: + name: publish stable packages runs-on: ubuntu-latest - # Only run if CI workflow succeeded (for workflow_run trigger) - if: ${{ github.event.workflow_run.conclusion == 'success' || github.event_name == 'push' }} + if: github.event_name == 'push' || github.event_name == 'workflow_dispatch' steps: - - name: Checkout code + - name: Resolve tag + id: tag + env: + INPUT_TAG: ${{ inputs.tag }} + REF_NAME: ${{ github.ref_name }} + run: | + set -euo pipefail + TAG="${INPUT_TAG:-$REF_NAME}" + if [[ -z "$TAG" || ! "$TAG" =~ ^v[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z.-]+)?$ ]]; then + echo "Expected a vX.Y.Z or vX.Y.Z-prerelease tag, got '$TAG'" >&2 + exit 1 + fi + echo "tag=$TAG" >> "$GITHUB_OUTPUT" + VERSION="${TAG#v}" + if [[ "$VERSION" == *-* ]]; then + NPM_TAG="${VERSION#*-}" + NPM_TAG="${NPM_TAG%%.*}" + else + NPM_TAG="latest" + fi + echo "version=$VERSION" >> "$GITHUB_OUTPUT" + echo "npm_tag=$NPM_TAG" >> "$GITHUB_OUTPUT" + + - name: Checkout tag uses: actions/checkout@v4 with: - ref: ${{ github.ref }} - fetch-depth: 0 # Required for git describe to find tags + ref: ${{ steps.tag.outputs.tag }} + fetch-depth: 0 submodules: recursive + - name: Validate tag and source versions + env: + TAG: ${{ steps.tag.outputs.tag }} + VERSION: ${{ steps.tag.outputs.version }} + run: | + set -euo pipefail + git fetch origin main --tags + if ! git merge-base --is-ancestor "$TAG" origin/main; then + echo "Tag $TAG is not an ancestor of origin/main" >&2 + exit 1 + fi + node <<'NODE' + const fs = require('fs'); + const version = process.env.VERSION; + const root = JSON.parse(fs.readFileSync('package.json', 'utf8')).version; + const demo = JSON.parse(fs.readFileSync('demo/package.json', 'utf8')).version; + const flake = fs.readFileSync('flake.nix', 'utf8').match(/version = "([^"]+)";/)?.[1]; + for (const [name, value] of Object.entries({ root, demo, flake })) { + if (value !== version) throw new Error(`${name} version ${value} does not match tag version ${version}`); + } + console.log(`Validated source versions for ${version}`); + NODE + - name: Setup Bun uses: oven-sh/setup-bun@v1 with: @@ -39,11 +88,8 @@ jobs: with: version: 0.15.2 - - name: Build WASM - run: ./scripts/build-wasm.sh - - name: Install dependencies - run: bun install + run: bun install --frozen-lockfile - name: Check formatting run: bun run fmt @@ -60,178 +106,188 @@ jobs: - name: Build library run: bun run build + - name: Check WASM size + run: | + SIZE=$(stat -c%s ghostty-vt.wasm) + echo "WASM size: $SIZE bytes" + if [ "$SIZE" -gt 524288 ]; then + echo "āŒ Error: WASM exceeds 512 KiB limit" + exit 1 + fi + - name: Setup Node.js for npm uses: actions/setup-node@v4 with: node-version: '20' registry-url: 'https://registry.npmjs.org' - # Ensure npm 11.5.1 or later for trusted publishing - - run: npm install -g npm@latest + - name: Ensure current npm for trusted publishing + run: npm install -g npm@latest - - name: Detect trigger type - id: detect + - name: Publish ghostty-web + env: + VERSION: ${{ steps.tag.outputs.version }} + NPM_TAG: ${{ steps.tag.outputs.npm_tag }} run: | - if [[ $GITHUB_REF == refs/tags/* ]]; then - echo "is_tag=true" >> $GITHUB_OUTPUT - echo "trigger_type=tag" >> $GITHUB_OUTPUT - echo "trigger_name=${GITHUB_REF#refs/tags/}" >> $GITHUB_OUTPUT - echo "šŸ“¦ Detected tag push: ${GITHUB_REF#refs/tags/}" + set -euo pipefail + PACKAGE_NAME=$(node -p "require('./package.json').name") + if npm view "${PACKAGE_NAME}@${VERSION}" version >/dev/null 2>&1; then + echo "${PACKAGE_NAME}@${VERSION} already exists; skipping publish" + npm dist-tag add "${PACKAGE_NAME}@${VERSION}" "${NPM_TAG}" || echo "Unable to repair ${NPM_TAG} dist-tag with current npm credentials; package already exists." else - echo "is_tag=false" >> $GITHUB_OUTPUT - echo "trigger_type=branch" >> $GITHUB_OUTPUT - echo "trigger_name=${GITHUB_REF#refs/heads/}" >> $GITHUB_OUTPUT - echo "🚧 Detected branch push: ${GITHUB_REF#refs/heads/}" + npm publish --tag "${NPM_TAG}" --provenance --access public fi - - name: Generate version - id: version + - name: Pin and validate demo package + env: + VERSION: ${{ steps.tag.outputs.version }} run: | - if [[ "${{ steps.detect.outputs.is_tag }}" == "true" ]]; then - # For tags, extract version from git tag (strip 'v' prefix) - NPM_VERSION="${GITHUB_REF#refs/tags/v}" - NPM_TAG="latest" - echo "šŸ“¦ Publishing stable release: ${NPM_VERSION}" - else - # Get base version from latest tag for pre-releases - LATEST_TAG=$(git describe --tags --abbrev=0) - BASE_VERSION="${LATEST_TAG#v}" - # For main branch, create a pre-release version using git describe - # Format: 0.3.0-next.5.g1a2b3c4 (base-next.commits.hash) - GIT_COMMIT=$(git rev-parse --short HEAD) - COMMITS_SINCE_TAG=$(git rev-list --count HEAD ^$(git describe --tags --abbrev=0 2>/dev/null || echo HEAD) 2>/dev/null || echo "0") - NPM_VERSION="${BASE_VERSION}-next.${COMMITS_SINCE_TAG}.g${GIT_COMMIT}" - NPM_TAG="next" - echo "🚧 Publishing pre-release: ${NPM_VERSION}" - fi - - echo "version=${NPM_VERSION}" >> $GITHUB_OUTPUT - echo "tag=${NPM_TAG}" >> $GITHUB_OUTPUT - - # Update package.json with the new version - node -e "const fs = require('fs'); const pkg = JSON.parse(fs.readFileSync('package.json')); pkg.version = '${NPM_VERSION}'; fs.writeFileSync('package.json', JSON.stringify(pkg, null, 2) + '\n');" - - echo "Updated package.json to version ${NPM_VERSION}" - - - name: Check if version exists - id: check-exists + set -euo pipefail + node <<'NODE' + const fs = require('fs'); + const version = process.env.VERSION; + const path = 'demo/package.json'; + const pkg = JSON.parse(fs.readFileSync(path, 'utf8')); + pkg.version = version; + pkg.dependencies['ghostty-web'] = version; + fs.writeFileSync(path, JSON.stringify(pkg, null, 2) + '\n'); + console.log(`Pinned @ghostty-web/demo to ghostty-web ${version}`); + NODE + + - name: Publish @ghostty-web/demo + working-directory: demo + env: + VERSION: ${{ steps.tag.outputs.version }} + NPM_TAG: ${{ steps.tag.outputs.npm_tag }} run: | + set -euo pipefail PACKAGE_NAME=$(node -p "require('./package.json').name") - VERSION="${{ steps.version.outputs.version }}" - - if npm view "${PACKAGE_NAME}@${VERSION}" version &>/dev/null; then - echo "exists=true" >> $GITHUB_OUTPUT - echo "Version ${VERSION} already exists on npm" + if npm view "${PACKAGE_NAME}@${VERSION}" version >/dev/null 2>&1; then + echo "${PACKAGE_NAME}@${VERSION} already exists; skipping publish" + npm dist-tag add "${PACKAGE_NAME}@${VERSION}" "${NPM_TAG}" || echo "Unable to repair ${NPM_TAG} dist-tag with current npm credentials; package already exists." else - echo "exists=false" >> $GITHUB_OUTPUT - echo "Version ${VERSION} does not exist, will publish" + npm publish --tag "${NPM_TAG}" --provenance --access public fi - - name: Publish to npm (with OIDC trusted publishing) - if: steps.check-exists.outputs.exists == 'false' - run: npm publish --tag ${{ steps.version.outputs.tag }} --provenance --access public + publish-next: + name: publish next packages + runs-on: ubuntu-latest + if: github.event_name == 'workflow_run' && github.event.workflow_run.conclusion == 'success' + steps: + - name: Checkout CI head + uses: actions/checkout@v4 + with: + ref: ${{ github.event.workflow_run.head_sha }} + fetch-depth: 0 + submodules: recursive - - name: Update dist-tag (version already exists) - if: steps.check-exists.outputs.exists == 'true' && steps.detect.outputs.is_tag == 'true' + - name: Skip release commits + id: release-commit + env: + HEAD_SHA: ${{ github.event.workflow_run.head_sha }} run: | - PACKAGE_NAME=$(node -p "require('./package.json').name") - VERSION="${{ steps.version.outputs.version }}" - TAG="${{ steps.version.outputs.tag }}" + set -euo pipefail + SUBJECT=$(git log -1 --format=%s "$HEAD_SHA") + echo "subject=$SUBJECT" + if [[ "$SUBJECT" =~ ^chore\(release\):\ ]]; then + echo "skip=true" >> "$GITHUB_OUTPUT" + echo "Skipping next publish for release commit" + else + echo "skip=false" >> "$GITHUB_OUTPUT" + fi - echo "Version ${VERSION} already published, updating dist-tag to ${TAG}" - npm dist-tag add "${PACKAGE_NAME}@${VERSION}" "${TAG}" + - name: Setup Bun + if: steps.release-commit.outputs.skip != 'true' + uses: oven-sh/setup-bun@v1 + with: + bun-version: latest - - name: Skip (pre-release already exists) - if: steps.check-exists.outputs.exists == 'true' && steps.detect.outputs.is_tag != 'true' - run: | - echo "ā­ļø Pre-release version already exists, skipping" + - name: Setup Zig + if: steps.release-commit.outputs.skip != 'true' + uses: ./.github/actions/setup-zig + with: + version: 0.15.2 - - name: Create GitHub Release - if: steps.detect.outputs.is_tag == 'true' - run: gh release create "${{ steps.detect.outputs.trigger_name }}" --title "${{ steps.detect.outputs.trigger_name }}" --generate-notes --verify-tag - env: - GH_TOKEN: ${{ github.token }} + - name: Install dependencies + if: steps.release-commit.outputs.skip != 'true' + run: bun install --frozen-lockfile - publish-demo: - name: publish @ghostty-web/demo to npm - runs-on: ubuntu-latest - needs: publish - if: ${{ github.event.workflow_run.conclusion == 'success' || github.event_name == 'push' }} - steps: - - name: Checkout code - uses: actions/checkout@v4 - with: - ref: ${{ github.ref }} - fetch-depth: 0 + - name: Build library + if: steps.release-commit.outputs.skip != 'true' + run: bun run build - name: Setup Node.js for npm + if: steps.release-commit.outputs.skip != 'true' uses: actions/setup-node@v4 with: node-version: '20' registry-url: 'https://registry.npmjs.org' - - run: npm install -g npm@latest - - - name: Detect trigger type - id: detect - run: | - if [[ $GITHUB_REF == refs/tags/* ]]; then - echo "is_tag=true" >> $GITHUB_OUTPUT - echo "trigger_name=${GITHUB_REF#refs/tags/}" >> $GITHUB_OUTPUT - else - echo "is_tag=false" >> $GITHUB_OUTPUT - echo "trigger_name=${GITHUB_REF#refs/heads/}" >> $GITHUB_OUTPUT - fi + - name: Ensure current npm for trusted publishing + if: steps.release-commit.outputs.skip != 'true' + run: npm install -g npm@latest - - name: Generate demo version + - name: Compute next version + if: steps.release-commit.outputs.skip != 'true' id: version - working-directory: demo run: | - if [[ "${{ steps.detect.outputs.is_tag }}" == "true" ]]; then - # For tags, extract version from git tag (strip 'v' prefix) - NPM_VERSION="${GITHUB_REF#refs/tags/v}" - NPM_TAG="latest" - # Pin to exact version to avoid npx cache issues with transitive deps - GHOSTTY_WEB_DEP="${NPM_VERSION}" + set -euo pipefail + LATEST_TAG=$(git describe --tags --abbrev=0) + BASE_VERSION="${LATEST_TAG#v}" + SHORT_SHA=$(git rev-parse --short HEAD) + COMMITS_SINCE_TAG=$(git rev-list --count HEAD ^"$LATEST_TAG") + NEXT_VERSION="${BASE_VERSION}-next.${COMMITS_SINCE_TAG}.g${SHORT_SHA}" + echo "version=$NEXT_VERSION" >> "$GITHUB_OUTPUT" + echo "Publishing next version $NEXT_VERSION" + + - name: Prepare root package + if: steps.release-commit.outputs.skip != 'true' + env: + VERSION: ${{ steps.version.outputs.version }} + run: | + node <<'NODE' + const fs = require('fs'); + const pkg = JSON.parse(fs.readFileSync('package.json', 'utf8')); + pkg.version = process.env.VERSION; + fs.writeFileSync('package.json', JSON.stringify(pkg, null, 2) + '\n'); + NODE + + - name: Publish ghostty-web next + if: steps.release-commit.outputs.skip != 'true' + env: + VERSION: ${{ steps.version.outputs.version }} + run: | + set -euo pipefail + PACKAGE_NAME=$(node -p "require('./package.json').name") + if npm view "${PACKAGE_NAME}@${VERSION}" version >/dev/null 2>&1; then + echo "${PACKAGE_NAME}@${VERSION} already exists; skipping" else - # Get base version from latest tag for pre-releases - LATEST_TAG=$(git describe --tags --abbrev=0) - BASE_VERSION="${LATEST_TAG#v}" - GIT_COMMIT=$(git rev-parse --short HEAD) - COMMITS_SINCE_TAG=$(git rev-list --count HEAD ^${LATEST_TAG}) - NPM_VERSION="${BASE_VERSION}-next.${COMMITS_SINCE_TAG}.g${GIT_COMMIT}" - NPM_TAG="next" - # Pin to exact version to avoid npx cache issues with transitive deps - GHOSTTY_WEB_DEP="${NPM_VERSION}" + npm publish --tag next --provenance --access public fi - echo "version=${NPM_VERSION}" >> $GITHUB_OUTPUT - echo "tag=${NPM_TAG}" >> $GITHUB_OUTPUT - - # Update version and ghostty-web dependency - node -e " - const fs = require('fs'); - const pkg = JSON.parse(fs.readFileSync('package.json')); - pkg.version = '${NPM_VERSION}'; - pkg.dependencies['ghostty-web'] = '${GHOSTTY_WEB_DEP}'; - fs.writeFileSync('package.json', JSON.stringify(pkg, null, 2) + '\n'); - " - echo "Updated demo package.json: version=${NPM_VERSION}, ghostty-web=${GHOSTTY_WEB_DEP}" - - - name: Check if demo version exists - id: check-exists + - name: Prepare demo package + if: steps.release-commit.outputs.skip != 'true' + env: + VERSION: ${{ steps.version.outputs.version }} + run: | + node <<'NODE' + const fs = require('fs'); + const pkg = JSON.parse(fs.readFileSync('demo/package.json', 'utf8')); + pkg.version = process.env.VERSION; + pkg.dependencies['ghostty-web'] = process.env.VERSION; + fs.writeFileSync('demo/package.json', JSON.stringify(pkg, null, 2) + '\n'); + NODE + + - name: Publish @ghostty-web/demo next + if: steps.release-commit.outputs.skip != 'true' working-directory: demo + env: + VERSION: ${{ steps.version.outputs.version }} run: | + set -euo pipefail PACKAGE_NAME=$(node -p "require('./package.json').name") - VERSION="${{ steps.version.outputs.version }}" - - if npm view "${PACKAGE_NAME}@${VERSION}" version &>/dev/null; then - echo "exists=true" >> $GITHUB_OUTPUT + if npm view "${PACKAGE_NAME}@${VERSION}" version >/dev/null 2>&1; then + echo "${PACKAGE_NAME}@${VERSION} already exists; skipping" else - echo "exists=false" >> $GITHUB_OUTPUT + npm publish --tag next --provenance --access public fi - - - name: Publish demo to npm - if: steps.check-exists.outputs.exists == 'false' - working-directory: demo - run: npm publish --tag ${{ steps.version.outputs.tag }} --provenance --access public diff --git a/.github/workflows/release-please.yml b/.github/workflows/release-please.yml new file mode 100644 index 00000000..3f2b1a4a --- /dev/null +++ b/.github/workflows/release-please.yml @@ -0,0 +1,81 @@ +name: Release Please + +on: + workflow_dispatch: + push: + branches: [main] + +permissions: + actions: write + contents: write + issues: write + pull-requests: write + +concurrency: + group: release-please-${{ github.ref }} + cancel-in-progress: false + +jobs: + release-please: + name: release-please + runs-on: ubuntu-latest + steps: + - name: Checkout main + uses: actions/checkout@v4 + with: + fetch-depth: 0 + persist-credentials: false + + - name: Setup Bun + uses: oven-sh/setup-bun@v1 + with: + bun-version: latest + + - name: Install dependencies + env: + NPM_CONFIG_IGNORE_SCRIPTS: 'true' + run: bun install --frozen-lockfile + + - name: Test release tooling + run: bun test scripts/release-please-ai scripts/release-please-runner.test.ts + + - name: Run Release Please + id: release-please + env: + GITHUB_TOKEN: ${{ github.token }} + GITHUB_REPOSITORY: ${{ github.repository }} + ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} + RELEASE_NOTES_MODEL: ${{ vars.RELEASE_NOTES_MODEL }} + run: bun run release-please + + - name: Dispatch publish workflow for stable release + if: steps.release-please.outputs.releases_created == 'true' + env: + GH_TOKEN: ${{ github.token }} + RELEASE_TAGS: ${{ steps.release-please.outputs.release_tags }} + run: | + set -euo pipefail + for tag in $RELEASE_TAGS; do + echo "Dispatching publish.yml for $tag" + gh workflow run publish.yml --ref "$tag" --field "tag=$tag" + done + + - name: Dispatch checks for release PR branches + if: steps.release-please.outputs.prs_created == 'true' + env: + GH_TOKEN: ${{ github.token }} + PR_METADATA: ${{ steps.release-please.outputs.pr_metadata }} + run: | + set -euo pipefail + node <<'NODE' > /tmp/release-prs.tsv + const metadata = JSON.parse(process.env.PR_METADATA || '[]'); + for (const pr of metadata) { + if (!pr.branch || !pr.title) throw new Error(`Invalid PR metadata: ${JSON.stringify(pr)}`); + console.log(`${pr.branch}\t${pr.title}`); + } + NODE + while IFS=$'\t' read -r branch title; do + echo "Dispatching checks for $branch ($title)" + gh workflow run ci.yml --ref "$branch" + gh workflow run pr-title.yml --ref "$branch" --raw-field "title=$title" + done < /tmp/release-prs.tsv diff --git a/.release-please-manifest.json b/.release-please-manifest.json new file mode 100644 index 00000000..2537c1f1 --- /dev/null +++ b/.release-please-manifest.json @@ -0,0 +1,3 @@ +{ + ".": "0.4.0" +} diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 00000000..af268edb --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,98 @@ +# Changelog + +## [0.4.0](https://github.com/coder/ghostty-web/compare/v0.3.0...v0.4.0) (2025-12-09) + +### Features + +- Added DSR response handling for better nushell compatibility. +- Added dynamic font resizing support. +- Added IME input support for languages such as Chinese and Japanese. +- Migrated rendering internals to RenderState. +- Unified the demo HTTP/WebSocket server for reverse proxy compatibility. + +### Bug Fixes + +- Corrected application cursor mode (DECCKM) handling for arrow keys. +- Fixed Unicode grapheme cluster rendering for complex scripts. +- Fixed selection overflow during auto-scroll and integrated selection highlighting into cell rendering. +- Added `contenteditable` to prevent browser extension conflicts. +- Enabled linefeed mode so newline moves the cursor back to column 0. + +### Other Changes + +- Added iOS support. +- Enabled alpha transparency in the canvas context. +- Simplified the publishing flow for new tags. +- Updated README badges, demo links, and project description. + +## [0.3.0](https://github.com/coder/ghostty-web/compare/v0.2.1...v0.3.0) (2025-11-26) + +### Features + +- Added a one-line `npx @ghostty-web/demo@next` path for trying the library. +- Created and published the `@ghostty-web/demo` package. +- Implemented broader xterm.js-compatible API coverage. +- Simplified initialization with a module-level `init()` API. + +### Bug Fixes + +- Fixed demo package path resolution for installed and development builds. +- Improved demo terminal resizing to fit its container. +- Fixed multiple text highlighting and selection bugs. +- Persisted VT stream parser state across writes. +- Pinned the demo package to exact `ghostty-web` versions to avoid `npx` cache issues. +- Fixed terminal options not being passed to WASM. + +### Documentation + +- Updated README usage instructions and demo media. + +## [0.2.1](https://github.com/coder/ghostty-web/compare/v0.2.0...v0.2.1) (2025-11-19) + +### Other Changes + +- Switched the package license to MIT. + +## [0.2.0](https://github.com/coder/ghostty-web/compare/v0.1.1...v0.2.0) (2025-11-19) + +### Features + +- Improved xterm.js parity. +- Switched to Ghostty-native scrollback, alternate screen, and line wrapping support. +- Added scrolling support for the alternate screen. +- Implemented the buffer access API. +- Added hyperlink parsing, hyperlink rendering, and hover/clickable URL support. +- Added a right-click context menu. +- Added terminal modes API support. +- Improved scrollbar UX with auto-hide and interactive controls. +- Added smooth scrolling. + +### Bug Fixes + +- Fixed WASM build and Zig setup issues. +- Fixed duplicate paste behavior from the right-click context menu. +- Fixed copying text from scrollback and selected text ranges. +- Cleared text selection when clicking outside the canvas. +- Fixed npm publishing setup for main-branch and prepublish builds. + +### Other Changes + +- Redesigned the demo page and refreshed README documentation. + +## [0.1.1](https://github.com/coder/ghostty-web/compare/v0.1.0...v0.1.1) (2025-11-13) + +### Other Changes + +- Bumped the package version to 0.1.1. + +## [0.1.0](https://github.com/coder/ghostty-web/releases/tag/v0.1.0) (2025-11-13) + +### Features + +- Built the first Ghostty-backed WASM terminal prototype. +- Integrated Ghostty's VT parser and screen buffer with a Canvas renderer. +- Added keyboard input handling, terminal integration, FitAddon support, demos, and documentation. +- Added terminal text selection and paste support. +- Added optional WASM path auto-detection. +- Built WASM from the `ghostty-org/ghostty` submodule with repository patches. +- Added CI and npm trusted-publishing workflow setup. diff --git a/bun.lock b/bun.lock index 557c739b..5508ba54 100644 --- a/bun.lock +++ b/bun.lock @@ -1,24 +1,38 @@ { "lockfileVersion": 1, - "configVersion": 0, "workspaces": { "": { "name": "@cmux/ghostty-terminal", "devDependencies": { + "@ai-sdk/anthropic": "^4.0.0", "@biomejs/biome": "^1.9.4", "@happy-dom/global-registrator": "^15.11.0", "@types/bun": "^1.3.2", "@xterm/headless": "^5.5.0", "@xterm/xterm": "^5.5.0", + "ai": "^7.0.2", "mitata": "^1.0.34", "prettier": "^3.6.2", + "release-please": "17.9.0", + "tsx": "^4.22.4", "typescript": "^5.9.3", "vite": "^4.5.0", "vite-plugin-dts": "^4.5.4", + "zod": "^4.4.3", }, }, }, "packages": { + "@ai-sdk/anthropic": ["@ai-sdk/anthropic@4.0.0", "", { "dependencies": { "@ai-sdk/provider": "4.0.0", "@ai-sdk/provider-utils": "5.0.0" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-N0lT1g6/5DEIZvalpkpwYRCdu7n5qb8qPN3PcTem6k4VkPBLC2+T2LAAyx1GS0eNOxavVa0CP7n2kCiye0yyfw=="], + + "@ai-sdk/gateway": ["@ai-sdk/gateway@4.0.2", "", { "dependencies": { "@ai-sdk/provider": "4.0.0", "@ai-sdk/provider-utils": "5.0.0", "@vercel/oidc": "3.2.0" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-Jz1BiiTSvhDsCBJrkFRSqLHDRMVjFtYk9GdbSi3UOqY+/epza+oIESMDzfN4m+YHT/1IYmNEmxaMfjXOvxKDjQ=="], + + "@ai-sdk/provider": ["@ai-sdk/provider@4.0.0", "", { "dependencies": { "json-schema": "^0.4.0" } }, "sha512-fr9Gs89prDWiuox/T+kCA+i2cJkHpxU5S+tr4megjTzRC27ZsvFhwjU/+XrqqMbvBUlfmXxTOYWy8ng45dsjIg=="], + + "@ai-sdk/provider-utils": ["@ai-sdk/provider-utils@5.0.0", "", { "dependencies": { "@ai-sdk/provider": "4.0.0", "@standard-schema/spec": "^1.1.0", "@workflow/serde": "4.1.0", "eventsource-parser": "^3.0.8" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-zj66M02jc6ASYwIgWZowsooDUwaVngeNZQ3H10GwcPMZ+KR6gHMhcUuKl6tkai+JPXTKDyHY1pnszuxRtw2D4A=="], + + "@babel/code-frame": ["@babel/code-frame@7.29.7", "", { "dependencies": { "@babel/helper-validator-identifier": "^7.29.7", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" } }, "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw=="], + "@babel/helper-string-parser": ["@babel/helper-string-parser@7.27.1", "", {}, "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA=="], "@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@7.28.5", "", {}, "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q=="], @@ -45,58 +59,76 @@ "@biomejs/cli-win32-x64": ["@biomejs/cli-win32-x64@1.9.4", "", { "os": "win32", "cpu": "x64" }, "sha512-8Y5wMhVIPaWe6jw2H+KlEm4wP/f7EW3810ZLmDlrEEy5KvBsb9ECEfu/kMWD484ijfQ8+nIi0giMgu9g1UAuuA=="], - "@esbuild/android-arm": ["@esbuild/android-arm@0.18.20", "", { "os": "android", "cpu": "arm" }, "sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw=="], + "@conventional-commits/parser": ["@conventional-commits/parser@0.4.1", "", { "dependencies": { "unist-util-visit": "^2.0.3", "unist-util-visit-parents": "^3.1.1" } }, "sha512-H2ZmUVt6q+KBccXfMBhbBF14NlANeqHTXL4qCL6QGbMzrc4HDXyzWuxPxPNbz71f/5UkR5DrycP5VO9u7crahg=="], + + "@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.28.1", "", { "os": "aix", "cpu": "ppc64" }, "sha512-Svl7tq8k/08+p6CXPpRjQ1fKX+1odH/BQbb48fV6fj3CWHhsoIOoY87w1oHXm0qEpkIK3ZfVgp0hed3XBXzXMQ=="], - "@esbuild/android-arm64": ["@esbuild/android-arm64@0.18.20", "", { "os": "android", "cpu": "arm64" }, "sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ=="], + "@esbuild/android-arm": ["@esbuild/android-arm@0.28.1", "", { "os": "android", "cpu": "arm" }, "sha512-0k2F129Xdio1TdJfzJ8sy1Q47vUD2NnwdhiAf7drUN1EBTfPf4hsFCtmMgu/6m8JSzsBrlmVjudMBQqOfG8usQ=="], - "@esbuild/android-x64": ["@esbuild/android-x64@0.18.20", "", { "os": "android", "cpu": "x64" }, "sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg=="], + "@esbuild/android-arm64": ["@esbuild/android-arm64@0.28.1", "", { "os": "android", "cpu": "arm64" }, "sha512-34EGEbCIAgosYz6goLcopX6Mo7NyGv9tfwEM2/7Ce2VcVRk568iSvniGWcUXIy7wEDR1wzolcxcriFVrWYcwBg=="], - "@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.18.20", "", { "os": "darwin", "cpu": "arm64" }, "sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA=="], + "@esbuild/android-x64": ["@esbuild/android-x64@0.28.1", "", { "os": "android", "cpu": "x64" }, "sha512-dbwY7ltSMDWsRatcRpCnES4F+im88OCUgGZjy52shC7GqHRE/cYlxNbB4Z4UpJswpcc4Qxd2oE/ufM0p61IKng=="], - "@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.18.20", "", { "os": "darwin", "cpu": "x64" }, "sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ=="], + "@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.28.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-TZbWkQY7kvTAXbXUT7uVACR5cMHsDiSz9z7ZKAX/RTq/WJEk3QyRr0wZpNhBDX+/0CtdqUIJlOiodQcta6tY3Q=="], - "@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.18.20", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw=="], + "@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.28.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-zfdzgK9ACBNZLI/CyHTOx81SyNbM6YXn7rxSgX97VjyiPl9W1i4Ka4fgKECEoFCKGpvBj5qArWIGgQjOwkgskQ=="], - "@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.18.20", "", { "os": "freebsd", "cpu": "x64" }, "sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ=="], + "@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.28.1", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-wG2EA8ENdEI0qhkSZMjfqrdY+ziCYCPMmtZjjIwOmXFjmyzEHn+UUxk5of+SYsjtfs3VpnlC7QLzSI5hY/rOAw=="], - "@esbuild/linux-arm": ["@esbuild/linux-arm@0.18.20", "", { "os": "linux", "cpu": "arm" }, "sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg=="], + "@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.28.1", "", { "os": "freebsd", "cpu": "x64" }, "sha512-i7dZ9vQgnvSCzi/rYCXNgtF/U+eKZNJBzu3eTQbRgHnM7tNSizLOkRFAl3qzVc/Op/u5YkHHa4pf/3DOYHthLQ=="], - "@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.18.20", "", { "os": "linux", "cpu": "arm64" }, "sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA=="], + "@esbuild/linux-arm": ["@esbuild/linux-arm@0.28.1", "", { "os": "linux", "cpu": "arm" }, "sha512-qVXBOHQS+d5Y722GwJzJUtOLlX7km3CraOaGormF1pDtPd2C/l1SHRPgjLunLGe51Sh5YYWKMFDyV4SxgMQYTQ=="], - "@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.18.20", "", { "os": "linux", "cpu": "ia32" }, "sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA=="], + "@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.28.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-yHs+0uc8+nvEAfAfxrWQKK5peSNzBc4PegcMO0EJ2hT71uA7vB8Ihg2e77R2P7SG5uYjPbHlLLmve4LLLRCf0g=="], - "@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.18.20", "", { "os": "linux", "cpu": "none" }, "sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg=="], + "@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.28.1", "", { "os": "linux", "cpu": "ia32" }, "sha512-d1z4ZuP0ajrfz/FhGT4vv278rX8KnPPJx8i5+AtK7TYbx9Le9F1hyzurZpkEyjkGa9dUGhQow4C1NmeGvqxN2w=="], - "@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.18.20", "", { "os": "linux", "cpu": "none" }, "sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ=="], + "@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.28.1", "", { "os": "linux", "cpu": "none" }, "sha512-M5sRjUVZrkm1OAPR3dlOYzNmN+loZKGVi1VUQGrwuqLcbR6qeAz+famMhjASeH3YVKvZz+zT1jlh/keC3Rj/lg=="], - "@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.18.20", "", { "os": "linux", "cpu": "ppc64" }, "sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA=="], + "@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.28.1", "", { "os": "linux", "cpu": "none" }, "sha512-mRObBZeHh2OxcBFPWE/FjylkRgZdYuiTR3vaTozquCGOH14iP9oN4x4Ge81CoIDYQrXmIxpFumJBu5MtZpnQJQ=="], - "@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.18.20", "", { "os": "linux", "cpu": "none" }, "sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A=="], + "@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.28.1", "", { "os": "linux", "cpu": "ppc64" }, "sha512-slScBsMAb3GFDcdrCgLwZtPYRoH2H/youv10QiZyRjmsP48fznoveWytSgCI/R0ZcUgpc0ZhIUEx6LHts8yrfQ=="], - "@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.18.20", "", { "os": "linux", "cpu": "s390x" }, "sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ=="], + "@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.28.1", "", { "os": "linux", "cpu": "none" }, "sha512-kw0owk1o0GFETUJyW0jc0G4Yzs0BHZn0JDZ8JRT088vjJYX777BAs1fDGxAC+q831qOs2DTC96mNsG2opdfyyQ=="], - "@esbuild/linux-x64": ["@esbuild/linux-x64@0.18.20", "", { "os": "linux", "cpu": "x64" }, "sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w=="], + "@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.28.1", "", { "os": "linux", "cpu": "s390x" }, "sha512-/lAIjX8aYFRByhh6L5rYtPEDRqa9de/4V/juOXcta5frjvzXO4/sqEtyytse0g3zZFuWu5cDN0MkLz2qRDD2Ag=="], - "@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.18.20", "", { "os": "none", "cpu": "x64" }, "sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A=="], + "@esbuild/linux-x64": ["@esbuild/linux-x64@0.28.1", "", { "os": "linux", "cpu": "x64" }, "sha512-u/anNYF2mmVOEDwLtnQ1wOr3EZ9sTNGLWrsYGYwHWzGA3Si84IOkHXlbWTD1NB+9/1lcnweYKO54uhxZydNzfA=="], - "@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.18.20", "", { "os": "openbsd", "cpu": "x64" }, "sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg=="], + "@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.28.1", "", { "os": "none", "cpu": "arm64" }, "sha512-oks0DYbLwWMmaakTsCb+zL4E+aHRVLom9IJZOAthMQEPiQmydXHkziYEsGYRx0uNV/IjEKGAV941JzH02pflqw=="], - "@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.18.20", "", { "os": "sunos", "cpu": "x64" }, "sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ=="], + "@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.28.1", "", { "os": "none", "cpu": "x64" }, "sha512-aeL6lAnN89Hz43Mlh1G8ARasbuoYvSITDEx0tHh5b7jJnHcssqgjy9Yx430GDpmCa6OyrKoS0aNRjKundRizGg=="], - "@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.18.20", "", { "os": "win32", "cpu": "arm64" }, "sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg=="], + "@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.28.1", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-MEFJe5C3R8pwXdZ5Y21oo6m7ePiS0d9pWucn99O/wvyJZChoIQKrQDxKrGeW8F5+T0okTHesAmDeiHDTIq0V/Q=="], - "@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.18.20", "", { "os": "win32", "cpu": "ia32" }, "sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g=="], + "@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.28.1", "", { "os": "openbsd", "cpu": "x64" }, "sha512-i/ZLIOafE0Z8cI/XANJAixoJL/uRAoS2xOA3rb0xN+KK0K177cMAsQYkzHtBrtMXAKuAc7HGgcWiZ/sRC1Nxgw=="], - "@esbuild/win32-x64": ["@esbuild/win32-x64@0.18.20", "", { "os": "win32", "cpu": "x64" }, "sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ=="], + "@esbuild/openharmony-arm64": ["@esbuild/openharmony-arm64@0.28.1", "", { "os": "none", "cpu": "arm64" }, "sha512-ge+Z7EXFNt2BO1oAMsVpiQ8EwndV9i1xXerAeTIK7AtPs3bKFXQM7nlRxDSIUIMeueR1CNXxqztLzdNeReKBJg=="], + + "@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.28.1", "", { "os": "sunos", "cpu": "x64" }, "sha512-BEjgtECkL3vY+SaSQ6nzVfiALUeFxpawyp8Jmf5PtYhf1Ug40N1h/hxlhts+f1FvSvarEigdxS3BlSMI2PJLcQ=="], + + "@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.28.1", "", { "os": "win32", "cpu": "arm64" }, "sha512-lCv9eK/H6ZJWbE7bh2nw54CZ9M2nupBxJcTsdk/QQnWkdSjKGuxmmH8/GWrlT1eMmZfn4dGcCjRte397WqfQXA=="], + + "@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.28.1", "", { "os": "win32", "cpu": "ia32" }, "sha512-zvb/mB2bSCoJOpoCBgYKKpX6YM6mJBlBUVUtVj41DlZJVEB6/0CKlRYxP5wWl1C1ILiCoAU5wZZ4q1P3qeS6Eg=="], + + "@esbuild/win32-x64": ["@esbuild/win32-x64@0.28.1", "", { "os": "win32", "cpu": "x64" }, "sha512-bm4Mowrv+GXMlpWX++EcXw/iLyd1o3+bJkC2DkWXYVvgZCqD/bSj9ctZeAMC3cIxgjRVR2Dufaiu4YPxr5gW1A=="], + + "@google-automations/git-file-utils": ["@google-automations/git-file-utils@3.0.1", "", { "dependencies": { "@octokit/rest": "^20.1.1", "@octokit/types": "^13.0.0", "js-yaml": "^4.1.1", "minimatch": "^10.2.4" } }, "sha512-vlQZ8DlBcippB5zTY0M5Rib8tKT4yQ7oBKbs6kcWAzp70oyillKinXLZwlIgNTmfzzZx1J6cez3M0EmrpXFRcw=="], "@happy-dom/global-registrator": ["@happy-dom/global-registrator@15.11.7", "", { "dependencies": { "happy-dom": "^15.11.7" } }, "sha512-mfOoUlIw8VBiJYPrl5RZfMzkXC/z7gbSpi2ecycrj/gRWLq2CMV+Q+0G+JPjeOmuNFgg0skEIzkVFzVYFP6URw=="], + "@iarna/toml": ["@iarna/toml@3.0.0", "", {}, "sha512-td6ZUkz2oS3VeleBcN+m//Q6HlCFCPrnI0FZhrt/h4XqLEdOyYp2u21nd8MdsR+WJy5r9PTDaHTDDfhf4H4l6Q=="], + "@isaacs/balanced-match": ["@isaacs/balanced-match@4.0.1", "", {}, "sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ=="], "@isaacs/brace-expansion": ["@isaacs/brace-expansion@5.0.0", "", { "dependencies": { "@isaacs/balanced-match": "^4.0.1" } }, "sha512-ZT55BDLV0yv0RBm2czMiZ+SqCGO7AvmOM3G/w2xhVPH+te0aKgFjmBvGlL1dH+ql2tgGO3MVrbb3jCKyvpgnxA=="], "@jridgewell/sourcemap-codec": ["@jridgewell/sourcemap-codec@1.5.5", "", {}, "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og=="], + "@jsep-plugin/assignment": ["@jsep-plugin/assignment@1.3.0", "", { "peerDependencies": { "jsep": "^0.4.0||^1.0.0" } }, "sha512-VVgV+CXrhbMI3aSusQyclHkenWSAm95WaiKrMxRFam3JSUiIaQjoMIw2sEs/OX4XifnqeQUN4DYbJjlA8EfktQ=="], + + "@jsep-plugin/regex": ["@jsep-plugin/regex@1.0.4", "", { "peerDependencies": { "jsep": "^0.4.0||^1.0.0" } }, "sha512-q7qL4Mgjs1vByCaTnDFcBnV9HS7GVPJX5vyVoCgZHNSC9rjwIlmbXG5sUuorR5ndfHAIlJ8pVStxvjXHbNvtUg=="], + "@microsoft/api-extractor": ["@microsoft/api-extractor@7.55.0", "", { "dependencies": { "@microsoft/api-extractor-model": "7.32.0", "@microsoft/tsdoc": "~0.16.0", "@microsoft/tsdoc-config": "~0.18.0", "@rushstack/node-core-library": "5.18.0", "@rushstack/rig-package": "0.6.0", "@rushstack/terminal": "0.19.3", "@rushstack/ts-command-line": "5.1.3", "diff": "~8.0.2", "lodash": "~4.17.15", "minimatch": "10.0.3", "resolve": "~1.22.1", "semver": "~7.5.4", "source-map": "~0.6.1", "typescript": "5.8.2" }, "bin": { "api-extractor": "bin/api-extractor" } }, "sha512-TYc5OtAK/9E3HGgd2bIfSjQDYIwPc0dysf9rPiwXZGsq916I6W2oww9bhm1OxPOeg6rMfOX3PoroGd7oCryYog=="], "@microsoft/api-extractor-model": ["@microsoft/api-extractor-model@7.32.0", "", { "dependencies": { "@microsoft/tsdoc": "~0.16.0", "@microsoft/tsdoc-config": "~0.18.0", "@rushstack/node-core-library": "5.18.0" } }, "sha512-QIVJSreb8fGGJy1Qx0yzGVXxvHJN1WXgkFNHFheVv1iBJNqgvp+xeT3ienJmRwXmPPc5Es/cxBrXtKZJR3i7iw=="], @@ -105,6 +137,30 @@ "@microsoft/tsdoc-config": ["@microsoft/tsdoc-config@0.18.0", "", { "dependencies": { "@microsoft/tsdoc": "0.16.0", "ajv": "~8.12.0", "jju": "~1.4.0", "resolve": "~1.22.2" } }, "sha512-8N/vClYyfOH+l4fLkkr9+myAoR6M7akc8ntBJ4DJdWH2b09uVfr71+LTMpNyG19fNqWDg8KEDZhx5wxuqHyGjw=="], + "@octokit/auth-token": ["@octokit/auth-token@4.0.0", "", {}, "sha512-tY/msAuJo6ARbK6SPIxZrPBms3xPbfwBrulZe0Wtr/DIY9lje2HeV1uoebShn6mx7SjCHif6EjMvoREj+gZ+SA=="], + + "@octokit/core": ["@octokit/core@5.2.2", "", { "dependencies": { "@octokit/auth-token": "^4.0.0", "@octokit/graphql": "^7.1.0", "@octokit/request": "^8.4.1", "@octokit/request-error": "^5.1.1", "@octokit/types": "^13.0.0", "before-after-hook": "^2.2.0", "universal-user-agent": "^6.0.0" } }, "sha512-/g2d4sW9nUDJOMz3mabVQvOGhVa4e/BN/Um7yca9Bb2XTzPPnfTWHWQg+IsEYO7M3Vx+EXvaM/I2pJWIMun1bg=="], + + "@octokit/endpoint": ["@octokit/endpoint@9.0.6", "", { "dependencies": { "@octokit/types": "^13.1.0", "universal-user-agent": "^6.0.0" } }, "sha512-H1fNTMA57HbkFESSt3Y9+FBICv+0jFceJFPWDePYlR/iMGrwM5ph+Dd4XRQs+8X+PUFURLQgX9ChPfhJ/1uNQw=="], + + "@octokit/graphql": ["@octokit/graphql@7.1.1", "", { "dependencies": { "@octokit/request": "^8.4.1", "@octokit/types": "^13.0.0", "universal-user-agent": "^6.0.0" } }, "sha512-3mkDltSfcDUoa176nlGoA32RGjeWjl3K7F/BwHwRMJUW/IteSa4bnSV8p2ThNkcIcZU2umkZWxwETSSCJf2Q7g=="], + + "@octokit/openapi-types": ["@octokit/openapi-types@24.2.0", "", {}, "sha512-9sIH3nSUttelJSXUrmGzl7QUBFul0/mB8HRYl3fOlgHbIWG+WnYDXU3v/2zMtAvuzZ/ed00Ei6on975FhBfzrg=="], + + "@octokit/plugin-paginate-rest": ["@octokit/plugin-paginate-rest@11.4.4-cjs.2", "", { "dependencies": { "@octokit/types": "^13.7.0" }, "peerDependencies": { "@octokit/core": "5" } }, "sha512-2dK6z8fhs8lla5PaOTgqfCGBxgAv/le+EhPs27KklPhm1bKObpu6lXzwfUEQ16ajXzqNrKMujsFyo9K2eaoISw=="], + + "@octokit/plugin-request-log": ["@octokit/plugin-request-log@4.0.1", "", { "peerDependencies": { "@octokit/core": "5" } }, "sha512-GihNqNpGHorUrO7Qa9JbAl0dbLnqJVrV8OXe2Zm5/Y4wFkZQDfTreBzVmiRfJVfE4mClXdihHnbpyyO9FSX4HA=="], + + "@octokit/plugin-rest-endpoint-methods": ["@octokit/plugin-rest-endpoint-methods@13.3.2-cjs.1", "", { "dependencies": { "@octokit/types": "^13.8.0" }, "peerDependencies": { "@octokit/core": "^5" } }, "sha512-VUjIjOOvF2oELQmiFpWA1aOPdawpyaCUqcEBc/UOUnj3Xp6DJGrJ1+bjUIIDzdHjnFNO6q57ODMfdEZnoBkCwQ=="], + + "@octokit/request": ["@octokit/request@8.4.1", "", { "dependencies": { "@octokit/endpoint": "^9.0.6", "@octokit/request-error": "^5.1.1", "@octokit/types": "^13.1.0", "universal-user-agent": "^6.0.0" } }, "sha512-qnB2+SY3hkCmBxZsR/MPCybNmbJe4KAlfWErXq+rBKkQJlbjdJeS85VI9r8UqeLYLvnAenU8Q1okM/0MBsAGXw=="], + + "@octokit/request-error": ["@octokit/request-error@5.1.1", "", { "dependencies": { "@octokit/types": "^13.1.0", "deprecation": "^2.0.0", "once": "^1.4.0" } }, "sha512-v9iyEQJH6ZntoENr9/yXxjuezh4My67CBSu9r6Ve/05Iu5gNgnisNWOsoJHTP6k0Rr0+HQIpnH+kyammu90q/g=="], + + "@octokit/rest": ["@octokit/rest@20.1.2", "", { "dependencies": { "@octokit/core": "^5.0.2", "@octokit/plugin-paginate-rest": "11.4.4-cjs.2", "@octokit/plugin-request-log": "^4.0.0", "@octokit/plugin-rest-endpoint-methods": "13.3.2-cjs.1" } }, "sha512-GmYiltypkHHtihFwPRxlaorG5R9VAHuk/vbszVoRTGXnAsY60wYLkh/E2XiFmdZmqrisw+9FaazS1i5SbdWYgA=="], + + "@octokit/types": ["@octokit/types@13.10.0", "", { "dependencies": { "@octokit/openapi-types": "^24.2.0" } }, "sha512-ifLaO34EbbPj0Xgro4G5lP5asESjwHracYJvVaPIyXMuiuXLlhic3S47cBdTb+jfODkTE5YtGCLt3Ay3+J97sA=="], + "@rollup/pluginutils": ["@rollup/pluginutils@5.3.0", "", { "dependencies": { "@types/estree": "^1.0.0", "estree-walker": "^2.0.2", "picomatch": "^4.0.2" }, "peerDependencies": { "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" }, "optionalPeers": ["rollup"] }, "sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q=="], "@rushstack/node-core-library": ["@rushstack/node-core-library@5.18.0", "", { "dependencies": { "ajv": "~8.13.0", "ajv-draft-04": "~1.0.0", "ajv-formats": "~3.0.1", "fs-extra": "~11.3.0", "import-lazy": "~4.0.0", "jju": "~1.4.0", "resolve": "~1.22.1", "semver": "~7.5.4" }, "peerDependencies": { "@types/node": "*" }, "optionalPeers": ["@types/node"] }, "sha512-XDebtBdw5S3SuZIt+Ra2NieT8kQ3D2Ow1HxhDQ/2soinswnOu9e7S69VSwTOLlQnx5mpWbONu+5JJjDxMAb6Fw=="], @@ -117,16 +173,28 @@ "@rushstack/ts-command-line": ["@rushstack/ts-command-line@5.1.3", "", { "dependencies": { "@rushstack/terminal": "0.19.3", "@types/argparse": "1.0.38", "argparse": "~1.0.9", "string-argv": "~0.3.1" } }, "sha512-Kdv0k/BnnxIYFlMVC1IxrIS0oGQd4T4b7vKfx52Y2+wk2WZSDFIvedr7JrhenzSlm3ou5KwtoTGTGd5nbODRug=="], + "@standard-schema/spec": ["@standard-schema/spec@1.1.0", "", {}, "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="], + "@types/argparse": ["@types/argparse@1.0.38", "", {}, "sha512-ebDJ9b0e702Yr7pWgB0jzm+CX4Srzz8RcXtLJDJB+BSccqMa36uyH/zUsSYao5+BD1ytv3k3rPYCq4mAE1hsXA=="], "@types/bun": ["@types/bun@1.3.2", "", { "dependencies": { "bun-types": "1.3.2" } }, "sha512-t15P7k5UIgHKkxwnMNkJbWlh/617rkDGEdSsDbu+qNHTaz9SKf7aC8fiIlUdD5RPpH6GEkP0cK7WlvmrEBRtWg=="], "@types/estree": ["@types/estree@1.0.8", "", {}, "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w=="], + "@types/minimist": ["@types/minimist@1.2.5", "", {}, "sha512-hov8bUuiLiyFPGyFPE1lwWhmzYbirOXQNNo40+y3zow8aFVTeyn3VWL0VFFfdNddA8S4Vf0Tc062rzyNr7Paag=="], + "@types/node": ["@types/node@20.19.25", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-ZsJzA5thDQMSQO788d7IocwwQbI8B5OPzmqNvpf3NY/+MHDAS759Wo0gd2WQeXYt5AAAQjzcrTVC6SKCuYgoCQ=="], + "@types/normalize-package-data": ["@types/normalize-package-data@2.4.4", "", {}, "sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA=="], + + "@types/npm-package-arg": ["@types/npm-package-arg@6.1.4", "", {}, "sha512-vDgdbMy2QXHnAruzlv68pUtXCjmqUk3WrBAsRboRovsOmxbfn/WiYCjmecyKjGztnMps5dWp4Uq2prp+Ilo17Q=="], + "@types/react": ["@types/react@19.2.2", "", { "dependencies": { "csstype": "^3.0.2" } }, "sha512-6mDvHUFSjyT2B2yeNx2nUgMxh9LtOWvkhIU3uePn2I2oyNymUAX1NIsdgviM4CH+JSrp2D2hsMvJOkxY+0wNRA=="], + "@types/unist": ["@types/unist@2.0.11", "", {}, "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA=="], + + "@vercel/oidc": ["@vercel/oidc@3.2.0", "", {}, "sha512-UycprH3T6n3jH0k44NHMa7pnFHGu/N05MjojYr+Mc6I7obkoLIJujSWwin1pCvdy/eOxrI/l3uDLQsmcrOb4ug=="], + "@volar/language-core": ["@volar/language-core@2.4.23", "", { "dependencies": { "@volar/source-map": "2.4.23" } }, "sha512-hEEd5ET/oSmBC6pi1j6NaNYRWoAiDhINbT8rmwtINugR39loROSlufGdYMF9TaKGfz+ViGs1Idi3mAhnuPcoGQ=="], "@volar/source-map": ["@volar/source-map@2.4.23", "", {}, "sha512-Z1Uc8IB57Lm6k7q6KIDu/p+JWtf3xsXJqAX/5r18hYOTpJyBn0KXUR8oTJ4WFYOcDzWC9n3IflGgHowx6U6z9Q=="], @@ -143,12 +211,20 @@ "@vue/shared": ["@vue/shared@3.5.24", "", {}, "sha512-9cwHL2EsJBdi8NY22pngYYWzkTDhld6fAD6jlaeloNGciNSJL6bLpbxVgXl96X00Jtc6YWQv96YA/0sxex/k1A=="], + "@workflow/serde": ["@workflow/serde@4.1.0", "", {}, "sha512-pav4F2BoirECWR7Nf1TKt+2eETcBj7jj4cBefQ8VXQCA6NPkaKeLfj/zMgi+3zYV5ZIBT4GuUiphsj0/b9hPQQ=="], + + "@xmldom/xmldom": ["@xmldom/xmldom@0.8.13", "", {}, "sha512-KRYzxepc14G/CEpEGc3Yn+JKaAeT63smlDr+vjB8jRfgTBBI9wRj/nkQEO+ucV8p8I9bfKLWp37uHgFrbntPvw=="], + "@xterm/headless": ["@xterm/headless@5.5.0", "", {}, "sha512-5xXB7kdQlFBP82ViMJTwwEc3gKCLGKR/eoxQm4zge7GPBl86tCdI0IdPJjoKd8mUSFXz5V7i/25sfsEkP4j46g=="], "@xterm/xterm": ["@xterm/xterm@5.5.0", "", {}, "sha512-hqJHYaQb5OptNunnyAnkHyM8aCjZ1MEIDTQu1iIbbTD/xops91NB5yq1ZK/dC2JDbVWtF23zUtl9JE2NqwT87A=="], "acorn": ["acorn@8.15.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg=="], + "agent-base": ["agent-base@7.1.4", "", {}, "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ=="], + + "ai": ["ai@7.0.2", "", { "dependencies": { "@ai-sdk/gateway": "4.0.2", "@ai-sdk/provider": "4.0.0", "@ai-sdk/provider-utils": "5.0.0" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-VMU08jHIDJnnKDrbC9AFa5ZsPpOTfAPRLvTRHtJk4FGAoeldmJROMxvZ2ak5lCjEJ2GP2OLPQbMRyEK8w0+S4A=="], + "ajv": ["ajv@8.12.0", "", { "dependencies": { "fast-deep-equal": "^3.1.1", "json-schema-traverse": "^1.0.0", "require-from-string": "^2.0.2", "uri-js": "^4.2.2" } }, "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA=="], "ajv-draft-04": ["ajv-draft-04@1.0.0", "", { "peerDependencies": { "ajv": "^8.5.0" }, "optionalPeers": ["ajv"] }, "sha512-mv00Te6nmYbRp5DCwclxtt7yV/joXJPGS7nM+97GdxvuttCOfgI3K4U25zboyeX0O+myI8ERluxQe5wljMmVIw=="], @@ -157,86 +233,236 @@ "alien-signals": ["alien-signals@0.4.14", "", {}, "sha512-itUAVzhczTmP2U5yX67xVpsbbOiquusbWVyA9N+sy6+r6YVbFkahXvNCeEPWEOMhwDYwbVbGHFkVL03N9I5g+Q=="], - "argparse": ["argparse@1.0.10", "", { "dependencies": { "sprintf-js": "~1.0.2" } }, "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg=="], + "ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], + + "ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="], + + "argparse": ["argparse@2.0.1", "", {}, "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="], + + "array-ify": ["array-ify@1.0.0", "", {}, "sha512-c5AMf34bKdvPhQ7tBGhqkgKNUzMr4WUs+WDtC2ZUGOUncbxKMTvqxYctiseW3+L4bA8ec+GcZ6/A/FW4m8ukng=="], + + "arrify": ["arrify@1.0.1", "", {}, "sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA=="], + + "async-retry": ["async-retry@1.3.3", "", { "dependencies": { "retry": "0.13.1" } }, "sha512-wfr/jstw9xNi/0teMHrRW7dsz3Lt5ARhYNZ2ewpadnhaIp5mbALhOAP+EAdsC7t4Z6wqsDVv9+W6gm1Dk9mEyw=="], - "balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], + "balanced-match": ["balanced-match@4.0.4", "", {}, "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA=="], - "brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="], + "before-after-hook": ["before-after-hook@2.2.3", "", {}, "sha512-NzUnlZexiaH/46WDhANlyR2bXRopNg4F/zuSA3OpZnllCUgRaOF2znDioDWrmbNVsuZk6l9pMquQB38cfBZwkQ=="], + + "boolbase": ["boolbase@1.0.0", "", {}, "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww=="], + + "brace-expansion": ["brace-expansion@5.0.6", "", { "dependencies": { "balanced-match": "^4.0.2" } }, "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g=="], "bun-types": ["bun-types@1.3.2", "", { "dependencies": { "@types/node": "*" }, "peerDependencies": { "@types/react": "^19" } }, "sha512-i/Gln4tbzKNuxP70OWhJRZz1MRfvqExowP7U6JKoI8cntFrtxg7RJK3jvz7wQW54UuvNC8tbKHHri5fy74FVqg=="], + "camelcase": ["camelcase@5.3.1", "", {}, "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg=="], + + "camelcase-keys": ["camelcase-keys@6.2.2", "", { "dependencies": { "camelcase": "^5.3.1", "map-obj": "^4.0.0", "quick-lru": "^4.0.1" } }, "sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg=="], + + "chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="], + + "cliui": ["cliui@8.0.1", "", { "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.1", "wrap-ansi": "^7.0.0" } }, "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ=="], + + "color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "~1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="], + + "color-name": ["color-name@1.1.4", "", {}, "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="], + + "compare-func": ["compare-func@2.0.0", "", { "dependencies": { "array-ify": "^1.0.0", "dot-prop": "^5.1.0" } }, "sha512-zHig5N+tPWARooBnb0Zx1MFcdfpyJrfTJ3Y5L+IFvUm8rM74hHz66z0gw0x4tijh5CorKkKUCnW82R2vmpeCRA=="], + "compare-versions": ["compare-versions@6.1.1", "", {}, "sha512-4hm4VPpIecmlg59CHXnRDnqGplJFrbLG4aFEl5vl6cK1u76ws3LLvX7ikFnTDl5vo39sjWD6AaDPYodJp/NNHg=="], "confbox": ["confbox@0.2.2", "", {}, "sha512-1NB+BKqhtNipMsov4xI/NnhCKp9XG9NamYp5PVm9klAT0fsrNPjaFICsCFhNhwZJKNh7zB/3q8qXz0E9oaMNtQ=="], + "conventional-changelog-conventionalcommits": ["conventional-changelog-conventionalcommits@6.1.0", "", { "dependencies": { "compare-func": "^2.0.0" } }, "sha512-3cS3GEtR78zTfMzk0AizXKKIdN4OvSh7ibNz6/DPbhWWQu7LqE/8+/GqSodV+sywUR2gpJAdP/1JFf4XtN7Zpw=="], + + "conventional-changelog-writer": ["conventional-changelog-writer@6.0.1", "", { "dependencies": { "conventional-commits-filter": "^3.0.0", "dateformat": "^3.0.3", "handlebars": "^4.7.7", "json-stringify-safe": "^5.0.1", "meow": "^8.1.2", "semver": "^7.0.0", "split": "^1.0.1" }, "bin": { "conventional-changelog-writer": "cli.js" } }, "sha512-359t9aHorPw+U+nHzUXHS5ZnPBOizRxfQsWT5ZDHBfvfxQOAik+yfuhKXG66CN5LEWPpMNnIMHUTCKeYNprvHQ=="], + + "conventional-commits-filter": ["conventional-commits-filter@3.0.0", "", { "dependencies": { "lodash.ismatch": "^4.4.0", "modify-values": "^1.0.1" } }, "sha512-1ymej8b5LouPx9Ox0Dw/qAO2dVdfpRFq28e5Y0jJEU8ZrLdy0vOSkkIInwmxErFGhg6SALro60ZrwYFVTUDo4Q=="], + + "css-select": ["css-select@5.2.2", "", { "dependencies": { "boolbase": "^1.0.0", "css-what": "^6.1.0", "domhandler": "^5.0.2", "domutils": "^3.0.1", "nth-check": "^2.0.1" } }, "sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw=="], + + "css-what": ["css-what@6.2.2", "", {}, "sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA=="], + "csstype": ["csstype@3.1.3", "", {}, "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="], + "dateformat": ["dateformat@3.0.3", "", {}, "sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q=="], + "de-indent": ["de-indent@1.0.2", "", {}, "sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg=="], "debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="], - "diff": ["diff@8.0.2", "", {}, "sha512-sSuxWU5j5SR9QQji/o2qMvqRNYRDOcBTgsJ/DeCf4iSN4gW+gNMXM7wFIP+fdXZxoNiAnHUTGjCr+TSWXdRDKg=="], + "decamelize": ["decamelize@1.2.0", "", {}, "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA=="], + + "decamelize-keys": ["decamelize-keys@1.1.1", "", { "dependencies": { "decamelize": "^1.1.0", "map-obj": "^1.0.0" } }, "sha512-WiPxgEirIV0/eIOMcnFBA3/IJZAZqKnwAwWyvvdi4lsr1WCN22nhdf/3db3DoZcUjTV2SqfzIwNyp6y2xs3nmg=="], + + "deprecation": ["deprecation@2.3.1", "", {}, "sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ=="], + + "detect-indent": ["detect-indent@6.1.0", "", {}, "sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA=="], + + "diff": ["diff@8.0.4", "", {}, "sha512-DPi0FmjiSU5EvQV0++GFDOJ9ASQUVFh5kD+OzOnYdi7n3Wpm9hWWGfB/O2blfHcMVTL5WkQXSnRiK9makhrcnw=="], + + "dom-serializer": ["dom-serializer@2.0.0", "", { "dependencies": { "domelementtype": "^2.3.0", "domhandler": "^5.0.2", "entities": "^4.2.0" } }, "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg=="], + + "domelementtype": ["domelementtype@2.3.0", "", {}, "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw=="], + + "domhandler": ["domhandler@5.0.3", "", { "dependencies": { "domelementtype": "^2.3.0" } }, "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w=="], + + "domutils": ["domutils@3.2.2", "", { "dependencies": { "dom-serializer": "^2.0.0", "domelementtype": "^2.3.0", "domhandler": "^5.0.3" } }, "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw=="], + + "dot-prop": ["dot-prop@5.3.0", "", { "dependencies": { "is-obj": "^2.0.0" } }, "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q=="], + + "emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="], "entities": ["entities@4.5.0", "", {}, "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw=="], - "esbuild": ["esbuild@0.18.20", "", { "optionalDependencies": { "@esbuild/android-arm": "0.18.20", "@esbuild/android-arm64": "0.18.20", "@esbuild/android-x64": "0.18.20", "@esbuild/darwin-arm64": "0.18.20", "@esbuild/darwin-x64": "0.18.20", "@esbuild/freebsd-arm64": "0.18.20", "@esbuild/freebsd-x64": "0.18.20", "@esbuild/linux-arm": "0.18.20", "@esbuild/linux-arm64": "0.18.20", "@esbuild/linux-ia32": "0.18.20", "@esbuild/linux-loong64": "0.18.20", "@esbuild/linux-mips64el": "0.18.20", "@esbuild/linux-ppc64": "0.18.20", "@esbuild/linux-riscv64": "0.18.20", "@esbuild/linux-s390x": "0.18.20", "@esbuild/linux-x64": "0.18.20", "@esbuild/netbsd-x64": "0.18.20", "@esbuild/openbsd-x64": "0.18.20", "@esbuild/sunos-x64": "0.18.20", "@esbuild/win32-arm64": "0.18.20", "@esbuild/win32-ia32": "0.18.20", "@esbuild/win32-x64": "0.18.20" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA=="], + "error-ex": ["error-ex@1.3.4", "", { "dependencies": { "is-arrayish": "^0.2.1" } }, "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ=="], + + "esbuild": ["esbuild@0.28.1", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.28.1", "@esbuild/android-arm": "0.28.1", "@esbuild/android-arm64": "0.28.1", "@esbuild/android-x64": "0.28.1", "@esbuild/darwin-arm64": "0.28.1", "@esbuild/darwin-x64": "0.28.1", "@esbuild/freebsd-arm64": "0.28.1", "@esbuild/freebsd-x64": "0.28.1", "@esbuild/linux-arm": "0.28.1", "@esbuild/linux-arm64": "0.28.1", "@esbuild/linux-ia32": "0.28.1", "@esbuild/linux-loong64": "0.28.1", "@esbuild/linux-mips64el": "0.28.1", "@esbuild/linux-ppc64": "0.28.1", "@esbuild/linux-riscv64": "0.28.1", "@esbuild/linux-s390x": "0.28.1", "@esbuild/linux-x64": "0.28.1", "@esbuild/netbsd-arm64": "0.28.1", "@esbuild/netbsd-x64": "0.28.1", "@esbuild/openbsd-arm64": "0.28.1", "@esbuild/openbsd-x64": "0.28.1", "@esbuild/openharmony-arm64": "0.28.1", "@esbuild/sunos-x64": "0.28.1", "@esbuild/win32-arm64": "0.28.1", "@esbuild/win32-ia32": "0.28.1", "@esbuild/win32-x64": "0.28.1" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-HrJrvZv5ayxBzPfwphOoNzkzOIIlifzk0KJrGK2c8R4+LKpMtpYLQeUdjnwjWv/LZlkH2laZk+4w78pi99D4Vw=="], + + "escalade": ["escalade@3.2.0", "", {}, "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA=="], + + "escape-string-regexp": ["escape-string-regexp@1.0.5", "", {}, "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg=="], "estree-walker": ["estree-walker@2.0.2", "", {}, "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w=="], + "eventsource-parser": ["eventsource-parser@3.1.0", "", {}, "sha512-kJezFj9YFAMLeORyi7aCLxLbD5/qWMQnoMVlVPyHIll7lgRJCc3JVln9Vgl9nwQi0YkMnhdGTMNn7CkRRAptMg=="], + "exsolve": ["exsolve@1.0.8", "", {}, "sha512-LmDxfWXwcTArk8fUEnOfSZpHOJ6zOMUJKOtFLFqJLoKJetuQG874Uc7/Kki7zFLzYybmZhp1M7+98pfMqeX8yA=="], "fast-deep-equal": ["fast-deep-equal@3.1.3", "", {}, "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="], + "figures": ["figures@3.2.0", "", { "dependencies": { "escape-string-regexp": "^1.0.5" } }, "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg=="], + + "find-up": ["find-up@4.1.0", "", { "dependencies": { "locate-path": "^5.0.0", "path-exists": "^4.0.0" } }, "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw=="], + "fs-extra": ["fs-extra@11.3.2", "", { "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" } }, "sha512-Xr9F6z6up6Ws+NjzMCZc6WXg2YFRlrLP9NQDO3VQrWrfiojdhS56TzueT88ze0uBdCTwEIhQ3ptnmKeWGFAe0A=="], "fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="], "function-bind": ["function-bind@1.1.2", "", {}, "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA=="], + "get-caller-file": ["get-caller-file@2.0.5", "", {}, "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg=="], + "graceful-fs": ["graceful-fs@4.2.11", "", {}, "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="], + "handlebars": ["handlebars@4.7.9", "", { "dependencies": { "minimist": "^1.2.5", "neo-async": "^2.6.2", "source-map": "^0.6.1", "wordwrap": "^1.0.0" }, "optionalDependencies": { "uglify-js": "^3.1.4" }, "bin": { "handlebars": "bin/handlebars" } }, "sha512-4E71E0rpOaQuJR2A3xDZ+GM1HyWYv1clR58tC8emQNeQe3RH7MAzSbat+V0wG78LQBo6m6bzSG/L4pBuCsgnUQ=="], + "happy-dom": ["happy-dom@15.11.7", "", { "dependencies": { "entities": "^4.5.0", "webidl-conversions": "^7.0.0", "whatwg-mimetype": "^3.0.0" } }, "sha512-KyrFvnl+J9US63TEzwoiJOQzZBJY7KgBushJA8X61DMbNsH+2ONkDuLDnCnwUiPTF42tLoEmrPyoqbenVA5zrg=="], + "hard-rejection": ["hard-rejection@2.1.0", "", {}, "sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA=="], + "has-flag": ["has-flag@4.0.0", "", {}, "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="], "hasown": ["hasown@2.0.2", "", { "dependencies": { "function-bind": "^1.1.2" } }, "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ=="], "he": ["he@1.2.0", "", { "bin": { "he": "bin/he" } }, "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw=="], + "hosted-git-info": ["hosted-git-info@4.1.0", "", { "dependencies": { "lru-cache": "^6.0.0" } }, "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA=="], + + "http-proxy-agent": ["http-proxy-agent@7.0.2", "", { "dependencies": { "agent-base": "^7.1.0", "debug": "^4.3.4" } }, "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig=="], + + "https-proxy-agent": ["https-proxy-agent@7.0.6", "", { "dependencies": { "agent-base": "^7.1.2", "debug": "4" } }, "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw=="], + "import-lazy": ["import-lazy@4.0.0", "", {}, "sha512-rKtvo6a868b5Hu3heneU+L4yEQ4jYKLtjpnPeUdK7h0yzXGmyBTypknlkCvHFBqfX9YlorEiMM6Dnq/5atfHkw=="], + "indent-string": ["indent-string@4.0.0", "", {}, "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg=="], + + "is-arrayish": ["is-arrayish@0.2.1", "", {}, "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg=="], + "is-core-module": ["is-core-module@2.16.1", "", { "dependencies": { "hasown": "^2.0.2" } }, "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w=="], + "is-fullwidth-code-point": ["is-fullwidth-code-point@3.0.0", "", {}, "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="], + + "is-obj": ["is-obj@2.0.0", "", {}, "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w=="], + + "is-plain-obj": ["is-plain-obj@1.1.0", "", {}, "sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg=="], + "jju": ["jju@1.4.0", "", {}, "sha512-8wb9Yw966OSxApiCt0K3yNJL8pnNeIv+OEq2YMidz4FKP6nonSRoOXc80iXY4JaN2FC11B9qsNmDsm+ZOfMROA=="], + "js-tokens": ["js-tokens@4.0.0", "", {}, "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="], + + "js-yaml": ["js-yaml@4.2.0", "", { "dependencies": { "argparse": "^2.0.1" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, "sha512-ePWsvanv0DWuDRsW8dnt+R4jQ31SCRCQ7hhNcPXZPsoBZiemuZNYGf7adZdqX2D86j6rvKp3RpCxVTSb8WQlOw=="], + + "jsep": ["jsep@1.4.0", "", {}, "sha512-B7qPcEVE3NVkmSJbaYxvv4cHkVW7DQsZz13pUMrfS8z8Q/BuShN+gcTXrUlPiGqM2/t/EEaI030bpxMqY8gMlw=="], + + "json-parse-even-better-errors": ["json-parse-even-better-errors@2.3.1", "", {}, "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w=="], + + "json-schema": ["json-schema@0.4.0", "", {}, "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA=="], + "json-schema-traverse": ["json-schema-traverse@1.0.0", "", {}, "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="], + "json-stringify-safe": ["json-stringify-safe@5.0.1", "", {}, "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA=="], + "jsonfile": ["jsonfile@6.2.0", "", { "dependencies": { "universalify": "^2.0.0" }, "optionalDependencies": { "graceful-fs": "^4.1.6" } }, "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg=="], + "jsonpath-plus": ["jsonpath-plus@10.4.0", "", { "dependencies": { "@jsep-plugin/assignment": "^1.3.0", "@jsep-plugin/regex": "^1.0.4", "jsep": "^1.4.0" }, "bin": { "jsonpath": "bin/jsonpath-cli.js", "jsonpath-plus": "bin/jsonpath-cli.js" } }, "sha512-T92WWatJXmhBbKsgH/0hl+jxjdXrifi5IKeMY02DWggRxX0UElcbVzPlmgLTbvsPeW1PasQ6xE2Q75stkhGbsA=="], + + "kind-of": ["kind-of@6.0.3", "", {}, "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw=="], + "kolorist": ["kolorist@1.8.0", "", {}, "sha512-Y+60/zizpJ3HRH8DCss+q95yr6145JXZo46OTpFvDZWLfRCE4qChOyk1b26nMaNpfHHgxagk9dXT5OP0Tfe+dQ=="], + "lines-and-columns": ["lines-and-columns@1.2.4", "", {}, "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg=="], + "local-pkg": ["local-pkg@1.1.2", "", { "dependencies": { "mlly": "^1.7.4", "pkg-types": "^2.3.0", "quansync": "^0.2.11" } }, "sha512-arhlxbFRmoQHl33a0Zkle/YWlmNwoyt6QNZEIJcqNbdrsix5Lvc4HyyI3EnwxTYlZYc32EbYrQ8SzEZ7dqgg9A=="], + "locate-path": ["locate-path@5.0.0", "", { "dependencies": { "p-locate": "^4.1.0" } }, "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g=="], + "lodash": ["lodash@4.17.21", "", {}, "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="], + "lodash.ismatch": ["lodash.ismatch@4.4.0", "", {}, "sha512-fPMfXjGQEV9Xsq/8MTSgUf255gawYRbjwMyDbcvDhXgV7enSZA0hynz6vMPnpAb5iONEzBHBPsT+0zes5Z301g=="], + "lru-cache": ["lru-cache@6.0.0", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA=="], "magic-string": ["magic-string@0.30.21", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.5" } }, "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ=="], - "minimatch": ["minimatch@10.0.3", "", { "dependencies": { "@isaacs/brace-expansion": "^5.0.0" } }, "sha512-IPZ167aShDZZUMdRk66cyQAW3qr0WzbHkPdMYa8bzZhlHhO3jALbKdxcaak7W9FfT2rZNpQuUu4Od7ILEpXSaw=="], + "map-obj": ["map-obj@4.3.0", "", {}, "sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ=="], + + "meow": ["meow@8.1.2", "", { "dependencies": { "@types/minimist": "^1.2.0", "camelcase-keys": "^6.2.2", "decamelize-keys": "^1.1.0", "hard-rejection": "^2.1.0", "minimist-options": "4.1.0", "normalize-package-data": "^3.0.0", "read-pkg-up": "^7.0.1", "redent": "^3.0.0", "trim-newlines": "^3.0.0", "type-fest": "^0.18.0", "yargs-parser": "^20.2.3" } }, "sha512-r85E3NdZ+mpYk1C6RjPFEMSE+s1iZMuHtsHAqY0DT3jZczl0diWUZ8g6oU7h0M9cD2EL+PzaYghhCLzR0ZNn5Q=="], + + "min-indent": ["min-indent@1.0.1", "", {}, "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg=="], + + "minimatch": ["minimatch@10.2.5", "", { "dependencies": { "brace-expansion": "^5.0.5" } }, "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg=="], + + "minimist": ["minimist@1.2.8", "", {}, "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA=="], + + "minimist-options": ["minimist-options@4.1.0", "", { "dependencies": { "arrify": "^1.0.1", "is-plain-obj": "^1.1.0", "kind-of": "^6.0.3" } }, "sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A=="], "mitata": ["mitata@1.0.34", "", {}, "sha512-Mc3zrtNBKIMeHSCQ0XqRLo1vbdIx1wvFV9c8NJAiyho6AjNfMY8bVhbS12bwciUdd1t4rj8099CH3N3NFahaUA=="], "mlly": ["mlly@1.8.0", "", { "dependencies": { "acorn": "^8.15.0", "pathe": "^2.0.3", "pkg-types": "^1.3.1", "ufo": "^1.6.1" } }, "sha512-l8D9ODSRWLe2KHJSifWGwBqpTZXIXTeo8mlKjY+E2HAakaTeNpqAyBZ8GSqLzHgw4XmHmC8whvpjJNMbFZN7/g=="], + "modify-values": ["modify-values@1.0.1", "", {}, "sha512-xV2bxeN6F7oYjZWTe/YPAy6MN2M+sL4u/Rlm2AHCIVGfo2p1yGmBHQ6vHehl4bRTZBdHu3TSkWdYgkwpYzAGSw=="], + "ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="], "muggle-string": ["muggle-string@0.4.1", "", {}, "sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ=="], "nanoid": ["nanoid@3.3.11", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="], + "neo-async": ["neo-async@2.6.2", "", {}, "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw=="], + + "node-html-parser": ["node-html-parser@6.1.13", "", { "dependencies": { "css-select": "^5.1.0", "he": "1.2.0" } }, "sha512-qIsTMOY4C/dAa5Q5vsobRpOOvPfC4pB61UVW2uSwZNUp0QU/jCekTal1vMmbO0DgdHeLUJpv/ARmDqErVxA3Sg=="], + + "normalize-package-data": ["normalize-package-data@3.0.3", "", { "dependencies": { "hosted-git-info": "^4.0.1", "is-core-module": "^2.5.0", "semver": "^7.3.4", "validate-npm-package-license": "^3.0.1" } }, "sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA=="], + + "nth-check": ["nth-check@2.1.1", "", { "dependencies": { "boolbase": "^1.0.0" } }, "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w=="], + + "once": ["once@1.4.0", "", { "dependencies": { "wrappy": "1" } }, "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w=="], + + "p-limit": ["p-limit@2.3.0", "", { "dependencies": { "p-try": "^2.0.0" } }, "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w=="], + + "p-locate": ["p-locate@4.1.0", "", { "dependencies": { "p-limit": "^2.2.0" } }, "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A=="], + + "p-try": ["p-try@2.2.0", "", {}, "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ=="], + + "parse-github-repo-url": ["parse-github-repo-url@1.4.1", "", {}, "sha512-bSWyzBKqcSL4RrncTpGsEKoJ7H8a4L3++ifTAbTFeMHyq2wRV+42DGmQcHIrJIvdcacjIOxEuKH/w4tthF17gg=="], + + "parse-json": ["parse-json@5.2.0", "", { "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" } }, "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg=="], + "path-browserify": ["path-browserify@1.0.1", "", {}, "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g=="], + "path-exists": ["path-exists@4.0.0", "", {}, "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w=="], + "path-parse": ["path-parse@1.0.7", "", {}, "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw=="], "pathe": ["pathe@2.0.3", "", {}, "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w=="], @@ -255,10 +481,24 @@ "quansync": ["quansync@0.2.11", "", {}, "sha512-AifT7QEbW9Nri4tAwR5M/uzpBuqfZf+zwaEM/QkzEjj7NBuFD2rBuy0K3dE+8wltbezDV7JMA0WfnCPYRSYbXA=="], + "quick-lru": ["quick-lru@4.0.1", "", {}, "sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g=="], + + "read-pkg": ["read-pkg@5.2.0", "", { "dependencies": { "@types/normalize-package-data": "^2.4.0", "normalize-package-data": "^2.5.0", "parse-json": "^5.0.0", "type-fest": "^0.6.0" } }, "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg=="], + + "read-pkg-up": ["read-pkg-up@7.0.1", "", { "dependencies": { "find-up": "^4.1.0", "read-pkg": "^5.2.0", "type-fest": "^0.8.1" } }, "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg=="], + + "redent": ["redent@3.0.0", "", { "dependencies": { "indent-string": "^4.0.0", "strip-indent": "^3.0.0" } }, "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg=="], + + "release-please": ["release-please@17.9.0", "", { "dependencies": { "@conventional-commits/parser": "^0.4.1", "@google-automations/git-file-utils": "^3.0.0", "@iarna/toml": "^3.0.0", "@octokit/graphql": "^7.1.0", "@octokit/request": "^8.3.1", "@octokit/request-error": "^5.1.0", "@octokit/rest": "^20.1.1", "@types/npm-package-arg": "^6.1.0", "@xmldom/xmldom": "^0.8.4", "async-retry": "^1.3.3", "chalk": "^4.0.0", "conventional-changelog-conventionalcommits": "^6.0.0", "conventional-changelog-writer": "^6.0.0", "conventional-commits-filter": "^3.0.0", "detect-indent": "^6.1.0", "diff": "^8.0.3", "figures": "^3.0.0", "http-proxy-agent": "^7.0.0", "https-proxy-agent": "^7.0.0", "js-yaml": "^4.0.0", "jsonpath-plus": "^10.0.0", "node-html-parser": "^6.0.0", "parse-github-repo-url": "^1.4.1", "semver": "^7.5.3", "type-fest": "^3.0.0", "typescript": "^4.6.4", "unist-util-visit": "^2.0.3", "unist-util-visit-parents": "^3.1.1", "xpath": "^0.0.34", "yaml": "^2.2.2", "yargs": "^17.0.0" }, "bin": { "release-please": "build/src/bin/release-please.js" } }, "sha512-3/dVnZpsR2qfZMcYXKsiE8MiZPNYntff2csLFR0m2Hil0QN74cuF+nllubqD2qxdhtg81SmK+zzriQUZuI5wpw=="], + + "require-directory": ["require-directory@2.1.1", "", {}, "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q=="], + "require-from-string": ["require-from-string@2.0.2", "", {}, "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw=="], "resolve": ["resolve@1.22.11", "", { "dependencies": { "is-core-module": "^2.16.1", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": { "resolve": "bin/resolve" } }, "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ=="], + "retry": ["retry@0.13.1", "", {}, "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg=="], + "rollup": ["rollup@3.29.5", "", { "optionalDependencies": { "fsevents": "~2.3.2" }, "bin": { "rollup": "dist/bin/rollup" } }, "sha512-GVsDdsbJzzy4S/v3dqWPJ7EfvZJfCHiDqe80IyrF59LYuP+e6U1LJoUqeuqRbwAWoMNoXivMNeNAOf5E22VA1w=="], "semver": ["semver@7.5.4", "", { "dependencies": { "lru-cache": "^6.0.0" }, "bin": { "semver": "bin/semver.js" } }, "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA=="], @@ -267,26 +507,62 @@ "source-map-js": ["source-map-js@1.2.1", "", {}, "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="], + "spdx-correct": ["spdx-correct@3.2.0", "", { "dependencies": { "spdx-expression-parse": "^3.0.0", "spdx-license-ids": "^3.0.0" } }, "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA=="], + + "spdx-exceptions": ["spdx-exceptions@2.5.0", "", {}, "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w=="], + + "spdx-expression-parse": ["spdx-expression-parse@3.0.1", "", { "dependencies": { "spdx-exceptions": "^2.1.0", "spdx-license-ids": "^3.0.0" } }, "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q=="], + + "spdx-license-ids": ["spdx-license-ids@3.0.23", "", {}, "sha512-CWLcCCH7VLu13TgOH+r8p1O/Znwhqv/dbb6lqWy67G+pT1kHmeD/+V36AVb/vq8QMIQwVShJ6Ssl5FPh0fuSdw=="], + + "split": ["split@1.0.1", "", { "dependencies": { "through": "2" } }, "sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg=="], + "sprintf-js": ["sprintf-js@1.0.3", "", {}, "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g=="], "string-argv": ["string-argv@0.3.2", "", {}, "sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q=="], + "string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="], + + "strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], + + "strip-indent": ["strip-indent@3.0.0", "", { "dependencies": { "min-indent": "^1.0.0" } }, "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ=="], + "strip-json-comments": ["strip-json-comments@3.1.1", "", {}, "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig=="], - "supports-color": ["supports-color@8.1.1", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q=="], + "supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="], "supports-preserve-symlinks-flag": ["supports-preserve-symlinks-flag@1.0.0", "", {}, "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w=="], + "through": ["through@2.3.8", "", {}, "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg=="], + + "trim-newlines": ["trim-newlines@3.0.1", "", {}, "sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw=="], + + "tsx": ["tsx@4.22.4", "", { "dependencies": { "esbuild": "~0.28.0" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "bin": { "tsx": "dist/cli.mjs" } }, "sha512-X8EX+XV4QR5xCsrgxaED954zTDfY8KqlDtskKEL0cHhyS/P8b4IFOvGDQpsC9Q1XnLq915wEfwwY/zzskCtmhg=="], + + "type-fest": ["type-fest@3.13.1", "", {}, "sha512-tLq3bSNx+xSpwvAJnzrK0Ep5CLNWjvFTOp71URMaAEWBfRb9nnJiBoUe0tF8bI4ZFO3omgBR6NvnbzVUT3Ly4g=="], + "typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="], "ufo": ["ufo@1.6.1", "", {}, "sha512-9a4/uxlTWJ4+a5i0ooc1rU7C7YOw3wT+UGqdeNNHWnOF9qcMBgLRS+4IYUqbczewFx4mLEig6gawh7X6mFlEkA=="], + "uglify-js": ["uglify-js@3.19.3", "", { "bin": { "uglifyjs": "bin/uglifyjs" } }, "sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ=="], + "undici-types": ["undici-types@6.21.0", "", {}, "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ=="], + "unist-util-is": ["unist-util-is@4.1.0", "", {}, "sha512-ZOQSsnce92GrxSqlnEEseX0gi7GH9zTJZ0p9dtu87WRb/37mMPO2Ilx1s/t9vBHrFhbgweUwb+t7cIn5dxPhZg=="], + + "unist-util-visit": ["unist-util-visit@2.0.3", "", { "dependencies": { "@types/unist": "^2.0.0", "unist-util-is": "^4.0.0", "unist-util-visit-parents": "^3.0.0" } }, "sha512-iJ4/RczbJMkD0712mGktuGpm/U4By4FfDonL7N/9tATGIF4imikjOuagyMY53tnZq3NP6BcmlrHhEKAfGWjh7Q=="], + + "unist-util-visit-parents": ["unist-util-visit-parents@3.1.1", "", { "dependencies": { "@types/unist": "^2.0.0", "unist-util-is": "^4.0.0" } }, "sha512-1KROIZWo6bcMrZEwiH2UrXDyalAa0uqzWCxCJj6lPOvTve2WkfgCytoDTPaMnodXh1WrXOq0haVYHj99ynJlsg=="], + + "universal-user-agent": ["universal-user-agent@6.0.1", "", {}, "sha512-yCzhz6FN2wU1NiiQRogkTQszlQSlpWaw8SvVegAc+bDxbzHgh1vX8uIe8OYyMH6DwH+sdTJsgMl36+mSMdRJIQ=="], + "universalify": ["universalify@2.0.1", "", {}, "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw=="], "uri-js": ["uri-js@4.4.1", "", { "dependencies": { "punycode": "^2.1.0" } }, "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg=="], + "validate-npm-package-license": ["validate-npm-package-license@3.0.4", "", { "dependencies": { "spdx-correct": "^3.0.0", "spdx-expression-parse": "^3.0.0" } }, "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew=="], + "vite": ["vite@4.5.14", "", { "dependencies": { "esbuild": "^0.18.10", "postcss": "^8.4.27", "rollup": "^3.27.1" }, "optionalDependencies": { "fsevents": "~2.3.2" }, "peerDependencies": { "@types/node": ">= 14", "less": "*", "lightningcss": "^1.21.0", "sass": "*", "stylus": "*", "sugarss": "*", "terser": "^5.4.0" }, "optionalPeers": ["@types/node", "less", "lightningcss", "sass", "stylus", "sugarss", "terser"], "bin": { "vite": "bin/vite.js" } }, "sha512-+v57oAaoYNnO3hIu5Z/tJRZjq5aHM2zDve9YZ8HngVHbhk66RStobhb1sqPMIPEleV6cNKYK4eGrAbE9Ulbl2g=="], "vite-plugin-dts": ["vite-plugin-dts@4.5.4", "", { "dependencies": { "@microsoft/api-extractor": "^7.50.1", "@rollup/pluginutils": "^5.1.4", "@volar/typescript": "^2.4.11", "@vue/language-core": "2.2.0", "compare-versions": "^6.1.1", "debug": "^4.4.0", "kolorist": "^1.8.0", "local-pkg": "^1.0.0", "magic-string": "^0.30.17" }, "peerDependencies": { "typescript": "*", "vite": "*" }, "optionalPeers": ["vite"] }, "sha512-d4sOM8M/8z7vRXHHq/ebbblfaxENjogAAekcfcDCCwAyvGqnPrc7f4NZbvItS+g4WTgerW0xDwSz5qz11JT3vg=="], @@ -297,22 +573,118 @@ "whatwg-mimetype": ["whatwg-mimetype@3.0.0", "", {}, "sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q=="], + "wordwrap": ["wordwrap@1.0.0", "", {}, "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q=="], + + "wrap-ansi": ["wrap-ansi@7.0.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q=="], + + "wrappy": ["wrappy@1.0.2", "", {}, "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="], + + "xpath": ["xpath@0.0.34", "", {}, "sha512-FxF6+rkr1rNSQrhUNYrAFJpRXNzlDoMxeXN5qI84939ylEv3qqPFKa85Oxr6tDaJKqwW6KKyo2v26TSv3k6LeA=="], + + "y18n": ["y18n@5.0.8", "", {}, "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA=="], + "yallist": ["yallist@4.0.0", "", {}, "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="], + "yaml": ["yaml@2.9.0", "", { "bin": { "yaml": "bin.mjs" } }, "sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA=="], + + "yargs": ["yargs@17.7.3", "", { "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" } }, "sha512-GZtjxm/J/4TSxuL3FNYjCmLktBTnIw/rVmKSIyKeYAZpmJB2ig9VauCC5xsa82GNKVKDAqpOn3KVzNt0zmrU0g=="], + + "yargs-parser": ["yargs-parser@21.1.1", "", {}, "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw=="], + + "zod": ["zod@4.4.3", "", {}, "sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ=="], + + "@babel/code-frame/@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@7.29.7", "", {}, "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg=="], + + "@microsoft/api-extractor/diff": ["diff@8.0.2", "", {}, "sha512-sSuxWU5j5SR9QQji/o2qMvqRNYRDOcBTgsJ/DeCf4iSN4gW+gNMXM7wFIP+fdXZxoNiAnHUTGjCr+TSWXdRDKg=="], + + "@microsoft/api-extractor/minimatch": ["minimatch@10.0.3", "", { "dependencies": { "@isaacs/brace-expansion": "^5.0.0" } }, "sha512-IPZ167aShDZZUMdRk66cyQAW3qr0WzbHkPdMYa8bzZhlHhO3jALbKdxcaak7W9FfT2rZNpQuUu4Od7ILEpXSaw=="], + "@microsoft/api-extractor/typescript": ["typescript@5.8.2", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-aJn6wq13/afZp/jT9QZmwEjDqqvSGp1VT5GVg+f/t6/oVyrgXM6BY1h9BRh/O5p3PlUPAe+WuiEZOmb/49RqoQ=="], "@rushstack/node-core-library/ajv": ["ajv@8.13.0", "", { "dependencies": { "fast-deep-equal": "^3.1.3", "json-schema-traverse": "^1.0.0", "require-from-string": "^2.0.2", "uri-js": "^4.4.1" } }, "sha512-PRA911Blj99jR5RMeTunVbNXMF6Lp4vZXnk5GQjcnUWUTsrXtekg/pnmFFI2u/I36Y/2bITGS30GZCXei6uNkA=="], + "@rushstack/terminal/supports-color": ["supports-color@8.1.1", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q=="], + + "@rushstack/ts-command-line/argparse": ["argparse@1.0.10", "", { "dependencies": { "sprintf-js": "~1.0.2" } }, "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg=="], + "@vue/language-core/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="], "ajv-formats/ajv": ["ajv@8.13.0", "", { "dependencies": { "fast-deep-equal": "^3.1.3", "json-schema-traverse": "^1.0.0", "require-from-string": "^2.0.2", "uri-js": "^4.4.1" } }, "sha512-PRA911Blj99jR5RMeTunVbNXMF6Lp4vZXnk5GQjcnUWUTsrXtekg/pnmFFI2u/I36Y/2bITGS30GZCXei6uNkA=="], "bun-types/@types/node": ["@types/node@24.10.0", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-qzQZRBqkFsYyaSWXuEHc2WR9c0a0CXwiE5FWUvn7ZM+vdy1uZLfCunD38UzhuB7YN/J11ndbDBcTmOdxJo9Q7A=="], + "decamelize-keys/map-obj": ["map-obj@1.0.1", "", {}, "sha512-7N/q3lyZ+LVCp7PzuxrJr4KMbBE2hW7BT7YNia330OFxIf4d3r5zVpicP2650l7CPN6RM9zOJRl3NGpqSiw3Eg=="], + + "meow/type-fest": ["type-fest@0.18.1", "", {}, "sha512-OIAYXk8+ISY+qTOwkHtKqzAuxchoMiD9Udx+FSGQDuiRR+PJKJHc2NJAXlbhkGwTt/4/nKZxELY1w3ReWOL8mw=="], + + "meow/yargs-parser": ["yargs-parser@20.2.9", "", {}, "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w=="], + "mlly/pkg-types": ["pkg-types@1.3.1", "", { "dependencies": { "confbox": "^0.1.8", "mlly": "^1.7.4", "pathe": "^2.0.1" } }, "sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ=="], + "read-pkg/normalize-package-data": ["normalize-package-data@2.5.0", "", { "dependencies": { "hosted-git-info": "^2.1.4", "resolve": "^1.10.0", "semver": "2 || 3 || 4 || 5", "validate-npm-package-license": "^3.0.1" } }, "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA=="], + + "read-pkg/type-fest": ["type-fest@0.6.0", "", {}, "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg=="], + + "read-pkg-up/type-fest": ["type-fest@0.8.1", "", {}, "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA=="], + + "release-please/typescript": ["typescript@4.9.5", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g=="], + + "vite/esbuild": ["esbuild@0.18.20", "", { "optionalDependencies": { "@esbuild/android-arm": "0.18.20", "@esbuild/android-arm64": "0.18.20", "@esbuild/android-x64": "0.18.20", "@esbuild/darwin-arm64": "0.18.20", "@esbuild/darwin-x64": "0.18.20", "@esbuild/freebsd-arm64": "0.18.20", "@esbuild/freebsd-x64": "0.18.20", "@esbuild/linux-arm": "0.18.20", "@esbuild/linux-arm64": "0.18.20", "@esbuild/linux-ia32": "0.18.20", "@esbuild/linux-loong64": "0.18.20", "@esbuild/linux-mips64el": "0.18.20", "@esbuild/linux-ppc64": "0.18.20", "@esbuild/linux-riscv64": "0.18.20", "@esbuild/linux-s390x": "0.18.20", "@esbuild/linux-x64": "0.18.20", "@esbuild/netbsd-x64": "0.18.20", "@esbuild/openbsd-x64": "0.18.20", "@esbuild/sunos-x64": "0.18.20", "@esbuild/win32-arm64": "0.18.20", "@esbuild/win32-ia32": "0.18.20", "@esbuild/win32-x64": "0.18.20" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA=="], + + "@vue/language-core/minimatch/brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="], + "bun-types/@types/node/undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="], "mlly/pkg-types/confbox": ["confbox@0.1.8", "", {}, "sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w=="], + + "read-pkg/normalize-package-data/hosted-git-info": ["hosted-git-info@2.8.9", "", {}, "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw=="], + + "read-pkg/normalize-package-data/semver": ["semver@5.7.2", "", { "bin": { "semver": "bin/semver" } }, "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g=="], + + "vite/esbuild/@esbuild/android-arm": ["@esbuild/android-arm@0.18.20", "", { "os": "android", "cpu": "arm" }, "sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw=="], + + "vite/esbuild/@esbuild/android-arm64": ["@esbuild/android-arm64@0.18.20", "", { "os": "android", "cpu": "arm64" }, "sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ=="], + + "vite/esbuild/@esbuild/android-x64": ["@esbuild/android-x64@0.18.20", "", { "os": "android", "cpu": "x64" }, "sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg=="], + + "vite/esbuild/@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.18.20", "", { "os": "darwin", "cpu": "arm64" }, "sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA=="], + + "vite/esbuild/@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.18.20", "", { "os": "darwin", "cpu": "x64" }, "sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ=="], + + "vite/esbuild/@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.18.20", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw=="], + + "vite/esbuild/@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.18.20", "", { "os": "freebsd", "cpu": "x64" }, "sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ=="], + + "vite/esbuild/@esbuild/linux-arm": ["@esbuild/linux-arm@0.18.20", "", { "os": "linux", "cpu": "arm" }, "sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg=="], + + "vite/esbuild/@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.18.20", "", { "os": "linux", "cpu": "arm64" }, "sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA=="], + + "vite/esbuild/@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.18.20", "", { "os": "linux", "cpu": "ia32" }, "sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA=="], + + "vite/esbuild/@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.18.20", "", { "os": "linux", "cpu": "none" }, "sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg=="], + + "vite/esbuild/@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.18.20", "", { "os": "linux", "cpu": "none" }, "sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ=="], + + "vite/esbuild/@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.18.20", "", { "os": "linux", "cpu": "ppc64" }, "sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA=="], + + "vite/esbuild/@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.18.20", "", { "os": "linux", "cpu": "none" }, "sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A=="], + + "vite/esbuild/@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.18.20", "", { "os": "linux", "cpu": "s390x" }, "sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ=="], + + "vite/esbuild/@esbuild/linux-x64": ["@esbuild/linux-x64@0.18.20", "", { "os": "linux", "cpu": "x64" }, "sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w=="], + + "vite/esbuild/@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.18.20", "", { "os": "none", "cpu": "x64" }, "sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A=="], + + "vite/esbuild/@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.18.20", "", { "os": "openbsd", "cpu": "x64" }, "sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg=="], + + "vite/esbuild/@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.18.20", "", { "os": "sunos", "cpu": "x64" }, "sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ=="], + + "vite/esbuild/@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.18.20", "", { "os": "win32", "cpu": "arm64" }, "sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg=="], + + "vite/esbuild/@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.18.20", "", { "os": "win32", "cpu": "ia32" }, "sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g=="], + + "vite/esbuild/@esbuild/win32-x64": ["@esbuild/win32-x64@0.18.20", "", { "os": "win32", "cpu": "x64" }, "sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ=="], + + "@vue/language-core/minimatch/brace-expansion/balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], } } diff --git a/demo/package.json b/demo/package.json index 09be0888..2e96f9ad 100644 --- a/demo/package.json +++ b/demo/package.json @@ -1,6 +1,6 @@ { "name": "@ghostty-web/demo", - "version": "0.3.0", + "version": "0.4.0", "description": "Cross-platform demo server for ghostty-web terminal emulator", "type": "module", "bin": { diff --git a/docs/release.md b/docs/release.md new file mode 100644 index 00000000..4c328d64 --- /dev/null +++ b/docs/release.md @@ -0,0 +1,48 @@ +# Release runbook + +## Automated flow + +1. Pull requests must use a Conventional Commit title such as `feat(renderer): add cursor support`. +2. Repository settings should allow squash merges only and configure the squash commit title to use the pull request title. +3. After changes land on `main`, `.github/workflows/release-please.yml` opens or updates one Release Please PR. +4. Merging the Release Please PR creates one `vX.Y.Z-rc.N` tag and a GitHub prerelease while this RC configuration is enabled. The first expected release candidate is `v0.5.0-rc.0`. +5. The Release Please workflow explicitly dispatches `.github/workflows/publish.yml` for the tag because workflows created with `GITHUB_TOKEN` do not reliably trigger follow-up workflows automatically. +6. `publish.yml` validates the tag and source versions, runs the release quality gates, publishes `ghostty-web`, then publishes `@ghostty-web/demo` with its `ghostty-web` dependency pinned to the exact release version. + +## AI release notes + +Release Please owns the canonical changelog structure, commit sections, headings, and links. The custom `changelog-type: "ai"` generator only inserts a concise editorial summary and optional highlights below the version heading. + +The AI path uses an AI SDK `ToolLoopAgent` with scoped tools. It can list the release commits and inspect GitHub commit diffs for those SHAs before producing the structured editorial summary. The tools reject SHAs outside the current release scope. + +- Configure `ANTHROPIC_API_KEY` as a repository secret to enable AI editorial notes. +- Configure `RELEASE_NOTES_MODEL` as a repository variable to choose the model. +- If either setting is missing or model generation fails, the runner logs the reason and falls back to default Release Please notes. + +## Next publishes + +`.github/workflows/publish.yml` also publishes `ghostty-web@next` and `@ghostty-web/demo@next` after successful CI on `main`. Release-only squash commits whose subject matches `chore(release): ...` are skipped so version/changelog-only release PR merges do not create noisy prereleases. + +Stable, release-candidate, and `next` publishing intentionally live in this single workflow file because npm trusted publishing is configured against a workflow identity. + +## Release candidate rollout + +The Release Please config intentionally uses the `prerelease` versioning strategy with `prerelease-type: rc.0` so the next release PR should produce `0.5.0-rc.0` instead of `0.5.0`. The publish workflow derives the npm dist-tag from prerelease versions, so `0.5.0-rc.0` publishes under the `rc` tag rather than `latest`. + +When the pipeline has been test-driven successfully and maintainers are ready for a stable release, remove the prerelease settings from `release-please-config.json` so the next Release Please PR can promote to a normal `0.5.0` release. + +## Manual recovery + +- Rerun `Release Please` on `main` to recreate or update a release PR. +- Dispatch `publish.yml` manually with an existing `vX.Y.Z-rc.N` or `vX.Y.Z` tag to retry npm publishing. +- Publish jobs are idempotent: if a package version already exists on npm, the workflow skips publishing and attempts to repair the matching dist-tag (`rc` for `0.5.0-rc.0`, `latest` for stable versions). + +## Required admin setup + +Before the first automated stable release: + +- Configure npm trusted publishers for both `ghostty-web` and `@ghostty-web/demo` for `.github/workflows/publish.yml`. +- Add the `ANTHROPIC_API_KEY` repository secret if AI editorial notes should be enabled. +- Add the `RELEASE_NOTES_MODEL` repository variable when using AI notes. +- Enable squash merging, disable merge commits and rebase merging, and set squash commit titles to use the pull request title. +- Require the `pr-title`, `fmt`, `lint`, `type check`, `test`, and `build` checks before merge; require merge-group variants too if merge queue is enabled. diff --git a/flake.nix b/flake.nix index eef8e68c..695f5b34 100644 --- a/flake.nix +++ b/flake.nix @@ -26,7 +26,7 @@ packages.default = pkgs.stdenv.mkDerivation { pname = "ghostty-web"; - version = "0.3.0"; + version = "0.4.0"; # x-release-please-version src = ./.; diff --git a/package.json b/package.json index 0b93caba..ecaf531a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ghostty-web", - "version": "0.3.0", + "version": "0.4.0", "description": "Web-based terminal emulator using Ghostty's VT100 parser via WebAssembly", "type": "module", "main": "./dist/ghostty-web.umd.cjs", @@ -59,18 +59,24 @@ "fmt:fix": "prettier --write --cache .", "lint": "biome check .", "lint:fix": "biome check --write .", - "prepublishOnly": "bun run build" + "prepublishOnly": "bun run build", + "release-please": "tsx scripts/release-please-runner.ts" }, "devDependencies": { + "@ai-sdk/anthropic": "^4.0.0", "@biomejs/biome": "^1.9.4", "@happy-dom/global-registrator": "^15.11.0", "@types/bun": "^1.3.2", "@xterm/headless": "^5.5.0", "@xterm/xterm": "^5.5.0", + "ai": "^7.0.2", "mitata": "^1.0.34", "prettier": "^3.6.2", + "release-please": "17.9.0", + "tsx": "^4.22.4", "typescript": "^5.9.3", "vite": "^4.5.0", - "vite-plugin-dts": "^4.5.4" + "vite-plugin-dts": "^4.5.4", + "zod": "^4.4.3" } } diff --git a/release-please-config.json b/release-please-config.json new file mode 100644 index 00000000..c80e04f7 --- /dev/null +++ b/release-please-config.json @@ -0,0 +1,83 @@ +{ + "$schema": "https://raw.githubusercontent.com/googleapis/release-please/main/schemas/config.json", + "release-type": "node", + "changelog-type": "ai", + "include-component-in-tag": false, + "include-v-in-tag": true, + "bump-minor-pre-major": true, + "pull-request-title-pattern": "chore(release): ${version}", + "pull-request-header": "The next ghostty-web release candidate. Merging this PR creates a prerelease tag and GitHub Release, then starts the publish pipeline.", + "pull-request-footer": "Maintained by the release-please workflow. Manual edits to generated release notes may be overwritten.", + "changelog-sections": [ + { + "type": "feat", + "section": "Features" + }, + { + "type": "fix", + "section": "Bug Fixes" + }, + { + "type": "perf", + "section": "Performance Improvements" + }, + { + "type": "revert", + "section": "Reverts" + }, + { + "type": "deps", + "section": "Dependencies" + }, + { + "type": "docs", + "section": "Documentation" + }, + { + "type": "refactor", + "section": "Code Refactoring" + }, + { + "type": "build", + "section": "Build System", + "hidden": true + }, + { + "type": "ci", + "section": "Continuous Integration", + "hidden": true + }, + { + "type": "test", + "section": "Tests", + "hidden": true + }, + { + "type": "style", + "section": "Styles", + "hidden": true + }, + { + "type": "chore", + "section": "Miscellaneous Chores", + "hidden": true + } + ], + "packages": { + ".": { + "package-name": "ghostty-web", + "changelog-path": "CHANGELOG.md", + "extra-files": [ + { + "type": "json", + "path": "demo/package.json", + "jsonpath": "$.version" + }, + "flake.nix" + ] + } + }, + "versioning": "prerelease", + "prerelease": true, + "prerelease-type": "rc.0" +} diff --git a/scripts/release-please-ai/changelog-notes.test.ts b/scripts/release-please-ai/changelog-notes.test.ts new file mode 100644 index 00000000..15b340db --- /dev/null +++ b/scripts/release-please-ai/changelog-notes.test.ts @@ -0,0 +1,83 @@ +import { describe, expect, test } from 'bun:test'; +import type { BuildNotesOptions, ChangelogNotes } from 'release-please/build/src/changelog-notes'; +import type { ConventionalCommit } from 'release-please/build/src/commit'; +import { AiChangelogNotes } from './changelog-notes'; + +const options: BuildNotesOptions = { + owner: 'coder', + repository: 'ghostty-web', + version: '1.2.3', + currentTag: 'v1.2.3', + targetBranch: 'main', + changelogSections: [{ type: 'feat', section: 'Features' }], +}; + +const commits: ConventionalCommit[] = [ + { + sha: 'abc123', + message: 'feat: add renderer support', + files: [], + type: 'feat', + scope: null, + notes: [], + references: [ + { action: null, owner: null, repository: null, issue: '17', raw: '#17', prefix: '#' }, + ], + bareMessage: 'add renderer support', + breaking: false, + }, +]; + +class FakeDefaultNotes implements ChangelogNotes { + async buildNotes(): Promise { + return '## [1.2.3](link)\n\n### Features\n- add renderer support'; + } +} + +describe('AiChangelogNotes', () => { + test('returns default release-please notes when ANTHROPIC_API_KEY is missing', async () => { + const notes = new AiChangelogNotes({ + defaultNotes: new FakeDefaultNotes(), + env: {}, + generate: async () => { + throw new Error('should not call the model without credentials'); + }, + }); + + await expect(notes.buildNotes(commits, options)).resolves.toBe( + '## [1.2.3](link)\n\n### Features\n- add renderer support' + ); + }); + + test('injects mocked editorial notes when model generation succeeds', async () => { + const notes = new AiChangelogNotes({ + defaultNotes: new FakeDefaultNotes(), + env: { ANTHROPIC_API_KEY: 'test-key', RELEASE_NOTES_MODEL: 'test-model' }, + generate: async ({ commits: visible }) => { + expect(visible).toHaveLength(1); + return { + summary: 'Renderer support improves terminal integrations.', + highlights: [{ text: 'Renderer support', prNumber: 17 }], + }; + }, + }); + + await expect(notes.buildNotes(commits, options)).resolves.toBe( + '## [1.2.3](link)\n\nRenderer support improves terminal integrations.\n\n**Highlights**\n\n- Renderer support (#17)\n\n### Features\n- add renderer support' + ); + }); + test('falls back to default release-please notes when model generation fails', async () => { + const notes = new AiChangelogNotes({ + defaultNotes: new FakeDefaultNotes(), + env: { ANTHROPIC_API_KEY: 'test-key', RELEASE_NOTES_MODEL: 'test-model' }, + logger: { log() {}, warn() {} }, + generate: async () => { + throw new Error('model unavailable'); + }, + }); + + await expect(notes.buildNotes(commits, options)).resolves.toBe( + '## [1.2.3](link)\n\n### Features\n- add renderer support' + ); + }); +}); diff --git a/scripts/release-please-ai/changelog-notes.ts b/scripts/release-please-ai/changelog-notes.ts new file mode 100644 index 00000000..dd23066e --- /dev/null +++ b/scripts/release-please-ai/changelog-notes.ts @@ -0,0 +1,91 @@ +import type { BuildNotesOptions, ChangelogNotes } from 'release-please/build/src/changelog-notes'; +import { DefaultChangelogNotes } from 'release-please/build/src/changelog-notes/default'; +import type { ConventionalCommit } from 'release-please/build/src/commit'; +import { + type ChangelogNotesFactoryOptions, + registerChangelogNotes, +} from 'release-please/build/src/factories/changelog-notes-factory'; +import { generateEditorial } from './generate'; +import { injectAfterHeader, renderEditorial, visibleCommits } from './sections'; +import type { GenerateEditorial } from './types'; + +export const AI_CHANGELOG_TYPE = 'ai'; + +type Env = Pick; + +export interface AiChangelogNotesOptions { + defaultNotes?: ChangelogNotes; + env?: Env; + generate?: GenerateEditorial; + logger?: Pick; +} + +export class AiChangelogNotes implements ChangelogNotes { + private readonly defaultNotes: ChangelogNotes; + private readonly env: Env; + private readonly generate: GenerateEditorial; + private readonly logger: Pick; + + constructor(options: AiChangelogNotesOptions = {}) { + this.defaultNotes = options.defaultNotes ?? new DefaultChangelogNotes(); + this.env = options.env ?? process.env; + this.generate = options.generate ?? generateEditorial; + this.logger = options.logger ?? console; + } + + async buildNotes(commits: ConventionalCommit[], options: BuildNotesOptions): Promise { + const defaultNotes = await this.defaultNotes.buildNotes(commits, options); + const apiKey = this.env.ANTHROPIC_API_KEY; + const model = this.env.RELEASE_NOTES_MODEL; + + if (!apiKey) { + this.logger.log( + 'Release notes AI disabled: ANTHROPIC_API_KEY is not configured; using default notes.' + ); + return defaultNotes; + } + if (!model) { + this.logger.warn( + 'Release notes AI disabled: RELEASE_NOTES_MODEL is not configured; using default notes.' + ); + return defaultNotes; + } + + const visible = visibleCommits(commits, options.changelogSections); + if (visible.length === 0) { + this.logger.log('Release notes AI skipped: no visible commits; using default notes.'); + return defaultNotes; + } + + try { + const editorial = await this.generate({ + commits: visible, + owner: options.owner, + repository: options.repository, + version: options.version, + model, + githubToken: this.env.GITHUB_TOKEN, + }); + const rendered = renderEditorial(editorial); + this.logger.log('Release notes AI generated editorial summary.'); + return injectAfterHeader(defaultNotes, rendered); + } catch (error) { + this.logger.warn( + `Release notes AI failed; using default notes. ${error instanceof Error ? error.message : String(error)}` + ); + return defaultNotes; + } + } +} + +export function registerAiChangelogNotes(): void { + registerChangelogNotes(AI_CHANGELOG_TYPE, (options: ChangelogNotesFactoryOptions) => { + return new AiChangelogNotes({ + defaultNotes: new DefaultChangelogNotes({ + commitPartial: options.commitPartial, + headerPartial: options.headerPartial, + mainTemplate: options.mainTemplate, + }), + }); + }); +} diff --git a/scripts/release-please-ai/generate.ts b/scripts/release-please-ai/generate.ts new file mode 100644 index 00000000..b3c69acf --- /dev/null +++ b/scripts/release-please-ai/generate.ts @@ -0,0 +1,37 @@ +import { createAnthropic } from '@ai-sdk/anthropic'; +import { Output, ToolLoopAgent, stepCountIs } from 'ai'; +import { buildReleaseNotesPrompt } from './prompt'; +import { createReleaseInspectionTools } from './tools'; +import { type Editorial, type GenerateEditorialInput, editorialSchema } from './types'; + +export async function generateEditorial(input: GenerateEditorialInput): Promise { + if (!input.model) { + throw new Error('RELEASE_NOTES_MODEL is required when ANTHROPIC_API_KEY is set'); + } + + const anthropic = createAnthropic({ apiKey: process.env.ANTHROPIC_API_KEY }); + const tools = createReleaseInspectionTools({ + commits: input.commits, + owner: input.owner, + repository: input.repository, + githubToken: input.githubToken, + }); + const agent = new ToolLoopAgent({ + model: anthropic(input.model), + tools, + toolChoice: 'auto', + stopWhen: stepCountIs(6), + output: Output.object({ + schema: editorialSchema, + name: 'ghosttyWebReleaseNotesEditorial', + description: 'Concise editorial release notes summary and highlights.', + }), + instructions: + 'You are writing release notes for ghostty-web. Inspect relevant commit diffs with the provided tools before producing the final structured output.', + }); + + const result = await agent.generate({ + prompt: buildReleaseNotesPrompt(input.commits, input.version), + }); + return result.output; +} diff --git a/scripts/release-please-ai/prompt.test.ts b/scripts/release-please-ai/prompt.test.ts new file mode 100644 index 00000000..8f078db0 --- /dev/null +++ b/scripts/release-please-ai/prompt.test.ts @@ -0,0 +1,31 @@ +import { describe, expect, test } from 'bun:test'; +import type { ConventionalCommit } from 'release-please/build/src/commit'; +import { buildReleaseNotesPrompt } from './prompt'; + +function commit(): ConventionalCommit { + return { + sha: 'abc123def456', + message: 'feat(renderer): improve cursor contrast (#42)', + files: [], + type: 'feat', + scope: 'renderer', + notes: [], + references: [ + { action: null, owner: null, repository: null, issue: '42', raw: '#42', prefix: '#' }, + ], + bareMessage: 'improve cursor contrast', + breaking: false, + }; +} + +describe('buildReleaseNotesPrompt', () => { + test('directs the model to inspect diffs with tools instead of relying on commit titles only', () => { + const prompt = buildReleaseNotesPrompt([commit()], '1.2.3'); + + expect(prompt).toContain('Call `listReleaseCommits`'); + expect(prompt).toContain('`inspectCommit`'); + expect(prompt).toContain('abc123def456'); + expect(prompt).toContain('"prNumber": 42'); + expect(prompt).not.toContain('- feat(renderer): improve cursor contrast'); + }); +}); diff --git a/scripts/release-please-ai/prompt.ts b/scripts/release-please-ai/prompt.ts new file mode 100644 index 00000000..aced8848 --- /dev/null +++ b/scripts/release-please-ai/prompt.ts @@ -0,0 +1,20 @@ +import type { ConventionalCommit } from 'release-please/build/src/commit'; +import { summarizeReleaseCommits } from './tools'; + +export function buildReleaseNotesPrompt(commits: ConventionalCommit[], version: string): string { + return [ + `Write concise editorial release notes for ghostty-web ${version}.`, + '', + 'Audience: engineers using a browser terminal emulator, integrating WASM terminal parsing, Canvas rendering, keyboard/input handling, selection, PTY demo tooling, or xterm.js-compatible APIs.', + 'Explain what changed and why it matters. Be factual and sparse when commit titles are sparse.', + 'Highlight user-visible terminal rendering, input/keyboard protocol, WASM/VT parsing, selection/clipboard, demo/server usability, performance, and compatibility changes.', + 'Skip pure internal chores, CI, tests, formatting, and release automation unless they directly affect users.', + '', + 'Call `listReleaseCommits` first, then call `inspectCommit` for notable or ambiguous changes so the summary is based on actual diffs rather than commit titles alone.', + 'Use only PR numbers returned by the tools; do not guess PR numbers.', + 'Return only the structured summary/highlights object requested by the output schema.', + '', + 'Release commit scope:', + JSON.stringify(summarizeReleaseCommits(commits), null, 2), + ].join('\n'); +} diff --git a/scripts/release-please-ai/render.test.ts b/scripts/release-please-ai/render.test.ts new file mode 100644 index 00000000..fdd53500 --- /dev/null +++ b/scripts/release-please-ai/render.test.ts @@ -0,0 +1,36 @@ +import { describe, expect, test } from 'bun:test'; +import { injectAfterHeader, renderEditorial } from './sections'; + +describe('renderEditorial', () => { + test('renders flattened summary and linked highlights', () => { + expect( + renderEditorial({ + summary: 'First line\n## not a heading', + highlights: [ + { text: 'Adds rendering fix\nwith details', prNumber: 42 }, + { text: 'No PR link', prNumber: null }, + ], + }) + ).toBe( + 'First line ## not a heading\n\n**Highlights**\n\n- Adds rendering fix with details (#42)\n- No PR link' + ); + }); + + test('omits an empty highlight list', () => { + expect(renderEditorial({ summary: 'Only summary', highlights: [] })).toBe('Only summary'); + }); +}); + +describe('injectAfterHeader', () => { + test('injects editorial notes immediately below the version heading', () => { + expect(injectAfterHeader('## [1.0.0](link)\n\n### Features\n- one', 'Summary')).toBe( + '## [1.0.0](link)\n\nSummary\n\n### Features\n- one' + ); + }); + + test('falls back safely when release-please notes have no heading', () => { + expect(injectAfterHeader('### Features\n- one', 'Summary')).toBe( + 'Summary\n\n### Features\n- one' + ); + }); +}); diff --git a/scripts/release-please-ai/sections.test.ts b/scripts/release-please-ai/sections.test.ts new file mode 100644 index 00000000..8a10d24c --- /dev/null +++ b/scripts/release-please-ai/sections.test.ts @@ -0,0 +1,44 @@ +import { describe, expect, test } from 'bun:test'; +import type { ChangelogSection } from 'release-please/build/src/changelog-notes'; +import type { ConventionalCommit } from 'release-please/build/src/commit'; +import { visibleCommits } from './sections'; + +function commit(type: string, bareMessage = `${type}: message`): ConventionalCommit { + return { + sha: `sha-${type}`, + message: bareMessage, + files: [], + type, + scope: null, + notes: [], + references: [], + bareMessage, + breaking: false, + }; +} + +describe('visibleCommits', () => { + test('filters commits whose configured changelog section is hidden', () => { + const sections: ChangelogSection[] = [ + { type: 'feat', section: 'Features' }, + { type: 'fix', section: 'Bug Fixes' }, + { type: 'chore', section: 'Chores', hidden: true }, + { type: 'ci', section: 'CI', hidden: true }, + ]; + + expect( + visibleCommits([commit('feat'), commit('chore'), commit('fix'), commit('ci')], sections).map( + (c) => c.type + ) + ).toEqual(['feat', 'fix']); + }); + + test('uses the ghostty-web visible type allowlist when sections are absent', () => { + expect( + visibleCommits( + [commit('docs'), commit('build'), commit('deps'), commit('test')], + undefined + ).map((c) => c.type) + ).toEqual(['docs', 'deps']); + }); +}); diff --git a/scripts/release-please-ai/sections.ts b/scripts/release-please-ai/sections.ts new file mode 100644 index 00000000..76ffed3d --- /dev/null +++ b/scripts/release-please-ai/sections.ts @@ -0,0 +1,84 @@ +import type { ChangelogSection } from 'release-please/build/src/changelog-notes'; +import type { ConventionalCommit } from 'release-please/build/src/commit'; +import type { Editorial } from './types'; + +const DEFAULT_VISIBLE_TYPES = new Set([ + 'feat', + 'fix', + 'perf', + 'revert', + 'deps', + 'docs', + 'refactor', +]); + +export function visibleCommits( + commits: ConventionalCommit[], + sections?: ChangelogSection[] +): ConventionalCommit[] { + if (!sections?.length) { + return commits.filter((commit) => DEFAULT_VISIBLE_TYPES.has(commit.type)); + } + + const visibleTypes = new Set( + sections.filter((section) => !section.hidden).map((section) => section.type) + ); + return commits.filter((commit) => visibleTypes.has(commit.type)); +} + +function flattenMarkdownLine(value: string): string { + return value + .replace(/[\r\n]+/g, ' ') + .replace(/\s+/g, ' ') + .trim(); +} + +export function renderEditorial(editorial: Editorial): string { + const summary = flattenMarkdownLine(editorial.summary); + const highlights = editorial.highlights + .map((highlight) => ({ + text: flattenMarkdownLine(highlight.text), + prNumber: highlight.prNumber, + })) + .filter((highlight) => highlight.text.length > 0) + .slice(0, 5); + + if (highlights.length === 0) { + return summary; + } + + return [ + summary, + '', + '**Highlights**', + '', + ...highlights.map( + (highlight) => `- ${highlight.text}${highlight.prNumber ? ` (#${highlight.prNumber})` : ''}` + ), + ].join('\n'); +} + +export function injectAfterHeader(defaultNotes: string, editorialMarkdown: string): string { + const editorial = editorialMarkdown.trim(); + if (!editorial) { + return defaultNotes; + } + + const match = defaultNotes.match(/^(##\s+[^\n]+)\n+/); + if (!match) { + return `${editorial}\n\n${defaultNotes}`; + } + + return `${match[1]}\n\n${editorial}\n\n${defaultNotes.slice(match[0].length)}`; +} + +export function firstPullRequestNumber(commit: ConventionalCommit): number | null { + for (const reference of commit.references ?? []) { + const issue = Number.parseInt(reference.issue, 10); + if (Number.isInteger(issue) && issue > 0) { + return issue; + } + } + const prNumber = commit.pullRequest?.number; + return Number.isInteger(prNumber) && prNumber > 0 ? prNumber : null; +} diff --git a/scripts/release-please-ai/tools.test.ts b/scripts/release-please-ai/tools.test.ts new file mode 100644 index 00000000..b1305f9f --- /dev/null +++ b/scripts/release-please-ai/tools.test.ts @@ -0,0 +1,88 @@ +import { describe, expect, test } from 'bun:test'; +import type { ConventionalCommit } from 'release-please/build/src/commit'; +import { createReleaseInspectionTools } from './tools'; + +function commit(): ConventionalCommit { + return { + sha: 'abc123', + message: 'fix: render cursor accent (#9)', + files: [], + type: 'fix', + scope: null, + notes: [], + references: [ + { action: null, owner: null, repository: null, issue: '9', raw: '#9', prefix: '#' }, + ], + bareMessage: 'render cursor accent', + breaking: false, + }; +} + +describe('createReleaseInspectionTools', () => { + test('lists scoped release commits for the agent', async () => { + const tools = createReleaseInspectionTools({ + commits: [commit()], + owner: 'coder', + repository: 'ghostty-web', + fetch: async () => new Response('{}'), + }); + + const result = await tools.listReleaseCommits.execute({}, {} as never); + + expect(result).toEqual([ + { + sha: 'abc123', + type: 'fix', + scope: null, + message: 'render cursor accent', + prNumber: 9, + }, + ]); + }); + + test('inspects only allowed release commit diffs and truncates patches', async () => { + const tools = createReleaseInspectionTools({ + commits: [commit()], + owner: 'coder', + repository: 'ghostty-web', + fetch: async (url) => { + expect(String(url)).toContain('/repos/coder/ghostty-web/commits/abc123'); + return Response.json({ + sha: 'abc123', + commit: { message: 'fix: render cursor accent (#9)' }, + files: [ + { + filename: 'lib/renderer.ts', + status: 'modified', + additions: 10, + deletions: 2, + patch: `${'x'.repeat(5000)}\nend`, + }, + ], + }); + }, + }); + + const result = await tools.inspectCommit.execute({ sha: 'abc123' }, {} as never); + + expect(result.sha).toBe('abc123'); + expect(result.files).toHaveLength(1); + expect(result.files[0].patch.length).toBeLessThan(4200); + expect(result.files[0].patch).toContain('…'); + }); + + test('rejects commits outside the release scope', async () => { + const tools = createReleaseInspectionTools({ + commits: [commit()], + owner: 'coder', + repository: 'ghostty-web', + fetch: async () => { + throw new Error('should not fetch unknown commits'); + }, + }); + + await expect(tools.inspectCommit.execute({ sha: 'unknown' }, {} as never)).rejects.toThrow( + 'not part of this release' + ); + }); +}); diff --git a/scripts/release-please-ai/tools.ts b/scripts/release-please-ai/tools.ts new file mode 100644 index 00000000..d083430a --- /dev/null +++ b/scripts/release-please-ai/tools.ts @@ -0,0 +1,120 @@ +import { tool } from 'ai'; +import type { ConventionalCommit } from 'release-please/build/src/commit'; +import { z } from 'zod'; +import { firstPullRequestNumber } from './sections'; + +const MAX_FILES = 12; +const MAX_PATCH_CHARS = 4_000; +const MAX_TOTAL_PATCH_CHARS = 16_000; + +export interface ReleaseInspectionToolsOptions { + commits: ConventionalCommit[]; + owner: string; + repository: string; + githubToken?: string; + fetch?: typeof fetch; +} + +interface GitHubCommitFile { + filename: string; + status?: string; + additions?: number; + deletions?: number; + patch?: string; +} + +interface GitHubCommitResponse { + sha: string; + commit?: { message?: string }; + files?: GitHubCommitFile[]; +} + +function truncate(value: string, maxLength: number): string { + if (value.length <= maxLength) { + return value; + } + return `${value.slice(0, maxLength)}\n… truncated …`; +} + +function summarizeCommit(commit: ConventionalCommit) { + return { + sha: commit.sha, + type: commit.type, + scope: commit.scope, + message: commit.bareMessage, + prNumber: firstPullRequestNumber(commit), + }; +} + +export function summarizeReleaseCommits( + commits: ConventionalCommit[] +): ReturnType[] { + return commits.map(summarizeCommit); +} + +export function createReleaseInspectionTools(options: ReleaseInspectionToolsOptions) { + const commitsBySha = new Map(options.commits.map((commit) => [commit.sha, commit])); + const fetchImpl = options.fetch ?? fetch; + + return { + listReleaseCommits: tool({ + description: 'List the release commits that may be inspected for this changelog.', + inputSchema: z.object({}), + execute: async () => summarizeReleaseCommits(options.commits), + }), + inspectCommit: tool({ + description: + 'Fetch a scoped GitHub commit diff for one release commit. Use this before writing notes for non-trivial changes.', + inputSchema: z.object({ + sha: z.string().describe('One SHA returned by listReleaseCommits.'), + }), + execute: async ({ sha }) => { + const commit = commitsBySha.get(sha); + if (!commit) { + throw new Error(`Commit ${sha} is not part of this release.`); + } + + const headers: Record = { + Accept: 'application/vnd.github+json', + 'X-GitHub-Api-Version': '2022-11-28', + }; + if (options.githubToken) { + headers.Authorization = `Bearer ${options.githubToken}`; + } + + const response = await fetchImpl( + `https://api.github.com/repos/${options.owner}/${options.repository}/commits/${sha}`, + { headers } + ); + if (!response.ok) { + throw new Error( + `GitHub commit lookup failed for ${sha}: ${response.status} ${response.statusText}` + ); + } + + const data = (await response.json()) as GitHubCommitResponse; + let totalPatchChars = 0; + const files = (data.files ?? []).slice(0, MAX_FILES).map((file) => { + const remaining = Math.max(0, MAX_TOTAL_PATCH_CHARS - totalPatchChars); + const patch = truncate(file.patch ?? '', Math.min(MAX_PATCH_CHARS, remaining)); + totalPatchChars += patch.length; + return { + filename: file.filename, + status: file.status ?? 'modified', + additions: file.additions ?? 0, + deletions: file.deletions ?? 0, + patch, + }; + }); + + return { + sha: data.sha || sha, + message: data.commit?.message || commit.message, + releaseSummary: summarizeCommit(commit), + files, + truncatedFiles: Math.max(0, (data.files?.length ?? 0) - files.length), + }; + }, + }), + }; +} diff --git a/scripts/release-please-ai/types.ts b/scripts/release-please-ai/types.ts new file mode 100644 index 00000000..1b28271c --- /dev/null +++ b/scripts/release-please-ai/types.ts @@ -0,0 +1,27 @@ +import type { ConventionalCommit } from 'release-please/build/src/commit'; +import { z } from 'zod'; + +export const editorialSchema = z.object({ + summary: z.string(), + highlights: z + .array( + z.object({ + text: z.string(), + prNumber: z.number().int().positive().nullable(), + }) + ) + .default([]), +}); + +export type Editorial = z.infer; + +export interface GenerateEditorialInput { + commits: ConventionalCommit[]; + owner: string; + repository: string; + version: string; + model: string; + githubToken?: string; +} + +export type GenerateEditorial = (input: GenerateEditorialInput) => Promise; diff --git a/scripts/release-please-runner.test.ts b/scripts/release-please-runner.test.ts new file mode 100644 index 00000000..a6dc356d --- /dev/null +++ b/scripts/release-please-runner.test.ts @@ -0,0 +1,47 @@ +import { describe, expect, test } from 'bun:test'; +import { readFileSync } from 'node:fs'; +import { formatOutputLines, formatPrMetadata } from './release-please-runner'; + +describe('release-please config', () => { + test('creates the next release as an RC prerelease for pipeline dogfooding', () => { + const config = JSON.parse(readFileSync('release-please-config.json', 'utf8')); + + expect(config.versioning).toBe('prerelease'); + expect(config.prerelease).toBe(true); + expect(config['prerelease-type']).toBe('rc.0'); + }); +}); + +describe('release-please runner output formatting', () => { + test('formats release tags, PR branches, and JSON PR metadata', () => { + const outputs = formatOutputLines({ + releases: [{ tagName: 'v1.0.0' }, { tagName: 'v1.1.0' }], + pullRequests: [ + { branch: 'release-please--branches--main', title: 'chore(release): 1.1.0' }, + { + branch: 'release-please--branches--main--components--docs', + title: 'docs: release notes', + }, + ], + }); + + expect(outputs).toContain('releases_created=true'); + expect(outputs).toContain('release_tags=v1.0.0 v1.1.0'); + expect(outputs).toContain('prs_created=true'); + expect(outputs).toContain( + 'pr_branches=release-please--branches--main release-please--branches--main--components--docs' + ); + expect( + JSON.parse( + outputs.find((line) => line.startsWith('pr_metadata='))!.slice('pr_metadata='.length) + ) + ).toEqual([ + { branch: 'release-please--branches--main', title: 'chore(release): 1.1.0' }, + { branch: 'release-please--branches--main--components--docs', title: 'docs: release notes' }, + ]); + }); + + test('formats empty PR metadata as a stable JSON array', () => { + expect(formatPrMetadata([])).toBe('[]'); + }); +}); diff --git a/scripts/release-please-runner.ts b/scripts/release-please-runner.ts new file mode 100644 index 00000000..8258afb8 --- /dev/null +++ b/scripts/release-please-runner.ts @@ -0,0 +1,165 @@ +import { appendFileSync } from 'node:fs'; +import { createRequire } from 'node:module'; +import type { BaseStrategyOptions } from 'release-please/build/src/strategies/base'; +import { registerAiChangelogNotes } from './release-please-ai/changelog-notes'; + +const nodeRequire = createRequire(import.meta.url); + +export interface RunnerReleaseOutput { + tagName: string; +} + +export interface RunnerPullRequestOutput { + branch: string; + title: string; +} + +export interface RunnerOutputs { + releases: RunnerReleaseOutput[]; + pullRequests: RunnerPullRequestOutput[]; +} + +export function formatPrMetadata(pullRequests: RunnerPullRequestOutput[]): string { + return JSON.stringify(pullRequests.map(({ branch, title }) => ({ branch, title }))); +} + +export function formatOutputLines(outputs: RunnerOutputs): string[] { + const releaseTags = outputs.releases.map((release) => release.tagName).join(' '); + const prBranches = outputs.pullRequests.map((pr) => pr.branch).join(' '); + return [ + `releases_created=${outputs.releases.length > 0}`, + `release_tags=${releaseTags}`, + `prs_created=${outputs.pullRequests.length > 0}`, + `pr_branches=${prBranches}`, + `pr_metadata=${formatPrMetadata(outputs.pullRequests)}`, + ]; +} + +function writeGithubOutputs(lines: string[]): void { + const outputPath = process.env.GITHUB_OUTPUT; + if (!outputPath) { + for (const line of lines) { + console.log(line); + } + return; + } + appendFileSync(outputPath, `${lines.join('\n')}\n`); +} + +async function registerReleasePleaseExtensions(): Promise { + const { registerReleaseType } = nodeRequire('release-please/build/src/factory'); + const { Node: NodeStrategy } = nodeRequire('release-please/build/src/strategies/node'); + + class GhosttyWebNodeStrategy extends NodeStrategy { + // Release Please otherwise may suffix the release branch with the component even + // though this single-package repository intentionally uses plain vX.Y.Z tags. + async getBranchComponent(): Promise { + if (!this.includeComponentInTag) { + return undefined; + } + return super.getBranchComponent(); + } + } + + registerAiChangelogNotes(); + registerReleaseType( + 'node', + (options: BaseStrategyOptions) => new GhosttyWebNodeStrategy(options) + ); +} + +function requireEnv(name: string): string { + const value = process.env[name]; + if (!value) { + throw new Error(`${name} is required`); + } + return value; +} + +function parseRepository(repository: string): { owner: string; repo: string } { + const [owner, repo] = repository.split('/'); + if (!owner || !repo) { + throw new Error(`GITHUB_REPOSITORY must be in owner/repo form, got ${repository}`); + } + return { owner, repo }; +} + +function tagNameFromRelease(release: { tag: { toString(): string } }): string { + return release.tag.toString(); +} + +async function main(): Promise { + const dryRun = process.argv.includes('--dry-run'); + const token = requireEnv('GITHUB_TOKEN'); + const { owner, repo } = parseRepository(requireEnv('GITHUB_REPOSITORY')); + const targetBranch = process.env.RELEASE_PLEASE_TARGET_BRANCH || 'main'; + const configFile = process.env.RELEASE_PLEASE_CONFIG_FILE || 'release-please-config.json'; + const manifestFile = process.env.RELEASE_PLEASE_MANIFEST_FILE || '.release-please-manifest.json'; + + await registerReleasePleaseExtensions(); + + const { GitHub } = nodeRequire('release-please/build/src/github'); + const { Manifest } = nodeRequire('release-please/build/src/manifest'); + const github = await GitHub.create({ owner, repo, token }); + const manifest = await Manifest.fromManifest(github, targetBranch, configFile, manifestFile); + + if (dryRun) { + const releases = await manifest.buildReleases(); + const pullRequests = await manifest.buildPullRequests(); + const preview = { + dryRun: true, + releases: releases.map((release) => ({ + tag: tagNameFromRelease(release), + name: release.name, + sha: release.sha, + notes: release.notes, + })), + pullRequests: pullRequests.map((pullRequest) => ({ + branch: pullRequest.headRefName, + title: pullRequest.title.toString(), + version: pullRequest.version?.toString(), + updates: pullRequest.updates.map((update) => update.path), + body: pullRequest.body.toString(), + })), + }; + console.log(JSON.stringify(preview, null, 2)); + writeGithubOutputs( + formatOutputLines({ + releases: releases.map((release) => ({ tagName: tagNameFromRelease(release) })), + pullRequests: pullRequests.map((pullRequest) => ({ + branch: pullRequest.headRefName, + title: pullRequest.title.toString(), + })), + }) + ); + return; + } + + const createdReleases = (await manifest.createReleases()).filter( + (release) => release !== undefined + ); + writeGithubOutputs([ + `releases_created=${createdReleases.length > 0}`, + `release_tags=${createdReleases.map((release) => release.tagName).join(' ')}`, + ]); + + const createdPullRequests = (await manifest.createPullRequests()).filter( + (pullRequest) => pullRequest !== undefined + ); + const pullRequests = createdPullRequests.map((pullRequest) => ({ + branch: pullRequest.headBranchName, + title: pullRequest.title, + })); + writeGithubOutputs([ + `prs_created=${pullRequests.length > 0}`, + `pr_branches=${pullRequests.map((pr) => pr.branch).join(' ')}`, + `pr_metadata=${formatPrMetadata(pullRequests)}`, + ]); +} + +if (import.meta.url === `file://${process.argv[1]}`) { + main().catch((error) => { + console.error(error); + process.exitCode = 1; + }); +}