From 3237132df0dd749cb561512eef5c388e8acac968 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 2 May 2026 15:47:24 +0000 Subject: [PATCH 1/2] feat: scaffold experimental aw-harness TypeScript project Implements specs/aw-harness.md as an EXPERIMENTAL engine: aw execution engine built on the Pi SDK (@mariozechner/pi-coding-agent). - Creates aw-harness/ TypeScript project with pinned deps, vitest tests, and esbuild bundler - Implements all 5 Pi extensions: provider-setup, cost-tracker, steering, repair, observability - 75 unit tests covering all modules - Adds make aw-harness, make deps-aw-harness, make lint-aw-harness targets - Links aw-harness to make build (aw-harness as build dep) and make lint - Marks as [EXPERIMENTAL] in entry point, README, step summary, and runtime stderr warning Agent-Logs-Url: https://github.com/github/gh-aw/sessions/c34f8c7a-4089-44e1-8a52-edaaa5c215a7 Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- .gitignore | 5 +- Makefile | 33 +- aw-harness/README.md | 96 + aw-harness/build.ts | 36 + aw-harness/package-lock.json | 5780 +++++++++++++++++ aw-harness/package.json | 26 + aw-harness/src/context.ts | 47 + aw-harness/src/extensions/cost-tracker.ts | 97 + aw-harness/src/extensions/observability.ts | 272 + aw-harness/src/extensions/provider-setup.ts | 76 + aw-harness/src/extensions/repair.ts | 104 + aw-harness/src/extensions/steering.ts | 69 + aw-harness/src/index.ts | 161 + aw-harness/src/loader.ts | 212 + aw-harness/src/types.ts | 170 + aw-harness/src/user-extensions.ts | 77 + aw-harness/test/context.test.ts | 61 + .../test/extensions/cost-tracker.test.ts | 164 + .../test/extensions/observability.test.ts | 169 + .../test/extensions/provider-setup.test.ts | 104 + aw-harness/test/extensions/repair.test.ts | 142 + aw-harness/test/extensions/steering.test.ts | 154 + aw-harness/test/loader.test.ts | 236 + aw-harness/test/user-extensions.test.ts | 50 + aw-harness/tsconfig.json | 16 + aw-harness/vitest.config.ts | 15 + 26 files changed, 8368 insertions(+), 4 deletions(-) create mode 100644 aw-harness/README.md create mode 100644 aw-harness/build.ts create mode 100644 aw-harness/package-lock.json create mode 100644 aw-harness/package.json create mode 100644 aw-harness/src/context.ts create mode 100644 aw-harness/src/extensions/cost-tracker.ts create mode 100644 aw-harness/src/extensions/observability.ts create mode 100644 aw-harness/src/extensions/provider-setup.ts create mode 100644 aw-harness/src/extensions/repair.ts create mode 100644 aw-harness/src/extensions/steering.ts create mode 100644 aw-harness/src/index.ts create mode 100644 aw-harness/src/loader.ts create mode 100644 aw-harness/src/types.ts create mode 100644 aw-harness/src/user-extensions.ts create mode 100644 aw-harness/test/context.test.ts create mode 100644 aw-harness/test/extensions/cost-tracker.test.ts create mode 100644 aw-harness/test/extensions/observability.test.ts create mode 100644 aw-harness/test/extensions/provider-setup.test.ts create mode 100644 aw-harness/test/extensions/repair.test.ts create mode 100644 aw-harness/test/extensions/steering.test.ts create mode 100644 aw-harness/test/loader.test.ts create mode 100644 aw-harness/test/user-extensions.test.ts create mode 100644 aw-harness/tsconfig.json create mode 100644 aw-harness/vitest.config.ts diff --git a/.gitignore b/.gitignore index 4df954b0975..552f142ad68 100644 --- a/.gitignore +++ b/.gitignore @@ -174,8 +174,9 @@ detection/ test-script-mode.md test-script-mode.lock.yml -# Test metrics patterns workflow (temporary validation file) -.github/workflows/test-metrics-patterns.md +# AW Harness (EXPERIMENTAL) — generated by make aw-harness, do not commit +actions/setup/js/aw_harness.cjs + .github/workflows/test-metrics-patterns.lock.yml .github/workflows/test-*.md .github/workflows/test-*.lock.yml diff --git a/Makefile b/Makefile index 9b3fce2d4e6..f30cfcc7037 100644 --- a/Makefile +++ b/Makefile @@ -19,7 +19,7 @@ all: build # Build the binary, run make deps before this .PHONY: build -build: sync-action-pins sync-action-scripts +build: sync-action-pins sync-action-scripts aw-harness go build $(LDFLAGS) -o $(BINARY_NAME) ./cmd/gh-aw # Build for all platforms @@ -233,6 +233,35 @@ bundle-js: @echo "✓ bundle-js tool built" @echo "To bundle a JavaScript file: ./bundle-js [output-file]" +# ── AW Harness (EXPERIMENTAL) ───────────────────────────────────────────────── + +# Install aw-harness dependencies +.PHONY: deps-aw-harness +deps-aw-harness: check-node-version + @echo "Installing aw-harness dependencies..." + cd aw-harness && npm ci + @echo "✓ aw-harness dependencies installed" + +# Build the aw-harness TypeScript project and copy bundle to actions/setup/js/ +# EXPERIMENTAL: engine: aw is experimental and subject to breaking changes +.PHONY: aw-harness +aw-harness: deps-aw-harness + @echo "Building aw-harness (EXPERIMENTAL)..." + cd aw-harness && npm run typecheck && node --experimental-strip-types build.ts + @echo "✓ aw-harness built → actions/setup/js/aw_harness.cjs" + +# Run aw-harness tests +.PHONY: test-aw-harness +test-aw-harness: deps-aw-harness + cd aw-harness && npx vitest run + +# Lint aw-harness TypeScript sources (typecheck + prettier) +.PHONY: lint-aw-harness +lint-aw-harness: deps-aw-harness + @echo "Linting aw-harness..." + cd aw-harness && npm run typecheck + @echo "✓ aw-harness lint passed" + # Test all code (Go, JavaScript, and wasm golden) .PHONY: test-all test-all: test test-js test-wasm-golden @@ -609,7 +638,7 @@ check-validator-sizes: # Validate all project files .PHONY: lint -lint: fmt-check fmt-check-json lint-cjs golint +lint: fmt-check fmt-check-json lint-cjs lint-aw-harness golint @echo "✓ All validations passed" # Install the binary locally diff --git a/aw-harness/README.md b/aw-harness/README.md new file mode 100644 index 00000000000..28358b39967 --- /dev/null +++ b/aw-harness/README.md @@ -0,0 +1,96 @@ +# AW Harness + +> ⚠️ **EXPERIMENTAL** — This package is experimental and subject to breaking changes without notice. Do not use in production workflows. + +The AW Harness (`aw_harness.cjs`) is a Node.js execution engine for the `engine: aw` mode of GitHub Agentic Workflows (gh-aw). It runs a single Pi `AgentSession` with budget management, steering, and observability. + +## Architecture + +The harness is a Pi SDK application: it creates a single `AgentSession` and runs a compiled prompt through it, with gh-aw Pi extensions providing budget gating, steering, and observability. See [`specs/aw-harness.md`](../specs/aw-harness.md) for the full specification. + +## Status + +| Feature | Status | +|---------|--------| +| Project scaffolding | ✅ | +| Provider setup extension | ✅ | +| Cost tracker extension | ✅ | +| Steering extension | ✅ | +| Repair extension | ✅ | +| Observability extension | ✅ | +| Loader (config.json + prompt.txt) | ✅ | +| User extension loading | ✅ | +| Context assembly | ✅ | +| Entry point | ✅ | +| gh-aw compiler integration | 🔲 | + +## Development + +```bash +# Install dependencies +make deps-aw-harness + +# Build (bundles to actions/setup/js/aw_harness.cjs) +make aw-harness + +# Run tests +cd aw-harness && npm test + +# Typecheck only +cd aw-harness && npm run typecheck + +# Lint +make lint-aw-harness +``` + +## Project Structure + +``` +aw-harness/ +├── package.json # Pinned dependencies +├── tsconfig.json # TypeScript config (ES2024, noEmit) +├── vitest.config.ts # Vitest test runner config +├── build.ts # esbuild → dist/aw_harness.cjs +├── src/ +│ ├── index.ts # Entry point (EXPERIMENTAL) +│ ├── types.ts # Shared config types +│ ├── loader.ts # config.json + prompt.txt reader +│ ├── context.ts # Prompt assembly with imports +│ ├── user-extensions.ts # Load user-declared extensions +│ └── extensions/ +│ ├── provider-setup.ts # Register LLM providers from env vars +│ ├── cost-tracker.ts # Budget gates via turn_end events +│ ├── steering.ts # Time/budget pressure messages +│ ├── repair.ts # Broken session recovery +│ └── observability.ts # JSONL events + OTel + step summary +├── test/ +│ ├── loader.test.ts +│ ├── context.test.ts +│ ├── user-extensions.test.ts +│ └── extensions/ +│ ├── provider-setup.test.ts +│ ├── cost-tracker.test.ts +│ ├── steering.test.ts +│ ├── repair.test.ts +│ └── observability.test.ts +└── dist/ + └── aw_harness.cjs # Copied to actions/setup/js/aw_harness.cjs +``` + +## Invocation + +The gh-aw compiler pre-processes the workflow markdown and provides the harness with: +- `config.json` — parsed harness configuration +- `prompt.txt` — extracted prompt body + +``` +node aw_harness.cjs --config --prompt +``` + +## Exit Codes + +| Code | Meaning | +|------|---------| +| `0` | Prompt completed successfully | +| `1` | Session failed or budget exceeded | +| `2` | Invocation error (missing arguments, unreadable files) | diff --git a/aw-harness/build.ts b/aw-harness/build.ts new file mode 100644 index 00000000000..e2ea09b9305 --- /dev/null +++ b/aw-harness/build.ts @@ -0,0 +1,36 @@ +/** + * esbuild bundle script for aw_harness. + * + * Compiles src/index.ts → dist/aw_harness.cjs and copies to actions/setup/js/. + * Run with: node --experimental-strip-types build.ts + */ + +import { build } from "esbuild"; +import { copyFileSync, mkdirSync } from "node:fs"; +import { dirname, resolve } from "node:path"; +import { fileURLToPath } from "node:url"; + +const __dirname = dirname(fileURLToPath(import.meta.url)); + +const outfile = resolve(__dirname, "dist/aw_harness.cjs"); +const dest = resolve(__dirname, "../actions/setup/js/aw_harness.cjs"); + +await build({ + entryPoints: [resolve(__dirname, "src/index.ts")], + bundle: true, + platform: "node", + target: "node24", + format: "cjs", + outfile, + // Bundle all dependencies into the single .cjs (no runtime npm install in container) + external: [], + // Keep readable in Actions logs; inline sourcemap for CI debugging + minify: false, + sourcemap: "inline", +}); + +mkdirSync(dirname(dest), { recursive: true }); +copyFileSync(outfile, dest); + +console.log(`✓ Bundled: ${outfile}`); +console.log(`✓ Copied: ${dest}`); diff --git a/aw-harness/package-lock.json b/aw-harness/package-lock.json new file mode 100644 index 00000000000..feb65565376 --- /dev/null +++ b/aw-harness/package-lock.json @@ -0,0 +1,5780 @@ +{ + "name": "@github/aw-harness", + "version": "0.1.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "@github/aw-harness", + "version": "0.1.0", + "dependencies": { + "@mariozechner/pi-coding-agent": "0.72.1" + }, + "devDependencies": { + "@types/node": "22.15.3", + "@vitest/coverage-v8": "3.1.3", + "esbuild": "0.25.4", + "prettier": "3.5.3", + "typescript": "5.8.3", + "vitest": "3.1.3" + } + }, + "node_modules/@ampproject/remapping": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", + "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@anthropic-ai/sdk": { + "version": "0.91.1", + "resolved": "https://registry.npmjs.org/@anthropic-ai/sdk/-/sdk-0.91.1.tgz", + "integrity": "sha512-LAmu761tSN9r66ixvmciswUj/ZC+1Q4iAfpedTfSVLeswRwnY3n2Nb6Tsk+cLPP28aLOPWeMgIuTuCcMC6W/iw==", + "license": "MIT", + "dependencies": { + "json-schema-to-ts": "^3.1.1" + }, + "bin": { + "anthropic-ai-sdk": "bin/cli" + }, + "peerDependencies": { + "zod": "^3.25.0 || ^4.0.0" + }, + "peerDependenciesMeta": { + "zod": { + "optional": true + } + } + }, + "node_modules/@aws-crypto/crc32": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/crc32/-/crc32-5.2.0.tgz", + "integrity": "sha512-nLbCWqQNgUiwwtFsen1AdzAtvuLRsQS8rYgMuxCrdKf9kOssamGLuPwyTY9wyYblNr9+1XM8v6zoDTPPSIeANg==", + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/util": "^5.2.0", + "@aws-sdk/types": "^3.222.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-crypto/sha256-browser": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-browser/-/sha256-browser-5.2.0.tgz", + "integrity": "sha512-AXfN/lGotSQwu6HNcEsIASo7kWXZ5HYWvfOmSNKDsEqC4OashTp8alTmaz+F7TC2L083SFv5RdB+qU3Vs1kZqw==", + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/sha256-js": "^5.2.0", + "@aws-crypto/supports-web-crypto": "^5.2.0", + "@aws-crypto/util": "^5.2.0", + "@aws-sdk/types": "^3.222.0", + "@aws-sdk/util-locate-window": "^3.0.0", + "@smithy/util-utf8": "^2.0.0", + "tslib": "^2.6.2" + } + }, + "node_modules/@aws-crypto/sha256-browser/node_modules/@smithy/is-array-buffer": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-2.2.0.tgz", + "integrity": "sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-crypto/sha256-browser/node_modules/@smithy/util-buffer-from": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-2.2.0.tgz", + "integrity": "sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/is-array-buffer": "^2.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-crypto/sha256-browser/node_modules/@smithy/util-utf8": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-2.3.0.tgz", + "integrity": "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/util-buffer-from": "^2.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-crypto/sha256-js": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-js/-/sha256-js-5.2.0.tgz", + "integrity": "sha512-FFQQyu7edu4ufvIZ+OadFpHHOt+eSTBaYaki44c+akjg7qZg9oOQeLlk77F6tSYqjDAFClrHJk9tMf0HdVyOvA==", + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/util": "^5.2.0", + "@aws-sdk/types": "^3.222.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-crypto/supports-web-crypto": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/supports-web-crypto/-/supports-web-crypto-5.2.0.tgz", + "integrity": "sha512-iAvUotm021kM33eCdNfwIN//F77/IADDSs58i+MDaOqFrVjZo9bAal0NK7HurRuWLLpF1iLX7gbWrjHjeo+YFg==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + } + }, + "node_modules/@aws-crypto/util": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/util/-/util-5.2.0.tgz", + "integrity": "sha512-4RkU9EsI6ZpBve5fseQlGNUWKMa1RLPQ1dnjnQoe07ldfIzcsGb5hC5W0Dm7u423KWzawlrpbjXBrXCEv9zazQ==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "^3.222.0", + "@smithy/util-utf8": "^2.0.0", + "tslib": "^2.6.2" + } + }, + "node_modules/@aws-crypto/util/node_modules/@smithy/is-array-buffer": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-2.2.0.tgz", + "integrity": "sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-crypto/util/node_modules/@smithy/util-buffer-from": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-2.2.0.tgz", + "integrity": "sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/is-array-buffer": "^2.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-crypto/util/node_modules/@smithy/util-utf8": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-2.3.0.tgz", + "integrity": "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/util-buffer-from": "^2.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/client-bedrock-runtime": { + "version": "3.1041.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-bedrock-runtime/-/client-bedrock-runtime-3.1041.0.tgz", + "integrity": "sha512-1QehYO3jhdvNQ5mOKtwIiNV04y4aywaNZw9HzCp7SSYCX4yy+AGXc2hhYjCiMDUvQPIELuvbR8MXw81NGAj8ZQ==", + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "^3.974.8", + "@aws-sdk/credential-provider-node": "^3.972.39", + "@aws-sdk/eventstream-handler-node": "^3.972.14", + "@aws-sdk/middleware-eventstream": "^3.972.10", + "@aws-sdk/middleware-host-header": "^3.972.10", + "@aws-sdk/middleware-logger": "^3.972.10", + "@aws-sdk/middleware-recursion-detection": "^3.972.11", + "@aws-sdk/middleware-user-agent": "^3.972.38", + "@aws-sdk/middleware-websocket": "^3.972.16", + "@aws-sdk/region-config-resolver": "^3.972.13", + "@aws-sdk/token-providers": "3.1041.0", + "@aws-sdk/types": "^3.973.8", + "@aws-sdk/util-endpoints": "^3.996.8", + "@aws-sdk/util-user-agent-browser": "^3.972.10", + "@aws-sdk/util-user-agent-node": "^3.973.24", + "@smithy/config-resolver": "^4.4.17", + "@smithy/core": "^3.23.17", + "@smithy/eventstream-serde-browser": "^4.2.14", + "@smithy/eventstream-serde-config-resolver": "^4.3.14", + "@smithy/eventstream-serde-node": "^4.2.14", + "@smithy/fetch-http-handler": "^5.3.17", + "@smithy/hash-node": "^4.2.14", + "@smithy/invalid-dependency": "^4.2.14", + "@smithy/middleware-content-length": "^4.2.14", + "@smithy/middleware-endpoint": "^4.4.32", + "@smithy/middleware-retry": "^4.5.7", + "@smithy/middleware-serde": "^4.2.20", + "@smithy/middleware-stack": "^4.2.14", + "@smithy/node-config-provider": "^4.3.14", + "@smithy/node-http-handler": "^4.6.1", + "@smithy/protocol-http": "^5.3.14", + "@smithy/smithy-client": "^4.12.13", + "@smithy/types": "^4.14.1", + "@smithy/url-parser": "^4.2.14", + "@smithy/util-base64": "^4.3.2", + "@smithy/util-body-length-browser": "^4.2.2", + "@smithy/util-body-length-node": "^4.2.3", + "@smithy/util-defaults-mode-browser": "^4.3.49", + "@smithy/util-defaults-mode-node": "^4.2.54", + "@smithy/util-endpoints": "^3.4.2", + "@smithy/util-middleware": "^4.2.14", + "@smithy/util-retry": "^4.3.6", + "@smithy/util-stream": "^4.5.25", + "@smithy/util-utf8": "^4.2.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/core": { + "version": "3.974.8", + "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.974.8.tgz", + "integrity": "sha512-njR2qoG6ZuB0kvAS2FyICsFZJ6gmCcf2X/7JcD14sUvGDm26wiZ5BrA6LOiUxKFEF+IVe7kdroxyE00YlkiYsw==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "^3.973.8", + "@aws-sdk/xml-builder": "^3.972.22", + "@smithy/core": "^3.23.17", + "@smithy/node-config-provider": "^4.3.14", + "@smithy/property-provider": "^4.2.14", + "@smithy/protocol-http": "^5.3.14", + "@smithy/signature-v4": "^5.3.14", + "@smithy/smithy-client": "^4.12.13", + "@smithy/types": "^4.14.1", + "@smithy/util-base64": "^4.3.2", + "@smithy/util-middleware": "^4.2.14", + "@smithy/util-retry": "^4.3.6", + "@smithy/util-utf8": "^4.2.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-env": { + "version": "3.972.34", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.972.34.tgz", + "integrity": "sha512-XT0jtf8Fw9JE6ppsQeoNnZRiG+jqRixMT1v1ZR17G60UvVdsQmTG8nbEyHuEPfMxDXEhfdARaM/XiEhca4lGHQ==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "^3.974.8", + "@aws-sdk/types": "^3.973.8", + "@smithy/property-provider": "^4.2.14", + "@smithy/types": "^4.14.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-http": { + "version": "3.972.36", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.972.36.tgz", + "integrity": "sha512-DPoGWfy7J7RKxvbf5kOKIGQkD2ek3dbKgzKIGrnLuvZBz5myU+Im/H6pmc14QcnFbqHMqxvtWSgRDSJW3qXLQg==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "^3.974.8", + "@aws-sdk/types": "^3.973.8", + "@smithy/fetch-http-handler": "^5.3.17", + "@smithy/node-http-handler": "^4.6.1", + "@smithy/property-provider": "^4.2.14", + "@smithy/protocol-http": "^5.3.14", + "@smithy/smithy-client": "^4.12.13", + "@smithy/types": "^4.14.1", + "@smithy/util-stream": "^4.5.25", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-ini": { + "version": "3.972.38", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.972.38.tgz", + "integrity": "sha512-oDzUBu2MGJFgoar05sPMCwSrhw44ASyccrHzj66vO69OZqi7I6hZZxXfuPLC8OCzW7C+sU+bI73XHij41yekgQ==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "^3.974.8", + "@aws-sdk/credential-provider-env": "^3.972.34", + "@aws-sdk/credential-provider-http": "^3.972.36", + "@aws-sdk/credential-provider-login": "^3.972.38", + "@aws-sdk/credential-provider-process": "^3.972.34", + "@aws-sdk/credential-provider-sso": "^3.972.38", + "@aws-sdk/credential-provider-web-identity": "^3.972.38", + "@aws-sdk/nested-clients": "^3.997.6", + "@aws-sdk/types": "^3.973.8", + "@smithy/credential-provider-imds": "^4.2.14", + "@smithy/property-provider": "^4.2.14", + "@smithy/shared-ini-file-loader": "^4.4.9", + "@smithy/types": "^4.14.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-login": { + "version": "3.972.38", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-login/-/credential-provider-login-3.972.38.tgz", + "integrity": "sha512-g1NosS8qe4OF++G2UFCM5ovSkgipC7YYor5KCWatG0UoMSO5YFj9C8muePlyVmOBV/WTI16Jo3/s1NUo/o1Bww==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "^3.974.8", + "@aws-sdk/nested-clients": "^3.997.6", + "@aws-sdk/types": "^3.973.8", + "@smithy/property-provider": "^4.2.14", + "@smithy/protocol-http": "^5.3.14", + "@smithy/shared-ini-file-loader": "^4.4.9", + "@smithy/types": "^4.14.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-node": { + "version": "3.972.39", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.972.39.tgz", + "integrity": "sha512-HEswDQyxUtadoZ/bJsPPENHg7R0Lzym5LuMksJeHvqhCOpP+rtkDLKI4/ZChH4w3cf5kG8n6bZuI8PzajoiqMg==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/credential-provider-env": "^3.972.34", + "@aws-sdk/credential-provider-http": "^3.972.36", + "@aws-sdk/credential-provider-ini": "^3.972.38", + "@aws-sdk/credential-provider-process": "^3.972.34", + "@aws-sdk/credential-provider-sso": "^3.972.38", + "@aws-sdk/credential-provider-web-identity": "^3.972.38", + "@aws-sdk/types": "^3.973.8", + "@smithy/credential-provider-imds": "^4.2.14", + "@smithy/property-provider": "^4.2.14", + "@smithy/shared-ini-file-loader": "^4.4.9", + "@smithy/types": "^4.14.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-process": { + "version": "3.972.34", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.972.34.tgz", + "integrity": "sha512-T3IFs4EVmVi1dVN5RciFnklCANSzvrQd/VuHY9ThHSQmYkTogjcGkoJEr+oNUPQZnso52183088NqysMPji1/Q==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "^3.974.8", + "@aws-sdk/types": "^3.973.8", + "@smithy/property-provider": "^4.2.14", + "@smithy/shared-ini-file-loader": "^4.4.9", + "@smithy/types": "^4.14.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-sso": { + "version": "3.972.38", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.972.38.tgz", + "integrity": "sha512-5ZxG+t0+3Q3QPh8KEjX6syskhgNf7I0MN7oGioTf6Lm1NTjfP7sIcYGNsthXC2qR8vcD3edNZwCr2ovfSSWuRA==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "^3.974.8", + "@aws-sdk/nested-clients": "^3.997.6", + "@aws-sdk/token-providers": "3.1041.0", + "@aws-sdk/types": "^3.973.8", + "@smithy/property-provider": "^4.2.14", + "@smithy/shared-ini-file-loader": "^4.4.9", + "@smithy/types": "^4.14.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-web-identity": { + "version": "3.972.38", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.972.38.tgz", + "integrity": "sha512-lYHFF30DGI20jZcYX8cm6Ns0V7f1dDN6g/MBDLTyD/5iw+bXs3yBr2iAiHDkx4RFU5JgsnZvCHYKiRVPRdmOgw==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "^3.974.8", + "@aws-sdk/nested-clients": "^3.997.6", + "@aws-sdk/types": "^3.973.8", + "@smithy/property-provider": "^4.2.14", + "@smithy/shared-ini-file-loader": "^4.4.9", + "@smithy/types": "^4.14.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/eventstream-handler-node": { + "version": "3.972.14", + "resolved": "https://registry.npmjs.org/@aws-sdk/eventstream-handler-node/-/eventstream-handler-node-3.972.14.tgz", + "integrity": "sha512-m4X56gxG76/CKfxNVbOFuYwnAZcHgS6HOH8lgp15HoGHIAVTcZfZrXvcYzJFOMLEJgVn+JHBu6EiNV+xSNXXFg==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "^3.973.8", + "@smithy/eventstream-codec": "^4.2.14", + "@smithy/types": "^4.14.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/middleware-eventstream": { + "version": "3.972.10", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-eventstream/-/middleware-eventstream-3.972.10.tgz", + "integrity": "sha512-QUqLs7Af1II9X4fCRAu+EGHG3KHyOp4RkuLhRKoA3NuFlh6TL8i+zXBl8w2LUxqm44B/Kom45hgSlwA1SpTsXQ==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "^3.973.8", + "@smithy/protocol-http": "^5.3.14", + "@smithy/types": "^4.14.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/middleware-host-header": { + "version": "3.972.10", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.972.10.tgz", + "integrity": "sha512-IJSsIMeVQ8MMCPbuh1AbltkFhLBLXn7aejzfX5YKT/VLDHn++Dcz8886tXckE+wQssyPUhaXrJhdakO2VilRhg==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "^3.973.8", + "@smithy/protocol-http": "^5.3.14", + "@smithy/types": "^4.14.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/middleware-logger": { + "version": "3.972.10", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.972.10.tgz", + "integrity": "sha512-OOuGvvz1Dm20SjZo5oEBePFqxt5nf8AwkNDSyUHvD9/bfNASmstcYxFAHUowy4n6Io7mWUZ04JURZwSBvyQanQ==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "^3.973.8", + "@smithy/types": "^4.14.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/middleware-recursion-detection": { + "version": "3.972.11", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.972.11.tgz", + "integrity": "sha512-+zz6f79Kj9V5qFK2P+D8Ehjnw4AhphAlCAsPjUqEcInA9umtSSKMrHbSagEeOIsDNuvVrH98bjRHcyQukTrhaQ==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "^3.973.8", + "@aws/lambda-invoke-store": "^0.2.2", + "@smithy/protocol-http": "^5.3.14", + "@smithy/types": "^4.14.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/middleware-sdk-s3": { + "version": "3.972.37", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-sdk-s3/-/middleware-sdk-s3-3.972.37.tgz", + "integrity": "sha512-Km7M+i8DrLArVzrid1gfxeGhYHBd3uxvE77g0s5a52zPSVosxzQBnJ0gwWb6NIp/DOk8gsBMhi7V+cpJG0ndTA==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "^3.974.8", + "@aws-sdk/types": "^3.973.8", + "@aws-sdk/util-arn-parser": "^3.972.3", + "@smithy/core": "^3.23.17", + "@smithy/node-config-provider": "^4.3.14", + "@smithy/protocol-http": "^5.3.14", + "@smithy/signature-v4": "^5.3.14", + "@smithy/smithy-client": "^4.12.13", + "@smithy/types": "^4.14.1", + "@smithy/util-config-provider": "^4.2.2", + "@smithy/util-middleware": "^4.2.14", + "@smithy/util-stream": "^4.5.25", + "@smithy/util-utf8": "^4.2.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/middleware-user-agent": { + "version": "3.972.38", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.972.38.tgz", + "integrity": "sha512-iz+B29TXcAZsJpwB+AwG/TTGA5l/VnmMZ2UxtiySOZjI6gCdmviXPwdgzcmuazMy16rXoPY4mYCGe7zdNKfx5A==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "^3.974.8", + "@aws-sdk/types": "^3.973.8", + "@aws-sdk/util-endpoints": "^3.996.8", + "@smithy/core": "^3.23.17", + "@smithy/protocol-http": "^5.3.14", + "@smithy/types": "^4.14.1", + "@smithy/util-retry": "^4.3.6", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/middleware-websocket": { + "version": "3.972.16", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-websocket/-/middleware-websocket-3.972.16.tgz", + "integrity": "sha512-86+S9oCyRVGzoMRpQhxkArp7kD2K75GPmaNevd9B6EyNhWoNvnCZZ3WbgN4j7ZT+jvtvBCGZvI2XHsWZJ+BRIg==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "^3.973.8", + "@aws-sdk/util-format-url": "^3.972.10", + "@smithy/eventstream-codec": "^4.2.14", + "@smithy/eventstream-serde-browser": "^4.2.14", + "@smithy/fetch-http-handler": "^5.3.17", + "@smithy/protocol-http": "^5.3.14", + "@smithy/signature-v4": "^5.3.14", + "@smithy/types": "^4.14.1", + "@smithy/util-base64": "^4.3.2", + "@smithy/util-hex-encoding": "^4.2.2", + "@smithy/util-utf8": "^4.2.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@aws-sdk/nested-clients": { + "version": "3.997.6", + "resolved": "https://registry.npmjs.org/@aws-sdk/nested-clients/-/nested-clients-3.997.6.tgz", + "integrity": "sha512-WBDnqatJl+kGObpfmfSxqnXeYTu3Me8wx8WCtvoxX3pfWrrTv8I4WTMSSs7PZqcRcVh8WeUKMgGFjMG+52SR1w==", + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "^3.974.8", + "@aws-sdk/middleware-host-header": "^3.972.10", + "@aws-sdk/middleware-logger": "^3.972.10", + "@aws-sdk/middleware-recursion-detection": "^3.972.11", + "@aws-sdk/middleware-user-agent": "^3.972.38", + "@aws-sdk/region-config-resolver": "^3.972.13", + "@aws-sdk/signature-v4-multi-region": "^3.996.25", + "@aws-sdk/types": "^3.973.8", + "@aws-sdk/util-endpoints": "^3.996.8", + "@aws-sdk/util-user-agent-browser": "^3.972.10", + "@aws-sdk/util-user-agent-node": "^3.973.24", + "@smithy/config-resolver": "^4.4.17", + "@smithy/core": "^3.23.17", + "@smithy/fetch-http-handler": "^5.3.17", + "@smithy/hash-node": "^4.2.14", + "@smithy/invalid-dependency": "^4.2.14", + "@smithy/middleware-content-length": "^4.2.14", + "@smithy/middleware-endpoint": "^4.4.32", + "@smithy/middleware-retry": "^4.5.7", + "@smithy/middleware-serde": "^4.2.20", + "@smithy/middleware-stack": "^4.2.14", + "@smithy/node-config-provider": "^4.3.14", + "@smithy/node-http-handler": "^4.6.1", + "@smithy/protocol-http": "^5.3.14", + "@smithy/smithy-client": "^4.12.13", + "@smithy/types": "^4.14.1", + "@smithy/url-parser": "^4.2.14", + "@smithy/util-base64": "^4.3.2", + "@smithy/util-body-length-browser": "^4.2.2", + "@smithy/util-body-length-node": "^4.2.3", + "@smithy/util-defaults-mode-browser": "^4.3.49", + "@smithy/util-defaults-mode-node": "^4.2.54", + "@smithy/util-endpoints": "^3.4.2", + "@smithy/util-middleware": "^4.2.14", + "@smithy/util-retry": "^4.3.6", + "@smithy/util-utf8": "^4.2.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/region-config-resolver": { + "version": "3.972.13", + "resolved": "https://registry.npmjs.org/@aws-sdk/region-config-resolver/-/region-config-resolver-3.972.13.tgz", + "integrity": "sha512-CvJ2ZIjK/jVD/lbOpowBVElJyC1YxLTIJ13yM0AEo0t2v7swOzGjSA6lJGH+DwZXQhcjUjoYwc8bVYCX5MDr1A==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "^3.973.8", + "@smithy/config-resolver": "^4.4.17", + "@smithy/node-config-provider": "^4.3.14", + "@smithy/types": "^4.14.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/signature-v4-multi-region": { + "version": "3.996.25", + "resolved": "https://registry.npmjs.org/@aws-sdk/signature-v4-multi-region/-/signature-v4-multi-region-3.996.25.tgz", + "integrity": "sha512-+CMIt3e1VzlklAECmG+DtP1sV8iKq25FuA0OKpnJ4KA0kxUtd7CgClY7/RU6VzJBQwbN4EJ9Ue6plvqx1qGadw==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/middleware-sdk-s3": "^3.972.37", + "@aws-sdk/types": "^3.973.8", + "@smithy/protocol-http": "^5.3.14", + "@smithy/signature-v4": "^5.3.14", + "@smithy/types": "^4.14.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/token-providers": { + "version": "3.1041.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.1041.0.tgz", + "integrity": "sha512-Th7kPI6YPtvJUcdznooXJMy+9rQWjmEF81LxaJssngBzuysK4a/x+l8kjm1zb7nYsUPbndnBdUnwng/3PLvtGw==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "^3.974.8", + "@aws-sdk/nested-clients": "^3.997.6", + "@aws-sdk/types": "^3.973.8", + "@smithy/property-provider": "^4.2.14", + "@smithy/shared-ini-file-loader": "^4.4.9", + "@smithy/types": "^4.14.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/types": { + "version": "3.973.8", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.973.8.tgz", + "integrity": "sha512-gjlAdtHMbtR9X5iIhVUvbVcy55KnznpC6bkDUWW9z915bi0ckdUr5cjf16Kp6xq0bP5HBD2xzgbL9F9Quv5vUw==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.14.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/util-arn-parser": { + "version": "3.972.3", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-arn-parser/-/util-arn-parser-3.972.3.tgz", + "integrity": "sha512-HzSD8PMFrvgi2Kserxuff5VitNq2sgf3w9qxmskKDiDTThWfVteJxuCS9JXiPIPtmCrp+7N9asfIaVhBFORllA==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/util-endpoints": { + "version": "3.996.8", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.996.8.tgz", + "integrity": "sha512-oOZHcRDihk5iEe5V25NVWg45b3qEA8OpHWVdU/XQh8Zj4heVPAJqWvMphQnU7LkufmUo10EpvFPZuQMiFLJK3g==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "^3.973.8", + "@smithy/types": "^4.14.1", + "@smithy/url-parser": "^4.2.14", + "@smithy/util-endpoints": "^3.4.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/util-format-url": { + "version": "3.972.10", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-format-url/-/util-format-url-3.972.10.tgz", + "integrity": "sha512-DEKiHNJVtNxdyTeQspzY+15Po/kHm6sF0Cs4HV9Q2+lplB63+DrvdeiSoOSdWEWAoO2RcY1veoXVDz2tWxWCgQ==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "^3.973.8", + "@smithy/querystring-builder": "^4.2.14", + "@smithy/types": "^4.14.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/util-locate-window": { + "version": "3.965.5", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-locate-window/-/util-locate-window-3.965.5.tgz", + "integrity": "sha512-WhlJNNINQB+9qtLtZJcpQdgZw3SCDCpXdUJP7cToGwHbCWCnRckGlc6Bx/OhWwIYFNAn+FIydY8SZ0QmVu3xTQ==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/util-user-agent-browser": { + "version": "3.972.10", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.972.10.tgz", + "integrity": "sha512-FAzqXvfEssGdSIz8ejatan0bOdx1qefBWKF/gWmVBXIP1HkS7v/wjjaqrAGGKvyihrXTXW00/2/1nTJtxpXz7g==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "^3.973.8", + "@smithy/types": "^4.14.1", + "bowser": "^2.11.0", + "tslib": "^2.6.2" + } + }, + "node_modules/@aws-sdk/util-user-agent-node": { + "version": "3.973.24", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.973.24.tgz", + "integrity": "sha512-ZWwlkjcIp7cEL8ZfTpTAPNkwx25p7xol0xlKoWVVf22+nsjwmLcHYtTPjIV1cSpmB/b6DaK4cb1fSkvCXHgRdw==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/middleware-user-agent": "^3.972.38", + "@aws-sdk/types": "^3.973.8", + "@smithy/node-config-provider": "^4.3.14", + "@smithy/types": "^4.14.1", + "@smithy/util-config-provider": "^4.2.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "aws-crt": ">=1.0.0" + }, + "peerDependenciesMeta": { + "aws-crt": { + "optional": true + } + } + }, + "node_modules/@aws-sdk/xml-builder": { + "version": "3.972.22", + "resolved": "https://registry.npmjs.org/@aws-sdk/xml-builder/-/xml-builder-3.972.22.tgz", + "integrity": "sha512-PMYKKtJd70IsSG0yHrdAbxBr+ZWBKLvzFZfD3/urxgf6hXVMzuU5M+3MJ5G67RpOmLBu1fAUN65SbWuKUCOlAA==", + "license": "Apache-2.0", + "dependencies": { + "@nodable/entities": "2.1.0", + "@smithy/types": "^4.14.1", + "fast-xml-parser": "5.7.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws/lambda-invoke-store": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/@aws/lambda-invoke-store/-/lambda-invoke-store-0.2.4.tgz", + "integrity": "sha512-iY8yvjE0y651BixKNPgmv1WrQc+GZ142sb0z4gYnChDDY2YqI4P/jsSopBWrKfAt7LOJAkOXt7rC/hms+WclQQ==", + "license": "Apache-2.0", + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", + "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.29.3", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.3.tgz", + "integrity": "sha512-b3ctpQwp+PROvU/cttc4OYl4MzfJUWy6FZg+PMXfzmt/+39iHVF0sDfqay8TQM3JA2EUOyKcFZt75jWriQijsA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.0" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/runtime": { + "version": "7.29.2", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.29.2.tgz", + "integrity": "sha512-JiDShH45zKHWyGe4ZNVRrCjBz8Nh9TMmZG1kh4QTK8hCBTWBi8Da+i7s1fJw7/lYpM4ccepSNfqzZ/QvABBi5g==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz", + "integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.28.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@bcoe/v8-coverage": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-1.0.2.tgz", + "integrity": "sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/@borewit/text-codec": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/@borewit/text-codec/-/text-codec-0.2.2.tgz", + "integrity": "sha512-DDaRehssg1aNrH4+2hnj1B7vnUGEjU6OIlyRdkMd0aUdIUvKXrJfXsy8LVtXAy7DRvYVluWbMspsRhz2lcW0mQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Borewit" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.4.tgz", + "integrity": "sha512-1VCICWypeQKhVbE9oW/sJaAmjLxhVqacdkvPLEjwlttjfwENRSClS8EjBz0KzRyFSCPDIkuXW34Je/vk7zdB7Q==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.4.tgz", + "integrity": "sha512-QNdQEps7DfFwE3hXiU4BZeOV68HHzYwGd0Nthhd3uCkkEKK7/R6MTgM0P7H7FAs5pU/DIWsviMmEGxEoxIZ+ZQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.4.tgz", + "integrity": "sha512-bBy69pgfhMGtCnwpC/x5QhfxAz/cBgQ9enbtwjf6V9lnPI/hMyT9iWpR1arm0l3kttTr4L0KSLpKmLp/ilKS9A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.4.tgz", + "integrity": "sha512-TVhdVtQIFuVpIIR282btcGC2oGQoSfZfmBdTip2anCaVYcqWlZXGcdcKIUklfX2wj0JklNYgz39OBqh2cqXvcQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.4.tgz", + "integrity": "sha512-Y1giCfM4nlHDWEfSckMzeWNdQS31BQGs9/rouw6Ub91tkK79aIMTH3q9xHvzH8d0wDru5Ci0kWB8b3up/nl16g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.4.tgz", + "integrity": "sha512-CJsry8ZGM5VFVeyUYB3cdKpd/H69PYez4eJh1W/t38vzutdjEjtP7hB6eLKBoOdxcAlCtEYHzQ/PJ/oU9I4u0A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.4.tgz", + "integrity": "sha512-yYq+39NlTRzU2XmoPW4l5Ifpl9fqSk0nAJYM/V/WUGPEFfek1epLHJIkTQM6bBs1swApjO5nWgvr843g6TjxuQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.4.tgz", + "integrity": "sha512-0FgvOJ6UUMflsHSPLzdfDnnBBVoCDtBTVyn/MrWloUNvq/5SFmh13l3dvgRPkDihRxb77Y17MbqbCAa2strMQQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.4.tgz", + "integrity": "sha512-kro4c0P85GMfFYqW4TWOpvmF8rFShbWGnrLqlzp4X1TNWjRY3JMYUfDCtOxPKOIY8B0WC8HN51hGP4I4hz4AaQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.4.tgz", + "integrity": "sha512-+89UsQTfXdmjIvZS6nUnOOLoXnkUTB9hR5QAeLrQdzOSWZvNSAXAtcRDHWtqAUtAmv7ZM1WPOOeSxDzzzMogiQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.4.tgz", + "integrity": "sha512-yTEjoapy8UP3rv8dB0ip3AfMpRbyhSN3+hY8mo/i4QXFeDxmiYbEKp3ZRjBKcOP862Ua4b1PDfwlvbuwY7hIGQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.4.tgz", + "integrity": "sha512-NeqqYkrcGzFwi6CGRGNMOjWGGSYOpqwCjS9fvaUlX5s3zwOtn1qwg1s2iE2svBe4Q/YOG1q6875lcAoQK/F4VA==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.4.tgz", + "integrity": "sha512-IcvTlF9dtLrfL/M8WgNI/qJYBENP3ekgsHbYUIzEzq5XJzzVEV/fXY9WFPfEEXmu3ck2qJP8LG/p3Q8f7Zc2Xg==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.4.tgz", + "integrity": "sha512-HOy0aLTJTVtoTeGZh4HSXaO6M95qu4k5lJcH4gxv56iaycfz1S8GO/5Jh6X4Y1YiI0h7cRyLi+HixMR+88swag==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.4.tgz", + "integrity": "sha512-i8JUDAufpz9jOzo4yIShCTcXzS07vEgWzyX3NH2G7LEFVgrLEhjwL3ajFE4fZI3I4ZgiM7JH3GQ7ReObROvSUA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.4.tgz", + "integrity": "sha512-jFnu+6UbLlzIjPQpWCNh5QtrcNfMLjgIavnwPQAfoGx4q17ocOU9MsQ2QVvFxwQoWpZT8DvTLooTvmOQXkO51g==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.4.tgz", + "integrity": "sha512-6e0cvXwzOnVWJHq+mskP8DNSrKBr1bULBvnFLpc1KY+d+irZSgZ02TGse5FsafKS5jg2e4pbvK6TPXaF/A6+CA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.4.tgz", + "integrity": "sha512-vUnkBYxZW4hL/ie91hSqaSNjulOnYXE1VSLusnvHg2u3jewJBz3YzB9+oCw8DABeVqZGg94t9tyZFoHma8gWZQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.4.tgz", + "integrity": "sha512-XAg8pIQn5CzhOB8odIcAm42QsOfa98SBeKUdo4xa8OvX8LbMZqEtgeWE9P/Wxt7MlG2QqvjGths+nq48TrUiKw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.4.tgz", + "integrity": "sha512-Ct2WcFEANlFDtp1nVAXSNBPDxyU+j7+tId//iHXU2f/lN5AmO4zLyhDcpR5Cz1r08mVxzt3Jpyt4PmXQ1O6+7A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.4.tgz", + "integrity": "sha512-xAGGhyOQ9Otm1Xu8NT1ifGLnA6M3sJxZ6ixylb+vIUVzvvd6GOALpwQrYrtlPouMqd/vSbgehz6HaVk4+7Afhw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.4.tgz", + "integrity": "sha512-Mw+tzy4pp6wZEK0+Lwr76pWLjrtjmJyUB23tHKqEDP74R3q95luY/bXqXZeYl4NYlvwOqoRKlInQialgCKy67Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.4.tgz", + "integrity": "sha512-AVUP428VQTSddguz9dO9ngb+E5aScyg7nOeJDrF1HPYu555gmza3bDGMPhmVXL8svDSoqPCsCPjb265yG/kLKQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.4.tgz", + "integrity": "sha512-i1sW+1i+oWvQzSgfRcxxG2k4I9n3O9NRqy8U+uugaT2Dy7kLO9Y7wI72haOahxceMX8hZAzgGou1FhndRldxRg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.4.tgz", + "integrity": "sha512-nOT2vZNw6hJ+z43oP1SPea/G/6AbN6X+bGNhNuq8NtRHy4wsMhw765IKLNmnjek7GvjWBYQ8Q5VBoYTFg9y1UQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@google/genai": { + "version": "1.51.0", + "resolved": "https://registry.npmjs.org/@google/genai/-/genai-1.51.0.tgz", + "integrity": "sha512-vTZZF3CSimN7cn2zsLpW2p5WF0eZa5Gz69ITMPCNHpPrDlAstOfGifSfi0p/s9Z9400f7xJRkgvkQNrcM7pJ6w==", + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "google-auth-library": "^10.3.0", + "p-retry": "^4.6.2", + "protobufjs": "^7.5.4", + "ws": "^8.18.0" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "@modelcontextprotocol/sdk": "^1.25.2" + }, + "peerDependenciesMeta": { + "@modelcontextprotocol/sdk": { + "optional": true + } + } + }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@isaacs/cliui/node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@isaacs/cliui/node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/@istanbuljs/schema": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.6.tgz", + "integrity": "sha512-+Sg6GCR/wy1oSmQDFq4LQDAhm3ETKnorxN+y5nbLULOR3P0c14f2Wurzj3/xqPXtasLFfHd5iRFQ7AJt4KH2cw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@mariozechner/clipboard": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@mariozechner/clipboard/-/clipboard-0.3.5.tgz", + "integrity": "sha512-D3F+UrU9CR7roJt0zDLp6Oc+4/KlLDIrN4frH+6V90SJNW2KKUec1oCQIPaaDjCqeOsQyX9dyqYbImIQIM45PA==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">= 10" + }, + "optionalDependencies": { + "@mariozechner/clipboard-darwin-arm64": "0.3.2", + "@mariozechner/clipboard-darwin-universal": "0.3.2", + "@mariozechner/clipboard-darwin-x64": "0.3.2", + "@mariozechner/clipboard-linux-arm64-gnu": "0.3.2", + "@mariozechner/clipboard-linux-arm64-musl": "0.3.2", + "@mariozechner/clipboard-linux-riscv64-gnu": "0.3.2", + "@mariozechner/clipboard-linux-x64-gnu": "0.3.2", + "@mariozechner/clipboard-linux-x64-musl": "0.3.2", + "@mariozechner/clipboard-win32-arm64-msvc": "0.3.2", + "@mariozechner/clipboard-win32-x64-msvc": "0.3.2" + } + }, + "node_modules/@mariozechner/clipboard-darwin-arm64": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@mariozechner/clipboard-darwin-arm64/-/clipboard-darwin-arm64-0.3.2.tgz", + "integrity": "sha512-uBf6K7Je1ihsgvmWxA8UCGCeI+nbRVRXoarZdLjl6slz94Zs1tNKFZqx7aCI5O1i3e0B6ja82zZ06BWrl0MCVw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@mariozechner/clipboard-darwin-universal": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@mariozechner/clipboard-darwin-universal/-/clipboard-darwin-universal-0.3.2.tgz", + "integrity": "sha512-mxSheKTW2U9LsBdXy0SdmdCAE5HqNS9QUmpNHLnfJ+SsbFKALjEZc5oRrVMXxGQSirDvYf5bjmRyT0QYYonnlg==", + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@mariozechner/clipboard-darwin-x64": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@mariozechner/clipboard-darwin-x64/-/clipboard-darwin-x64-0.3.2.tgz", + "integrity": "sha512-U1BcVEoidvwIp95+HJswSW+xr28EQiHR7rZjH6pn8Sja5yO4Yoe3yCN0Zm8Lo72BbSOK/fTSq0je7CJpaPCspg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@mariozechner/clipboard-linux-arm64-gnu": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@mariozechner/clipboard-linux-arm64-gnu/-/clipboard-linux-arm64-gnu-0.3.2.tgz", + "integrity": "sha512-BsinwG3yWTIjdgNCxsFlip7LkfwPk+ruw/aFCXHUg/fb5XC/Ksp+YMQ7u0LUtiKzIv/7LMXgZInJQH6gxbAaqQ==", + "cpu": [ + "arm64" + ], + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@mariozechner/clipboard-linux-arm64-musl": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@mariozechner/clipboard-linux-arm64-musl/-/clipboard-linux-arm64-musl-0.3.2.tgz", + "integrity": "sha512-0/Gi5Xq2V6goXBop19ePoHvXsmJD9SzFlO3S+d6+T2b+BlPcpOu3Oa0wTjl+cZrLAAEzA86aPNBI+VVAFDFPKw==", + "cpu": [ + "arm64" + ], + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@mariozechner/clipboard-linux-riscv64-gnu": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@mariozechner/clipboard-linux-riscv64-gnu/-/clipboard-linux-riscv64-gnu-0.3.2.tgz", + "integrity": "sha512-2AFFiXB24qf0zOZsxI1GJGb9wQGlOJyN6UwoXqmKS3dpQi/l6ix30IzDDA4c4ZcCcx4D+9HLYXhC1w7Sov8pXA==", + "cpu": [ + "riscv64" + ], + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@mariozechner/clipboard-linux-x64-gnu": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@mariozechner/clipboard-linux-x64-gnu/-/clipboard-linux-x64-gnu-0.3.2.tgz", + "integrity": "sha512-v6fVnsn7WMGg73Dab8QMwyFce7tzGfgEixKgzLP8f1GJqkJZi5zO4k4FOHzSgUufgLil63gnxvMpjWkgfeQN7A==", + "cpu": [ + "x64" + ], + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@mariozechner/clipboard-linux-x64-musl": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@mariozechner/clipboard-linux-x64-musl/-/clipboard-linux-x64-musl-0.3.2.tgz", + "integrity": "sha512-xVUtnoMQ8v2JVyfJLKKXACA6avdnchdbBkTsZs8BgJQo29qwCp5NIHAUO8gbJ40iaEGToW5RlmVk2M9V0HsHEw==", + "cpu": [ + "x64" + ], + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@mariozechner/clipboard-win32-arm64-msvc": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@mariozechner/clipboard-win32-arm64-msvc/-/clipboard-win32-arm64-msvc-0.3.2.tgz", + "integrity": "sha512-AEgg95TNi8TGgak2wSXZkXKCvAUTjWoU1Pqb0ON7JHrX78p616XUFNTJohtIon3e0w6k0pYPZeCuqRCza/Tqeg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@mariozechner/clipboard-win32-x64-msvc": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@mariozechner/clipboard-win32-x64-msvc/-/clipboard-win32-x64-msvc-0.3.2.tgz", + "integrity": "sha512-tGRuYpZwDOD7HBrCpyRuhGnHHSCknELvqwKKUG4JSfSB7JIU7LKRh6zx6fMUOQd8uISK35TjFg5UcNih+vJhFA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@mariozechner/jiti": { + "version": "2.6.5", + "resolved": "https://registry.npmjs.org/@mariozechner/jiti/-/jiti-2.6.5.tgz", + "integrity": "sha512-faGUlTcXka5l7rv0lP3K3vGW/ejRuOS24RR2aSFWREUQqzjgdsuWNo/IiPqL3kWRGt6Ahl2+qcDAwtdeWeuGUw==", + "license": "MIT", + "dependencies": { + "std-env": "^3.10.0", + "yoctocolors": "^2.1.2" + }, + "bin": { + "jiti": "lib/jiti-cli.mjs" + } + }, + "node_modules/@mariozechner/pi-agent-core": { + "version": "0.72.1", + "resolved": "https://registry.npmjs.org/@mariozechner/pi-agent-core/-/pi-agent-core-0.72.1.tgz", + "integrity": "sha512-Z5XH9mUDsBymh7Prtk5Eun4Cs+s9C3uzynug+oWAjzQESjjnCuy7KU6Ek8E9Eg+b9yroCwVw2ItLDxp2E3vYjA==", + "license": "MIT", + "dependencies": { + "@mariozechner/pi-ai": "^0.72.1", + "typebox": "^1.1.24" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@mariozechner/pi-ai": { + "version": "0.72.1", + "resolved": "https://registry.npmjs.org/@mariozechner/pi-ai/-/pi-ai-0.72.1.tgz", + "integrity": "sha512-mOq71Pjnu72xxzwrh52VIiNwt+/a+Wpa11k5segi01/zTZJt8eMDc5Q2z6GhczYMr5+6EpZ8T+BaeHqq0jk5ag==", + "license": "MIT", + "dependencies": { + "@anthropic-ai/sdk": "^0.91.1", + "@aws-sdk/client-bedrock-runtime": "^3.1030.0", + "@google/genai": "^1.40.0", + "@mistralai/mistralai": "^2.2.0", + "chalk": "^5.6.2", + "openai": "6.26.0", + "partial-json": "^0.1.7", + "proxy-agent": "^6.5.0", + "typebox": "^1.1.24", + "undici": "^7.19.1", + "zod-to-json-schema": "^3.24.6" + }, + "bin": { + "pi-ai": "dist/cli.js" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@mariozechner/pi-coding-agent": { + "version": "0.72.1", + "resolved": "https://registry.npmjs.org/@mariozechner/pi-coding-agent/-/pi-coding-agent-0.72.1.tgz", + "integrity": "sha512-gKApiLfAYpvPnWThvwXrLjZIhsziSSUKBph7DHCy/1IomuIGN1MTxS/9ZtcuFqPy3/+VfEUOKegGlY6m+CRNlA==", + "license": "MIT", + "dependencies": { + "@mariozechner/jiti": "^2.6.2", + "@mariozechner/pi-agent-core": "^0.72.1", + "@mariozechner/pi-ai": "^0.72.1", + "@mariozechner/pi-tui": "^0.72.1", + "@silvia-odwyer/photon-node": "^0.3.4", + "chalk": "^5.5.0", + "cli-highlight": "^2.1.11", + "diff": "^8.0.2", + "extract-zip": "^2.0.1", + "file-type": "^21.1.1", + "glob": "^13.0.1", + "hosted-git-info": "^9.0.2", + "ignore": "^7.0.5", + "marked": "^15.0.12", + "minimatch": "^10.2.3", + "proper-lockfile": "^4.1.2", + "strip-ansi": "^7.1.0", + "typebox": "^1.1.24", + "undici": "^7.19.1", + "uuid": "^14.0.0", + "yaml": "^2.8.2" + }, + "bin": { + "pi": "dist/cli.js" + }, + "engines": { + "node": ">=20.6.0" + }, + "optionalDependencies": { + "@mariozechner/clipboard": "^0.3.5" + } + }, + "node_modules/@mariozechner/pi-tui": { + "version": "0.72.1", + "resolved": "https://registry.npmjs.org/@mariozechner/pi-tui/-/pi-tui-0.72.1.tgz", + "integrity": "sha512-KjeqzMQp4vafomfkvI8HKv5/52PqRP5BmlowGC8WKyOaB+u0UkkTdfM5U1Ui3ty2gA7FOfglVRiyvcitiWwvMQ==", + "license": "MIT", + "dependencies": { + "@types/mime-types": "^2.1.4", + "chalk": "^5.5.0", + "get-east-asian-width": "^1.3.0", + "marked": "^15.0.12", + "mime-types": "^3.0.1" + }, + "engines": { + "node": ">=20.0.0" + }, + "optionalDependencies": { + "koffi": "^2.9.0" + } + }, + "node_modules/@mistralai/mistralai": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@mistralai/mistralai/-/mistralai-2.2.1.tgz", + "integrity": "sha512-uKU8CZmL2RzYKmplsU01hii4p3pe4HqJefpWNRWXm1Tcm0Sm4xXfwSLIy4k7ZCPlbETCGcp69E7hZs+WOJ5itQ==", + "license": "Apache-2.0", + "dependencies": { + "ws": "^8.18.0", + "zod": "^3.25.0 || ^4.0.0", + "zod-to-json-schema": "^3.25.0" + } + }, + "node_modules/@nodable/entities": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@nodable/entities/-/entities-2.1.0.tgz", + "integrity": "sha512-nyT7T3nbMyBI/lvr6L5TyWbFJAI9FTgVRakNoBqCD+PmID8DzFrrNdLLtHMwMszOtqZa8PAOV24ZqDnQrhQINA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/nodable" + } + ], + "license": "MIT" + }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/@protobufjs/aspromise": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", + "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/base64": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", + "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/codegen": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.5.tgz", + "integrity": "sha512-zgXFLzW3Ap33e6d0Wlj4MGIm6Ce8O89n/apUaGNB/jx+hw+ruWEp7EwGUshdLKVRCxZW12fp9r40E1mQrf/34g==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/eventemitter": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", + "integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/fetch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", + "integrity": "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==", + "license": "BSD-3-Clause", + "dependencies": { + "@protobufjs/aspromise": "^1.1.1", + "@protobufjs/inquire": "^1.1.0" + } + }, + "node_modules/@protobufjs/float": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", + "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/inquire": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.1.tgz", + "integrity": "sha512-mnzgDV26ueAvk7rsbt9L7bE0SuAoqyuys/sMMrmVcN5x9VsxpcG3rqAUSgDyLp0UZlmNfIbQ4fHfCtreVBk8Ew==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/path": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", + "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/pool": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", + "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/utf8": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.1.tgz", + "integrity": "sha512-oOAWABowe8EAbMyWKM0tYDKi8Yaox52D+HWZhAIJqQXbqe0xI/GV7FhLWqlEKreMkfDjshR5FKgi3mnle0h6Eg==", + "license": "BSD-3-Clause" + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.60.2.tgz", + "integrity": "sha512-dnlp69efPPg6Uaw2dVqzWRfAWRnYVb1XJ8CyyhIbZeaq4CA5/mLeZ1IEt9QqQxmbdvagjLIm2ZL8BxXv5lH4Yw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.60.2.tgz", + "integrity": "sha512-OqZTwDRDchGRHHm/hwLOL7uVPB9aUvI0am/eQuWMNyFHf5PSEQmyEeYYheA0EPPKUO/l0uigCp+iaTjoLjVoHg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.60.2.tgz", + "integrity": "sha512-UwRE7CGpvSVEQS8gUMBe1uADWjNnVgP3Iusyda1nSRwNDCsRjnGc7w6El6WLQsXmZTbLZx9cecegumcitNfpmA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.60.2.tgz", + "integrity": "sha512-gjEtURKLCC5VXm1I+2i1u9OhxFsKAQJKTVB8WvDAHF+oZlq0GTVFOlTlO1q3AlCTE/DF32c16ESvfgqR7343/g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.60.2.tgz", + "integrity": "sha512-Bcl6CYDeAgE70cqZaMojOi/eK63h5Me97ZqAQoh77VPjMysA/4ORQBRGo3rRy45x4MzVlU9uZxs8Uwy7ZaKnBw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.60.2.tgz", + "integrity": "sha512-LU+TPda3mAE2QB0/Hp5VyeKJivpC6+tlOXd1VMoXV/YFMvk/MNk5iXeBfB4MQGRWyOYVJ01625vjkr0Az98OJQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.60.2.tgz", + "integrity": "sha512-2QxQrM+KQ7DAW4o22j+XZ6RKdxjLD7BOWTP0Bv0tmjdyhXSsr2Ul1oJDQqh9Zf5qOwTuTc7Ek83mOFaKnodPjg==", + "cpu": [ + "arm" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.60.2.tgz", + "integrity": "sha512-TbziEu2DVsTEOPif2mKWkMeDMLoYjx95oESa9fkQQK7r/Orta0gnkcDpzwufEcAO2BLBsD7mZkXGFqEdMRRwfw==", + "cpu": [ + "arm" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.60.2.tgz", + "integrity": "sha512-bO/rVDiDUuM2YfuCUwZ1t1cP+/yqjqz+Xf2VtkdppefuOFS2OSeAfgafaHNkFn0t02hEyXngZkxtGqXcXwO8Rg==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.60.2.tgz", + "integrity": "sha512-hr26p7e93Rl0Za+JwW7EAnwAvKkehh12BU1Llm9Ykiibg4uIr2rbpxG9WCf56GuvidlTG9KiiQT/TXT1yAWxTA==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.60.2.tgz", + "integrity": "sha512-pOjB/uSIyDt+ow3k/RcLvUAOGpysT2phDn7TTUB3n75SlIgZzM6NKAqlErPhoFU+npgY3/n+2HYIQVbF70P9/A==", + "cpu": [ + "loong64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-musl": { + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.60.2.tgz", + "integrity": "sha512-2/w+q8jszv9Ww1c+6uJT3OwqhdmGP2/4T17cu8WuwyUuuaCDDJ2ojdyYwZzCxx0GcsZBhzi3HmH+J5pZNXnd+Q==", + "cpu": [ + "loong64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.60.2.tgz", + "integrity": "sha512-11+aL5vKheYgczxtPVVRhdptAM2H7fcDR5Gw4/bTcteuZBlH4oP9f5s9zYO9aGZvoGeBpqXI/9TZZihZ609wKw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-musl": { + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.60.2.tgz", + "integrity": "sha512-i16fokAGK46IVZuV8LIIwMdtqhin9hfYkCh8pf8iC3QU3LpwL+1FSFGej+O7l3E/AoknL6Dclh2oTdnRMpTzFQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.60.2.tgz", + "integrity": "sha512-49FkKS6RGQoriDSK/6E2GkAsAuU5kETFCh7pG4yD/ylj9rKhTmO3elsnmBvRD4PgJPds5W2PkhC82aVwmUcJ7A==", + "cpu": [ + "riscv64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.60.2.tgz", + "integrity": "sha512-mjYNkHPfGpUR00DuM1ZZIgs64Hpf4bWcz9Z41+4Q+pgDx73UwWdAYyf6EG/lRFldmdHHzgrYyge5akFUW0D3mQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.60.2.tgz", + "integrity": "sha512-ALyvJz965BQk8E9Al/JDKKDLH2kfKFLTGMlgkAbbYtZuJt9LU8DW3ZoDMCtQpXAltZxwBHevXz5u+gf0yA0YoA==", + "cpu": [ + "s390x" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.60.2.tgz", + "integrity": "sha512-UQjrkIdWrKI626Du8lCQ6MJp/6V1LAo2bOK9OTu4mSn8GGXIkPXk/Vsp4bLHCd9Z9Iz2OTEaokUE90VweJgIYQ==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.60.2.tgz", + "integrity": "sha512-bTsRGj6VlSdn/XD4CGyzMnzaBs9bsRxy79eTqTCBsA8TMIEky7qg48aPkvJvFe1HyzQ5oMZdg7AnVlWQSKLTnw==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-openbsd-x64": { + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.60.2.tgz", + "integrity": "sha512-6d4Z3534xitaA1FcMWP7mQPq5zGwBmGbhphh2DwaA1aNIXUu3KTOfwrWpbwI4/Gr0uANo7NTtaykFyO2hPuFLg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ] + }, + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.60.2.tgz", + "integrity": "sha512-NetAg5iO2uN7eB8zE5qrZ3CSil+7IJt4WDFLcC75Ymywq1VZVD6qJ6EvNLjZ3rEm6gB7XW5JdT60c6MN35Z85Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.60.2.tgz", + "integrity": "sha512-NCYhOotpgWZ5kdxCZsv6Iudx0wX8980Q/oW4pNFNihpBKsDbEA1zpkfxJGC0yugsUuyDZ7gL37dbzwhR0VI7pQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.60.2.tgz", + "integrity": "sha512-RXsaOqXxfoUBQoOgvmmijVxJnW2IGB0eoMO7F8FAjaj0UTywUO/luSqimWBJn04WNgUkeNhh7fs7pESXajWmkg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.60.2.tgz", + "integrity": "sha512-qdAzEULD+/hzObedtmV6iBpdL5TIbKVztGiK7O3/KYSf+HIzU257+MX1EXJcyIiDbMAqmbwaufcYPvyRryeZtA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.60.2.tgz", + "integrity": "sha512-Nd/SgG27WoA9e+/TdK74KnHz852TLa94ovOYySo/yMPuTmpckK/jIF2jSwS3g7ELSKXK13/cVdmg1Z/DaCWKxA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@silvia-odwyer/photon-node": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/@silvia-odwyer/photon-node/-/photon-node-0.3.4.tgz", + "integrity": "sha512-bnly4BKB3KDTFxrUIcgCLbaeVVS8lrAkri1pEzskpmxu9MdfGQTy8b8EgcD83ywD3RPMsIulY8xJH5Awa+t9fA==", + "license": "Apache-2.0" + }, + "node_modules/@smithy/config-resolver": { + "version": "4.4.17", + "resolved": "https://registry.npmjs.org/@smithy/config-resolver/-/config-resolver-4.4.17.tgz", + "integrity": "sha512-TzDZcAnhTyAHbXVxWZo7/tEcrIeFq20IBk8So3OLOetWpR8EwY/yEqBMBFaJMeyEiREDq4NfEl+qO3OAUD+vbQ==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/node-config-provider": "^4.3.14", + "@smithy/types": "^4.14.1", + "@smithy/util-config-provider": "^4.2.2", + "@smithy/util-endpoints": "^3.4.2", + "@smithy/util-middleware": "^4.2.14", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/core": { + "version": "3.23.17", + "resolved": "https://registry.npmjs.org/@smithy/core/-/core-3.23.17.tgz", + "integrity": "sha512-x7BlLbUFL8NWCGjMF9C+1N5cVCxcPa7g6Tv9B4A2luWx3be3oU8hQ96wIwxe/s7OhIzvoJH73HAUSg5JXVlEtQ==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/protocol-http": "^5.3.14", + "@smithy/types": "^4.14.1", + "@smithy/url-parser": "^4.2.14", + "@smithy/util-base64": "^4.3.2", + "@smithy/util-body-length-browser": "^4.2.2", + "@smithy/util-middleware": "^4.2.14", + "@smithy/util-stream": "^4.5.25", + "@smithy/util-utf8": "^4.2.2", + "@smithy/uuid": "^1.1.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/credential-provider-imds": { + "version": "4.2.14", + "resolved": "https://registry.npmjs.org/@smithy/credential-provider-imds/-/credential-provider-imds-4.2.14.tgz", + "integrity": "sha512-Au28zBN48ZAoXdooGUHemuVBrkE+Ie6RPmGNIAJsFqj33Vhb6xAgRifUydZ2aY+M+KaMAETAlKk5NC5h1G7wpg==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/node-config-provider": "^4.3.14", + "@smithy/property-provider": "^4.2.14", + "@smithy/types": "^4.14.1", + "@smithy/url-parser": "^4.2.14", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/eventstream-codec": { + "version": "4.2.14", + "resolved": "https://registry.npmjs.org/@smithy/eventstream-codec/-/eventstream-codec-4.2.14.tgz", + "integrity": "sha512-erZq0nOIpzfeZdCyzZjdJb4nVSKLUmSkaQUVkRGQTXs30gyUGeKnrYEg+Xe1W5gE3aReS7IgsvANwVPxSzY6Pw==", + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/crc32": "5.2.0", + "@smithy/types": "^4.14.1", + "@smithy/util-hex-encoding": "^4.2.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/eventstream-serde-browser": { + "version": "4.2.14", + "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-browser/-/eventstream-serde-browser-4.2.14.tgz", + "integrity": "sha512-8IelTCtTctWRbb+0Dcy+C0aICh1qa0qWXqgjcXDmMuCvPJRnv26hiDZoAau2ILOniki65mCPKqOQs/BaWvO4CQ==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/eventstream-serde-universal": "^4.2.14", + "@smithy/types": "^4.14.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/eventstream-serde-config-resolver": { + "version": "4.3.14", + "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-config-resolver/-/eventstream-serde-config-resolver-4.3.14.tgz", + "integrity": "sha512-sqHiHpYRYo3FJlaIxD1J8PhbcmJAm7IuM16mVnwSkCToD7g00IBZzKuiLNMGmftULmEUX6/UAz8/NN5uMP8bVA==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.14.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/eventstream-serde-node": { + "version": "4.2.14", + "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-node/-/eventstream-serde-node-4.2.14.tgz", + "integrity": "sha512-Ht/8BuGlKfFTy0H3+8eEu0vdpwGztCnaLLXtpXNdQqiR7Hj4vFScU3T436vRAjATglOIPjJXronY+1WxxNLSiw==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/eventstream-serde-universal": "^4.2.14", + "@smithy/types": "^4.14.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/eventstream-serde-universal": { + "version": "4.2.14", + "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-universal/-/eventstream-serde-universal-4.2.14.tgz", + "integrity": "sha512-lWyt4T2XQZUZgK3tQ3Wn0w3XBvZsK/vjTuJl6bXbnGZBHH0ZUSONTYiK9TgjTTzU54xQr3DRFwpjmhp0oLm3gg==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/eventstream-codec": "^4.2.14", + "@smithy/types": "^4.14.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/fetch-http-handler": { + "version": "5.3.17", + "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-5.3.17.tgz", + "integrity": "sha512-bXOvQzaSm6MnmLaWA1elgfQcAtN4UP3vXqV97bHuoOrHQOJiLT3ds6o9eo5bqd0TJfRFpzdGnDQdW3FACiAVdw==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/protocol-http": "^5.3.14", + "@smithy/querystring-builder": "^4.2.14", + "@smithy/types": "^4.14.1", + "@smithy/util-base64": "^4.3.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/hash-node": { + "version": "4.2.14", + "resolved": "https://registry.npmjs.org/@smithy/hash-node/-/hash-node-4.2.14.tgz", + "integrity": "sha512-8ZBDY2DD4wr+GGjTpPtiglEsqr0lUP+KHqgZcWczFf6qeZ/YRjMIOoQWVQlmwu7EtxKTd8YXD8lblmYcpBIA1g==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.14.1", + "@smithy/util-buffer-from": "^4.2.2", + "@smithy/util-utf8": "^4.2.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/invalid-dependency": { + "version": "4.2.14", + "resolved": "https://registry.npmjs.org/@smithy/invalid-dependency/-/invalid-dependency-4.2.14.tgz", + "integrity": "sha512-c21qJiTSb25xvvOp+H2TNZzPCngrvl5vIPqPB8zQ/DmJF4QWXO19x1dWfMJZ6wZuuWUPPm0gV8C0cU3+ifcWuw==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.14.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/is-array-buffer": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-4.2.2.tgz", + "integrity": "sha512-n6rQ4N8Jj4YTQO3YFrlgZuwKodf4zUFs7EJIWH86pSCWBaAtAGBFfCM7Wx6D2bBJ2xqFNxGBSrUWswT3M0VJow==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/middleware-content-length": { + "version": "4.2.14", + "resolved": "https://registry.npmjs.org/@smithy/middleware-content-length/-/middleware-content-length-4.2.14.tgz", + "integrity": "sha512-xhHq7fX4/3lv5NHxLUk3OeEvl0xZ+Ek3qIbWaCL4f9JwgDZEclPBElljaZCAItdGPQl/kSM4LPMOpy1MYgprpw==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/protocol-http": "^5.3.14", + "@smithy/types": "^4.14.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/middleware-endpoint": { + "version": "4.4.32", + "resolved": "https://registry.npmjs.org/@smithy/middleware-endpoint/-/middleware-endpoint-4.4.32.tgz", + "integrity": "sha512-ZZkgyjnJppiZbIm6Qbx92pbXYi1uzenIvGhBSCDlc7NwuAkiqSgS75j1czAD25ZLs2FjMjYy1q7gyRVWG6JA0Q==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/core": "^3.23.17", + "@smithy/middleware-serde": "^4.2.20", + "@smithy/node-config-provider": "^4.3.14", + "@smithy/shared-ini-file-loader": "^4.4.9", + "@smithy/types": "^4.14.1", + "@smithy/url-parser": "^4.2.14", + "@smithy/util-middleware": "^4.2.14", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/middleware-retry": { + "version": "4.5.7", + "resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-4.5.7.tgz", + "integrity": "sha512-bRt6ZImqVSeTk39Nm81K20ObIiAZ3WefY7G6+iz/0tZjs4dgRRjvRX2sgsH+zi6iDCRR/aQvQofLKxxz4rPBZg==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/core": "^3.23.17", + "@smithy/node-config-provider": "^4.3.14", + "@smithy/protocol-http": "^5.3.14", + "@smithy/service-error-classification": "^4.3.1", + "@smithy/smithy-client": "^4.12.13", + "@smithy/types": "^4.14.1", + "@smithy/util-middleware": "^4.2.14", + "@smithy/util-retry": "^4.3.6", + "@smithy/uuid": "^1.1.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/middleware-serde": { + "version": "4.2.20", + "resolved": "https://registry.npmjs.org/@smithy/middleware-serde/-/middleware-serde-4.2.20.tgz", + "integrity": "sha512-Lx9JMO9vArPtiChE3wbEZ5akMIDQpWQtlu90lhACQmNOXcGXRbaDywMHDzuDZ2OkZzP+9wQfZi3YJT9F67zTQQ==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/core": "^3.23.17", + "@smithy/protocol-http": "^5.3.14", + "@smithy/types": "^4.14.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/middleware-stack": { + "version": "4.2.14", + "resolved": "https://registry.npmjs.org/@smithy/middleware-stack/-/middleware-stack-4.2.14.tgz", + "integrity": "sha512-2dvkUKLuFdKsCRmOE4Mn63co0Djtsm+JMh0bYZQupN1pJwMeE8FmQmRLLzzEMN0dnNi7CDCYYH8F0EVwWiPBeA==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.14.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/node-config-provider": { + "version": "4.3.14", + "resolved": "https://registry.npmjs.org/@smithy/node-config-provider/-/node-config-provider-4.3.14.tgz", + "integrity": "sha512-S+gFjyo/weSVL0P1b9Ts8C/CwIfNCgUPikk3sl6QVsfE/uUuO+QsF+NsE/JkpvWqqyz1wg7HFdiaZuj5CoBMRg==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/property-provider": "^4.2.14", + "@smithy/shared-ini-file-loader": "^4.4.9", + "@smithy/types": "^4.14.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/node-http-handler": { + "version": "4.6.1", + "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-4.6.1.tgz", + "integrity": "sha512-iB+orM4x3xrr57X3YaXazfKnntl0LHlZB1kcXSGzMV1Tt0+YwEjGlbjk/44qEGtBzXAz6yFDzkYTKSV6Pj2HUg==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/protocol-http": "^5.3.14", + "@smithy/querystring-builder": "^4.2.14", + "@smithy/types": "^4.14.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/property-provider": { + "version": "4.2.14", + "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-4.2.14.tgz", + "integrity": "sha512-WuM31CgfsnQ/10i7NYr0PyxqknD72Y5uMfUMVSniPjbEPceiTErb4eIqJQ+pdxNEAUEWrewrGjIRjVbVHsxZiQ==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.14.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/protocol-http": { + "version": "5.3.14", + "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-5.3.14.tgz", + "integrity": "sha512-dN5F8kHx8RNU0r+pCwNmFZyz6ChjMkzShy/zup6MtkRmmix4vZzJdW+di7x//b1LiynIev88FM18ie+wwPcQtQ==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.14.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/querystring-builder": { + "version": "4.2.14", + "resolved": "https://registry.npmjs.org/@smithy/querystring-builder/-/querystring-builder-4.2.14.tgz", + "integrity": "sha512-XYA5Z0IqTeF+5XDdh4BBmSA0HvbgVZIyv4cmOoUheDNR57K1HgBp9ukUMx3Cr3XpDHHpLBnexPE3LAtDsZkj2A==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.14.1", + "@smithy/util-uri-escape": "^4.2.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/querystring-parser": { + "version": "4.2.14", + "resolved": "https://registry.npmjs.org/@smithy/querystring-parser/-/querystring-parser-4.2.14.tgz", + "integrity": "sha512-hr+YyqBD23GVvRxGGrcc/oOeNlK3PzT5Fu4dzrDXxzS1LpFiuL2PQQqKPs87M79aW7ziMs+nvB3qdw77SqE7Lw==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.14.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/service-error-classification": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@smithy/service-error-classification/-/service-error-classification-4.3.1.tgz", + "integrity": "sha512-aUQuDGh760ts/8MU+APjIZhlLPKhIIfqyzZaJikLEIMrdxFvxuLYD0WxWzaYWpmLbQlXDe9p7EWM3HsBe0K6Gw==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.14.1" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/shared-ini-file-loader": { + "version": "4.4.9", + "resolved": "https://registry.npmjs.org/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-4.4.9.tgz", + "integrity": "sha512-495/V2I15SHgedSJoDPD23JuSfKAp726ZI1V0wtjB07Wh7q/0tri/0e0DLefZCHgxZonrGKt/OCTpAtP1wE1kQ==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.14.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/signature-v4": { + "version": "5.3.14", + "resolved": "https://registry.npmjs.org/@smithy/signature-v4/-/signature-v4-5.3.14.tgz", + "integrity": "sha512-1D9Y/nmlVjCeSivCbhZ7hgEpmHyY1h0GvpSZt3l0xcD9JjmjVC1CHOozS6+Gh+/ldMH8JuJ6cujObQqfayAVFA==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/is-array-buffer": "^4.2.2", + "@smithy/protocol-http": "^5.3.14", + "@smithy/types": "^4.14.1", + "@smithy/util-hex-encoding": "^4.2.2", + "@smithy/util-middleware": "^4.2.14", + "@smithy/util-uri-escape": "^4.2.2", + "@smithy/util-utf8": "^4.2.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/smithy-client": { + "version": "4.12.13", + "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-4.12.13.tgz", + "integrity": "sha512-y/Pcj1V9+qG98gyu1gvftHB7rDpdh+7kIBIggs55yGm3JdtBV8GT8IFF3a1qxZ79QnaJHX9GXzvBG6tAd+czJA==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/core": "^3.23.17", + "@smithy/middleware-endpoint": "^4.4.32", + "@smithy/middleware-stack": "^4.2.14", + "@smithy/protocol-http": "^5.3.14", + "@smithy/types": "^4.14.1", + "@smithy/util-stream": "^4.5.25", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/types": { + "version": "4.14.1", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.14.1.tgz", + "integrity": "sha512-59b5HtSVrVR/eYNei3BUj3DCPKD/G7EtDDe7OEJE7i7FtQFugYo6MxbotS8mVJkLNVf8gYaAlEBwwtJ9HzhWSg==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/url-parser": { + "version": "4.2.14", + "resolved": "https://registry.npmjs.org/@smithy/url-parser/-/url-parser-4.2.14.tgz", + "integrity": "sha512-p06BiBigJ8bTA3MgnOfCtDUWnAMY0YfedO/GRpmc7p+wg3KW8vbXy1xwSu5ASy0wV7rRYtlfZOIKH4XqfhjSQQ==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/querystring-parser": "^4.2.14", + "@smithy/types": "^4.14.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-base64": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/@smithy/util-base64/-/util-base64-4.3.2.tgz", + "integrity": "sha512-XRH6b0H/5A3SgblmMa5ErXQ2XKhfbQB+Fm/oyLZ2O2kCUrwgg55bU0RekmzAhuwOjA9qdN5VU2BprOvGGUkOOQ==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/util-buffer-from": "^4.2.2", + "@smithy/util-utf8": "^4.2.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-body-length-browser": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@smithy/util-body-length-browser/-/util-body-length-browser-4.2.2.tgz", + "integrity": "sha512-JKCrLNOup3OOgmzeaKQwi4ZCTWlYR5H4Gm1r2uTMVBXoemo1UEghk5vtMi1xSu2ymgKVGW631e2fp9/R610ZjQ==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-body-length-node": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/@smithy/util-body-length-node/-/util-body-length-node-4.2.3.tgz", + "integrity": "sha512-ZkJGvqBzMHVHE7r/hcuCxlTY8pQr1kMtdsVPs7ex4mMU+EAbcXppfo5NmyxMYi2XU49eqaz56j2gsk4dHHPG/g==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-buffer-from": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-4.2.2.tgz", + "integrity": "sha512-FDXD7cvUoFWwN6vtQfEta540Y/YBe5JneK3SoZg9bThSoOAC/eGeYEua6RkBgKjGa/sz6Y+DuBZj3+YEY21y4Q==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/is-array-buffer": "^4.2.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-config-provider": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@smithy/util-config-provider/-/util-config-provider-4.2.2.tgz", + "integrity": "sha512-dWU03V3XUprJwaUIFVv4iOnS1FC9HnMHDfUrlNDSh4315v0cWyaIErP8KiqGVbf5z+JupoVpNM7ZB3jFiTejvQ==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-defaults-mode-browser": { + "version": "4.3.49", + "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-4.3.49.tgz", + "integrity": "sha512-a5bNrdiONYB/qE2BuKegvUMd/+ZDwdg4vsNuuSzYE8qs2EYAdK9CynL+Rzn29PbPiUqoz/cbpRbcLzD5lEevHw==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/property-provider": "^4.2.14", + "@smithy/smithy-client": "^4.12.13", + "@smithy/types": "^4.14.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-defaults-mode-node": { + "version": "4.2.54", + "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-4.2.54.tgz", + "integrity": "sha512-g1cvrJvOnzeJgEdf7AE4luI7gp6L8weE0y9a9wQUSGtjb8QRHDbCJYuE4Sy0SD9N8RrnNPFsPltAz/OSoBR9Zw==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/config-resolver": "^4.4.17", + "@smithy/credential-provider-imds": "^4.2.14", + "@smithy/node-config-provider": "^4.3.14", + "@smithy/property-provider": "^4.2.14", + "@smithy/smithy-client": "^4.12.13", + "@smithy/types": "^4.14.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-endpoints": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/@smithy/util-endpoints/-/util-endpoints-3.4.2.tgz", + "integrity": "sha512-a55Tr+3OKld4TTtnT+RhKOQHyPxm3j/xL4OR83WBUhLJaKDS9dnJ7arRMOp3t31dcLhApwG9bgvrRXBHlLdIkg==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/node-config-provider": "^4.3.14", + "@smithy/types": "^4.14.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-hex-encoding": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@smithy/util-hex-encoding/-/util-hex-encoding-4.2.2.tgz", + "integrity": "sha512-Qcz3W5vuHK4sLQdyT93k/rfrUwdJ8/HZ+nMUOyGdpeGA1Wxt65zYwi3oEl9kOM+RswvYq90fzkNDahPS8K0OIg==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-middleware": { + "version": "4.2.14", + "resolved": "https://registry.npmjs.org/@smithy/util-middleware/-/util-middleware-4.2.14.tgz", + "integrity": "sha512-1Su2vj9RYNDEv/V+2E+jXkkwGsgR7dc4sfHn9Z7ruzQHJIEni9zzw5CauvRXlFJfmgcqYP8fWa0dkh2Q2YaQyw==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.14.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-retry": { + "version": "4.3.8", + "resolved": "https://registry.npmjs.org/@smithy/util-retry/-/util-retry-4.3.8.tgz", + "integrity": "sha512-LUIxbTBi+OpvXpg91poGA6BdyoleMDLnfXjVDqyi2RvZmTveY5loE/FgYUBCR5LU2BThW2SoZRh8dTIIy38IPw==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/service-error-classification": "^4.3.1", + "@smithy/types": "^4.14.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-stream": { + "version": "4.5.25", + "resolved": "https://registry.npmjs.org/@smithy/util-stream/-/util-stream-4.5.25.tgz", + "integrity": "sha512-/PFpG4k8Ze8Ei+mMKj3oiPICYekthuzePZMgZbCqMiXIHHf4n2aZ4Ps0aSRShycFTGuj/J6XldmC0x0DwednIA==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/fetch-http-handler": "^5.3.17", + "@smithy/node-http-handler": "^4.6.1", + "@smithy/types": "^4.14.1", + "@smithy/util-base64": "^4.3.2", + "@smithy/util-buffer-from": "^4.2.2", + "@smithy/util-hex-encoding": "^4.2.2", + "@smithy/util-utf8": "^4.2.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-uri-escape": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@smithy/util-uri-escape/-/util-uri-escape-4.2.2.tgz", + "integrity": "sha512-2kAStBlvq+lTXHyAZYfJRb/DfS3rsinLiwb+69SstC9Vb0s9vNWkRwpnj918Pfi85mzi42sOqdV72OLxWAISnw==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-utf8": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-4.2.2.tgz", + "integrity": "sha512-75MeYpjdWRe8M5E3AW0O4Cx3UadweS+cwdXjwYGBW5h/gxxnbeZ877sLPX/ZJA9GVTlL/qG0dXP29JWFCD1Ayw==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/util-buffer-from": "^4.2.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/uuid": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@smithy/uuid/-/uuid-1.1.2.tgz", + "integrity": "sha512-O/IEdcCUKkubz60tFbGA7ceITTAJsty+lBjNoorP4Z6XRqaFb/OjQjZODophEcuq68nKm6/0r+6/lLQ+XVpk8g==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@tokenizer/inflate": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@tokenizer/inflate/-/inflate-0.4.1.tgz", + "integrity": "sha512-2mAv+8pkG6GIZiF1kNg1jAjh27IDxEPKwdGul3snfztFerfPGI1LjDezZp3i7BElXompqEtPmoPx6c2wgtWsOA==", + "license": "MIT", + "dependencies": { + "debug": "^4.4.3", + "token-types": "^6.1.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Borewit" + } + }, + "node_modules/@tokenizer/token": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@tokenizer/token/-/token-0.3.0.tgz", + "integrity": "sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==", + "license": "MIT" + }, + "node_modules/@tootallnate/quickjs-emscripten": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@tootallnate/quickjs-emscripten/-/quickjs-emscripten-0.23.0.tgz", + "integrity": "sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA==", + "license": "MIT" + }, + "node_modules/@types/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/mime-types": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@types/mime-types/-/mime-types-2.1.4.tgz", + "integrity": "sha512-lfU4b34HOri+kAY5UheuFMWPDOI+OPceBSHZKp69gEyTL/mmJ4cnU6Y/rlme3UL3GyOn6Y42hyIEw0/q8sWx5w==", + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "22.15.3", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.15.3.tgz", + "integrity": "sha512-lX7HFZeHf4QG/J7tBZqrCAXwz9J5RD56Y6MpP0eJkka8p+K0RY/yBTW7CYFJ4VGCclxqOLKmiGP5juQc6MKgcw==", + "license": "MIT", + "dependencies": { + "undici-types": "~6.21.0" + } + }, + "node_modules/@types/retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==", + "license": "MIT" + }, + "node_modules/@types/yauzl": { + "version": "2.10.3", + "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.3.tgz", + "integrity": "sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==", + "license": "MIT", + "optional": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@vitest/coverage-v8": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-3.1.3.tgz", + "integrity": "sha512-cj76U5gXCl3g88KSnf80kof6+6w+K4BjOflCl7t6yRJPDuCrHtVu0SgNYOUARJOL5TI8RScDbm5x4s1/P9bvpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@ampproject/remapping": "^2.3.0", + "@bcoe/v8-coverage": "^1.0.2", + "debug": "^4.4.0", + "istanbul-lib-coverage": "^3.2.2", + "istanbul-lib-report": "^3.0.1", + "istanbul-lib-source-maps": "^5.0.6", + "istanbul-reports": "^3.1.7", + "magic-string": "^0.30.17", + "magicast": "^0.3.5", + "std-env": "^3.9.0", + "test-exclude": "^7.0.1", + "tinyrainbow": "^2.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "@vitest/browser": "3.1.3", + "vitest": "3.1.3" + }, + "peerDependenciesMeta": { + "@vitest/browser": { + "optional": true + } + } + }, + "node_modules/@vitest/expect": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-3.1.3.tgz", + "integrity": "sha512-7FTQQuuLKmN1Ig/h+h/GO+44Q1IlglPlR2es4ab7Yvfx+Uk5xsv+Ykk+MEt/M2Yn/xGmzaLKxGw2lgy2bwuYqg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/spy": "3.1.3", + "@vitest/utils": "3.1.3", + "chai": "^5.2.0", + "tinyrainbow": "^2.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/mocker": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-3.1.3.tgz", + "integrity": "sha512-PJbLjonJK82uCWHjzgBJZuR7zmAOrSvKk1QBxrennDIgtH4uK0TB1PvYmc0XBCigxxtiAVPfWtAdy4lpz8SQGQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/spy": "3.1.3", + "estree-walker": "^3.0.3", + "magic-string": "^0.30.17" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "msw": "^2.4.9", + "vite": "^5.0.0 || ^6.0.0" + }, + "peerDependenciesMeta": { + "msw": { + "optional": true + }, + "vite": { + "optional": true + } + } + }, + "node_modules/@vitest/pretty-format": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-3.2.4.tgz", + "integrity": "sha512-IVNZik8IVRJRTr9fxlitMKeJeXFFFN0JaB9PHPGQ8NKQbGpfjlTx9zO4RefN8gp7eqjNy8nyK3NZmBzOPeIxtA==", + "dev": true, + "license": "MIT", + "dependencies": { + "tinyrainbow": "^2.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/runner": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-3.1.3.tgz", + "integrity": "sha512-Tae+ogtlNfFei5DggOsSUvkIaSuVywujMj6HzR97AHK6XK8i3BuVyIifWAm/sE3a15lF5RH9yQIrbXYuo0IFyA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/utils": "3.1.3", + "pathe": "^2.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/snapshot": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-3.1.3.tgz", + "integrity": "sha512-XVa5OPNTYUsyqG9skuUkFzAeFnEzDp8hQu7kZ0N25B1+6KjGm4hWLtURyBbsIAOekfWQ7Wuz/N/XXzgYO3deWQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "3.1.3", + "magic-string": "^0.30.17", + "pathe": "^2.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/snapshot/node_modules/@vitest/pretty-format": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-3.1.3.tgz", + "integrity": "sha512-i6FDiBeJUGLDKADw2Gb01UtUNb12yyXAqC/mmRWuYl+m/U9GS7s8us5ONmGkGpUUo7/iAYzI2ePVfOZTYvUifA==", + "dev": true, + "license": "MIT", + "dependencies": { + "tinyrainbow": "^2.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/spy": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-3.1.3.tgz", + "integrity": "sha512-x6w+ctOEmEXdWaa6TO4ilb7l9DxPR5bwEb6hILKuxfU1NqWT2mpJD9NJN7t3OTfxmVlOMrvtoFJGdgyzZ605lQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "tinyspy": "^3.0.2" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/utils": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-3.1.3.tgz", + "integrity": "sha512-2Ltrpht4OmHO9+c/nmHtF09HWiyWdworqnHIwjfvDyWjuwKbdkcS9AnhsDn+8E2RM4x++foD1/tNuLPVvWG1Rg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "3.1.3", + "loupe": "^3.1.3", + "tinyrainbow": "^2.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/utils/node_modules/@vitest/pretty-format": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-3.1.3.tgz", + "integrity": "sha512-i6FDiBeJUGLDKADw2Gb01UtUNb12yyXAqC/mmRWuYl+m/U9GS7s8us5ONmGkGpUUo7/iAYzI2ePVfOZTYvUifA==", + "dev": true, + "license": "MIT", + "dependencies": { + "tinyrainbow": "^2.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/agent-base": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", + "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, + "node_modules/ansi-regex": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/any-promise": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", + "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==", + "license": "MIT" + }, + "node_modules/assertion-error": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", + "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + } + }, + "node_modules/ast-types": { + "version": "0.13.4", + "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.13.4.tgz", + "integrity": "sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w==", + "license": "MIT", + "dependencies": { + "tslib": "^2.0.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/basic-ftp": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/basic-ftp/-/basic-ftp-5.3.1.tgz", + "integrity": "sha512-bopVNp6ugyA150DDuZfPFdt1KZ5a94ZDiwX4hMgZDzF+GttD80lEy8kj98kbyhLXnPvhtIo93mdnLIjpCAeeOw==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/bignumber.js": { + "version": "9.3.1", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.3.1.tgz", + "integrity": "sha512-Ko0uX15oIUS7wJ3Rb30Fs6SkVbLmPBAKdlm7q9+ak9bbIeFf0MwuBsQV6z7+X768/cHsfg+WlysDWJcmthjsjQ==", + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/bowser": { + "version": "2.14.1", + "resolved": "https://registry.npmjs.org/bowser/-/bowser-2.14.1.tgz", + "integrity": "sha512-tzPjzCxygAKWFOJP011oxFHs57HzIhOEracIgAePE4pqB3LikALKnSzUyU4MGs9/iCEUuHlAJTjTc5M+u7YEGg==", + "license": "MIT" + }, + "node_modules/brace-expansion": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.5.tgz", + "integrity": "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==", + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==", + "license": "BSD-3-Clause" + }, + "node_modules/cac": { + "version": "6.7.14", + "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz", + "integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/chai": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/chai/-/chai-5.3.3.tgz", + "integrity": "sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw==", + "dev": true, + "license": "MIT", + "dependencies": { + "assertion-error": "^2.0.1", + "check-error": "^2.1.1", + "deep-eql": "^5.0.1", + "loupe": "^3.1.0", + "pathval": "^2.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/chalk": { + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz", + "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==", + "license": "MIT", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/check-error": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-2.1.3.tgz", + "integrity": "sha512-PAJdDJusoxnwm1VwW07VWwUN1sl7smmC3OKggvndJFadxxDRyFJBX/ggnu/KE4kQAB7a3Dp8f/YXC1FlUprWmA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 16" + } + }, + "node_modules/cli-highlight": { + "version": "2.1.11", + "resolved": "https://registry.npmjs.org/cli-highlight/-/cli-highlight-2.1.11.tgz", + "integrity": "sha512-9KDcoEVwyUXrjcJNvHD0NFc/hiwe/WPVYIleQh2O1N2Zro5gWJZ/K+3DGn8w8P/F6FxOgzyC5bxDyHIgCSPhGg==", + "license": "ISC", + "dependencies": { + "chalk": "^4.0.0", + "highlight.js": "^10.7.1", + "mz": "^2.4.0", + "parse5": "^5.1.1", + "parse5-htmlparser2-tree-adapter": "^6.0.0", + "yargs": "^16.0.0" + }, + "bin": { + "highlight": "bin/highlight" + }, + "engines": { + "node": ">=8.0.0", + "npm": ">=5.0.0" + } + }, + "node_modules/cli-highlight/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "node_modules/cliui/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "license": "MIT" + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/data-uri-to-buffer": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", + "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==", + "license": "MIT", + "engines": { + "node": ">= 12" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/deep-eql": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-5.0.2.tgz", + "integrity": "sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/degenerator": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/degenerator/-/degenerator-5.0.1.tgz", + "integrity": "sha512-TllpMR/t0M5sqCXfj85i4XaAzxmS5tVA16dqvdkMwGmzI+dXLXnw3J+3Vdv7VKw+ThlTMboK6i9rnZ6Nntj5CQ==", + "license": "MIT", + "dependencies": { + "ast-types": "^0.13.4", + "escodegen": "^2.1.0", + "esprima": "^4.0.1" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/diff": { + "version": "8.0.4", + "resolved": "https://registry.npmjs.org/diff/-/diff-8.0.4.tgz", + "integrity": "sha512-DPi0FmjiSU5EvQV0++GFDOJ9ASQUVFh5kD+OzOnYdi7n3Wpm9hWWGfB/O2blfHcMVTL5WkQXSnRiK9makhrcnw==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true, + "license": "MIT" + }, + "node_modules/ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "license": "Apache-2.0", + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT" + }, + "node_modules/end-of-stream": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz", + "integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==", + "license": "MIT", + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/es-module-lexer": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz", + "integrity": "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==", + "dev": true, + "license": "MIT" + }, + "node_modules/esbuild": { + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.4.tgz", + "integrity": "sha512-8pgjLUcUjcgDg+2Q4NYXnPbo/vncAY4UmyaCm0jZevERqCHZIaWwdJHkf8XQtu4AxSKCdvrUbT0XUr1IdZzI8Q==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.25.4", + "@esbuild/android-arm": "0.25.4", + "@esbuild/android-arm64": "0.25.4", + "@esbuild/android-x64": "0.25.4", + "@esbuild/darwin-arm64": "0.25.4", + "@esbuild/darwin-x64": "0.25.4", + "@esbuild/freebsd-arm64": "0.25.4", + "@esbuild/freebsd-x64": "0.25.4", + "@esbuild/linux-arm": "0.25.4", + "@esbuild/linux-arm64": "0.25.4", + "@esbuild/linux-ia32": "0.25.4", + "@esbuild/linux-loong64": "0.25.4", + "@esbuild/linux-mips64el": "0.25.4", + "@esbuild/linux-ppc64": "0.25.4", + "@esbuild/linux-riscv64": "0.25.4", + "@esbuild/linux-s390x": "0.25.4", + "@esbuild/linux-x64": "0.25.4", + "@esbuild/netbsd-arm64": "0.25.4", + "@esbuild/netbsd-x64": "0.25.4", + "@esbuild/openbsd-arm64": "0.25.4", + "@esbuild/openbsd-x64": "0.25.4", + "@esbuild/sunos-x64": "0.25.4", + "@esbuild/win32-arm64": "0.25.4", + "@esbuild/win32-ia32": "0.25.4", + "@esbuild/win32-x64": "0.25.4" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escodegen": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.1.0.tgz", + "integrity": "sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==", + "license": "BSD-2-Clause", + "dependencies": { + "esprima": "^4.0.1", + "estraverse": "^5.2.0", + "esutils": "^2.0.2" + }, + "bin": { + "escodegen": "bin/escodegen.js", + "esgenerate": "bin/esgenerate.js" + }, + "engines": { + "node": ">=6.0" + }, + "optionalDependencies": { + "source-map": "~0.6.1" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "license": "BSD-2-Clause", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estree-walker": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/expect-type": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.3.0.tgz", + "integrity": "sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "license": "MIT" + }, + "node_modules/extract-zip": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz", + "integrity": "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==", + "license": "BSD-2-Clause", + "dependencies": { + "debug": "^4.1.1", + "get-stream": "^5.1.0", + "yauzl": "^2.10.0" + }, + "bin": { + "extract-zip": "cli.js" + }, + "engines": { + "node": ">= 10.17.0" + }, + "optionalDependencies": { + "@types/yauzl": "^2.9.1" + } + }, + "node_modules/fast-xml-builder": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/fast-xml-builder/-/fast-xml-builder-1.1.5.tgz", + "integrity": "sha512-4TJn/8FKLeslLAH3dnohXqE3QSoxkhvaMzepOIZytwJXZO69Bfz0HBdDHzOTOon6G59Zrk6VQ2bEiv1t61rfkA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "license": "MIT", + "dependencies": { + "path-expression-matcher": "^1.1.3" + } + }, + "node_modules/fast-xml-parser": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-5.7.2.tgz", + "integrity": "sha512-P7oW7tLbYnhOLQk/Gv7cZgzgMPP/XN03K02/Jy6Y/NHzyIAIpxuZIM/YqAkfiXFPxA2CTm7NtCijK9EDu09u2w==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "license": "MIT", + "dependencies": { + "@nodable/entities": "^2.1.0", + "fast-xml-builder": "^1.1.5", + "path-expression-matcher": "^1.5.0", + "strnum": "^2.2.3" + }, + "bin": { + "fxparser": "src/cli/cli.js" + } + }, + "node_modules/fd-slicer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", + "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==", + "license": "MIT", + "dependencies": { + "pend": "~1.2.0" + } + }, + "node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/fetch-blob": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz", + "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "paypal", + "url": "https://paypal.me/jimmywarting" + } + ], + "license": "MIT", + "dependencies": { + "node-domexception": "^1.0.0", + "web-streams-polyfill": "^3.0.3" + }, + "engines": { + "node": "^12.20 || >= 14.13" + } + }, + "node_modules/file-type": { + "version": "21.3.4", + "resolved": "https://registry.npmjs.org/file-type/-/file-type-21.3.4.tgz", + "integrity": "sha512-Ievi/yy8DS3ygGvT47PjSfdFoX+2isQueoYP1cntFW1JLYAuS4GD7NUPGg4zv2iZfV52uDyk5w5Z0TdpRS6Q1g==", + "license": "MIT", + "dependencies": { + "@tokenizer/inflate": "^0.4.1", + "strtok3": "^10.3.4", + "token-types": "^6.1.1", + "uint8array-extras": "^1.4.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sindresorhus/file-type?sponsor=1" + } + }, + "node_modules/foreground-child": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", + "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", + "dev": true, + "license": "ISC", + "dependencies": { + "cross-spawn": "^7.0.6", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/foreground-child/node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/formdata-polyfill": { + "version": "4.0.10", + "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", + "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==", + "license": "MIT", + "dependencies": { + "fetch-blob": "^3.1.2" + }, + "engines": { + "node": ">=12.20.0" + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/gaxios": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-7.1.4.tgz", + "integrity": "sha512-bTIgTsM2bWn3XklZISBTQX7ZSddGW+IO3bMdGaemHZ3tbqExMENHLx6kKZ/KlejgrMtj8q7wBItt51yegqalrA==", + "license": "Apache-2.0", + "dependencies": { + "extend": "^3.0.2", + "https-proxy-agent": "^7.0.1", + "node-fetch": "^3.3.2" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/gcp-metadata": { + "version": "8.1.2", + "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-8.1.2.tgz", + "integrity": "sha512-zV/5HKTfCeKWnxG0Dmrw51hEWFGfcF2xiXqcA3+J90WDuP0SvoiSO5ORvcBsifmx/FoIjgQN3oNOGaQ5PhLFkg==", + "license": "Apache-2.0", + "dependencies": { + "gaxios": "^7.0.0", + "google-logging-utils": "^1.0.0", + "json-bigint": "^1.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-east-asian-width": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.5.0.tgz", + "integrity": "sha512-CQ+bEO+Tva/qlmw24dCejulK5pMzVnUOFOijVogd3KQs07HnRIgp8TGipvCCRT06xeYEbpbgwaCxglFyiuIcmA==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "license": "MIT", + "dependencies": { + "pump": "^3.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-uri": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/get-uri/-/get-uri-6.0.5.tgz", + "integrity": "sha512-b1O07XYq8eRuVzBNgJLstU6FYc1tS6wnMtF1I1D9lE8LxZSOGZ7LhxN54yPP6mGw5f2CkXY2BQUL9Fx41qvcIg==", + "license": "MIT", + "dependencies": { + "basic-ftp": "^5.0.2", + "data-uri-to-buffer": "^6.0.2", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/get-uri/node_modules/data-uri-to-buffer": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-6.0.2.tgz", + "integrity": "sha512-7hvf7/GW8e86rW0ptuwS3OcBGDjIi6SZva7hCyWC0yYry2cOPmLIjXAUHI6DK2HsnwJd9ifmt57i8eV2n4YNpw==", + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, + "node_modules/glob": { + "version": "13.0.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-13.0.6.tgz", + "integrity": "sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw==", + "license": "BlueOak-1.0.0", + "dependencies": { + "minimatch": "^10.2.2", + "minipass": "^7.1.3", + "path-scurry": "^2.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/google-auth-library": { + "version": "10.6.2", + "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-10.6.2.tgz", + "integrity": "sha512-e27Z6EThmVNNvtYASwQxose/G57rkRuaRbQyxM2bvYLLX/GqWZ5chWq2EBoUchJbCc57eC9ArzO5wMsEmWftCw==", + "license": "Apache-2.0", + "dependencies": { + "base64-js": "^1.3.0", + "ecdsa-sig-formatter": "^1.0.11", + "gaxios": "^7.1.4", + "gcp-metadata": "8.1.2", + "google-logging-utils": "1.1.3", + "jws": "^4.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/google-logging-utils": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/google-logging-utils/-/google-logging-utils-1.1.3.tgz", + "integrity": "sha512-eAmLkjDjAFCVXg7A1unxHsLf961m6y17QFqXqAXGj/gVkKFrEICfStRfwUlGNfeCEjNRa32JEWOUTlYXPyyKvA==", + "license": "Apache-2.0", + "engines": { + "node": ">=14" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "license": "ISC" + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/highlight.js": { + "version": "10.7.3", + "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.7.3.tgz", + "integrity": "sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==", + "license": "BSD-3-Clause", + "engines": { + "node": "*" + } + }, + "node_modules/hosted-git-info": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-9.0.3.tgz", + "integrity": "sha512-Hc+ghLoSt6QaYZUv0WBiIvmMDZuZZ7oaDvdH8MbfOO4lOsxdXLEvuC6ePoGs9H1X9oCLyq6+NVN0MKqD+ydxyg==", + "license": "ISC", + "dependencies": { + "lru-cache": "^11.1.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true, + "license": "MIT" + }, + "node_modules/http-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", + "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/https-proxy-agent": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", + "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/ignore": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", + "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/ip-address": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.2.0.tgz", + "integrity": "sha512-/+S6j4E9AHvW9SWMSEY9Xfy66O5PWvVEJ08O0y5JGyEKQpojb0K0GKpz/v5HJ/G0vi3D2sjGK78119oXZeE0qA==", + "license": "MIT", + "engines": { + "node": ">= 12" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/istanbul-lib-coverage": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", + "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-report": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", + "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^4.0.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-source-maps": { + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-5.0.6.tgz", + "integrity": "sha512-yg2d+Em4KizZC5niWhQaIomgf5WlL4vOOjZ5xGCmF8SnPE/mDWWXgvRExdcpCgh9lLRRa1/fSYp2ymmbJ1pI+A==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.23", + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-reports": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.2.0.tgz", + "integrity": "sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jackspeak": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, + "node_modules/json-bigint": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-1.0.0.tgz", + "integrity": "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==", + "license": "MIT", + "dependencies": { + "bignumber.js": "^9.0.0" + } + }, + "node_modules/json-schema-to-ts": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/json-schema-to-ts/-/json-schema-to-ts-3.1.1.tgz", + "integrity": "sha512-+DWg8jCJG2TEnpy7kOm/7/AxaYoaRbjVB4LFZLySZlWn8exGs3A4OLJR966cVvU26N7X9TWxl+Jsw7dzAqKT6g==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.18.3", + "ts-algebra": "^2.0.0" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/jwa": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.1.tgz", + "integrity": "sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg==", + "license": "MIT", + "dependencies": { + "buffer-equal-constant-time": "^1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/jws": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.1.tgz", + "integrity": "sha512-EKI/M/yqPncGUUh44xz0PxSidXFr/+r0pA70+gIYhjv+et7yxM+s29Y+VGDkovRofQem0fs7Uvf4+YmAdyRduA==", + "license": "MIT", + "dependencies": { + "jwa": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/koffi": { + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/koffi/-/koffi-2.16.1.tgz", + "integrity": "sha512-0Ie6CfD026dNfWSosDw9dPxPzO9Rlyo0N8m5r05S8YjytIpuilzMFDMY4IDy/8xQsTwpuVinhncD+S8n3bcYZQ==", + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "funding": { + "url": "https://liberapay.com/Koromix" + } + }, + "node_modules/long": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/long/-/long-5.3.2.tgz", + "integrity": "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==", + "license": "Apache-2.0" + }, + "node_modules/loupe": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-3.2.1.tgz", + "integrity": "sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/lru-cache": { + "version": "11.3.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.3.5.tgz", + "integrity": "sha512-NxVFwLAnrd9i7KUBxC4DrUhmgjzOs+1Qm50D3oF1/oL+r1NpZ4gA7xvG0/zJ8evR7zIKn4vLf7qTNduWFtCrRw==", + "license": "BlueOak-1.0.0", + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/magic-string": { + "version": "0.30.21", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, + "node_modules/magicast": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/magicast/-/magicast-0.3.5.tgz", + "integrity": "sha512-L0WhttDl+2BOsybvEOLK7fW3UA0OQ0IQ2d6Zl2x/a6vVRs3bAY0ECOSHHeL5jD+SbOpOCUEi0y1DgHEn9Qn1AQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.25.4", + "@babel/types": "^7.25.4", + "source-map-js": "^1.2.0" + } + }, + "node_modules/make-dir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", + "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/marked": { + "version": "15.0.12", + "resolved": "https://registry.npmjs.org/marked/-/marked-15.0.12.tgz", + "integrity": "sha512-8dD6FusOQSrpv9Z1rdNMdlSgQOIP880DHqnohobOmYLElGEqAL/JvxvuxZO16r4HtjTlfPRDC1hbvxC9dPN2nA==", + "license": "MIT", + "bin": { + "marked": "bin/marked.js" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/mime-db": { + "version": "1.54.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz", + "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", + "license": "MIT", + "dependencies": { + "mime-db": "^1.54.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/minimatch": { + "version": "10.2.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", + "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.5" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/minipass": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz", + "integrity": "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==", + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/mz": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", + "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", + "license": "MIT", + "dependencies": { + "any-promise": "^1.0.0", + "object-assign": "^4.0.1", + "thenify-all": "^1.0.0" + } + }, + "node_modules/nanoid": { + "version": "3.3.12", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.12.tgz", + "integrity": "sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/netmask": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/netmask/-/netmask-2.1.1.tgz", + "integrity": "sha512-eonl3sLUha+S1GzTPxychyhnUzKyeQkZ7jLjKrBagJgPla13F+uQ71HgpFefyHgqrjEbCPkDArxYsjY8/+gLKA==", + "license": "MIT", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/node-domexception": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", + "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", + "deprecated": "Use your platform's native DOMException instead", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "github", + "url": "https://paypal.me/jimmywarting" + } + ], + "license": "MIT", + "engines": { + "node": ">=10.5.0" + } + }, + "node_modules/node-fetch": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz", + "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==", + "license": "MIT", + "dependencies": { + "data-uri-to-buffer": "^4.0.0", + "fetch-blob": "^3.1.4", + "formdata-polyfill": "^4.0.10" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/node-fetch" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/openai": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/openai/-/openai-6.26.0.tgz", + "integrity": "sha512-zd23dbWTjiJ6sSAX6s0HrCZi41JwTA1bQVs0wLQPZ2/5o2gxOJA5wh7yOAUgwYybfhDXyhwlpeQf7Mlgx8EOCA==", + "license": "Apache-2.0", + "bin": { + "openai": "bin/cli" + }, + "peerDependencies": { + "ws": "^8.18.0", + "zod": "^3.25 || ^4.0" + }, + "peerDependenciesMeta": { + "ws": { + "optional": true + }, + "zod": { + "optional": true + } + } + }, + "node_modules/p-retry": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-4.6.2.tgz", + "integrity": "sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==", + "license": "MIT", + "dependencies": { + "@types/retry": "0.12.0", + "retry": "^0.13.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pac-proxy-agent": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-7.2.0.tgz", + "integrity": "sha512-TEB8ESquiLMc0lV8vcd5Ql/JAKAoyzHFXaStwjkzpOpC5Yv+pIzLfHvjTSdf3vpa2bMiUQrg9i6276yn8666aA==", + "license": "MIT", + "dependencies": { + "@tootallnate/quickjs-emscripten": "^0.23.0", + "agent-base": "^7.1.2", + "debug": "^4.3.4", + "get-uri": "^6.0.1", + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.6", + "pac-resolver": "^7.0.1", + "socks-proxy-agent": "^8.0.5" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/pac-resolver": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/pac-resolver/-/pac-resolver-7.0.1.tgz", + "integrity": "sha512-5NPgf87AT2STgwa2ntRMr45jTKrYBGkVU36yT0ig/n/GMAa3oPqhZfIQ2kMEimReg0+t9kZViDVZ83qfVUlckg==", + "license": "MIT", + "dependencies": { + "degenerator": "^5.0.0", + "netmask": "^2.0.2" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/package-json-from-dist": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", + "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", + "dev": true, + "license": "BlueOak-1.0.0" + }, + "node_modules/parse5": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-5.1.1.tgz", + "integrity": "sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug==", + "license": "MIT" + }, + "node_modules/parse5-htmlparser2-tree-adapter": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-6.0.1.tgz", + "integrity": "sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA==", + "license": "MIT", + "dependencies": { + "parse5": "^6.0.1" + } + }, + "node_modules/parse5-htmlparser2-tree-adapter/node_modules/parse5": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", + "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", + "license": "MIT" + }, + "node_modules/partial-json": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/partial-json/-/partial-json-0.1.7.tgz", + "integrity": "sha512-Njv/59hHaokb/hRUjce3Hdv12wd60MtM9Z5Olmn+nehe0QDAsRtRbJPvJ0Z91TusF0SuZRIvnM+S4l6EIP8leA==", + "license": "MIT" + }, + "node_modules/path-expression-matcher": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/path-expression-matcher/-/path-expression-matcher-1.5.0.tgz", + "integrity": "sha512-cbrerZV+6rvdQrrD+iGMcZFEiiSrbv9Tfdkvnusy6y0x0GKBXREFg/Y65GhIfm0tnLntThhzCnfKwp1WRjeCyQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-scurry": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.2.tgz", + "integrity": "sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==", + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^11.0.0", + "minipass": "^7.1.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", + "dev": true, + "license": "MIT" + }, + "node_modules/pathval": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-2.0.1.tgz", + "integrity": "sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14.16" + } + }, + "node_modules/pend": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", + "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", + "license": "MIT" + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/postcss": { + "version": "8.5.13", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.13.tgz", + "integrity": "sha512-qif0+jGGZoLWdHey3UFHHWP0H7Gbmsk8T5VEqyYFbWqPr1XqvLGBbk/sl8V5exGmcYJklJOhOQq1pV9IcsiFag==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/prettier": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.5.3.tgz", + "integrity": "sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw==", + "dev": true, + "license": "MIT", + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/proper-lockfile": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/proper-lockfile/-/proper-lockfile-4.1.2.tgz", + "integrity": "sha512-TjNPblN4BwAWMXU8s9AEz4JmQxnD1NNL7bNOY/AKUzyamc379FWASUhc/K1pL2noVb+XmZKLL68cjzLsiOAMaA==", + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.4", + "retry": "^0.12.0", + "signal-exit": "^3.0.2" + } + }, + "node_modules/proper-lockfile/node_modules/retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==", + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/protobufjs": { + "version": "7.5.6", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.5.6.tgz", + "integrity": "sha512-M71sTMB146U3u0di3yup8iM+zv8yPRNQVr1KK4tyBitl3qFvEGucq/rGDRShD2rsJhtN02RJaJ7j5X5hmy8SJg==", + "hasInstallScript": true, + "license": "BSD-3-Clause", + "dependencies": { + "@protobufjs/aspromise": "^1.1.2", + "@protobufjs/base64": "^1.1.2", + "@protobufjs/codegen": "^2.0.5", + "@protobufjs/eventemitter": "^1.1.0", + "@protobufjs/fetch": "^1.1.0", + "@protobufjs/float": "^1.0.2", + "@protobufjs/inquire": "^1.1.1", + "@protobufjs/path": "^1.1.2", + "@protobufjs/pool": "^1.1.0", + "@protobufjs/utf8": "^1.1.1", + "@types/node": ">=13.7.0", + "long": "^5.0.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/proxy-agent": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-6.5.0.tgz", + "integrity": "sha512-TmatMXdr2KlRiA2CyDu8GqR8EjahTG3aY3nXjdzFyoZbmB8hrBsTyMezhULIXKnC0jpfjlmiZ3+EaCzoInSu/A==", + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "^4.3.4", + "http-proxy-agent": "^7.0.1", + "https-proxy-agent": "^7.0.6", + "lru-cache": "^7.14.1", + "pac-proxy-agent": "^7.1.0", + "proxy-from-env": "^1.1.0", + "socks-proxy-agent": "^8.0.5" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/proxy-agent/node_modules/lru-cache": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", + "license": "MIT" + }, + "node_modules/pump": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.4.tgz", + "integrity": "sha512-VS7sjc6KR7e1ukRFhQSY5LM2uBWAUPiOPa/A3mkKmiMwSmRFUITt0xuj+/lesgnCv+dPIEYlkzrcyXgquIHMcA==", + "license": "MIT", + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/retry": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", + "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/rollup": { + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.60.2.tgz", + "integrity": "sha512-J9qZyW++QK/09NyN/zeO0dG/1GdGfyp9lV8ajHnRVLfo/uFsbji5mHnDgn/qYdUHyCkM2N+8VyspgZclfAh0eQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.8" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.60.2", + "@rollup/rollup-android-arm64": "4.60.2", + "@rollup/rollup-darwin-arm64": "4.60.2", + "@rollup/rollup-darwin-x64": "4.60.2", + "@rollup/rollup-freebsd-arm64": "4.60.2", + "@rollup/rollup-freebsd-x64": "4.60.2", + "@rollup/rollup-linux-arm-gnueabihf": "4.60.2", + "@rollup/rollup-linux-arm-musleabihf": "4.60.2", + "@rollup/rollup-linux-arm64-gnu": "4.60.2", + "@rollup/rollup-linux-arm64-musl": "4.60.2", + "@rollup/rollup-linux-loong64-gnu": "4.60.2", + "@rollup/rollup-linux-loong64-musl": "4.60.2", + "@rollup/rollup-linux-ppc64-gnu": "4.60.2", + "@rollup/rollup-linux-ppc64-musl": "4.60.2", + "@rollup/rollup-linux-riscv64-gnu": "4.60.2", + "@rollup/rollup-linux-riscv64-musl": "4.60.2", + "@rollup/rollup-linux-s390x-gnu": "4.60.2", + "@rollup/rollup-linux-x64-gnu": "4.60.2", + "@rollup/rollup-linux-x64-musl": "4.60.2", + "@rollup/rollup-openbsd-x64": "4.60.2", + "@rollup/rollup-openharmony-arm64": "4.60.2", + "@rollup/rollup-win32-arm64-msvc": "4.60.2", + "@rollup/rollup-win32-ia32-msvc": "4.60.2", + "@rollup/rollup-win32-x64-gnu": "4.60.2", + "@rollup/rollup-win32-x64-msvc": "4.60.2", + "fsevents": "~2.3.2" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/semver": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/siginfo": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", + "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", + "dev": true, + "license": "ISC" + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "license": "ISC" + }, + "node_modules/smart-buffer": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", + "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", + "license": "MIT", + "engines": { + "node": ">= 6.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socks": { + "version": "2.8.8", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.8.tgz", + "integrity": "sha512-NlGELfPrgX2f1TAAcz0WawlLn+0r3FyhhCRpFFK2CemXenPYvzMWWZINv3eDNo9ucdwme7oCHRY0Jnbs4aIkog==", + "license": "MIT", + "dependencies": { + "ip-address": "^10.1.1", + "smart-buffer": "^4.2.0" + }, + "engines": { + "node": ">= 10.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socks-proxy-agent": { + "version": "8.0.5", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.5.tgz", + "integrity": "sha512-HehCEsotFqbPW9sJ8WVYB6UbmIMv7kUUORIF2Nncq4VQvBfNBLibW9YZR5dlYCSUhwcD628pRllm7n+E+YTzJw==", + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "^4.3.4", + "socks": "^2.8.3" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "license": "BSD-3-Clause", + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/stackback": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", + "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==", + "dev": true, + "license": "MIT" + }, + "node_modules/std-env": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.10.0.tgz", + "integrity": "sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==", + "license": "MIT" + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", + "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.2.2" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/strnum": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/strnum/-/strnum-2.2.3.tgz", + "integrity": "sha512-oKx6RUCuHfT3oyVjtnrmn19H1SiCqgJSg+54XqURKp5aCMbrXrhLjRN9TjuwMjiYstZ0MzDrHqkGZ5dFTKd+zg==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "license": "MIT" + }, + "node_modules/strtok3": { + "version": "10.3.5", + "resolved": "https://registry.npmjs.org/strtok3/-/strtok3-10.3.5.tgz", + "integrity": "sha512-ki4hZQfh5rX0QDLLkOCj+h+CVNkqmp/CMf8v8kZpkNVK6jGQooMytqzLZYUVYIZcFZ6yDB70EfD8POcFXiF5oA==", + "license": "MIT", + "dependencies": { + "@tokenizer/token": "^0.3.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Borewit" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/test-exclude": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-7.0.2.tgz", + "integrity": "sha512-u9E6A+ZDYdp7a4WnarkXPZOx8Ilz46+kby6p1yZ8zsGTz9gYa6FIS7lj2oezzNKmtdyyJNNmmXDppga5GB7kSw==", + "dev": true, + "license": "ISC", + "dependencies": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^10.4.1", + "minimatch": "^10.2.2" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/test-exclude/node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/test-exclude/node_modules/brace-expansion": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.0.tgz", + "integrity": "sha512-TN1kCZAgdgweJhWWpgKYrQaMNHcDULHkWwQIspdtjV4Y5aurRdZpjAqn6yX3FPqTA9ngHCc4hJxMAMgGfve85w==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/test-exclude/node_modules/glob": { + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz", + "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", + "dev": true, + "license": "ISC", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/test-exclude/node_modules/glob/node_modules/minimatch": { + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", + "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.2" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/test-exclude/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/test-exclude/node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/thenify": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", + "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", + "license": "MIT", + "dependencies": { + "any-promise": "^1.0.0" + } + }, + "node_modules/thenify-all": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", + "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", + "license": "MIT", + "dependencies": { + "thenify": ">= 3.1.0 < 4" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/tinybench": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", + "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==", + "dev": true, + "license": "MIT" + }, + "node_modules/tinyexec": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-0.3.2.tgz", + "integrity": "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==", + "dev": true, + "license": "MIT" + }, + "node_modules/tinyglobby": { + "version": "0.2.16", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.16.tgz", + "integrity": "sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.4" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tinypool": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-1.1.1.tgz", + "integrity": "sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.0.0 || >=20.0.0" + } + }, + "node_modules/tinyrainbow": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-2.0.0.tgz", + "integrity": "sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/tinyspy": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-3.0.2.tgz", + "integrity": "sha512-n1cw8k1k0x4pgA2+9XrOkFydTerNcJ1zWCO5Nn9scWHTD+5tp8dghT2x1uduQePZTZgd3Tupf+x9BxJjeJi77Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/token-types": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/token-types/-/token-types-6.1.2.tgz", + "integrity": "sha512-dRXchy+C0IgK8WPC6xvCHFRIWYUbqqdEIKPaKo/AcTUNzwLTK6AH7RjdLWsEZcAN/TBdtfUw3PYEgPr5VPr6ww==", + "license": "MIT", + "dependencies": { + "@borewit/text-codec": "^0.2.1", + "@tokenizer/token": "^0.3.0", + "ieee754": "^1.2.1" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Borewit" + } + }, + "node_modules/ts-algebra": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ts-algebra/-/ts-algebra-2.0.0.tgz", + "integrity": "sha512-FPAhNPFMrkwz76P7cdjdmiShwMynZYN6SgOujD1urY4oNm80Ou9oMdmbR45LotcKOXoy7wSmHkRFE6Mxbrhefw==", + "license": "MIT" + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" + }, + "node_modules/typebox": { + "version": "1.1.37", + "resolved": "https://registry.npmjs.org/typebox/-/typebox-1.1.37.tgz", + "integrity": "sha512-jb7jp6KvOvvy5sd+11AfJ0/e0F0AS9RcOXd55oGi2ZnRHIGmFvrTaNF+ZidRmGBmmNTkM5KKl0Z37KzxJ+owEQ==", + "license": "MIT" + }, + "node_modules/typescript": { + "version": "5.8.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz", + "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/uint8array-extras": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/uint8array-extras/-/uint8array-extras-1.5.0.tgz", + "integrity": "sha512-rvKSBiC5zqCCiDZ9kAOszZcDvdAHwwIKJG33Ykj43OKcWsnmcBRL09YTU4nOeHZ8Y2a7l1MgTd08SBe9A8Qj6A==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/undici": { + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-7.25.0.tgz", + "integrity": "sha512-xXnp4kTyor2Zq+J1FfPI6Eq3ew5h6Vl0F/8d9XU5zZQf1tX9s2Su1/3PiMmUANFULpmksxkClamIZcaUqryHsQ==", + "license": "MIT", + "engines": { + "node": ">=20.18.1" + } + }, + "node_modules/undici-types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "license": "MIT" + }, + "node_modules/uuid": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-14.0.0.tgz", + "integrity": "sha512-Qo+uWgilfSmAhXCMav1uYFynlQO7fMFiMVZsQqZRMIXp0O7rR7qjkj+cPvBHLgBqi960QCoo/PH2/6ZtVqKvrg==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "license": "MIT", + "bin": { + "uuid": "dist-node/bin/uuid" + } + }, + "node_modules/vite": { + "version": "6.4.2", + "resolved": "https://registry.npmjs.org/vite/-/vite-6.4.2.tgz", + "integrity": "sha512-2N/55r4JDJ4gdrCvGgINMy+HH3iRpNIz8K6SFwVsA+JbQScLiC+clmAxBgwiSPgcG9U15QmvqCGWzMbqda5zGQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "^0.25.0", + "fdir": "^6.4.4", + "picomatch": "^4.0.2", + "postcss": "^8.5.3", + "rollup": "^4.34.9", + "tinyglobby": "^0.2.13" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^18.0.0 || ^20.0.0 || >=22.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", + "jiti": ">=1.21.0", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "sass-embedded": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/vite-node": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-3.1.3.tgz", + "integrity": "sha512-uHV4plJ2IxCl4u1up1FQRrqclylKAogbtBfOTwcuJ28xFi+89PZ57BRh+naIRvH70HPwxy5QHYzg1OrEaC7AbA==", + "dev": true, + "license": "MIT", + "dependencies": { + "cac": "^6.7.14", + "debug": "^4.4.0", + "es-module-lexer": "^1.7.0", + "pathe": "^2.0.3", + "vite": "^5.0.0 || ^6.0.0" + }, + "bin": { + "vite-node": "vite-node.mjs" + }, + "engines": { + "node": "^18.0.0 || ^20.0.0 || >=22.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/vitest": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-3.1.3.tgz", + "integrity": "sha512-188iM4hAHQ0km23TN/adso1q5hhwKqUpv+Sd6p5sOuh6FhQnRNW3IsiIpvxqahtBabsJ2SLZgmGSpcYK4wQYJw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/expect": "3.1.3", + "@vitest/mocker": "3.1.3", + "@vitest/pretty-format": "^3.1.3", + "@vitest/runner": "3.1.3", + "@vitest/snapshot": "3.1.3", + "@vitest/spy": "3.1.3", + "@vitest/utils": "3.1.3", + "chai": "^5.2.0", + "debug": "^4.4.0", + "expect-type": "^1.2.1", + "magic-string": "^0.30.17", + "pathe": "^2.0.3", + "std-env": "^3.9.0", + "tinybench": "^2.9.0", + "tinyexec": "^0.3.2", + "tinyglobby": "^0.2.13", + "tinypool": "^1.0.2", + "tinyrainbow": "^2.0.0", + "vite": "^5.0.0 || ^6.0.0", + "vite-node": "3.1.3", + "why-is-node-running": "^2.3.0" + }, + "bin": { + "vitest": "vitest.mjs" + }, + "engines": { + "node": "^18.0.0 || ^20.0.0 || >=22.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "@edge-runtime/vm": "*", + "@types/debug": "^4.1.12", + "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", + "@vitest/browser": "3.1.3", + "@vitest/ui": "3.1.3", + "happy-dom": "*", + "jsdom": "*" + }, + "peerDependenciesMeta": { + "@edge-runtime/vm": { + "optional": true + }, + "@types/debug": { + "optional": true + }, + "@types/node": { + "optional": true + }, + "@vitest/browser": { + "optional": true + }, + "@vitest/ui": { + "optional": true + }, + "happy-dom": { + "optional": true + }, + "jsdom": { + "optional": true + } + } + }, + "node_modules/web-streams-polyfill": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz", + "integrity": "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==", + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/why-is-node-running": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz", + "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==", + "dev": true, + "license": "MIT", + "dependencies": { + "siginfo": "^2.0.0", + "stackback": "0.0.2" + }, + "bin": { + "why-is-node-running": "cli.js" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "license": "ISC" + }, + "node_modules/ws": { + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.20.0.tgz", + "integrity": "sha512-sAt8BhgNbzCtgGbt2OxmpuryO63ZoDk/sqaB/znQm94T4fCEsy/yV+7CdC1kJhOU9lboAEU7R3kquuycDoibVA==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/yaml": { + "version": "2.8.4", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.4.tgz", + "integrity": "sha512-ml/JPOj9fOQK8RNnWojA67GbZ0ApXAUlN2UQclwv2eVgTgn7O9gg9o7paZWKMp4g0H3nTLtS9LVzhkpOFIKzog==", + "license": "ISC", + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14.6" + }, + "funding": { + "url": "https://github.com/sponsors/eemeli" + } + }, + "node_modules/yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "license": "MIT", + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs-parser": { + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/yauzl": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", + "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", + "license": "MIT", + "dependencies": { + "buffer-crc32": "~0.2.3", + "fd-slicer": "~1.1.0" + } + }, + "node_modules/yoctocolors": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yoctocolors/-/yoctocolors-2.1.2.tgz", + "integrity": "sha512-CzhO+pFNo8ajLM2d2IW/R93ipy99LWjtwblvC1RsoSUMZgyLbYFr221TnSNT7GjGdYui6P459mw9JH/g/zW2ug==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/zod": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/zod/-/zod-4.4.2.tgz", + "integrity": "sha512-IynmDyxsEsb9RKzO3J9+4SxXnl2FTFSzNBaKKaMV6tsSk0rw9gYw9gs+JFCq/qk2LCZ78KDwyj+Z289TijSkUw==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, + "node_modules/zod-to-json-schema": { + "version": "3.25.2", + "resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.25.2.tgz", + "integrity": "sha512-O/PgfnpT1xKSDeQYSCfRI5Gy3hPf91mKVDuYLUHZJMiDFptvP41MSnWofm8dnCm0256ZNfZIM7DSzuSMAFnjHA==", + "license": "ISC", + "peerDependencies": { + "zod": "^3.25.28 || ^4" + } + } + } +} diff --git a/aw-harness/package.json b/aw-harness/package.json new file mode 100644 index 00000000000..13a77ba9c97 --- /dev/null +++ b/aw-harness/package.json @@ -0,0 +1,26 @@ +{ + "name": "@github/aw-harness", + "version": "0.1.0", + "private": true, + "description": "EXPERIMENTAL: Pi SDK-based execution engine for engine: aw workflows", + "type": "module", + "scripts": { + "typecheck": "tsc --noEmit", + "test": "npm run typecheck && vitest run", + "test:watch": "vitest", + "test:coverage": "vitest run --coverage", + "build": "node --experimental-strip-types build.ts", + "lint": "prettier --check 'src/**/*.ts' 'test/**/*.ts'" + }, + "dependencies": { + "@mariozechner/pi-coding-agent": "0.72.1" + }, + "devDependencies": { + "@types/node": "22.15.3", + "@vitest/coverage-v8": "3.1.3", + "esbuild": "0.25.4", + "prettier": "3.5.3", + "typescript": "5.8.3", + "vitest": "3.1.3" + } +} diff --git a/aw-harness/src/context.ts b/aw-harness/src/context.ts new file mode 100644 index 00000000000..448834018e6 --- /dev/null +++ b/aw-harness/src/context.ts @@ -0,0 +1,47 @@ +/** + * Prompt assembly with imports. + * + * Prepends resolved import file contents (from imports: frontmatter key) to the + * prompt body text. The assembled string is passed as the single user prompt to + * the Pi AgentSession. + * + * Per spec §6.4: every item in the session prompt MUST come from an explicitly + * declared origin. No ambient files (AGENTS.md, skills directories, etc.) are + * auto-loaded. Skills must be listed individually under imports:. + */ + +import type { ImportEntry } from "./types.js"; + +// ─── assemblePrompt ────────────────────────────────────────────────────────── + +/** + * Assemble the final prompt string from imports and the prompt body. + * + * Import contents are prepended in declaration order, each wrapped in a + * fenced block with the source path as a header, so the agent can identify + * which resource each block came from. + * + * @param imports - Resolved import entries (may be empty) + * @param promptBody - Raw prompt body from prompt.txt + * @returns Assembled prompt string + */ +export function assemblePrompt(imports: ImportEntry[], promptBody: string): string { + if (imports.length === 0) { + return promptBody; + } + + const sections: string[] = []; + + for (const entry of imports) { + sections.push( + [ + ``, + entry.content.trimEnd(), + ``, + ].join("\n"), + ); + } + + sections.push(promptBody); + return sections.join("\n\n"); +} diff --git a/aw-harness/src/extensions/cost-tracker.ts b/aw-harness/src/extensions/cost-tracker.ts new file mode 100644 index 00000000000..c4401ce2a77 --- /dev/null +++ b/aw-harness/src/extensions/cost-tracker.ts @@ -0,0 +1,97 @@ +/** + * Extension 2: Cost Tracker + * + * Monitors token usage via Pi's turn_end events and enforces budget gates. + * + * - When tokens reach budget-warn-percent, injects a steering message. + * - When tokens reach budget-critical-percent, injects a critical message + * and sets sharedState.budgetAborted so the main entry point can exit(1). + * + * Token counts are read from the AssistantMessage usage field in the + * TurnEndEvent.message when available, falling back to context usage percent. + * + * Per spec §8.2. + */ + +import type { ExtensionFactory } from "@mariozechner/pi-coding-agent"; +import type { BudgetConfig, SharedHarnessState, SteeringConfig } from "../types.js"; + +// ─── createCostTrackerExtension ────────────────────────────────────────────── + +/** + * Create the cost-tracker Pi extension factory. + * + * @param budget - Budget configuration (undefined = no limit) + * @param steering - Steering thresholds (percent values) + * @param sharedState - Mutable runtime state shared with the entry point + */ +export function createCostTrackerExtension( + budget: BudgetConfig | undefined, + steering: SteeringConfig, + sharedState: SharedHarnessState, +): ExtensionFactory { + return (pi) => { + // Track whether we have already sent warn/critical messages to avoid spam + let warnSent = false; + let criticalSent = false; + + pi.on("turn_end", (event, ctx) => { + sharedState.turnCount++; + + // Extract token usage from the assistant message if available + const msg = event.message as { + role?: string; + usage?: { input?: number; output?: number; totalTokens?: number; cost?: { total?: number } }; + }; + + if (msg.role === "assistant" && msg.usage) { + const turnTokens = msg.usage.totalTokens ?? (msg.usage.input ?? 0) + (msg.usage.output ?? 0); + const turnCost = msg.usage.cost?.total ?? 0; + sharedState.cumulativeTokens += turnTokens; + sharedState.cumulativeCostUsd += turnCost; + } else { + // Fallback: use context window percentage as a proxy for token usage + const ctxUsage = ctx.getContextUsage(); + if (ctxUsage?.tokens != null) { + sharedState.cumulativeTokens = ctxUsage.tokens; + } + } + + if (!budget) { + return; // No budget configured — nothing to gate + } + + const { maxEffectiveTokens } = budget; + const pct = (sharedState.cumulativeTokens / maxEffectiveTokens) * 100; + + if (!criticalSent && pct >= steering.budgetCriticalPercent) { + criticalSent = true; + sharedState.budgetAborted = true; + process.stderr.write( + `[aw-harness] 🚨 Budget critical: ${pct.toFixed(1)}% used ` + + `(${sharedState.cumulativeTokens}/${maxEffectiveTokens} tokens). Aborting.\n`, + ); + pi.sendUserMessage( + `🚨 CRITICAL: Token budget exhausted (${pct.toFixed(0)}% used). ` + + `You have ${maxEffectiveTokens - sharedState.cumulativeTokens} tokens remaining. ` + + `Produce your final output NOW and stop immediately.`, + { deliverAs: "steer" }, + ); + return; + } + + if (!warnSent && pct >= steering.budgetWarnPercent) { + warnSent = true; + process.stderr.write( + `[aw-harness] ⚠️ Budget warning: ${pct.toFixed(1)}% used ` + + `(${sharedState.cumulativeTokens}/${maxEffectiveTokens} tokens).\n`, + ); + pi.sendUserMessage( + `⚠️ Token budget: ${pct.toFixed(0)}% used (${sharedState.cumulativeTokens}/${maxEffectiveTokens}). ` + + `Be concise and wrap up soon.`, + { deliverAs: "steer" }, + ); + } + }); + }; +} diff --git a/aw-harness/src/extensions/observability.ts b/aw-harness/src/extensions/observability.ts new file mode 100644 index 00000000000..0fd2b65386c --- /dev/null +++ b/aw-harness/src/extensions/observability.ts @@ -0,0 +1,272 @@ +/** + * Extension 5: Observability + * + * Emits structured JSONL event stream to stderr, writes a context provenance + * file, renders a GitHub Actions step summary, and reports per-turn token + * consumption. + * + * Per spec §8.5. + */ + +import { appendFileSync, mkdirSync, writeFileSync } from "node:fs"; +import { dirname } from "node:path"; +import type { ExtensionFactory } from "@mariozechner/pi-coding-agent"; +import type { ImportEntry, ObservabilityConfig, SharedHarnessState } from "../types.js"; + +// ─── Constants ─────────────────────────────────────────────────────────────── + +/** Default path for the context provenance JSONL file. */ +export const CONTEXT_PROVENANCE_PATH = "/tmp/gh-aw/context-provenance.jsonl"; + +// ─── ProvenanceEntry ───────────────────────────────────────────────────────── + +interface ProvenanceEntry { + timestamp: string; + source: "prompt" | "import"; + path?: string; + tokens: number; + cumulativeTokens: number; + role: "user"; +} + +// ─── TurnRecord ────────────────────────────────────────────────────────────── + +interface TurnRecord { + turn: number; + inputTokens: number; + outputTokens: number; + cumulativeTokens: number; + estimatedCostUsd: number; +} + +// ─── emitJsonl ─────────────────────────────────────────────────────────────── + +function emitJsonl(record: Record): void { + process.stderr.write(JSON.stringify(record) + "\n"); +} + +// ─── estimateTokens ────────────────────────────────────────────────────────── + +/** Rough token estimate: ~4 chars per token. */ +function estimateTokens(text: string): number { + return Math.ceil(text.length / 4); +} + +// ─── createObservabilityExtension ──────────────────────────────────────────── + +/** + * Create the observability Pi extension factory. + * + * @param imports - Resolved import entries for context provenance tracking + * @param observabilityConfig - Optional OTLP configuration + * @param sharedState - Mutable runtime state shared with the entry point + * @param promptBody - Raw prompt body text (for token estimation) + */ +export function createObservabilityExtension( + imports: ImportEntry[], + observabilityConfig: ObservabilityConfig | undefined, + sharedState: SharedHarnessState, + promptBody: string, +): ExtensionFactory { + return (pi) => { + const provenanceLog: ProvenanceEntry[] = []; + const turnRecords: TurnRecord[] = []; + let cumulativeProvenanceTokens = 0; + + // ── agent_start ────────────────────────────────────────────────────────── + pi.on("agent_start", () => { + const model = sharedState.model; + emitJsonl({ event: "session_start", model, ts: new Date().toISOString() }); + + if (observabilityConfig?.otlp?.endpoint) { + process.stderr.write( + `[aw-harness] ℹ OTel tracing to ${observabilityConfig.otlp.endpoint}\n`, + ); + // OTel span creation would go here when an OTLP client is wired in + } + + // Record context provenance for imports + for (const entry of imports) { + const tokens = estimateTokens(entry.content); + cumulativeProvenanceTokens += tokens; + const record: ProvenanceEntry = { + timestamp: new Date().toISOString(), + source: "import", + path: entry.path, + tokens, + cumulativeTokens: cumulativeProvenanceTokens, + role: "user", + }; + provenanceLog.push(record); + } + + // Record context provenance for the prompt body + const promptTokens = estimateTokens(promptBody); + cumulativeProvenanceTokens += promptTokens; + provenanceLog.push({ + timestamp: new Date().toISOString(), + source: "prompt", + tokens: promptTokens, + cumulativeTokens: cumulativeProvenanceTokens, + role: "user", + }); + }); + + // ── model_select ───────────────────────────────────────────────────────── + pi.on("model_select", (event) => { + const modelId = (event as { model?: { id?: string } }).model?.id; + if (modelId) { + sharedState.model = modelId; + } + }); + + // ── turn_end ───────────────────────────────────────────────────────────── + pi.on("turn_end", (event) => { + const msg = event.message as { + role?: string; + usage?: { input?: number; output?: number; totalTokens?: number; cost?: { total?: number } }; + }; + + let inputTokens = 0; + let outputTokens = 0; + let turnCostUsd = 0; + + if (msg.role === "assistant" && msg.usage) { + inputTokens = msg.usage.input ?? 0; + outputTokens = msg.usage.output ?? 0; + turnCostUsd = msg.usage.cost?.total ?? 0; + } + + const turnRecord: TurnRecord = { + turn: sharedState.turnCount, + inputTokens, + outputTokens, + cumulativeTokens: sharedState.cumulativeTokens, + estimatedCostUsd: sharedState.cumulativeCostUsd, + }; + turnRecords.push(turnRecord); + + // Structured JSONL event + emitJsonl({ + event: "turn_end", + turn: sharedState.turnCount, + input_tokens: inputTokens, + output_tokens: outputTokens, + cumulative_tokens: sharedState.cumulativeTokens, + cumulative_cost_usd: sharedState.cumulativeCostUsd, + model: sharedState.model, + ts: new Date().toISOString(), + }); + + // Human-readable per-turn line (markdown blockquote format per spec §8.5.4) + process.stderr.write( + `> **Turn ${sharedState.turnCount}**: ${inputTokens.toLocaleString()} in / ` + + `${outputTokens.toLocaleString()} out` + + ` | cumulative ${sharedState.cumulativeTokens.toLocaleString()} tokens` + + ` ($${sharedState.cumulativeCostUsd.toFixed(4)})\n`, + ); + + void turnCostUsd; // used indirectly via sharedState + }); + + // ── tool_execution_end ─────────────────────────────────────────────────── + pi.on("tool_execution_end", (event) => { + const e = event as { toolName?: string; duration?: number }; + emitJsonl({ + event: "tool_end", + tool: e.toolName ?? "unknown", + duration_ms: e.duration, + ts: new Date().toISOString(), + }); + }); + + // ── agent_end ──────────────────────────────────────────────────────────── + pi.on("agent_end", () => { + const elapsedMs = sharedState.sessionStartMs > 0 ? Date.now() - sharedState.sessionStartMs : 0; + + emitJsonl({ + event: "session_end", + tokens: sharedState.cumulativeTokens, + cost_usd: sharedState.cumulativeCostUsd, + elapsed_ms: elapsedMs, + ts: new Date().toISOString(), + }); + + // Write context provenance file + writeProvenanceFile(provenanceLog); + + // Write GitHub Actions step summary + const stepSummaryPath = process.env["GITHUB_STEP_SUMMARY"]; + if (stepSummaryPath) { + writeStepSummary(stepSummaryPath, sharedState, turnRecords, provenanceLog, elapsedMs); + } + }); + }; +} + +// ─── writeProvenanceFile ───────────────────────────────────────────────────── + +function writeProvenanceFile(log: ProvenanceEntry[]): void { + try { + mkdirSync(dirname(CONTEXT_PROVENANCE_PATH), { recursive: true }); + const lines = log.map((e) => JSON.stringify(e)).join("\n") + (log.length > 0 ? "\n" : ""); + writeFileSync(CONTEXT_PROVENANCE_PATH, lines, "utf8"); + } catch (err) { + process.stderr.write( + `[aw-harness] ⚠️ Failed to write context provenance: ${(err as Error).message}\n`, + ); + } +} + +// ─── writeStepSummary ──────────────────────────────────────────────────────── + +function writeStepSummary( + path: string, + state: SharedHarnessState, + turns: TurnRecord[], + provenance: ProvenanceEntry[], + elapsedMs: number, +): void { + try { + const elapsedSec = (elapsedMs / 1000).toFixed(1); + const lines: string[] = [ + `## AW Harness Run — \`${state.model}\``, + "", + "> ⚠️ **EXPERIMENTAL** — engine: aw is experimental and subject to change.", + "", + "### Token Consumption", + "", + "| Turn | Input Tokens | Output Tokens | Cumulative | Est. Cost |", + "|------|-------------|---------------|------------|-----------|", + ]; + + for (const t of turns) { + lines.push( + `| ${t.turn} | ${t.inputTokens.toLocaleString()} | ${t.outputTokens.toLocaleString()} | ${t.cumulativeTokens.toLocaleString()} | $${t.estimatedCostUsd.toFixed(4)} |`, + ); + } + + lines.push( + `| **Total** | | | **${state.cumulativeTokens.toLocaleString()}** | **$${state.cumulativeCostUsd.toFixed(4)}** |`, + "", + `**Elapsed:** ${elapsedSec}s`, + "", + "### Context Provenance", + "", + "| Source | Path | Tokens |", + "|--------|------|--------|", + ); + + for (const p of provenance) { + const src = p.source === "import" ? "import" : "prompt"; + const pathCol = p.path ? p.path : "_(prompt.txt)_"; + lines.push(`| ${src} | ${pathCol} | ${p.tokens.toLocaleString()} |`); + } + + appendFileSync(path, lines.join("\n") + "\n", "utf8"); + } catch (err) { + process.stderr.write( + `[aw-harness] ⚠️ Failed to write step summary: ${(err as Error).message}\n`, + ); + } +} diff --git a/aw-harness/src/extensions/provider-setup.ts b/aw-harness/src/extensions/provider-setup.ts new file mode 100644 index 00000000000..7e7005c72f6 --- /dev/null +++ b/aw-harness/src/extensions/provider-setup.ts @@ -0,0 +1,76 @@ +/** + * Extension 1: Provider Setup + * + * Registers LLM providers with Pi SDK using credentials injected by AWF into + * the container environment. The harness MUST NOT hard-code any provider URL + * or API key; all credentials MUST come from environment variables. + * + * Per spec §8.1. + */ + +import type { ExtensionFactory } from "@mariozechner/pi-coding-agent"; + +// ─── Supported providers ───────────────────────────────────────────────────── + +interface ProviderSpec { + envKey: string; + baseUrlEnv?: string; + api: "anthropic-messages" | "openai-completions" | "openai-responses"; +} + +const PROVIDERS: Record = { + anthropic: { + envKey: "ANTHROPIC_API_KEY", + baseUrlEnv: "ANTHROPIC_BASE_URL", + api: "anthropic-messages", + }, + openai: { + envKey: "OPENAI_API_KEY", + baseUrlEnv: "OPENAI_BASE_URL", + api: "openai-completions", + }, + // GitHub Copilot uses GITHUB_TOKEN for model routing via the Copilot API + copilot: { + envKey: "GITHUB_TOKEN", + baseUrlEnv: "COPILOT_BASE_URL", + api: "openai-completions", + }, +}; + +// ─── providerSetupExtension ────────────────────────────────────────────────── + +/** + * Pi extension factory: register available LLM providers from environment variables. + */ +export const providerSetupExtension: ExtensionFactory = (pi) => { + let registered = 0; + + for (const [name, spec] of Object.entries(PROVIDERS)) { + const apiKey = process.env[spec.envKey]; + if (!apiKey) { + continue; + } + + const baseUrl = spec.baseUrlEnv ? process.env[spec.baseUrlEnv] : undefined; + + pi.registerProvider(name, { + apiKey, + api: spec.api, + ...(baseUrl ? { baseUrl } : {}), + }); + + registered++; + process.stderr.write( + `[aw-harness] ✓ Registered provider '${name}'` + + (baseUrl ? ` (base URL: ${baseUrl})` : "") + + "\n", + ); + } + + if (registered === 0) { + throw new Error( + "[aw-harness] No LLM provider credentials found in environment. " + + "Set ANTHROPIC_API_KEY, OPENAI_API_KEY, or GITHUB_TOKEN before running.", + ); + } +}; diff --git a/aw-harness/src/extensions/repair.ts b/aw-harness/src/extensions/repair.ts new file mode 100644 index 00000000000..6f2e4075e54 --- /dev/null +++ b/aw-harness/src/extensions/repair.ts @@ -0,0 +1,104 @@ +/** + * Extension 4: Session Repair + * + * Detects broken tool calls and repairs the session by emitting a follow-up + * message summarising progress so the agent can continue from where it left off. + * + * Currently implements the agent_end recovery path: if the session ends with a + * recoverable error, inject a follow-up message so Pi can resume. + * + * Per spec §8.4. + */ + +import type { ExtensionFactory } from "@mariozechner/pi-coding-agent"; + +// ─── Recoverable error patterns ────────────────────────────────────────────── + +/** Patterns that indicate a transient / recoverable error. */ +const RECOVERABLE_PATTERNS: RegExp[] = [ + /rate.?limit/i, + /overloaded/i, + /timeout/i, + /network/i, + /ECONNRESET/, + /ETIMEDOUT/, +]; + +/** Patterns that indicate a corrupted tool result payload. */ +const CORRUPTED_TOOL_PATTERNS: RegExp[] = [ + /null.*tool_call/i, + /invalid type.*tool_calls/i, + /tool_calls\[\d+\]\.type.*null/, +]; + +// ─── Helpers ───────────────────────────────────────────────────────────────── + +function isRecoverableError(error: Error): boolean { + return RECOVERABLE_PATTERNS.some((p) => p.test(error.message)); +} + +function isCorruptedToolContent(content: unknown): boolean { + const str = typeof content === "string" ? content : JSON.stringify(content ?? ""); + return CORRUPTED_TOOL_PATTERNS.some((p) => p.test(str)); +} + +// ─── createRepairExtension ─────────────────────────────────────────────────── + +/** + * Create the repair Pi extension factory. + */ +export function createRepairExtension(): ExtensionFactory { + return (pi) => { + // Detect corrupted tool results and log them for diagnostic purposes + pi.on("tool_result", (event) => { + const content = (event as { content?: unknown }).content; + if (isCorruptedToolContent(content)) { + process.stderr.write( + `[aw-harness] ⚠️ Corrupted tool result detected for tool '` + + `${(event as { toolName?: string }).toolName ?? "unknown"}'. ` + + `The agent may produce degraded output for this turn.\n`, + ); + // Emit a JSONL repair event for observability + const record = { + event: "repair", + action: "corrupted_tool_result_detected", + toolName: (event as { toolName?: string }).toolName ?? "unknown", + ts: new Date().toISOString(), + }; + process.stderr.write(JSON.stringify(record) + "\n"); + } + }); + + // On agent_end with a recoverable error, inject a follow-up so the agent can resume + pi.on("agent_end", (event, _ctx) => { + const endEvent = event as { error?: Error }; + if (!endEvent.error) { + return; + } + + if (isRecoverableError(endEvent.error)) { + process.stderr.write( + `[aw-harness] ⚠️ Recoverable error on agent_end: ${endEvent.error.message}. ` + + `Injecting follow-up for continuation.\n`, + ); + const record = { + event: "repair", + action: "follow_up_after_recoverable_error", + error: endEvent.error.message, + ts: new Date().toISOString(), + }; + process.stderr.write(JSON.stringify(record) + "\n"); + + pi.sendUserMessage( + `The previous turn ended with a transient error: "${endEvent.error.message}". ` + + `Please review your progress so far and continue from where you left off.`, + { deliverAs: "followUp" }, + ); + } else { + process.stderr.write( + `[aw-harness] ✗ Non-recoverable error on agent_end: ${endEvent.error.message}\n`, + ); + } + }); + }; +} diff --git a/aw-harness/src/extensions/steering.ts b/aw-harness/src/extensions/steering.ts new file mode 100644 index 00000000000..48578f8fed6 --- /dev/null +++ b/aw-harness/src/extensions/steering.ts @@ -0,0 +1,69 @@ +/** + * Extension 3: Steering (Resource Pressure) + * + * Monitors elapsed time and injects user steering messages via Pi's sendUserMessage + * when the session is approaching the workflow timeout. + * + * Per spec §8.3. + */ + +import type { ExtensionFactory } from "@mariozechner/pi-coding-agent"; +import type { SharedHarnessState, SteeringConfig } from "../types.js"; + +// ─── createSteeringExtension ───────────────────────────────────────────────── + +/** + * Create the steering Pi extension factory. + * + * @param timeoutMinutes - Total workflow timeout in minutes + * @param steering - Steering thresholds (time-warning and time-critical minutes) + * @param sharedState - Mutable runtime state shared with the entry point + */ +export function createSteeringExtension( + timeoutMinutes: number, + steering: SteeringConfig, + sharedState: SharedHarnessState, +): ExtensionFactory { + return (pi) => { + let timeWarnSent = false; + let timeCriticalSent = false; + + pi.on("agent_start", () => { + sharedState.sessionStartMs = Date.now(); + }); + + pi.on("turn_end", (_event, _ctx) => { + if (sharedState.sessionStartMs === 0) { + return; + } + + const elapsedMs = Date.now() - sharedState.sessionStartMs; + const elapsedMinutes = elapsedMs / 60_000; + const remainingMinutes = timeoutMinutes - elapsedMinutes; + + if (!timeCriticalSent && remainingMinutes <= steering.timeCriticalMinutes) { + timeCriticalSent = true; + process.stderr.write( + `[aw-harness] 🚨 Time critical: ${remainingMinutes.toFixed(1)} min remaining of ${timeoutMinutes}.\n`, + ); + pi.sendUserMessage( + `🚨 CRITICAL: Only ${remainingMinutes.toFixed(0)} minute(s) remaining before timeout. ` + + `Write your final output NOW and stop.`, + { deliverAs: "steer" }, + ); + return; + } + + if (!timeWarnSent && remainingMinutes <= steering.timeWarningMinutes) { + timeWarnSent = true; + process.stderr.write( + `[aw-harness] ⚠️ Time warning: ${remainingMinutes.toFixed(1)} min remaining of ${timeoutMinutes}.\n`, + ); + pi.sendUserMessage( + `⚠️ ${remainingMinutes.toFixed(0)} minute(s) remaining. Begin wrapping up your task.`, + { deliverAs: "steer" }, + ); + } + }); + }; +} diff --git a/aw-harness/src/index.ts b/aw-harness/src/index.ts new file mode 100644 index 00000000000..7769b2f1687 --- /dev/null +++ b/aw-harness/src/index.ts @@ -0,0 +1,161 @@ +/** + * ⚠️ EXPERIMENTAL — AW Harness Entry Point + * + * This file is the entry point for the `engine: aw` execution engine. + * It is EXPERIMENTAL and subject to breaking changes without notice. + * Do not use in production workflows without understanding the risks. + * + * See specs/aw-harness.md for the full specification. + * + * Usage: + * node aw_harness.cjs --config --prompt + * + * Exit codes: + * 0 — Prompt completed successfully + * 1 — Session failed or budget exceeded + * 2 — Invocation error (missing arguments, unreadable files) + */ + +import { + createAgentSession, + DefaultResourceLoader, + SessionManager, + getAgentDir, +} from "@mariozechner/pi-coding-agent"; + +import { assemblePrompt } from "./context.js"; +import { loadInputs, parseArgs } from "./loader.js"; +import { createSharedState } from "./types.js"; +import { loadUserExtensions } from "./user-extensions.js"; +import { createCostTrackerExtension } from "./extensions/cost-tracker.js"; +import { createObservabilityExtension } from "./extensions/observability.js"; +import { providerSetupExtension } from "./extensions/provider-setup.js"; +import { createRepairExtension } from "./extensions/repair.js"; +import { createSteeringExtension } from "./extensions/steering.js"; + +// ─── main ──────────────────────────────────────────────────────────────────── + +async function main(): Promise { + // Emit experimental warning on every invocation + process.stderr.write( + "[aw-harness] ⚠️ EXPERIMENTAL: engine: aw is experimental and subject to breaking changes.\n", + ); + + // ── Parse CLI arguments ── + let configPath: string; + let promptPath: string; + try { + ({ configPath, promptPath } = parseArgs(process.argv.slice(2))); + } catch (err) { + process.stderr.write(`[aw-harness] ✗ ${(err as Error).message}\n`); + process.exit(2); + } + + // ── Load config.json + prompt.txt ── + let config: Awaited>["config"]; + let promptBody: string; + try { + ({ config, promptBody } = loadInputs(configPath, promptPath)); + } catch (err) { + process.stderr.write(`[aw-harness] ✗ ${(err as Error).message}\n`); + process.exit(2); + } + + process.stderr.write( + `[aw-harness] ✓ Loaded config (model: ${config.model}, timeout: ${config.timeoutMinutes}min)\n`, + ); + + // ── Assemble prompt (imports prepended to prompt body) ── + const prompt = assemblePrompt(config.imports ?? [], promptBody); + + // ── Create shared runtime state ── + const sharedState = createSharedState(config.model); + + // ── Build built-in extension factories ── + const builtinExtensions = [ + providerSetupExtension, + createCostTrackerExtension(config.budget, config.steering, sharedState), + createSteeringExtension(config.timeoutMinutes, config.steering, sharedState), + createRepairExtension(), + createObservabilityExtension( + config.imports ?? [], + config.observability, + sharedState, + promptBody, + ), + ]; + + // ── Load user-declared extensions (harness.extensions) ── + let userExtensions: Awaited> = []; + try { + userExtensions = await loadUserExtensions( + config.extensions ?? [], + process.cwd(), + config.extensionsRequired ?? false, + ); + } catch (err) { + // loadUserExtensions only throws if extensionsRequired: true + process.stderr.write(`[aw-harness] ✗ User extension load failed: ${(err as Error).message}\n`); + process.exit(1); + } + + const allExtensions = [...builtinExtensions, ...userExtensions]; + + // ── Create Pi AgentSession ── + const agentDir = getAgentDir(); + const resourceLoader = new DefaultResourceLoader({ + cwd: process.cwd(), + agentDir, + extensionFactories: allExtensions, + // No auto-discovery of skills/context files per spec §6.4 + noContextFiles: true, + noSkills: true, + noPromptTemplates: true, + noThemes: true, + }); + await resourceLoader.reload(); + + let session: Awaited>["session"]; + try { + ({ session } = await createAgentSession({ + sessionManager: SessionManager.inMemory(), + resourceLoader, + // Disable built-in interactive tools; bash is available via cli-proxy on PATH + noTools: "builtin", + })); + } catch (err) { + process.stderr.write( + `[aw-harness] ✗ Failed to create agent session: ${(err as Error).message}\n`, + ); + process.exit(1); + } + + // ── Run the session ── + process.stderr.write(`[aw-harness] → Starting session (model: ${config.model})\n`); + + try { + await session.prompt(prompt, { source: "rpc" }); + } catch (err) { + process.stderr.write( + `[aw-harness] ✗ Session failed: ${(err as Error).message}\n`, + ); + session.dispose(); + process.exit(1); + } finally { + session.dispose(); + } + + // ── Check post-session exit conditions ── + if (sharedState.budgetAborted) { + process.stderr.write("[aw-harness] ✗ Session aborted: budget limit exceeded.\n"); + process.exit(1); + } + + process.stderr.write("[aw-harness] ✓ Session completed successfully.\n"); + process.exit(0); +} + +main().catch((err: unknown) => { + process.stderr.write(`[aw-harness] ✗ Unhandled error: ${(err as Error).message ?? String(err)}\n`); + process.exit(1); +}); diff --git a/aw-harness/src/loader.ts b/aw-harness/src/loader.ts new file mode 100644 index 00000000000..3458b04a0ab --- /dev/null +++ b/aw-harness/src/loader.ts @@ -0,0 +1,212 @@ +/** + * Loader for compiler-generated harness inputs. + * + * Reads config.json and prompt.txt produced by the gh-aw compiler and + * assembles the final prompt string (imports prepended to prompt body). + * + * The harness MUST NOT read or parse raw workflow Markdown files directly. + * All configuration and prompt content MUST come from these pre-processed inputs. + */ + +import { readFileSync } from "node:fs"; +import type { HarnessConfig } from "./types.js"; + +// ─── Defaults ──────────────────────────────────────────────────────────────── + +/** Default values applied when optional harness config keys are absent. */ +export const CONFIG_DEFAULTS = { + timeoutMinutes: 60, + context: { + compaction: "none" as const, + compactionThreshold: 0.75, + }, + steering: { + timeWarningMinutes: 5, + timeCriticalMinutes: 2, + budgetWarnPercent: 75, + budgetCriticalPercent: 90, + }, +}; + +// ─── parseConfig ───────────────────────────────────────────────────────────── + +/** + * Parse and validate the compiler-generated config.json object, applying defaults. + * + * @param raw - Parsed JSON object from config.json + * @throws {Error} if required fields are missing or invalid + */ +export function parseConfig(raw: unknown): HarnessConfig { + if (!raw || typeof raw !== "object") { + throw new Error("config.json must be a JSON object"); + } + + const r = raw as Record; + + if (typeof r["model"] !== "string" || r["model"].trim() === "") { + throw new Error('config.json must include a non-empty "model" string'); + } + + const timeoutMinutes = + typeof r["timeoutMinutes"] === "number" && r["timeoutMinutes"] > 0 + ? r["timeoutMinutes"] + : CONFIG_DEFAULTS.timeoutMinutes; + + // ── budget ── + let budget: HarnessConfig["budget"]; + if (r["budget"] && typeof r["budget"] === "object") { + const b = r["budget"] as Record; + if (typeof b["maxEffectiveTokens"] === "number" && b["maxEffectiveTokens"] > 0) { + budget = { maxEffectiveTokens: b["maxEffectiveTokens"] }; + } + } + + // ── context ── + const rawCtx = + r["context"] && typeof r["context"] === "object" ? (r["context"] as Record) : {}; + const compactionRaw = rawCtx["compaction"]; + const compaction = + compactionRaw === "none" || compactionRaw === "sliding-window" || compactionRaw === "summarize" + ? compactionRaw + : CONFIG_DEFAULTS.context.compaction; + const compactionThreshold = + typeof rawCtx["compactionThreshold"] === "number" + ? Math.max(0, Math.min(1, rawCtx["compactionThreshold"])) + : CONFIG_DEFAULTS.context.compactionThreshold; + + // ── steering ── + const rawSt = + r["steering"] && typeof r["steering"] === "object" ? (r["steering"] as Record) : {}; + const steering = { + timeWarningMinutes: + typeof rawSt["timeWarningMinutes"] === "number" + ? rawSt["timeWarningMinutes"] + : CONFIG_DEFAULTS.steering.timeWarningMinutes, + timeCriticalMinutes: + typeof rawSt["timeCriticalMinutes"] === "number" + ? rawSt["timeCriticalMinutes"] + : CONFIG_DEFAULTS.steering.timeCriticalMinutes, + budgetWarnPercent: + typeof rawSt["budgetWarnPercent"] === "number" + ? rawSt["budgetWarnPercent"] + : CONFIG_DEFAULTS.steering.budgetWarnPercent, + budgetCriticalPercent: + typeof rawSt["budgetCriticalPercent"] === "number" + ? rawSt["budgetCriticalPercent"] + : CONFIG_DEFAULTS.steering.budgetCriticalPercent, + }; + + // ── observability ── + let observability: HarnessConfig["observability"]; + if (r["observability"] && typeof r["observability"] === "object") { + const obs = r["observability"] as Record; + if (obs["otlp"] && typeof obs["otlp"] === "object") { + const otlp = obs["otlp"] as Record; + if (typeof otlp["endpoint"] === "string") { + observability = { + otlp: { + endpoint: otlp["endpoint"], + headers: + otlp["headers"] && typeof otlp["headers"] === "object" + ? (otlp["headers"] as Record) + : undefined, + }, + }; + } + } + } + + // ── extensions ── + const extensions = Array.isArray(r["extensions"]) + ? (r["extensions"] as unknown[]).filter((e): e is string => typeof e === "string") + : undefined; + + const extensionsRequired = + typeof r["extensionsRequired"] === "boolean" ? r["extensionsRequired"] : false; + + // ── imports ── + const imports = Array.isArray(r["imports"]) + ? (r["imports"] as unknown[]).filter( + (e): e is { path: string; content: string } => + typeof e === "object" && + e !== null && + typeof (e as Record)["path"] === "string" && + typeof (e as Record)["content"] === "string", + ) + : undefined; + + return { + model: r["model"], + timeoutMinutes, + budget, + context: { compaction, compactionThreshold }, + steering, + observability, + extensions, + extensionsRequired, + imports, + }; +} + +// ─── loadInputs ────────────────────────────────────────────────────────────── + +/** + * Load and parse the compiler-generated config.json and prompt.txt. + * + * @param configPath - Path to config.json + * @param promptPath - Path to prompt.txt + * @returns Parsed config and raw prompt body + * @throws {Error} on I/O or parse errors + */ +export function loadInputs( + configPath: string, + promptPath: string, +): { config: HarnessConfig; promptBody: string } { + let rawJson: unknown; + try { + rawJson = JSON.parse(readFileSync(configPath, "utf8")); + } catch (err) { + throw new Error(`Failed to read config.json at '${configPath}': ${(err as Error).message}`); + } + + let promptBody: string; + try { + promptBody = readFileSync(promptPath, "utf8"); + } catch (err) { + throw new Error(`Failed to read prompt.txt at '${promptPath}': ${(err as Error).message}`); + } + + const config = parseConfig(rawJson); + return { config, promptBody }; +} + +// ─── parseArgs ─────────────────────────────────────────────────────────────── + +/** + * Parse CLI arguments for the harness entry point. + * Expects: --config --prompt + * + * @param argv - process.argv slice (from index 2) + * @throws {Error} if required flags are missing + */ +export function parseArgs(argv: string[]): { configPath: string; promptPath: string } { + let configPath: string | undefined; + let promptPath: string | undefined; + + for (let i = 0; i < argv.length; i++) { + if (argv[i] === "--config" && argv[i + 1]) { + configPath = argv[++i]; + } else if (argv[i] === "--prompt" && argv[i + 1]) { + promptPath = argv[++i]; + } + } + + if (!configPath) { + throw new Error("Missing required argument: --config "); + } + if (!promptPath) { + throw new Error("Missing required argument: --prompt "); + } + + return { configPath, promptPath }; +} diff --git a/aw-harness/src/types.ts b/aw-harness/src/types.ts new file mode 100644 index 00000000000..61ee0c515b1 --- /dev/null +++ b/aw-harness/src/types.ts @@ -0,0 +1,170 @@ +/** + * Shared type definitions for the AW Harness. + * + * These types match the compiler-generated config.json schema consumed at runtime. + * The harness MUST NOT re-parse raw Markdown frontmatter; all configuration comes + * from the pre-processed inputs produced by the gh-aw compiler. + */ + +// ─── Budget ───────────────────────────────────────────────────────────────── + +/** Budget configuration from harness.budget in workflow frontmatter. */ +export interface BudgetConfig { + /** Maximum effective token count for the run. */ + maxEffectiveTokens: number; +} + +// ─── Context ───────────────────────────────────────────────────────────────── + +/** Compaction strategy. */ +export type CompactionMode = "none" | "sliding-window" | "summarize"; + +/** Context configuration from harness.context. */ +export interface ContextConfig { + /** Compaction mode. Default: "none". */ + compaction: CompactionMode; + /** Fraction of context window at which compaction triggers. Default: 0.75. */ + compactionThreshold: number; +} + +// ─── Steering ──────────────────────────────────────────────────────────────── + +/** Steering configuration from harness.steering. */ +export interface SteeringConfig { + /** Minutes before timeout at which a warning is injected. Default: 5. */ + timeWarningMinutes: number; + /** Minutes before timeout at which a critical message is injected. Default: 2. */ + timeCriticalMinutes: number; + /** Budget percentage at which a warning is injected. Default: 75. */ + budgetWarnPercent: number; + /** Budget percentage at which the session is aborted. Default: 90. */ + budgetCriticalPercent: number; +} + +// ─── Observability ─────────────────────────────────────────────────────────── + +/** OTLP endpoint configuration. */ +export interface OtlpConfig { + endpoint: string; + headers?: Record; +} + +/** Observability configuration from the workflow frontmatter. */ +export interface ObservabilityConfig { + otlp?: OtlpConfig; +} + +// ─── Top-level HarnessConfig ───────────────────────────────────────────────── + +/** + * Compiler-generated harness configuration consumed from config.json. + * + * Corresponds to the `harness:` block in the workflow frontmatter, with + * defaults already applied by the compiler. + */ +export interface HarnessConfig { + /** Model alias or fully-qualified provider/model string. */ + model: string; + + /** Timeout for the workflow run, in minutes. */ + timeoutMinutes: number; + + /** Budget configuration. Absent means no budget limit. */ + budget?: BudgetConfig; + + /** Context/compaction configuration. */ + context: ContextConfig; + + /** Steering (time/budget pressure) configuration. */ + steering: SteeringConfig; + + /** Observability configuration. */ + observability?: ObservabilityConfig; + + /** + * User-declared extension references from harness.extensions. + * Each entry is a repo-relative path (./…) or npm package name. + */ + extensions?: string[]; + + /** + * When true, abort the session if any user extension fails to load. + * Default: false (emit warning only). + */ + extensionsRequired?: boolean; + + /** + * Resolved import entries from the imports: frontmatter key. + * Each entry contains the file path and its full text content, + * resolved by the compiler before the harness is invoked. + */ + imports?: ImportEntry[]; +} + +/** A single resolved import file. */ +export interface ImportEntry { + /** Repository-relative path (e.g. "skills/reporting/SKILL.md"). */ + path: string; + /** Full text content of the file. */ + content: string; +} + +// ─── Loaded inputs ─────────────────────────────────────────────────────────── + +/** Fully loaded harness inputs returned by loadInputs(). */ +export interface LoadedInputs { + config: HarnessConfig; + /** Assembled prompt string (imports + prompt.txt body). */ + prompt: string; +} + +// ─── Shared runtime state ──────────────────────────────────────────────────── + +/** + * Mutable state shared across extensions and the main entry point. + * Extensions close over this object to communicate outcomes back to the harness. + */ +export interface SharedHarnessState { + /** + * Set by the cost-tracker extension when the budget critical threshold is hit. + * The main entry point exits with code 1 after session.dispose() when this is set. + */ + budgetAborted: boolean; + + /** + * Running cumulative token total, updated by the cost-tracker extension on each turn. + */ + cumulativeTokens: number; + + /** + * Running cumulative estimated cost (USD), updated by the cost-tracker extension. + */ + cumulativeCostUsd: number; + + /** + * Turn index counter, incremented on each turn_end event. + */ + turnCount: number; + + /** + * Session start timestamp (ms since epoch), set on agent_start. + */ + sessionStartMs: number; + + /** + * Name of the model used by the session, set on agent_start or model_select. + */ + model: string; +} + +/** Create a fresh SharedHarnessState with default values. */ +export function createSharedState(model: string): SharedHarnessState { + return { + budgetAborted: false, + cumulativeTokens: 0, + cumulativeCostUsd: 0, + turnCount: 0, + sessionStartMs: 0, + model, + }; +} diff --git a/aw-harness/src/user-extensions.ts b/aw-harness/src/user-extensions.ts new file mode 100644 index 00000000000..34602a765ad --- /dev/null +++ b/aw-harness/src/user-extensions.ts @@ -0,0 +1,77 @@ +/** + * User extension loader. + * + * Loads user-declared Pi extensions from harness.extensions paths in config.json. + * Each entry is either a repo-relative path (./…) or an npm package name. + * + * Per spec §6.1.4: + * - Emit a warning to stderr if an extension fails to load. + * - Only abort if harness.extensions-required: true is set. + * - User extensions MUST NOT override or replace built-in gh-aw extensions. + */ + +import { resolve } from "node:path"; +import type { ExtensionFactory } from "@mariozechner/pi-coding-agent"; + +// ─── loadUserExtensions ────────────────────────────────────────────────────── + +/** + * Load and validate user-declared Pi extensions. + * + * @param refs - Extension references from harness.extensions (paths or npm names) + * @param cwd - Working directory for resolving relative paths + * @param extensionsRequired - Whether to throw on load failure (default: false) + * @returns Array of loaded ExtensionFactory functions + */ +export async function loadUserExtensions( + refs: string[], + cwd: string, + extensionsRequired: boolean, +): Promise { + const loaded: ExtensionFactory[] = []; + + for (const ref of refs) { + try { + const factory = await loadOneExtension(ref, cwd); + loaded.push(factory); + } catch (err) { + const msg = `[aw-harness] ⚠️ Failed to load user extension '${ref}': ${(err as Error).message}`; + process.stderr.write(msg + "\n"); + if (extensionsRequired) { + throw new Error(msg); + } + } + } + + return loaded; +} + +// ─── loadOneExtension ──────────────────────────────────────────────────────── + +/** + * Load a single Pi extension from a path or package name. + * + * @param ref - Repo-relative path (./…) or npm package name + * @param cwd - Working directory for resolving relative paths + */ +async function loadOneExtension(ref: string, cwd: string): Promise { + // Resolve repo-relative paths; leave npm package names unchanged + const resolved = + ref.startsWith("./") || ref.startsWith("../") + ? resolve(cwd, ref) + : ref; + + // Use CommonJS require() — compatible with the bundled CJS output and with + // compiled Pi extension modules, which are also CJS. + // eslint-disable-next-line @typescript-eslint/no-require-imports + const mod = require(resolved) as Record; + + // Normalise: support both module.exports = fn and module.exports.default = fn + const factory: unknown = typeof mod?.["default"] === "function" ? mod["default"] : mod; + + if (typeof factory !== "function") { + throw new Error(`Extension '${ref}' does not export a default function`); + } + + return factory as ExtensionFactory; +} diff --git a/aw-harness/test/context.test.ts b/aw-harness/test/context.test.ts new file mode 100644 index 00000000000..9bf930de918 --- /dev/null +++ b/aw-harness/test/context.test.ts @@ -0,0 +1,61 @@ +import { describe, it, expect } from "vitest"; +import { assemblePrompt } from "../src/context.js"; +import type { ImportEntry } from "../src/types.js"; + +describe("assemblePrompt", () => { + it("returns prompt body unchanged when there are no imports", () => { + const result = assemblePrompt([], "Do the task."); + expect(result).toBe("Do the task."); + }); + + it("prepends a single import with delimiters", () => { + const imports: ImportEntry[] = [{ path: "skills/foo/SKILL.md", content: "# Foo skill\nContent." }]; + const result = assemblePrompt(imports, "Do the task."); + + expect(result).toContain(""); + expect(result).toContain("# Foo skill"); + expect(result).toContain(""); + expect(result).toContain("Do the task."); + // Imports come before the prompt body + expect(result.indexOf(""); + expect(result).toContain("Prompt"); + }); + + it("handles empty prompt body", () => { + const imports: ImportEntry[] = [{ path: "foo.md", content: "Content" }]; + const result = assemblePrompt(imports, ""); + expect(result).toContain("Content"); + // Should include the empty prompt (might be just the imports + separator) + expect(typeof result).toBe("string"); + }); +}); diff --git a/aw-harness/test/extensions/cost-tracker.test.ts b/aw-harness/test/extensions/cost-tracker.test.ts new file mode 100644 index 00000000000..892331e0015 --- /dev/null +++ b/aw-harness/test/extensions/cost-tracker.test.ts @@ -0,0 +1,164 @@ +import { describe, it, expect, vi, beforeEach, afterEach } from "vitest"; +import { createSharedState } from "../../src/types.js"; +import { createCostTrackerExtension } from "../../src/extensions/cost-tracker.js"; +import type { ExtensionAPI, ExtensionContext } from "@mariozechner/pi-coding-agent"; + +// ─── Minimal mock helpers ───────────────────────────────────────────────────── + +type TurnEndHandler = ( + event: { message: Record }, + ctx: Partial, +) => void; + +function buildMockPi(): { + pi: ExtensionAPI; + turnEndHandlers: TurnEndHandler[]; + sentMessages: Array<{ content: string; options: { deliverAs?: string } }>; +} { + const turnEndHandlers: TurnEndHandler[] = []; + const sentMessages: Array<{ content: string; options: { deliverAs?: string } }> = []; + + const pi = { + on: vi.fn((event: string, handler: unknown) => { + if (event === "turn_end") turnEndHandlers.push(handler as TurnEndHandler); + }), + sendUserMessage: vi.fn((content: unknown, options: unknown) => { + sentMessages.push({ + content: content as string, + options: (options ?? {}) as { deliverAs?: string }, + }); + }), + } as unknown as ExtensionAPI; + + return { pi, turnEndHandlers, sentMessages }; +} + +function buildMockCtx(tokens: number | null = null): Partial { + return { + getContextUsage: () => + tokens != null ? { tokens, contextWindow: 200_000, percent: tokens / 2000 } : undefined, + }; +} + +function makeTurnEndEvent( + role: "assistant" | "user" | "toolResult", + usage?: { input?: number; output?: number; totalTokens?: number; cost?: { total?: number } }, +): { message: Record } { + return { message: { role, usage } }; +} + +// ─── Tests ─────────────────────────────────────────────────────────────────── + +describe("createCostTrackerExtension", () => { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + let stderrSpy: any; + + beforeEach(() => { + stderrSpy = vi.spyOn(process.stderr, "write").mockImplementation(() => true); + }); + + afterEach(() => { + stderrSpy.mockRestore(); + }); + + it("registers a turn_end handler", () => { + const state = createSharedState("sonnet"); + const { pi } = buildMockPi(); + const factory = createCostTrackerExtension(undefined, { budgetWarnPercent: 75, budgetCriticalPercent: 90, timeWarningMinutes: 5, timeCriticalMinutes: 2 }, state); + factory(pi); + expect((pi.on as ReturnType).mock.calls.some(([e]) => e === "turn_end")).toBe(true); + }); + + it("increments turnCount on each turn_end", () => { + const state = createSharedState("sonnet"); + const steering = { budgetWarnPercent: 75, budgetCriticalPercent: 90, timeWarningMinutes: 5, timeCriticalMinutes: 2 }; + const { pi, turnEndHandlers } = buildMockPi(); + const factory = createCostTrackerExtension(undefined, steering, state); + factory(pi); + + const ctx = buildMockCtx(); + turnEndHandlers[0]?.(makeTurnEndEvent("assistant", { input: 100, output: 50, totalTokens: 150 }), ctx); + expect(state.turnCount).toBe(1); + turnEndHandlers[0]?.(makeTurnEndEvent("assistant", { input: 100, output: 50, totalTokens: 150 }), ctx); + expect(state.turnCount).toBe(2); + }); + + it("accumulates token counts from assistant messages", () => { + const state = createSharedState("sonnet"); + const steering = { budgetWarnPercent: 75, budgetCriticalPercent: 90, timeWarningMinutes: 5, timeCriticalMinutes: 2 }; + const { pi, turnEndHandlers } = buildMockPi(); + const factory = createCostTrackerExtension(undefined, steering, state); + factory(pi); + + const ctx = buildMockCtx(); + turnEndHandlers[0]?.(makeTurnEndEvent("assistant", { input: 1000, output: 500, totalTokens: 1500 }), ctx); + expect(state.cumulativeTokens).toBe(1500); + turnEndHandlers[0]?.(makeTurnEndEvent("assistant", { input: 500, output: 200, totalTokens: 700 }), ctx); + expect(state.cumulativeTokens).toBe(2200); + }); + + it("sends a budget warning at budgetWarnPercent", () => { + const state = createSharedState("sonnet"); + const budget = { maxEffectiveTokens: 1000 }; + const steering = { budgetWarnPercent: 75, budgetCriticalPercent: 90, timeWarningMinutes: 5, timeCriticalMinutes: 2 }; + const { pi, turnEndHandlers, sentMessages } = buildMockPi(); + const factory = createCostTrackerExtension(budget, steering, state); + factory(pi); + + const ctx = buildMockCtx(); + // 800 tokens = 80% > warn threshold (75%) + turnEndHandlers[0]?.(makeTurnEndEvent("assistant", { totalTokens: 800 }), ctx); + + expect(sentMessages).toHaveLength(1); + expect(sentMessages[0]?.content).toMatch(/75|80|budget/i); + expect(sentMessages[0]?.options?.deliverAs).toBe("steer"); + }); + + it("sends a critical message and sets budgetAborted at budgetCriticalPercent", () => { + const state = createSharedState("sonnet"); + const budget = { maxEffectiveTokens: 1000 }; + const steering = { budgetWarnPercent: 75, budgetCriticalPercent: 90, timeWarningMinutes: 5, timeCriticalMinutes: 2 }; + const { pi, turnEndHandlers, sentMessages } = buildMockPi(); + const factory = createCostTrackerExtension(budget, steering, state); + factory(pi); + + const ctx = buildMockCtx(); + // 950 tokens = 95% > critical threshold (90%) + turnEndHandlers[0]?.(makeTurnEndEvent("assistant", { totalTokens: 950 }), ctx); + + expect(state.budgetAborted).toBe(true); + expect(sentMessages.some((m) => m.content.includes("CRITICAL"))).toBe(true); + }); + + it("does not send messages when no budget is configured", () => { + const state = createSharedState("sonnet"); + const steering = { budgetWarnPercent: 75, budgetCriticalPercent: 90, timeWarningMinutes: 5, timeCriticalMinutes: 2 }; + const { pi, turnEndHandlers, sentMessages } = buildMockPi(); + const factory = createCostTrackerExtension(undefined, steering, state); + factory(pi); + + const ctx = buildMockCtx(); + turnEndHandlers[0]?.(makeTurnEndEvent("assistant", { totalTokens: 99_999 }), ctx); + + expect(sentMessages).toHaveLength(0); + expect(state.budgetAborted).toBe(false); + }); + + it("sends the warning message only once even with multiple turns", () => { + const state = createSharedState("sonnet"); + const budget = { maxEffectiveTokens: 1000 }; + const steering = { budgetWarnPercent: 75, budgetCriticalPercent: 90, timeWarningMinutes: 5, timeCriticalMinutes: 2 }; + const { pi, turnEndHandlers, sentMessages } = buildMockPi(); + const factory = createCostTrackerExtension(budget, steering, state); + factory(pi); + + const ctx = buildMockCtx(); + // First turn: hit warn + turnEndHandlers[0]?.(makeTurnEndEvent("assistant", { totalTokens: 800 }), ctx); + // Second turn: still above warn, below critical + turnEndHandlers[0]?.(makeTurnEndEvent("assistant", { totalTokens: 10 }), ctx); + + const warnMessages = sentMessages.filter((m) => !m.content.includes("CRITICAL")); + expect(warnMessages).toHaveLength(1); + }); +}); diff --git a/aw-harness/test/extensions/observability.test.ts b/aw-harness/test/extensions/observability.test.ts new file mode 100644 index 00000000000..d09bbdf9db6 --- /dev/null +++ b/aw-harness/test/extensions/observability.test.ts @@ -0,0 +1,169 @@ +import { describe, it, expect, vi, beforeEach, afterEach } from "vitest"; +import { existsSync, readFileSync, rmSync } from "node:fs"; +import { createSharedState } from "../../src/types.js"; +import { createObservabilityExtension, CONTEXT_PROVENANCE_PATH } from "../../src/extensions/observability.js"; +import type { ExtensionAPI } from "@mariozechner/pi-coding-agent"; +import type { ImportEntry } from "../../src/types.js"; + +type EventHandler = (event: unknown, ctx?: unknown) => void; + +function buildMockPi(): { + pi: ExtensionAPI; + handlers: Record; +} { + const handlers: Record = {}; + const pi = { + on: vi.fn((event: string, handler: unknown) => { + handlers[event] = handler as EventHandler; + }), + sendUserMessage: vi.fn(), + } as unknown as ExtensionAPI; + return { pi, handlers }; +} + +describe("createObservabilityExtension", () => { + let stderrLines: string[]; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + let stderrSpy: any; + + beforeEach(() => { + stderrLines = []; + stderrSpy = vi.spyOn(process.stderr, "write").mockImplementation((msg: unknown) => { + stderrLines.push(String(msg)); + return true; + }); + // Clean up provenance file before each test + try { + rmSync(CONTEXT_PROVENANCE_PATH, { force: true }); + } catch { + // ignore + } + }); + + afterEach(() => { + stderrSpy.mockRestore(); + delete process.env["GITHUB_STEP_SUMMARY"]; + }); + + it("registers all required event handlers", () => { + const state = createSharedState("claude-sonnet-4.6"); + const { pi, handlers } = buildMockPi(); + createObservabilityExtension([], undefined, state, "prompt text")(pi); + + expect(handlers["agent_start"]).toBeDefined(); + expect(handlers["model_select"]).toBeDefined(); + expect(handlers["turn_end"]).toBeDefined(); + expect(handlers["tool_execution_end"]).toBeDefined(); + expect(handlers["agent_end"]).toBeDefined(); + }); + + it("emits session_start JSONL on agent_start", () => { + const state = createSharedState("claude-sonnet-4.6"); + const { pi, handlers } = buildMockPi(); + createObservabilityExtension([], undefined, state, "prompt")(pi); + + handlers["agent_start"]?.({}); + + const jsonLines = stderrLines.filter((l) => l.trimStart().startsWith("{")); + const sessionStart = jsonLines + .map((l) => { try { return JSON.parse(l) as Record; } catch { return null; } }) + .find((r) => r?.["event"] === "session_start"); + expect(sessionStart).toBeDefined(); + expect(sessionStart?.["model"]).toBe("claude-sonnet-4.6"); + }); + + it("emits turn_end JSONL with token info", () => { + const state = createSharedState("sonnet"); + state.turnCount = 1; + state.cumulativeTokens = 1500; + state.cumulativeCostUsd = 0.005; + + const { pi, handlers } = buildMockPi(); + createObservabilityExtension([], undefined, state, "")(pi); + + handlers["turn_end"]?.({ + message: { + role: "assistant", + usage: { input: 1000, output: 500, totalTokens: 1500 }, + }, + }); + + const jsonLines = stderrLines.filter((l) => l.trimStart().startsWith("{")); + const turnEnd = jsonLines + .map((l) => { try { return JSON.parse(l) as Record; } catch { return null; } }) + .find((r) => r?.["event"] === "turn_end"); + expect(turnEnd).toBeDefined(); + expect(turnEnd?.["input_tokens"]).toBe(1000); + expect(turnEnd?.["output_tokens"]).toBe(500); + }); + + it("emits a human-readable per-turn line to stderr", () => { + const state = createSharedState("sonnet"); + state.turnCount = 2; + state.cumulativeTokens = 2000; + + const { pi, handlers } = buildMockPi(); + createObservabilityExtension([], undefined, state, "")(pi); + + handlers["turn_end"]?.({ + message: { role: "assistant", usage: { input: 800, output: 200 } }, + }); + + const humanLine = stderrLines.find((l) => l.startsWith("> **Turn")); + expect(humanLine).toBeDefined(); + expect(humanLine).toContain("Turn 2"); + }); + + it("writes context provenance file on agent_end", () => { + const imports: ImportEntry[] = [ + { path: "skills/foo/SKILL.md", content: "Skill content" }, + ]; + const state = createSharedState("sonnet"); + const { pi, handlers } = buildMockPi(); + createObservabilityExtension(imports, undefined, state, "Prompt body")(pi); + + handlers["agent_start"]?.({}); + handlers["agent_end"]?.({}); + + expect(existsSync(CONTEXT_PROVENANCE_PATH)).toBe(true); + const content = readFileSync(CONTEXT_PROVENANCE_PATH, "utf8"); + const records = content + .trim() + .split("\n") + .filter(Boolean) + .map((l) => JSON.parse(l) as Record); + + expect(records.some((r) => r["source"] === "import" && r["path"] === "skills/foo/SKILL.md")).toBe(true); + expect(records.some((r) => r["source"] === "prompt")).toBe(true); + }); + + it("writes GitHub step summary when GITHUB_STEP_SUMMARY is set", () => { + const summaryPath = `/tmp/aw-test-summary-${Date.now()}.md`; + process.env["GITHUB_STEP_SUMMARY"] = summaryPath; + + const state = createSharedState("claude-sonnet-4.6"); + const { pi, handlers } = buildMockPi(); + createObservabilityExtension([], undefined, state, "prompt")(pi); + + handlers["agent_start"]?.({}); + handlers["agent_end"]?.({}); + + expect(existsSync(summaryPath)).toBe(true); + const content = readFileSync(summaryPath, "utf8"); + expect(content).toContain("AW Harness Run"); + expect(content).toContain("EXPERIMENTAL"); + expect(content).toContain("claude-sonnet-4.6"); + + rmSync(summaryPath, { force: true }); + }); + + it("updates model from model_select event", () => { + const state = createSharedState("initial-model"); + const { pi, handlers } = buildMockPi(); + createObservabilityExtension([], undefined, state, "")(pi); + + handlers["model_select"]?.({ model: { id: "gpt-4-updated" } }); + + expect(state.model).toBe("gpt-4-updated"); + }); +}); diff --git a/aw-harness/test/extensions/provider-setup.test.ts b/aw-harness/test/extensions/provider-setup.test.ts new file mode 100644 index 00000000000..0dcfb5834cf --- /dev/null +++ b/aw-harness/test/extensions/provider-setup.test.ts @@ -0,0 +1,104 @@ +import { describe, it, expect, vi, beforeEach, afterEach } from "vitest"; +import { providerSetupExtension } from "../../src/extensions/provider-setup.js"; +import type { ExtensionAPI } from "@mariozechner/pi-coding-agent"; + +function buildMockPi(): { + pi: ExtensionAPI; + registered: Array<{ name: string; config: Record }>; +} { + const registered: Array<{ name: string; config: Record }> = []; + const pi = { + on: vi.fn(), + registerProvider: vi.fn((name: unknown, config: unknown) => { + registered.push({ name: name as string, config: config as Record }); + }), + } as unknown as ExtensionAPI; + return { pi, registered }; +} + +describe("providerSetupExtension", () => { + const origEnv = { ...process.env }; + + beforeEach(() => { + // Clear provider keys before each test + delete process.env["ANTHROPIC_API_KEY"]; + delete process.env["OPENAI_API_KEY"]; + delete process.env["GITHUB_TOKEN"]; + delete process.env["ANTHROPIC_BASE_URL"]; + delete process.env["OPENAI_BASE_URL"]; + delete process.env["COPILOT_BASE_URL"]; + vi.spyOn(process.stderr, "write").mockImplementation(() => true); + }); + + afterEach(() => { + // Restore env + Object.assign(process.env, origEnv); + vi.restoreAllMocks(); + }); + + it("throws when no provider credentials are set", () => { + const { pi } = buildMockPi(); + expect(() => providerSetupExtension(pi)).toThrow(/No LLM provider credentials/); + }); + + it("registers anthropic provider when ANTHROPIC_API_KEY is set", () => { + process.env["ANTHROPIC_API_KEY"] = "sk-ant-test"; + const { pi, registered } = buildMockPi(); + providerSetupExtension(pi); + + expect(registered.some((r) => r.name === "anthropic")).toBe(true); + const anthropic = registered.find((r) => r.name === "anthropic"); + expect(anthropic?.config?.["apiKey"]).toBe("sk-ant-test"); + expect(anthropic?.config?.["api"]).toBe("anthropic-messages"); + }); + + it("includes baseUrl when ANTHROPIC_BASE_URL is set", () => { + process.env["ANTHROPIC_API_KEY"] = "sk-ant-test"; + process.env["ANTHROPIC_BASE_URL"] = "https://proxy.example.com"; + const { pi, registered } = buildMockPi(); + providerSetupExtension(pi); + + const anthropic = registered.find((r) => r.name === "anthropic"); + expect(anthropic?.config?.["baseUrl"]).toBe("https://proxy.example.com"); + }); + + it("omits baseUrl when ANTHROPIC_BASE_URL is not set", () => { + process.env["ANTHROPIC_API_KEY"] = "sk-ant-test"; + const { pi, registered } = buildMockPi(); + providerSetupExtension(pi); + + const anthropic = registered.find((r) => r.name === "anthropic"); + expect(anthropic?.config?.["baseUrl"]).toBeUndefined(); + }); + + it("registers openai provider when OPENAI_API_KEY is set", () => { + process.env["OPENAI_API_KEY"] = "sk-openai-test"; + const { pi, registered } = buildMockPi(); + providerSetupExtension(pi); + + const openai = registered.find((r) => r.name === "openai"); + expect(openai).toBeDefined(); + expect(openai?.config?.["apiKey"]).toBe("sk-openai-test"); + }); + + it("registers copilot provider when GITHUB_TOKEN is set", () => { + process.env["GITHUB_TOKEN"] = "ghs_test"; + const { pi, registered } = buildMockPi(); + providerSetupExtension(pi); + + const copilot = registered.find((r) => r.name === "copilot"); + expect(copilot).toBeDefined(); + expect(copilot?.config?.["apiKey"]).toBe("ghs_test"); + }); + + it("registers multiple providers when multiple keys are set", () => { + process.env["ANTHROPIC_API_KEY"] = "sk-ant"; + process.env["OPENAI_API_KEY"] = "sk-oai"; + const { pi, registered } = buildMockPi(); + providerSetupExtension(pi); + + expect(registered.length).toBeGreaterThanOrEqual(2); + expect(registered.some((r) => r.name === "anthropic")).toBe(true); + expect(registered.some((r) => r.name === "openai")).toBe(true); + }); +}); diff --git a/aw-harness/test/extensions/repair.test.ts b/aw-harness/test/extensions/repair.test.ts new file mode 100644 index 00000000000..83213cc810a --- /dev/null +++ b/aw-harness/test/extensions/repair.test.ts @@ -0,0 +1,142 @@ +import { describe, it, expect, vi, beforeEach, afterEach } from "vitest"; +import { createRepairExtension } from "../../src/extensions/repair.js"; +import type { ExtensionAPI } from "@mariozechner/pi-coding-agent"; + +type EventHandler = (event: unknown, ctx?: unknown) => void; + +function buildMockPi(): { + pi: ExtensionAPI; + handlers: Record; + sentMessages: Array<{ content: string; options: { deliverAs?: string } }>; +} { + const handlers: Record = {}; + const sentMessages: Array<{ content: string; options: { deliverAs?: string } }> = []; + + const pi = { + on: vi.fn((event: string, handler: unknown) => { + handlers[event] = handler as EventHandler; + }), + sendUserMessage: vi.fn((content: unknown, options: unknown) => { + sentMessages.push({ + content: content as string, + options: (options ?? {}) as { deliverAs?: string }, + }); + }), + } as unknown as ExtensionAPI; + + return { pi, handlers, sentMessages }; +} + +describe("createRepairExtension", () => { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + let stderrSpy: any; + + beforeEach(() => { + stderrSpy = vi.spyOn(process.stderr, "write").mockImplementation(() => true); + }); + + afterEach(() => { + stderrSpy.mockRestore(); + }); + + it("registers tool_result and agent_end handlers", () => { + const { pi, handlers } = buildMockPi(); + createRepairExtension()(pi); + expect(handlers["tool_result"]).toBeDefined(); + expect(handlers["agent_end"]).toBeDefined(); + }); + + it("emits a JSONL repair event for corrupted tool results", () => { + const { pi, handlers } = buildMockPi(); + createRepairExtension()(pi); + + const writtenLines: string[] = []; + stderrSpy.mockImplementation((msg: unknown) => { + writtenLines.push(String(msg)); + return true; + }); + + handlers["tool_result"]?.({ + toolName: "bash", + content: "tool_calls[0].type is null", + }); + + const jsonLines = writtenLines.filter((l) => l.trimStart().startsWith("{")); + expect(jsonLines.some((l) => l.includes("corrupted_tool_result_detected"))).toBe(true); + }); + + it("does not emit repair event for clean tool results", () => { + const { pi, handlers } = buildMockPi(); + createRepairExtension()(pi); + + const writtenLines: string[] = []; + stderrSpy.mockImplementation((msg: unknown) => { + writtenLines.push(String(msg)); + return true; + }); + + handlers["tool_result"]?.({ + toolName: "read", + content: "file contents here", + }); + + const jsonLines = writtenLines.filter((l) => l.trimStart().startsWith("{")); + expect(jsonLines.some((l) => l.includes("repair"))).toBe(false); + }); + + it("injects a follow-up message for recoverable errors on agent_end", () => { + const { pi, handlers, sentMessages } = buildMockPi(); + createRepairExtension()(pi); + + handlers["agent_end"]?.({ error: new Error("rate limit exceeded") }); + + expect(sentMessages).toHaveLength(1); + expect(sentMessages[0]?.options?.deliverAs).toBe("followUp"); + expect(sentMessages[0]?.content).toMatch(/transient error|continue/i); + }); + + it("does not inject a follow-up for non-recoverable errors", () => { + const { pi, handlers, sentMessages } = buildMockPi(); + createRepairExtension()(pi); + + handlers["agent_end"]?.({ error: new Error("permission denied") }); + + expect(sentMessages).toHaveLength(0); + }); + + it("does nothing on agent_end without an error", () => { + const { pi, handlers, sentMessages } = buildMockPi(); + createRepairExtension()(pi); + + handlers["agent_end"]?.({}); + + expect(sentMessages).toHaveLength(0); + }); + + it("treats timeout errors as recoverable", () => { + const { pi, handlers, sentMessages } = buildMockPi(); + createRepairExtension()(pi); + + handlers["agent_end"]?.({ error: new Error("request timeout") }); + + expect(sentMessages).toHaveLength(1); + }); + + it("treats ECONNRESET as recoverable", () => { + const { pi, handlers, sentMessages } = buildMockPi(); + createRepairExtension()(pi); + + handlers["agent_end"]?.({ error: new Error("ECONNRESET: connection reset") }); + + expect(sentMessages).toHaveLength(1); + }); + + it("treats overloaded errors as recoverable", () => { + const { pi, handlers, sentMessages } = buildMockPi(); + createRepairExtension()(pi); + + handlers["agent_end"]?.({ error: new Error("API overloaded, please retry") }); + + expect(sentMessages).toHaveLength(1); + }); +}); diff --git a/aw-harness/test/extensions/steering.test.ts b/aw-harness/test/extensions/steering.test.ts new file mode 100644 index 00000000000..eb44f7b2392 --- /dev/null +++ b/aw-harness/test/extensions/steering.test.ts @@ -0,0 +1,154 @@ +import { describe, it, expect, vi, beforeEach, afterEach } from "vitest"; +import { createSharedState } from "../../src/types.js"; +import { createSteeringExtension } from "../../src/extensions/steering.js"; +import type { ExtensionAPI } from "@mariozechner/pi-coding-agent"; + +type EventHandler = (event: unknown, ctx?: unknown) => void; + +function buildMockPi(): { + pi: ExtensionAPI; + handlers: Record; + sentMessages: Array<{ content: string; options: { deliverAs?: string } }>; +} { + const handlers: Record = {}; + const sentMessages: Array<{ content: string; options: { deliverAs?: string } }> = []; + + const pi = { + on: vi.fn((event: string, handler: unknown) => { + handlers[event] = handler as EventHandler; + }), + sendUserMessage: vi.fn((content: unknown, options: unknown) => { + sentMessages.push({ + content: content as string, + options: (options ?? {}) as { deliverAs?: string }, + }); + }), + } as unknown as ExtensionAPI; + + return { pi, handlers, sentMessages }; +} + +describe("createSteeringExtension", () => { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + let stderrSpy: any; + + beforeEach(() => { + stderrSpy = vi.spyOn(process.stderr, "write").mockImplementation(() => true); + }); + + afterEach(() => { + stderrSpy.mockRestore(); + vi.useRealTimers(); + }); + + const defaultSteering = { + timeWarningMinutes: 5, + timeCriticalMinutes: 2, + budgetWarnPercent: 75, + budgetCriticalPercent: 90, + }; + + it("registers agent_start and turn_end handlers", () => { + const state = createSharedState("sonnet"); + const { pi, handlers } = buildMockPi(); + createSteeringExtension(60, defaultSteering, state)(pi); + expect(handlers["agent_start"]).toBeDefined(); + expect(handlers["turn_end"]).toBeDefined(); + }); + + it("sets sessionStartMs on agent_start", () => { + vi.useFakeTimers(); + vi.setSystemTime(new Date("2026-01-01T00:00:00Z")); + + const state = createSharedState("sonnet"); + const { pi, handlers } = buildMockPi(); + createSteeringExtension(60, defaultSteering, state)(pi); + + handlers["agent_start"]?.({}); + expect(state.sessionStartMs).toBe(new Date("2026-01-01T00:00:00Z").getTime()); + }); + + it("sends a time warning when remaining time is below timeWarningMinutes", () => { + vi.useFakeTimers(); + vi.setSystemTime(new Date("2026-01-01T00:00:00Z")); + + const state = createSharedState("sonnet"); + const { pi, handlers, sentMessages } = buildMockPi(); + // Timeout = 60 min, warning at 5 min remaining + createSteeringExtension(60, defaultSteering, state)(pi); + + handlers["agent_start"]?.({}); + // Advance time to 56 minutes in → 4 minutes remaining (< 5 min warning) + vi.advanceTimersByTime(56 * 60 * 1000); + + handlers["turn_end"]?.({}); + + expect(sentMessages).toHaveLength(1); + expect(sentMessages[0]?.content).toMatch(/minute|remaining/i); + expect(sentMessages[0]?.options?.deliverAs).toBe("steer"); + }); + + it("sends a critical message when remaining time is below timeCriticalMinutes", () => { + vi.useFakeTimers(); + vi.setSystemTime(new Date("2026-01-01T00:00:00Z")); + + const state = createSharedState("sonnet"); + const { pi, handlers, sentMessages } = buildMockPi(); + createSteeringExtension(60, defaultSteering, state)(pi); + + handlers["agent_start"]?.({}); + // Advance 59 minutes → 1 minute remaining (< 2 min critical) + vi.advanceTimersByTime(59 * 60 * 1000); + + handlers["turn_end"]?.({}); + + expect(sentMessages.some((m) => m.content.toUpperCase().includes("CRITICAL"))).toBe(true); + }); + + it("does nothing when time is not yet near the warning threshold", () => { + vi.useFakeTimers(); + vi.setSystemTime(new Date("2026-01-01T00:00:00Z")); + + const state = createSharedState("sonnet"); + const { pi, handlers, sentMessages } = buildMockPi(); + createSteeringExtension(60, defaultSteering, state)(pi); + + handlers["agent_start"]?.({}); + // Only 10 minutes elapsed → plenty of time remaining + vi.advanceTimersByTime(10 * 60 * 1000); + + handlers["turn_end"]?.({}); + + expect(sentMessages).toHaveLength(0); + }); + + it("does not send time warning when sessionStartMs is 0 (agent_start not yet fired)", () => { + const state = createSharedState("sonnet"); + // Do NOT fire agent_start + const { pi, handlers, sentMessages } = buildMockPi(); + createSteeringExtension(60, defaultSteering, state)(pi); + + handlers["turn_end"]?.({}); + + expect(sentMessages).toHaveLength(0); + }); + + it("sends warning only once even across multiple turns", () => { + vi.useFakeTimers(); + vi.setSystemTime(new Date("2026-01-01T00:00:00Z")); + + const state = createSharedState("sonnet"); + const { pi, handlers, sentMessages } = buildMockPi(); + createSteeringExtension(60, defaultSteering, state)(pi); + + handlers["agent_start"]?.({}); + vi.advanceTimersByTime(56 * 60 * 1000); // into warning zone + + handlers["turn_end"]?.({}); + handlers["turn_end"]?.({}); + handlers["turn_end"]?.({}); + + const warnMessages = sentMessages.filter((m) => !m.content.toUpperCase().includes("CRITICAL")); + expect(warnMessages).toHaveLength(1); + }); +}); diff --git a/aw-harness/test/loader.test.ts b/aw-harness/test/loader.test.ts new file mode 100644 index 00000000000..8a66aa41c94 --- /dev/null +++ b/aw-harness/test/loader.test.ts @@ -0,0 +1,236 @@ +import { describe, it, expect, beforeEach, afterEach } from "vitest"; +import { writeFileSync, mkdirSync, rmSync } from "node:fs"; +import { join } from "node:path"; +import { tmpdir } from "node:os"; +import { parseArgs, loadInputs, parseConfig, CONFIG_DEFAULTS } from "../src/loader.js"; + +// ─── parseArgs ─────────────────────────────────────────────────────────────── + +describe("parseArgs", () => { + it("parses --config and --prompt flags", () => { + const result = parseArgs(["--config", "/tmp/config.json", "--prompt", "/tmp/prompt.txt"]); + expect(result).toEqual({ configPath: "/tmp/config.json", promptPath: "/tmp/prompt.txt" }); + }); + + it("parses flags in reverse order", () => { + const result = parseArgs(["--prompt", "/tmp/prompt.txt", "--config", "/tmp/config.json"]); + expect(result).toEqual({ configPath: "/tmp/config.json", promptPath: "/tmp/prompt.txt" }); + }); + + it("throws when --config is missing", () => { + expect(() => parseArgs(["--prompt", "/tmp/prompt.txt"])).toThrow("--config"); + }); + + it("throws when --prompt is missing", () => { + expect(() => parseArgs(["--config", "/tmp/config.json"])).toThrow("--prompt"); + }); + + it("throws when both flags are missing", () => { + expect(() => parseArgs([])).toThrow("--config"); + }); + + it("ignores unknown flags", () => { + const result = parseArgs([ + "--verbose", + "--config", + "/tmp/config.json", + "--prompt", + "/tmp/prompt.txt", + "--extra", + "value", + ]); + expect(result).toEqual({ configPath: "/tmp/config.json", promptPath: "/tmp/prompt.txt" }); + }); +}); + +// ─── parseConfig ───────────────────────────────────────────────────────────── + +describe("parseConfig", () => { + it("parses a minimal valid config", () => { + const config = parseConfig({ model: "claude-sonnet-4.6" }); + expect(config.model).toBe("claude-sonnet-4.6"); + expect(config.timeoutMinutes).toBe(CONFIG_DEFAULTS.timeoutMinutes); + expect(config.context.compaction).toBe("none"); + expect(config.context.compactionThreshold).toBe(0.75); + expect(config.steering.timeWarningMinutes).toBe(5); + expect(config.steering.timeCriticalMinutes).toBe(2); + expect(config.budget).toBeUndefined(); + expect(config.observability).toBeUndefined(); + }); + + it("throws when model is missing", () => { + expect(() => parseConfig({ timeoutMinutes: 30 })).toThrow("model"); + }); + + it("throws when model is empty string", () => { + expect(() => parseConfig({ model: "" })).toThrow("model"); + }); + + it("throws on non-object input", () => { + expect(() => parseConfig("not-an-object")).toThrow(); + expect(() => parseConfig(null)).toThrow(); + expect(() => parseConfig(42)).toThrow(); + }); + + it("applies default timeoutMinutes when missing", () => { + const config = parseConfig({ model: "gpt-4" }); + expect(config.timeoutMinutes).toBe(CONFIG_DEFAULTS.timeoutMinutes); + }); + + it("uses provided timeoutMinutes", () => { + const config = parseConfig({ model: "gpt-4", timeoutMinutes: 45 }); + expect(config.timeoutMinutes).toBe(45); + }); + + it("parses budget config", () => { + const config = parseConfig({ + model: "sonnet", + budget: { maxEffectiveTokens: 100_000 }, + }); + expect(config.budget?.maxEffectiveTokens).toBe(100_000); + }); + + it("ignores invalid budget (negative tokens)", () => { + const config = parseConfig({ model: "sonnet", budget: { maxEffectiveTokens: -1 } }); + expect(config.budget).toBeUndefined(); + }); + + it("parses context config", () => { + const config = parseConfig({ + model: "sonnet", + context: { compaction: "summarize", compactionThreshold: 0.8 }, + }); + expect(config.context.compaction).toBe("summarize"); + expect(config.context.compactionThreshold).toBe(0.8); + }); + + it("clamps compactionThreshold to [0, 1]", () => { + const configHigh = parseConfig({ model: "m", context: { compactionThreshold: 1.5 } }); + expect(configHigh.context.compactionThreshold).toBe(1); + + const configLow = parseConfig({ model: "m", context: { compactionThreshold: -0.1 } }); + expect(configLow.context.compactionThreshold).toBe(0); + }); + + it("falls back to 'none' for unknown compaction mode", () => { + const config = parseConfig({ model: "m", context: { compaction: "magic" } }); + expect(config.context.compaction).toBe("none"); + }); + + it("parses steering config", () => { + const config = parseConfig({ + model: "m", + steering: { + timeWarningMinutes: 10, + timeCriticalMinutes: 3, + budgetWarnPercent: 80, + budgetCriticalPercent: 95, + }, + }); + expect(config.steering.timeWarningMinutes).toBe(10); + expect(config.steering.timeCriticalMinutes).toBe(3); + expect(config.steering.budgetWarnPercent).toBe(80); + expect(config.steering.budgetCriticalPercent).toBe(95); + }); + + it("parses observability config", () => { + const config = parseConfig({ + model: "m", + observability: { otlp: { endpoint: "https://otlp.example.com", headers: { Authorization: "Bearer tok" } } }, + }); + expect(config.observability?.otlp?.endpoint).toBe("https://otlp.example.com"); + expect(config.observability?.otlp?.headers?.["Authorization"]).toBe("Bearer tok"); + }); + + it("ignores observability with missing endpoint", () => { + const config = parseConfig({ model: "m", observability: { otlp: { noEndpoint: true } } }); + expect(config.observability).toBeUndefined(); + }); + + it("parses extensions list", () => { + const config = parseConfig({ + model: "m", + extensions: ["./ext.cjs", "@my-org/ext"], + extensionsRequired: true, + }); + expect(config.extensions).toEqual(["./ext.cjs", "@my-org/ext"]); + expect(config.extensionsRequired).toBe(true); + }); + + it("filters non-string entries from extensions", () => { + const config = parseConfig({ model: "m", extensions: ["./a.cjs", 42, null, "./b.cjs"] }); + expect(config.extensions).toEqual(["./a.cjs", "./b.cjs"]); + }); + + it("parses imports list", () => { + const config = parseConfig({ + model: "m", + imports: [{ path: "skills/foo/SKILL.md", content: "# Foo skill" }], + }); + expect(config.imports).toHaveLength(1); + expect(config.imports?.[0]?.path).toBe("skills/foo/SKILL.md"); + expect(config.imports?.[0]?.content).toBe("# Foo skill"); + }); +}); + +// ─── loadInputs ────────────────────────────────────────────────────────────── + +describe("loadInputs", () => { + let tmpDir: string; + + beforeEach(() => { + tmpDir = join(tmpdir(), `aw-harness-test-${Date.now()}`); + mkdirSync(tmpDir, { recursive: true }); + }); + + afterEach(() => { + rmSync(tmpDir, { recursive: true, force: true }); + }); + + it("loads valid config.json and prompt.txt", () => { + const configPath = join(tmpDir, "config.json"); + const promptPath = join(tmpDir, "prompt.txt"); + + writeFileSync(configPath, JSON.stringify({ model: "claude-sonnet-4.6", timeoutMinutes: 30 })); + writeFileSync(promptPath, "Review the changes and create an issue."); + + const { config, promptBody } = loadInputs(configPath, promptPath); + expect(config.model).toBe("claude-sonnet-4.6"); + expect(config.timeoutMinutes).toBe(30); + expect(promptBody).toBe("Review the changes and create an issue."); + }); + + it("throws when config.json is missing", () => { + const promptPath = join(tmpDir, "prompt.txt"); + writeFileSync(promptPath, "hello"); + + expect(() => loadInputs(join(tmpDir, "nonexistent.json"), promptPath)).toThrow("config.json"); + }); + + it("throws when prompt.txt is missing", () => { + const configPath = join(tmpDir, "config.json"); + writeFileSync(configPath, JSON.stringify({ model: "gpt-4" })); + + expect(() => loadInputs(configPath, join(tmpDir, "nonexistent.txt"))).toThrow("prompt.txt"); + }); + + it("throws when config.json contains invalid JSON", () => { + const configPath = join(tmpDir, "config.json"); + const promptPath = join(tmpDir, "prompt.txt"); + + writeFileSync(configPath, "{ not valid json"); + writeFileSync(promptPath, "hello"); + + expect(() => loadInputs(configPath, promptPath)).toThrow("config.json"); + }); + + it("throws when config.json is missing the model field", () => { + const configPath = join(tmpDir, "config.json"); + const promptPath = join(tmpDir, "prompt.txt"); + + writeFileSync(configPath, JSON.stringify({ timeoutMinutes: 30 })); + writeFileSync(promptPath, "hello"); + + expect(() => loadInputs(configPath, promptPath)).toThrow("model"); + }); +}); diff --git a/aw-harness/test/user-extensions.test.ts b/aw-harness/test/user-extensions.test.ts new file mode 100644 index 00000000000..4c9a331acdc --- /dev/null +++ b/aw-harness/test/user-extensions.test.ts @@ -0,0 +1,50 @@ +import { describe, it, expect, vi, beforeEach, afterEach } from "vitest"; +import { createSharedState } from "../src/types.js"; +import { loadUserExtensions } from "../src/user-extensions.js"; +import type { ExtensionFactory } from "@mariozechner/pi-coding-agent"; + +describe("loadUserExtensions", () => { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + let stderrSpy: any; + + beforeEach(() => { + stderrSpy = vi.spyOn(process.stderr, "write").mockImplementation(() => true); + }); + + afterEach(() => { + stderrSpy.mockRestore(); + }); + + it("returns an empty array when no refs are provided", async () => { + const result = await loadUserExtensions([], process.cwd(), false); + expect(result).toEqual([]); + }); + + it("emits a warning and skips a failing extension when extensionsRequired is false", async () => { + const result = await loadUserExtensions(["./nonexistent-extension.cjs"], process.cwd(), false); + expect(result).toEqual([]); + expect(stderrSpy).toHaveBeenCalled(); + const warnCall = stderrSpy.mock.calls.find((args: unknown[]) => + String(args[0]).includes("nonexistent-extension"), + ); + expect(warnCall).toBeDefined(); + }); + + it("throws when extensionsRequired is true and an extension fails to load", async () => { + await expect( + loadUserExtensions(["./nonexistent-extension.cjs"], process.cwd(), true), + ).rejects.toThrow("nonexistent-extension"); + }); +}); + +describe("createSharedState", () => { + it("initialises state with correct defaults", () => { + const state = createSharedState("claude-sonnet-4.6"); + expect(state.budgetAborted).toBe(false); + expect(state.cumulativeTokens).toBe(0); + expect(state.cumulativeCostUsd).toBe(0); + expect(state.turnCount).toBe(0); + expect(state.sessionStartMs).toBe(0); + expect(state.model).toBe("claude-sonnet-4.6"); + }); +}); diff --git a/aw-harness/tsconfig.json b/aw-harness/tsconfig.json new file mode 100644 index 00000000000..3e37e93dcda --- /dev/null +++ b/aw-harness/tsconfig.json @@ -0,0 +1,16 @@ +{ + "compilerOptions": { + "target": "es2024", + "module": "es2022", + "lib": ["es2024"], + "moduleResolution": "bundler", + "allowSyntheticDefaultImports": true, + "esModuleInterop": true, + "strict": true, + "skipLibCheck": true, + "noEmit": true, + "resolveJsonModule": true, + "declaration": false + }, + "include": ["src/**/*.ts", "test/**/*.ts", "build.ts", "vitest.config.ts"] +} diff --git a/aw-harness/vitest.config.ts b/aw-harness/vitest.config.ts new file mode 100644 index 00000000000..ec9b3e7d636 --- /dev/null +++ b/aw-harness/vitest.config.ts @@ -0,0 +1,15 @@ +import { defineConfig } from "vitest/config"; + +export default defineConfig({ + test: { + environment: "node", + include: ["test/**/*.test.ts"], + testTimeout: 10000, + coverage: { + provider: "v8", + reporter: ["text", "html"], + include: ["src/**/*.ts"], + exclude: ["src/index.ts"], + }, + }, +}); From 345fc358efbdd36749fcc7891fc5d4d0c4ed2031 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 2 May 2026 15:50:01 +0000 Subject: [PATCH 2/2] fix: address code review feedback for aw-harness - Remove unused turnCostUsd variable in observability.ts - Fix cost-tracker fallback to only update when context tokens > current count - Emit warning when invalid budget config is silently ignored in loader.ts - Use instanceof Error check in index.ts main() catch handler - Add critical-message-once test in steering.test.ts - Add test verifying budget warning is emitted to stderr in loader.test.ts Agent-Logs-Url: https://github.com/github/gh-aw/sessions/c34f8c7a-4089-44e1-8a52-edaaa5c215a7 Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- aw-harness/src/extensions/cost-tracker.ts | 6 ++++-- aw-harness/src/extensions/observability.ts | 6 ------ aw-harness/src/index.ts | 3 ++- aw-harness/src/loader.ts | 6 ++++++ aw-harness/test/extensions/steering.test.ts | 20 ++++++++++++++++++++ aw-harness/test/loader.test.ts | 18 ++++++++++++++---- 6 files changed, 46 insertions(+), 13 deletions(-) diff --git a/aw-harness/src/extensions/cost-tracker.ts b/aw-harness/src/extensions/cost-tracker.ts index c4401ce2a77..4ebfa972da3 100644 --- a/aw-harness/src/extensions/cost-tracker.ts +++ b/aw-harness/src/extensions/cost-tracker.ts @@ -50,9 +50,11 @@ export function createCostTrackerExtension( sharedState.cumulativeTokens += turnTokens; sharedState.cumulativeCostUsd += turnCost; } else { - // Fallback: use context window percentage as a proxy for token usage + // Fallback: use context window token count as a proxy for cumulative usage. + // This replaces the running total (not a delta) so we only update if the + // reported value is higher than what we already have. const ctxUsage = ctx.getContextUsage(); - if (ctxUsage?.tokens != null) { + if (ctxUsage?.tokens != null && ctxUsage.tokens > sharedState.cumulativeTokens) { sharedState.cumulativeTokens = ctxUsage.tokens; } } diff --git a/aw-harness/src/extensions/observability.ts b/aw-harness/src/extensions/observability.ts index 0fd2b65386c..76e3b1a0d1c 100644 --- a/aw-harness/src/extensions/observability.ts +++ b/aw-harness/src/extensions/observability.ts @@ -129,12 +129,10 @@ export function createObservabilityExtension( let inputTokens = 0; let outputTokens = 0; - let turnCostUsd = 0; if (msg.role === "assistant" && msg.usage) { inputTokens = msg.usage.input ?? 0; outputTokens = msg.usage.output ?? 0; - turnCostUsd = msg.usage.cost?.total ?? 0; } const turnRecord: TurnRecord = { @@ -145,8 +143,6 @@ export function createObservabilityExtension( estimatedCostUsd: sharedState.cumulativeCostUsd, }; turnRecords.push(turnRecord); - - // Structured JSONL event emitJsonl({ event: "turn_end", turn: sharedState.turnCount, @@ -165,8 +161,6 @@ export function createObservabilityExtension( ` | cumulative ${sharedState.cumulativeTokens.toLocaleString()} tokens` + ` ($${sharedState.cumulativeCostUsd.toFixed(4)})\n`, ); - - void turnCostUsd; // used indirectly via sharedState }); // ── tool_execution_end ─────────────────────────────────────────────────── diff --git a/aw-harness/src/index.ts b/aw-harness/src/index.ts index 7769b2f1687..f72635a53a2 100644 --- a/aw-harness/src/index.ts +++ b/aw-harness/src/index.ts @@ -156,6 +156,7 @@ async function main(): Promise { } main().catch((err: unknown) => { - process.stderr.write(`[aw-harness] ✗ Unhandled error: ${(err as Error).message ?? String(err)}\n`); + const msg = err instanceof Error ? err.message : String(err); + process.stderr.write(`[aw-harness] ✗ Unhandled error: ${msg}\n`); process.exit(1); }); diff --git a/aw-harness/src/loader.ts b/aw-harness/src/loader.ts index 3458b04a0ab..8becbf2e2c3 100644 --- a/aw-harness/src/loader.ts +++ b/aw-harness/src/loader.ts @@ -58,6 +58,12 @@ export function parseConfig(raw: unknown): HarnessConfig { const b = r["budget"] as Record; if (typeof b["maxEffectiveTokens"] === "number" && b["maxEffectiveTokens"] > 0) { budget = { maxEffectiveTokens: b["maxEffectiveTokens"] }; + } else { + // Log a warning so workflow authors understand why budget was ignored + process.stderr.write( + `[aw-harness] ⚠️ Ignoring invalid budget configuration: ` + + `maxEffectiveTokens must be a positive number (got: ${JSON.stringify(b["maxEffectiveTokens"])})\n`, + ); } } diff --git a/aw-harness/test/extensions/steering.test.ts b/aw-harness/test/extensions/steering.test.ts index eb44f7b2392..253d175d3f5 100644 --- a/aw-harness/test/extensions/steering.test.ts +++ b/aw-harness/test/extensions/steering.test.ts @@ -151,4 +151,24 @@ describe("createSteeringExtension", () => { const warnMessages = sentMessages.filter((m) => !m.content.toUpperCase().includes("CRITICAL")); expect(warnMessages).toHaveLength(1); }); + + it("sends the critical message only once even across multiple turns", () => { + vi.useFakeTimers(); + vi.setSystemTime(new Date("2026-01-01T00:00:00Z")); + + const state = createSharedState("sonnet"); + const { pi, handlers, sentMessages } = buildMockPi(); + createSteeringExtension(60, defaultSteering, state)(pi); + + handlers["agent_start"]?.({}); + // 59 minutes elapsed → 1 min remaining (< 2 min critical threshold) + vi.advanceTimersByTime(59 * 60 * 1000); + + handlers["turn_end"]?.({}); + handlers["turn_end"]?.({}); + handlers["turn_end"]?.({}); + + const criticalMessages = sentMessages.filter((m) => m.content.toUpperCase().includes("CRITICAL")); + expect(criticalMessages).toHaveLength(1); + }); }); diff --git a/aw-harness/test/loader.test.ts b/aw-harness/test/loader.test.ts index 8a66aa41c94..c16afe617ca 100644 --- a/aw-harness/test/loader.test.ts +++ b/aw-harness/test/loader.test.ts @@ -1,4 +1,4 @@ -import { describe, it, expect, beforeEach, afterEach } from "vitest"; +import { describe, it, expect, beforeEach, afterEach, vi } from "vitest"; import { writeFileSync, mkdirSync, rmSync } from "node:fs"; import { join } from "node:path"; import { tmpdir } from "node:os"; @@ -90,9 +90,19 @@ describe("parseConfig", () => { expect(config.budget?.maxEffectiveTokens).toBe(100_000); }); - it("ignores invalid budget (negative tokens)", () => { - const config = parseConfig({ model: "sonnet", budget: { maxEffectiveTokens: -1 } }); - expect(config.budget).toBeUndefined(); + it("ignores invalid budget (negative tokens) and emits a warning to stderr", () => { + const warnLines: string[] = []; + const spy = vi.spyOn(process.stderr, "write").mockImplementation((msg: unknown) => { + warnLines.push(String(msg)); + return true; + }); + try { + const config = parseConfig({ model: "sonnet", budget: { maxEffectiveTokens: -1 } }); + expect(config.budget).toBeUndefined(); + expect(warnLines.some((l) => l.includes("Ignoring invalid budget"))).toBe(true); + } finally { + spy.mockRestore(); + } }); it("parses context config", () => {