diff --git a/.github/workflows/create-release.yml b/.github/workflows/create-release.yml index 629709a..61910d7 100644 --- a/.github/workflows/create-release.yml +++ b/.github/workflows/create-release.yml @@ -1,5 +1,5 @@ # .github/workflows/create-release.yml -name: Create GitHub Release and Publish to PyPI +name: Create GitHub Release and Publish SDKs on: push: branches: [main] # Trigger on ANY push to main (including PR merges) @@ -7,9 +7,13 @@ on: types: [closed] # Also trigger when PRs are merged branches: [main] jobs: - detect-and-release: + detect-release: runs-on: ubuntu-latest if: github.event_name == 'push' || (github.event.pull_request.merged == true) + outputs: + latest_tag: ${{ steps.find-tags.outputs.latest_tag }} + version: ${{ steps.find-tags.outputs.version }} + should_release: ${{ steps.check-release.outputs.should_release }} permissions: contents: write pull-requests: read @@ -81,118 +85,70 @@ jobs: env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - # NEW: Set up Python for PyPI publishing - - name: Set up Python - if: steps.check-release.outputs.should_release == 'true' - uses: actions/setup-python@v5 - with: - python-version: '3.11' - - # NEW: Install build dependencies - - name: Install build dependencies - if: steps.check-release.outputs.should_release == 'true' - run: | - python -m pip install --upgrade pip - python -m pip install build twine - - # NEW: Verify version matches tag - - name: Verify package version matches tag - if: steps.check-release.outputs.should_release == 'true' - run: | - TAG_VERSION="${{ steps.find-tags.outputs.version }}" - - # Check if setup.py exists - if [ -f "setup.py" ]; then - PACKAGE_VERSION=$(python setup.py --version) - # Check if pyproject.toml exists - elif [ -f "pyproject.toml" ]; then - # Extract version from pyproject.toml - PACKAGE_VERSION=$(python -c "import tomllib; data = tomllib.load(open('pyproject.toml', 'rb')); print(data['project']['version'])") - else - echo "❌ Neither setup.py nor pyproject.toml found!" - exit 1 - fi - - echo "Tag version: $TAG_VERSION" - echo "Package version: $PACKAGE_VERSION" - - if [ "$TAG_VERSION" != "$PACKAGE_VERSION" ]; then - echo "❌ Version mismatch! Tag: $TAG_VERSION, Package: $PACKAGE_VERSION" - exit 1 - else - echo "✅ Version match confirmed: $TAG_VERSION" - fi - - # NEW: Build Python package - - name: Build package - if: steps.check-release.outputs.should_release == 'true' - run: python -m build - - # NEW: Check if package already exists on PyPI - - name: Check if package exists on PyPI - if: steps.check-release.outputs.should_release == 'true' - id: check-pypi - run: | - VERSION="${{ steps.find-tags.outputs.version }}" - - # Get package name from setup.py or pyproject.toml - if [ -f "pyproject.toml" ]; then - PACKAGE_NAME=$(python -c "import tomllib; data = tomllib.load(open('pyproject.toml', 'rb')); print(data['project']['name'])") - elif [ -f "setup.py" ]; then - PACKAGE_NAME=$(python setup.py --name) - else - echo "❌ Cannot determine package name" - exit 1 - fi - - echo "Checking if $PACKAGE_NAME version $VERSION exists on PyPI..." - - # Check if this version already exists on PyPI - HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" "https://pypi.org/pypi/$PACKAGE_NAME/$VERSION/json/") - - if [ "$HTTP_CODE" = "200" ]; then - echo "⚠️ Package $PACKAGE_NAME v$VERSION already exists on PyPI, skipping upload" - echo "should_publish_pypi=false" >> $GITHUB_OUTPUT - else - echo "✅ Package $PACKAGE_NAME v$VERSION not found on PyPI, proceeding with upload" - echo "should_publish_pypi=true" >> $GITHUB_OUTPUT - fi - - # NEW: Publish to PyPI using API token - - name: Publish package to PyPI - if: steps.check-release.outputs.should_release == 'true' && steps.check-pypi.outputs.should_publish_pypi == 'true' - uses: pypa/gh-action-pypi-publish@release/v1 - with: - password: ${{ secrets.PYPI_API_TOKEN }} - print-hash: true - - - name: Create main GitHub Release - if: steps.check-release.outputs.should_release == 'true' - uses: softprops/action-gh-release@v1 - with: - tag_name: ${{ steps.find-tags.outputs.latest_tag }} - name: RunAgent v${{ steps.find-tags.outputs.version }} - body: | - # 🚀 RunAgent v${{ steps.find-tags.outputs.version }} - - **Universal AI Agent Platform - All SDKs synchronized at v${{ steps.find-tags.outputs.version }}** - - ## 📋 What's New - - For detailed changes in this release, see [CHANGELOG.md](./CHANGELOG.md). - - This release synchronizes all RunAgent SDKs (Python, JavaScript, Rust, Go) to version ${{ steps.find-tags.outputs.version }}. - - ## 📦 Installation - - ```bash - pip install runagent==${{ steps.find-tags.outputs.version }} - ``` - - draft: false - prerelease: false - generate_release_notes: true # Let GitHub add commit-based notes - files: | - CHANGELOG.md - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file + publish-python: + name: Publish Python SDK + needs: detect-release + if: needs.detect-release.outputs.should_release == 'true' + uses: ./.github/workflows/reusable-sdk-release.yml + with: + sdk: python + working-directory: . + tag: ${{ needs.detect-release.outputs.latest_tag }} + version: ${{ needs.detect-release.outputs.version }} + secrets: inherit + + publish-typescript: + name: Publish TypeScript SDK + needs: detect-release + if: needs.detect-release.outputs.should_release == 'true' + uses: ./.github/workflows/reusable-sdk-release.yml + with: + sdk: typescript + working-directory: runagent-ts + tag: ${{ needs.detect-release.outputs.latest_tag }} + version: ${{ needs.detect-release.outputs.version }} + secrets: inherit + + create-release: + name: Create GitHub Release + needs: + - detect-release + - publish-python + - publish-typescript + if: needs.detect-release.outputs.should_release == 'true' + runs-on: ubuntu-latest + permissions: + contents: write + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: Create main GitHub Release + uses: softprops/action-gh-release@v1 + with: + tag_name: ${{ needs.detect-release.outputs.latest_tag }} + name: RunAgent v${{ needs.detect-release.outputs.version }} + body: | + # 🚀 RunAgent v${{ needs.detect-release.outputs.version }} + + **Universal AI Agent Platform - All SDKs synchronized at v${{ needs.detect-release.outputs.version }}** + + ## 📋 What's New + + For detailed changes in this release, see [CHANGELOG.md](./CHANGELOG.md). + + This release synchronizes all RunAgent SDKs (Python, JavaScript, Rust, Go) to version ${{ needs.detect-release.outputs.version }}. + + ## 📦 Installation + + ```bash + pip install runagent==${{ needs.detect-release.outputs.version }} + ``` + + draft: false + prerelease: false + generate_release_notes: true # Let GitHub add commit-based notes + files: | + CHANGELOG.md + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file diff --git a/.github/workflows/python-release.yml b/.github/workflows/python-release.yml new file mode 100644 index 0000000..faf35be --- /dev/null +++ b/.github/workflows/python-release.yml @@ -0,0 +1,99 @@ +name: Python SDK Release + +on: + workflow_call: + inputs: + working-directory: + description: Path where build commands should run + required: true + type: string + tag: + description: Git tag for this release (e.g., v0.1.0) + required: true + type: string + version: + description: Package version without the leading v (e.g., 0.1.0) + required: true + type: string + python-version: + description: Python version used to build the package + required: false + type: string + default: "3.11" + secrets: + PYPI_API_TOKEN: + required: true + +jobs: + publish: + name: Publish Python SDK + runs-on: ubuntu-latest + if: inputs.version != '' + defaults: + run: + shell: bash + working-directory: ${{ inputs.working-directory }} + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Show release context + run: | + echo "Tag: ${{ inputs.tag }}" + echo "Version: ${{ inputs.version }}" + echo "Working directory: ${{ inputs.working-directory }}" + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: ${{ inputs.python-version }} + + - name: Upgrade pip and install build dependencies + run: | + python -m pip install --upgrade pip + python -m pip install build twine + + - name: Verify package version matches tag + id: verify-python-version + run: | + TAG_VERSION="${{ inputs.version }}" + PACKAGE_VERSION=$(python -c "import tomllib; data = tomllib.load(open('pyproject.toml', 'rb')); print(data['project']['version'])") + echo "Detected package version: $PACKAGE_VERSION" + if [ "$PACKAGE_VERSION" != "$TAG_VERSION" ]; then + echo "❌ Version mismatch! Tag: $TAG_VERSION, Package: $PACKAGE_VERSION" + exit 1 + fi + echo "✅ Python version matches tag" + + - name: Build package + run: python -m build + + - name: Check if package version already exists on PyPI + id: check-python + run: | + VERSION="${{ inputs.version }}" + PACKAGE_NAME=$(python -c "import tomllib; data = tomllib.load(open('pyproject.toml', 'rb')); print(data['project']['name'])") + echo "Package name: $PACKAGE_NAME" + HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" "https://pypi.org/pypi/$PACKAGE_NAME/$VERSION/json/") + if [ "$HTTP_CODE" = "200" ]; then + echo "⚠️ $PACKAGE_NAME v$VERSION already exists on PyPI" + echo "should_publish=false" >> "$GITHUB_OUTPUT" + else + echo "✅ $PACKAGE_NAME v$VERSION not found on PyPI" + echo "should_publish=true" >> "$GITHUB_OUTPUT" + fi + echo "package_name=$PACKAGE_NAME" >> "$GITHUB_OUTPUT" + + - name: Publish package to PyPI + if: steps.check-python.outputs.should_publish == 'true' + uses: pypa/gh-action-pypi-publish@release/v1 + with: + password: ${{ secrets.PYPI_API_TOKEN }} + print-hash: true + + - name: Skip publish (already exists) + if: steps.check-python.outputs.should_publish != 'true' + run: echo "Skipping PyPI publish because version already exists." + diff --git a/.github/workflows/reusable-sdk-release.yml b/.github/workflows/reusable-sdk-release.yml new file mode 100644 index 0000000..0c9b1b8 --- /dev/null +++ b/.github/workflows/reusable-sdk-release.yml @@ -0,0 +1,58 @@ +name: SDK Release Router + +on: + workflow_call: + inputs: + sdk: + description: Identifier for the SDK (e.g., python, typescript) + required: true + type: string + working-directory: + description: Path where build commands should run + required: true + type: string + tag: + description: Git tag for this release (e.g., v0.1.0) + required: true + type: string + version: + description: Package version without the leading v (e.g., 0.1.0) + required: true + type: string + python-version: + description: Python version to use when sdk == python + required: false + type: string + default: "3.11" + node-version: + description: Node.js version to use when sdk == typescript + required: false + type: string + default: "20" + secrets: + PYPI_API_TOKEN: + required: false + NPM_TOKEN: + required: false + +jobs: + python: + if: inputs.sdk == 'python' && inputs.version != '' + uses: ./.github/workflows/python-release.yml + with: + working-directory: ${{ inputs.working-directory }} + tag: ${{ inputs.tag }} + version: ${{ inputs.version }} + python-version: ${{ inputs.python-version }} + secrets: inherit + + typescript: + if: inputs.sdk == 'typescript' && inputs.version != '' + uses: ./.github/workflows/typescript-release.yml + with: + working-directory: ${{ inputs.working-directory }} + tag: ${{ inputs.tag }} + version: ${{ inputs.version }} + node-version: ${{ inputs.node-version }} + secrets: inherit + diff --git a/.github/workflows/typescript-release.yml b/.github/workflows/typescript-release.yml new file mode 100644 index 0000000..eb13a3e --- /dev/null +++ b/.github/workflows/typescript-release.yml @@ -0,0 +1,106 @@ +name: TypeScript SDK Release + +on: + workflow_call: + inputs: + working-directory: + description: Path where build commands should run + required: true + type: string + tag: + description: Git tag for this release (e.g., v0.1.0) + required: true + type: string + version: + description: Package version without the leading v (e.g., 0.1.0) + required: true + type: string + node-version: + description: Node.js version used to build the package + required: false + type: string + default: "20" + secrets: + NPM_TOKEN: + required: false + +jobs: + publish: + name: Publish TypeScript SDK + runs-on: ubuntu-latest + if: inputs.version != '' + permissions: + contents: read + id-token: write + defaults: + run: + shell: bash + working-directory: ${{ inputs.working-directory }} + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Show release context + run: | + echo "Tag: ${{ inputs.tag }}" + echo "Version: ${{ inputs.version }}" + echo "Working directory: ${{ inputs.working-directory }}" + + - name: Set up Node + uses: actions/setup-node@v4 + with: + node-version: ${{ inputs.node-version }} + cache: npm + cache-dependency-path: ${{ inputs.working-directory }}/package-lock.json + registry-url: https://registry.npmjs.org + + - name: Ensure npm supports trusted publishing + run: npm install -g npm@^11.5.1 + + - name: Install dependencies + run: npm ci + + - name: Type-check + run: npm run type-check + + - name: Build package + run: npm run build + + - name: Verify package version matches tag + id: verify-ts-version + run: | + TAG_VERSION="${{ inputs.version }}" + PACKAGE_VERSION=$(node -p "require('./package.json').version") + echo "Detected package version: $PACKAGE_VERSION" + if [ "$PACKAGE_VERSION" != "$TAG_VERSION" ]; then + echo "❌ Version mismatch! Tag: $TAG_VERSION, Package: $PACKAGE_VERSION" + exit 1 + fi + echo "✅ TypeScript version matches tag" + + - name: Check if package version already exists on npm + id: check-npm + run: | + VERSION="${{ inputs.version }}" + PACKAGE_NAME=$(node -p "require('./package.json').name") + echo "Package name: $PACKAGE_NAME" + HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" "https://registry.npmjs.org/$PACKAGE_NAME/$VERSION") + if [ "$HTTP_CODE" = "200" ]; then + echo "⚠️ $PACKAGE_NAME v$VERSION already exists on npm" + echo "should_publish=false" >> "$GITHUB_OUTPUT" + else + echo "✅ $PACKAGE_NAME v$VERSION not found on npm" + echo "should_publish=true" >> "$GITHUB_OUTPUT" + fi + echo "package_name=$PACKAGE_NAME" >> "$GITHUB_OUTPUT" + + - name: Publish package to npm + if: steps.check-npm.outputs.should_publish == 'true' + run: npm publish --access public + + - name: Skip publish (already exists) + if: steps.check-npm.outputs.should_publish != 'true' + run: echo "Skipping npm publish because version already exists." + diff --git a/runagent-ts/PUBLISH.md b/runagent-ts/PUBLISH.md new file mode 100644 index 0000000..9693819 --- /dev/null +++ b/runagent-ts/PUBLISH.md @@ -0,0 +1,73 @@ +# Publishing `runagent` + +This package ships the TypeScript SDK that mirrors the RunAgent CLI/Python client. Follow these steps whenever you publish an updated build to npm. + +--- + +## 1. Prerequisites + +- npm account with publish rights to the `runagent` package. +- `npm login` already performed in your shell. +- Local environment with Node.js ≥ 18. + +--- + +## 2. Preflight Checklist + +1. **Update version**: bump `"version"` in `package.json` following semver (major/minor/patch). +2. **Changelog**: ensure release notes exist (main repository changelog, or add release notes to the docs site). +3. **Dependencies**: verify `peerDependencies` remain accurate (`ws`, `better-sqlite3` optional). + +--- + +## 3. Build & Test + +```bash +# From runagent-ts/ +npm install # installs dev deps +npm run type-check # TypeScript compile check +npm run build # bundles cjs + esm + dts +``` + +Optional sanity checks: + +```bash +npm pack # creates a local tarball for inspection +``` + +Inspect `dist/` and the pack output to confirm only the expected files are included (`runagent-client.js`, `.cjs`, `index.d.ts`, etc.). + +--- + +## 4. Publish + +The package uses the contents of the `dist/` folder that `vite build` produces. + +```bash +npm publish --access public +``` + +> **Dry run**: add `--dry-run` if you want to verify the payload before publishing. + +If two-factor auth is enabled on npm, complete the OTP prompt. + +--- + +## 5. Post-Publish + +- Tag the release in git (e.g. `git tag sdk-ts-v0.1.27 && git push origin sdk-ts-v0.1.27`). +- Notify the team / update release notes. +- Ensure docs references (CLI docs, SDK docs) point at the new version. + +--- + +## Troubleshooting + +- **`npm ERR! publish fail`**: verify you have publish rights and that the version is new (npm rejects republishing the same version). +- **Bundled `better-sqlite3`**: confirm the dependency stayed as optional peer; browser consumers should not be forced to install it. +- **Missing WebSocket support**: remind Node users to install `ws`, or include that note in the release notes if API changes require it. + +--- + +You’re done! 🚀 + diff --git a/runagent-ts/README.md b/runagent-ts/README.md new file mode 100644 index 0000000..c96cfd6 --- /dev/null +++ b/runagent-ts/README.md @@ -0,0 +1,255 @@ +# RunAgent TypeScript SDK + +The RunAgent TypeScript SDK delivers the same `RunAgentClient` interface found in the Python SDK, tailored for both Node.js services and browser-based applications. Use it to invoke agents you deploy with the RunAgent CLI, whether they run locally on the same machine or remotely on `backend.run-agent.ai`. + +--- + +## Installation + +```bash +npm install runagent +``` + +Optional peer dependencies: + +- `ws` – required for WebSocket streaming in Node.js environments. +- `better-sqlite3` – only needed when you want Node.js clients to auto-discover local agents via the RunAgent registry. Browser builds should not install it. + +```bash +# For Node.js apps that rely on registry discovery: +npm install ws better-sqlite3 +``` + +--- + +## Configuration Overview + +```ts +interface RunAgentConfig { + agentId: string; + entrypointTag: string; + local?: boolean; // default: false in browser, true in Node if not specified + host?: string; // required in browser when local = true (no registry access) + port?: number; // required in browser when local = true (no registry access) + apiKey?: string; // defaults to RUNAGENT_API_KEY env variable + baseUrl?: string; // defaults to RUNAGENT_BASE_URL env variable or https://backend.run-agent.ai + baseSocketUrl?: string; // optional override for WebSocket origin + apiPrefix?: string; // defaults to /api/v1 + timeoutSeconds?: number; // defaults to 300 + extraParams?: Record; // reserved for metadata forwarding + enableRegistry?: boolean; // defaults to true in Node, false in browsers +} +``` + +**Environment variables** + +- `RUNAGENT_API_KEY` – API key for remote agents (Bearer token). +- `RUNAGENT_BASE_URL` – override the default remote base URL (useful for staging/self-hosted deployments). + +For browser builds, you can expose these via bundler secrets or a custom `globalThis.RUNAGENT_ENV` object before initialising the client. + +--- + +## Usage (Node.js) + +### 1. Remote agent + +```ts +import { RunAgentClient } from 'runagent'; + +const client = new RunAgentClient({ + agentId: 'agent-id-from-dashboard', + entrypointTag: 'support_flow', + apiKey: process.env.RUNAGENT_API_KEY, + // Optional: baseUrl defaults to https://backend.run-agent.ai +}); + +await client.initialize(); + +const result = await client.run({ + customer_email: 'alex@example.com', + issue_summary: 'Billing question', +}); + +console.log(result); +``` + +### 2. Remote streaming + +```ts +import { RunAgentClient } from 'runagent'; + +const client = new RunAgentClient({ + agentId: 'agent-id-from-dashboard', + entrypointTag: 'support_flow_stream', + apiKey: process.env.RUNAGENT_API_KEY, +}); + +await client.initialize(); + +for await (const chunk of client.runStream({ transcript: [] })) { + console.log('>>>', chunk); +} +``` + +### 3. Local agent discovery (Node only) + +```ts +import { RunAgentClient } from 'runagent'; + +const client = new RunAgentClient({ + agentId: 'local-agent-id', + entrypointTag: 'minimal', + local: true, + // enableRegistry defaults to true in Node; make sure better-sqlite3 is installed +}); + +await client.initialize(); // looks up ~/.runagent/runagent_local.db +const result = await client.run({ message: 'Hello there' }); +console.log(result); +``` + +If you prefer to bypass the registry (or if `better-sqlite3` isn’t installed), pass the host and port explicitly: + +```ts +const client = new RunAgentClient({ + agentId: 'local-agent-id', + entrypointTag: 'minimal', + local: true, + enableRegistry: false, + host: '127.0.0.1', + port: 8450, +}); +``` + +--- + +## Usage (Browser / Edge Runtimes) + +Browser builds cannot access the local registry or the filesystem. Provide connection details explicitly and set `enableRegistry: false`. + +```ts +import { RunAgentClient } from 'runagent'; + +const client = new RunAgentClient({ + agentId: 'agent-id-from-dashboard', + entrypointTag: 'support_flow', + local: false, + apiKey: window.RUNAGENT_API_KEY, // inject securely via bundler/runtime + enableRegistry: false, +}); + +await client.initialize(); +const result = await client.run({ message: 'Hello!' }); +``` + +For browser streaming: + +```ts +const client = new RunAgentClient({ + agentId: 'agent-id', + entrypointTag: 'support_flow_stream', + apiKey: window.RUNAGENT_API_KEY, + enableRegistry: false, +}); + +await client.initialize(); + +for await (const chunk of client.runStream({ message: 'Need help' })) { + renderChunk(chunk); +} +``` + +> **Tip:** To keep bundles light, Webpack/Vite can tree-shake the optional registry path when `enableRegistry` is `false`. This avoids shipping Node-only dependencies to the browser. + +--- + +## API Reference + +### `RunAgentClient` methods + +- `initialize(): Promise` + Resolves connection details (registry lookup for local Node use, base URLs for remote) and validates that the requested entrypoint exists. + +- `run(inputKwargs?: Record): Promise` + Executes a non-streaming entrypoint via HTTPS and returns deserialized output (matching the Python SDK semantics). + +- `runStream(inputKwargs?: Record): AsyncGenerator` + Streams chunks via WebSocket for entrypoints whose tags end with `_stream`. Throws if you call it on a non-stream entrypoint. + +- `getExtraParams(): Record | undefined` + Returns any metadata passed in `extraParams`. Reserved for forward compatibility. + +### Constructor precedence rules + +1. Explicit constructor values. +2. Environment variables (`RUNAGENT_API_KEY`, `RUNAGENT_BASE_URL`). +3. Defaults (remote base URL, 300 second timeout, registry disabled in browsers). + +--- + +## Security Best Practices + +- Never commit API keys to source control. Use environment variables or secret managers, even on the client side (e.g., provide short-lived tokens from your backend). +- Browsers cannot safely store long-lived keys. Prefer proxying via your backend or issuing ephemeral tokens per session. +- For Node environments, rely on OS-level key storage or `.env` files owned by your deployment platform. + +--- + +## Troubleshooting + +- **`Entrypoint ... is streaming. Use runStream()`** + Call `runStream()` for tags ending in `_stream`. + +- **`Unable to determine host/port` (local mode)** + Install `better-sqlite3` and ensure the agent was started through the CLI (`runagent serve ...`). Otherwise provide `host` and `port` manually. + +- **Authentication failures (401/403)** + Make sure `RUNAGENT_API_KEY` (or `apiKey` in the constructor) corresponds to an account with access to the agent. + +- **WebSocket connection fails in browser** + Confirm your environment allows WSS connections to `backend.run-agent.ai` and set `enableRegistry: false`. + +--- + +## Example Build Targets + +### Vite (Node backend + browser client) + +```ts +// vite.config.ts +export default defineConfig({ + define: { + 'process.env.RUNAGENT_API_KEY': JSON.stringify(process.env.RUNAGENT_API_KEY), + 'process.env.RUNAGENT_BASE_URL': JSON.stringify(process.env.RUNAGENT_BASE_URL), + }, +}); +``` + +### Serverless (Edge Functions, Cloudflare Workers, etc.) + +Edge runtimes are closer to browsers: disable the registry and pass host/base URLs explicitly. + +```ts +const client = new RunAgentClient({ + agentId: env.AGENT_ID, + entrypointTag: 'edge_entry', + apiKey: env.RUNAGENT_API_KEY, + enableRegistry: false, +}); +``` + +--- + +## Version Compatibility + +- SDK version `0.1.26` aligns with the CLI v1+ REST/WebSocket APIs (`/agents/{id}/run` & `/run-stream` routes). +- Breaking changes are communicated in the main RunAgent changelog; the TypeScript SDK follows semantic versioning. + +--- + +## Need Help? + +- Consult the main documentation in `docs/sdk/javascript/`. +- Join the RunAgent community channels or open an issue if you encounter integration problems that aren’t covered here. + diff --git a/runagent-ts/package.json b/runagent-ts/package.json index 45d1929..7ff82f2 100644 --- a/runagent-ts/package.json +++ b/runagent-ts/package.json @@ -34,14 +34,15 @@ "vite-plugin-dts": "^3.0.0" }, "peerDependencies": { - "ws": "^8.18.3" + "ws": "^8.18.3", + "better-sqlite3": "^12.2.0" }, "peerDependenciesMeta": { "ws": { "optional": true + }, + "better-sqlite3": { + "optional": true } - }, - "dependencies": { - "better-sqlite3": "^12.2.0" } } diff --git a/runagent-ts/pnpm-lock.yaml b/runagent-ts/pnpm-lock.yaml new file mode 100644 index 0000000..dd0a7c8 --- /dev/null +++ b/runagent-ts/pnpm-lock.yaml @@ -0,0 +1,1515 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: + dependencies: + better-sqlite3: + specifier: ^12.2.0 + version: 12.4.1 + ws: + specifier: ^8.18.3 + version: 8.18.3 + devDependencies: + '@types/better-sqlite3': + specifier: ^7.6.13 + version: 7.6.13 + '@types/node': + specifier: ^24.0.14 + version: 24.10.1 + '@types/ws': + specifier: ^8.18.1 + version: 8.18.1 + typescript: + specifier: ^5.0.0 + version: 5.9.3 + vite: + specifier: ^5.0.0 + version: 5.4.21(@types/node@24.10.1) + vite-plugin-dts: + specifier: ^3.0.0 + version: 3.9.1(@types/node@24.10.1)(rollup@4.53.2)(typescript@5.9.3)(vite@5.4.21(@types/node@24.10.1)) + +packages: + + '@babel/helper-string-parser@7.27.1': + resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-identifier@7.28.5': + resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==} + engines: {node: '>=6.9.0'} + + '@babel/parser@7.28.5': + resolution: {integrity: sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==} + engines: {node: '>=6.0.0'} + hasBin: true + + '@babel/types@7.28.5': + resolution: {integrity: sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==} + engines: {node: '>=6.9.0'} + + '@esbuild/aix-ppc64@0.21.5': + resolution: {integrity: sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==} + engines: {node: '>=12'} + cpu: [ppc64] + os: [aix] + + '@esbuild/android-arm64@0.21.5': + resolution: {integrity: sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==} + engines: {node: '>=12'} + cpu: [arm64] + os: [android] + + '@esbuild/android-arm@0.21.5': + resolution: {integrity: sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==} + engines: {node: '>=12'} + cpu: [arm] + os: [android] + + '@esbuild/android-x64@0.21.5': + resolution: {integrity: sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==} + engines: {node: '>=12'} + cpu: [x64] + os: [android] + + '@esbuild/darwin-arm64@0.21.5': + resolution: {integrity: sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==} + engines: {node: '>=12'} + cpu: [arm64] + os: [darwin] + + '@esbuild/darwin-x64@0.21.5': + resolution: {integrity: sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==} + engines: {node: '>=12'} + cpu: [x64] + os: [darwin] + + '@esbuild/freebsd-arm64@0.21.5': + resolution: {integrity: sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==} + engines: {node: '>=12'} + cpu: [arm64] + os: [freebsd] + + '@esbuild/freebsd-x64@0.21.5': + resolution: {integrity: sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [freebsd] + + '@esbuild/linux-arm64@0.21.5': + resolution: {integrity: sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==} + engines: {node: '>=12'} + cpu: [arm64] + os: [linux] + + '@esbuild/linux-arm@0.21.5': + resolution: {integrity: sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==} + engines: {node: '>=12'} + cpu: [arm] + os: [linux] + + '@esbuild/linux-ia32@0.21.5': + resolution: {integrity: sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==} + engines: {node: '>=12'} + cpu: [ia32] + os: [linux] + + '@esbuild/linux-loong64@0.21.5': + resolution: {integrity: sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==} + engines: {node: '>=12'} + cpu: [loong64] + os: [linux] + + '@esbuild/linux-mips64el@0.21.5': + resolution: {integrity: sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==} + engines: {node: '>=12'} + cpu: [mips64el] + os: [linux] + + '@esbuild/linux-ppc64@0.21.5': + resolution: {integrity: sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==} + engines: {node: '>=12'} + cpu: [ppc64] + os: [linux] + + '@esbuild/linux-riscv64@0.21.5': + resolution: {integrity: sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==} + engines: {node: '>=12'} + cpu: [riscv64] + os: [linux] + + '@esbuild/linux-s390x@0.21.5': + resolution: {integrity: sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==} + engines: {node: '>=12'} + cpu: [s390x] + os: [linux] + + '@esbuild/linux-x64@0.21.5': + resolution: {integrity: sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [linux] + + '@esbuild/netbsd-x64@0.21.5': + resolution: {integrity: sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==} + engines: {node: '>=12'} + cpu: [x64] + os: [netbsd] + + '@esbuild/openbsd-x64@0.21.5': + resolution: {integrity: sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==} + engines: {node: '>=12'} + cpu: [x64] + os: [openbsd] + + '@esbuild/sunos-x64@0.21.5': + resolution: {integrity: sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==} + engines: {node: '>=12'} + cpu: [x64] + os: [sunos] + + '@esbuild/win32-arm64@0.21.5': + resolution: {integrity: sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==} + engines: {node: '>=12'} + cpu: [arm64] + os: [win32] + + '@esbuild/win32-ia32@0.21.5': + resolution: {integrity: sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==} + engines: {node: '>=12'} + cpu: [ia32] + os: [win32] + + '@esbuild/win32-x64@0.21.5': + resolution: {integrity: sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==} + engines: {node: '>=12'} + cpu: [x64] + os: [win32] + + '@jridgewell/sourcemap-codec@1.5.5': + resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} + + '@microsoft/api-extractor-model@7.28.13': + resolution: {integrity: sha512-39v/JyldX4MS9uzHcdfmjjfS6cYGAoXV+io8B5a338pkHiSt+gy2eXQ0Q7cGFJ7quSa1VqqlMdlPrB6sLR/cAw==} + + '@microsoft/api-extractor@7.43.0': + resolution: {integrity: sha512-GFhTcJpB+MI6FhvXEI9b2K0snulNLWHqC/BbcJtyNYcKUiw7l3Lgis5ApsYncJ0leALX7/of4XfmXk+maT111w==} + hasBin: true + + '@microsoft/tsdoc-config@0.16.2': + resolution: {integrity: sha512-OGiIzzoBLgWWR0UdRJX98oYO+XKGf7tiK4Zk6tQ/E4IJqGCe7dvkTvgDZV5cFJUzLGDOjeAXrnZoA6QkVySuxw==} + + '@microsoft/tsdoc@0.14.2': + resolution: {integrity: sha512-9b8mPpKrfeGRuhFH5iO1iwCLeIIsV6+H1sRfxbkoGXIyQE2BTsPd9zqSqQJ+pv5sJ/hT5M1zvOFL02MnEezFug==} + + '@rollup/pluginutils@5.3.0': + resolution: {integrity: sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q==} + engines: {node: '>=14.0.0'} + peerDependencies: + rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true + + '@rollup/rollup-android-arm-eabi@4.53.2': + resolution: {integrity: sha512-yDPzwsgiFO26RJA4nZo8I+xqzh7sJTZIWQOxn+/XOdPE31lAvLIYCKqjV+lNH/vxE2L2iH3plKxDCRK6i+CwhA==} + cpu: [arm] + os: [android] + + '@rollup/rollup-android-arm64@4.53.2': + resolution: {integrity: sha512-k8FontTxIE7b0/OGKeSN5B6j25EuppBcWM33Z19JoVT7UTXFSo3D9CdU39wGTeb29NO3XxpMNauh09B+Ibw+9g==} + cpu: [arm64] + os: [android] + + '@rollup/rollup-darwin-arm64@4.53.2': + resolution: {integrity: sha512-A6s4gJpomNBtJ2yioj8bflM2oogDwzUiMl2yNJ2v9E7++sHrSrsQ29fOfn5DM/iCzpWcebNYEdXpaK4tr2RhfQ==} + cpu: [arm64] + os: [darwin] + + '@rollup/rollup-darwin-x64@4.53.2': + resolution: {integrity: sha512-e6XqVmXlHrBlG56obu9gDRPW3O3hLxpwHpLsBJvuI8qqnsrtSZ9ERoWUXtPOkY8c78WghyPHZdmPhHLWNdAGEw==} + cpu: [x64] + os: [darwin] + + '@rollup/rollup-freebsd-arm64@4.53.2': + resolution: {integrity: sha512-v0E9lJW8VsrwPux5Qe5CwmH/CF/2mQs6xU1MF3nmUxmZUCHazCjLgYvToOk+YuuUqLQBio1qkkREhxhc656ViA==} + cpu: [arm64] + os: [freebsd] + + '@rollup/rollup-freebsd-x64@4.53.2': + resolution: {integrity: sha512-ClAmAPx3ZCHtp6ysl4XEhWU69GUB1D+s7G9YjHGhIGCSrsg00nEGRRZHmINYxkdoJehde8VIsDC5t9C0gb6yqA==} + cpu: [x64] + os: [freebsd] + + '@rollup/rollup-linux-arm-gnueabihf@4.53.2': + resolution: {integrity: sha512-EPlb95nUsz6Dd9Qy13fI5kUPXNSljaG9FiJ4YUGU1O/Q77i5DYFW5KR8g1OzTcdZUqQQ1KdDqsTohdFVwCwjqg==} + cpu: [arm] + os: [linux] + + '@rollup/rollup-linux-arm-musleabihf@4.53.2': + resolution: {integrity: sha512-BOmnVW+khAUX+YZvNfa0tGTEMVVEerOxN0pDk2E6N6DsEIa2Ctj48FOMfNDdrwinocKaC7YXUZ1pHlKpnkja/Q==} + cpu: [arm] + os: [linux] + + '@rollup/rollup-linux-arm64-gnu@4.53.2': + resolution: {integrity: sha512-Xt2byDZ+6OVNuREgBXr4+CZDJtrVso5woFtpKdGPhpTPHcNG7D8YXeQzpNbFRxzTVqJf7kvPMCub/pcGUWgBjA==} + cpu: [arm64] + os: [linux] + + '@rollup/rollup-linux-arm64-musl@4.53.2': + resolution: {integrity: sha512-+LdZSldy/I9N8+klim/Y1HsKbJ3BbInHav5qE9Iy77dtHC/pibw1SR/fXlWyAk0ThnpRKoODwnAuSjqxFRDHUQ==} + cpu: [arm64] + os: [linux] + + '@rollup/rollup-linux-loong64-gnu@4.53.2': + resolution: {integrity: sha512-8ms8sjmyc1jWJS6WdNSA23rEfdjWB30LH8Wqj0Cqvv7qSHnvw6kgMMXRdop6hkmGPlyYBdRPkjJnj3KCUHV/uQ==} + cpu: [loong64] + os: [linux] + + '@rollup/rollup-linux-ppc64-gnu@4.53.2': + resolution: {integrity: sha512-3HRQLUQbpBDMmzoxPJYd3W6vrVHOo2cVW8RUo87Xz0JPJcBLBr5kZ1pGcQAhdZgX9VV7NbGNipah1omKKe23/g==} + cpu: [ppc64] + os: [linux] + + '@rollup/rollup-linux-riscv64-gnu@4.53.2': + resolution: {integrity: sha512-fMjKi+ojnmIvhk34gZP94vjogXNNUKMEYs+EDaB/5TG/wUkoeua7p7VCHnE6T2Tx+iaghAqQX8teQzcvrYpaQA==} + cpu: [riscv64] + os: [linux] + + '@rollup/rollup-linux-riscv64-musl@4.53.2': + resolution: {integrity: sha512-XuGFGU+VwUUV5kLvoAdi0Wz5Xbh2SrjIxCtZj6Wq8MDp4bflb/+ThZsVxokM7n0pcbkEr2h5/pzqzDYI7cCgLQ==} + cpu: [riscv64] + os: [linux] + + '@rollup/rollup-linux-s390x-gnu@4.53.2': + resolution: {integrity: sha512-w6yjZF0P+NGzWR3AXWX9zc0DNEGdtvykB03uhonSHMRa+oWA6novflo2WaJr6JZakG2ucsyb+rvhrKac6NIy+w==} + cpu: [s390x] + os: [linux] + + '@rollup/rollup-linux-x64-gnu@4.53.2': + resolution: {integrity: sha512-yo8d6tdfdeBArzC7T/PnHd7OypfI9cbuZzPnzLJIyKYFhAQ8SvlkKtKBMbXDxe1h03Rcr7u++nFS7tqXz87Gtw==} + cpu: [x64] + os: [linux] + + '@rollup/rollup-linux-x64-musl@4.53.2': + resolution: {integrity: sha512-ah59c1YkCxKExPP8O9PwOvs+XRLKwh/mV+3YdKqQ5AMQ0r4M4ZDuOrpWkUaqO7fzAHdINzV9tEVu8vNw48z0lA==} + cpu: [x64] + os: [linux] + + '@rollup/rollup-openharmony-arm64@4.53.2': + resolution: {integrity: sha512-4VEd19Wmhr+Zy7hbUsFZ6YXEiP48hE//KPLCSVNY5RMGX2/7HZ+QkN55a3atM1C/BZCGIgqN+xrVgtdak2S9+A==} + cpu: [arm64] + os: [openharmony] + + '@rollup/rollup-win32-arm64-msvc@4.53.2': + resolution: {integrity: sha512-IlbHFYc/pQCgew/d5fslcy1KEaYVCJ44G8pajugd8VoOEI8ODhtb/j8XMhLpwHCMB3yk2J07ctup10gpw2nyMA==} + cpu: [arm64] + os: [win32] + + '@rollup/rollup-win32-ia32-msvc@4.53.2': + resolution: {integrity: sha512-lNlPEGgdUfSzdCWU176ku/dQRnA7W+Gp8d+cWv73jYrb8uT7HTVVxq62DUYxjbaByuf1Yk0RIIAbDzp+CnOTFg==} + cpu: [ia32] + os: [win32] + + '@rollup/rollup-win32-x64-gnu@4.53.2': + resolution: {integrity: sha512-S6YojNVrHybQis2lYov1sd+uj7K0Q05NxHcGktuMMdIQ2VixGwAfbJ23NnlvvVV1bdpR2m5MsNBViHJKcA4ADw==} + cpu: [x64] + os: [win32] + + '@rollup/rollup-win32-x64-msvc@4.53.2': + resolution: {integrity: sha512-k+/Rkcyx//P6fetPoLMb8pBeqJBNGx81uuf7iljX9++yNBVRDQgD04L+SVXmXmh5ZP4/WOp4mWF0kmi06PW2tA==} + cpu: [x64] + os: [win32] + + '@rushstack/node-core-library@4.0.2': + resolution: {integrity: sha512-hyES82QVpkfQMeBMteQUnrhASL/KHPhd7iJ8euduwNJG4mu2GSOKybf0rOEjOm1Wz7CwJEUm9y0yD7jg2C1bfg==} + peerDependencies: + '@types/node': '*' + peerDependenciesMeta: + '@types/node': + optional: true + + '@rushstack/rig-package@0.5.2': + resolution: {integrity: sha512-mUDecIJeH3yYGZs2a48k+pbhM6JYwWlgjs2Ca5f2n1G2/kgdgP9D/07oglEGf6mRyXEnazhEENeYTSNDRCwdqA==} + + '@rushstack/terminal@0.10.0': + resolution: {integrity: sha512-UbELbXnUdc7EKwfH2sb8ChqNgapUOdqcCIdQP4NGxBpTZV2sQyeekuK3zmfQSa/MN+/7b4kBogl2wq0vpkpYGw==} + peerDependencies: + '@types/node': '*' + peerDependenciesMeta: + '@types/node': + optional: true + + '@rushstack/ts-command-line@4.19.1': + resolution: {integrity: sha512-J7H768dgcpG60d7skZ5uSSwyCZs/S2HrWP1Ds8d1qYAyaaeJmpmmLr9BVw97RjFzmQPOYnoXcKA4GkqDCkduQg==} + + '@types/argparse@1.0.38': + resolution: {integrity: sha512-ebDJ9b0e702Yr7pWgB0jzm+CX4Srzz8RcXtLJDJB+BSccqMa36uyH/zUsSYao5+BD1ytv3k3rPYCq4mAE1hsXA==} + + '@types/better-sqlite3@7.6.13': + resolution: {integrity: sha512-NMv9ASNARoKksWtsq/SHakpYAYnhBrQgGD8zkLYk/jaK8jUGn08CfEdTRgYhMypUQAfzSP8W6gNLe0q19/t4VA==} + + '@types/estree@1.0.8': + resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} + + '@types/node@24.10.1': + resolution: {integrity: sha512-GNWcUTRBgIRJD5zj+Tq0fKOJ5XZajIiBroOF0yvj2bSU1WvNdYS/dn9UxwsujGW4JX06dnHyjV2y9rRaybH0iQ==} + + '@types/ws@8.18.1': + resolution: {integrity: sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==} + + '@volar/language-core@1.11.1': + resolution: {integrity: sha512-dOcNn3i9GgZAcJt43wuaEykSluAuOkQgzni1cuxLxTV0nJKanQztp7FxyswdRILaKH+P2XZMPRp2S4MV/pElCw==} + + '@volar/source-map@1.11.1': + resolution: {integrity: sha512-hJnOnwZ4+WT5iupLRnuzbULZ42L7BWWPMmruzwtLhJfpDVoZLjNBxHDi2sY2bgZXCKlpU5XcsMFoYrsQmPhfZg==} + + '@volar/typescript@1.11.1': + resolution: {integrity: sha512-iU+t2mas/4lYierSnoFOeRFQUhAEMgsFuQxoxvwn5EdQopw43j+J27a4lt9LMInx1gLJBC6qL14WYGlgymaSMQ==} + + '@vue/compiler-core@3.5.24': + resolution: {integrity: sha512-eDl5H57AOpNakGNAkFDH+y7kTqrQpJkZFXhWZQGyx/5Wh7B1uQYvcWkvZi11BDhscPgj8N7XV3oRwiPnx1Vrig==} + + '@vue/compiler-dom@3.5.24': + resolution: {integrity: sha512-1QHGAvs53gXkWdd3ZMGYuvQFXHW4ksKWPG8HP8/2BscrbZ0brw183q2oNWjMrSWImYLHxHrx1ItBQr50I/q2zw==} + + '@vue/language-core@1.8.27': + resolution: {integrity: sha512-L8Kc27VdQserNaCUNiSFdDl9LWT24ly8Hpwf1ECy3aFb9m6bDhBGQYOujDm21N7EW3moKIOKEanQwe1q5BK+mA==} + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + + '@vue/shared@3.5.24': + resolution: {integrity: sha512-9cwHL2EsJBdi8NY22pngYYWzkTDhld6fAD6jlaeloNGciNSJL6bLpbxVgXl96X00Jtc6YWQv96YA/0sxex/k1A==} + + ajv@6.12.6: + resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} + + argparse@1.0.10: + resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==} + + balanced-match@1.0.2: + resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + + base64-js@1.5.1: + resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} + + better-sqlite3@12.4.1: + resolution: {integrity: sha512-3yVdyZhklTiNrtg+4WqHpJpFDd+WHTg2oM7UcR80GqL05AOV0xEJzc6qNvFYoEtE+hRp1n9MpN6/+4yhlGkDXQ==} + engines: {node: 20.x || 22.x || 23.x || 24.x} + + bindings@1.5.0: + resolution: {integrity: sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==} + + bl@4.1.0: + resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==} + + brace-expansion@1.1.12: + resolution: {integrity: sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==} + + brace-expansion@2.0.2: + resolution: {integrity: sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==} + + buffer@5.7.1: + resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==} + + chownr@1.1.4: + resolution: {integrity: sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==} + + commander@9.5.0: + resolution: {integrity: sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==} + engines: {node: ^12.20.0 || >=14} + + computeds@0.0.1: + resolution: {integrity: sha512-7CEBgcMjVmitjYo5q8JTJVra6X5mQ20uTThdK+0kR7UEaDrAWEQcRiBtWJzga4eRpP6afNwwLsX2SET2JhVB1Q==} + + concat-map@0.0.1: + resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + + de-indent@1.0.2: + resolution: {integrity: sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg==} + + debug@4.4.3: + resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + decompress-response@6.0.0: + resolution: {integrity: sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==} + engines: {node: '>=10'} + + deep-extend@0.6.0: + resolution: {integrity: sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==} + engines: {node: '>=4.0.0'} + + detect-libc@2.1.2: + resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} + engines: {node: '>=8'} + + end-of-stream@1.4.5: + resolution: {integrity: sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==} + + entities@4.5.0: + resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} + engines: {node: '>=0.12'} + + esbuild@0.21.5: + resolution: {integrity: sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==} + engines: {node: '>=12'} + hasBin: true + + estree-walker@2.0.2: + resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} + + expand-template@2.0.3: + resolution: {integrity: sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==} + engines: {node: '>=6'} + + fast-deep-equal@3.1.3: + resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} + + fast-json-stable-stringify@2.1.0: + resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} + + file-uri-to-path@1.0.0: + resolution: {integrity: sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==} + + fs-constants@1.0.0: + resolution: {integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==} + + fs-extra@7.0.1: + resolution: {integrity: sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==} + engines: {node: '>=6 <7 || >=8'} + + fsevents@2.3.3: + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + + function-bind@1.1.2: + resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + + github-from-package@0.0.0: + resolution: {integrity: sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==} + + graceful-fs@4.2.11: + resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + + has-flag@4.0.0: + resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} + engines: {node: '>=8'} + + hasown@2.0.2: + resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} + engines: {node: '>= 0.4'} + + he@1.2.0: + resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==} + hasBin: true + + ieee754@1.2.1: + resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} + + import-lazy@4.0.0: + resolution: {integrity: sha512-rKtvo6a868b5Hu3heneU+L4yEQ4jYKLtjpnPeUdK7h0yzXGmyBTypknlkCvHFBqfX9YlorEiMM6Dnq/5atfHkw==} + engines: {node: '>=8'} + + inherits@2.0.4: + resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + + ini@1.3.8: + resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==} + + is-core-module@2.16.1: + resolution: {integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==} + engines: {node: '>= 0.4'} + + jju@1.4.0: + resolution: {integrity: sha512-8wb9Yw966OSxApiCt0K3yNJL8pnNeIv+OEq2YMidz4FKP6nonSRoOXc80iXY4JaN2FC11B9qsNmDsm+ZOfMROA==} + + json-schema-traverse@0.4.1: + resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} + + jsonfile@4.0.0: + resolution: {integrity: sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==} + + kolorist@1.8.0: + resolution: {integrity: sha512-Y+60/zizpJ3HRH8DCss+q95yr6145JXZo46OTpFvDZWLfRCE4qChOyk1b26nMaNpfHHgxagk9dXT5OP0Tfe+dQ==} + + lodash.get@4.4.2: + resolution: {integrity: sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==} + deprecated: This package is deprecated. Use the optional chaining (?.) operator instead. + + lodash.isequal@4.5.0: + resolution: {integrity: sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==} + deprecated: This package is deprecated. Use require('node:util').isDeepStrictEqual instead. + + lodash@4.17.21: + resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} + + lru-cache@6.0.0: + resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} + engines: {node: '>=10'} + + magic-string@0.30.21: + resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} + + mimic-response@3.1.0: + resolution: {integrity: sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==} + engines: {node: '>=10'} + + minimatch@3.0.8: + resolution: {integrity: sha512-6FsRAQsxQ61mw+qP1ZzbL9Bc78x2p5OqNgNpnoAFLTrX8n5Kxph0CsnhmKKNXTWjXqU5L0pGPR7hYk+XWZr60Q==} + + minimatch@9.0.5: + resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} + engines: {node: '>=16 || 14 >=14.17'} + + minimist@1.2.8: + resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} + + mkdirp-classic@0.5.3: + resolution: {integrity: sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==} + + ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + + muggle-string@0.3.1: + resolution: {integrity: sha512-ckmWDJjphvd/FvZawgygcUeQCxzvohjFO5RxTjj4eq8kw359gFF3E1brjfI+viLMxss5JrHTDRHZvu2/tuy0Qg==} + + nanoid@3.3.11: + resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + + napi-build-utils@2.0.0: + resolution: {integrity: sha512-GEbrYkbfF7MoNaoh2iGG84Mnf/WZfB0GdGEsM8wz7Expx/LlWf5U8t9nvJKXSp3qr5IsEbK04cBGhol/KwOsWA==} + + node-abi@3.80.0: + resolution: {integrity: sha512-LyPuZJcI9HVwzXK1GPxWNzrr+vr8Hp/3UqlmWxxh8p54U1ZbclOqbSog9lWHaCX+dBaiGi6n/hIX+mKu74GmPA==} + engines: {node: '>=10'} + + once@1.4.0: + resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + + path-browserify@1.0.1: + resolution: {integrity: sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==} + + path-parse@1.0.7: + resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} + + picocolors@1.1.1: + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + + picomatch@4.0.3: + resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==} + engines: {node: '>=12'} + + postcss@8.5.6: + resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==} + engines: {node: ^10 || ^12 || >=14} + + prebuild-install@7.1.3: + resolution: {integrity: sha512-8Mf2cbV7x1cXPUILADGI3wuhfqWvtiLA1iclTDbFRZkgRQS0NqsPZphna9V+HyTEadheuPmjaJMsbzKQFOzLug==} + engines: {node: '>=10'} + hasBin: true + + pump@3.0.3: + resolution: {integrity: sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA==} + + punycode@2.3.1: + resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} + engines: {node: '>=6'} + + rc@1.2.8: + resolution: {integrity: sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==} + hasBin: true + + readable-stream@3.6.2: + resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} + engines: {node: '>= 6'} + + resolve@1.19.0: + resolution: {integrity: sha512-rArEXAgsBG4UgRGcynxWIWKFvh/XZCcS8UJdHhwy91zwAvCZIbcs+vAbflgBnNjYMs/i/i+/Ux6IZhML1yPvxg==} + + resolve@1.22.11: + resolution: {integrity: sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==} + engines: {node: '>= 0.4'} + hasBin: true + + rollup@4.53.2: + resolution: {integrity: sha512-MHngMYwGJVi6Fmnk6ISmnk7JAHRNF0UkuucA0CUW3N3a4KnONPEZz+vUanQP/ZC/iY1Qkf3bwPWzyY84wEks1g==} + engines: {node: '>=18.0.0', npm: '>=8.0.0'} + hasBin: true + + safe-buffer@5.2.1: + resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} + + semver@7.5.4: + resolution: {integrity: sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==} + engines: {node: '>=10'} + hasBin: true + + semver@7.7.3: + resolution: {integrity: sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==} + engines: {node: '>=10'} + hasBin: true + + simple-concat@1.0.1: + resolution: {integrity: sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==} + + simple-get@4.0.1: + resolution: {integrity: sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==} + + source-map-js@1.2.1: + resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} + engines: {node: '>=0.10.0'} + + source-map@0.6.1: + resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} + engines: {node: '>=0.10.0'} + + sprintf-js@1.0.3: + resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} + + string-argv@0.3.2: + resolution: {integrity: sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==} + engines: {node: '>=0.6.19'} + + string_decoder@1.3.0: + resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} + + strip-json-comments@2.0.1: + resolution: {integrity: sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==} + engines: {node: '>=0.10.0'} + + strip-json-comments@3.1.1: + resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} + engines: {node: '>=8'} + + supports-color@8.1.1: + resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} + engines: {node: '>=10'} + + supports-preserve-symlinks-flag@1.0.0: + resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} + engines: {node: '>= 0.4'} + + tar-fs@2.1.4: + resolution: {integrity: sha512-mDAjwmZdh7LTT6pNleZ05Yt65HC3E+NiQzl672vQG38jIrehtJk/J3mNwIg+vShQPcLF/LV7CMnDW6vjj6sfYQ==} + + tar-stream@2.2.0: + resolution: {integrity: sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==} + engines: {node: '>=6'} + + tunnel-agent@0.6.0: + resolution: {integrity: sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==} + + typescript@5.4.2: + resolution: {integrity: sha512-+2/g0Fds1ERlP6JsakQQDXjZdZMM+rqpamFZJEKh4kwTIn3iDkgKtby0CeNd5ATNZ4Ry1ax15TMx0W2V+miizQ==} + engines: {node: '>=14.17'} + hasBin: true + + typescript@5.9.3: + resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} + engines: {node: '>=14.17'} + hasBin: true + + undici-types@7.16.0: + resolution: {integrity: sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==} + + universalify@0.1.2: + resolution: {integrity: sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==} + engines: {node: '>= 4.0.0'} + + uri-js@4.4.1: + resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + + util-deprecate@1.0.2: + resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + + validator@13.15.23: + resolution: {integrity: sha512-4yoz1kEWqUjzi5zsPbAS/903QXSYp0UOtHsPpp7p9rHAw/W+dkInskAE386Fat3oKRROwO98d9ZB0G4cObgUyw==} + engines: {node: '>= 0.10'} + + vite-plugin-dts@3.9.1: + resolution: {integrity: sha512-rVp2KM9Ue22NGWB8dNtWEr+KekN3rIgz1tWD050QnRGlriUCmaDwa7qA5zDEjbXg5lAXhYMSBJtx3q3hQIJZSg==} + engines: {node: ^14.18.0 || >=16.0.0} + peerDependencies: + typescript: '*' + vite: '*' + peerDependenciesMeta: + vite: + optional: true + + vite@5.4.21: + resolution: {integrity: sha512-o5a9xKjbtuhY6Bi5S3+HvbRERmouabWbyUcpXXUA1u+GNUKoROi9byOJ8M0nHbHYHkYICiMlqxkg1KkYmm25Sw==} + engines: {node: ^18.0.0 || >=20.0.0} + hasBin: true + peerDependencies: + '@types/node': ^18.0.0 || >=20.0.0 + less: '*' + lightningcss: ^1.21.0 + sass: '*' + sass-embedded: '*' + stylus: '*' + sugarss: '*' + terser: ^5.4.0 + peerDependenciesMeta: + '@types/node': + optional: true + less: + optional: true + lightningcss: + optional: true + sass: + optional: true + sass-embedded: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + + vue-template-compiler@2.7.16: + resolution: {integrity: sha512-AYbUWAJHLGGQM7+cNTELw+KsOG9nl2CnSv467WobS5Cv9uk3wFcnr1Etsz2sEIHEZvw1U+o9mRlEO6QbZvUPGQ==} + + vue-tsc@1.8.27: + resolution: {integrity: sha512-WesKCAZCRAbmmhuGl3+VrdWItEvfoFIPXOvUJkjULi+x+6G/Dy69yO3TBRJDr9eUlmsNAwVmxsNZxvHKzbkKdg==} + hasBin: true + peerDependencies: + typescript: '*' + + wrappy@1.0.2: + resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + + ws@8.18.3: + resolution: {integrity: sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==} + 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 + + yallist@4.0.0: + resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} + + z-schema@5.0.5: + resolution: {integrity: sha512-D7eujBWkLa3p2sIpJA0d1pr7es+a7m0vFAnZLlCEKq/Ij2k0MLi9Br2UPxoxdYystm5K1yeBGzub0FlYUEWj2Q==} + engines: {node: '>=8.0.0'} + hasBin: true + +snapshots: + + '@babel/helper-string-parser@7.27.1': {} + + '@babel/helper-validator-identifier@7.28.5': {} + + '@babel/parser@7.28.5': + dependencies: + '@babel/types': 7.28.5 + + '@babel/types@7.28.5': + dependencies: + '@babel/helper-string-parser': 7.27.1 + '@babel/helper-validator-identifier': 7.28.5 + + '@esbuild/aix-ppc64@0.21.5': + optional: true + + '@esbuild/android-arm64@0.21.5': + optional: true + + '@esbuild/android-arm@0.21.5': + optional: true + + '@esbuild/android-x64@0.21.5': + optional: true + + '@esbuild/darwin-arm64@0.21.5': + optional: true + + '@esbuild/darwin-x64@0.21.5': + optional: true + + '@esbuild/freebsd-arm64@0.21.5': + optional: true + + '@esbuild/freebsd-x64@0.21.5': + optional: true + + '@esbuild/linux-arm64@0.21.5': + optional: true + + '@esbuild/linux-arm@0.21.5': + optional: true + + '@esbuild/linux-ia32@0.21.5': + optional: true + + '@esbuild/linux-loong64@0.21.5': + optional: true + + '@esbuild/linux-mips64el@0.21.5': + optional: true + + '@esbuild/linux-ppc64@0.21.5': + optional: true + + '@esbuild/linux-riscv64@0.21.5': + optional: true + + '@esbuild/linux-s390x@0.21.5': + optional: true + + '@esbuild/linux-x64@0.21.5': + optional: true + + '@esbuild/netbsd-x64@0.21.5': + optional: true + + '@esbuild/openbsd-x64@0.21.5': + optional: true + + '@esbuild/sunos-x64@0.21.5': + optional: true + + '@esbuild/win32-arm64@0.21.5': + optional: true + + '@esbuild/win32-ia32@0.21.5': + optional: true + + '@esbuild/win32-x64@0.21.5': + optional: true + + '@jridgewell/sourcemap-codec@1.5.5': {} + + '@microsoft/api-extractor-model@7.28.13(@types/node@24.10.1)': + dependencies: + '@microsoft/tsdoc': 0.14.2 + '@microsoft/tsdoc-config': 0.16.2 + '@rushstack/node-core-library': 4.0.2(@types/node@24.10.1) + transitivePeerDependencies: + - '@types/node' + + '@microsoft/api-extractor@7.43.0(@types/node@24.10.1)': + dependencies: + '@microsoft/api-extractor-model': 7.28.13(@types/node@24.10.1) + '@microsoft/tsdoc': 0.14.2 + '@microsoft/tsdoc-config': 0.16.2 + '@rushstack/node-core-library': 4.0.2(@types/node@24.10.1) + '@rushstack/rig-package': 0.5.2 + '@rushstack/terminal': 0.10.0(@types/node@24.10.1) + '@rushstack/ts-command-line': 4.19.1(@types/node@24.10.1) + lodash: 4.17.21 + minimatch: 3.0.8 + resolve: 1.22.11 + semver: 7.5.4 + source-map: 0.6.1 + typescript: 5.4.2 + transitivePeerDependencies: + - '@types/node' + + '@microsoft/tsdoc-config@0.16.2': + dependencies: + '@microsoft/tsdoc': 0.14.2 + ajv: 6.12.6 + jju: 1.4.0 + resolve: 1.19.0 + + '@microsoft/tsdoc@0.14.2': {} + + '@rollup/pluginutils@5.3.0(rollup@4.53.2)': + dependencies: + '@types/estree': 1.0.8 + estree-walker: 2.0.2 + picomatch: 4.0.3 + optionalDependencies: + rollup: 4.53.2 + + '@rollup/rollup-android-arm-eabi@4.53.2': + optional: true + + '@rollup/rollup-android-arm64@4.53.2': + optional: true + + '@rollup/rollup-darwin-arm64@4.53.2': + optional: true + + '@rollup/rollup-darwin-x64@4.53.2': + optional: true + + '@rollup/rollup-freebsd-arm64@4.53.2': + optional: true + + '@rollup/rollup-freebsd-x64@4.53.2': + optional: true + + '@rollup/rollup-linux-arm-gnueabihf@4.53.2': + optional: true + + '@rollup/rollup-linux-arm-musleabihf@4.53.2': + optional: true + + '@rollup/rollup-linux-arm64-gnu@4.53.2': + optional: true + + '@rollup/rollup-linux-arm64-musl@4.53.2': + optional: true + + '@rollup/rollup-linux-loong64-gnu@4.53.2': + optional: true + + '@rollup/rollup-linux-ppc64-gnu@4.53.2': + optional: true + + '@rollup/rollup-linux-riscv64-gnu@4.53.2': + optional: true + + '@rollup/rollup-linux-riscv64-musl@4.53.2': + optional: true + + '@rollup/rollup-linux-s390x-gnu@4.53.2': + optional: true + + '@rollup/rollup-linux-x64-gnu@4.53.2': + optional: true + + '@rollup/rollup-linux-x64-musl@4.53.2': + optional: true + + '@rollup/rollup-openharmony-arm64@4.53.2': + optional: true + + '@rollup/rollup-win32-arm64-msvc@4.53.2': + optional: true + + '@rollup/rollup-win32-ia32-msvc@4.53.2': + optional: true + + '@rollup/rollup-win32-x64-gnu@4.53.2': + optional: true + + '@rollup/rollup-win32-x64-msvc@4.53.2': + optional: true + + '@rushstack/node-core-library@4.0.2(@types/node@24.10.1)': + dependencies: + fs-extra: 7.0.1 + import-lazy: 4.0.0 + jju: 1.4.0 + resolve: 1.22.11 + semver: 7.5.4 + z-schema: 5.0.5 + optionalDependencies: + '@types/node': 24.10.1 + + '@rushstack/rig-package@0.5.2': + dependencies: + resolve: 1.22.11 + strip-json-comments: 3.1.1 + + '@rushstack/terminal@0.10.0(@types/node@24.10.1)': + dependencies: + '@rushstack/node-core-library': 4.0.2(@types/node@24.10.1) + supports-color: 8.1.1 + optionalDependencies: + '@types/node': 24.10.1 + + '@rushstack/ts-command-line@4.19.1(@types/node@24.10.1)': + dependencies: + '@rushstack/terminal': 0.10.0(@types/node@24.10.1) + '@types/argparse': 1.0.38 + argparse: 1.0.10 + string-argv: 0.3.2 + transitivePeerDependencies: + - '@types/node' + + '@types/argparse@1.0.38': {} + + '@types/better-sqlite3@7.6.13': + dependencies: + '@types/node': 24.10.1 + + '@types/estree@1.0.8': {} + + '@types/node@24.10.1': + dependencies: + undici-types: 7.16.0 + + '@types/ws@8.18.1': + dependencies: + '@types/node': 24.10.1 + + '@volar/language-core@1.11.1': + dependencies: + '@volar/source-map': 1.11.1 + + '@volar/source-map@1.11.1': + dependencies: + muggle-string: 0.3.1 + + '@volar/typescript@1.11.1': + dependencies: + '@volar/language-core': 1.11.1 + path-browserify: 1.0.1 + + '@vue/compiler-core@3.5.24': + dependencies: + '@babel/parser': 7.28.5 + '@vue/shared': 3.5.24 + entities: 4.5.0 + estree-walker: 2.0.2 + source-map-js: 1.2.1 + + '@vue/compiler-dom@3.5.24': + dependencies: + '@vue/compiler-core': 3.5.24 + '@vue/shared': 3.5.24 + + '@vue/language-core@1.8.27(typescript@5.9.3)': + dependencies: + '@volar/language-core': 1.11.1 + '@volar/source-map': 1.11.1 + '@vue/compiler-dom': 3.5.24 + '@vue/shared': 3.5.24 + computeds: 0.0.1 + minimatch: 9.0.5 + muggle-string: 0.3.1 + path-browserify: 1.0.1 + vue-template-compiler: 2.7.16 + optionalDependencies: + typescript: 5.9.3 + + '@vue/shared@3.5.24': {} + + ajv@6.12.6: + dependencies: + fast-deep-equal: 3.1.3 + fast-json-stable-stringify: 2.1.0 + json-schema-traverse: 0.4.1 + uri-js: 4.4.1 + + argparse@1.0.10: + dependencies: + sprintf-js: 1.0.3 + + balanced-match@1.0.2: {} + + base64-js@1.5.1: {} + + better-sqlite3@12.4.1: + dependencies: + bindings: 1.5.0 + prebuild-install: 7.1.3 + + bindings@1.5.0: + dependencies: + file-uri-to-path: 1.0.0 + + bl@4.1.0: + dependencies: + buffer: 5.7.1 + inherits: 2.0.4 + readable-stream: 3.6.2 + + brace-expansion@1.1.12: + dependencies: + balanced-match: 1.0.2 + concat-map: 0.0.1 + + brace-expansion@2.0.2: + dependencies: + balanced-match: 1.0.2 + + buffer@5.7.1: + dependencies: + base64-js: 1.5.1 + ieee754: 1.2.1 + + chownr@1.1.4: {} + + commander@9.5.0: + optional: true + + computeds@0.0.1: {} + + concat-map@0.0.1: {} + + de-indent@1.0.2: {} + + debug@4.4.3: + dependencies: + ms: 2.1.3 + + decompress-response@6.0.0: + dependencies: + mimic-response: 3.1.0 + + deep-extend@0.6.0: {} + + detect-libc@2.1.2: {} + + end-of-stream@1.4.5: + dependencies: + once: 1.4.0 + + entities@4.5.0: {} + + esbuild@0.21.5: + optionalDependencies: + '@esbuild/aix-ppc64': 0.21.5 + '@esbuild/android-arm': 0.21.5 + '@esbuild/android-arm64': 0.21.5 + '@esbuild/android-x64': 0.21.5 + '@esbuild/darwin-arm64': 0.21.5 + '@esbuild/darwin-x64': 0.21.5 + '@esbuild/freebsd-arm64': 0.21.5 + '@esbuild/freebsd-x64': 0.21.5 + '@esbuild/linux-arm': 0.21.5 + '@esbuild/linux-arm64': 0.21.5 + '@esbuild/linux-ia32': 0.21.5 + '@esbuild/linux-loong64': 0.21.5 + '@esbuild/linux-mips64el': 0.21.5 + '@esbuild/linux-ppc64': 0.21.5 + '@esbuild/linux-riscv64': 0.21.5 + '@esbuild/linux-s390x': 0.21.5 + '@esbuild/linux-x64': 0.21.5 + '@esbuild/netbsd-x64': 0.21.5 + '@esbuild/openbsd-x64': 0.21.5 + '@esbuild/sunos-x64': 0.21.5 + '@esbuild/win32-arm64': 0.21.5 + '@esbuild/win32-ia32': 0.21.5 + '@esbuild/win32-x64': 0.21.5 + + estree-walker@2.0.2: {} + + expand-template@2.0.3: {} + + fast-deep-equal@3.1.3: {} + + fast-json-stable-stringify@2.1.0: {} + + file-uri-to-path@1.0.0: {} + + fs-constants@1.0.0: {} + + fs-extra@7.0.1: + dependencies: + graceful-fs: 4.2.11 + jsonfile: 4.0.0 + universalify: 0.1.2 + + fsevents@2.3.3: + optional: true + + function-bind@1.1.2: {} + + github-from-package@0.0.0: {} + + graceful-fs@4.2.11: {} + + has-flag@4.0.0: {} + + hasown@2.0.2: + dependencies: + function-bind: 1.1.2 + + he@1.2.0: {} + + ieee754@1.2.1: {} + + import-lazy@4.0.0: {} + + inherits@2.0.4: {} + + ini@1.3.8: {} + + is-core-module@2.16.1: + dependencies: + hasown: 2.0.2 + + jju@1.4.0: {} + + json-schema-traverse@0.4.1: {} + + jsonfile@4.0.0: + optionalDependencies: + graceful-fs: 4.2.11 + + kolorist@1.8.0: {} + + lodash.get@4.4.2: {} + + lodash.isequal@4.5.0: {} + + lodash@4.17.21: {} + + lru-cache@6.0.0: + dependencies: + yallist: 4.0.0 + + magic-string@0.30.21: + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + + mimic-response@3.1.0: {} + + minimatch@3.0.8: + dependencies: + brace-expansion: 1.1.12 + + minimatch@9.0.5: + dependencies: + brace-expansion: 2.0.2 + + minimist@1.2.8: {} + + mkdirp-classic@0.5.3: {} + + ms@2.1.3: {} + + muggle-string@0.3.1: {} + + nanoid@3.3.11: {} + + napi-build-utils@2.0.0: {} + + node-abi@3.80.0: + dependencies: + semver: 7.7.3 + + once@1.4.0: + dependencies: + wrappy: 1.0.2 + + path-browserify@1.0.1: {} + + path-parse@1.0.7: {} + + picocolors@1.1.1: {} + + picomatch@4.0.3: {} + + postcss@8.5.6: + dependencies: + nanoid: 3.3.11 + picocolors: 1.1.1 + source-map-js: 1.2.1 + + prebuild-install@7.1.3: + dependencies: + detect-libc: 2.1.2 + expand-template: 2.0.3 + github-from-package: 0.0.0 + minimist: 1.2.8 + mkdirp-classic: 0.5.3 + napi-build-utils: 2.0.0 + node-abi: 3.80.0 + pump: 3.0.3 + rc: 1.2.8 + simple-get: 4.0.1 + tar-fs: 2.1.4 + tunnel-agent: 0.6.0 + + pump@3.0.3: + dependencies: + end-of-stream: 1.4.5 + once: 1.4.0 + + punycode@2.3.1: {} + + rc@1.2.8: + dependencies: + deep-extend: 0.6.0 + ini: 1.3.8 + minimist: 1.2.8 + strip-json-comments: 2.0.1 + + readable-stream@3.6.2: + dependencies: + inherits: 2.0.4 + string_decoder: 1.3.0 + util-deprecate: 1.0.2 + + resolve@1.19.0: + dependencies: + is-core-module: 2.16.1 + path-parse: 1.0.7 + + resolve@1.22.11: + dependencies: + is-core-module: 2.16.1 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + + rollup@4.53.2: + dependencies: + '@types/estree': 1.0.8 + optionalDependencies: + '@rollup/rollup-android-arm-eabi': 4.53.2 + '@rollup/rollup-android-arm64': 4.53.2 + '@rollup/rollup-darwin-arm64': 4.53.2 + '@rollup/rollup-darwin-x64': 4.53.2 + '@rollup/rollup-freebsd-arm64': 4.53.2 + '@rollup/rollup-freebsd-x64': 4.53.2 + '@rollup/rollup-linux-arm-gnueabihf': 4.53.2 + '@rollup/rollup-linux-arm-musleabihf': 4.53.2 + '@rollup/rollup-linux-arm64-gnu': 4.53.2 + '@rollup/rollup-linux-arm64-musl': 4.53.2 + '@rollup/rollup-linux-loong64-gnu': 4.53.2 + '@rollup/rollup-linux-ppc64-gnu': 4.53.2 + '@rollup/rollup-linux-riscv64-gnu': 4.53.2 + '@rollup/rollup-linux-riscv64-musl': 4.53.2 + '@rollup/rollup-linux-s390x-gnu': 4.53.2 + '@rollup/rollup-linux-x64-gnu': 4.53.2 + '@rollup/rollup-linux-x64-musl': 4.53.2 + '@rollup/rollup-openharmony-arm64': 4.53.2 + '@rollup/rollup-win32-arm64-msvc': 4.53.2 + '@rollup/rollup-win32-ia32-msvc': 4.53.2 + '@rollup/rollup-win32-x64-gnu': 4.53.2 + '@rollup/rollup-win32-x64-msvc': 4.53.2 + fsevents: 2.3.3 + + safe-buffer@5.2.1: {} + + semver@7.5.4: + dependencies: + lru-cache: 6.0.0 + + semver@7.7.3: {} + + simple-concat@1.0.1: {} + + simple-get@4.0.1: + dependencies: + decompress-response: 6.0.0 + once: 1.4.0 + simple-concat: 1.0.1 + + source-map-js@1.2.1: {} + + source-map@0.6.1: {} + + sprintf-js@1.0.3: {} + + string-argv@0.3.2: {} + + string_decoder@1.3.0: + dependencies: + safe-buffer: 5.2.1 + + strip-json-comments@2.0.1: {} + + strip-json-comments@3.1.1: {} + + supports-color@8.1.1: + dependencies: + has-flag: 4.0.0 + + supports-preserve-symlinks-flag@1.0.0: {} + + tar-fs@2.1.4: + dependencies: + chownr: 1.1.4 + mkdirp-classic: 0.5.3 + pump: 3.0.3 + tar-stream: 2.2.0 + + tar-stream@2.2.0: + dependencies: + bl: 4.1.0 + end-of-stream: 1.4.5 + fs-constants: 1.0.0 + inherits: 2.0.4 + readable-stream: 3.6.2 + + tunnel-agent@0.6.0: + dependencies: + safe-buffer: 5.2.1 + + typescript@5.4.2: {} + + typescript@5.9.3: {} + + undici-types@7.16.0: {} + + universalify@0.1.2: {} + + uri-js@4.4.1: + dependencies: + punycode: 2.3.1 + + util-deprecate@1.0.2: {} + + validator@13.15.23: {} + + vite-plugin-dts@3.9.1(@types/node@24.10.1)(rollup@4.53.2)(typescript@5.9.3)(vite@5.4.21(@types/node@24.10.1)): + dependencies: + '@microsoft/api-extractor': 7.43.0(@types/node@24.10.1) + '@rollup/pluginutils': 5.3.0(rollup@4.53.2) + '@vue/language-core': 1.8.27(typescript@5.9.3) + debug: 4.4.3 + kolorist: 1.8.0 + magic-string: 0.30.21 + typescript: 5.9.3 + vue-tsc: 1.8.27(typescript@5.9.3) + optionalDependencies: + vite: 5.4.21(@types/node@24.10.1) + transitivePeerDependencies: + - '@types/node' + - rollup + - supports-color + + vite@5.4.21(@types/node@24.10.1): + dependencies: + esbuild: 0.21.5 + postcss: 8.5.6 + rollup: 4.53.2 + optionalDependencies: + '@types/node': 24.10.1 + fsevents: 2.3.3 + + vue-template-compiler@2.7.16: + dependencies: + de-indent: 1.0.2 + he: 1.2.0 + + vue-tsc@1.8.27(typescript@5.9.3): + dependencies: + '@volar/typescript': 1.11.1 + '@vue/language-core': 1.8.27(typescript@5.9.3) + semver: 7.7.3 + typescript: 5.9.3 + + wrappy@1.0.2: {} + + ws@8.18.3: {} + + yallist@4.0.0: {} + + z-schema@5.0.5: + dependencies: + lodash.get: 4.4.2 + lodash.isequal: 4.5.0 + validator: 13.15.23 + optionalDependencies: + commander: 9.5.0 diff --git a/runagent-ts/runagent-0.1.26.tgz b/runagent-ts/runagent-0.1.26.tgz new file mode 100644 index 0000000..47815bb Binary files /dev/null and b/runagent-ts/runagent-0.1.26.tgz differ diff --git a/runagent-ts/src/client/index.ts b/runagent-ts/src/client/index.ts index 6e1c82e..0dad822 100644 --- a/runagent-ts/src/client/index.ts +++ b/runagent-ts/src/client/index.ts @@ -1,8 +1,8 @@ -declare const __IS_NODE__: boolean; -declare const __IS_BROWSER__: boolean; +declare const __IS_NODE__: boolean | undefined; +declare const __IS_BROWSER__: boolean | undefined; -const isNode = __IS_NODE__; -const isBrowser = __IS_BROWSER__; +const isNode = Boolean(__IS_NODE__); +const isBrowser = Boolean(__IS_BROWSER__); import { RestClient } from '../rest/index.js'; import { BrowserWebSocketClient } from '../websocket/browser.js'; @@ -13,65 +13,120 @@ import type { AgentArchitecture, JsonValue, } from '../types/index.js'; -import { RunAgentRegistry } from '../database/index.js'; - -// Environment detection -// const isNode = (() => { -// try { -// return ( -// typeof process !== 'undefined' && -// typeof process.versions !== 'undefined' && -// typeof process.versions.node !== 'undefined' -// ); -// } catch { -// return false; -// } -// })(); - -// const isBrowser = (() => { -// try { -// // eslint-disable-next-line @typescript-eslint/no-explicit-any -// return typeof (globalThis as any).window !== 'undefined'; -// } catch { -// return false; -// } -// })(); +import type { RunAgentRegistry } from '../database/index.js'; type WebSocketClientType = BrowserWebSocketClient | NodeWebSocketClient; +const DEFAULT_REMOTE_BASE_URL = 'https://backend.run-agent.ai'; +const DEFAULT_API_PREFIX = '/api/v1'; +const DEFAULT_TIMEOUT_SECONDS = 300; +const API_KEY_ENV = 'RUNAGENT_API_KEY'; +const BASE_URL_ENV = 'RUNAGENT_BASE_URL'; + +interface ClientEndpoints { + restBaseUrl: string; + socketBaseUrl: string; + apiPrefix: string; + isLocal: boolean; +} + +const sanitizeBaseUrl = (baseUrl: string): string => + baseUrl.replace(/\/$/, ''); + +const toWebSocketBase = (baseUrl: string): string => { + if (baseUrl.startsWith('wss://') || baseUrl.startsWith('ws://')) { + return sanitizeBaseUrl(baseUrl); + } + if (baseUrl.startsWith('https://')) { + return sanitizeBaseUrl(baseUrl.replace(/^https:\/\//, 'wss://')); + } + if (baseUrl.startsWith('http://')) { + return sanitizeBaseUrl(baseUrl.replace(/^http:\/\//, 'ws://')); + } + return `wss://${sanitizeBaseUrl(baseUrl)}`; +}; + +const getEnvVar = (name: string): string | undefined => { + try { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const globalProcessEnv = (globalThis as any)?.process?.env; + if (globalProcessEnv && typeof globalProcessEnv[name] === 'string') { + return globalProcessEnv[name] as string; + } + } catch { + // Ignore environment probing errors + } + + try { + // Allow browser builds to inject env via globalThis.RUNAGENT_ENV + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const runtimeEnv = (globalThis as any)?.RUNAGENT_ENV; + if (runtimeEnv && typeof runtimeEnv[name] === 'string') { + return runtimeEnv[name] as string; + } + } catch { + // Ignore missing global object + } + + return undefined; +}; + export class RunAgentClient { private serializer: CoreSerializer; private local: boolean; private agentId: string; private entrypointTag: string; - private config: RunAgentConfig; // Store original config - // private apiKey?: string; - private restClient!: RestClient; // Will be initialized in initialize() - private socketClient!: WebSocketClientType; // Will be initialized in initialize() + private config: RunAgentConfig; + private restClient?: RestClient; + private socketClient?: WebSocketClientType; private agentArchitecture?: AgentArchitecture; private static registry: RunAgentRegistry | null = null; - private static registryInitialized: boolean = false; + private static registryInitialized = false; + private initialized = false; + private apiKey?: string; + private baseUrl?: string; + private baseSocketUrl?: string; + private timeoutSeconds: number; + private extraParams?: Record; + private enableRegistry: boolean; - /** - * Get or create registry instance (Node.js only) - */ - private static async getRegistry(): Promise { - if (isBrowser) { - return null; // Registry not available in browser + constructor(config: RunAgentConfig) { + this.serializer = new CoreSerializer(); + this.config = config; + this.agentId = config.agentId; + this.entrypointTag = config.entrypointTag; + this.local = config.local ?? false; + this.timeoutSeconds = config.timeoutSeconds ?? DEFAULT_TIMEOUT_SECONDS; + this.extraParams = config.extraParams; + this.enableRegistry = config.enableRegistry ?? isNode; + + this.apiKey = config.apiKey ?? getEnvVar(API_KEY_ENV); + this.baseUrl = config.baseUrl ?? getEnvVar(BASE_URL_ENV); + this.baseSocketUrl = config.baseSocketUrl; + + if (!this.baseUrl && !this.local) { + this.baseUrl = DEFAULT_REMOTE_BASE_URL; + } + } + + // ------------------------------------------------------------------ + // Initialization helpers + // ------------------------------------------------------------------ + + private static async getRegistry( + enableRegistry: boolean + ): Promise { + if (!enableRegistry || !isNode) { + return null; } if (!this.registry && !this.registryInitialized) { try { - // Check if registry features are available - const isAvailable = await RunAgentRegistry.isAvailable(); - if (isAvailable) { + const { RunAgentRegistry } = await import('../database/index.js'); + const available = await RunAgentRegistry.isAvailable(); + if (available) { this.registry = new RunAgentRegistry(); await this.registry.initialize(); - console.log('🗃️ Agent registry initialized successfully'); - } else { - console.log( - '📋 Agent registry unavailable (better-sqlite3 not installed)' - ); } } catch (error) { console.warn('📋 Failed to initialize agent registry:', error); @@ -83,14 +138,11 @@ export class RunAgentClient { return this.registry; } - /** - * Try to lookup agent in registry, with graceful fallback - */ private async lookupAgent( agentId: string ): Promise<{ host: string; port: number } | null> { try { - const registry = await RunAgentClient.getRegistry(); + const registry = await RunAgentClient.getRegistry(this.enableRegistry); if (registry) { return registry.lookupAgent(agentId); } @@ -100,77 +152,112 @@ export class RunAgentClient { return null; } - constructor(config: RunAgentConfig) { - this.serializer = new CoreSerializer(); - this.local = config.local ?? false; - this.agentId = config.agentId; - this.entrypointTag = config.entrypointTag; - this.config = config; // Store original config - // this.apiKey = config.apiKey; + private initializeClients(endpoints: ClientEndpoints): void { + this.restClient = new RestClient({ + baseUrl: endpoints.restBaseUrl, + apiKey: endpoints.isLocal ? undefined : this.apiKey, + apiPrefix: endpoints.apiPrefix, + isLocal: endpoints.isLocal, + timeoutSeconds: this.timeoutSeconds, + }); - if (!this.local) { - throw new Error( - 'Non-local (remote) RunAgent deployment is not available yet. Coming soon.' - ); - } + const socketConfig = { + baseSocketUrl: endpoints.socketBaseUrl, + apiKey: endpoints.isLocal ? undefined : this.apiKey, + apiPrefix: endpoints.apiPrefix, + isLocal: endpoints.isLocal, + timeoutSeconds: this.timeoutSeconds, + }; + + this.socketClient = isNode + ? new NodeWebSocketClient(socketConfig) + : new BrowserWebSocketClient(socketConfig); + } - // For browser, initialize clients immediately if host/port provided - if (isBrowser && config.host && config.port) { - this.initializeClients(config.host, config.port); + private async ensureInitialized(): Promise { + if (!this.initialized) { + await this.initialize(); } } async initialize(): Promise { - // Step 1: Determine connection details - let agentHost: string; - let agentPort: number; + if (this.initialized) { + return this; + } - if (isBrowser) { - // Browser: host + port are mandatory for local mode - if (!this.config.host || !this.config.port) { - throw new Error( - "For browser environments, both 'host' and 'port' are required when local=true" + const apiPrefix = this.config.apiPrefix ?? DEFAULT_API_PREFIX; + + if (this.local) { + const resolved = await this.resolveLocalConnection(); + this.initializeClients({ + restBaseUrl: resolved.baseUrl, + socketBaseUrl: resolved.socketBaseUrl, + apiPrefix, + isLocal: true, + }); + } else { + const resolvedBaseUrl = sanitizeBaseUrl( + this.baseUrl ?? DEFAULT_REMOTE_BASE_URL + ); + let socketBaseUrl = sanitizeBaseUrl( + this.baseSocketUrl ?? toWebSocketBase(resolvedBaseUrl) + ); + + if (socketBaseUrl.endsWith(apiPrefix)) { + socketBaseUrl = sanitizeBaseUrl( + socketBaseUrl.slice(0, socketBaseUrl.length - apiPrefix.length) ); } - agentHost = this.config.host; - agentPort = this.config.port; - console.log(`🌐 Browser mode - connecting to: ${agentHost}:${agentPort}`); - // Initialize clients if not already done - if (!this.restClient) { - this.initializeClients(agentHost, agentPort); + if (!socketBaseUrl) { + socketBaseUrl = toWebSocketBase(resolvedBaseUrl); } - } else { - // Node.js: support both direct connection and agent discovery - if (this.config.host && this.config.port) { - // Direct connection mode - agentHost = this.config.host; - agentPort = this.config.port; - console.log(`🔌 Direct connection: ${agentHost}:${agentPort}`); - } else { - // Try agent discovery first - const agentInfo = await this.lookupAgent(this.agentId); - - if (agentInfo) { - agentHost = agentInfo.host; - agentPort = agentInfo.port; - console.log( - `🔍 Discovered agent ${this.agentId}: ${agentHost}:${agentPort}` - ); - } else { - // No registry lookup successful - require explicit config - throw new Error( - `Failed to discover agent ${this.agentId}. ` + - `Please provide explicit 'host' and 'port' in config, or ensure agent is registered.` - ); - } + + this.initializeClients({ + restBaseUrl: resolvedBaseUrl, + socketBaseUrl, + apiPrefix, + isLocal: false, + }); + } + + await this.loadAgentMetadata(); + this.initialized = true; + return this; + } + + private async resolveLocalConnection(): Promise<{ + baseUrl: string; + socketBaseUrl: string; + }> { + let host = this.config.host; + let port = this.config.port; + + if (!host || !port) { + const info = await this.lookupAgent(this.agentId); + if (info) { + host = info.host; + port = info.port; } + } - // Initialize clients - this.initializeClients(agentHost, agentPort); + if (!host || !port) { + throw new Error( + `Unable to determine host/port for local agent ${this.agentId}. ` + + `Provide 'host' and 'port' in RunAgentClient config or register the agent locally.` + ); } - // Step 2: Get agent architecture + const baseUrl = sanitizeBaseUrl(`http://${host}:${port}`); + const socketBaseUrl = sanitizeBaseUrl(`ws://${host}:${port}`); + + return { baseUrl, socketBaseUrl }; + } + + private async loadAgentMetadata(): Promise { + if (!this.restClient) { + throw new Error('REST client not initialized'); + } try { this.agentArchitecture = await this.restClient.getAgentArchitecture( this.agentId @@ -185,47 +272,62 @@ export class RunAgentClient { `Entrypoint \`${this.entrypointTag}\` not found in agent ${this.agentId}` ); } - - console.log(`✅ Agent ${this.agentId} initialized successfully`); - return this; } catch (error) { console.error('❌ Failed to initialize agent:', error); throw error; } } - /** - * Initialize REST and WebSocket clients - */ - private initializeClients(host: string, port: number): void { - const agentBaseUrl = `http://${host}:${port}`; - const agentSocketUrl = `ws://${host}:${port}`; + // ------------------------------------------------------------------ + // Public execution methods + // ------------------------------------------------------------------ - this.restClient = new RestClient({ - baseUrl: agentBaseUrl, - apiPrefix: '/api/v1', - }); + async run( + inputKwargs: Record = {} + ): Promise { + await this.ensureInitialized(); - if (isNode) { - this.socketClient = new NodeWebSocketClient({ - baseSocketUrl: agentSocketUrl, - apiPrefix: '/api/v1', - }); - } else { - this.socketClient = new BrowserWebSocketClient({ - baseSocketUrl: agentSocketUrl, - apiPrefix: '/api/v1', - }); + if (this.entrypointTag.endsWith('_stream')) { + throw new Error( + `Entrypoint \`${this.entrypointTag}\` is streaming. Use runStream() instead.` + ); } + + return this.executeRun(inputKwargs); } - private async _run(inputKwargs: Record): Promise { + async *runStream( + inputKwargs: Record = {} + ): AsyncGenerator { + await this.ensureInitialized(); + + if (!this.entrypointTag.endsWith('_stream')) { + throw new Error( + `Entrypoint \`${this.entrypointTag}\` is not streaming. Use run() instead.` + ); + } + + yield* this.executeStream(inputKwargs); + } + + // ------------------------------------------------------------------ + // Internal execution helpers + // ------------------------------------------------------------------ + + private async executeRun( + inputKwargs: Record + ): Promise { + if (!this.restClient) { + throw new Error('REST client not initialized'); + } + const response = await this.restClient.runAgent( this.agentId, this.entrypointTag, { inputArgs: [], - inputKwargs: inputKwargs, + inputKwargs, + timeoutSeconds: this.timeoutSeconds, } ); @@ -259,32 +361,34 @@ export class RunAgentClient { const errorMessage = typeof response.error === 'string' ? response.error - : (response.error as { message?: string })?.message ?? 'Agent execution failed'; + : (response.error as { message?: string })?.message ?? + 'Agent execution failed'; throw new Error(errorMessage); } - private async *_runStream( + private executeStream( inputKwargs: Record ): AsyncGenerator { - yield* this.socketClient.runStream(this.agentId, this.entrypointTag, { - inputArgs: [], - inputKwargs: inputKwargs, - }); - } - - // Main run method - matches your Python interface exactly! - async run( - inputKwargs: Record - ): Promise> { - if (this.entrypointTag.endsWith('_stream')) { - return this._runStream(inputKwargs); - } else { - return this._run(inputKwargs); + if (!this.socketClient) { + throw new Error('WebSocket client not initialized'); } + + return this.socketClient.runStream( + this.agentId, + this.entrypointTag, + { + inputArgs: [], + inputKwargs, + timeoutSeconds: this.timeoutSeconds, + } + ); } - // Utility methods + // ------------------------------------------------------------------ + // Utility getters + // ------------------------------------------------------------------ + get environment(): 'node' | 'browser' { return isNode ? 'node' : 'browser'; } @@ -297,18 +401,27 @@ export class RunAgentClient { return isBrowser; } + getExtraParams(): Record | undefined { + return this.extraParams; + } + /** - * Check if registry features are available + * Check if registry features are available. */ static async hasRegistry(): Promise { - if (isBrowser) return false; - return await RunAgentRegistry.isAvailable(); + if (!isNode) return false; + try { + const { RunAgentRegistry } = await import('../database/index.js'); + return await RunAgentRegistry.isAvailable(); + } catch { + return false; + } } /** - * Get registry instance (for advanced users) + * Get registry instance (for advanced Node.js users). */ static async getRegistryInstance(): Promise { - return await this.getRegistry(); + return await this.getRegistry(true); } } diff --git a/runagent-ts/src/http/index.ts b/runagent-ts/src/http/index.ts index a6ce79c..fdeafcb 100644 --- a/runagent-ts/src/http/index.ts +++ b/runagent-ts/src/http/index.ts @@ -27,25 +27,25 @@ import { // function fetch(url: string, init?: RequestInit): Promise; // } - export class HttpHandler { - private apiKey?: string; - private baseUrl: string; - private defaultHeaders: Record; - - constructor(apiKey?: string, baseUrl: string = '') { - this.apiKey = apiKey; - this.baseUrl = baseUrl.replace(/\/$/, ''); - - this.defaultHeaders = { - accept: 'application/json', - 'content-type': 'application/json', - }; - - if (this.apiKey) { - this.defaultHeaders['Authorization'] = `Bearer ${this.apiKey}`; - this.defaultHeaders['User-Agent'] = 'RunAgent-TS/1.0'; - } +export class HttpHandler { + private apiKey?: string; + private baseUrl: string; + private defaultHeaders: Record; + + constructor(apiKey?: string, baseUrl: string = '', _isLocal = true) { + this.apiKey = apiKey; + this.baseUrl = baseUrl.replace(/\/$/, ''); + + this.defaultHeaders = { + accept: 'application/json', + 'content-type': 'application/json', + 'User-Agent': 'RunAgent-TS/1.0', + }; + + if (this.apiKey) { + this.defaultHeaders['Authorization'] = `Bearer ${this.apiKey}`; } + } private _getUrl(path: string): string { return `${this.baseUrl}/${path.replace(/^\//, '')}`; diff --git a/runagent-ts/src/rest/index.ts b/runagent-ts/src/rest/index.ts index 48bc318..d8176a5 100644 --- a/runagent-ts/src/rest/index.ts +++ b/runagent-ts/src/rest/index.ts @@ -1,29 +1,46 @@ import { HttpHandler } from '../http/index.js'; +import { + AuthenticationError, + ClientError, + ConnectionError, + ServerError, + ValidationError, +} from '../errors/index.js'; import type { ApiResponse, AgentArchitecture, JsonValue } from '../types/index.js'; interface RunAgentOptions { inputArgs?: unknown[]; inputKwargs?: Record; - executionType?: string; + timeoutSeconds?: number; } interface RestClientConfig { baseUrl?: string; apiKey?: string; apiPrefix?: string; + isLocal?: boolean; + timeoutSeconds?: number; } export class RestClient { private http: HttpHandler; private baseUrl: string; private apiKey?: string; + private defaultTimeoutSeconds: number; constructor(options: RestClientConfig = {}) { - const { baseUrl = 'http://localhost:8080', apiKey, apiPrefix = '/api/v1' } = options; - + const { + baseUrl = 'http://localhost:8080', + apiKey, + apiPrefix = '/api/v1', + isLocal = true, + timeoutSeconds = 300, + } = options; + this.baseUrl = baseUrl.replace(/\/$/, '') + apiPrefix; this.apiKey = apiKey; - this.http = new HttpHandler(this.apiKey, this.baseUrl); + this.defaultTimeoutSeconds = timeoutSeconds; + this.http = new HttpHandler(this.apiKey, this.baseUrl, isLocal); } async runAgent( @@ -31,45 +48,92 @@ export class RestClient { entrypointTag: string, options: RunAgentOptions = {} ): Promise { - const { inputArgs = null, inputKwargs = null } = options; + const { + inputArgs = [], + inputKwargs = {}, + timeoutSeconds = this.defaultTimeoutSeconds, + } = options; + + const requestData = { + entrypoint_tag: entrypointTag, + input_args: inputArgs, + input_kwargs: inputKwargs, + timeout_seconds: timeoutSeconds, + async_execution: false, + } as JsonValue; + + const timeoutMs = timeoutSeconds * 1000 + 10_000; // Add buffer similar to Python SDK try { - console.log(`🤖 Executing agent: ${agentId}`); + const response = await this.http.post( + `/agents/${agentId}/run`, + requestData, + { timeout: timeoutMs } + ); - const requestData = { - input_data: { - input_args: inputArgs, - input_kwargs: inputKwargs, - }, - } as JsonValue; - - - try { - const response = await this.http.post( - `/agents/${agentId}/execute/${entrypointTag}`, - requestData, - { timeout: 120000 } - ); - - const result = await response.json() as ApiResponse; - - if (result.success !== false) { - console.log('✅ Agent execution completed!'); - return result; - } else { - console.log(`❌ Agent execution failed: ${result.error || 'Unknown error'}`); - return result; - } - } catch (error) { + return (await response.json()) as ApiResponse; + } catch (error) { + const errorMessage = + error instanceof Error ? error.message : 'Unknown error'; + + if (error instanceof AuthenticationError) { + const code = + error.statusCode === 403 ? 'PERMISSION_ERROR' : 'AUTHENTICATION_ERROR'; return { success: false, - error: `Agent execution failed: ${error instanceof Error ? error.message : 'Unknown error'}`, + error: { + code, + message: errorMessage, + }, }; } - } catch (error) { + + if (error instanceof ValidationError) { + return { + success: false, + error: { + code: 'VALIDATION_ERROR', + message: errorMessage, + }, + }; + } + + if (error instanceof ConnectionError) { + return { + success: false, + error: { + code: 'CONNECTION_ERROR', + message: errorMessage, + }, + }; + } + + if (error instanceof ServerError) { + return { + success: false, + error: { + code: 'SERVER_ERROR', + message: errorMessage, + }, + }; + } + + if (error instanceof ClientError) { + return { + success: false, + error: { + code: 'CLIENT_ERROR', + message: errorMessage, + }, + }; + } + return { success: false, - error: `Execute agent failed: ${error instanceof Error ? error.message : 'Unknown error'}`, + error: { + code: 'UNKNOWN_ERROR', + message: errorMessage, + }, }; } } @@ -77,9 +141,13 @@ export class RestClient { async getAgentArchitecture(agentId: string): Promise { try { const response = await this.http.get(`/agents/${agentId}/architecture`); - return response.json() as Promise; + return (await response.json()) as AgentArchitecture; } catch (error) { - throw new Error(`Failed to get architecture: ${error instanceof Error ? error.message : 'Unknown error'}`); + throw new Error( + `Failed to get architecture: ${ + error instanceof Error ? error.message : 'Unknown error' + }` + ); } } diff --git a/runagent-ts/src/types/index.ts b/runagent-ts/src/types/index.ts index 40148f4..82fc24c 100644 --- a/runagent-ts/src/types/index.ts +++ b/runagent-ts/src/types/index.ts @@ -1,14 +1,17 @@ export interface RunAgentConfig { - agentId: string; - entrypointTag: string; - local?: boolean; - host?: string; - port?: number; - apiKey?: string; - baseUrl?: string; - baseSocketUrl?: string; - apiPrefix?: string; - } + agentId: string; + entrypointTag: string; + local?: boolean; + host?: string; + port?: number; + apiKey?: string; + baseUrl?: string; + baseSocketUrl?: string; + apiPrefix?: string; + timeoutSeconds?: number; + extraParams?: Record; + enableRegistry?: boolean; +} export interface ApiResponse { success: boolean; @@ -45,13 +48,12 @@ export interface AgentArchitecture { } export interface ExecutionRequest { - action: string; - agent_id: string; - input_data: { - input_args: unknown[]; - input_kwargs: Record; - }; - } + entrypoint_tag: string; + input_args: unknown[]; + input_kwargs: Record; + timeout_seconds?: number; + async_execution?: boolean; +} export interface SerializedObject { content: unknown; diff --git a/runagent-ts/src/websocket/base.ts b/runagent-ts/src/websocket/base.ts index 6989ffc..bb1e77c 100644 --- a/runagent-ts/src/websocket/base.ts +++ b/runagent-ts/src/websocket/base.ts @@ -1,64 +1,91 @@ import { CoreSerializer } from '../serializer/index.js'; -import type { WebSocketMessage, ExecutionRequest } from '../types/index.js'; +import type { ExecutionRequest, JsonValue } from '../types/index.js'; interface WebSocketConfig { baseSocketUrl?: string; apiKey?: string; apiPrefix?: string; + isLocal?: boolean; + timeoutSeconds?: number; } interface RunStreamOptions { inputArgs?: unknown[]; inputKwargs?: Record; + timeoutSeconds?: number; +} + +interface StreamMessage { + type: string; + status?: string; + payload?: unknown; + error?: unknown; } export abstract class BaseWebSocketClient { protected serializer: CoreSerializer; protected baseSocketUrl: string; protected apiKey?: string; + protected apiPrefix: string; + protected isLocal: boolean; + protected timeoutSeconds: number; constructor(config: WebSocketConfig) { - const { baseSocketUrl = 'ws://localhost:8080', apiKey, apiPrefix = '/api/v1' } = config; - + const { + baseSocketUrl = 'ws://localhost:8080', + apiKey, + apiPrefix = '/api/v1', + isLocal = true, + timeoutSeconds = 300, + } = config; + this.baseSocketUrl = baseSocketUrl.replace(/\/$/, '') + apiPrefix; this.apiKey = apiKey; this.serializer = new CoreSerializer(); + this.apiPrefix = apiPrefix; + this.isLocal = isLocal; + this.timeoutSeconds = timeoutSeconds; } - abstract createWebSocket(url: string): unknown | Promise; + abstract createWebSocket( + url: string, + headers?: Record + ): unknown | Promise; async *runStream( agentId: string, entrypointTag: string, options: RunStreamOptions = {} ): AsyncGenerator { - const { inputArgs = null, inputKwargs = null } = options; - const uri = `${this.baseSocketUrl}/agents/${agentId}/execute/${entrypointTag}`; + const { inputArgs = null, inputKwargs = null, timeoutSeconds } = options; + const endpoint = `${this.baseSocketUrl}/agents/${agentId}/run-stream`; + + let uri = endpoint; + if (!this.isLocal && this.apiKey) { + const separator = endpoint.includes('?') ? '&' : '?'; + uri = `${endpoint}${separator}token=${encodeURIComponent(this.apiKey)}`; + } + + const headers = + !this.isLocal && this.apiKey + ? { Authorization: `Bearer ${this.apiKey}` } + : undefined; let websocket: unknown; try { - websocket = await Promise.resolve(this.createWebSocket(uri)); - await this.waitForConnection(websocket); + websocket = await Promise.resolve(this.createWebSocket(uri, headers)); + await this.waitForConnection(websocket); const request: ExecutionRequest = { - action: 'start_stream', - agent_id: agentId, - input_data: { - input_args: inputArgs || [], - input_kwargs: inputKwargs || {}, - }, + entrypoint_tag: entrypointTag, + input_args: inputArgs || [], + input_kwargs: inputKwargs || {}, + timeout_seconds: timeoutSeconds ?? this.timeoutSeconds, + async_execution: false, }; - const startMsg: Partial = { - id: 'stream_start', - type: 'status', - timestamp: new Date().toISOString(), - data: request, - }; - - const serializedMsg = this.serializer.serializeMessage(startMsg); - this.sendMessage(websocket, serializedMsg); + this.sendMessage(websocket, JSON.stringify(request)); yield* this.createWebSocketIterator(websocket); } finally { @@ -73,4 +100,116 @@ export abstract class BaseWebSocketClient { protected abstract isWebSocketOpen(websocket: unknown): boolean; protected abstract closeWebSocket(websocket: unknown): void; protected abstract createWebSocketIterator(websocket: unknown): AsyncGenerator; + + protected parseStreamMessage(raw: string): StreamMessage { + let parsed: unknown; + try { + parsed = JSON.parse(raw); + } catch { + return { type: 'data', payload: raw }; + } + + if (parsed === null || typeof parsed !== 'object') { + return { type: 'data', payload: parsed }; + } + + const message = parsed as Record; + const type = + typeof message.type === 'string' + ? message.type.toLowerCase() + : 'data'; + + const status = + typeof message.status === 'string' + ? message.status + : typeof message.data === 'object' && + message.data !== null && + typeof (message.data as Record).status === 'string' + ? ((message.data as Record).status as string) + : undefined; + + const error = + message.error ?? + message.detail ?? + (typeof message.data === 'object' && + message.data !== null && + 'error' in (message.data as Record) + ? (message.data as Record).error + : undefined); + + const payload = + message.content ?? + message.data ?? + message.payload ?? + message.delta ?? + undefined; + + return { type, status, payload, error }; + } + + protected cleanErrorMessage(error: unknown): string { + if (!error) { + return 'Unknown error'; + } + + let message = + typeof error === 'string' + ? error + : error instanceof Error + ? error.message + : JSON.stringify(error); + + if (!message) { + return 'Unknown error'; + } + + const prefixes = [ + 'Streaming error: ', + 'Stream error: ', + 'Internal server error: ', + 'Server error: ', + 'Database error: ', + 'HTTP Error: ', + 'Error: ', + ]; + + for (const prefix of prefixes) { + if (message.startsWith(prefix)) { + message = message.slice(prefix.length).trim(); + } + } + + message = message.replace(/^\d{3}:\s*/, ''); + + const duplicateIndex = message.toLowerCase().indexOf('; then sent'); + if (duplicateIndex !== -1) { + message = message.slice(0, duplicateIndex).trim(); + } + + return message.trim() || 'Unknown error'; + } + + protected deserializeStreamPayload(payload: unknown): unknown { + if (payload === null || payload === undefined) { + return payload; + } + + if (typeof payload === 'string') { + try { + return this.serializer.deserializeObject(payload); + } catch { + return payload; + } + } + + if (typeof payload === 'object') { + try { + return this.serializer.deserializeObject(payload as JsonValue); + } catch { + return payload; + } + } + + return payload; + } } \ No newline at end of file diff --git a/runagent-ts/src/websocket/browser.ts b/runagent-ts/src/websocket/browser.ts index 7c813dd..03b1f59 100644 --- a/runagent-ts/src/websocket/browser.ts +++ b/runagent-ts/src/websocket/browser.ts @@ -38,7 +38,10 @@ interface IteratorResolverItem { } export class BrowserWebSocketClient extends BaseWebSocketClient { - createWebSocket(url: string): WebSocket { + createWebSocket( + url: string, + _headers?: Record + ): WebSocket { return new WebSocket(url); } @@ -93,39 +96,31 @@ export class BrowserWebSocketClient extends BaseWebSocketClient { const messageHandler = (event: MessageEvent) => { try { - console.log('received=> ', event.data); - const safeMsg = this.serializer.deserializeMessage(event.data as string); + const streamMessage = this.parseStreamMessage(event.data as string); - if (safeMsg.error) { - error = new Error(`Stream error: ${safeMsg.error}`); - rejectAll(error); - return; - } - - if (safeMsg.type === 'status') { - const status = (safeMsg.data as Record)?.status; - if (status === 'stream_completed') { + if (streamMessage.type === 'status') { + if (streamMessage.status === 'stream_completed') { finished = true; resolveAll(); - return; - } else if (status === 'stream_started') { - return; } - } else if (safeMsg.type === 'ERROR') { - error = new Error(`Agent error: ${JSON.stringify(safeMsg.data)}`); + return; + } + + if (streamMessage.type === 'error') { + error = new Error(this.cleanErrorMessage(streamMessage.error)); rejectAll(error); return; - } else { - if (resolvers.length > 0) { - console.log('resolving immediately'); - const resolver = resolvers.shift(); - if (resolver) { - resolver.resolve({ done: false, value: safeMsg.data }); - } - } else { - console.log('queueing message'); - messageQueue.push(safeMsg.data); + } + + const payload = this.deserializeStreamPayload(streamMessage.payload); + + if (resolvers.length > 0) { + const resolver = resolvers.shift(); + if (resolver) { + resolver.resolve({ done: false, value: payload }); } + } else { + messageQueue.push(payload); } } catch (err) { error = err instanceof Error ? err : new Error('Unknown error'); diff --git a/runagent-ts/src/websocket/node.ts b/runagent-ts/src/websocket/node.ts index bae59ae..d600c9b 100644 --- a/runagent-ts/src/websocket/node.ts +++ b/runagent-ts/src/websocket/node.ts @@ -5,13 +5,6 @@ interface IteratorResolverItem { reject: (error: Error) => void; } -interface NodeWebSocket { - on(event: string, callback: (...args: unknown[]) => void): void; - send(data: string): void; - close(): void; - readyState: number; -} - export class NodeWebSocketClient extends BaseWebSocketClient { private WebSocketClass: any = null; @@ -36,13 +29,16 @@ export class NodeWebSocketClient extends BaseWebSocketClient { } } - async createWebSocket(url: string): Promise { + async createWebSocket( + url: string, + headers?: Record + ): Promise { const WebSocket = await this.loadWebSocket(); - return new WebSocket(url) as NodeWebSocket; + return new WebSocket(url, headers ? { headers } : undefined); } protected async waitForConnection(websocket: unknown): Promise { - const ws = websocket as NodeWebSocket; + const ws = websocket as any; return new Promise((resolve, reject) => { ws.on('open', () => resolve()); ws.on('error', (...args: unknown[]) => { @@ -53,23 +49,23 @@ export class NodeWebSocketClient extends BaseWebSocketClient { } protected sendMessage(websocket: unknown, message: string): void { - const ws = websocket as NodeWebSocket; + const ws = websocket as any; ws.send(message); } protected isWebSocketOpen(websocket: unknown): boolean { - const ws = websocket as NodeWebSocket; + const ws = websocket as any; return ws.readyState === 1; // WebSocket.OPEN } protected closeWebSocket(websocket: unknown): void { - const ws = websocket as NodeWebSocket; + const ws = websocket as any; ws.close(); } // Rest of the methods remain the same... protected async *createWebSocketIterator(websocket: unknown): AsyncGenerator { - const ws = websocket as NodeWebSocket; + const ws = websocket as any; const messageQueue: unknown[] = []; const resolvers: IteratorResolverItem[] = []; let finished = false; @@ -96,39 +92,32 @@ export class NodeWebSocketClient extends BaseWebSocketClient { const messageHandler = (...args: unknown[]) => { const data = args[0] as Buffer | string; try { - console.log('received=> ', data.toString()); - const safeMsg = this.serializer.deserializeMessage(data.toString()); + const raw = typeof data === 'string' ? data : data.toString(); + const streamMessage = this.parseStreamMessage(raw); - if (safeMsg.error) { - error = new Error(`Stream error: ${safeMsg.error}`); - rejectAll(error); - return; - } - - if (safeMsg.type === 'status') { - const status = (safeMsg.data as Record)?.status; - if (status === 'stream_completed') { + if (streamMessage.type === 'status') { + if (streamMessage.status === 'stream_completed') { finished = true; resolveAll(); - return; - } else if (status === 'stream_started') { - return; } - } else if (safeMsg.type === 'ERROR') { - error = new Error(`Agent error: ${JSON.stringify(safeMsg.data)}`); + return; + } + + if (streamMessage.type === 'error') { + error = new Error(this.cleanErrorMessage(streamMessage.error)); rejectAll(error); return; - } else { - if (resolvers.length > 0) { - console.log('resolving immediately'); - const resolver = resolvers.shift(); - if (resolver) { - resolver.resolve({ done: false, value: safeMsg.data }); - } - } else { - console.log('queueing message'); - messageQueue.push(safeMsg.data); + } + + const payload = this.deserializeStreamPayload(streamMessage.payload); + + if (resolvers.length > 0) { + const resolver = resolvers.shift(); + if (resolver) { + resolver.resolve({ done: false, value: payload }); } + } else { + messageQueue.push(payload); } } catch (err) { error = err instanceof Error ? err : new Error('Unknown error'); diff --git a/sdk_checklist.md b/sdk_checklist.md new file mode 100644 index 0000000..ac6c9d7 --- /dev/null +++ b/sdk_checklist.md @@ -0,0 +1,159 @@ +## SDK Implementation Guide + +### Purpose And Scope +- **Goal**: every SDK (Python, JS/TS, Go, Rust, future C#/Swift/Flutter, etc.) exposes a single `RunAgentClient` class with `run()` and `run_stream()`; Python CLI is the superset, other SDKs only need client functions. +- **Reference implementation**: Python CLI layers on top of the Python SDK. When unsure, mirror the Python behavior and propose parity improvements if features are missing. +- **Separation of concerns**: the CLI covers deployment/orchestration; SDKs focus purely on invoking deployed agents. + +### Client Initialization Contract +- **Constructor signature** *(language-idiomatic)*: `RunAgentClient({ agent_id, entrypoint_tag, local?, host?, port?, api_key?, base_url?, extra_params? })`. +- **Required inputs**: `agent_id`, `entrypoint_tag`. +- **Optional inputs**: + - `local` (default `false` except Python CLI) indicates whether to auto-discover host/port for co-located agents. + - `host`/`port` override local discovery; required when running on a device that cannot read the local SQLite DB (e.g. browsers, remote SDK consumers). + - `api_key` overrides environment configuration for cloud calls. + - `base_url` overrides the default cloud endpoint. + - `extra_params` is an open-ended key/value bag stored on the client for future metadata use without breaking changes (simply accept and retain it; no mandated behavior yet). + +- **Configuration precedence** (must be explicit in every SDK): + 1. Explicit constructor arguments + 2. Environment variables (`RUNAGENT_API_KEY`, `RUNAGENT_BASE_URL`, etc.) + 3. Library defaults (`https://backend.run-agent.ai`, standard port 8450 for local) + +### Local Agent Discovery (Optional) +- When `local=true` **and** filesystem access is available, read the SQLite DB at `~/.runagent/runagent_local.db`; reuse the Python schema (`agents` table mapping `agent_id → host, port, framework, status`). + ```35:55:runagent/client/client.py + if local: + if host and port: + agent_host = host + agent_port = port + else: + agent_info = self.sdk.db_service.get_agent(agent_id) + ... + agent_host = self.agent_info["host"] + agent_port = self.agent_info["port"] + ``` +- If the agent is missing, raise a clear error telling users to start or register the agent locally. +- SDKs running in sandboxes (browser, mobile, serverless) should skip DB probing and require `host`/`port`. + +### Remote Agent Defaults +- Default REST base URL: `https://backend.run-agent.ai` (append `/api/v1`). +- Default WebSocket base: convert to `wss://backend.run-agent.ai/api/v1`. +- Allow overrides via constructor or `RUNAGENT_BASE_URL` env var. +- Respect per-request overrides for self-hosted or staging deployments. + +### Authentication +- Use Bearer tokens everywhere; reuse the CLI convention (`Authorization: Bearer ${api_key}`) and query-string token fallback for WebSockets. +- Environment variable name: `RUNAGENT_API_KEY`. +- If no API key is present for remote calls, surface a clear error instructing users to set env vars or pass `api_key=`. + +### HTTP `run()` Semantics +- Endpoint: `POST /api/v1/agents/{agent_id}/run`. +- Payload: + ```json + { + "entrypoint_tag": "...", + "input_args": [], + "input_kwargs": {}, + "timeout_seconds": 300, + "async_execution": false + } + ``` +- Deserialize result payloads exactly as the Python client: + - `data.result_data.data` (legacy structured output) + - `data` directly when it’s a stringified artifact +- When errors arrive, mirror the Python `RunAgentExecutionError` structure (code/message/suggestion/details). + ```70:118:runagent/client/client.py + response = self.rest_client.run_agent(...) + if response.get("success"): + ... + else: + error_info = response.get("error") + ... + raise RunAgentExecutionError(code=..., message=..., suggestion=..., details=...) + ``` +- Recommended error taxonomy: `AUTHENTICATION_ERROR`, `PERMISSION_ERROR`, `CONNECTION_ERROR`, `VALIDATION_ERROR`, `SERVER_ERROR`, `UNKNOWN_ERROR`. + +### WebSocket `run_stream()` Semantics +- Endpoint: `GET wss://.../api/v1/agents/{agent_id}/run-stream`. +- Handshake: immediately send JSON body identical to REST payload (minus `async_execution` optional). +- Incoming frames: JSON objects with `type ∈ {status, data, error}`. + - `status=stream_started` (informational), `status=stream_completed` (terminate). + - `data` frames carry `content` (string or JSON); attempt structured deserialization first. + - `error` frames emit exception and stop the stream. + ```61:147:runagent/sdk/socket_client.py + if self.is_local: + uri = f"{self.base_socket_url}/agents/{agent_id}/run-stream" + else: + uri = f"{self.base_socket_url}/agents/{agent_id}/run-stream?token={self.api_key}" + ... + request_data = { "entrypoint_tag": ..., "input_args": ..., "input_kwargs": ..., "timeout_seconds": 600 } + websocket.send(json.dumps(request_data)) + for raw_message in websocket: + message = json.loads(raw_message) + if message["type"] == "data": + ... + ``` +- Provide both sync iterator and async iterator variants when idiomatic for the language. + +### Extra Params Handling +- Accept `extra_params` at construction; store but do not mutate. +- For now, just keep it accessible via a getter to future-proof metadata features (e.g., tracing context, client tags). + +### Error Handling Guidance +- Raise language-idiomatic exceptions derived from a base `RunAgentError`. +- Wrap network-layer issues (timeouts, DNS) into `ConnectionError`. +- When HTTP 401/403 occurs, raise `AuthenticationError` with friendly guidance (e.g., “Set RUNAGENT_API_KEY or pass api_key”). + +### Environment And Config Utilities +- Provide helpers to load env vars (`RUNAGENT_API_KEY`, `RUNAGENT_BASE_URL`, optional future keys). +- Offer a `from_env()` factory for ergonomic initialization. +- Document that constructor args override env vars, which override defaults. + +### Testing Expectations +- Unit tests: mock REST/WebSocket interactions; assert payload shape and error translation. +- Integration tests: optional “local mode” harness reading a test SQLite DB. +- Provide CI examples for each SDK (reference existing Python/Go/Rust tests under `test_scripts/`). + +### Implementation Checklist (Per New SDK) +- [ ] Build `RunAgentClient` with constructor precedence and optional local DB hook. +- [ ] Implement REST `run()` and WebSocket `run_stream()` following payload schemas. +- [ ] Surface consistent error types and messages. +- [ ] Support explicit `api_key`, `base_url`, `host`, `port`. +- [ ] Expose `extra_params` without opinionated behavior. +- [ ] Add environment-based helpers (`from_env`, `configure_from_env`). +- [ ] Include README snippet showing local vs remote usage. +- [ ] Add automated tests for success/error paths. +- [ ] Audit docs to ensure new SDK mirrors this guide. + +### Suggested Documentation Template For SDK Repos +1. Quickstart (init client, call `run`, call `run_stream`). +2. Configuration (env vars, constructor precedence). +3. Local vs remote usage (with/without DB, when to set `local=true`). +4. Authentication setup (API key instructions). +5. Error handling reference table. +6. Advanced topics (custom base URL, extra params, retries). +7. Troubleshooting (common connection/auth issues). + +### References +```24:37:runagent/constants.py +LOCAL_CACHE_DIRECTORY_PATH = "~/.runagent" +... +DATABASE_FILE_NAME = "runagent_local.db" +``` + +```25:118:runagent/client/client.py +class RunAgentClient: + def __init__(..., local: bool = True, host: str = None, port: int = None): + ... +``` + +```61:147:runagent/sdk/socket_client.py + if self.is_local: + uri = f"{self.base_socket_url}/agents/{agent_id}/run-stream" + else: + uri = f"{self.base_socket_url}/agents/{agent_id}/run-stream?token={self.api_key}" + ... +``` + +---