Compare commits

...
Author SHA1 Message Date
Peter Steinberger ffa25f47da chore: rebrand user-facing to OpenClaw 2026-01-30 07:02:35 +01:00
Peter Steinberger f866dc05d1 style: format moderation flags 2026-01-30 05:27:19 +01:00
Peter Steinberger 69436fd79b fix: allow moltbot parsed data 2026-01-30 05:26:09 +01:00
Peter Steinberger f185ca6f55 feat: release 0.4.0 2026-01-30 05:23:12 +01:00
Peter Steinberger f3fc8d62b6 Revert "chore: rename molthub branding"
This reverts commit 8d68b55333.
2026-01-30 05:23:12 +01:00
Shakker 71f94a774f Merge pull request #70 from moltbot/remove-clawd-authenticator-tool
chore(moderation): block ClawdAuthenticatorTool (suspected malware)
2026-01-29 17:18:09 +00:00
139 changed files with 1506 additions and 1207 deletions
+1 -1
View File
@@ -34,7 +34,7 @@ jobs:
- name: Typecheck packages
run: |
bunx tsc -p packages/schema/tsconfig.json --noEmit
bunx tsc -p packages/molthub/tsconfig.json --noEmit
bunx tsc -p packages/clawdhub/tsconfig.json --noEmit
- name: Build
run: bun run build
+22 -7
View File
@@ -2,8 +2,23 @@
## Unreleased
### Added
### Changed
### Fixed
## 0.4.0 - 2026-01-30
### Added
- Web: show published skills on user profiles (thanks @njoylab, #20).
- CLI: include OpenClaw + Moltbot fallback skill roots for sync scans.
- CLI: support OpenClaw configuration files (`OPENCLAW_CONFIG_PATH` / `OPENCLAW_STATE_DIR`).
### Changed
- Brand: rebrand to OpenClaw and publish CLI as `clawhub` (legacy `clawdhub` supported).
- Domain: default site/registry now `https://clawhub.ai`; `.well-known/clawhub.json` preferred.
- Theme: persist theme under `clawhub-theme` (legacy key still read).
### Fixed
- Registry: drop missing skills during search hydration (thanks @aaronn, #28).
@@ -26,7 +41,7 @@
### Added
- Web: dynamic OG image cards for skills (name, description, version).
- CLI: auto-scan Moltbot skill roots (per-agent workspaces, shared skills, extraDirs).
- CLI: auto-scan Clawdbot skill roots (per-agent workspaces, shared skills, extraDirs).
- Web: import skills from public GitHub URLs (auto-detect `SKILL.md`, smart file selection, provenance).
- Web/API: SoulHub (SOUL.md registry) with v1 endpoints and first-run auto-seed.
@@ -36,7 +51,7 @@
- Registry: make SoulHub auto-seed idempotent and non-user-owned.
- Registry: keep GitHub backup state + publish backups intact (thanks @joshp123, #1).
- CLI/Registry: restore fork lineage on sync + clamp bulk list queries (thanks @joshp123, #1).
- CLI: default workdir falls back to Moltbot workspace (override with `--workdir` / `MOLTHUB_WORKDIR`).
- CLI: default workdir falls back to Clawdbot workspace (override with `--workdir` / `CLAWHUB_WORKDIR`).
## 0.0.6 - 2026-01-07
@@ -52,7 +67,7 @@
## 0.0.5 - 2026-01-06
### Added
- Telemetry: track installs via `molthub sync` (logged-in only), per root, with 120-day staleness.
- Telemetry: track installs via `clawhub sync` (logged-in only), per root, with 120-day staleness.
- Skills: show current + all-time installs; sort by installs.
- Profile: private "Installed" tab with JSON export + delete telemetry controls.
- Docs: add `docs/telemetry.md` (what we track + how to opt out).
@@ -60,7 +75,7 @@
- Web: dashboard for managing your published skills (thanks @dbhurley!).
### Changed
- CLI: telemetry opt-out via `MOLTHUB_DISABLE_TELEMETRY=1`.
- CLI: telemetry opt-out via `CLAWHUB_DISABLE_TELEMETRY=1`.
- Web: move theme picker into mobile menu.
### Fixed
@@ -89,7 +104,7 @@
- Web: improved mobile responsiveness (nav menu, skill detail layout, install command overflow).
- Web: upload now unwraps folder picks so `SKILL.md` can be at the bundle root.
- Registry: cap embedding payload size to avoid model context errors.
- CLI: ignore legacy `auth.molthub.com` registry and prefer site discovery.
- CLI: ignore legacy `auth.clawdhub.com` registry and prefer site discovery.
### Changed
- Web: homepage search now expands into full search mode with live results + highlighted toggle.
@@ -108,8 +123,8 @@
### Fixed
- CLI sync: wrap note output to avoid terminal overflow; cap list lengths.
- CLI sync: label fallback scans as fallback locations.
- CLI package: bundle schema internally (no external `molthub-schema` publish).
- Repo: mark `molthub-schema` as private to prevent publishing.
- CLI package: bundle schema internally (no external `clawhub-schema` publish).
- Repo: mark `clawhub-schema` as private to prevent publishing.
## 0.0.2 - 2026-01-04
+17 -17
View File
@@ -1,17 +1,17 @@
# MoltHub
# OpenClaw
<p align="center">
<a href="https://github.com/moltbot/molthub/actions/workflows/ci.yml?branch=main"><img src="https://img.shields.io/github/actions/workflow/status/moltbot/molthub/ci.yml?branch=main&style=for-the-badge" alt="CI status"></a>
<a href="https://discord.gg/molt"><img src="https://img.shields.io/discord/1456350064065904867?label=Discord&logo=discord&logoColor=white&color=5865F2&style=for-the-badge" alt="Discord"></a>
<a href="https://github.com/openclaw/clawhub/actions/workflows/ci.yml?branch=main"><img src="https://img.shields.io/github/actions/workflow/status/openclaw/clawhub/ci.yml?branch=main&style=for-the-badge" alt="CI status"></a>
<a href="https://discord.gg/clawd"><img src="https://img.shields.io/discord/1456350064065904867?label=Discord&logo=discord&logoColor=white&color=5865F2&style=for-the-badge" alt="Discord"></a>
<a href="LICENSE"><img src="https://img.shields.io/badge/License-MIT-blue.svg?style=for-the-badge" alt="MIT License"></a>
</p>
MoltHub is the **public skill registry for Moltbot**: publish, version, and search text-based agent skills (a `SKILL.md` plus supporting files).
OpenClaw is the **public skill registry for Clawdbot**: publish, version, and search text-based agent skills (a `SKILL.md` plus supporting files).
Its designed for fast browsing + a CLI-friendly API, with moderation hooks and vector search.
onlycrabs.ai is the **SOUL.md registry**: publish and share system lore the same way you publish skills.
Live: `https://molthub.com`
Live: `https://clawhub.ai`
onlycrabs.ai: `https://onlycrabs.ai`
## What you can do
@@ -27,7 +27,7 @@ onlycrabs.ai: `https://onlycrabs.ai`
- Entry point is host-based: `onlycrabs.ai`.
- On the onlycrabs.ai host, the home page and nav default to souls.
- On MoltHub, souls live under `/souls`.
- On OpenClaw, souls live under `/souls`.
- Soul bundles only accept `SOUL.md` for now (no extra files).
## How it works (high level)
@@ -35,15 +35,15 @@ onlycrabs.ai: `https://onlycrabs.ai`
- Web app: TanStack Start (React, Vite/Nitro).
- Backend: Convex (DB + file storage + HTTP actions) + Convex Auth (GitHub OAuth).
- Search: OpenAI embeddings (`text-embedding-3-small`) + Convex vector search.
- API schema + routes: `packages/schema` (`molthub-schema`).
- API schema + routes: `packages/schema` (`clawhub-schema`).
## Telemetry
MoltHub tracks minimal **install telemetry** (to compute install counts) when you run `molthub sync` while logged in.
OpenClaw tracks minimal **install telemetry** (to compute install counts) when you run `clawhub sync` while logged in.
Disable via:
```bash
export MOLTHUB_DISABLE_TELEMETRY=1
export CLAWHUB_DISABLE_TELEMETRY=1
```
Details: `docs/telemetry.md`.
@@ -95,7 +95,7 @@ This writes `JWT_PRIVATE_KEY` + `JWKS` to the deployment and prints values for y
## Nix plugins (nixmode skills)
MoltHub can store a nix-moltbot plugin pointer in SKILL frontmatter so the registry knows which
OpenClaw can store a nix-clawdbot plugin pointer in SKILL frontmatter so the registry knows which
Nix package bundle to install. A nix plugin is different from a regular skill pack: it bundles the
skill pack, the CLI binary, and its config flags/requirements together.
@@ -105,15 +105,15 @@ Add this to `SKILL.md`:
---
name: peekaboo
description: Capture and automate macOS UI with the Peekaboo CLI.
metadata: {"moltbot":{"nix":{"plugin":"github:moltbot/nix-steipete-tools?dir=tools/peekaboo","systems":["aarch64-darwin"]}}}
metadata: {"clawdbot":{"nix":{"plugin":"github:clawdbot/nix-steipete-tools?dir=tools/peekaboo","systems":["aarch64-darwin"]}}}
---
```
Install via nix-moltbot:
Install via nix-clawdbot:
```nix
programs.moltbot.plugins = [
{ source = "github:moltbot/nix-steipete-tools?dir=tools/peekaboo"; }
programs.clawdbot.plugins = [
{ source = "github:clawdbot/nix-steipete-tools?dir=tools/peekaboo"; }
];
```
@@ -123,7 +123,7 @@ You can also declare config requirements + an example snippet:
---
name: padel
description: Check padel court availability and manage bookings via Playtomic.
metadata: {"moltbot":{"config":{"requiredEnv":["PADEL_AUTH_FILE"],"stateDirs":[".config/padel"],"example":"config = { env = { PADEL_AUTH_FILE = \\\"/run/agenix/padel-auth\\\"; }; };"}}}
metadata: {"clawdbot":{"config":{"requiredEnv":["PADEL_AUTH_FILE"],"stateDirs":[".config/padel"],"example":"config = { env = { PADEL_AUTH_FILE = \\\"/run/agenix/padel-auth\\\"; }; };"}}}
---
```
@@ -133,11 +133,11 @@ To show CLI help (recommended for nix plugins), include the `cli --help` output:
---
name: padel
description: Check padel court availability and manage bookings via Playtomic.
metadata: {"moltbot":{"cliHelp":"padel --help\\nUsage: padel [command]\\n"}}
metadata: {"clawdbot":{"cliHelp":"padel --help\\nUsage: padel [command]\\n"}}
---
```
`metadata.moltbot` is preferred, but `metadata.moltbot` is accepted as an alias for compatibility.
`metadata.clawdbot` is preferred, but `metadata.clawdis` is accepted as an alias for compatibility.
## Scripts
+1 -1
View File
@@ -1,5 +1,5 @@
{
"$schema": "https://biomejs.dev/schemas/2.3.11/schema.json",
"$schema": "https://biomejs.dev/schemas/2.3.13/schema.json",
"files": {
"includes": [
"**",
+218 -191
View File
@@ -1,9 +1,9 @@
{
"lockfileVersion": 1,
"configVersion": 0,
"configVersion": 1,
"workspaces": {
"": {
"name": "molthub",
"name": "clawhub",
"dependencies": {
"@auth/core": "^0.37.4",
"@convex-dev/auth": "^0.0.90",
@@ -21,13 +21,13 @@
"@tanstack/react-start": "^1.152.0",
"@tanstack/router-plugin": "^1.151.6",
"@vercel/analytics": "^1.6.1",
"clawhub-schema": "workspace:*",
"clsx": "^2.1.1",
"convex": "^1.31.6",
"convex-helpers": "^0.1.111",
"fflate": "^0.8.2",
"h3": "2.0.1-rc.8",
"lucide-react": "^0.562.0",
"molthub-schema": "workspace:*",
"monaco-editor": "^0.55.1",
"nitro": "^3.0.1-alpha.1",
"react": "^19.2.3",
@@ -61,11 +61,12 @@
"vitest": "^4.0.17",
},
},
"packages/molthub": {
"name": "molthub",
"version": "0.3.0",
"packages/clawdhub": {
"name": "clawhub",
"version": "0.4.0",
"bin": {
"molthub": "bin/molthub.js",
"clawhub": "bin/clawdhub.js",
"clawdhub": "bin/clawdhub.js",
},
"dependencies": {
"@clack/prompts": "^0.11.0",
@@ -86,7 +87,7 @@
},
},
"packages/schema": {
"name": "molthub-schema",
"name": "clawhub-schema",
"version": "0.0.2",
"dependencies": {
"arktype": "^2.1.29",
@@ -97,7 +98,7 @@
},
},
"packages": {
"@acemir/cssom": ["@acemir/cssom@0.9.30", "", {}, "sha512-9CnlMCI0LmCIq0olalQqdWrJHPzm0/tw3gzOA9zJSgvFX7Xau3D24mAGa4BtwxwY69nsuJW6kQqqCzf/mEcQgg=="],
"@acemir/cssom": ["@acemir/cssom@0.9.31", "", {}, "sha512-ZnR3GSaH+/vJ0YlHau21FjfLYjMpYVIzTD8M8vIEQvIGxeOXyXdzCI140rrCY862p/C/BbzWsjc1dgnM9mkoTA=="],
"@ark/schema": ["@ark/schema@0.56.0", "", { "dependencies": { "@ark/util": "0.56.0" } }, "sha512-ECg3hox/6Z/nLajxXqNhgPtNdHWC9zNsDyskwO28WinoFEnWow4IsERNz9AnXRhTZJnYIlAJ4uGn3nlLk65vZA=="],
@@ -111,23 +112,23 @@
"@auth/core": ["@auth/core@0.37.4", "", { "dependencies": { "@panva/hkdf": "^1.2.1", "jose": "^5.9.6", "oauth4webapi": "^3.1.1", "preact": "10.24.3", "preact-render-to-string": "6.5.11" }, "peerDependencies": { "@simplewebauthn/browser": "^9.0.1", "@simplewebauthn/server": "^9.0.2", "nodemailer": "^6.8.0" }, "optionalPeers": ["@simplewebauthn/browser", "@simplewebauthn/server", "nodemailer"] }, "sha512-HOXJwXWXQRhbBDHlMU0K/6FT1v+wjtzdKhsNg0ZN7/gne6XPsIrjZ4daMcFnbq0Z/vsAbYBinQhhua0d77v7qw=="],
"@babel/code-frame": ["@babel/code-frame@7.27.1", "", { "dependencies": { "@babel/helper-validator-identifier": "^7.27.1", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" } }, "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg=="],
"@babel/code-frame": ["@babel/code-frame@7.28.6", "", { "dependencies": { "@babel/helper-validator-identifier": "^7.28.5", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" } }, "sha512-JYgintcMjRiCvS8mMECzaEn+m3PfoQiyqukOMCCVQtoJGYJw8j/8LBJEiqkHLkfwCcs74E3pbAUFNg7d9VNJ+Q=="],
"@babel/compat-data": ["@babel/compat-data@7.28.5", "", {}, "sha512-6uFXyCayocRbqhZOB+6XcuZbkMNimwfVGFji8CTZnCzOHVGvDqzvitu1re2AU5LROliz7eQPhB8CpAMvnx9EjA=="],
"@babel/compat-data": ["@babel/compat-data@7.28.6", "", {}, "sha512-2lfu57JtzctfIrcGMz992hyLlByuzgIk58+hhGCxjKZ3rWI82NnVLjXcaTqkI2NvlcvOskZaiZ5kjUALo3Lpxg=="],
"@babel/core": ["@babel/core@7.28.5", "", { "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.5", "@babel/helper-compilation-targets": "^7.27.2", "@babel/helper-module-transforms": "^7.28.3", "@babel/helpers": "^7.28.4", "@babel/parser": "^7.28.5", "@babel/template": "^7.27.2", "@babel/traverse": "^7.28.5", "@babel/types": "^7.28.5", "@jridgewell/remapping": "^2.3.5", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", "json5": "^2.2.3", "semver": "^6.3.1" } }, "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw=="],
"@babel/core": ["@babel/core@7.28.6", "", { "dependencies": { "@babel/code-frame": "^7.28.6", "@babel/generator": "^7.28.6", "@babel/helper-compilation-targets": "^7.28.6", "@babel/helper-module-transforms": "^7.28.6", "@babel/helpers": "^7.28.6", "@babel/parser": "^7.28.6", "@babel/template": "^7.28.6", "@babel/traverse": "^7.28.6", "@babel/types": "^7.28.6", "@jridgewell/remapping": "^2.3.5", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", "json5": "^2.2.3", "semver": "^6.3.1" } }, "sha512-H3mcG6ZDLTlYfaSNi0iOKkigqMFvkTKlGUYlD8GW7nNOYRrevuA46iTypPyv+06V3fEmvvazfntkBU34L0azAw=="],
"@babel/generator": ["@babel/generator@7.28.5", "", { "dependencies": { "@babel/parser": "^7.28.5", "@babel/types": "^7.28.5", "@jridgewell/gen-mapping": "^0.3.12", "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" } }, "sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ=="],
"@babel/generator": ["@babel/generator@7.28.6", "", { "dependencies": { "@babel/parser": "^7.28.6", "@babel/types": "^7.28.6", "@jridgewell/gen-mapping": "^0.3.12", "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" } }, "sha512-lOoVRwADj8hjf7al89tvQ2a1lf53Z+7tiXMgpZJL3maQPDxh0DgLMN62B2MKUOFcoodBHLMbDM6WAbKgNy5Suw=="],
"@babel/helper-compilation-targets": ["@babel/helper-compilation-targets@7.27.2", "", { "dependencies": { "@babel/compat-data": "^7.27.2", "@babel/helper-validator-option": "^7.27.1", "browserslist": "^4.24.0", "lru-cache": "^5.1.1", "semver": "^6.3.1" } }, "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ=="],
"@babel/helper-compilation-targets": ["@babel/helper-compilation-targets@7.28.6", "", { "dependencies": { "@babel/compat-data": "^7.28.6", "@babel/helper-validator-option": "^7.27.1", "browserslist": "^4.24.0", "lru-cache": "^5.1.1", "semver": "^6.3.1" } }, "sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA=="],
"@babel/helper-globals": ["@babel/helper-globals@7.28.0", "", {}, "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw=="],
"@babel/helper-module-imports": ["@babel/helper-module-imports@7.27.1", "", { "dependencies": { "@babel/traverse": "^7.27.1", "@babel/types": "^7.27.1" } }, "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w=="],
"@babel/helper-module-imports": ["@babel/helper-module-imports@7.28.6", "", { "dependencies": { "@babel/traverse": "^7.28.6", "@babel/types": "^7.28.6" } }, "sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw=="],
"@babel/helper-module-transforms": ["@babel/helper-module-transforms@7.28.3", "", { "dependencies": { "@babel/helper-module-imports": "^7.27.1", "@babel/helper-validator-identifier": "^7.27.1", "@babel/traverse": "^7.28.3" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw=="],
"@babel/helper-module-transforms": ["@babel/helper-module-transforms@7.28.6", "", { "dependencies": { "@babel/helper-module-imports": "^7.28.6", "@babel/helper-validator-identifier": "^7.28.5", "@babel/traverse": "^7.28.6" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA=="],
"@babel/helper-plugin-utils": ["@babel/helper-plugin-utils@7.27.1", "", {}, "sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw=="],
"@babel/helper-plugin-utils": ["@babel/helper-plugin-utils@7.28.6", "", {}, "sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug=="],
"@babel/helper-string-parser": ["@babel/helper-string-parser@7.27.1", "", {}, "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA=="],
@@ -135,45 +136,45 @@
"@babel/helper-validator-option": ["@babel/helper-validator-option@7.27.1", "", {}, "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg=="],
"@babel/helpers": ["@babel/helpers@7.28.4", "", { "dependencies": { "@babel/template": "^7.27.2", "@babel/types": "^7.28.4" } }, "sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w=="],
"@babel/helpers": ["@babel/helpers@7.28.6", "", { "dependencies": { "@babel/template": "^7.28.6", "@babel/types": "^7.28.6" } }, "sha512-xOBvwq86HHdB7WUDTfKfT/Vuxh7gElQ+Sfti2Cy6yIWNW05P8iUslOVcZ4/sKbE+/jQaukQAdz/gf3724kYdqw=="],
"@babel/parser": ["@babel/parser@7.28.5", "", { "dependencies": { "@babel/types": "^7.28.5" }, "bin": "./bin/babel-parser.js" }, "sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ=="],
"@babel/parser": ["@babel/parser@7.28.6", "", { "dependencies": { "@babel/types": "^7.28.6" }, "bin": "./bin/babel-parser.js" }, "sha512-TeR9zWR18BvbfPmGbLampPMW+uW1NZnJlRuuHso8i87QZNq2JRF9i6RgxRqtEq+wQGsS19NNTWr2duhnE49mfQ=="],
"@babel/plugin-syntax-jsx": ["@babel/plugin-syntax-jsx@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-y8YTNIeKoyhGd9O0Jiyzyyqk8gdjnumGTQPsz0xOZOQ2RmkVJeZ1vmmfIvFEKqucBG6axJGBZDE/7iI5suUI/w=="],
"@babel/plugin-syntax-jsx": ["@babel/plugin-syntax-jsx@7.28.6", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.28.6" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-wgEmr06G6sIpqr8YDwA2dSRTE3bJ+V0IfpzfSY3Lfgd7YWOaAdlykvJi13ZKBt8cZHfgH1IXN+CL656W3uUa4w=="],
"@babel/plugin-syntax-typescript": ["@babel/plugin-syntax-typescript@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-xfYCBMxveHrRMnAWl1ZlPXOZjzkN82THFvLhQhFXFt81Z5HnN+EtUkZhv/zcKpmT3fzmWZB0ywiBrbC3vogbwQ=="],
"@babel/plugin-syntax-typescript": ["@babel/plugin-syntax-typescript@7.28.6", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.28.6" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-+nDNmQye7nlnuuHDboPbGm00Vqg3oO8niRRL27/4LYHUsHYh0zJ1xWOz0uRwNFmM1Avzk8wZbc6rdiYhomzv/A=="],
"@babel/plugin-transform-react-jsx-self": ["@babel/plugin-transform-react-jsx-self@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw=="],
"@babel/plugin-transform-react-jsx-source": ["@babel/plugin-transform-react-jsx-source@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw=="],
"@babel/runtime": ["@babel/runtime@7.28.4", "", {}, "sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ=="],
"@babel/runtime": ["@babel/runtime@7.28.6", "", {}, "sha512-05WQkdpL9COIMz4LjTxGpPNCdlpyimKppYNoJ5Di5EUObifl8t4tuLuUBBZEpoLYOmfvIWrsp9fCl0HoPRVTdA=="],
"@babel/template": ["@babel/template@7.27.2", "", { "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/parser": "^7.27.2", "@babel/types": "^7.27.1" } }, "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw=="],
"@babel/template": ["@babel/template@7.28.6", "", { "dependencies": { "@babel/code-frame": "^7.28.6", "@babel/parser": "^7.28.6", "@babel/types": "^7.28.6" } }, "sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ=="],
"@babel/traverse": ["@babel/traverse@7.28.5", "", { "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.5", "@babel/helper-globals": "^7.28.0", "@babel/parser": "^7.28.5", "@babel/template": "^7.27.2", "@babel/types": "^7.28.5", "debug": "^4.3.1" } }, "sha512-TCCj4t55U90khlYkVV/0TfkJkAkUg3jZFA3Neb7unZT8CPok7iiRfaX0F+WnqWqt7OxhOn0uBKXCw4lbL8W0aQ=="],
"@babel/traverse": ["@babel/traverse@7.28.6", "", { "dependencies": { "@babel/code-frame": "^7.28.6", "@babel/generator": "^7.28.6", "@babel/helper-globals": "^7.28.0", "@babel/parser": "^7.28.6", "@babel/template": "^7.28.6", "@babel/types": "^7.28.6", "debug": "^4.3.1" } }, "sha512-fgWX62k02qtjqdSNTAGxmKYY/7FSL9WAS1o2Hu5+I5m9T0yxZzr4cnrfXQ/MX0rIifthCSs6FKTlzYbJcPtMNg=="],
"@babel/types": ["@babel/types@7.28.5", "", { "dependencies": { "@babel/helper-string-parser": "^7.27.1", "@babel/helper-validator-identifier": "^7.28.5" } }, "sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA=="],
"@babel/types": ["@babel/types@7.28.6", "", { "dependencies": { "@babel/helper-string-parser": "^7.27.1", "@babel/helper-validator-identifier": "^7.28.5" } }, "sha512-0ZrskXVEHSWIqZM/sQZ4EV3jZJXRkio/WCxaqKZP1g//CEWEPSfeZFcms4XeKBCHU0ZKnIkdJeU/kF+eRp5lBg=="],
"@bcoe/v8-coverage": ["@bcoe/v8-coverage@1.0.2", "", {}, "sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA=="],
"@biomejs/biome": ["@biomejs/biome@2.3.11", "", { "optionalDependencies": { "@biomejs/cli-darwin-arm64": "2.3.11", "@biomejs/cli-darwin-x64": "2.3.11", "@biomejs/cli-linux-arm64": "2.3.11", "@biomejs/cli-linux-arm64-musl": "2.3.11", "@biomejs/cli-linux-x64": "2.3.11", "@biomejs/cli-linux-x64-musl": "2.3.11", "@biomejs/cli-win32-arm64": "2.3.11", "@biomejs/cli-win32-x64": "2.3.11" }, "bin": { "biome": "bin/biome" } }, "sha512-/zt+6qazBWguPG6+eWmiELqO+9jRsMZ/DBU3lfuU2ngtIQYzymocHhKiZRyrbra4aCOoyTg/BmY+6WH5mv9xmQ=="],
"@biomejs/biome": ["@biomejs/biome@2.3.13", "", { "optionalDependencies": { "@biomejs/cli-darwin-arm64": "2.3.13", "@biomejs/cli-darwin-x64": "2.3.13", "@biomejs/cli-linux-arm64": "2.3.13", "@biomejs/cli-linux-arm64-musl": "2.3.13", "@biomejs/cli-linux-x64": "2.3.13", "@biomejs/cli-linux-x64-musl": "2.3.13", "@biomejs/cli-win32-arm64": "2.3.13", "@biomejs/cli-win32-x64": "2.3.13" }, "bin": { "biome": "bin/biome" } }, "sha512-Fw7UsV0UAtWIBIm0M7g5CRerpu1eKyKAXIazzxhbXYUyMkwNrkX/KLkGI7b+uVDQ5cLUMfOC9vR60q9IDYDstA=="],
"@biomejs/cli-darwin-arm64": ["@biomejs/cli-darwin-arm64@2.3.11", "", { "os": "darwin", "cpu": "arm64" }, "sha512-/uXXkBcPKVQY7rc9Ys2CrlirBJYbpESEDme7RKiBD6MmqR2w3j0+ZZXRIL2xiaNPsIMMNhP1YnA+jRRxoOAFrA=="],
"@biomejs/cli-darwin-arm64": ["@biomejs/cli-darwin-arm64@2.3.13", "", { "os": "darwin", "cpu": "arm64" }, "sha512-0OCwP0/BoKzyJHnFdaTk/i7hIP9JHH9oJJq6hrSCPmJPo8JWcJhprK4gQlhFzrwdTBAW4Bjt/RmCf3ZZe59gwQ=="],
"@biomejs/cli-darwin-x64": ["@biomejs/cli-darwin-x64@2.3.11", "", { "os": "darwin", "cpu": "x64" }, "sha512-fh7nnvbweDPm2xEmFjfmq7zSUiox88plgdHF9OIW4i99WnXrAC3o2P3ag9judoUMv8FCSUnlwJCM1B64nO5Fbg=="],
"@biomejs/cli-darwin-x64": ["@biomejs/cli-darwin-x64@2.3.13", "", { "os": "darwin", "cpu": "x64" }, "sha512-AGr8OoemT/ejynbIu56qeil2+F2WLkIjn2d8jGK1JkchxnMUhYOfnqc9sVzcRxpG9Ycvw4weQ5sprRvtb7Yhcw=="],
"@biomejs/cli-linux-arm64": ["@biomejs/cli-linux-arm64@2.3.11", "", { "os": "linux", "cpu": "arm64" }, "sha512-l4xkGa9E7Uc0/05qU2lMYfN1H+fzzkHgaJoy98wO+b/7Gl78srbCRRgwYSW+BTLixTBrM6Ede5NSBwt7rd/i6g=="],
"@biomejs/cli-linux-arm64": ["@biomejs/cli-linux-arm64@2.3.13", "", { "os": "linux", "cpu": "arm64" }, "sha512-xvOiFkrDNu607MPMBUQ6huHmBG1PZLOrqhtK6pXJW3GjfVqJg0Z/qpTdhXfcqWdSZHcT+Nct2fOgewZvytESkw=="],
"@biomejs/cli-linux-arm64-musl": ["@biomejs/cli-linux-arm64-musl@2.3.11", "", { "os": "linux", "cpu": "arm64" }, "sha512-XPSQ+XIPZMLaZ6zveQdwNjbX+QdROEd1zPgMwD47zvHV+tCGB88VH+aynyGxAHdzL+Tm/+DtKST5SECs4iwCLg=="],
"@biomejs/cli-linux-arm64-musl": ["@biomejs/cli-linux-arm64-musl@2.3.13", "", { "os": "linux", "cpu": "arm64" }, "sha512-TUdDCSY+Eo/EHjhJz7P2GnWwfqet+lFxBZzGHldrvULr59AgahamLs/N85SC4+bdF86EhqDuuw9rYLvLFWWlXA=="],
"@biomejs/cli-linux-x64": ["@biomejs/cli-linux-x64@2.3.11", "", { "os": "linux", "cpu": "x64" }, "sha512-/1s9V/H3cSe0r0Mv/Z8JryF5x9ywRxywomqZVLHAoa/uN0eY7F8gEngWKNS5vbbN/BsfpCG5yeBT5ENh50Frxg=="],
"@biomejs/cli-linux-x64": ["@biomejs/cli-linux-x64@2.3.13", "", { "os": "linux", "cpu": "x64" }, "sha512-s+YsZlgiXNq8XkgHs6xdvKDFOj/bwTEevqEY6rC2I3cBHbxXYU1LOZstH3Ffw9hE5tE1sqT7U23C00MzkXztMw=="],
"@biomejs/cli-linux-x64-musl": ["@biomejs/cli-linux-x64-musl@2.3.11", "", { "os": "linux", "cpu": "x64" }, "sha512-vU7a8wLs5C9yJ4CB8a44r12aXYb8yYgBn+WeyzbMjaCMklzCv1oXr8x+VEyWodgJt9bDmhiaW/I0RHbn7rsNmw=="],
"@biomejs/cli-linux-x64-musl": ["@biomejs/cli-linux-x64-musl@2.3.13", "", { "os": "linux", "cpu": "x64" }, "sha512-0bdwFVSbbM//Sds6OjtnmQGp4eUjOTt6kHvR/1P0ieR9GcTUAlPNvPC3DiavTqq302W34Ae2T6u5VVNGuQtGlQ=="],
"@biomejs/cli-win32-arm64": ["@biomejs/cli-win32-arm64@2.3.11", "", { "os": "win32", "cpu": "arm64" }, "sha512-PZQ6ElCOnkYapSsysiTy0+fYX+agXPlWugh6+eQ6uPKI3vKAqNp6TnMhoM3oY2NltSB89hz59o8xIfOdyhi9Iw=="],
"@biomejs/cli-win32-arm64": ["@biomejs/cli-win32-arm64@2.3.13", "", { "os": "win32", "cpu": "arm64" }, "sha512-QweDxY89fq0VvrxME+wS/BXKmqMrOTZlN9SqQ79kQSIc3FrEwvW/PvUegQF6XIVaekncDykB5dzPqjbwSKs9DA=="],
"@biomejs/cli-win32-x64": ["@biomejs/cli-win32-x64@2.3.11", "", { "os": "win32", "cpu": "x64" }, "sha512-43VrG813EW+b5+YbDbz31uUsheX+qFKCpXeY9kfdAx+ww3naKxeVkTD9zLIWxUPfJquANMHrmW3wbe/037G0Qg=="],
"@biomejs/cli-win32-x64": ["@biomejs/cli-win32-x64@2.3.13", "", { "os": "win32", "cpu": "x64" }, "sha512-trDw2ogdM2lyav9WFQsdsfdVy1dvZALymRpgmWsvSez0BJzBjulhOT/t+wyKeh3pZWvwP3VMs1SoOKwO3wecMQ=="],
"@clack/core": ["@clack/core@0.5.0", "", { "dependencies": { "picocolors": "^1.0.0", "sisteransi": "^1.0.5" } }, "sha512-p3y0FIOwaYRUPRcMO7+dlmLh8PSRcrjuTndsiA0WAFbWES0mLZlrjVoBRZ9DzkPFJZG6KGkJmoEAY0ZcVWTkow=="],
@@ -189,13 +190,13 @@
"@csstools/css-parser-algorithms": ["@csstools/css-parser-algorithms@3.0.5", "", { "peerDependencies": { "@csstools/css-tokenizer": "^3.0.4" } }, "sha512-DaDeUkXZKjdGhgYaHNJTV9pV7Y9B3b644jCLs9Upc3VeNGg6LWARAT6O+Q+/COo+2gg/bM5rhpMAtf70WqfBdQ=="],
"@csstools/css-syntax-patches-for-csstree": ["@csstools/css-syntax-patches-for-csstree@1.0.22", "", {}, "sha512-qBcx6zYlhleiFfdtzkRgwNC7VVoAwfK76Vmsw5t+PbvtdknO9StgRk7ROvq9so1iqbdW4uLIDAsXRsTfUrIoOw=="],
"@csstools/css-syntax-patches-for-csstree": ["@csstools/css-syntax-patches-for-csstree@1.0.26", "", {}, "sha512-6boXK0KkzT5u5xOgF6TKB+CLq9SOpEGmkZw0g5n9/7yg85wab3UzSxB8TxhLJ31L4SGJ6BCFRw/iftTha1CJXA=="],
"@csstools/css-tokenizer": ["@csstools/css-tokenizer@3.0.4", "", {}, "sha512-Vd/9EVDiu6PPJt9yAh6roZP6El1xHrdvIVGjyBsHR0RYwNHgL7FJPyIIW4fANJNG6FtyZfvlRPpFI4ZM/lubvw=="],
"@emnapi/core": ["@emnapi/core@1.8.0", "", { "dependencies": { "@emnapi/wasi-threads": "1.1.0", "tslib": "^2.4.0" } }, "sha512-ryJnSmj4UhrGLZZPJ6PKVb4wNPAIkW6iyLy+0TRwazd3L1u0wzMe8RfqevAh2HbcSkoeLiSYnOVDOys4JSGYyg=="],
"@emnapi/core": ["@emnapi/core@1.8.1", "", { "dependencies": { "@emnapi/wasi-threads": "1.1.0", "tslib": "^2.4.0" } }, "sha512-AvT9QFpxK0Zd8J0jopedNm+w/2fIzvtPKPjqyw9jwvBaReTTqPBk9Hixaz7KbjimP+QNz605/XnjFcDAL2pqBg=="],
"@emnapi/runtime": ["@emnapi/runtime@1.8.0", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-Z82FDl1ByxqPEPrAYYeTQVlx2FSHPe1qwX465c+96IRS3fTdSYRoJcRxg3g2fEG5I69z1dSEWQlNRRr0/677mg=="],
"@emnapi/runtime": ["@emnapi/runtime@1.8.1", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-mehfKSMWjjNol8659Z8KxEMrdSJDDot5SXMq00dM8BN4o+CLNXQ0xH2V7EchNHV4RmbZLmmPdEaXZc5H2FXmDg=="],
"@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.1.0", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ=="],
@@ -251,13 +252,13 @@
"@esbuild/win32-x64": ["@esbuild/win32-x64@0.27.2", "", { "os": "win32", "cpu": "x64" }, "sha512-sRdU18mcKf7F+YgheI/zGf5alZatMUTKj/jNS6l744f9u3WFu4v7twcUI9vu4mknF4Y9aDlblIie0IM+5xxaqQ=="],
"@exodus/bytes": ["@exodus/bytes@1.8.0", "", { "peerDependencies": { "@exodus/crypto": "^1.0.0-rc.4" }, "optionalPeers": ["@exodus/crypto"] }, "sha512-8JPn18Bcp8Uo1T82gR8lh2guEOa5KKU/IEKvvdp0sgmi7coPBWf1Doi1EXsGZb2ehc8ym/StJCjffYV+ne7sXQ=="],
"@exodus/bytes": ["@exodus/bytes@1.10.0", "", { "peerDependencies": { "@noble/hashes": "^1.8.0 || ^2.0.0" }, "optionalPeers": ["@noble/hashes"] }, "sha512-tf8YdcbirXdPnJ+Nd4UN1EXnz+IP2DI45YVEr3vvzcVTOyrApkmIB4zvOQVd3XPr7RXnfBtAx+PXImXOIU0Ajg=="],
"@floating-ui/core": ["@floating-ui/core@1.7.3", "", { "dependencies": { "@floating-ui/utils": "^0.2.10" } }, "sha512-sGnvb5dmrJaKEZ+LDIpguvdX3bDlEllmv4/ClQ9awcmCZrlx5jQyyMWFM5kBI+EyNOCDDiKk8il0zeuX3Zlg/w=="],
"@floating-ui/core": ["@floating-ui/core@1.7.4", "", { "dependencies": { "@floating-ui/utils": "^0.2.10" } }, "sha512-C3HlIdsBxszvm5McXlB8PeOEWfBhcGBTZGkGlWc2U0KFY5IwG5OQEuQ8rq52DZmcHDlPLd+YFBK+cZcytwIFWg=="],
"@floating-ui/dom": ["@floating-ui/dom@1.7.4", "", { "dependencies": { "@floating-ui/core": "^1.7.3", "@floating-ui/utils": "^0.2.10" } }, "sha512-OOchDgh4F2CchOX94cRVqhvy7b3AFb+/rQXyswmzmGakRfkMgoWVjfnLWkRirfLEfuD4ysVW16eXzwt3jHIzKA=="],
"@floating-ui/dom": ["@floating-ui/dom@1.7.5", "", { "dependencies": { "@floating-ui/core": "^1.7.4", "@floating-ui/utils": "^0.2.10" } }, "sha512-N0bD2kIPInNHUHehXhMke1rBGs1dwqvC9O9KYMyyjK7iXt7GAhnro7UlcuYcGdS/yYOlq0MAVgrow8IbWJwyqg=="],
"@floating-ui/react-dom": ["@floating-ui/react-dom@2.1.6", "", { "dependencies": { "@floating-ui/dom": "^1.7.4" }, "peerDependencies": { "react": ">=16.8.0", "react-dom": ">=16.8.0" } }, "sha512-4JX6rEatQEvlmgU80wZyq9RT96HZJa88q8hp0pBd+LrczeDI4o6uA2M+uvxngVHo4Ihr8uibXxH6+70zhAFrVw=="],
"@floating-ui/react-dom": ["@floating-ui/react-dom@2.1.7", "", { "dependencies": { "@floating-ui/dom": "^1.7.5" }, "peerDependencies": { "react": ">=16.8.0", "react-dom": ">=16.8.0" } }, "sha512-0tLRojf/1Go2JgEVm+3Frg9A3IW8bJgKgdO0BN5RkF//ufuz2joZM63Npau2ff3J6lUVYgDSNzNkR+aH3IVfjg=="],
"@floating-ui/utils": ["@floating-ui/utils@0.2.10", "", {}, "sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ=="],
@@ -299,97 +300,117 @@
"@oslojs/encoding": ["@oslojs/encoding@1.1.0", "", {}, "sha512-70wQhgYmndg4GCPxPPxPGevRKqTIJ2Nh4OkiMWmDAVYsTQ+Ta7Sq+rPevXyXGdzr30/qZBnyOalCszoMxlyldQ=="],
"@oxc-minify/binding-android-arm64": ["@oxc-minify/binding-android-arm64@0.96.0", "", { "os": "android", "cpu": "arm64" }, "sha512-lzeIEMu/v6Y+La5JSesq4hvyKtKBq84cgQpKYTYM/yGuNk2tfd5Ha31hnC+mTh48lp/5vZH+WBfjVUjjINCfug=="],
"@oxc-minify/binding-android-arm-eabi": ["@oxc-minify/binding-android-arm-eabi@0.110.0", "", { "os": "android", "cpu": "arm" }, "sha512-43fMTO8/5bMlqfOiNSZNKUzIqeLIYuB9Hr1Ohyf58B1wU11S2dPGibTXOGNaWsfgHy99eeZ1bSgeIHy/fEYqbw=="],
"@oxc-minify/binding-darwin-arm64": ["@oxc-minify/binding-darwin-arm64@0.96.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-i0LkJAUXb4BeBFrJQbMKQPoxf8+cFEffDyLSb7NEzzKuPcH8qrVsnEItoOzeAdYam8Sr6qCHVwmBNEQzl7PWpw=="],
"@oxc-minify/binding-android-arm64": ["@oxc-minify/binding-android-arm64@0.110.0", "", { "os": "android", "cpu": "arm64" }, "sha512-5oQrnn9eK/ccOp80PTrNj0Vq893NPNNRryjGpOIVsYNgWFuoGCfpnKg68oEFcN8bArizYAqw4nvgHljEnar69w=="],
"@oxc-minify/binding-darwin-x64": ["@oxc-minify/binding-darwin-x64@0.96.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-C5vI0WPR+KPIFAD5LMOJk2J8iiT+Nv65vDXmemzXEXouzfEOLYNqnW+u6NSsccpuZHHWAiLyPFkYvKFduveAUQ=="],
"@oxc-minify/binding-darwin-arm64": ["@oxc-minify/binding-darwin-arm64@0.110.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-dqBDgTG9tF2z2lrZp9E8wU+Godz1i8gCGSei2eFKS2hRploBOD5dmOLp1j4IMornkPvSQmbwB3uSjPq7fjx4EA=="],
"@oxc-minify/binding-freebsd-x64": ["@oxc-minify/binding-freebsd-x64@0.96.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-3//5DNx+xUjVBMLLk2sl6hfe4fwfENJtjVQUBXjxzwPuv8xgZUqASG4cRG3WqG5Qe8dV6SbCI4EgKQFjO4KCZA=="],
"@oxc-minify/binding-darwin-x64": ["@oxc-minify/binding-darwin-x64@0.110.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-U0AqabqaooDOpYmeeOye8wClv8PSScELXgOfYqyqgrwH9J9KrpCE1jL8Rlqgz68QbL4mPw3V6sKiiHssI4CLeQ=="],
"@oxc-minify/binding-linux-arm-gnueabihf": ["@oxc-minify/binding-linux-arm-gnueabihf@0.96.0", "", { "os": "linux", "cpu": "arm" }, "sha512-WXChFKV7VdDk1NePDK1J31cpSvxACAVztJ7f7lJVYBTkH+iz5D0lCqPcE7a9eb7nC3xvz4yk7DM6dA9wlUQkQg=="],
"@oxc-minify/binding-freebsd-x64": ["@oxc-minify/binding-freebsd-x64@0.110.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-H0w8o/Wo1072WSdLfhwwrpFpwZnPpjQODlHuRYkTfsSSSJbTxQtjJd4uxk7YJsRv5RQp69y0I7zvdH6f8Xueyw=="],
"@oxc-minify/binding-linux-arm-musleabihf": ["@oxc-minify/binding-linux-arm-musleabihf@0.96.0", "", { "os": "linux", "cpu": "arm" }, "sha512-7B18glYMX4Z/YoqgE3VRLs/2YhVLxlxNKSgrtsRpuR8xv58xca+hEhiFwZN1Rn+NSMZ29Z33LWD7iYWnqYFvRA=="],
"@oxc-minify/binding-linux-arm-gnueabihf": ["@oxc-minify/binding-linux-arm-gnueabihf@0.110.0", "", { "os": "linux", "cpu": "arm" }, "sha512-qd6sW0AvEVYZhbVVMGtmKZw3b1zDYGIW+54Uh42moWRAj6i4Jhk/LGr6r9YNZpOINeuvZfkFuEeDD/jbu7xPUA=="],
"@oxc-minify/binding-linux-arm64-gnu": ["@oxc-minify/binding-linux-arm64-gnu@0.96.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-Yl+KcTldsEJNcaYxxonwAXZ2q3gxIzn3kXYQWgKWdaGIpNhOCWqF+KE5WLsldoh5Ro5SHtomvb8GM6cXrIBMog=="],
"@oxc-minify/binding-linux-arm-musleabihf": ["@oxc-minify/binding-linux-arm-musleabihf@0.110.0", "", { "os": "linux", "cpu": "arm" }, "sha512-7WXP0aXMrWSn0ScppUBi3jf68ebfBG0eri8kxLmBOVSBj6jw1repzkHMITJMBeLr5d0tT/51qFEptiAk2EP2iA=="],
"@oxc-minify/binding-linux-arm64-musl": ["@oxc-minify/binding-linux-arm64-musl@0.96.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-rNqoFWOWaxwMmUY5fspd/h5HfvgUlA3sv9CUdA2MpnHFiyoJNovR7WU8tGh+Yn0qOAs0SNH0a05gIthHig14IA=="],
"@oxc-minify/binding-linux-arm64-gnu": ["@oxc-minify/binding-linux-arm64-gnu@0.110.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-LYfADrq5x1W5gs+u9OIbMbDQNYkAECTXX0ufnAuf3oGmO51rF98kGFR5qJqC/6/csokDyT3wwTpxhE0TkcF/Og=="],
"@oxc-minify/binding-linux-riscv64-gnu": ["@oxc-minify/binding-linux-riscv64-gnu@0.96.0", "", { "os": "linux", "cpu": "none" }, "sha512-3paajIuzGnukHwSI3YBjYVqbd72pZd8NJxaayaNFR0AByIm8rmIT5RqFXbq8j2uhtpmNdZRXiu0em1zOmIScWA=="],
"@oxc-minify/binding-linux-arm64-musl": ["@oxc-minify/binding-linux-arm64-musl@0.110.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-53GjCVY8kvymk9P6qNDh6zyblcehF5QHstq9QgCjv13ONGRnSHjeds0PxIwiihD7h295bxsWs84DN39syLPH4Q=="],
"@oxc-minify/binding-linux-s390x-gnu": ["@oxc-minify/binding-linux-s390x-gnu@0.96.0", "", { "os": "linux", "cpu": "s390x" }, "sha512-9ESrpkB2XG0lQ89JlsxlZa86iQCOs+jkDZLl6O+u5wb7ynUy21bpJJ1joauCOSYIOUlSy3+LbtJLiqi7oSQt5Q=="],
"@oxc-minify/binding-linux-ppc64-gnu": ["@oxc-minify/binding-linux-ppc64-gnu@0.110.0", "", { "os": "linux", "cpu": "ppc64" }, "sha512-li8XcN81dxbJDMBESnTgGhoiAQ+CNIdM0QGscZ4duVPjCry1RpX+5FJySFbGqG3pk4s9ZzlL/vtQtbRzZIZOzg=="],
"@oxc-minify/binding-linux-x64-gnu": ["@oxc-minify/binding-linux-x64-gnu@0.96.0", "", { "os": "linux", "cpu": "x64" }, "sha512-UMM1jkns+p+WwwmdjC5giI3SfR2BCTga18x3C0cAu6vDVf4W37uTZeTtSIGmwatTBbgiq++Te24/DE0oCdm1iQ=="],
"@oxc-minify/binding-linux-riscv64-gnu": ["@oxc-minify/binding-linux-riscv64-gnu@0.110.0", "", { "os": "linux", "cpu": "none" }, "sha512-SweKfsnLKShu6UFV8mwuj1d1wmlNoL/FlAxPUzwjEBgwiT2HQkY24KnjBH+TIA+//1O83kzmWKvvs4OuEhdIEQ=="],
"@oxc-minify/binding-linux-x64-musl": ["@oxc-minify/binding-linux-x64-musl@0.96.0", "", { "os": "linux", "cpu": "x64" }, "sha512-8b1naiC7MdP7xeMi7cQ5tb9W1rZAP9Qz/jBRqp1Y5EOZ1yhSGnf1QWuZ/0pCc+XiB9vEHXEY3Aki/H+86m2eOg=="],
"@oxc-minify/binding-linux-riscv64-musl": ["@oxc-minify/binding-linux-riscv64-musl@0.110.0", "", { "os": "linux", "cpu": "none" }, "sha512-oH8G4aFMP8XyTsEpdANC5PQyHgSeGlopHZuW1rpyYcaErg5YaK0vXjQ4EM5HVvPm+feBV24JjxgakTnZoF3aOQ=="],
"@oxc-minify/binding-wasm32-wasi": ["@oxc-minify/binding-wasm32-wasi@0.96.0", "", { "dependencies": { "@napi-rs/wasm-runtime": "^1.0.7" }, "cpu": "none" }, "sha512-bjGDjkGzo3GWU9Vg2qiFUrfoo5QxojPNV/2RHTlbIB5FWkkV4ExVjsfyqihFiAuj0NXIZqd2SAiEq9htVd3RFw=="],
"@oxc-minify/binding-linux-s390x-gnu": ["@oxc-minify/binding-linux-s390x-gnu@0.110.0", "", { "os": "linux", "cpu": "s390x" }, "sha512-W9na+Vza7XVUlpf8wMt4QBfH35KeTENEmnpPUq3NSlbQHz8lSlSvhAafvo43NcKvHAXV3ckD/mUf2VkqSdbklg=="],
"@oxc-minify/binding-win32-arm64-msvc": ["@oxc-minify/binding-win32-arm64-msvc@0.96.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-4L4DlHUT47qMWQuTyUghpncR3NZHWtxvd0G1KgSjVgXf+cXzFdWQCWZZtCU0yrmOoVCNUf4S04IFCJyAe+Ie7A=="],
"@oxc-minify/binding-linux-x64-gnu": ["@oxc-minify/binding-linux-x64-gnu@0.110.0", "", { "os": "linux", "cpu": "x64" }, "sha512-XJdA4mmmXOjJxSRgNJXsDP7Xe8h3gQhmb56hUcCrvq5d+h5UcEi2pR8rxsdIrS8QmkLuBA3eHkGK8E27D7DTgQ=="],
"@oxc-minify/binding-win32-x64-msvc": ["@oxc-minify/binding-win32-x64-msvc@0.96.0", "", { "os": "win32", "cpu": "x64" }, "sha512-T2ijfqZLpV2bgGGocXV4SXTuMoouqN0asYTIm+7jVOLvT5XgDogf3ZvCmiEnSWmxl21+r5wHcs8voU2iUROXAg=="],
"@oxc-minify/binding-linux-x64-musl": ["@oxc-minify/binding-linux-x64-musl@0.110.0", "", { "os": "linux", "cpu": "x64" }, "sha512-QqzvALuOTtSckI8x467R4GNArzYDb/yEh6aNzLoeaY1O7vfT7SPDwlOEcchaTznutpeS9Dy8gUS/AfqtUHaufw=="],
"@oxc-transform/binding-android-arm64": ["@oxc-transform/binding-android-arm64@0.96.0", "", { "os": "android", "cpu": "arm64" }, "sha512-wOm+ZsqFvyZ7B9RefUMsj0zcXw77Z2pXA51nbSQyPXqr+g0/pDGxriZWP8Sdpz/e4AEaKPA9DvrwyOZxu7GRDQ=="],
"@oxc-minify/binding-openharmony-arm64": ["@oxc-minify/binding-openharmony-arm64@0.110.0", "", { "os": "none", "cpu": "arm64" }, "sha512-gAMssLs2Q3+uhLZxanh1DF+27Kaug3cf4PXb9AB7XK81DR+LVcKySXaoGYoOs20Co0fFSphd6rRzKge2qDK3dA=="],
"@oxc-transform/binding-darwin-arm64": ["@oxc-transform/binding-darwin-arm64@0.96.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-td1sbcvzsyuoNRiNdIRodPXRtFFwxzPpC/6/yIUtRRhKn30XQcizxupIvQQVpJWWchxkphbBDh6UN+u+2CJ8Zw=="],
"@oxc-minify/binding-wasm32-wasi": ["@oxc-minify/binding-wasm32-wasi@0.110.0", "", { "dependencies": { "@napi-rs/wasm-runtime": "^1.1.1" }, "cpu": "none" }, "sha512-7Wqi5Zjl022bs2zXq+ICdalDPeDuCH/Nhbi8q2isLihAonMVIT0YH2hqqnNEylRNGYck+FJ6gRZwMpGCgrNxPg=="],
"@oxc-transform/binding-darwin-x64": ["@oxc-transform/binding-darwin-x64@0.96.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-xgqxnqhPYH2NYkgbqtnCJfhbXvxIf/pnhF/ig5UBK8PYpCEWIP/cfLpQRQ9DcQnRfuxi7RMIF6LdmB1AiS6Fkg=="],
"@oxc-minify/binding-win32-arm64-msvc": ["@oxc-minify/binding-win32-arm64-msvc@0.110.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-ZPx+0Tj4dqn41ecyoGotlvekQKy6JxJCixn9Rw7h/dafZ3eDuBcEVh3c2ZoldXXsyMIt5ywI8IWzFZsjNedd5Q=="],
"@oxc-transform/binding-freebsd-x64": ["@oxc-transform/binding-freebsd-x64@0.96.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-1i67OXdl/rvSkcTXqDlh6qGRXYseEmf0rl/R+/i88scZ/o3A+FzlX56sThuaPzSSv9eVgesnoYUjIBJELFc1oA=="],
"@oxc-minify/binding-win32-ia32-msvc": ["@oxc-minify/binding-win32-ia32-msvc@0.110.0", "", { "os": "win32", "cpu": "ia32" }, "sha512-H0Oyd3RWBfpEyvJIrFK94RYiY7KKSQl11Ym7LMDwLEagelIAfRCkt1amHZhFa/S3ZRoaOJFXzEw4YKeSsjVFsg=="],
"@oxc-transform/binding-linux-arm-gnueabihf": ["@oxc-transform/binding-linux-arm-gnueabihf@0.96.0", "", { "os": "linux", "cpu": "arm" }, "sha512-9MJBs0SWODsqyzO3eAnacXgJ/sZu1xqinjEwBzkcZ3tQI8nKhMADOzu2NzbVWDWujeoC8DESXaO08tujvUru+Q=="],
"@oxc-minify/binding-win32-x64-msvc": ["@oxc-minify/binding-win32-x64-msvc@0.110.0", "", { "os": "win32", "cpu": "x64" }, "sha512-Hr3nK90+qXKJ2kepXwFIcNfQQIOBecB4FFCyaMMypthoEEhVP08heRynj4eSXZ8NL9hLjs3fQzH8PJXfpznRnQ=="],
"@oxc-transform/binding-linux-arm-musleabihf": ["@oxc-transform/binding-linux-arm-musleabihf@0.96.0", "", { "os": "linux", "cpu": "arm" }, "sha512-BQom57I2ScccixljNYh2Wy+5oVZtF1LXiiUPxSLtDHbsanpEvV/+kzCagQpTjk1BVzSQzOxfEUWjvL7mY53pRQ=="],
"@oxc-transform/binding-android-arm-eabi": ["@oxc-transform/binding-android-arm-eabi@0.110.0", "", { "os": "android", "cpu": "arm" }, "sha512-sE9dxvqqAax1YYJ3t7j+h5ZSI9jl6dYuDfngl6ieZUrIy5P89/8JKVgAzgp8o3wQSo7ndpJvYsi1K4ZqrmbP7w=="],
"@oxc-transform/binding-linux-arm64-gnu": ["@oxc-transform/binding-linux-arm64-gnu@0.96.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-kaqvUzNu8LL4aBSXqcqGVLFG13GmJEplRI2+yqzkgAItxoP/LfFMdEIErlTWLGyBwd0OLiNMHrOvkcCQRWadVg=="],
"@oxc-transform/binding-android-arm64": ["@oxc-transform/binding-android-arm64@0.110.0", "", { "os": "android", "cpu": "arm64" }, "sha512-nqtbP4aMCtsCZ6qpHlHaQoWVHSBtlKzwaAgwEOvR+9DWqHjk31BHvpGiDXlMeed6CVNpl3lCbWgygb3RcSjcfw=="],
"@oxc-transform/binding-linux-arm64-musl": ["@oxc-transform/binding-linux-arm64-musl@0.96.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-EiG/L3wEkPgTm4p906ufptyblBgtiQWTubGg/JEw82f8uLRroayr5zhbUqx40EgH037a3SfJthIyLZi7XPRFJw=="],
"@oxc-transform/binding-darwin-arm64": ["@oxc-transform/binding-darwin-arm64@0.110.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-oeSeHnL4Z4cMXtc8V0/rwoVn0dgwlS9q0j6LcHn9dIhtFEdp3W0iSBF8YmMQA+E7sILeLDjsHmHE4Kp0sOScXw=="],
"@oxc-transform/binding-linux-riscv64-gnu": ["@oxc-transform/binding-linux-riscv64-gnu@0.96.0", "", { "os": "linux", "cpu": "none" }, "sha512-r01CY6OxKGtVeYnvH4mGmtkQMlLkXdPWWNXwo5o7fE2s/fgZPMpqh8bAuXEhuMXipZRJrjxTk1+ZQ4KCHpMn3Q=="],
"@oxc-transform/binding-darwin-x64": ["@oxc-transform/binding-darwin-x64@0.110.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-nL9K5x7OuZydobAGPylsEW9d4APs2qEkIBLMgQPA+kY8dtVD3IR87QsTbs4l4DBQYyun/+ay6qVCDlxqxdX2Jg=="],
"@oxc-transform/binding-linux-s390x-gnu": ["@oxc-transform/binding-linux-s390x-gnu@0.96.0", "", { "os": "linux", "cpu": "s390x" }, "sha512-4djg2vYLGbVeS8YiA2K4RPPpZE4fxTGCX5g/bOMbCYyirDbmBAIop4eOAj8vOA9i1CcWbDtmp+PVJ1dSw7f3IQ=="],
"@oxc-transform/binding-freebsd-x64": ["@oxc-transform/binding-freebsd-x64@0.110.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-GS29zXXirDQhZEUq8xKJ1azAWMuUy3Ih3W5Bc5ddk12LRthO5wRLFcKIyeHpAXCoXymQ+LmxbMtbPf84GPxouw=="],
"@oxc-transform/binding-linux-x64-gnu": ["@oxc-transform/binding-linux-x64-gnu@0.96.0", "", { "os": "linux", "cpu": "x64" }, "sha512-f6pcWVz57Y8jXa2OS7cz3aRNuks34Q3j61+3nQ4xTE8H1KbalcEvHNmM92OEddaJ8QLs9YcE0kUC6eDTbY34+A=="],
"@oxc-transform/binding-linux-arm-gnueabihf": ["@oxc-transform/binding-linux-arm-gnueabihf@0.110.0", "", { "os": "linux", "cpu": "arm" }, "sha512-glzDHak8ISyZJemCUi7RCvzNSl+MQ1ly9RceT2qRufhUsvNZ4C/2QLJ1HJwd2N6E88bO4laYn+RofdRzNnGGEA=="],
"@oxc-transform/binding-linux-x64-musl": ["@oxc-transform/binding-linux-x64-musl@0.96.0", "", { "os": "linux", "cpu": "x64" }, "sha512-NSiRtFvR7Pbhv3mWyPMkTK38czIjcnK0+K5STo3CuzZRVbX1TM17zGdHzKBUHZu7v6IQ6/XsQ3ELa1BlEHPGWQ=="],
"@oxc-transform/binding-linux-arm-musleabihf": ["@oxc-transform/binding-linux-arm-musleabihf@0.110.0", "", { "os": "linux", "cpu": "arm" }, "sha512-8JThvgJ2FRoTVfbp7e4wqeZqCZbtudM06SfZmNzND9kPNu/LVYygIR+72RWs+xm4bWkuYHg/islo/boNPtMT5Q=="],
"@oxc-transform/binding-wasm32-wasi": ["@oxc-transform/binding-wasm32-wasi@0.96.0", "", { "dependencies": { "@napi-rs/wasm-runtime": "^1.0.7" }, "cpu": "none" }, "sha512-A91ARLiuZHGN4hBds9s7bW3czUuLuHLsV+cz44iF9j8e1zX9m2hNGXf/acQRbg/zcFUXmjz5nmk8EkZyob876w=="],
"@oxc-transform/binding-linux-arm64-gnu": ["@oxc-transform/binding-linux-arm64-gnu@0.110.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-IRh21Ub/g4bkHoErZ0AUWMlWfoZaS0A6EaOVtbcY70RSYIMlrsbjiFwJCzM+b/1DD1rXbH5tsGcH7GweTbfRqg=="],
"@oxc-transform/binding-win32-arm64-msvc": ["@oxc-transform/binding-win32-arm64-msvc@0.96.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-IedJf40djKgDObomhYjdRAlmSYUEdfqX3A3M9KfUltl9AghTBBLkTzUMA7O09oo71vYf5TEhbFM7+Vn5vqw7AQ=="],
"@oxc-transform/binding-linux-arm64-musl": ["@oxc-transform/binding-linux-arm64-musl@0.110.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-e5JN94/oy+wevk76q+LMr+2klTTcO60uXa+Wkq558Ms7mdF2TvkKFI++d/JeiuIwJLTi/BxQ4qdT5FWcsHM/ug=="],
"@oxc-transform/binding-win32-x64-msvc": ["@oxc-transform/binding-win32-x64-msvc@0.96.0", "", { "os": "win32", "cpu": "x64" }, "sha512-0fI0P0W7bSO/GCP/N5dkmtB9vBqCA4ggo1WmXTnxNJVmFFOtcA1vYm1I9jl8fxo+sucW2WnlpnI4fjKdo3JKxA=="],
"@oxc-transform/binding-linux-ppc64-gnu": ["@oxc-transform/binding-linux-ppc64-gnu@0.110.0", "", { "os": "linux", "cpu": "ppc64" }, "sha512-Y3/Tnnz1GvDpmv8FXBIKtdZPsdZklOEPdrL6NHrN5i2u54BOkybFaDSptgWF53wOrJlTrcmAVSE6fRKK9XCM2Q=="],
"@oxlint-tsgolint/darwin-arm64": ["@oxlint-tsgolint/darwin-arm64@0.11.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-UJIOFeJZpFTJIGS+bMdFXcvjslvnXBEouMvzynfQD7RTazcFIRLbokYgEbhrN2P6B352Ut1TUtvR0CLAp/9QfA=="],
"@oxc-transform/binding-linux-riscv64-gnu": ["@oxc-transform/binding-linux-riscv64-gnu@0.110.0", "", { "os": "linux", "cpu": "none" }, "sha512-Y0E35iA9/v9jlkNcP6tMJ+ZFOS0rLsWDqG6rU9z+X2R3fBFJBO9UARIK6ngx8upxk81y1TFR2CmBFhupfYdH6Q=="],
"@oxlint-tsgolint/darwin-x64": ["@oxlint-tsgolint/darwin-x64@0.11.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-68O8YvexIm+ISZKl2vBFII1dMfLrteDyPcuCIecDuiBIj2tV0KYq13zpSCMz4dvJUWJW6RmOOGZKrkkvOAy6uQ=="],
"@oxc-transform/binding-linux-riscv64-musl": ["@oxc-transform/binding-linux-riscv64-musl@0.110.0", "", { "os": "linux", "cpu": "none" }, "sha512-JOUSYFfHjBUs7xp2FHmZHb8eTYD/oEu0NklS6JgUauqnoXZHiTLPLVW2o2uVCqldnabYHcomuwI2iqVFYJNhTw=="],
"@oxlint-tsgolint/linux-arm64": ["@oxlint-tsgolint/linux-arm64@0.11.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-hXBInrFxPNbPPbPQYozo8YpSsFFYdtHBWRUiLMxul71vTy1CdSA7H5Qq2KbrKomr/ASmhvIDVAQZxh9hIJNHMA=="],
"@oxc-transform/binding-linux-s390x-gnu": ["@oxc-transform/binding-linux-s390x-gnu@0.110.0", "", { "os": "linux", "cpu": "s390x" }, "sha512-7blgoXF9D3Ngzb7eun23pNrHJpoV/TtE6LObwlZ3Nmb4oZ6Z+yMvBVaoW68NarbmvNGfZ95zrOjgm6cVETLYBA=="],
"@oxlint-tsgolint/linux-x64": ["@oxlint-tsgolint/linux-x64@0.11.1", "", { "os": "linux", "cpu": "x64" }, "sha512-aMaGctlwrJhaIQPOdVJR+AGHZGPm4D1pJ457l0SqZt4dLXAhuUt2ene6cUUGF+864R7bDyFVGZqbZHODYpENyA=="],
"@oxc-transform/binding-linux-x64-gnu": ["@oxc-transform/binding-linux-x64-gnu@0.110.0", "", { "os": "linux", "cpu": "x64" }, "sha512-YQ2joGWCVDZVEU2cD/r/w49hVjDm/Qu1BvC/7zs8LvprzdLS/HyMXGF2oA0puw0b+AqgYaz3bhwKB2xexHyITQ=="],
"@oxlint-tsgolint/win32-arm64": ["@oxlint-tsgolint/win32-arm64@0.11.1", "", { "os": "win32", "cpu": "arm64" }, "sha512-ipOs6kKo8fz5n5LSHvcbyZFmEpEIsh2m7+B03RW3jGjBEPMiXb4PfKNuxnusFYTtJM9WaR3bCVm5UxeJTA8r3w=="],
"@oxc-transform/binding-linux-x64-musl": ["@oxc-transform/binding-linux-x64-musl@0.110.0", "", { "os": "linux", "cpu": "x64" }, "sha512-fkjr5qE632ULmNgvFXWDR/8668WxERz3tU7TQFp6JebPBneColitjSkdx6VKNVXEoMmQnOvBIGeP5tUNT384oA=="],
"@oxlint-tsgolint/win32-x64": ["@oxlint-tsgolint/win32-x64@0.11.1", "", { "os": "win32", "cpu": "x64" }, "sha512-m2apsAXg6qU3ulQG45W/qshyEpOjoL+uaQyXJG5dBoDoa66XPtCaSkBlKltD0EwGu0aoB8lM4I5I3OzQ6raNhw=="],
"@oxc-transform/binding-openharmony-arm64": ["@oxc-transform/binding-openharmony-arm64@0.110.0", "", { "os": "none", "cpu": "arm64" }, "sha512-HWH9Zj+lMrdSTqFRCZsvDWMz7OnMjbdGsm3xURXWfRZpuaz0bVvyuZNDQXc4FyyhRDsemICaJbU1bgeIpUJDGw=="],
"@oxlint/darwin-arm64": ["@oxlint/darwin-arm64@1.39.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-lT3hNhIa02xCujI6YGgjmYGg3Ht/X9ag5ipUVETaMpx5Rd4BbTNWUPif1WN1YZHxt3KLCIqaAe7zVhatv83HOQ=="],
"@oxc-transform/binding-wasm32-wasi": ["@oxc-transform/binding-wasm32-wasi@0.110.0", "", { "dependencies": { "@napi-rs/wasm-runtime": "^1.1.1" }, "cpu": "none" }, "sha512-ejdxHmYfIcHDPhZUe3WklViLt9mDEJE5BzcW7+R1vc5i/5JFA8D0l7NUSsHBJ7FB8Bu9gF+5iMDm6cXGAgaghw=="],
"@oxlint/darwin-x64": ["@oxlint/darwin-x64@1.39.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-UT+rfTWd+Yr7iJeSLd/7nF8X4gTYssKh+n77hxl6Oilp3NnG1CKRHxZDy3o3lIBnwgzJkdyUAiYWO1bTMXQ1lA=="],
"@oxc-transform/binding-win32-arm64-msvc": ["@oxc-transform/binding-win32-arm64-msvc@0.110.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-9VTwpXCZs7xkV+mKhQ62dVk7KLnLXtEUxNS2T4nLz3iMl1IJbA4h5oltK0JoobtiUAnbkV53QmMVGW8+Nh3bDQ=="],
"@oxlint/linux-arm64-gnu": ["@oxlint/linux-arm64-gnu@1.39.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-qocBkvS2V6rH0t9AT3DfQunMnj3xkM7srs5/Ycj2j5ZqMoaWd/FxHNVJDFP++35roKSvsRJoS0mtA8/77jqm6Q=="],
"@oxc-transform/binding-win32-ia32-msvc": ["@oxc-transform/binding-win32-ia32-msvc@0.110.0", "", { "os": "win32", "cpu": "ia32" }, "sha512-5y0fzuNON7/F2hh2P94vANFaRPJ/3DI1hVl5rseCT8VUVqOGIjWaza0YS/D1g6t1WwycW2LWDMi2raOKoWU5GQ=="],
"@oxlint/linux-arm64-musl": ["@oxlint/linux-arm64-musl@1.39.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-arZzAc1PPcz9epvGBBCMHICeyQloKtHX3eoOe62B3Dskn7gf6Q14wnDHr1r9Vp4vtcBATNq6HlKV14smdlC/qA=="],
"@oxc-transform/binding-win32-x64-msvc": ["@oxc-transform/binding-win32-x64-msvc@0.110.0", "", { "os": "win32", "cpu": "x64" }, "sha512-QROrowwlrApI1fEScMknGWKM6GTM/Z2xwMnDqvSaEmzNazBsDUlE08Jasw610hFEsYAVU2K5sp/YaCa9ORdP4A=="],
"@oxlint/linux-x64-gnu": ["@oxlint/linux-x64-gnu@1.39.0", "", { "os": "linux", "cpu": "x64" }, "sha512-ZVt5qsECpuNprdWxAPpDBwoixr1VTcZ4qAEQA2l/wmFyVPDYFD3oBY/SWACNnWBddMrswjTg9O8ALxYWoEpmXw=="],
"@oxlint-tsgolint/darwin-arm64": ["@oxlint-tsgolint/darwin-arm64@0.11.3", "", { "os": "darwin", "cpu": "arm64" }, "sha512-FU4e+w09D+2rkCVdL7I7zMuQOJ2tuapVhBGPGY66VAct2FUwFDVmgU+rNJ2hHIdc9uHg24v+FD8PcfFYpask8Q=="],
"@oxlint/linux-x64-musl": ["@oxlint/linux-x64-musl@1.39.0", "", { "os": "linux", "cpu": "x64" }, "sha512-pB0hlGyKPbxr9NMIV783lD6cWL3MpaqnZRM9MWni4yBdHPTKyFNYdg5hGD0Bwg+UP4S2rOevq/+OO9x9Bi7E6g=="],
"@oxlint-tsgolint/darwin-x64": ["@oxlint-tsgolint/darwin-x64@0.11.3", "", { "os": "darwin", "cpu": "x64" }, "sha512-7sm1d920HfFsC3hIP7SJVm11WhYufA8qnLQQVk7odTpSzVUAT1jtG8LdfFigzgb38zHszQbsqJ7OjAgIW/OgmA=="],
"@oxlint/win32-arm64": ["@oxlint/win32-arm64@1.39.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-Gg2SFaJohI9+tIQVKXlPw3FsPQFi/eCSWiCgwPtPn5uzQxHRTeQEZKuluz1fuzR5U70TXubb2liZi4Dgl8LJQA=="],
"@oxlint-tsgolint/linux-arm64": ["@oxlint-tsgolint/linux-arm64@0.11.3", "", { "os": "linux", "cpu": "arm64" }, "sha512-eoJfdmHcpG9k8fufb8yL3rC3HC6QELoTEfs56lmGaRIHHmd1aj4MWDbGCqdRqPEp7oC5fVvFxi7wDkA1MDf99Q=="],
"@oxlint/win32-x64": ["@oxlint/win32-x64@1.39.0", "", { "os": "win32", "cpu": "x64" }, "sha512-sbi25lfj74hH+6qQtb7s1wEvd1j8OQbTaH8v3xTcDjrwm579Cyh0HBv1YSZ2+gsnVwfVDiCTL1D0JsNqYXszVA=="],
"@oxlint-tsgolint/linux-x64": ["@oxlint-tsgolint/linux-x64@0.11.3", "", { "os": "linux", "cpu": "x64" }, "sha512-t7jGK0vBApuAGvOnCPTxsdX+1e9nMdvqU3zHCJWQ7yUDaJxki0bCy4zbKfUgVo8ePeVRgIKWwqLFBOVTXQ5AMQ=="],
"@oxlint-tsgolint/win32-arm64": ["@oxlint-tsgolint/win32-arm64@0.11.3", "", { "os": "win32", "cpu": "arm64" }, "sha512-6ellG0zcWnj2b6Mr7fl19x+nlFIWGWoKCBlYnqNZ4CaziRYGpYx7PLwHhPJq331w7zzRRSnYqhyTrVluYjZADQ=="],
"@oxlint-tsgolint/win32-x64": ["@oxlint-tsgolint/win32-x64@0.11.3", "", { "os": "win32", "cpu": "x64" }, "sha512-rzvfaRJPK9eRYVWMXCt8JtvOsVFAsqScgsFhnXzsipU6W1Te0g+b4q068o7hZ3NRTjJxNgFJj8ayOkZ6NbX0tA=="],
"@oxlint/darwin-arm64": ["@oxlint/darwin-arm64@1.42.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-ui5CdAcDsXPQwZQEXOOSWsilJWhgj9jqHCvYBm2tDE8zfwZZuF9q58+hGKH1x5y0SV4sRlyobB2Quq6uU6EgeA=="],
"@oxlint/darwin-x64": ["@oxlint/darwin-x64@1.42.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-wo0M/hcpHRv7vFje99zHHqheOhVEwUOKjOgBKyi0M99xcLizv04kcSm1rTd6HSCeZgOtiJYZRVAlKhQOQw2byQ=="],
"@oxlint/linux-arm64-gnu": ["@oxlint/linux-arm64-gnu@1.42.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-j4QzfCM8ks+OyM+KKYWDiBEQsm5RCW50H1Wz16wUyoFsobJ+X5qqcJxq6HvkE07m8euYmZelyB0WqsiDoz1v8g=="],
"@oxlint/linux-arm64-musl": ["@oxlint/linux-arm64-musl@1.42.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-g5b1Uw7zo6yw4Ymzyd1etKzAY7xAaGA3scwB8tAp3QzuY7CYdfTwlhiLKSAKbd7T/JBgxOXAGNcLDorJyVTXcg=="],
"@oxlint/linux-x64-gnu": ["@oxlint/linux-x64-gnu@1.42.0", "", { "os": "linux", "cpu": "x64" }, "sha512-HnD99GD9qAbpV4q9iQil7mXZUJFpoBdDavfcC2CgGLPlawfcV5COzQPNwOgvPVkr7C0cBx6uNCq3S6r9IIiEIg=="],
"@oxlint/linux-x64-musl": ["@oxlint/linux-x64-musl@1.42.0", "", { "os": "linux", "cpu": "x64" }, "sha512-8NTe8A78HHFn+nBi+8qMwIjgv9oIBh+9zqCPNLH56ah4vKOPvbePLI6NIv9qSkmzrBuu8SB+FJ2TH/G05UzbNA=="],
"@oxlint/win32-arm64": ["@oxlint/win32-arm64@1.42.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-lAPS2YAuu+qFqoTNPFcNsxXjwSV0M+dOgAzzVTAN7Yo2ifj+oLOx0GsntWoM78PvQWI7Q827ZxqtU2ImBmDapA=="],
"@oxlint/win32-x64": ["@oxlint/win32-x64@1.42.0", "", { "os": "win32", "cpu": "x64" }, "sha512-3/KmyUOHNriL6rLpaFfm9RJxdhpXY2/Ehx9UuorJr2pUA+lrZL15FAEx/DOszYm5r10hfzj40+efAHcCilNvSQ=="],
"@panva/hkdf": ["@panva/hkdf@1.2.1", "", {}, "sha512-6oclG6Y3PiDFcoyk8srjLfVKyMfVCKJ27JwNPViuXziFpmdz+MZnZN/aKY0JGXgYuO/VghU0jcOAZgWXZ1Dmrw=="],
"@playwright/test": ["@playwright/test@1.57.0", "", { "dependencies": { "playwright": "1.57.0" }, "bin": { "playwright": "cli.js" } }, "sha512-6TyEnHgd6SArQO8UO2OMTxshln3QMWBtPGrOCgs3wVEmQmwyuNtB10IZMfmYDE0riwNR1cu4q+pPcxMVtaG3TA=="],
"@playwright/test": ["@playwright/test@1.58.0", "", { "dependencies": { "playwright": "1.58.0" }, "bin": { "playwright": "cli.js" } }, "sha512-fWza+Lpbj6SkQKCrU6si4iu+fD2dD3gxNHFhUPxsfXBPhnv3rRSQVd0NtBUT9Z/RhF/boCBcuUaMUSTRTopjZg=="],
"@radix-ui/primitive": ["@radix-ui/primitive@1.1.3", "", {}, "sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg=="],
@@ -451,49 +472,55 @@
"@rolldown/pluginutils": ["@rolldown/pluginutils@1.0.0-beta.53", "", {}, "sha512-vENRlFU4YbrwVqNDZ7fLvy+JR1CRkyr01jhSiDpE1u6py3OMzQfztQU2jxykW3ALNxO4kSlqIDeYyD0Y9RcQeQ=="],
"@rollup/rollup-android-arm-eabi": ["@rollup/rollup-android-arm-eabi@4.54.0", "", { "os": "android", "cpu": "arm" }, "sha512-OywsdRHrFvCdvsewAInDKCNyR3laPA2mc9bRYJ6LBp5IyvF3fvXbbNR0bSzHlZVFtn6E0xw2oZlyjg4rKCVcng=="],
"@rollup/rollup-android-arm-eabi": ["@rollup/rollup-android-arm-eabi@4.57.0", "", { "os": "android", "cpu": "arm" }, "sha512-tPgXB6cDTndIe1ah7u6amCI1T0SsnlOuKgg10Xh3uizJk4e5M1JGaUMk7J4ciuAUcFpbOiNhm2XIjP9ON0dUqA=="],
"@rollup/rollup-android-arm64": ["@rollup/rollup-android-arm64@4.54.0", "", { "os": "android", "cpu": "arm64" }, "sha512-Skx39Uv+u7H224Af+bDgNinitlmHyQX1K/atIA32JP3JQw6hVODX5tkbi2zof/E69M1qH2UoN3Xdxgs90mmNYw=="],
"@rollup/rollup-android-arm64": ["@rollup/rollup-android-arm64@4.57.0", "", { "os": "android", "cpu": "arm64" }, "sha512-sa4LyseLLXr1onr97StkU1Nb7fWcg6niokTwEVNOO7awaKaoRObQ54+V/hrF/BP1noMEaaAW6Fg2d/CfLiq3Mg=="],
"@rollup/rollup-darwin-arm64": ["@rollup/rollup-darwin-arm64@4.54.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-k43D4qta/+6Fq+nCDhhv9yP2HdeKeP56QrUUTW7E6PhZP1US6NDqpJj4MY0jBHlJivVJD5P8NxrjuobZBJTCRw=="],
"@rollup/rollup-darwin-arm64": ["@rollup/rollup-darwin-arm64@4.57.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-/NNIj9A7yLjKdmkx5dC2XQ9DmjIECpGpwHoGmA5E1AhU0fuICSqSWScPhN1yLCkEdkCwJIDu2xIeLPs60MNIVg=="],
"@rollup/rollup-darwin-x64": ["@rollup/rollup-darwin-x64@4.54.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-cOo7biqwkpawslEfox5Vs8/qj83M/aZCSSNIWpVzfU2CYHa2G3P1UN5WF01RdTHSgCkri7XOlTdtk17BezlV3A=="],
"@rollup/rollup-darwin-x64": ["@rollup/rollup-darwin-x64@4.57.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-xoh8abqgPrPYPr7pTYipqnUi1V3em56JzE/HgDgitTqZBZ3yKCWI+7KUkceM6tNweyUKYru1UMi7FC060RyKwA=="],
"@rollup/rollup-freebsd-arm64": ["@rollup/rollup-freebsd-arm64@4.54.0", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-miSvuFkmvFbgJ1BevMa4CPCFt5MPGw094knM64W9I0giUIMMmRYcGW/JWZDriaw/k1kOBtsWh1z6nIFV1vPNtA=="],
"@rollup/rollup-freebsd-arm64": ["@rollup/rollup-freebsd-arm64@4.57.0", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-PCkMh7fNahWSbA0OTUQ2OpYHpjZZr0hPr8lId8twD7a7SeWrvT3xJVyza+dQwXSSq4yEQTMoXgNOfMCsn8584g=="],
"@rollup/rollup-freebsd-x64": ["@rollup/rollup-freebsd-x64@4.54.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-KGXIs55+b/ZfZsq9aR026tmr/+7tq6VG6MsnrvF4H8VhwflTIuYh+LFUlIsRdQSgrgmtM3fVATzEAj4hBQlaqQ=="],
"@rollup/rollup-freebsd-x64": ["@rollup/rollup-freebsd-x64@4.57.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-1j3stGx+qbhXql4OCDZhnK7b01s6rBKNybfsX+TNrEe9JNq4DLi1yGiR1xW+nL+FNVvI4D02PUnl6gJ/2y6WJA=="],
"@rollup/rollup-linux-arm-gnueabihf": ["@rollup/rollup-linux-arm-gnueabihf@4.54.0", "", { "os": "linux", "cpu": "arm" }, "sha512-EHMUcDwhtdRGlXZsGSIuXSYwD5kOT9NVnx9sqzYiwAc91wfYOE1g1djOEDseZJKKqtHAHGwnGPQu3kytmfaXLQ=="],
"@rollup/rollup-linux-arm-gnueabihf": ["@rollup/rollup-linux-arm-gnueabihf@4.57.0", "", { "os": "linux", "cpu": "arm" }, "sha512-eyrr5W08Ms9uM0mLcKfM/Uzx7hjhz2bcjv8P2uynfj0yU8GGPdz8iYrBPhiLOZqahoAMB8ZiolRZPbbU2MAi6Q=="],
"@rollup/rollup-linux-arm-musleabihf": ["@rollup/rollup-linux-arm-musleabihf@4.54.0", "", { "os": "linux", "cpu": "arm" }, "sha512-+pBrqEjaakN2ySv5RVrj/qLytYhPKEUwk+e3SFU5jTLHIcAtqh2rLrd/OkbNuHJpsBgxsD8ccJt5ga/SeG0JmA=="],
"@rollup/rollup-linux-arm-musleabihf": ["@rollup/rollup-linux-arm-musleabihf@4.57.0", "", { "os": "linux", "cpu": "arm" }, "sha512-Xds90ITXJCNyX9pDhqf85MKWUI4lqjiPAipJ8OLp8xqI2Ehk+TCVhF9rvOoN8xTbcafow3QOThkNnrM33uCFQA=="],
"@rollup/rollup-linux-arm64-gnu": ["@rollup/rollup-linux-arm64-gnu@4.54.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-NSqc7rE9wuUaRBsBp5ckQ5CVz5aIRKCwsoa6WMF7G01sX3/qHUw/z4pv+D+ahL1EIKy6Enpcnz1RY8pf7bjwng=="],
"@rollup/rollup-linux-arm64-gnu": ["@rollup/rollup-linux-arm64-gnu@4.57.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-Xws2KA4CLvZmXjy46SQaXSejuKPhwVdaNinldoYfqruZBaJHqVo6hnRa8SDo9z7PBW5x84SH64+izmldCgbezw=="],
"@rollup/rollup-linux-arm64-musl": ["@rollup/rollup-linux-arm64-musl@4.54.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-gr5vDbg3Bakga5kbdpqx81m2n9IX8M6gIMlQQIXiLTNeQW6CucvuInJ91EuCJ/JYvc+rcLLsDFcfAD1K7fMofg=="],
"@rollup/rollup-linux-arm64-musl": ["@rollup/rollup-linux-arm64-musl@4.57.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-hrKXKbX5FdaRJj7lTMusmvKbhMJSGWJ+w++4KmjiDhpTgNlhYobMvKfDoIWecy4O60K6yA4SnztGuNTQF+Lplw=="],
"@rollup/rollup-linux-loong64-gnu": ["@rollup/rollup-linux-loong64-gnu@4.54.0", "", { "os": "linux", "cpu": "none" }, "sha512-gsrtB1NA3ZYj2vq0Rzkylo9ylCtW/PhpLEivlgWe0bpgtX5+9j9EZa0wtZiCjgu6zmSeZWyI/e2YRX1URozpIw=="],
"@rollup/rollup-linux-loong64-gnu": ["@rollup/rollup-linux-loong64-gnu@4.57.0", "", { "os": "linux", "cpu": "none" }, "sha512-6A+nccfSDGKsPm00d3xKcrsBcbqzCTAukjwWK6rbuAnB2bHaL3r9720HBVZ/no7+FhZLz/U3GwwZZEh6tOSI8Q=="],
"@rollup/rollup-linux-ppc64-gnu": ["@rollup/rollup-linux-ppc64-gnu@4.54.0", "", { "os": "linux", "cpu": "ppc64" }, "sha512-y3qNOfTBStmFNq+t4s7Tmc9hW2ENtPg8FeUD/VShI7rKxNW7O4fFeaYbMsd3tpFlIg1Q8IapFgy7Q9i2BqeBvA=="],
"@rollup/rollup-linux-loong64-musl": ["@rollup/rollup-linux-loong64-musl@4.57.0", "", { "os": "linux", "cpu": "none" }, "sha512-4P1VyYUe6XAJtQH1Hh99THxr0GKMMwIXsRNOceLrJnaHTDgk1FTcTimDgneRJPvB3LqDQxUmroBclQ1S0cIJwQ=="],
"@rollup/rollup-linux-riscv64-gnu": ["@rollup/rollup-linux-riscv64-gnu@4.54.0", "", { "os": "linux", "cpu": "none" }, "sha512-89sepv7h2lIVPsFma8iwmccN7Yjjtgz0Rj/Ou6fEqg3HDhpCa+Et+YSufy27i6b0Wav69Qv4WBNl3Rs6pwhebQ=="],
"@rollup/rollup-linux-ppc64-gnu": ["@rollup/rollup-linux-ppc64-gnu@4.57.0", "", { "os": "linux", "cpu": "ppc64" }, "sha512-8Vv6pLuIZCMcgXre6c3nOPhE0gjz1+nZP6T+hwWjr7sVH8k0jRkH+XnfjjOTglyMBdSKBPPz54/y1gToSKwrSQ=="],
"@rollup/rollup-linux-riscv64-musl": ["@rollup/rollup-linux-riscv64-musl@4.54.0", "", { "os": "linux", "cpu": "none" }, "sha512-ZcU77ieh0M2Q8Ur7D5X7KvK+UxbXeDHwiOt/CPSBTI1fBmeDMivW0dPkdqkT4rOgDjrDDBUed9x4EgraIKoR2A=="],
"@rollup/rollup-linux-ppc64-musl": ["@rollup/rollup-linux-ppc64-musl@4.57.0", "", { "os": "linux", "cpu": "ppc64" }, "sha512-r1te1M0Sm2TBVD/RxBPC6RZVwNqUTwJTA7w+C/IW5v9Ssu6xmxWEi+iJQlpBhtUiT1raJ5b48pI8tBvEjEFnFA=="],
"@rollup/rollup-linux-s390x-gnu": ["@rollup/rollup-linux-s390x-gnu@4.54.0", "", { "os": "linux", "cpu": "s390x" }, "sha512-2AdWy5RdDF5+4YfG/YesGDDtbyJlC9LHmL6rZw6FurBJ5n4vFGupsOBGfwMRjBYH7qRQowT8D/U4LoSvVwOhSQ=="],
"@rollup/rollup-linux-riscv64-gnu": ["@rollup/rollup-linux-riscv64-gnu@4.57.0", "", { "os": "linux", "cpu": "none" }, "sha512-say0uMU/RaPm3CDQLxUUTF2oNWL8ysvHkAjcCzV2znxBr23kFfaxocS9qJm+NdkRhF8wtdEEAJuYcLPhSPbjuQ=="],
"@rollup/rollup-linux-x64-gnu": ["@rollup/rollup-linux-x64-gnu@4.54.0", "", { "os": "linux", "cpu": "x64" }, "sha512-WGt5J8Ij/rvyqpFexxk3ffKqqbLf9AqrTBbWDk7ApGUzaIs6V+s2s84kAxklFwmMF/vBNGrVdYgbblCOFFezMQ=="],
"@rollup/rollup-linux-riscv64-musl": ["@rollup/rollup-linux-riscv64-musl@4.57.0", "", { "os": "linux", "cpu": "none" }, "sha512-/MU7/HizQGsnBREtRpcSbSV1zfkoxSTR7wLsRmBPQ8FwUj5sykrP1MyJTvsxP5KBq9SyE6kH8UQQQwa0ASeoQQ=="],
"@rollup/rollup-linux-x64-musl": ["@rollup/rollup-linux-x64-musl@4.54.0", "", { "os": "linux", "cpu": "x64" }, "sha512-JzQmb38ATzHjxlPHuTH6tE7ojnMKM2kYNzt44LO/jJi8BpceEC8QuXYA908n8r3CNuG/B3BV8VR3Hi1rYtmPiw=="],
"@rollup/rollup-linux-s390x-gnu": ["@rollup/rollup-linux-s390x-gnu@4.57.0", "", { "os": "linux", "cpu": "s390x" }, "sha512-Q9eh+gUGILIHEaJf66aF6a414jQbDnn29zeu0eX3dHMuysnhTvsUvZTCAyZ6tJhUjnvzBKE4FtuaYxutxRZpOg=="],
"@rollup/rollup-openharmony-arm64": ["@rollup/rollup-openharmony-arm64@4.54.0", "", { "os": "none", "cpu": "arm64" }, "sha512-huT3fd0iC7jigGh7n3q/+lfPcXxBi+om/Rs3yiFxjvSxbSB6aohDFXbWvlspaqjeOh+hx7DDHS+5Es5qRkWkZg=="],
"@rollup/rollup-linux-x64-gnu": ["@rollup/rollup-linux-x64-gnu@4.57.0", "", { "os": "linux", "cpu": "x64" }, "sha512-OR5p5yG5OKSxHReWmwvM0P+VTPMwoBS45PXTMYaskKQqybkS3Kmugq1W+YbNWArF8/s7jQScgzXUhArzEQ7x0A=="],
"@rollup/rollup-win32-arm64-msvc": ["@rollup/rollup-win32-arm64-msvc@4.54.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-c2V0W1bsKIKfbLMBu/WGBz6Yci8nJ/ZJdheE0EwB73N3MvHYKiKGs3mVilX4Gs70eGeDaMqEob25Tw2Gb9Nqyw=="],
"@rollup/rollup-linux-x64-musl": ["@rollup/rollup-linux-x64-musl@4.57.0", "", { "os": "linux", "cpu": "x64" }, "sha512-XeatKzo4lHDsVEbm1XDHZlhYZZSQYym6dg2X/Ko0kSFgio+KXLsxwJQprnR48GvdIKDOpqWqssC3iBCjoMcMpw=="],
"@rollup/rollup-win32-ia32-msvc": ["@rollup/rollup-win32-ia32-msvc@4.54.0", "", { "os": "win32", "cpu": "ia32" }, "sha512-woEHgqQqDCkAzrDhvDipnSirm5vxUXtSKDYTVpZG3nUdW/VVB5VdCYA2iReSj/u3yCZzXID4kuKG7OynPnB3WQ=="],
"@rollup/rollup-openbsd-x64": ["@rollup/rollup-openbsd-x64@4.57.0", "", { "os": "openbsd", "cpu": "x64" }, "sha512-Lu71y78F5qOfYmubYLHPcJm74GZLU6UJ4THkf/a1K7Tz2ycwC2VUbsqbJAXaR6Bx70SRdlVrt2+n5l7F0agTUw=="],
"@rollup/rollup-win32-x64-gnu": ["@rollup/rollup-win32-x64-gnu@4.54.0", "", { "os": "win32", "cpu": "x64" }, "sha512-dzAc53LOuFvHwbCEOS0rPbXp6SIhAf2txMP5p6mGyOXXw5mWY8NGGbPMPrs4P1WItkfApDathBj/NzMLUZ9rtQ=="],
"@rollup/rollup-openharmony-arm64": ["@rollup/rollup-openharmony-arm64@4.57.0", "", { "os": "none", "cpu": "arm64" }, "sha512-v5xwKDWcu7qhAEcsUubiav7r+48Uk/ENWdr82MBZZRIm7zThSxCIVDfb3ZeRRq9yqk+oIzMdDo6fCcA5DHfMyA=="],
"@rollup/rollup-win32-x64-msvc": ["@rollup/rollup-win32-x64-msvc@4.54.0", "", { "os": "win32", "cpu": "x64" }, "sha512-hYT5d3YNdSh3mbCU1gwQyPgQd3T2ne0A3KG8KSBdav5TiBg6eInVmV+TeR5uHufiIgSFg0XsOWGW5/RhNcSvPg=="],
"@rollup/rollup-win32-arm64-msvc": ["@rollup/rollup-win32-arm64-msvc@4.57.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-XnaaaSMGSI6Wk8F4KK3QP7GfuuhjGchElsVerCplUuxRIzdvZ7hRBpLR0omCmw+kI2RFJB80nenhOoGXlJ5TfQ=="],
"@rollup/rollup-win32-ia32-msvc": ["@rollup/rollup-win32-ia32-msvc@4.57.0", "", { "os": "win32", "cpu": "ia32" }, "sha512-3K1lP+3BXY4t4VihLw5MEg6IZD3ojSYzqzBG571W3kNQe4G4CcFpSUQVgurYgib5d+YaCjeFow8QivWp8vuSvA=="],
"@rollup/rollup-win32-x64-gnu": ["@rollup/rollup-win32-x64-gnu@4.57.0", "", { "os": "win32", "cpu": "x64" }, "sha512-MDk610P/vJGc5L5ImE4k5s+GZT3en0KoK1MKPXCRgzmksAMk79j4h3k1IerxTNqwDLxsGxStEZVBqG0gIqZqoA=="],
"@rollup/rollup-win32-x64-msvc": ["@rollup/rollup-win32-x64-msvc@4.57.0", "", { "os": "win32", "cpu": "x64" }, "sha512-Zv7v6q6aV+VslnpwzqKAmrk5JdVkLUzok2208ZXGipjb+msxBr/fJPZyeEXiFgH7k62Ak0SLIfxQRZQvTuf7rQ=="],
"@solid-primitives/event-listener": ["@solid-primitives/event-listener@2.4.3", "", { "dependencies": { "@solid-primitives/utils": "^6.3.2" }, "peerDependencies": { "solid-js": "^1.6.12" } }, "sha512-h4VqkYFv6Gf+L7SQj+Y6puigL/5DIi7x5q07VZET7AWcS+9/G3WfIE9WheniHWJs51OEkRB43w6lDys5YeFceg=="],
@@ -539,7 +566,7 @@
"@tailwindcss/vite": ["@tailwindcss/vite@4.1.18", "", { "dependencies": { "@tailwindcss/node": "4.1.18", "@tailwindcss/oxide": "4.1.18", "tailwindcss": "4.1.18" }, "peerDependencies": { "vite": "^5.2.0 || ^6 || ^7" } }, "sha512-jVA+/UpKL1vRLg6Hkao5jldawNmRo7mQYrZtNHMIVpLfLhDml5nMRUo/8MwoX2vNXvnaXNNMedrMfMugAVX1nA=="],
"@tanstack/devtools": ["@tanstack/devtools@0.10.3", "", { "dependencies": { "@solid-primitives/event-listener": "^2.4.3", "@solid-primitives/keyboard": "^1.3.3", "@solid-primitives/resize-observer": "^2.1.3", "@tanstack/devtools-client": "0.0.5", "@tanstack/devtools-event-bus": "0.4.0", "@tanstack/devtools-ui": "0.4.4", "clsx": "^2.1.1", "goober": "^2.1.16", "solid-js": "^1.9.9" } }, "sha512-M2HnKtaNf3Z8JDTNDq+X7/1gwOqSwTnCyC0GR+TYiRZM9mkY9GpvTqp6p6bx3DT8onu2URJiVxgHD9WK2e3MNQ=="],
"@tanstack/devtools": ["@tanstack/devtools@0.10.4", "", { "dependencies": { "@solid-primitives/event-listener": "^2.4.3", "@solid-primitives/keyboard": "^1.3.3", "@solid-primitives/resize-observer": "^2.1.3", "@tanstack/devtools-client": "0.0.5", "@tanstack/devtools-event-bus": "0.4.0", "@tanstack/devtools-ui": "0.4.4", "clsx": "^2.1.1", "goober": "^2.1.16", "solid-js": "^1.9.9" } }, "sha512-GR/HMWe+eAZgSm/mOeuWMs/cXy3pEcrdMBU+OH0c6Qv1IXYv/xqru4aCSJPe+2/eJXng5ioqCsoVt9MztyU1mg=="],
"@tanstack/devtools-client": ["@tanstack/devtools-client@0.0.5", "", { "dependencies": { "@tanstack/devtools-event-client": "^0.4.0" } }, "sha512-hsNDE3iu4frt9cC2ppn1mNRnLKo2uc1/1hXAyY9z4UYb+o40M2clFAhiFoo4HngjfGJDV3x18KVVIq7W4Un+zA=="],
@@ -551,49 +578,49 @@
"@tanstack/devtools-vite": ["@tanstack/devtools-vite@0.4.1", "", { "dependencies": { "@babel/core": "^7.28.4", "@babel/generator": "^7.28.3", "@babel/parser": "^7.28.4", "@babel/traverse": "^7.28.4", "@babel/types": "^7.28.4", "@tanstack/devtools-client": "0.0.5", "@tanstack/devtools-event-bus": "0.4.0", "chalk": "^5.6.2", "launch-editor": "^2.11.1", "picomatch": "^4.0.3" }, "peerDependencies": { "vite": "^6.0.0 || ^7.0.0" } }, "sha512-PkMOomcWnl/pUkCqIjqL/csjPHtkMVBirDpJVOZR7XJZDxo5CuD7B+3KsujFCF4Dsn6QYlae97gCZvxi/CB76Q=="],
"@tanstack/history": ["@tanstack/history@1.151.1", "", {}, "sha512-Z/eymNBuUGHYIea7nNX3xR5feqx418ChlwWOKklVpCVzEQ5Q3kNTUw+WK4HYUKxF+1uXFN01Dbuhhl7SmW1LJA=="],
"@tanstack/history": ["@tanstack/history@1.154.14", "", {}, "sha512-xyIfof8eHBuub1CkBnbKNKQXeRZC4dClhmzePHVOEel4G7lk/dW+TQ16da7CFdeNLv6u6Owf5VoBQxoo6DFTSA=="],
"@tanstack/react-devtools": ["@tanstack/react-devtools@0.9.2", "", { "dependencies": { "@tanstack/devtools": "0.10.3" }, "peerDependencies": { "@types/react": ">=16.8", "@types/react-dom": ">=16.8", "react": ">=16.8", "react-dom": ">=16.8" } }, "sha512-JNXvBO3jgq16GzTVm7p65n5zHNfMhnqF6Bm7CawjoqZrjEakxbM6Yvy63aKSIpbrdf+Wun2Xn8P0qD+vp56e1g=="],
"@tanstack/react-devtools": ["@tanstack/react-devtools@0.9.3", "", { "dependencies": { "@tanstack/devtools": "0.10.4" }, "peerDependencies": { "@types/react": ">=16.8", "@types/react-dom": ">=16.8", "react": ">=16.8", "react-dom": ">=16.8" } }, "sha512-SJTYWXWZkbWznwUwZ11awinPGB5StVIVyJXT0BFM1zUgjuajRwT8xRHl1oXVzVqqjJP5kfj89jkbFrcQPpq7Ng=="],
"@tanstack/react-router": ["@tanstack/react-router@1.151.6", "", { "dependencies": { "@tanstack/history": "1.151.1", "@tanstack/react-store": "^0.8.0", "@tanstack/router-core": "1.151.6", "isbot": "^5.1.22", "tiny-invariant": "^1.3.3", "tiny-warning": "^1.0.3" }, "peerDependencies": { "react": ">=18.0.0 || >=19.0.0", "react-dom": ">=18.0.0 || >=19.0.0" } }, "sha512-KDbz7kacZCOoDrUwYljz4I/qjqVGq+bgUhpi/CWubi7by0GZ3JEECwFl/+k+4V6ATinJDjTNmCGwFcdwqjQDtA=="],
"@tanstack/react-router": ["@tanstack/react-router@1.157.16", "", { "dependencies": { "@tanstack/history": "1.154.14", "@tanstack/react-store": "^0.8.0", "@tanstack/router-core": "1.157.16", "isbot": "^5.1.22", "tiny-invariant": "^1.3.3", "tiny-warning": "^1.0.3" }, "peerDependencies": { "react": ">=18.0.0 || >=19.0.0", "react-dom": ">=18.0.0 || >=19.0.0" } }, "sha512-xwFQa7S7dhBhm3aJYwU79cITEYgAKSrcL6wokaROIvl2JyIeazn8jueWqUPJzFjv+QF6Q8euKRlKUEyb5q2ymg=="],
"@tanstack/react-router-devtools": ["@tanstack/react-router-devtools@1.151.6", "", { "dependencies": { "@tanstack/router-devtools-core": "1.151.6" }, "peerDependencies": { "@tanstack/react-router": "^1.151.6", "@tanstack/router-core": "^1.151.6", "react": ">=18.0.0 || >=19.0.0", "react-dom": ">=18.0.0 || >=19.0.0" }, "optionalPeers": ["@tanstack/router-core"] }, "sha512-mRRFzIAIOAWYcZrEr0FYy/1FmM51iWwUdK0J3nWuXjAIeEb7uizS0HkeNbzX5yxfGZgkplk23eCXIUmJcDuVRQ=="],
"@tanstack/react-router-devtools": ["@tanstack/react-router-devtools@1.157.16", "", { "dependencies": { "@tanstack/router-devtools-core": "1.157.16" }, "peerDependencies": { "@tanstack/react-router": "^1.157.16", "@tanstack/router-core": "^1.157.16", "react": ">=18.0.0 || >=19.0.0", "react-dom": ">=18.0.0 || >=19.0.0" }, "optionalPeers": ["@tanstack/router-core"] }, "sha512-g6ekyzumfLBX6T5e+Vu2r37Z2CFJKrWRFqIy3vZ6A3x7OcuPV8uXNjyrLSiT/IsGTiF8YzwI4nWJa4fyd7NlCw=="],
"@tanstack/react-start": ["@tanstack/react-start@1.152.0", "", { "dependencies": { "@tanstack/react-router": "1.151.6", "@tanstack/react-start-client": "1.152.0", "@tanstack/react-start-server": "1.152.0", "@tanstack/router-utils": "^1.143.11", "@tanstack/start-client-core": "1.152.0", "@tanstack/start-plugin-core": "1.152.0", "@tanstack/start-server-core": "1.152.0", "pathe": "^2.0.3" }, "peerDependencies": { "react": ">=18.0.0 || >=19.0.0", "react-dom": ">=18.0.0 || >=19.0.0", "vite": ">=7.0.0" } }, "sha512-btRNNIJGnXVEmD9yuiyNRvMITX5aocVJVdv/LQHxca4EcxntPEn1+HboPXFr6SDl9UNekH/6NZqv3LPz9tDm7A=="],
"@tanstack/react-start": ["@tanstack/react-start@1.157.16", "", { "dependencies": { "@tanstack/react-router": "1.157.16", "@tanstack/react-start-client": "1.157.16", "@tanstack/react-start-server": "1.157.16", "@tanstack/router-utils": "^1.154.7", "@tanstack/start-client-core": "1.157.16", "@tanstack/start-plugin-core": "1.157.16", "@tanstack/start-server-core": "1.157.16", "pathe": "^2.0.3" }, "peerDependencies": { "react": ">=18.0.0 || >=19.0.0", "react-dom": ">=18.0.0 || >=19.0.0", "vite": ">=7.0.0" } }, "sha512-FO6UYjsZyNaC0ickSSvClqfVZemp9/HWnbRJQU2dOKYQsI+wnznhLp9IkgG90iFBLcuMAWhcNHMiIuz603GJBg=="],
"@tanstack/react-start-client": ["@tanstack/react-start-client@1.152.0", "", { "dependencies": { "@tanstack/react-router": "1.151.6", "@tanstack/router-core": "1.151.6", "@tanstack/start-client-core": "1.152.0", "tiny-invariant": "^1.3.3", "tiny-warning": "^1.0.3" }, "peerDependencies": { "react": ">=18.0.0 || >=19.0.0", "react-dom": ">=18.0.0 || >=19.0.0" } }, "sha512-YI2VVdCLk86QP5Q0oMXZWdk551haIisuF5AIr+S9ZAF415s4AgDpKRlXX251aqiHXYvv4rFnV1c9o7w02031Cw=="],
"@tanstack/react-start-client": ["@tanstack/react-start-client@1.157.16", "", { "dependencies": { "@tanstack/react-router": "1.157.16", "@tanstack/router-core": "1.157.16", "@tanstack/start-client-core": "1.157.16", "tiny-invariant": "^1.3.3", "tiny-warning": "^1.0.3" }, "peerDependencies": { "react": ">=18.0.0 || >=19.0.0", "react-dom": ">=18.0.0 || >=19.0.0" } }, "sha512-r3XTxYPJXZ/szhbloxqT6CQtsoEjw8DjbnZh/3ZsQv2PLKTOl925cy7YVdQc2cWZyXtn5e19Ig78R+8tsoTpig=="],
"@tanstack/react-start-server": ["@tanstack/react-start-server@1.152.0", "", { "dependencies": { "@tanstack/history": "1.151.1", "@tanstack/react-router": "1.151.6", "@tanstack/router-core": "1.151.6", "@tanstack/start-client-core": "1.152.0", "@tanstack/start-server-core": "1.152.0" }, "peerDependencies": { "react": ">=18.0.0 || >=19.0.0", "react-dom": ">=18.0.0 || >=19.0.0" } }, "sha512-oz3J3Ipj04IUAfVSE1DD41x8+7DDWHZez+fCqLnk8sw63ct013CeKwIvW9v1n0OtU6axekuVHHYBOsF5wO5/lg=="],
"@tanstack/react-start-server": ["@tanstack/react-start-server@1.157.16", "", { "dependencies": { "@tanstack/history": "1.154.14", "@tanstack/react-router": "1.157.16", "@tanstack/router-core": "1.157.16", "@tanstack/start-client-core": "1.157.16", "@tanstack/start-server-core": "1.157.16" }, "peerDependencies": { "react": ">=18.0.0 || >=19.0.0", "react-dom": ">=18.0.0 || >=19.0.0" } }, "sha512-1YkBss4SUQ+HqVC1yGN/j7VNwjvdHHd3K58fASe0bz+uf7GrkGJlRXPkMJdxJkkmefYHQfyBL+q7o723N4CMYA=="],
"@tanstack/react-store": ["@tanstack/react-store@0.8.0", "", { "dependencies": { "@tanstack/store": "0.8.0", "use-sync-external-store": "^1.6.0" }, "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-1vG9beLIuB7q69skxK9r5xiLN3ztzIPfSQSs0GfeqWGO2tGIyInZx0x1COhpx97RKaONSoAb8C3dxacWksm1ow=="],
"@tanstack/router-core": ["@tanstack/router-core@1.151.6", "", { "dependencies": { "@tanstack/history": "1.151.1", "@tanstack/store": "^0.8.0", "cookie-es": "^2.0.0", "seroval": "^1.4.1", "seroval-plugins": "^1.4.0", "tiny-invariant": "^1.3.3", "tiny-warning": "^1.0.3" } }, "sha512-eyqWx6vhKffkINWLujDF2sxAG9GE/XUdi3HrlD94ddJO9MBi/90a1HJaTYFSV8LmngjcRv8A3tt7OvFdv/UqhA=="],
"@tanstack/router-core": ["@tanstack/router-core@1.157.16", "", { "dependencies": { "@tanstack/history": "1.154.14", "@tanstack/store": "^0.8.0", "cookie-es": "^2.0.0", "seroval": "^1.4.2", "seroval-plugins": "^1.4.2", "tiny-invariant": "^1.3.3", "tiny-warning": "^1.0.3" } }, "sha512-eJuVgM7KZYTTr4uPorbUzUflmljMVcaX2g6VvhITLnHmg9SBx9RAgtQ1HmT+72mzyIbRSlQ1q0fY/m+of/fosA=="],
"@tanstack/router-devtools-core": ["@tanstack/router-devtools-core@1.151.6", "", { "dependencies": { "clsx": "^2.1.1", "goober": "^2.1.16", "tiny-invariant": "^1.3.3" }, "peerDependencies": { "@tanstack/router-core": "^1.151.6", "csstype": "^3.0.10" }, "optionalPeers": ["csstype"] }, "sha512-OHGGvEtnANEbEwjYCChbvCyCLk/3Cqh9G5bhM5DVqrZ+b9wfeu46IdEsbSi1JfuK2sCHNMS5MrJaE2HZPsFx6Q=="],
"@tanstack/router-devtools-core": ["@tanstack/router-devtools-core@1.157.16", "", { "dependencies": { "clsx": "^2.1.1", "goober": "^2.1.16", "tiny-invariant": "^1.3.3" }, "peerDependencies": { "@tanstack/router-core": "^1.157.16", "csstype": "^3.0.10" }, "optionalPeers": ["csstype"] }, "sha512-XBJTs/kMZYK6J2zhbGucHNuypwDB1t2vi8K5To+V6dUnLGBEyfQTf01fegiF4rpL1yXgomdGnP6aTiOFgldbVg=="],
"@tanstack/router-generator": ["@tanstack/router-generator@1.151.6", "", { "dependencies": { "@tanstack/router-core": "1.151.6", "@tanstack/router-utils": "1.143.11", "@tanstack/virtual-file-routes": "1.145.4", "prettier": "^3.5.0", "recast": "^0.23.11", "source-map": "^0.7.4", "tsx": "^4.19.2", "zod": "^3.24.2" } }, "sha512-IS4tkrkLIwI2EViGlUXCVgnKJ4EhWMM6w75XoJqd0X4t6K0/OiHkr3AQ0f2qZXbNciqLGxS88GLe5UiSAOS5Vw=="],
"@tanstack/router-generator": ["@tanstack/router-generator@1.157.16", "", { "dependencies": { "@tanstack/router-core": "1.157.16", "@tanstack/router-utils": "1.154.7", "@tanstack/virtual-file-routes": "1.154.7", "prettier": "^3.5.0", "recast": "^0.23.11", "source-map": "^0.7.4", "tsx": "^4.19.2", "zod": "^3.24.2" } }, "sha512-Ae2M00VTFjjED7glSCi/mMLENRzhEym6NgjoOx7UVNbCC/rLU/5ASDe5VIlDa8QLEqP5Pj088Gi51gjmRuICvQ=="],
"@tanstack/router-plugin": ["@tanstack/router-plugin@1.151.6", "", { "dependencies": { "@babel/core": "^7.28.5", "@babel/plugin-syntax-jsx": "^7.27.1", "@babel/plugin-syntax-typescript": "^7.27.1", "@babel/template": "^7.27.2", "@babel/traverse": "^7.28.5", "@babel/types": "^7.28.5", "@tanstack/router-core": "1.151.6", "@tanstack/router-generator": "1.151.6", "@tanstack/router-utils": "1.143.11", "@tanstack/virtual-file-routes": "1.145.4", "babel-dead-code-elimination": "^1.0.11", "chokidar": "^3.6.0", "unplugin": "^2.1.2", "zod": "^3.24.2" }, "peerDependencies": { "@rsbuild/core": ">=1.0.2", "@tanstack/react-router": "^1.151.6", "vite": ">=5.0.0 || >=6.0.0 || >=7.0.0", "vite-plugin-solid": "^2.11.10", "webpack": ">=5.92.0" }, "optionalPeers": ["@rsbuild/core", "@tanstack/react-router", "vite", "vite-plugin-solid", "webpack"] }, "sha512-Kz9wmAgcylung1KoXvEEVTW91PNh4U65MgVwSmz5fYQP7UqNHPvHqBFWKEu17a45SfZ4LufsNW3LTFT35tWGXg=="],
"@tanstack/router-plugin": ["@tanstack/router-plugin@1.157.16", "", { "dependencies": { "@babel/core": "^7.28.5", "@babel/plugin-syntax-jsx": "^7.27.1", "@babel/plugin-syntax-typescript": "^7.27.1", "@babel/template": "^7.27.2", "@babel/traverse": "^7.28.5", "@babel/types": "^7.28.5", "@tanstack/router-core": "1.157.16", "@tanstack/router-generator": "1.157.16", "@tanstack/router-utils": "1.154.7", "@tanstack/virtual-file-routes": "1.154.7", "babel-dead-code-elimination": "^1.0.11", "chokidar": "^3.6.0", "unplugin": "^2.1.2", "zod": "^3.24.2" }, "peerDependencies": { "@rsbuild/core": ">=1.0.2", "@tanstack/react-router": "^1.157.16", "vite": ">=5.0.0 || >=6.0.0 || >=7.0.0", "vite-plugin-solid": "^2.11.10", "webpack": ">=5.92.0" }, "optionalPeers": ["@rsbuild/core", "@tanstack/react-router", "vite", "vite-plugin-solid", "webpack"] }, "sha512-YQg7L06xyCJAYyrEJNZGAnDL8oChILU+G/eSDIwEfcWn5iLk+47x1Gcdxr82++47PWmOPhzuTo8edDQXWs7kAA=="],
"@tanstack/router-utils": ["@tanstack/router-utils@1.143.11", "", { "dependencies": { "@babel/core": "^7.28.5", "@babel/generator": "^7.28.5", "@babel/parser": "^7.28.5", "ansis": "^4.1.0", "diff": "^8.0.2", "pathe": "^2.0.3", "tinyglobby": "^0.2.15" } }, "sha512-N24G4LpfyK8dOlnP8BvNdkuxg1xQljkyl6PcrdiPSA301pOjatRT1y8wuCCJZKVVD8gkd0MpCZ0VEjRMGILOtA=="],
"@tanstack/router-utils": ["@tanstack/router-utils@1.154.7", "", { "dependencies": { "@babel/core": "^7.28.5", "@babel/generator": "^7.28.5", "@babel/parser": "^7.28.5", "ansis": "^4.1.0", "diff": "^8.0.2", "pathe": "^2.0.3", "tinyglobby": "^0.2.15" } }, "sha512-61bGx32tMKuEpVRseu2sh1KQe8CfB7793Mch/kyQt0EP3tD7X0sXmimCl3truRiDGUtI0CaSoQV1NPjAII1RBA=="],
"@tanstack/start-client-core": ["@tanstack/start-client-core@1.152.0", "", { "dependencies": { "@tanstack/router-core": "1.151.6", "@tanstack/start-fn-stubs": "1.151.3", "@tanstack/start-storage-context": "1.151.6", "seroval": "^1.4.1", "tiny-invariant": "^1.3.3", "tiny-warning": "^1.0.3" } }, "sha512-G88urpJImiGZttawtciSj46Ko57TXO2pd11Zef6Yw1VLD6fJs+RF0q9N0P98SGs9Jm0oUjLusi3Ti550fkQ2qw=="],
"@tanstack/start-client-core": ["@tanstack/start-client-core@1.157.16", "", { "dependencies": { "@tanstack/router-core": "1.157.16", "@tanstack/start-fn-stubs": "1.154.7", "@tanstack/start-storage-context": "1.157.16", "seroval": "^1.4.2", "tiny-invariant": "^1.3.3", "tiny-warning": "^1.0.3" } }, "sha512-O+7H133MWQTkOxmXJNhrLXiOhDcBlxvpEcCd/N25Ga6eyZ7/P5vvFzNkSSxeQNkZV+RiPWnA5B75gT+U+buz3w=="],
"@tanstack/start-fn-stubs": ["@tanstack/start-fn-stubs@1.151.3", "", {}, "sha512-/zWBnfsOwact936Bn0CxigudU1QRZdiNTsK7ME/LMXXA66XsDxkryX5+5FeGwU5ETNPfLAx6pRUet1mtUKnLCg=="],
"@tanstack/start-fn-stubs": ["@tanstack/start-fn-stubs@1.154.7", "", {}, "sha512-D69B78L6pcFN5X5PHaydv7CScQcKLzJeEYqs7jpuyyqGQHSUIZUjS955j+Sir8cHhuDIovCe2LmsYHeZfWf3dQ=="],
"@tanstack/start-plugin-core": ["@tanstack/start-plugin-core@1.152.0", "", { "dependencies": { "@babel/code-frame": "7.27.1", "@babel/core": "^7.28.5", "@babel/types": "^7.28.5", "@rolldown/pluginutils": "1.0.0-beta.40", "@tanstack/router-core": "1.151.6", "@tanstack/router-generator": "1.151.6", "@tanstack/router-plugin": "1.151.6", "@tanstack/router-utils": "1.143.11", "@tanstack/start-client-core": "1.152.0", "@tanstack/start-server-core": "1.152.0", "babel-dead-code-elimination": "^1.0.11", "cheerio": "^1.0.0", "exsolve": "^1.0.7", "pathe": "^2.0.3", "srvx": "^0.10.0", "tinyglobby": "^0.2.15", "ufo": "^1.5.4", "vitefu": "^1.1.1", "xmlbuilder2": "^4.0.3", "zod": "^3.24.2" }, "peerDependencies": { "vite": ">=7.0.0" } }, "sha512-XT+ECwpmi6cQj6gb9QHo1XOOw+7zGXOvwnrijg3HSzNKFDlawHycgOotnViTOjtVjhHLpW1/yGyivWX5OC8wTw=="],
"@tanstack/start-plugin-core": ["@tanstack/start-plugin-core@1.157.16", "", { "dependencies": { "@babel/code-frame": "7.27.1", "@babel/core": "^7.28.5", "@babel/types": "^7.28.5", "@rolldown/pluginutils": "1.0.0-beta.40", "@tanstack/router-core": "1.157.16", "@tanstack/router-generator": "1.157.16", "@tanstack/router-plugin": "1.157.16", "@tanstack/router-utils": "1.154.7", "@tanstack/start-client-core": "1.157.16", "@tanstack/start-server-core": "1.157.16", "babel-dead-code-elimination": "^1.0.11", "cheerio": "^1.0.0", "exsolve": "^1.0.7", "pathe": "^2.0.3", "srvx": "^0.10.1", "tinyglobby": "^0.2.15", "ufo": "^1.5.4", "vitefu": "^1.1.1", "xmlbuilder2": "^4.0.3", "zod": "^3.24.2" }, "peerDependencies": { "vite": ">=7.0.0" } }, "sha512-VmRXuvP5flryUAHeBM4Xb06n544qLtyA2cwmlQLRTUYtQiQEAdd9CvCGy8CPAly3f7eeXKqC7aX0v3MwWkLR8w=="],
"@tanstack/start-server-core": ["@tanstack/start-server-core@1.152.0", "", { "dependencies": { "@tanstack/history": "1.151.1", "@tanstack/router-core": "1.151.6", "@tanstack/start-client-core": "1.152.0", "@tanstack/start-storage-context": "1.151.6", "h3-v2": "npm:h3@2.0.1-rc.7", "seroval": "^1.4.1", "tiny-invariant": "^1.3.3" } }, "sha512-bMmc4tIhR3FClb1iWLw0zuhvY71b9k2iz8Jw0tSK/KKi++gl1bGyJjuPtx8kDbx5Ix1SoXp4QNdXuo7dv5INfQ=="],
"@tanstack/start-server-core": ["@tanstack/start-server-core@1.157.16", "", { "dependencies": { "@tanstack/history": "1.154.14", "@tanstack/router-core": "1.157.16", "@tanstack/start-client-core": "1.157.16", "@tanstack/start-storage-context": "1.157.16", "h3-v2": "npm:h3@2.0.1-rc.11", "seroval": "^1.4.2", "tiny-invariant": "^1.3.3" } }, "sha512-PEltFleYfiqz6+KcmzNXxc1lXgT7VDNKP6G6i1TirdHBDbRJ9CIY+ASLPlhrRwqwA2PL9PpFjXZl8u5bH/+Q9A=="],
"@tanstack/start-storage-context": ["@tanstack/start-storage-context@1.151.6", "", { "dependencies": { "@tanstack/router-core": "1.151.6" } }, "sha512-MvTcT40qnqatIpKjWSfMRxFzTkprGBxhX2c+em58iZLEsGksitMUWbprknD6AIUqjHty8V3LuhULks/o6tSugQ=="],
"@tanstack/start-storage-context": ["@tanstack/start-storage-context@1.157.16", "", { "dependencies": { "@tanstack/router-core": "1.157.16" } }, "sha512-56izE0oihAw2YRwYUEds2H+uO5dyT2CahXCgWX62+l+FHou09M9mSep68n1lBKPdphC2ZU3cPV7wnvgeraJWHg=="],
"@tanstack/store": ["@tanstack/store@0.8.0", "", {}, "sha512-Om+BO0YfMZe//X2z0uLF2j+75nQga6TpTJgLJQBiq85aOyZNIhkCgleNcud2KQg4k4v9Y9l+Uhru3qWMPGTOzQ=="],
"@tanstack/virtual-file-routes": ["@tanstack/virtual-file-routes@1.145.4", "", {}, "sha512-CI75JrfqSluhdGwLssgVeQBaCphgfkMQpi8MCY3UJX1hoGzXa8kHYJcUuIFMOLs1q7zqHy++EVVtMK03osR5wQ=="],
"@tanstack/virtual-file-routes": ["@tanstack/virtual-file-routes@1.154.7", "", {}, "sha512-cHHDnewHozgjpI+MIVp9tcib6lYEQK5MyUr0ChHpHFGBl8Xei55rohFK0I0ve/GKoHeioaK42Smd8OixPp6CTg=="],
"@testing-library/dom": ["@testing-library/dom@10.4.1", "", { "dependencies": { "@babel/code-frame": "^7.10.4", "@babel/runtime": "^7.12.5", "@types/aria-query": "^5.0.1", "aria-query": "5.3.0", "dom-accessibility-api": "^0.5.9", "lz-string": "^1.5.0", "picocolors": "1.1.1", "pretty-format": "^27.0.2" } }, "sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg=="],
"@testing-library/react": ["@testing-library/react@16.3.1", "", { "dependencies": { "@babel/runtime": "^7.12.5" }, "peerDependencies": { "@testing-library/dom": "^10.0.0", "@types/react": "^18.0.0 || ^19.0.0", "@types/react-dom": "^18.0.0 || ^19.0.0", "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-gr4KtAWqIOQoucWYD/f6ki+j5chXfcPc74Col/6poTyqTmn7zRmodWahWRCp8tYd+GMqBonw6hstNzqjbs6gjw=="],
"@testing-library/react": ["@testing-library/react@16.3.2", "", { "dependencies": { "@babel/runtime": "^7.12.5" }, "peerDependencies": { "@testing-library/dom": "^10.0.0", "@types/react": "^18.0.0 || ^19.0.0", "@types/react-dom": "^18.0.0 || ^19.0.0", "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-XU5/SytQM+ykqMnAnvB2umaJNIOsLF3PVv//1Ew4CTcpz0/BRyy/af40qqrt7SjKpDdT1saBMc42CUok5gaw+g=="],
"@tybys/wasm-util": ["@tybys/wasm-util@0.10.1", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg=="],
@@ -623,9 +650,9 @@
"@types/ms": ["@types/ms@2.1.0", "", {}, "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA=="],
"@types/node": ["@types/node@25.0.9", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-/rpCXHlCWeqClNBwUhDcusJxXYDjZTyE8v5oTO7WbL8eij2nKhUeU89/6xgjU7N4/Vh3He0BtyhJdQbDyhiXAw=="],
"@types/node": ["@types/node@25.1.0", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-t7frlewr6+cbx+9Ohpl0NOTKXZNV9xHRmNOvql47BFJKcEG1CxtxlPEEe+gR9uhVWM4DwhnvTF110mIL4yP9RA=="],
"@types/react": ["@types/react@19.2.8", "", { "dependencies": { "csstype": "^3.2.2" } }, "sha512-3MbSL37jEchWZz2p2mjntRZtPt837ij10ApxKfgmXCTuHWagYg7iA5bqPw6C8BMPfwidlvfPI/fxOc42HLhcyg=="],
"@types/react": ["@types/react@19.2.10", "", { "dependencies": { "csstype": "^3.2.2" } }, "sha512-WPigyYuGhgZ/cTPRXB2EwUw+XvsRA3GqHlsP4qteqrnnjDrApbS7MxcGr/hke5iUoeB7E/gQtrs9I37zAJ0Vjw=="],
"@types/react-dom": ["@types/react-dom@19.2.3", "", { "peerDependencies": { "@types/react": "^19.2.0" } }, "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ=="],
@@ -641,21 +668,21 @@
"@vitejs/plugin-react": ["@vitejs/plugin-react@5.1.2", "", { "dependencies": { "@babel/core": "^7.28.5", "@babel/plugin-transform-react-jsx-self": "^7.27.1", "@babel/plugin-transform-react-jsx-source": "^7.27.1", "@rolldown/pluginutils": "1.0.0-beta.53", "@types/babel__core": "^7.20.5", "react-refresh": "^0.18.0" }, "peerDependencies": { "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" } }, "sha512-EcA07pHJouywpzsoTUqNh5NwGayl2PPVEJKUSinGGSxFGYn+shYbqMGBg6FXDqgXum9Ou/ecb+411ssw8HImJQ=="],
"@vitest/coverage-v8": ["@vitest/coverage-v8@4.0.17", "", { "dependencies": { "@bcoe/v8-coverage": "^1.0.2", "@vitest/utils": "4.0.17", "ast-v8-to-istanbul": "^0.3.10", "istanbul-lib-coverage": "^3.2.2", "istanbul-lib-report": "^3.0.1", "istanbul-reports": "^3.2.0", "magicast": "^0.5.1", "obug": "^2.1.1", "std-env": "^3.10.0", "tinyrainbow": "^3.0.3" }, "peerDependencies": { "@vitest/browser": "4.0.17", "vitest": "4.0.17" }, "optionalPeers": ["@vitest/browser"] }, "sha512-/6zU2FLGg0jsd+ePZcwHRy3+WpNTBBhDY56P4JTRqUN/Dp6CvOEa9HrikcQ4KfV2b2kAHUFB4dl1SuocWXSFEw=="],
"@vitest/coverage-v8": ["@vitest/coverage-v8@4.0.18", "", { "dependencies": { "@bcoe/v8-coverage": "^1.0.2", "@vitest/utils": "4.0.18", "ast-v8-to-istanbul": "^0.3.10", "istanbul-lib-coverage": "^3.2.2", "istanbul-lib-report": "^3.0.1", "istanbul-reports": "^3.2.0", "magicast": "^0.5.1", "obug": "^2.1.1", "std-env": "^3.10.0", "tinyrainbow": "^3.0.3" }, "peerDependencies": { "@vitest/browser": "4.0.18", "vitest": "4.0.18" }, "optionalPeers": ["@vitest/browser"] }, "sha512-7i+N2i0+ME+2JFZhfuz7Tg/FqKtilHjGyGvoHYQ6iLV0zahbsJ9sljC9OcFcPDbhYKCet+sG8SsVqlyGvPflZg=="],
"@vitest/expect": ["@vitest/expect@4.0.17", "", { "dependencies": { "@standard-schema/spec": "^1.0.0", "@types/chai": "^5.2.2", "@vitest/spy": "4.0.17", "@vitest/utils": "4.0.17", "chai": "^6.2.1", "tinyrainbow": "^3.0.3" } }, "sha512-mEoqP3RqhKlbmUmntNDDCJeTDavDR+fVYkSOw8qRwJFaW/0/5zA9zFeTrHqNtcmwh6j26yMmwx2PqUDPzt5ZAQ=="],
"@vitest/expect": ["@vitest/expect@4.0.18", "", { "dependencies": { "@standard-schema/spec": "^1.0.0", "@types/chai": "^5.2.2", "@vitest/spy": "4.0.18", "@vitest/utils": "4.0.18", "chai": "^6.2.1", "tinyrainbow": "^3.0.3" } }, "sha512-8sCWUyckXXYvx4opfzVY03EOiYVxyNrHS5QxX3DAIi5dpJAAkyJezHCP77VMX4HKA2LDT/Jpfo8i2r5BE3GnQQ=="],
"@vitest/mocker": ["@vitest/mocker@4.0.17", "", { "dependencies": { "@vitest/spy": "4.0.17", "estree-walker": "^3.0.3", "magic-string": "^0.30.21" }, "peerDependencies": { "msw": "^2.4.9", "vite": "^6.0.0 || ^7.0.0-0" }, "optionalPeers": ["msw", "vite"] }, "sha512-+ZtQhLA3lDh1tI2wxe3yMsGzbp7uuJSWBM1iTIKCbppWTSBN09PUC+L+fyNlQApQoR+Ps8twt2pbSSXg2fQVEQ=="],
"@vitest/mocker": ["@vitest/mocker@4.0.18", "", { "dependencies": { "@vitest/spy": "4.0.18", "estree-walker": "^3.0.3", "magic-string": "^0.30.21" }, "peerDependencies": { "msw": "^2.4.9", "vite": "^6.0.0 || ^7.0.0-0" }, "optionalPeers": ["msw", "vite"] }, "sha512-HhVd0MDnzzsgevnOWCBj5Otnzobjy5wLBe4EdeeFGv8luMsGcYqDuFRMcttKWZA5vVO8RFjexVovXvAM4JoJDQ=="],
"@vitest/pretty-format": ["@vitest/pretty-format@4.0.17", "", { "dependencies": { "tinyrainbow": "^3.0.3" } }, "sha512-Ah3VAYmjcEdHg6+MwFE17qyLqBHZ+ni2ScKCiW2XrlSBV4H3Z7vYfPfz7CWQ33gyu76oc0Ai36+kgLU3rfF4nw=="],
"@vitest/pretty-format": ["@vitest/pretty-format@4.0.18", "", { "dependencies": { "tinyrainbow": "^3.0.3" } }, "sha512-P24GK3GulZWC5tz87ux0m8OADrQIUVDPIjjj65vBXYG17ZeU3qD7r+MNZ1RNv4l8CGU2vtTRqixrOi9fYk/yKw=="],
"@vitest/runner": ["@vitest/runner@4.0.17", "", { "dependencies": { "@vitest/utils": "4.0.17", "pathe": "^2.0.3" } }, "sha512-JmuQyf8aMWoo/LmNFppdpkfRVHJcsgzkbCA+/Bk7VfNH7RE6Ut2qxegeyx2j3ojtJtKIbIGy3h+KxGfYfk28YQ=="],
"@vitest/runner": ["@vitest/runner@4.0.18", "", { "dependencies": { "@vitest/utils": "4.0.18", "pathe": "^2.0.3" } }, "sha512-rpk9y12PGa22Jg6g5M3UVVnTS7+zycIGk9ZNGN+m6tZHKQb7jrP7/77WfZy13Y/EUDd52NDsLRQhYKtv7XfPQw=="],
"@vitest/snapshot": ["@vitest/snapshot@4.0.17", "", { "dependencies": { "@vitest/pretty-format": "4.0.17", "magic-string": "^0.30.21", "pathe": "^2.0.3" } }, "sha512-npPelD7oyL+YQM2gbIYvlavlMVWUfNNGZPcu0aEUQXt7FXTuqhmgiYupPnAanhKvyP6Srs2pIbWo30K0RbDtRQ=="],
"@vitest/snapshot": ["@vitest/snapshot@4.0.18", "", { "dependencies": { "@vitest/pretty-format": "4.0.18", "magic-string": "^0.30.21", "pathe": "^2.0.3" } }, "sha512-PCiV0rcl7jKQjbgYqjtakly6T1uwv/5BQ9SwBLekVg/EaYeQFPiXcgrC2Y7vDMA8dM1SUEAEV82kgSQIlXNMvA=="],
"@vitest/spy": ["@vitest/spy@4.0.17", "", {}, "sha512-I1bQo8QaP6tZlTomQNWKJE6ym4SHf3oLS7ceNjozxxgzavRAgZDc06T7kD8gb9bXKEgcLNt00Z+kZO6KaJ62Ew=="],
"@vitest/spy": ["@vitest/spy@4.0.18", "", {}, "sha512-cbQt3PTSD7P2OARdVW3qWER5EGq7PHlvE+QfzSC0lbwO+xnt7+XH06ZzFjFRgzUX//JmpxrCu92VdwvEPlWSNw=="],
"@vitest/utils": ["@vitest/utils@4.0.17", "", { "dependencies": { "@vitest/pretty-format": "4.0.17", "tinyrainbow": "^3.0.3" } }, "sha512-RG6iy+IzQpa9SB8HAFHJ9Y+pTzI+h8553MrciN9eC6TFBErqrQaTas4vG+MVj8S4uKk8uTT2p0vgZPnTdxd96w=="],
"@vitest/utils": ["@vitest/utils@4.0.18", "", { "dependencies": { "@vitest/pretty-format": "4.0.18", "tinyrainbow": "^3.0.3" } }, "sha512-msMRKLMVLWygpK3u2Hybgi4MNjcYJvwTb0Ru09+fOyCXIgT5raYP041DRRdiJiI3k/2U6SEbAETB3YtBrUkCFA=="],
"acorn": ["acorn@8.15.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg=="],
@@ -685,11 +712,11 @@
"ast-v8-to-istanbul": ["ast-v8-to-istanbul@0.3.10", "", { "dependencies": { "@jridgewell/trace-mapping": "^0.3.31", "estree-walker": "^3.0.3", "js-tokens": "^9.0.1" } }, "sha512-p4K7vMz2ZSk3wN8l5o3y2bJAoZXT3VuJI5OLTATY/01CYWumWvwkUw0SqDBnNq6IiTO3qDa1eSQDibAV8g7XOQ=="],
"babel-dead-code-elimination": ["babel-dead-code-elimination@1.0.11", "", { "dependencies": { "@babel/core": "^7.23.7", "@babel/parser": "^7.23.6", "@babel/traverse": "^7.23.7", "@babel/types": "^7.23.6" } }, "sha512-mwq3W3e/pKSI6TG8lXMiDWvEi1VXYlSBlJlB3l+I0bAb5u1RNUl88udos85eOPNK3m5EXK9uO7d2g08pesTySQ=="],
"babel-dead-code-elimination": ["babel-dead-code-elimination@1.0.12", "", { "dependencies": { "@babel/core": "^7.23.7", "@babel/parser": "^7.23.6", "@babel/traverse": "^7.23.7", "@babel/types": "^7.23.6" } }, "sha512-GERT7L2TiYcYDtYk1IpD+ASAYXjKbLTDPhBtYj7X1NuRMDTMtAx9kyBenub1Ev41lo91OHCKdmP+egTDmfQ7Ig=="],
"bail": ["bail@2.0.2", "", {}, "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw=="],
"baseline-browser-mapping": ["baseline-browser-mapping@2.9.11", "", { "bin": { "baseline-browser-mapping": "dist/cli.js" } }, "sha512-Sg0xJUNDU1sJNGdfGWhVHX0kkZ+HWcvmVymJbj6NSgZZmW/8S9Y2HQ5euytnIgakgxN6papOAWiwDo1ctFDcoQ=="],
"baseline-browser-mapping": ["baseline-browser-mapping@2.9.19", "", { "bin": { "baseline-browser-mapping": "dist/cli.js" } }, "sha512-ipDqC8FrAl/76p2SSWKSI+H9tFwm7vYqXQrItCuiVPt26Km0jS+NzSsBWAaBusvSbQcfJG+JitdMm+wZAgTYqg=="],
"bidi-js": ["bidi-js@1.0.3", "", { "dependencies": { "require-from-string": "^2.0.2" } }, "sha512-RKshQI1R3YQ+n9YJz2QQ147P66ELpa1FQEg20Dk8oW9t2KgLbpDLLp9aGZ7y8WHSshDknG0bknqGw5/tyCs5tw=="],
@@ -701,7 +728,7 @@
"browserslist": ["browserslist@4.28.1", "", { "dependencies": { "baseline-browser-mapping": "^2.9.0", "caniuse-lite": "^1.0.30001759", "electron-to-chromium": "^1.5.263", "node-releases": "^2.0.27", "update-browserslist-db": "^1.2.0" }, "bin": { "browserslist": "cli.js" } }, "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA=="],
"caniuse-lite": ["caniuse-lite@1.0.30001762", "", {}, "sha512-PxZwGNvH7Ak8WX5iXzoK1KPZttBXNPuaOvI2ZYU7NrlM+d9Ov+TUvlLOBNGzVXAntMSMMlJPd+jY6ovrVjSmUw=="],
"caniuse-lite": ["caniuse-lite@1.0.30001766", "", {}, "sha512-4C0lfJ0/YPjJQHagaE9x2Elb69CIqEPZeG0anQt9SIvIoOH4a4uaRl73IavyO+0qZh6MDLH//DrXThEYKHkmYA=="],
"ccount": ["ccount@2.0.1", "", {}, "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg=="],
@@ -717,15 +744,19 @@
"character-reference-invalid": ["character-reference-invalid@2.0.1", "", {}, "sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw=="],
"cheerio": ["cheerio@1.1.2", "", { "dependencies": { "cheerio-select": "^2.1.0", "dom-serializer": "^2.0.0", "domhandler": "^5.0.3", "domutils": "^3.2.2", "encoding-sniffer": "^0.2.1", "htmlparser2": "^10.0.0", "parse5": "^7.3.0", "parse5-htmlparser2-tree-adapter": "^7.1.0", "parse5-parser-stream": "^7.1.2", "undici": "^7.12.0", "whatwg-mimetype": "^4.0.0" } }, "sha512-IkxPpb5rS/d1IiLbHMgfPuS0FgiWTtFIm/Nj+2woXDLTZ7fOT2eqzgYbdMlLweqlHbsZjxEChoVK+7iph7jyQg=="],
"cheerio": ["cheerio@1.2.0", "", { "dependencies": { "cheerio-select": "^2.1.0", "dom-serializer": "^2.0.0", "domhandler": "^5.0.3", "domutils": "^3.2.2", "encoding-sniffer": "^0.2.1", "htmlparser2": "^10.1.0", "parse5": "^7.3.0", "parse5-htmlparser2-tree-adapter": "^7.1.0", "parse5-parser-stream": "^7.1.2", "undici": "^7.19.0", "whatwg-mimetype": "^4.0.0" } }, "sha512-WDrybc/gKFpTYQutKIK6UvfcuxijIZfMfXaYm8NMsPQxSYvf+13fXUJ4rztGGbJcBQ/GF55gvrZ0Bc0bj/mqvg=="],
"cheerio-select": ["cheerio-select@2.1.0", "", { "dependencies": { "boolbase": "^1.0.0", "css-select": "^5.1.0", "css-what": "^6.1.0", "domelementtype": "^2.3.0", "domhandler": "^5.0.3", "domutils": "^3.0.1" } }, "sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g=="],
"chokidar": ["chokidar@3.6.0", "", { "dependencies": { "anymatch": "~3.1.2", "braces": "~3.0.2", "glob-parent": "~5.1.2", "is-binary-path": "~2.1.0", "is-glob": "~4.0.1", "normalize-path": "~3.0.0", "readdirp": "~3.6.0" }, "optionalDependencies": { "fsevents": "~2.3.2" } }, "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw=="],
"clawhub": ["clawhub@workspace:packages/clawdhub"],
"clawhub-schema": ["clawhub-schema@workspace:packages/schema"],
"cli-cursor": ["cli-cursor@5.0.0", "", { "dependencies": { "restore-cursor": "^5.0.0" } }, "sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw=="],
"cli-spinners": ["cli-spinners@3.3.0", "", {}, "sha512-/+40ljC3ONVnYIttjMWrlL51nItDAbBrq2upN8BPyvGU/2n5Oxw3tbNwORCaNuNqLJnxGqOfjUuhsv7l5Q4IsQ=="],
"cli-spinners": ["cli-spinners@3.4.0", "", {}, "sha512-bXfOC4QcT1tKXGorxL3wbJm6XJPDqEnij2gQ2m7ESQuE+/z9YFIWnl/5RpTiKWbMq3EVKR4fRLJGn6DVfu0mpw=="],
"clsx": ["clsx@2.1.1", "", {}, "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA=="],
@@ -737,7 +768,7 @@
"convert-source-map": ["convert-source-map@2.0.0", "", {}, "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg=="],
"convex": ["convex@1.31.6", "", { "dependencies": { "esbuild": "0.27.0", "prettier": "^3.0.0" }, "peerDependencies": { "@auth0/auth0-react": "^2.0.1", "@clerk/clerk-react": "^4.12.8 || ^5.0.0", "react": "^18.0.0 || ^19.0.0-0 || ^19.0.0" }, "optionalPeers": ["@auth0/auth0-react", "@clerk/clerk-react", "react"], "bin": { "convex": "bin/main.js" } }, "sha512-9cIsOzepa3s9DURRF+fZHxbNuzLgilg9XGQCc45v0Xx4FemqeIezpPFSJF9WHC9ckk43TDUUXLecvLVt9djPkw=="],
"convex": ["convex@1.31.7", "", { "dependencies": { "esbuild": "0.27.0", "prettier": "^3.0.0" }, "peerDependencies": { "@auth0/auth0-react": "^2.0.1", "@clerk/clerk-react": "^4.12.8 || ^5.0.0", "react": "^18.0.0 || ^19.0.0-0 || ^19.0.0" }, "optionalPeers": ["@auth0/auth0-react", "@clerk/clerk-react", "react"], "bin": { "convex": "bin/main.js" } }, "sha512-PtNMe1mAIOvA8Yz100QTOaIdgt2rIuWqencVXrb4McdhxBHZ8IJ1eXTnrgCC9HydyilGT1pOn+KNqT14mqn9fQ=="],
"convex-helpers": ["convex-helpers@0.1.111", "", { "peerDependencies": { "@standard-schema/spec": "^1.0.0", "convex": "^1.25.4", "hono": "^4.0.5", "react": "^17.0.2 || ^18.0.0 || ^19.0.0", "typescript": "^5.5", "zod": "^3.25.0 || ^4.0.0" }, "optionalPeers": ["@standard-schema/spec", "hono", "react", "typescript", "zod"], "bin": { "convex-helpers": "bin.cjs" } }, "sha512-0O59Ohi8HVc3+KULxSC6JHsw8cQJyc8gZ7OAfNRVX7T5Wy6LhPx3l8veYN9avKg7UiPlO7m1eBiQMHKclIyXyQ=="],
@@ -745,7 +776,7 @@
"cookie-es": ["cookie-es@2.0.0", "", {}, "sha512-RAj4E421UYRgqokKUmotqAwuplYw15qtdXfY+hGzgCJ/MBjCVZcSoHK/kH9kocfjRjcDME7IiDWR/1WX1TM2Pg=="],
"crossws": ["crossws@0.4.1", "", { "peerDependencies": { "srvx": ">=0.7.1" }, "optionalPeers": ["srvx"] }, "sha512-E7WKBcHVhAVrY6JYD5kteNqVq1GSZxqGrdSiwXR9at+XHi43HJoCQKXcCczR5LBnBquFZPsB3o7HklulKoBU5w=="],
"crossws": ["crossws@0.4.4", "", { "peerDependencies": { "srvx": ">=0.7.1" }, "optionalPeers": ["srvx"] }, "sha512-w6c4OdpRNnudVmcgr7brb/+/HmYjMQvYToO/oTrprTwxRUiom3LYWU1PMWuD006okbUWpII1Ea9/+kwpUfmyRg=="],
"css-select": ["css-select@5.2.2", "", { "dependencies": { "boolbase": "^1.0.0", "css-what": "^6.1.0", "domhandler": "^5.0.2", "domutils": "^3.0.1", "nth-check": "^2.0.1" } }, "sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw=="],
@@ -753,11 +784,11 @@
"css-what": ["css-what@6.2.2", "", {}, "sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA=="],
"cssstyle": ["cssstyle@5.3.6", "", { "dependencies": { "@asamuzakjp/css-color": "^4.1.1", "@csstools/css-syntax-patches-for-csstree": "^1.0.21", "css-tree": "^3.1.0", "lru-cache": "^11.2.4" } }, "sha512-legscpSpgSAeGEe0TNcai97DKt9Vd9AsAdOL7Uoetb52Ar/8eJm3LIa39qpv8wWzLFlNG4vVvppQM+teaMPj3A=="],
"cssstyle": ["cssstyle@5.3.7", "", { "dependencies": { "@asamuzakjp/css-color": "^4.1.1", "@csstools/css-syntax-patches-for-csstree": "^1.0.21", "css-tree": "^3.1.0", "lru-cache": "^11.2.4" } }, "sha512-7D2EPVltRrsTkhpQmksIu+LxeWAIEk6wRDMJ1qljlv+CKHJM+cJLlfhWIzNA44eAsHXSNe3+vO6DW1yCYx8SuQ=="],
"csstype": ["csstype@3.2.3", "", {}, "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ=="],
"data-urls": ["data-urls@6.0.0", "", { "dependencies": { "whatwg-mimetype": "^4.0.0", "whatwg-url": "^15.0.0" } }, "sha512-BnBS08aLUM+DKamupXs3w2tJJoqU+AkaE/+6vQxi/G/DPmIZFJJp9Dkb1kM03AZx8ADehDUZgsNxju3mPXZYIA=="],
"data-urls": ["data-urls@6.0.1", "", { "dependencies": { "whatwg-mimetype": "^5.0.0", "whatwg-url": "^15.1.0" } }, "sha512-euIQENZg6x8mj3fO6o9+fOW8MimUI4PpD/fZBhJfeioZVy9TUpM4UY7KjQNVZFlqwJ0UdzRDzkycB997HEq1BQ=="],
"db0": ["db0@0.3.4", "", { "peerDependencies": { "@electric-sql/pglite": "*", "@libsql/client": "*", "better-sqlite3": "*", "drizzle-orm": "*", "mysql2": "*", "sqlite3": "*" }, "optionalPeers": ["@electric-sql/pglite", "@libsql/client", "better-sqlite3", "drizzle-orm", "mysql2", "sqlite3"] }, "sha512-RiXXi4WaNzPTHEOu8UPQKMooIbqOEyqA1t7Z6MsdxSCeb8iUC9ko3LcmsLmeUt2SM5bctfArZKkRQggKZz7JNw=="],
@@ -765,7 +796,7 @@
"decimal.js": ["decimal.js@10.6.0", "", {}, "sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg=="],
"decode-named-character-reference": ["decode-named-character-reference@1.2.0", "", { "dependencies": { "character-entities": "^2.0.0" } }, "sha512-c6fcElNV6ShtZXmsgNgFFV5tVX2PaV4g+MOAkb8eXHvn6sryJBrZa9r0zV6+dtTyoCKxtDy5tyQ5ZwQuidtd+Q=="],
"decode-named-character-reference": ["decode-named-character-reference@1.3.0", "", { "dependencies": { "character-entities": "^2.0.0" } }, "sha512-GtpQYB283KrPp6nRw50q3U9/VfOutZOe103qlN7BPP6Ad27xYnOIWv4lPzo8HCAL+mMZofJ9KEy30fq6MfaK6Q=="],
"dequal": ["dequal@2.0.3", "", {}, "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA=="],
@@ -775,7 +806,7 @@
"devlop": ["devlop@1.1.0", "", { "dependencies": { "dequal": "^2.0.0" } }, "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA=="],
"diff": ["diff@8.0.2", "", {}, "sha512-sSuxWU5j5SR9QQji/o2qMvqRNYRDOcBTgsJ/DeCf4iSN4gW+gNMXM7wFIP+fdXZxoNiAnHUTGjCr+TSWXdRDKg=="],
"diff": ["diff@8.0.3", "", {}, "sha512-qejHi7bcSD4hQAZE0tNAawRK1ZtafHDmMTMkrrIGgSLl7hTnQHmKCeB45xAcbfTqK2zowkM3j3bHt/4b/ARbYQ=="],
"dom-accessibility-api": ["dom-accessibility-api@0.5.16", "", {}, "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg=="],
@@ -789,7 +820,7 @@
"domutils": ["domutils@3.2.2", "", { "dependencies": { "dom-serializer": "^2.0.0", "domelementtype": "^2.3.0", "domhandler": "^5.0.3" } }, "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw=="],
"electron-to-chromium": ["electron-to-chromium@1.5.267", "", {}, "sha512-0Drusm6MVRXSOJpGbaSVgcQsuB4hEkMpHXaVstcPmhu5LIedxs1xNK/nIxmQIU/RPC0+1/o0AVZfBTkTNJOdUw=="],
"electron-to-chromium": ["electron-to-chromium@1.5.282", "", {}, "sha512-FCPkJtpst28UmFzd903iU7PdeVTfY0KAeJy+Lk0GLZRwgwYHn/irRcaCbQQOmr5Vytc/7rcavsYLvTM8RiHYhQ=="],
"encoding-sniffer": ["encoding-sniffer@0.2.1", "", { "dependencies": { "iconv-lite": "^0.6.3", "whatwg-encoding": "^3.1.1" } }, "sha512-5gvq20T6vfpekVtqrYQsSCFZ1wEg5+wW0/QaZMWkFr6BqD3NfKs0rLCx4rrVlSWJeZb5NBJgVLswK/w2MWU+Gw=="],
@@ -843,7 +874,7 @@
"h3": ["h3@2.0.1-rc.8", "", { "dependencies": { "rou3": "^0.7.12", "srvx": "^0.10.0" }, "peerDependencies": { "crossws": "^0.4.1" }, "optionalPeers": ["crossws"] }, "sha512-IIMQG7qnXx1Ls75suuMHH4xtcvTFxsUguDIZB+dgdYr1RftLj59FkeWF1dOr+jnejDs8Eo+ZKV1CMqogFeqGRQ=="],
"h3-v2": ["h3@2.0.1-rc.7", "", { "dependencies": { "rou3": "^0.7.12", "srvx": "^0.10.0" }, "peerDependencies": { "crossws": "^0.4.1" }, "optionalPeers": ["crossws"] }, "sha512-qbrRu1OLXmUYnysWOCVrYhtC/m8ZuXu/zCbo3U/KyphJxbPFiC76jHYwVrmEcss9uNAHO5BoUguQ46yEpgI2PA=="],
"h3-v2": ["h3@2.0.1-rc.11", "", { "dependencies": { "rou3": "^0.7.12", "srvx": "^0.10.1" }, "peerDependencies": { "crossws": "^0.4.1" }, "optionalPeers": ["crossws"] }, "sha512-2myzjCqy32c1As9TjZW9fNZXtLqNedjFSrdFy2AjFBQQ3LzrnGoDdFDYfC0tV2e4vcyfJ2Sfo/F6NQhO2Ly/Mw=="],
"has-flag": ["has-flag@4.0.0", "", {}, "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="],
@@ -857,7 +888,7 @@
"html-url-attributes": ["html-url-attributes@3.0.1", "", {}, "sha512-ol6UPyBWqsrO6EJySPz2O7ZSr856WDrEzM5zMqp+FJJLGMW35cLYmmZnl0vztAZxRUoNZJFTCohfjuIJ8I4QBQ=="],
"htmlparser2": ["htmlparser2@10.0.0", "", { "dependencies": { "domelementtype": "^2.3.0", "domhandler": "^5.0.3", "domutils": "^3.2.1", "entities": "^6.0.0" } }, "sha512-TwAZM+zE5Tq3lrEHvOlvwgj1XLWQCtaaibSN11Q+gGBAS7Y1uZSWwXXRe4iF6OXnaq1riyQAPFOBtYc77Mxq0g=="],
"htmlparser2": ["htmlparser2@10.1.0", "", { "dependencies": { "domelementtype": "^2.3.0", "domhandler": "^5.0.3", "domutils": "^3.2.2", "entities": "^7.0.1" } }, "sha512-VTZkM9GWRAtEpveh7MSF6SjjrpNVNNVJfFup7xTY3UpFtm67foy9HDVXneLtFVt4pMz5kZtgNcvCniNFb1hlEQ=="],
"http-proxy-agent": ["http-proxy-agent@7.0.2", "", { "dependencies": { "agent-base": "^7.1.0", "debug": "^4.3.4" } }, "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig=="],
@@ -895,7 +926,7 @@
"is-unicode-supported": ["is-unicode-supported@2.1.0", "", {}, "sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ=="],
"isbot": ["isbot@5.1.32", "", {}, "sha512-VNfjM73zz2IBZmdShMfAUg10prm6t7HFUQmNAEOAVS4YH92ZrZcvkMcGX6cIgBJAzWDzPent/EeAtYEHNPNPBQ=="],
"isbot": ["isbot@5.1.34", "", {}, "sha512-aCMIBSKd/XPRYdiCQTLC8QHH4YT8B3JUADu+7COgYIZPvkeoMcUHMRjZLM9/7V8fCj+l7FSREc1lOPNjzogo/A=="],
"istanbul-lib-coverage": ["istanbul-lib-coverage@3.2.2", "", {}, "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg=="],
@@ -949,7 +980,7 @@
"longest-streak": ["longest-streak@3.1.0", "", {}, "sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g=="],
"lru-cache": ["lru-cache@11.2.4", "", {}, "sha512-B5Y16Jr9LB9dHVkh6ZevG+vAbOsNOYCX+sXvFWFu7B3Iz5mijW3zdbMyhsh8ANd2mSWBYdJgnqi+mL7/LrOPYg=="],
"lru-cache": ["lru-cache@11.2.5", "", {}, "sha512-vFrFJkWtJvJnD5hg+hJvVE8Lh/TcMzKnTgCWmtBipwI5yLX/iX+5UB2tfuyODF5E7k9xEzMdYgGqaSb1c0c5Yw=="],
"lucia": ["lucia@3.2.2", "", { "dependencies": { "@oslojs/crypto": "^1.0.1", "@oslojs/encoding": "^1.1.0" } }, "sha512-P1FlFBGCMPMXu+EGdVD9W4Mjm0DqsusmKgO7Xc33mI5X1bklmsQb0hfzPhXomQr9waWIBDsiOjvr1e6BTaUqpA=="],
@@ -1059,19 +1090,15 @@
"mimic-function": ["mimic-function@5.0.1", "", {}, "sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA=="],
"molthub": ["molthub@workspace:packages/molthub"],
"molthub-schema": ["molthub-schema@workspace:packages/schema"],
"monaco-editor": ["monaco-editor@0.55.1", "", { "dependencies": { "dompurify": "3.2.7", "marked": "14.0.0" } }, "sha512-jz4x+TJNFHwHtwuV9vA9rMujcZRb0CEilTEwG2rRSpe/A7Jdkuj8xPKttCgOh+v/lkHy7HsZ64oj+q3xoAFl9A=="],
"ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="],
"nanoid": ["nanoid@3.3.11", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="],
"nf3": ["nf3@0.1.12", "", {}, "sha512-qbMXT7RTGh74MYWPeqTIED8nDW70NXOULVHpdWcdZ7IVHVnAsMV9fNugSNnvooipDc1FMOzpis7T9nXJEbJhvQ=="],
"nf3": ["nf3@0.3.7", "", {}, "sha512-wL73kyZbBoeTWlvQWQ0gQDZnqp+aNlUN5YIqsc3fv5V/06LAlwrwt+G7TpugFLJIai0AhrmnKJ2kgW0xprj+yQ=="],
"nitro": ["nitro@3.0.1-alpha.1", "", { "dependencies": { "consola": "^3.4.2", "crossws": "^0.4.1", "db0": "^0.3.4", "h3": "2.0.1-rc.5", "jiti": "^2.6.1", "nf3": "^0.1.10", "ofetch": "^2.0.0-alpha.3", "ohash": "^2.0.11", "oxc-minify": "^0.96.0", "oxc-transform": "^0.96.0", "srvx": "^0.9.5", "undici": "^7.16.0", "unenv": "^2.0.0-rc.24", "unstorage": "^2.0.0-alpha.4" }, "peerDependencies": { "rolldown": "*", "rollup": "^4", "vite": "^7", "xml2js": "^0.6.2" }, "optionalPeers": ["rolldown", "rollup", "vite", "xml2js"], "bin": { "nitro": "dist/cli/index.mjs" } }, "sha512-U4AxIsXxdkxzkFrK0XAw0e5Qbojk8jQ50MjjRBtBakC4HurTtQoiZvF+lSe382jhuQZCfAyywGWOFa9QzXLFaw=="],
"nitro": ["nitro@3.0.1-alpha.2", "", { "dependencies": { "consola": "^3.4.2", "crossws": "^0.4.3", "db0": "^0.3.4", "h3": "^2.0.1-rc.11", "jiti": "^2.6.1", "nf3": "^0.3.5", "ofetch": "^2.0.0-alpha.3", "ohash": "^2.0.11", "oxc-minify": "^0.110.0", "oxc-transform": "^0.110.0", "srvx": "^0.10.1", "undici": "^7.18.2", "unenv": "^2.0.0-rc.24", "unstorage": "^2.0.0-alpha.5" }, "peerDependencies": { "rolldown": ">=1.0.0-beta.0", "rollup": "^4", "vite": "^7 || ^8 || >=8.0.0-0", "xml2js": "^0.6.2" }, "optionalPeers": ["rolldown", "rollup", "vite", "xml2js"], "bin": { "nitro": "dist/cli/index.mjs" } }, "sha512-YviDY5J/trS821qQ1fpJtpXWIdPYiOizC/meHavlm1Hfuhx//H+Egd1+4C5SegJRgtWMnRPW9n//6Woaw81cTQ=="],
"node-releases": ["node-releases@2.0.27", "", {}, "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA=="],
@@ -1091,15 +1118,15 @@
"only-allow": ["only-allow@1.2.2", "", { "dependencies": { "which-pm-runs": "1.1.0" }, "bin": { "only-allow": "bin.js" } }, "sha512-uxyNYDsCh5YIJ780G7hC5OHjVUr9reHsbZNMM80L9tZlTpb3hUzb36KXgW4ZUGtJKQnGA3xegmWg1BxhWV0jJA=="],
"ora": ["ora@9.0.0", "", { "dependencies": { "chalk": "^5.6.2", "cli-cursor": "^5.0.0", "cli-spinners": "^3.2.0", "is-interactive": "^2.0.0", "is-unicode-supported": "^2.1.0", "log-symbols": "^7.0.1", "stdin-discarder": "^0.2.2", "string-width": "^8.1.0", "strip-ansi": "^7.1.2" } }, "sha512-m0pg2zscbYgWbqRR6ABga5c3sZdEon7bSgjnlXC64kxtxLOyjRcbbUkLj7HFyy/FTD+P2xdBWu8snGhYI0jc4A=="],
"ora": ["ora@9.1.0", "", { "dependencies": { "chalk": "^5.6.2", "cli-cursor": "^5.0.0", "cli-spinners": "^3.2.0", "is-interactive": "^2.0.0", "is-unicode-supported": "^2.1.0", "log-symbols": "^7.0.1", "stdin-discarder": "^0.2.2", "string-width": "^8.1.0" } }, "sha512-53uuLsXHOAJl5zLrUrzY9/kE+uIFEx7iaH4g2BIJQK4LZjY4LpCCYZVKDWIkL+F01wAaCg93duQ1whnK/AmY1A=="],
"oxc-minify": ["oxc-minify@0.96.0", "", { "optionalDependencies": { "@oxc-minify/binding-android-arm64": "0.96.0", "@oxc-minify/binding-darwin-arm64": "0.96.0", "@oxc-minify/binding-darwin-x64": "0.96.0", "@oxc-minify/binding-freebsd-x64": "0.96.0", "@oxc-minify/binding-linux-arm-gnueabihf": "0.96.0", "@oxc-minify/binding-linux-arm-musleabihf": "0.96.0", "@oxc-minify/binding-linux-arm64-gnu": "0.96.0", "@oxc-minify/binding-linux-arm64-musl": "0.96.0", "@oxc-minify/binding-linux-riscv64-gnu": "0.96.0", "@oxc-minify/binding-linux-s390x-gnu": "0.96.0", "@oxc-minify/binding-linux-x64-gnu": "0.96.0", "@oxc-minify/binding-linux-x64-musl": "0.96.0", "@oxc-minify/binding-wasm32-wasi": "0.96.0", "@oxc-minify/binding-win32-arm64-msvc": "0.96.0", "@oxc-minify/binding-win32-x64-msvc": "0.96.0" } }, "sha512-dXeeGrfPJJ4rMdw+NrqiCRtbzVX2ogq//R0Xns08zql2HjV3Zi2SBJ65saqfDaJzd2bcHqvGWH+M44EQCHPAcA=="],
"oxc-minify": ["oxc-minify@0.110.0", "", { "optionalDependencies": { "@oxc-minify/binding-android-arm-eabi": "0.110.0", "@oxc-minify/binding-android-arm64": "0.110.0", "@oxc-minify/binding-darwin-arm64": "0.110.0", "@oxc-minify/binding-darwin-x64": "0.110.0", "@oxc-minify/binding-freebsd-x64": "0.110.0", "@oxc-minify/binding-linux-arm-gnueabihf": "0.110.0", "@oxc-minify/binding-linux-arm-musleabihf": "0.110.0", "@oxc-minify/binding-linux-arm64-gnu": "0.110.0", "@oxc-minify/binding-linux-arm64-musl": "0.110.0", "@oxc-minify/binding-linux-ppc64-gnu": "0.110.0", "@oxc-minify/binding-linux-riscv64-gnu": "0.110.0", "@oxc-minify/binding-linux-riscv64-musl": "0.110.0", "@oxc-minify/binding-linux-s390x-gnu": "0.110.0", "@oxc-minify/binding-linux-x64-gnu": "0.110.0", "@oxc-minify/binding-linux-x64-musl": "0.110.0", "@oxc-minify/binding-openharmony-arm64": "0.110.0", "@oxc-minify/binding-wasm32-wasi": "0.110.0", "@oxc-minify/binding-win32-arm64-msvc": "0.110.0", "@oxc-minify/binding-win32-ia32-msvc": "0.110.0", "@oxc-minify/binding-win32-x64-msvc": "0.110.0" } }, "sha512-KWGTzPo83QmGrXC4ml83PM9HDwUPtZFfasiclUvTV4i3/0j7xRRqINVkrL77CbQnoWura3CMxkRofjQKVDuhBw=="],
"oxc-transform": ["oxc-transform@0.96.0", "", { "optionalDependencies": { "@oxc-transform/binding-android-arm64": "0.96.0", "@oxc-transform/binding-darwin-arm64": "0.96.0", "@oxc-transform/binding-darwin-x64": "0.96.0", "@oxc-transform/binding-freebsd-x64": "0.96.0", "@oxc-transform/binding-linux-arm-gnueabihf": "0.96.0", "@oxc-transform/binding-linux-arm-musleabihf": "0.96.0", "@oxc-transform/binding-linux-arm64-gnu": "0.96.0", "@oxc-transform/binding-linux-arm64-musl": "0.96.0", "@oxc-transform/binding-linux-riscv64-gnu": "0.96.0", "@oxc-transform/binding-linux-s390x-gnu": "0.96.0", "@oxc-transform/binding-linux-x64-gnu": "0.96.0", "@oxc-transform/binding-linux-x64-musl": "0.96.0", "@oxc-transform/binding-wasm32-wasi": "0.96.0", "@oxc-transform/binding-win32-arm64-msvc": "0.96.0", "@oxc-transform/binding-win32-x64-msvc": "0.96.0" } }, "sha512-dQPNIF+gHpSkmC0+Vg9IktNyhcn28Y8R3eTLyzn52UNymkasLicl3sFAtz7oEVuFmCpgGjaUTKkwk+jW2cHpDQ=="],
"oxc-transform": ["oxc-transform@0.110.0", "", { "optionalDependencies": { "@oxc-transform/binding-android-arm-eabi": "0.110.0", "@oxc-transform/binding-android-arm64": "0.110.0", "@oxc-transform/binding-darwin-arm64": "0.110.0", "@oxc-transform/binding-darwin-x64": "0.110.0", "@oxc-transform/binding-freebsd-x64": "0.110.0", "@oxc-transform/binding-linux-arm-gnueabihf": "0.110.0", "@oxc-transform/binding-linux-arm-musleabihf": "0.110.0", "@oxc-transform/binding-linux-arm64-gnu": "0.110.0", "@oxc-transform/binding-linux-arm64-musl": "0.110.0", "@oxc-transform/binding-linux-ppc64-gnu": "0.110.0", "@oxc-transform/binding-linux-riscv64-gnu": "0.110.0", "@oxc-transform/binding-linux-riscv64-musl": "0.110.0", "@oxc-transform/binding-linux-s390x-gnu": "0.110.0", "@oxc-transform/binding-linux-x64-gnu": "0.110.0", "@oxc-transform/binding-linux-x64-musl": "0.110.0", "@oxc-transform/binding-openharmony-arm64": "0.110.0", "@oxc-transform/binding-wasm32-wasi": "0.110.0", "@oxc-transform/binding-win32-arm64-msvc": "0.110.0", "@oxc-transform/binding-win32-ia32-msvc": "0.110.0", "@oxc-transform/binding-win32-x64-msvc": "0.110.0" } }, "sha512-/fymQNzzUoKZweH0nC5yvbI2eR0yWYusT9TEKDYVgOgYrf9Qmdez9lUFyvxKR9ycx+PTHi/reIOzqf3wkShQsw=="],
"oxlint": ["oxlint@1.39.0", "", { "optionalDependencies": { "@oxlint/darwin-arm64": "1.39.0", "@oxlint/darwin-x64": "1.39.0", "@oxlint/linux-arm64-gnu": "1.39.0", "@oxlint/linux-arm64-musl": "1.39.0", "@oxlint/linux-x64-gnu": "1.39.0", "@oxlint/linux-x64-musl": "1.39.0", "@oxlint/win32-arm64": "1.39.0", "@oxlint/win32-x64": "1.39.0" }, "peerDependencies": { "oxlint-tsgolint": ">=0.10.0" }, "optionalPeers": ["oxlint-tsgolint"], "bin": { "oxlint": "bin/oxlint" } }, "sha512-wSiLr0wjG+KTU6c1LpVoQk7JZ7l8HCKlAkVDVTJKWmCGazsNxexxnOXl7dsar92mQcRnzko5g077ggP3RINSjA=="],
"oxlint": ["oxlint@1.42.0", "", { "optionalDependencies": { "@oxlint/darwin-arm64": "1.42.0", "@oxlint/darwin-x64": "1.42.0", "@oxlint/linux-arm64-gnu": "1.42.0", "@oxlint/linux-arm64-musl": "1.42.0", "@oxlint/linux-x64-gnu": "1.42.0", "@oxlint/linux-x64-musl": "1.42.0", "@oxlint/win32-arm64": "1.42.0", "@oxlint/win32-x64": "1.42.0" }, "peerDependencies": { "oxlint-tsgolint": ">=0.11.2" }, "optionalPeers": ["oxlint-tsgolint"], "bin": { "oxlint": "bin/oxlint" } }, "sha512-qnspC/lrp8FgKNaONLLn14dm+W5t0SSlus6V5NJpgI2YNT1tkFYZt4fBf14ESxf9AAh98WBASnW5f0gtw462Lg=="],
"oxlint-tsgolint": ["oxlint-tsgolint@0.11.1", "", { "optionalDependencies": { "@oxlint-tsgolint/darwin-arm64": "0.11.1", "@oxlint-tsgolint/darwin-x64": "0.11.1", "@oxlint-tsgolint/linux-arm64": "0.11.1", "@oxlint-tsgolint/linux-x64": "0.11.1", "@oxlint-tsgolint/win32-arm64": "0.11.1", "@oxlint-tsgolint/win32-x64": "0.11.1" }, "bin": { "tsgolint": "bin/tsgolint.js" } }, "sha512-WulCp+0/6RvpM4zPv+dAXybf03QvRA8ATxaBlmj4XMIQqTs5jeq3cUTk48WCt4CpLwKhyyGZPHmjLl1KHQ/cvA=="],
"oxlint-tsgolint": ["oxlint-tsgolint@0.11.3", "", { "optionalDependencies": { "@oxlint-tsgolint/darwin-arm64": "0.11.3", "@oxlint-tsgolint/darwin-x64": "0.11.3", "@oxlint-tsgolint/linux-arm64": "0.11.3", "@oxlint-tsgolint/linux-x64": "0.11.3", "@oxlint-tsgolint/win32-arm64": "0.11.3", "@oxlint-tsgolint/win32-x64": "0.11.3" }, "bin": { "tsgolint": "bin/tsgolint.js" } }, "sha512-zkuGXJzE5WIoGQ6CHG3GbxncPNrvUG9giTKdXMqKrlieCRxa9hGMvMJM+7DFxKSaryVAEFrTQJNrGJHpeMmFPg=="],
"p-retry": ["p-retry@7.1.1", "", { "dependencies": { "is-network-error": "^1.1.0" } }, "sha512-J5ApzjyRkkf601HpEeykoiCvzHQjWxPAHhyjFcEUP2SWq0+35NKh8TLhpLw+Dkq5TZBFvUM6UigdE9hIVYTl5w=="],
@@ -1119,9 +1146,9 @@
"picomatch": ["picomatch@4.0.3", "", {}, "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q=="],
"playwright": ["playwright@1.57.0", "", { "dependencies": { "playwright-core": "1.57.0" }, "optionalDependencies": { "fsevents": "2.3.2" }, "bin": { "playwright": "cli.js" } }, "sha512-ilYQj1s8sr2ppEJ2YVadYBN0Mb3mdo9J0wQ+UuDhzYqURwSoW4n1Xs5vs7ORwgDGmyEh33tRMeS8KhdkMoLXQw=="],
"playwright": ["playwright@1.58.0", "", { "dependencies": { "playwright-core": "1.58.0" }, "optionalDependencies": { "fsevents": "2.3.2" }, "bin": { "playwright": "cli.js" } }, "sha512-2SVA0sbPktiIY/MCOPX8e86ehA/e+tDNq+e5Y8qjKYti2Z/JG7xnronT/TXTIkKbYGWlCbuucZ6dziEgkoEjQQ=="],
"playwright-core": ["playwright-core@1.57.0", "", { "bin": { "playwright-core": "cli.js" } }, "sha512-agTcKlMw/mjBWOnD6kFZttAAGHgi/Nw0CZ2o6JqWSbMlI219lAFLZZCyqByTsvVAJq5XA5H8cA6PrvBRpBWEuQ=="],
"playwright-core": ["playwright-core@1.58.0", "", { "bin": { "playwright-core": "cli.js" } }, "sha512-aaoB1RWrdNi3//rOeKuMiS65UCcgOVljU46At6eFcOFPFHWtd2weHRRow6z/n+Lec0Lvu0k9ZPKJSjPugikirw=="],
"postcss": ["postcss@8.5.6", "", { "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg=="],
@@ -1129,7 +1156,7 @@
"preact-render-to-string": ["preact-render-to-string@6.5.11", "", { "peerDependencies": { "preact": ">=10" } }, "sha512-ubnauqoGczeGISiOh6RjX0/cdaF8v/oDXIjO85XALCQjwQP+SB4RDXXtvZ6yTYSjG+PC1QRP2AhPgCEsM2EvUw=="],
"prettier": ["prettier@3.7.4", "", { "bin": { "prettier": "bin/prettier.cjs" } }, "sha512-v6UNi1+3hSlVvv8fSaoUbggEM5VErKmmpGA7Pl3HF8V6uKY7rvClBOJlH6yNwQtfTueNkGVpOv/mtWL9L4bgRA=="],
"prettier": ["prettier@3.8.1", "", { "bin": { "prettier": "bin/prettier.cjs" } }, "sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg=="],
"pretty-format": ["pretty-format@27.5.1", "", { "dependencies": { "ansi-regex": "^5.0.1", "ansi-styles": "^5.0.0", "react-is": "^17.0.1" } }, "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ=="],
@@ -1137,9 +1164,9 @@
"punycode": ["punycode@2.3.1", "", {}, "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg=="],
"react": ["react@19.2.3", "", {}, "sha512-Ku/hhYbVjOQnXDZFv2+RibmLFGwFdeeKHFcOTlrt7xplBnya5OGn/hIRDsqDiSUcfORsDC7MPxwork8jBwsIWA=="],
"react": ["react@19.2.4", "", {}, "sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ=="],
"react-dom": ["react-dom@19.2.3", "", { "dependencies": { "scheduler": "^0.27.0" }, "peerDependencies": { "react": "^19.2.3" } }, "sha512-yELu4WmLPw5Mr/lmeEpox5rw3RETacE++JgHqQzd2dg+YbJuat3jH4ingc+WPZhxaoFzdv9y33G+F7Nl5O0GBg=="],
"react-dom": ["react-dom@19.2.4", "", { "dependencies": { "scheduler": "^0.27.0" }, "peerDependencies": { "react": "^19.2.4" } }, "sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ=="],
"react-is": ["react-is@17.0.2", "", {}, "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w=="],
@@ -1171,7 +1198,7 @@
"restore-cursor": ["restore-cursor@5.1.0", "", { "dependencies": { "onetime": "^7.0.0", "signal-exit": "^4.1.0" } }, "sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA=="],
"rollup": ["rollup@4.54.0", "", { "dependencies": { "@types/estree": "1.0.8" }, "optionalDependencies": { "@rollup/rollup-android-arm-eabi": "4.54.0", "@rollup/rollup-android-arm64": "4.54.0", "@rollup/rollup-darwin-arm64": "4.54.0", "@rollup/rollup-darwin-x64": "4.54.0", "@rollup/rollup-freebsd-arm64": "4.54.0", "@rollup/rollup-freebsd-x64": "4.54.0", "@rollup/rollup-linux-arm-gnueabihf": "4.54.0", "@rollup/rollup-linux-arm-musleabihf": "4.54.0", "@rollup/rollup-linux-arm64-gnu": "4.54.0", "@rollup/rollup-linux-arm64-musl": "4.54.0", "@rollup/rollup-linux-loong64-gnu": "4.54.0", "@rollup/rollup-linux-ppc64-gnu": "4.54.0", "@rollup/rollup-linux-riscv64-gnu": "4.54.0", "@rollup/rollup-linux-riscv64-musl": "4.54.0", "@rollup/rollup-linux-s390x-gnu": "4.54.0", "@rollup/rollup-linux-x64-gnu": "4.54.0", "@rollup/rollup-linux-x64-musl": "4.54.0", "@rollup/rollup-openharmony-arm64": "4.54.0", "@rollup/rollup-win32-arm64-msvc": "4.54.0", "@rollup/rollup-win32-ia32-msvc": "4.54.0", "@rollup/rollup-win32-x64-gnu": "4.54.0", "@rollup/rollup-win32-x64-msvc": "4.54.0", "fsevents": "~2.3.2" }, "bin": { "rollup": "dist/bin/rollup" } }, "sha512-3nk8Y3a9Ea8szgKhinMlGMhGMw89mqule3KWczxhIzqudyHdCIOHw8WJlj/r329fACjKLEh13ZSk7oE22kyeIw=="],
"rollup": ["rollup@4.57.0", "", { "dependencies": { "@types/estree": "1.0.8" }, "optionalDependencies": { "@rollup/rollup-android-arm-eabi": "4.57.0", "@rollup/rollup-android-arm64": "4.57.0", "@rollup/rollup-darwin-arm64": "4.57.0", "@rollup/rollup-darwin-x64": "4.57.0", "@rollup/rollup-freebsd-arm64": "4.57.0", "@rollup/rollup-freebsd-x64": "4.57.0", "@rollup/rollup-linux-arm-gnueabihf": "4.57.0", "@rollup/rollup-linux-arm-musleabihf": "4.57.0", "@rollup/rollup-linux-arm64-gnu": "4.57.0", "@rollup/rollup-linux-arm64-musl": "4.57.0", "@rollup/rollup-linux-loong64-gnu": "4.57.0", "@rollup/rollup-linux-loong64-musl": "4.57.0", "@rollup/rollup-linux-ppc64-gnu": "4.57.0", "@rollup/rollup-linux-ppc64-musl": "4.57.0", "@rollup/rollup-linux-riscv64-gnu": "4.57.0", "@rollup/rollup-linux-riscv64-musl": "4.57.0", "@rollup/rollup-linux-s390x-gnu": "4.57.0", "@rollup/rollup-linux-x64-gnu": "4.57.0", "@rollup/rollup-linux-x64-musl": "4.57.0", "@rollup/rollup-openbsd-x64": "4.57.0", "@rollup/rollup-openharmony-arm64": "4.57.0", "@rollup/rollup-win32-arm64-msvc": "4.57.0", "@rollup/rollup-win32-ia32-msvc": "4.57.0", "@rollup/rollup-win32-x64-gnu": "4.57.0", "@rollup/rollup-win32-x64-msvc": "4.57.0", "fsevents": "~2.3.2" }, "bin": { "rollup": "dist/bin/rollup" } }, "sha512-e5lPJi/aui4TO1LpAXIRLySmwXSE8k3b9zoGfd42p67wzxog4WHjiZF3M2uheQih4DGyc25QEV4yRBbpueNiUA=="],
"rou3": ["rou3@0.7.12", "", {}, "sha512-iFE4hLDuloSWcD7mjdCDhx2bKcIsYbtOTpfH5MHHLSKMOUyjqQXTeZVa289uuwEGEKFoE/BAPbhaU4B774nceg=="],
@@ -1183,9 +1210,9 @@
"semver": ["semver@7.7.3", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q=="],
"seroval": ["seroval@1.4.2", "", {}, "sha512-N3HEHRCZYn3cQbsC4B5ldj9j+tHdf4JZoYPlcI4rRYu0Xy4qN8MQf1Z08EibzB0WpgRG5BGK08FTrmM66eSzKQ=="],
"seroval": ["seroval@1.5.0", "", {}, "sha512-OE4cvmJ1uSPrKorFIH9/w/Qwuvi/IMcGbv5RKgcJ/zjA/IohDLU6SVaxFN9FwajbP7nsX0dQqMDes1whk3y+yw=="],
"seroval-plugins": ["seroval-plugins@1.4.2", "", { "peerDependencies": { "seroval": "^1.0" } }, "sha512-X7p4MEDTi+60o2sXZ4bnDBhgsUYDSkQEvzYZuJyFqWg9jcoPsHts5nrg5O956py2wyt28lUrBxk0M0/wU8URpA=="],
"seroval-plugins": ["seroval-plugins@1.5.0", "", { "peerDependencies": { "seroval": "^1.0" } }, "sha512-EAHqADIQondwRZIdeW2I636zgsODzoBDwb3PT/+7TLDWyw1Dy/Xv7iGUIEXXav7usHDE9HVhOU61irI3EnyyHA=="],
"server-only": ["server-only@0.0.1", "", {}, "sha512-qepMx2JxAa5jjfzxG79yPPq+8BuFToHd1hm7kI+Z4zAq1ftQiP7HcxMhDDItrbtwVeLg/cY2JnKnrcFkmiswNA=="],
@@ -1197,7 +1224,7 @@
"sisteransi": ["sisteransi@1.0.5", "", {}, "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg=="],
"solid-js": ["solid-js@1.9.10", "", { "dependencies": { "csstype": "^3.1.0", "seroval": "~1.3.0", "seroval-plugins": "~1.3.0" } }, "sha512-Coz956cos/EPDlhs6+jsdTxKuJDPT7B5SVIWgABwROyxjY7Xbr8wkzD68Et+NxnV7DLJ3nJdAC2r9InuV/4Jew=="],
"solid-js": ["solid-js@1.9.11", "", { "dependencies": { "csstype": "^3.1.0", "seroval": "~1.5.0", "seroval-plugins": "~1.5.0" } }, "sha512-WEJtcc5mkh/BnHA6Yrg4whlF8g6QwpmXXRg4P2ztPmcKeHHlH4+djYecBLhSpecZY2RRECXYUwIc/C2r3yzQ4Q=="],
"source-map": ["source-map@0.7.6", "", {}, "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ=="],
@@ -1205,7 +1232,7 @@
"space-separated-tokens": ["space-separated-tokens@2.0.2", "", {}, "sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q=="],
"srvx": ["srvx@0.10.0", "", { "bin": { "srvx": "bin/srvx.mjs" } }, "sha512-NqIsR+wQCfkvvwczBh8J8uM4wTZx41K2lLSEp/3oMp917ODVVMtW5Me4epCmQ3gH8D+0b+/t4xxkUKutyhimTA=="],
"srvx": ["srvx@0.10.1", "", { "bin": { "srvx": "bin/srvx.mjs" } }, "sha512-A//xtfak4eESMWWydSRFUVvCTQbSwivnGCEf8YGPe2eHU0+Z6znfUTCPF0a7oV3sObSOcrXHlL6Bs9vVctfXdg=="],
"stackback": ["stackback@0.0.2", "", {}, "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw=="],
@@ -1215,7 +1242,7 @@
"stdin-discarder": ["stdin-discarder@0.2.2", "", {}, "sha512-UhDfHmA92YAlNnCfhmq0VeNL5bDbiZGg7sZ2IvPsXubGkiNa9EC+tUTsjBRsYUAz87btI6/1wf4XoVvQ3uRnmQ=="],
"string-width": ["string-width@8.1.0", "", { "dependencies": { "get-east-asian-width": "^1.3.0", "strip-ansi": "^7.1.0" } }, "sha512-Kxl3KJGb/gxkaUMOjRsQ8IrXiGW75O4E3RPjFIINOVH8AMl2SQ/yWdTzWwF3FevIX9LcMAjJW+GRwAlAbTSXdg=="],
"string-width": ["string-width@8.1.1", "", { "dependencies": { "get-east-asian-width": "^1.3.0", "strip-ansi": "^7.1.0" } }, "sha512-KpqHIdDL9KwYk22wEOg/VIqYbrnLeSApsKT/bSj6Ez7pn3CftUiLAv2Lccpq1ALcpLV9UX1Ppn92npZWu2w/aw=="],
"stringify-entities": ["stringify-entities@4.0.4", "", { "dependencies": { "character-entities-html4": "^2.0.0", "character-entities-legacy": "^3.0.0" } }, "sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg=="],
@@ -1269,9 +1296,9 @@
"typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="],
"ufo": ["ufo@1.6.1", "", {}, "sha512-9a4/uxlTWJ4+a5i0ooc1rU7C7YOw3wT+UGqdeNNHWnOF9qcMBgLRS+4IYUqbczewFx4mLEig6gawh7X6mFlEkA=="],
"ufo": ["ufo@1.6.3", "", {}, "sha512-yDJTmhydvl5lJzBmy/hyOAA0d+aqCBuwl818haVdYCRrWV84o7YyeVm4QlVHStqNrrJSTb6jKuFAVqAFsr+K3Q=="],
"undici": ["undici@7.16.0", "", {}, "sha512-QEg3HPMll0o3t2ourKwOeUAZ159Kn9mx5pnzHRQO8+Wixmh88YdZRiIwat0iNzNNXn0yoEtXJqFpyW7eM8BV7g=="],
"undici": ["undici@7.19.2", "", {}, "sha512-4VQSpGEGsWzk0VYxyB/wVX/Q7qf9t5znLRgs0dzszr9w9Fej/8RVNQ+S20vdXSAyra/bJ7ZQfGv6ZMj7UEbzSg=="],
"undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="],
@@ -1285,13 +1312,13 @@
"unist-util-stringify-position": ["unist-util-stringify-position@4.0.0", "", { "dependencies": { "@types/unist": "^3.0.0" } }, "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ=="],
"unist-util-visit": ["unist-util-visit@5.0.0", "", { "dependencies": { "@types/unist": "^3.0.0", "unist-util-is": "^6.0.0", "unist-util-visit-parents": "^6.0.0" } }, "sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg=="],
"unist-util-visit": ["unist-util-visit@5.1.0", "", { "dependencies": { "@types/unist": "^3.0.0", "unist-util-is": "^6.0.0", "unist-util-visit-parents": "^6.0.0" } }, "sha512-m+vIdyeCOpdr/QeQCu2EzxX/ohgS8KbnPDgFni4dQsfSCtpz8UqDyY5GjRru8PDKuYn7Fq19j1CQ+nJSsGKOzg=="],
"unist-util-visit-parents": ["unist-util-visit-parents@6.0.2", "", { "dependencies": { "@types/unist": "^3.0.0", "unist-util-is": "^6.0.0" } }, "sha512-goh1s1TBrqSqukSc8wrjwWhL0hiJxgA8m4kFxGlQ+8FYQ3C/m11FcTs4YYem7V664AhHVvgoQLk890Ssdsr2IQ=="],
"unplugin": ["unplugin@2.3.11", "", { "dependencies": { "@jridgewell/remapping": "^2.3.5", "acorn": "^8.15.0", "picomatch": "^4.0.3", "webpack-virtual-modules": "^0.6.2" } }, "sha512-5uKD0nqiYVzlmCRs01Fhs2BdkEgBS3SAVP6ndrBsuK42iC2+JHyxM05Rm9G8+5mkmRtzMZGY8Ct5+mliZxU/Ww=="],
"unstorage": ["unstorage@2.0.0-alpha.4", "", { "peerDependencies": { "@azure/app-configuration": "^1.8.0", "@azure/cosmos": "^4.2.0", "@azure/data-tables": "^13.3.0", "@azure/identity": "^4.6.0", "@azure/keyvault-secrets": "^4.9.0", "@azure/storage-blob": "^12.26.0", "@capacitor/preferences": "^6.0.3 || ^7.0.0", "@deno/kv": ">=0.9.0", "@netlify/blobs": "^6.5.0 || ^7.0.0 || ^8.1.0 || ^9.0.0 || ^10.0.0", "@planetscale/database": "^1.19.0", "@upstash/redis": "^1.34.3", "@vercel/blob": ">=0.27.1", "@vercel/functions": "^2.2.12 || ^3.0.0", "@vercel/kv": "^1.0.1", "aws4fetch": "^1.0.20", "chokidar": "^4.0.3", "db0": ">=0.2.1", "idb-keyval": "^6.2.1", "ioredis": "^5.4.2", "lru-cache": "^11.2.2", "mongodb": "^6.20.0", "ofetch": "*", "uploadthing": "^7.4.4" }, "optionalPeers": ["@azure/app-configuration", "@azure/cosmos", "@azure/data-tables", "@azure/identity", "@azure/keyvault-secrets", "@azure/storage-blob", "@capacitor/preferences", "@deno/kv", "@netlify/blobs", "@planetscale/database", "@upstash/redis", "@vercel/blob", "@vercel/functions", "@vercel/kv", "aws4fetch", "chokidar", "db0", "idb-keyval", "ioredis", "lru-cache", "mongodb", "ofetch", "uploadthing"] }, "sha512-ywXZMZRfrvmO1giJeMTCw6VUn0ALYxVl8pFqJPStiyQUvgJImejtAHrKvXPj4QGJAoS/iLGcVGF6ljN/lkh1bw=="],
"unstorage": ["unstorage@2.0.0-alpha.5", "", { "peerDependencies": { "@azure/app-configuration": "^1.9.0", "@azure/cosmos": "^4.7.0", "@azure/data-tables": "^13.3.1", "@azure/identity": "^4.13.0", "@azure/keyvault-secrets": "^4.10.0", "@azure/storage-blob": "^12.29.1", "@capacitor/preferences": "^6.0.3 || ^7.0.0", "@deno/kv": ">=0.12.0", "@netlify/blobs": "^6.5.0 || ^7.0.0 || ^8.1.0 || ^9.0.0 || ^10.0.0", "@planetscale/database": "^1.19.0", "@upstash/redis": "^1.35.6", "@vercel/blob": ">=0.27.3", "@vercel/functions": "^2.2.12 || ^3.0.0", "@vercel/kv": "^1.0.1", "aws4fetch": "^1.0.20", "chokidar": "^4 || ^5", "db0": ">=0.3.4", "idb-keyval": "^6.2.2", "ioredis": "^5.8.2", "lru-cache": "^11.2.2", "mongodb": "^6 || ^7", "ofetch": "*", "uploadthing": "^7.7.4" }, "optionalPeers": ["@azure/app-configuration", "@azure/cosmos", "@azure/data-tables", "@azure/identity", "@azure/keyvault-secrets", "@azure/storage-blob", "@capacitor/preferences", "@deno/kv", "@netlify/blobs", "@planetscale/database", "@upstash/redis", "@vercel/blob", "@vercel/functions", "@vercel/kv", "aws4fetch", "chokidar", "db0", "idb-keyval", "ioredis", "lru-cache", "mongodb", "ofetch", "uploadthing"] }, "sha512-Sj8btci21Twnd6M+N+MHhjg3fVn6lAPElPmvFTe0Y/wR0WImErUdA1PzlAaUavHylJ7uDiFwlZDQKm0elG4b7g=="],
"update-browserslist-db": ["update-browserslist-db@1.2.3", "", { "dependencies": { "escalade": "^3.2.0", "picocolors": "^1.1.1" }, "peerDependencies": { "browserslist": ">= 4.21.0" }, "bin": { "update-browserslist-db": "cli.js" } }, "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w=="],
@@ -1307,11 +1334,11 @@
"vite": ["vite@7.3.1", "", { "dependencies": { "esbuild": "^0.27.0", "fdir": "^6.5.0", "picomatch": "^4.0.3", "postcss": "^8.5.6", "rollup": "^4.43.0", "tinyglobby": "^0.2.15" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", "jiti": ">=1.21.0", "less": "^4.0.0", "lightningcss": "^1.21.0", "sass": "^1.70.0", "sass-embedded": "^1.70.0", "stylus": ">=0.54.8", "sugarss": "^5.0.0", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "jiti", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA=="],
"vite-tsconfig-paths": ["vite-tsconfig-paths@6.0.4", "", { "dependencies": { "debug": "^4.1.1", "globrex": "^0.1.2", "tsconfck": "^3.0.3", "vite": "*" } }, "sha512-iIsEJ+ek5KqRTK17pmxtgIxXtqr3qDdE6OxrP9mVeGhVDNXRJTKN/l9oMbujTQNzMLe6XZ8qmpztfbkPu2TiFQ=="],
"vite-tsconfig-paths": ["vite-tsconfig-paths@6.0.5", "", { "dependencies": { "debug": "^4.1.1", "globrex": "^0.1.2", "tsconfck": "^3.0.3" }, "peerDependencies": { "vite": "*" } }, "sha512-f/WvY6ekHykUF1rWJUAbCU7iS/5QYDIugwpqJA+ttwKbxSbzNlqlE8vZSrsnxNQciUW+z6lvhlXMaEyZn9MSig=="],
"vitefu": ["vitefu@1.1.1", "", { "peerDependencies": { "vite": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0-beta.0" }, "optionalPeers": ["vite"] }, "sha512-B/Fegf3i8zh0yFbpzZ21amWzHmuNlLlmJT6n7bu5e+pCHUKQIfXSYokrqOBGEMMe9UG2sostKQF9mml/vYaWJQ=="],
"vitest": ["vitest@4.0.17", "", { "dependencies": { "@vitest/expect": "4.0.17", "@vitest/mocker": "4.0.17", "@vitest/pretty-format": "4.0.17", "@vitest/runner": "4.0.17", "@vitest/snapshot": "4.0.17", "@vitest/spy": "4.0.17", "@vitest/utils": "4.0.17", "es-module-lexer": "^1.7.0", "expect-type": "^1.2.2", "magic-string": "^0.30.21", "obug": "^2.1.1", "pathe": "^2.0.3", "picomatch": "^4.0.3", "std-env": "^3.10.0", "tinybench": "^2.9.0", "tinyexec": "^1.0.2", "tinyglobby": "^0.2.15", "tinyrainbow": "^3.0.3", "vite": "^6.0.0 || ^7.0.0", "why-is-node-running": "^2.3.0" }, "peerDependencies": { "@edge-runtime/vm": "*", "@opentelemetry/api": "^1.9.0", "@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0", "@vitest/browser-playwright": "4.0.17", "@vitest/browser-preview": "4.0.17", "@vitest/browser-webdriverio": "4.0.17", "@vitest/ui": "4.0.17", "happy-dom": "*", "jsdom": "*" }, "optionalPeers": ["@edge-runtime/vm", "@opentelemetry/api", "@types/node", "@vitest/browser-playwright", "@vitest/browser-preview", "@vitest/browser-webdriverio", "@vitest/ui", "happy-dom", "jsdom"], "bin": { "vitest": "vitest.mjs" } }, "sha512-FQMeF0DJdWY0iOnbv466n/0BudNdKj1l5jYgl5JVTwjSsZSlqyXFt/9+1sEyhR6CLowbZpV7O1sCHrzBhucKKg=="],
"vitest": ["vitest@4.0.18", "", { "dependencies": { "@vitest/expect": "4.0.18", "@vitest/mocker": "4.0.18", "@vitest/pretty-format": "4.0.18", "@vitest/runner": "4.0.18", "@vitest/snapshot": "4.0.18", "@vitest/spy": "4.0.18", "@vitest/utils": "4.0.18", "es-module-lexer": "^1.7.0", "expect-type": "^1.2.2", "magic-string": "^0.30.21", "obug": "^2.1.1", "pathe": "^2.0.3", "picomatch": "^4.0.3", "std-env": "^3.10.0", "tinybench": "^2.9.0", "tinyexec": "^1.0.2", "tinyglobby": "^0.2.15", "tinyrainbow": "^3.0.3", "vite": "^6.0.0 || ^7.0.0", "why-is-node-running": "^2.3.0" }, "peerDependencies": { "@edge-runtime/vm": "*", "@opentelemetry/api": "^1.9.0", "@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0", "@vitest/browser-playwright": "4.0.18", "@vitest/browser-preview": "4.0.18", "@vitest/browser-webdriverio": "4.0.18", "@vitest/ui": "4.0.18", "happy-dom": "*", "jsdom": "*" }, "optionalPeers": ["@edge-runtime/vm", "@opentelemetry/api", "@types/node", "@vitest/browser-playwright", "@vitest/browser-preview", "@vitest/browser-webdriverio", "@vitest/ui", "happy-dom", "jsdom"], "bin": { "vitest": "vitest.mjs" } }, "sha512-hOQuK7h0FGKgBAas7v0mSAsnvrIgAvWmRFjmzpJ7SwFHH3g1k2u37JtYwOwmEKhK6ZO3v9ggDBBm0La1LCK4uQ=="],
"w3c-xmlserializer": ["w3c-xmlserializer@5.0.0", "", { "dependencies": { "xml-name-validator": "^5.0.0" } }, "sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA=="],
@@ -1329,7 +1356,7 @@
"why-is-node-running": ["why-is-node-running@2.3.0", "", { "dependencies": { "siginfo": "^2.0.0", "stackback": "0.0.2" }, "bin": { "why-is-node-running": "cli.js" } }, "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w=="],
"ws": ["ws@8.18.3", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg=="],
"ws": ["ws@8.19.0", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg=="],
"xml-name-validator": ["xml-name-validator@5.0.0", "", {}, "sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg=="],
@@ -1353,9 +1380,9 @@
"@babel/helper-compilation-targets/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="],
"@tailwindcss/oxide-wasm32-wasi/@emnapi/core": ["@emnapi/core@1.8.0", "", { "dependencies": { "@emnapi/wasi-threads": "1.1.0", "tslib": "^2.4.0" }, "bundled": true }, "sha512-ryJnSmj4UhrGLZZPJ6PKVb4wNPAIkW6iyLy+0TRwazd3L1u0wzMe8RfqevAh2HbcSkoeLiSYnOVDOys4JSGYyg=="],
"@tailwindcss/oxide-wasm32-wasi/@emnapi/core": ["@emnapi/core@1.8.1", "", { "dependencies": { "@emnapi/wasi-threads": "1.1.0", "tslib": "^2.4.0" }, "bundled": true }, "sha512-AvT9QFpxK0Zd8J0jopedNm+w/2fIzvtPKPjqyw9jwvBaReTTqPBk9Hixaz7KbjimP+QNz605/XnjFcDAL2pqBg=="],
"@tailwindcss/oxide-wasm32-wasi/@emnapi/runtime": ["@emnapi/runtime@1.8.0", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-Z82FDl1ByxqPEPrAYYeTQVlx2FSHPe1qwX465c+96IRS3fTdSYRoJcRxg3g2fEG5I69z1dSEWQlNRRr0/677mg=="],
"@tailwindcss/oxide-wasm32-wasi/@emnapi/runtime": ["@emnapi/runtime@1.8.1", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-mehfKSMWjjNol8659Z8KxEMrdSJDDot5SXMq00dM8BN4o+CLNXQ0xH2V7EchNHV4RmbZLmmPdEaXZc5H2FXmDg=="],
"@tailwindcss/oxide-wasm32-wasi/@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.1.0", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ=="],
@@ -1365,6 +1392,8 @@
"@tailwindcss/oxide-wasm32-wasi/tslib": ["tslib@2.8.1", "", { "bundled": true }, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="],
"@tanstack/start-plugin-core/@babel/code-frame": ["@babel/code-frame@7.27.1", "", { "dependencies": { "@babel/helper-validator-identifier": "^7.27.1", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" } }, "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg=="],
"@tanstack/start-plugin-core/@rolldown/pluginutils": ["@rolldown/pluginutils@1.0.0-beta.40", "", {}, "sha512-s3GeJKSQOwBlzdUrj4ISjJj5SfSh+aqn0wjOar4Bx95iV1ETI7F6S/5hLcfAxZ9kXDcyrAkxPlqmd1ZITttf+w=="],
"anymatch/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="],
@@ -1375,11 +1404,13 @@
"convex/esbuild": ["esbuild@0.27.0", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.27.0", "@esbuild/android-arm": "0.27.0", "@esbuild/android-arm64": "0.27.0", "@esbuild/android-x64": "0.27.0", "@esbuild/darwin-arm64": "0.27.0", "@esbuild/darwin-x64": "0.27.0", "@esbuild/freebsd-arm64": "0.27.0", "@esbuild/freebsd-x64": "0.27.0", "@esbuild/linux-arm": "0.27.0", "@esbuild/linux-arm64": "0.27.0", "@esbuild/linux-ia32": "0.27.0", "@esbuild/linux-loong64": "0.27.0", "@esbuild/linux-mips64el": "0.27.0", "@esbuild/linux-ppc64": "0.27.0", "@esbuild/linux-riscv64": "0.27.0", "@esbuild/linux-s390x": "0.27.0", "@esbuild/linux-x64": "0.27.0", "@esbuild/netbsd-arm64": "0.27.0", "@esbuild/netbsd-x64": "0.27.0", "@esbuild/openbsd-arm64": "0.27.0", "@esbuild/openbsd-x64": "0.27.0", "@esbuild/openharmony-arm64": "0.27.0", "@esbuild/sunos-x64": "0.27.0", "@esbuild/win32-arm64": "0.27.0", "@esbuild/win32-ia32": "0.27.0", "@esbuild/win32-x64": "0.27.0" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-jd0f4NHbD6cALCyGElNpGAOtWxSq46l9X/sWB0Nzd5er4Kz2YTm+Vl0qKFT9KUJvD8+fiO8AvoHhFvEatfVixA=="],
"data-urls/whatwg-mimetype": ["whatwg-mimetype@5.0.0", "", {}, "sha512-sXcNcHOC51uPGF0P/D4NVtrkjSU2fNsm9iog4ZvZJsL3rjoDAzXZhkm2MWt1y+PUdggKAYVoMAIYcs78wJ51Cw=="],
"dom-serializer/entities": ["entities@4.5.0", "", {}, "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw=="],
"nitro/h3": ["h3@2.0.1-rc.5", "", { "dependencies": { "rou3": "^0.7.9", "srvx": "^0.9.1" }, "peerDependencies": { "crossws": "^0.4.1" }, "optionalPeers": ["crossws"] }, "sha512-qkohAzCab0nLzXNm78tBjZDvtKMTmtygS8BJLT3VPczAQofdqlFXDPkXdLMJN4r05+xqneG8snZJ0HgkERCZTg=="],
"htmlparser2/entities": ["entities@7.0.1", "", {}, "sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA=="],
"nitro/srvx": ["srvx@0.9.8", "", { "bin": { "srvx": "bin/srvx.mjs" } }, "sha512-RZaxTKJEE/14HYn8COLuUOJAt0U55N9l1Xf6jj+T0GoA01EUH1Xz5JtSUOI+EHn+AEgPCVn7gk6jHJffrr06fQ=="],
"nitro/h3": ["h3@2.0.1-rc.11", "", { "dependencies": { "rou3": "^0.7.12", "srvx": "^0.10.1" }, "peerDependencies": { "crossws": "^0.4.1" }, "optionalPeers": ["crossws"] }, "sha512-2myzjCqy32c1As9TjZW9fNZXtLqNedjFSrdFy2AjFBQQ3LzrnGoDdFDYfC0tV2e4vcyfJ2Sfo/F6NQhO2Ly/Mw=="],
"parse-entities/@types/unist": ["@types/unist@2.0.11", "", {}, "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA=="],
@@ -1393,10 +1424,6 @@
"recast/source-map": ["source-map@0.6.1", "", {}, "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="],
"solid-js/seroval": ["seroval@1.3.2", "", {}, "sha512-RbcPH1n5cfwKrru7v7+zrZvjLurgHhGyso3HTyGtRivGWgYjbOmGuivCQaORNELjNONoK35nj28EoWul9sb1zQ=="],
"solid-js/seroval-plugins": ["seroval-plugins@1.3.3", "", { "peerDependencies": { "seroval": "^1.0" } }, "sha512-16OL3NnUBw8JG1jBLUoZJsLnQq0n5Ua6aHalhJK4fMQkz1lqR7Osz1sA30trBtd9VUDc2NgkuRCn8+/pBwqZ+w=="],
"strip-ansi/ansi-regex": ["ansi-regex@6.2.2", "", {}, "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg=="],
"convex/esbuild/@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.27.0", "", { "os": "aix", "cpu": "ppc64" }, "sha512-KuZrd2hRjz01y5JK9mEBSD3Vj3mbCvemhT466rSuJYeE/hjuBrHfjjcjMdTm/sz7au+++sdbJZJmuBwQLuw68A=="],
+3 -3
View File
@@ -3,9 +3,9 @@ import { existsSync } from 'node:fs'
import { stat } from 'node:fs/promises'
import { fileURLToPath } from 'node:url'
const distCliUrl = new URL('./packages/molthub/dist/cli.js', import.meta.url)
const distCliUrl = new URL('./packages/clawdhub/dist/cli.js', import.meta.url)
const distCliPath = fileURLToPath(distCliUrl)
const srcRootPath = fileURLToPath(new URL('./packages/molthub/src/', import.meta.url))
const srcRootPath = fileURLToPath(new URL('./packages/clawdhub/src/', import.meta.url))
const shouldBuild = await (async () => {
if (!existsSync(distCliPath)) return true
@@ -19,7 +19,7 @@ const shouldBuild = await (async () => {
})()
if (shouldBuild) {
const proc = Bun.spawn(['bunx', 'tsc', '-p', 'packages/molthub/tsconfig.json'], {
const proc = Bun.spawn(['bunx', 'tsc', '-p', 'packages/clawdhub/tsconfig.json'], {
stdin: 'inherit',
stdout: 'inherit',
stderr: 'inherit',
Executable
+46
View File
@@ -0,0 +1,46 @@
#!/usr/bin/env bun
import { existsSync } from 'node:fs'
import { stat } from 'node:fs/promises'
import { fileURLToPath } from 'node:url'
const distCliUrl = new URL('./packages/clawdhub/dist/cli.js', import.meta.url)
const distCliPath = fileURLToPath(distCliUrl)
const srcRootPath = fileURLToPath(new URL('./packages/clawdhub/src/', import.meta.url))
const shouldBuild = await (async () => {
if (!existsSync(distCliPath)) return true
try {
const dist = await stat(distCliPath)
const latestSrcMtime = await getLatestMtime(srcRootPath)
return latestSrcMtime > dist.mtimeMs
} catch {
return true
}
})()
if (shouldBuild) {
const proc = Bun.spawn(['bunx', 'tsc', '-p', 'packages/clawdhub/tsconfig.json'], {
stdin: 'inherit',
stdout: 'inherit',
stderr: 'inherit',
})
const code = await proc.exited
if (code !== 0) process.exit(code)
}
await import(distCliUrl.href)
async function getLatestMtime(root: string) {
let latest = 0
const glob = new Bun.Glob('**/*.ts')
for await (const rel of glob.scan({ cwd: root, onlyFiles: true })) {
const path = `${root}${root.endsWith('/') ? '' : '/'}${rel}`
try {
const entry = await stat(path)
latest = Math.max(latest, entry.mtimeMs)
} catch {
// ignore
}
}
return latest
}
+12 -12
View File
@@ -3,7 +3,7 @@ import { internal } from './_generated/api'
import type { ActionCtx } from './_generated/server'
import { internalAction, internalMutation } from './_generated/server'
import { EMBEDDING_DIMENSIONS } from './lib/embeddings'
import { parseFrontmatter, parseMoltbotMetadata } from './lib/skills'
import { parseClawdisMetadata, parseFrontmatter } from './lib/skills'
type SeedSkillSpec = {
slug: string
@@ -32,7 +32,7 @@ const SEED_SKILLS: SeedSkillSpec[] = [
summary: 'Check padel court availability and manage bookings via Playtomic.',
version: '0.1.0',
metadata: {
moltbot: {
clawdbot: {
nix: {
plugin: 'github:joshp123/padel-cli',
systems: ['aarch64-darwin', 'x86_64-linux'],
@@ -74,7 +74,7 @@ description: Check padel court availability and manage bookings via the padel CL
## CLI
\`\`\`bash
padel # On PATH (moltbot plugin bundle)
padel # On PATH (clawdbot plugin bundle)
\`\`\`
## Venues
@@ -110,7 +110,7 @@ Only the authorized booker can confirm bookings. If the requester is not authori
summary: 'Operate GoHome via gRPC discovery, metrics, and Grafana dashboards.',
version: '0.1.0',
metadata: {
moltbot: {
clawdbot: {
nix: {
plugin: 'github:joshp123/gohome',
systems: ['x86_64-linux', 'aarch64-linux'],
@@ -141,7 +141,7 @@ Flags:
},
rawSkillMd: `---
name: gohome
description: Use when Moltbot needs to test or operate GoHome via gRPC discovery, metrics, and Grafana.
description: Use when Clawdbot needs to test or operate GoHome via gRPC discovery, metrics, and Grafana.
---
# GoHome Skill
@@ -183,7 +183,7 @@ Only call write RPCs after explicit user approval.
summary: 'Teach Mandarin with the xuezh engine for review, speaking, and audits.',
version: '0.1.0',
metadata: {
moltbot: {
clawdbot: {
nix: {
plugin: 'github:joshp123/xuezh',
systems: ['aarch64-darwin', 'x86_64-linux'],
@@ -258,7 +258,7 @@ async function seedNixSkillsHandler(
for (const spec of SEED_SKILLS) {
const skillMd = injectMetadata(spec.rawSkillMd, spec.metadata)
const frontmatter = parseFrontmatter(skillMd)
const moltbot = parseMoltbotMetadata(frontmatter)
const clawdis = parseClawdisMetadata(frontmatter)
const storageId = await ctx.storage.store(new Blob([skillMd], { type: 'text/markdown' }))
const result: SeedMutationResult = await ctx.runMutation(internal.devSeed.seedSkillMutation, {
@@ -266,7 +266,7 @@ async function seedNixSkillsHandler(
storageId,
metadata: spec.metadata,
frontmatter,
moltbot,
clawdis,
skillMd,
slug: spec.slug,
displayName: spec.displayName,
@@ -296,7 +296,7 @@ async function seedPadelSkillHandler(
const skillMd = injectMetadata(spec.rawSkillMd, spec.metadata)
const frontmatter = parseFrontmatter(skillMd)
const moltbot = parseMoltbotMetadata(frontmatter)
const clawdis = parseClawdisMetadata(frontmatter)
const storageId = await ctx.storage.store(new Blob([skillMd], { type: 'text/markdown' }))
return (await ctx.runMutation(internal.devSeed.seedSkillMutation, {
@@ -304,7 +304,7 @@ async function seedPadelSkillHandler(
storageId,
metadata: spec.metadata,
frontmatter,
moltbot,
clawdis,
skillMd,
slug: spec.slug,
displayName: spec.displayName,
@@ -326,7 +326,7 @@ export const seedSkillMutation = internalMutation({
storageId: v.id('_storage'),
metadata: v.any(),
frontmatter: v.any(),
moltbot: v.any(),
clawdis: v.any(),
skillMd: v.string(),
slug: v.string(),
displayName: v.string(),
@@ -418,7 +418,7 @@ export const seedSkillMutation = internalMutation({
parsed: {
frontmatter: args.frontmatter,
metadata: args.metadata,
moltbot: args.moltbot,
clawdis: args.clawdis,
},
createdBy: userId,
createdAt: now,
+4 -4
View File
@@ -11,7 +11,7 @@ import { internal } from './_generated/api'
import type { Id } from './_generated/dataModel'
import type { ActionCtx } from './_generated/server'
import { internalAction, internalMutation } from './_generated/server'
import { parseFrontmatter, parseMoltbotMetadata } from './lib/skills'
import { parseClawdisMetadata, parseFrontmatter } from './lib/skills'
type SeedSkillSpec = {
slug: string
@@ -66,7 +66,7 @@ Use this skill to ${summary.toLowerCase()}.
summary,
version: '0.1.0',
metadata: {
moltbot: {
clawdbot: {
nix: {
plugin: `github:example/${slug}`,
systems: ['aarch64-darwin', 'x86_64-linux'],
@@ -505,7 +505,7 @@ export const seedExtraSkillsInternal = internalAction({
for (const spec of EXTRA_SEED_SKILLS) {
const skillMd = injectMetadata(spec.rawSkillMd, spec.metadata)
const frontmatter = parseFrontmatter(skillMd)
const moltbot = parseMoltbotMetadata(frontmatter)
const clawdis = parseClawdisMetadata(frontmatter)
const storageId = await ctx.storage.store(new Blob([skillMd], { type: 'text/markdown' }))
const result = (await ctx.runMutation(internal.devSeed.seedSkillMutation, {
@@ -513,7 +513,7 @@ export const seedExtraSkillsInternal = internalAction({
storageId,
metadata: spec.metadata,
frontmatter,
moltbot,
clawdis,
skillMd,
slug: spec.slug,
displayName: spec.displayName,
+1 -1
View File
@@ -1,5 +1,5 @@
import { ApiRoutes, LegacyApiRoutes } from 'clawhub-schema'
import { httpRouter } from 'convex/server'
import { ApiRoutes, LegacyApiRoutes } from 'molthub-schema'
import { auth } from './auth'
import { downloadZip } from './downloads'
import {
+1 -1
View File
@@ -5,7 +5,7 @@ import {
CliSkillDeleteRequestSchema,
CliTelemetrySyncRequestSchema,
parseArk,
} from 'molthub-schema'
} from 'clawhub-schema'
import { api, internal } from './_generated/api'
import type { Id } from './_generated/dataModel'
import type { ActionCtx } from './_generated/server'
+7 -7
View File
@@ -1,4 +1,4 @@
import { CliPublishRequestSchema, parseArk } from 'molthub-schema'
import { CliPublishRequestSchema, parseArk } from 'clawhub-schema'
import { api, internal } from './_generated/api'
import type { Doc, Id } from './_generated/dataModel'
import type { ActionCtx } from './_generated/server'
@@ -376,8 +376,7 @@ async function skillsGetRouterV1Handler(ctx: ActionCtx, request: Request) {
const textContent = await blob.text()
const isSvg =
file.contentType?.toLowerCase().includes('svg') ||
file.path.toLowerCase().endsWith('.svg')
file.contentType?.toLowerCase().includes('svg') || file.path.toLowerCase().endsWith('.svg')
const headers = mergeHeaders(rate.headers, {
'Content-Type': file.contentType
@@ -392,7 +391,8 @@ async function skillsGetRouterV1Handler(ctx: ActionCtx, request: Request) {
// For any text response that a browser might try to render, lock it down.
// In particular, this prevents SVG <foreignObject> script execution from
// reading localStorage tokens on this origin.
'Content-Security-Policy': "default-src 'none'; base-uri 'none'; form-action 'none'; frame-ancestors 'none'",
'Content-Security-Policy':
"default-src 'none'; base-uri 'none'; form-action 'none'; frame-ancestors 'none'",
...(isSvg ? { 'Content-Disposition': 'attachment' } : {}),
})
return new Response(textContent, { status: 200, headers })
@@ -996,8 +996,7 @@ async function soulsGetRouterV1Handler(ctx: ActionCtx, request: Request) {
void ctx.runMutation(api.soulDownloads.increment, { soulId: soulResult.soul._id })
const isSvg =
file.contentType?.toLowerCase().includes('svg') ||
file.path.toLowerCase().endsWith('.svg')
file.contentType?.toLowerCase().includes('svg') || file.path.toLowerCase().endsWith('.svg')
const headers = mergeHeaders(rate.headers, {
'Content-Type': file.contentType
@@ -1012,7 +1011,8 @@ async function soulsGetRouterV1Handler(ctx: ActionCtx, request: Request) {
// For any text response that a browser might try to render, lock it down.
// In particular, this prevents SVG <foreignObject> script execution from
// reading localStorage tokens on this origin.
'Content-Security-Policy': "default-src 'none'; base-uri 'none'; form-action 'none'; frame-ancestors 'none'",
'Content-Security-Policy':
"default-src 'none'; base-uri 'none'; form-action 'none'; frame-ancestors 'none'",
...(isSvg ? { 'Content-Disposition': 'attachment' } : {}),
})
return new Response(textContent, { status: 200, headers })
+2 -2
View File
@@ -5,10 +5,10 @@ import type { Id } from '../_generated/dataModel'
import type { ActionCtx } from '../_generated/server'
const GITHUB_API = 'https://api.github.com'
const DEFAULT_REPO = 'moltbot/skills'
const DEFAULT_REPO = 'clawdbot/skills'
const DEFAULT_ROOT = 'skills'
const META_FILENAME = '_meta.json'
const USER_AGENT = 'molthub/skills-backup'
const USER_AGENT = 'clawhub/skills-backup'
type BackupFile = {
path: string
+3 -3
View File
@@ -1,5 +1,5 @@
import { TEXT_FILE_EXTENSION_SET } from 'clawhub-schema'
import { zipSync } from 'fflate'
import { TEXT_FILE_EXTENSION_SET } from 'molthub-schema'
import semver from 'semver'
import { parseFrontmatter } from './skills'
@@ -118,7 +118,7 @@ async function resolveRefCommit(parsed: GitHubImportUrl, ref: string, fetcher: t
const response = await fetcher(apiUrl, {
headers: {
Accept: 'application/vnd.github+json',
'User-Agent': 'molthub/github-import',
'User-Agent': 'clawhub/github-import',
},
})
if (!response.ok) throw new Error('GitHub ref not found')
@@ -156,7 +156,7 @@ export async function fetchGitHubZipBytes(
const maxZipBytes = limits?.maxZipBytes ?? 25 * 1024 * 1024
const url = `https://${CODELOAD_HOST}/${resolved.owner}/${resolved.repo}/zip/${resolved.commit}`
const response = await fetcher(url, {
headers: { 'User-Agent': 'molthub/github-import' },
headers: { 'User-Agent': 'clawhub/github-import' },
})
if (!response.ok) throw new Error('GitHub archive download failed')
+2 -2
View File
@@ -5,10 +5,10 @@ import type { Id } from '../_generated/dataModel'
import type { ActionCtx } from '../_generated/server'
const GITHUB_API = 'https://api.github.com'
const DEFAULT_REPO = 'moltbot/souls'
const DEFAULT_REPO = 'clawdbot/souls'
const DEFAULT_ROOT = 'souls'
const META_FILENAME = '_meta.json'
const USER_AGENT = 'molthub/souls-backup'
const USER_AGENT = 'clawhub/souls-backup'
type BackupFile = {
path: string
+4 -1
View File
@@ -3,7 +3,10 @@ import type { Doc } from '../_generated/dataModel'
const FLAG_RULES: Array<{ flag: string; pattern: RegExp }> = [
// Known-bad / known-suspicious identifiers.
// NOTE: keep these narrowly scoped; use staff review to confirm removals.
{ flag: 'blocked.malware', pattern: /(keepcold131\/ClawdAuthenticatorTool|ClawdAuthenticatorTool)/i },
{
flag: 'blocked.malware',
pattern: /(keepcold131\/ClawdAuthenticatorTool|ClawdAuthenticatorTool)/i,
},
{ flag: 'suspicious.keyword', pattern: /(malware|stealer|phish|phishing|keylogger)/i },
{ flag: 'suspicious.secrets', pattern: /(api[-_ ]?key|token|password|private key|secret)/i },
-2
View File
@@ -75,8 +75,6 @@ export function toPublicSkill(skill: Doc<'skills'> | null | undefined): PublicSk
export function toPublicSoul(soul: Doc<'souls'> | null | undefined): PublicSoul | null {
if (!soul || soul.softDeletedAt) return null
if (soul.moderationStatus && soul.moderationStatus !== 'active') return null
if (soul.moderationFlags?.includes('blocked.malware')) return null
return {
_id: soul._id,
_creationTime: soul._creationTime,
+4 -4
View File
@@ -2,14 +2,14 @@ import {
getFrontmatterMetadata,
getFrontmatterValue,
type ParsedSkillFrontmatter,
parseClawdisMetadata,
parseFrontmatter,
parseMoltbotMetadata,
} from './skills'
export type ParsedSkillData = {
frontmatter: ParsedSkillFrontmatter
metadata?: unknown
moltbot?: unknown
clawdis?: unknown
}
export type SkillSummaryBackfillPatch = {
@@ -25,8 +25,8 @@ export function buildSkillSummaryBackfillPatch(args: {
const frontmatter = parseFrontmatter(args.readmeText)
const summary = getFrontmatterValue(frontmatter, 'description') ?? undefined
const metadata = getFrontmatterMetadata(frontmatter)
const moltbot = parseMoltbotMetadata(frontmatter)
const parsed: ParsedSkillData = { frontmatter, metadata, moltbot }
const clawdis = parseClawdisMetadata(frontmatter)
const parsed: ParsedSkillData = { frontmatter, metadata, clawdis }
const patch: SkillSummaryBackfillPatch = {}
if (summary && summary !== args.currentSummary) {
+2 -2
View File
@@ -4,7 +4,7 @@ import { __test } from './skillPublish'
describe('skillPublish', () => {
it('merges github source into metadata', () => {
const merged = __test.mergeSourceIntoMetadata(
{ moltbot: { emoji: 'x' } },
{ clawdis: { emoji: 'x' } },
{
kind: 'github',
url: 'https://github.com/a/b',
@@ -15,7 +15,7 @@ describe('skillPublish', () => {
importedAt: 123,
},
)
expect((merged as Record<string, unknown>).moltbot).toEqual({ emoji: 'x' })
expect((merged as Record<string, unknown>).clawdis).toEqual({ emoji: 'x' })
const source = (merged as Record<string, unknown>).source
expect(source).toEqual(
expect.objectContaining({
+3 -3
View File
@@ -12,8 +12,8 @@ import {
getFrontmatterMetadata,
hashSkillFiles,
isTextFile,
parseClawdisMetadata,
parseFrontmatter,
parseMoltbotMetadata,
sanitizePath,
} from './skills'
import type { WebhookSkillPayload } from './webhooks'
@@ -97,7 +97,7 @@ export async function publishVersionForUser(
const readmeText = await fetchText(ctx, readmeFile.storageId)
const frontmatter = parseFrontmatter(readmeText)
const moltbot = parseMoltbotMetadata(frontmatter)
const clawdis = parseClawdisMetadata(frontmatter)
const metadata = mergeSourceIntoMetadata(getFrontmatterMetadata(frontmatter), args.source)
const otherFiles = [] as Array<{ path: string; content: string }>
@@ -161,7 +161,7 @@ export async function publishVersionForUser(
parsed: {
frontmatter,
metadata,
moltbot,
clawdis,
},
embedding,
})) as PublishResult
+43 -43
View File
@@ -5,8 +5,8 @@ import {
getFrontmatterValue,
hashSkillFiles,
isTextFile,
parseClawdisMetadata,
parseFrontmatter,
parseMoltbotMetadata,
sanitizePath,
} from './skills'
@@ -51,89 +51,89 @@ describe('skills utils', () => {
expect(getFrontmatterValue(frontmatter, 'count')).toBeUndefined()
})
it('parses moltbot metadata', () => {
it('parses clawdis metadata', () => {
const frontmatter = parseFrontmatter(
`---\nmetadata: {"moltbot":{"requires":{"bins":["rg"]},"emoji":"🦞"}}\n---\nBody`,
`---\nmetadata: {"clawdis":{"requires":{"bins":["rg"]},"emoji":"🦞"}}\n---\nBody`,
)
const moltbot = parseMoltbotMetadata(frontmatter)
expect(moltbot?.emoji).toBe('🦞')
expect(moltbot?.requires?.bins).toEqual(['rg'])
const clawdis = parseClawdisMetadata(frontmatter)
expect(clawdis?.emoji).toBe('🦞')
expect(clawdis?.requires?.bins).toEqual(['rg'])
})
it('ignores invalid moltbot metadata', () => {
it('ignores invalid clawdis metadata', () => {
const frontmatter = parseFrontmatter(`---\nmetadata: not-json\n---\nBody`)
expect(parseMoltbotMetadata(frontmatter)).toBeUndefined()
expect(parseClawdisMetadata(frontmatter)).toBeUndefined()
})
it('accepts metadata as YAML object (no JSON string)', () => {
const frontmatter = parseFrontmatter(
`---\nmetadata:\n moltbot:\n emoji: "🦞"\n requires:\n bins:\n - rg\n---\nBody`,
`---\nmetadata:\n clawdis:\n emoji: "🦞"\n requires:\n bins:\n - rg\n---\nBody`,
)
expect(getFrontmatterMetadata(frontmatter)).toEqual({
moltbot: { emoji: '🦞', requires: { bins: ['rg'] } },
clawdis: { emoji: '🦞', requires: { bins: ['rg'] } },
})
const moltbot = parseMoltbotMetadata(frontmatter)
expect(moltbot?.emoji).toBe('🦞')
expect(moltbot?.requires?.bins).toEqual(['rg'])
const clawdis = parseClawdisMetadata(frontmatter)
expect(clawdis?.emoji).toBe('🦞')
expect(clawdis?.requires?.bins).toEqual(['rg'])
})
it('accepts moltbot as top-level YAML key', () => {
it('accepts clawdis as top-level YAML key', () => {
const frontmatter = parseFrontmatter(
`---\nmoltbot:\n emoji: "🦞"\n requires:\n anyBins: [rg, fd]\n---\nBody`,
`---\nclawdis:\n emoji: "🦞"\n requires:\n anyBins: [rg, fd]\n---\nBody`,
)
const moltbot = parseMoltbotMetadata(frontmatter)
expect(moltbot?.emoji).toBe('🦞')
expect(moltbot?.requires?.anyBins).toEqual(['rg', 'fd'])
const clawdis = parseClawdisMetadata(frontmatter)
expect(clawdis?.emoji).toBe('🦞')
expect(clawdis?.requires?.anyBins).toEqual(['rg', 'fd'])
})
it('accepts legacy metadata JSON string (quoted)', () => {
const frontmatter = parseFrontmatter(
`---\nmetadata: '{"moltbot":{"emoji":"🦞","requires":{"bins":["rg"]}}}'\n---\nBody`,
`---\nmetadata: '{"clawdis":{"emoji":"🦞","requires":{"bins":["rg"]}}}'\n---\nBody`,
)
const metadata = getFrontmatterMetadata(frontmatter)
expect(metadata).toEqual({ moltbot: { emoji: '🦞', requires: { bins: ['rg'] } } })
const moltbot = parseMoltbotMetadata(frontmatter)
expect(moltbot?.emoji).toBe('🦞')
expect(moltbot?.requires?.bins).toEqual(['rg'])
expect(metadata).toEqual({ clawdis: { emoji: '🦞', requires: { bins: ['rg'] } } })
const clawdis = parseClawdisMetadata(frontmatter)
expect(clawdis?.emoji).toBe('🦞')
expect(clawdis?.requires?.bins).toEqual(['rg'])
})
it('parses moltbot install specs and os', () => {
it('parses clawdis install specs and os', () => {
const frontmatter = parseFrontmatter(
`---\nmetadata: {"moltbot":{"install":[{"kind":"brew","formula":"rg"},{"kind":"nope"},{"kind":"node","package":"x"}],"os":"macos,linux","requires":{"anyBins":["rg","fd"]}}}\n---\nBody`,
`---\nmetadata: {"clawdis":{"install":[{"kind":"brew","formula":"rg"},{"kind":"nope"},{"kind":"node","package":"x"}],"os":"macos,linux","requires":{"anyBins":["rg","fd"]}}}\n---\nBody`,
)
const moltbot = parseMoltbotMetadata(frontmatter)
expect(moltbot?.install?.map((entry) => entry.kind)).toEqual(['brew', 'node'])
expect(moltbot?.os).toEqual(['macos', 'linux'])
expect(moltbot?.requires?.anyBins).toEqual(['rg', 'fd'])
const clawdis = parseClawdisMetadata(frontmatter)
expect(clawdis?.install?.map((entry) => entry.kind)).toEqual(['brew', 'node'])
expect(clawdis?.os).toEqual(['macos', 'linux'])
expect(clawdis?.requires?.anyBins).toEqual(['rg', 'fd'])
})
it('parses moltbot metadata with nix plugin pointer', () => {
it('parses clawdbot metadata with nix plugin pointer', () => {
const frontmatter = parseFrontmatter(
`---\nmetadata: {"moltbot":{"nix":{"plugin":"github:moltbot/nix-steipete-tools?dir=tools/peekaboo","systems":["aarch64-darwin"]}}}\n---\nBody`,
`---\nmetadata: {"clawdbot":{"nix":{"plugin":"github:clawdbot/nix-steipete-tools?dir=tools/peekaboo","systems":["aarch64-darwin"]}}}\n---\nBody`,
)
const moltbot = parseMoltbotMetadata(frontmatter)
expect(moltbot?.nix?.plugin).toBe('github:moltbot/nix-steipete-tools?dir=tools/peekaboo')
expect(moltbot?.nix?.systems).toEqual(['aarch64-darwin'])
const clawdis = parseClawdisMetadata(frontmatter)
expect(clawdis?.nix?.plugin).toBe('github:clawdbot/nix-steipete-tools?dir=tools/peekaboo')
expect(clawdis?.nix?.systems).toEqual(['aarch64-darwin'])
})
it('parses moltbot config requirements with example', () => {
it('parses clawdbot config requirements with example', () => {
const frontmatter = parseFrontmatter(
`---\nmetadata: {"moltbot":{"config":{"requiredEnv":["PADEL_AUTH_FILE"],"stateDirs":[".config/padel"],"example":"config = { env = { PADEL_AUTH_FILE = \\"/run/agenix/padel-auth\\"; }; };"}}}\n---\nBody`,
`---\nmetadata: {"clawdbot":{"config":{"requiredEnv":["PADEL_AUTH_FILE"],"stateDirs":[".config/padel"],"example":"config = { env = { PADEL_AUTH_FILE = \\"/run/agenix/padel-auth\\"; }; };"}}}\n---\nBody`,
)
const moltbot = parseMoltbotMetadata(frontmatter)
expect(moltbot?.config?.requiredEnv).toEqual(['PADEL_AUTH_FILE'])
expect(moltbot?.config?.stateDirs).toEqual(['.config/padel'])
expect(moltbot?.config?.example).toBe(
const clawdis = parseClawdisMetadata(frontmatter)
expect(clawdis?.config?.requiredEnv).toEqual(['PADEL_AUTH_FILE'])
expect(clawdis?.config?.stateDirs).toEqual(['.config/padel'])
expect(clawdis?.config?.example).toBe(
'config = { env = { PADEL_AUTH_FILE = "/run/agenix/padel-auth"; }; };',
)
})
it('parses cli help output', () => {
const frontmatter = parseFrontmatter(
`---\nmetadata: {"moltbot":{"cliHelp":"padel --help\\nUsage: padel [command]\\n"}}\n---\nBody`,
`---\nmetadata: {"clawdbot":{"cliHelp":"padel --help\\nUsage: padel [command]\\n"}}\n---\nBody`,
)
const moltbot = parseMoltbotMetadata(frontmatter)
expect(moltbot?.cliHelp).toBe('padel --help\nUsage: padel [command]')
const clawdis = parseClawdisMetadata(frontmatter)
expect(clawdis?.cliHelp).toBe('padel --help\nUsage: padel [command]')
})
it('sanitizes file paths', () => {
+32 -29
View File
@@ -1,17 +1,17 @@
import {
type ClawdbotConfigSpec,
type ClawdisSkillMetadata,
ClawdisSkillMetadataSchema,
isTextContentType,
type MoltbotConfigSpec,
type MoltbotSkillMetadata,
MoltbotSkillMetadataSchema,
type NixPluginSpec,
parseArk,
type SkillInstallSpec,
TEXT_FILE_EXTENSION_SET,
} from 'molthub-schema'
} from 'clawhub-schema'
import { parse as parseYaml } from 'yaml'
export type ParsedSkillFrontmatter = Record<string, unknown>
export type { MoltbotSkillMetadata, SkillInstallSpec }
export type { ClawdisSkillMetadata, SkillInstallSpec }
const FRONTMATTER_START = '---'
const DEFAULT_EMBEDDING_MAX_CHARS = 12_000
@@ -59,39 +59,42 @@ export function getFrontmatterMetadata(frontmatter: ParsedSkillFrontmatter) {
return undefined
}
export function parseMoltbotMetadata(frontmatter: ParsedSkillFrontmatter) {
export function parseClawdisMetadata(frontmatter: ParsedSkillFrontmatter) {
const metadata = getFrontmatterMetadata(frontmatter)
const metadataRecord =
metadata && typeof metadata === 'object' && !Array.isArray(metadata)
? (metadata as Record<string, unknown>)
: undefined
const moltbotMeta = metadataRecord?.moltbot
const clawdbotMeta = metadataRecord?.clawdbot
const clawdisMeta = metadataRecord?.clawdis
const metadataSource =
moltbotMeta && typeof moltbotMeta === 'object' && !Array.isArray(moltbotMeta)
? (moltbotMeta as Record<string, unknown>)
: undefined
const moltbotRaw = metadataSource ?? frontmatter.moltbot
if (!moltbotRaw || typeof moltbotRaw !== 'object' || Array.isArray(moltbotRaw)) return undefined
clawdbotMeta && typeof clawdbotMeta === 'object' && !Array.isArray(clawdbotMeta)
? (clawdbotMeta as Record<string, unknown>)
: clawdisMeta && typeof clawdisMeta === 'object' && !Array.isArray(clawdisMeta)
? (clawdisMeta as Record<string, unknown>)
: undefined
const clawdisRaw = metadataSource ?? frontmatter.clawdis
if (!clawdisRaw || typeof clawdisRaw !== 'object' || Array.isArray(clawdisRaw)) return undefined
try {
const moltbotObj = moltbotRaw as Record<string, unknown>
const clawdisObj = clawdisRaw as Record<string, unknown>
const requiresRaw =
typeof moltbotObj.requires === 'object' && moltbotObj.requires !== null
? (moltbotObj.requires as Record<string, unknown>)
typeof clawdisObj.requires === 'object' && clawdisObj.requires !== null
? (clawdisObj.requires as Record<string, unknown>)
: undefined
const installRaw = Array.isArray(moltbotObj.install) ? (moltbotObj.install as unknown[]) : []
const installRaw = Array.isArray(clawdisObj.install) ? (clawdisObj.install as unknown[]) : []
const install = installRaw
.map((entry) => parseInstallSpec(entry))
.filter((entry): entry is SkillInstallSpec => Boolean(entry))
const osRaw = normalizeStringList(moltbotObj.os)
const osRaw = normalizeStringList(clawdisObj.os)
const metadata: MoltbotSkillMetadata = {}
if (typeof moltbotObj.always === 'boolean') metadata.always = moltbotObj.always
if (typeof moltbotObj.emoji === 'string') metadata.emoji = moltbotObj.emoji
if (typeof moltbotObj.homepage === 'string') metadata.homepage = moltbotObj.homepage
if (typeof moltbotObj.skillKey === 'string') metadata.skillKey = moltbotObj.skillKey
if (typeof moltbotObj.primaryEnv === 'string') metadata.primaryEnv = moltbotObj.primaryEnv
if (typeof moltbotObj.cliHelp === 'string') metadata.cliHelp = moltbotObj.cliHelp
const metadata: ClawdisSkillMetadata = {}
if (typeof clawdisObj.always === 'boolean') metadata.always = clawdisObj.always
if (typeof clawdisObj.emoji === 'string') metadata.emoji = clawdisObj.emoji
if (typeof clawdisObj.homepage === 'string') metadata.homepage = clawdisObj.homepage
if (typeof clawdisObj.skillKey === 'string') metadata.skillKey = clawdisObj.skillKey
if (typeof clawdisObj.primaryEnv === 'string') metadata.primaryEnv = clawdisObj.primaryEnv
if (typeof clawdisObj.cliHelp === 'string') metadata.cliHelp = clawdisObj.cliHelp
if (osRaw.length > 0) metadata.os = osRaw
if (requiresRaw) {
@@ -109,12 +112,12 @@ export function parseMoltbotMetadata(frontmatter: ParsedSkillFrontmatter) {
}
if (install.length > 0) metadata.install = install
const nix = parseNixPluginSpec(moltbotObj.nix)
const nix = parseNixPluginSpec(clawdisObj.nix)
if (nix) metadata.nix = nix
const config = parseMoltbotConfigSpec(moltbotObj.config)
const config = parseClawdbotConfigSpec(clawdisObj.config)
if (config) metadata.config = config
return parseArk(MoltbotSkillMetadataSchema, metadata, 'Moltbot metadata')
return parseArk(ClawdisSkillMetadataSchema, metadata, 'Clawdis metadata')
} catch {
return undefined
}
@@ -247,13 +250,13 @@ function parseNixPluginSpec(input: unknown): NixPluginSpec | undefined {
return spec
}
function parseMoltbotConfigSpec(input: unknown): MoltbotConfigSpec | undefined {
function parseClawdbotConfigSpec(input: unknown): ClawdbotConfigSpec | undefined {
if (!input || typeof input !== 'object') return undefined
const raw = input as Record<string, unknown>
const requiredEnv = normalizeStringList(raw.requiredEnv)
const stateDirs = normalizeStringList(raw.stateDirs)
const example = typeof raw.example === 'string' ? raw.example.trim() : ''
const spec: MoltbotConfigSpec = {}
const spec: ClawdbotConfigSpec = {}
if (requiredEnv.length > 0) spec.requiredEnv = requiredEnv
if (stateDirs.length > 0) spec.stateDirs = stateDirs
if (example) spec.example = example
+6 -6
View File
@@ -20,7 +20,7 @@ describe('webhook config', () => {
delete process.env.SITE_URL
process.env.DISCORD_WEBHOOK_URL = 'https://example.com'
const config = getWebhookConfig()
expect(config.siteUrl).toBe('https://molthub.com')
expect(config.siteUrl).toBe('https://clawhub.ai')
})
})
@@ -36,7 +36,7 @@ describe('webhook filtering', () => {
const config = {
url: 'https://example.com',
highlightedOnly: true,
siteUrl: 'https://molthub.com',
siteUrl: 'https://clawhub.ai',
}
const allowed = shouldSendWebhook(
'skill.publish',
@@ -50,7 +50,7 @@ describe('webhook filtering', () => {
const config = {
url: 'https://example.com',
highlightedOnly: true,
siteUrl: 'https://molthub.com',
siteUrl: 'https://clawhub.ai',
}
const allowed = shouldSendWebhook(
'skill.highlighted',
@@ -65,9 +65,9 @@ describe('payload building', () => {
it('builds canonical url with owner', () => {
const url = buildSkillUrl(
{ slug: 'beeper', displayName: 'Beeper', ownerHandle: 'KrauseFx' },
'https://molthub.com',
'https://clawhub.ai',
)
expect(url).toBe('https://molthub.com/KrauseFx/beeper')
expect(url).toBe('https://clawhub.ai/KrauseFx/beeper')
})
it('builds a publish embed', () => {
@@ -81,7 +81,7 @@ describe('payload building', () => {
ownerHandle: 'steipete',
tags: ['latest', 'discord'],
},
{ url: 'https://example.com', highlightedOnly: false, siteUrl: 'https://molthub.com' },
{ url: 'https://example.com', highlightedOnly: false, siteUrl: 'https://clawhub.ai' },
)
const embed = payload.embeds[0]
expect(embed.title).toBe('Demo Skill')
+5 -5
View File
@@ -16,7 +16,7 @@ export type WebhookConfig = {
siteUrl: string
}
const DEFAULT_SITE_URL = 'https://molthub.com'
const DEFAULT_SITE_URL = 'https://clawhub.ai'
export function getWebhookConfig(env: NodeJS.ProcessEnv = process.env): WebhookConfig {
const url = env.DISCORD_WEBHOOK_URL?.trim() || null
@@ -72,7 +72,7 @@ export function buildDiscordPayload(
},
],
footer: {
text: 'MoltHub',
text: 'OpenClaw',
},
timestamp: new Date().toISOString(),
},
@@ -89,9 +89,9 @@ export function buildSkillUrl(skill: WebhookSkillPayload, siteUrl: string) {
function buildDescription(event: WebhookEvent, skill: WebhookSkillPayload) {
const summary = (skill.summary ?? '').trim()
if (summary) return truncate(summary, 200)
if (event === 'skill.highlighted') return 'Newly highlighted skill on MoltHub.'
if (skill.version) return `New version v${skill.version} published on MoltHub.`
return 'New skill published on MoltHub.'
if (event === 'skill.highlighted') return 'Newly highlighted skill on OpenClaw.'
if (skill.version) return `New version v${skill.version} published on OpenClaw.`
return 'New skill published on OpenClaw.'
}
function parseBoolean(value?: string) {
+1 -1
View File
@@ -62,7 +62,7 @@ describe('maintenance backfill', () => {
parsed: {
frontmatter: { description: 'Hello world.' },
metadata: undefined,
moltbot: undefined,
clawdis: undefined,
},
})
})
+1 -1
View File
@@ -100,7 +100,7 @@ export const applySkillBackfillPatchInternal = internalMutation({
v.object({
frontmatter: v.record(v.string(), v.any()),
metadata: v.optional(v.any()),
moltbot: v.optional(v.any()),
clawdis: v.optional(v.any()),
}),
),
},
+2 -1
View File
@@ -144,8 +144,8 @@ const skillVersions = defineTable({
parsed: v.object({
frontmatter: v.record(v.string(), v.any()),
metadata: v.optional(v.any()),
moltbot: v.optional(v.any()),
clawdis: v.optional(v.any()),
moltbot: v.optional(v.any()),
}),
createdBy: v.id('users'),
createdAt: v.number(),
@@ -173,6 +173,7 @@ const soulVersions = defineTable({
frontmatter: v.record(v.string(), v.any()),
metadata: v.optional(v.any()),
clawdis: v.optional(v.any()),
moltbot: v.optional(v.any()),
}),
createdBy: v.id('users'),
createdAt: v.number(),
+11 -11
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -1324,7 +1324,7 @@ export const insertVersion = internalMutation({
parsed: v.object({
frontmatter: v.record(v.string(), v.any()),
metadata: v.optional(v.any()),
moltbot: v.optional(v.any()),
clawdis: v.optional(v.any()),
}),
embedding: v.array(v.number()),
},
+1 -1
View File
@@ -22,7 +22,7 @@ Reading order (new contributor):
Feature/ops docs (already present):
- `docs/spec.md`: product + implementation spec (data model + flows).
- `docs/telemetry.md`: what `molthub sync` reports; opt-out.
- `docs/telemetry.md`: what `clawhub sync` reports; opt-out.
- `docs/webhook.md`: Discord webhook events/payload.
- `docs/diffing.md`: version-to-version diff UI spec.
- `docs/manual-testing.md`: CLI smoke scripts.
+1 -1
View File
@@ -7,7 +7,7 @@ read_when:
# API v1
Base: `https://molthub.com`
Base: `https://clawhub.ai`
OpenAPI: `/api/v1/openapi.json`
+4 -4
View File
@@ -11,8 +11,8 @@ read_when:
- Web app: TanStack Start (React) under `src/`.
- Backend: Convex under `convex/` (DB, storage, actions, HTTP routes).
- CLI: `packages/molthub/` (published as `molthub`).
- Shared schemas/routes: `packages/schema/` (`molthub-schema`).
- CLI: `packages/clawdhub/` (published as `clawhub`, legacy `clawdhub`).
- Shared schemas/routes: `packages/schema/` (`clawhub-schema`).
## Data + storage
@@ -38,8 +38,8 @@ read_when:
- Download zip via `/api/v1/download?slug=...&version=...`.
- Extract into `./skills/<slug>` (default).
- Persist install state:
- `./.molthub/lock.json` (per workdir)
- `./skills/<slug>/.molthub/origin.json` (per skill folder)
- `./.clawhub/lock.json` (per workdir, legacy `.clawdhub`)
- `./skills/<slug>/.clawhub/origin.json` (per skill folder, legacy `.clawdhub`)
### Update (CLI)
+4 -4
View File
@@ -23,7 +23,7 @@ The CLI uses a long-lived API token (Bearer token) for publish/sync/delete.
### Browser flow (default)
`molthub login` does:
`clawhub login` does:
1. Starts a loopback HTTP server on `127.0.0.1` (random port).
2. Opens `<site>/cli/auth?redirect_uri=http://127.0.0.1:<port>/callback&state=...`.
@@ -35,18 +35,18 @@ The CLI uses a long-lived API token (Bearer token) for publish/sync/delete.
Create a token in the web UI (Settings → API tokens) and paste it:
```bash
molthub login --token clh_...
clawhub login --token clh_...
```
### Token storage
Default global config path:
- macOS: `~/Library/Application Support/molthub/config.json`
- macOS: `~/Library/Application Support/clawhub/config.json`
Override:
- `MOLTHUB_CONFIG_PATH=/path/to/config.json`
- `CLAWHUB_CONFIG_PATH=/path/to/config.json` (legacy `CLAWDHUB_CONFIG_PATH`)
### Revocation
+18 -18
View File
@@ -7,41 +7,41 @@ read_when:
# CLI
CLI package: `packages/molthub/` (bin: `molthub`).
CLI package: `packages/clawdhub/` (published as `clawhub`, bin: `clawhub`).
From this repo you can run it via the wrapper script:
```bash
bun molthub --help
bun clawhub --help
```
## Global flags
- `--workdir <dir>`: working directory (default: cwd; falls back to Moltbot workspace if configured)
- `--workdir <dir>`: working directory (default: cwd; falls back to Clawdbot workspace if configured)
- `--dir <dir>`: install dir under workdir (default: `skills`)
- `--site <url>`: base URL for browser login (default: `https://molthub.com`)
- `--registry <url>`: API base URL (default: discovered, else `https://molthub.com`)
- `--site <url>`: base URL for browser login (default: `https://clawhub.ai`)
- `--registry <url>`: API base URL (default: discovered, else `https://clawhub.ai`)
- `--no-input`: disable prompts
Env equivalents:
- `MOLTHUB_SITE`
- `MOLTHUB_REGISTRY`
- `MOLTHUB_WORKDIR`
- `CLAWHUB_SITE` (legacy `CLAWDHUB_SITE`)
- `CLAWHUB_REGISTRY` (legacy `CLAWDHUB_REGISTRY`)
- `CLAWHUB_WORKDIR` (legacy `CLAWDHUB_WORKDIR`)
## Config file
Stores your API token + cached registry URL.
- macOS: `~/Library/Application Support/molthub/config.json`
- override: `MOLTHUB_CONFIG_PATH`
- macOS: `~/Library/Application Support/clawhub/config.json`
- override: `CLAWHUB_CONFIG_PATH` (legacy `CLAWDHUB_CONFIG_PATH`)
## Commands
### `login` / `auth login`
- Default: opens browser to `<site>/cli/auth` and completes via loopback callback.
- Headless: `molthub login --token clh_...`
- Headless: `clawhub login --token clh_...`
### `whoami`
@@ -72,12 +72,12 @@ Stores your API token + cached registry URL.
- Downloads zip via `/api/v1/download`.
- Extracts into `<workdir>/<dir>/<slug>`.
- Writes:
- `<workdir>/.molthub/lock.json`
- `<skill>/.molthub/origin.json`
- `<workdir>/.clawhub/lock.json` (legacy `.clawdhub`)
- `<skill>/.clawhub/origin.json` (legacy `.clawdhub`)
### `list`
- Reads `<workdir>/.molthub/lock.json`.
- Reads `<workdir>/.clawhub/lock.json` (legacy `.clawdhub`).
### `update [slug]` / `update --all`
@@ -96,12 +96,12 @@ Stores your API token + cached registry URL.
- Scans for local skill folders and publishes new/changed ones.
- Roots can be any folder: a skills directory or a single skill folder with `SKILL.md`.
- Auto-adds Moltbot skill roots when `~/.moltbot/moltbot.json` is present:
- Auto-adds Clawdbot skill roots when `~/.clawdbot/clawdbot.json` is present:
- `agent.workspace/skills` (main agent)
- `routing.agents.*.workspace/skills` (per-agent)
- `~/.moltbot/skills` (shared)
- `~/.clawdbot/skills` (shared)
- `skills.load.extraDirs` (shared packs)
- Respects `MOLTBOT_CONFIG_PATH` and `MOLTBOT_STATE_DIR`.
- Respects `CLAWDBOT_CONFIG_PATH` / `CLAWDBOT_STATE_DIR` and `OPENCLAW_CONFIG_PATH` / `OPENCLAW_STATE_DIR`.
- Flags:
- `--root <dir...>` extra scan roots
- `--all` upload without prompting
@@ -113,5 +113,5 @@ Stores your API token + cached registry URL.
Telemetry:
- Sent during `sync` when logged in, unless `MOLTHUB_DISABLE_TELEMETRY=1`.
- Sent during `sync` when logged in, unless `CLAWHUB_DISABLE_TELEMETRY=1` (legacy `CLAWDHUB_DISABLE_TELEMETRY=1`).
- Details: `docs/telemetry.md`.
+6 -5
View File
@@ -7,7 +7,7 @@ read_when:
# Deploy
MoltHub is two deployables:
OpenClaw is two deployables:
- Web app (TanStack Start) → typically Vercel.
- Convex backend → Convex deployment (serves `/api/...` routes).
@@ -55,12 +55,13 @@ For self-host:
The CLI can discover the API base from:
- `/.well-known/molthub.json`
- `/.well-known/clawhub.json` (preferred)
- `/.well-known/clawdhub.json` (legacy)
If you dont serve that file, users must set:
```bash
export MOLTHUB_REGISTRY=https://your-site.example
export CLAWHUB_REGISTRY=https://your-site.example
```
## 5) Post-deploy checks
@@ -73,6 +74,6 @@ curl -i "https://<site>/api/v1/skills/gifgrep"
Then:
```bash
molthub login --site https://<site>
molthub whoami
clawhub login --site https://<site>
clawhub whoami
```
+2 -2
View File
@@ -10,7 +10,7 @@ read_when:
## Goals
- Compare any file between two versions.
- Default compare: `latest` vs `previous` (SemVer precedence).
- UX feels native to MoltHub (theme + typography + motion).
- UX feels native to OpenClaw (theme + typography + motion).
- Inline or side-by-side toggle.
- Public access.
@@ -57,7 +57,7 @@ Optional helper action:
- Feed into Monaco diff editor.
## Monaco theming
- Define `molthub-light` / `molthub-dark` via `monaco.editor.defineTheme`.
- Define `clawhub-light` / `clawhub-dark` via `monaco.editor.defineTheme`.
- Derive colors from CSS variables on `document.documentElement`:
- `--surface`, `--surface-muted`, `--ink`, `--ink-soft`, `--line`, `--accent`.
- Apply theme on load + when theme changes (`data-theme`).
+6 -5
View File
@@ -7,7 +7,7 @@ read_when:
# HTTP API
Base URL: `https://molthub.com` (default).
Base URL: `https://clawhub.ai` (default).
All v1 paths are under `/api/v1/...` and implemented by Convex HTTP routes (`convex/http.ts`).
Legacy `/api/...` and `/api/cli/...` remain for compatibility (see `DEPRECATIONS.md`).
@@ -172,16 +172,17 @@ Still supported for older CLI versions:
See `DEPRECATIONS.md` for removal plan.
## Registry discovery (`/.well-known/molthub.json`)
## Registry discovery (`/.well-known/clawhub.json`)
The CLI can discover registry/auth settings from the site:
- `/.well-known/molthub.json` (JSON)
- `/.well-known/clawhub.json` (JSON, preferred)
- `/.well-known/clawdhub.json` (legacy)
Schema:
```json
{ "apiBase": "https://molthub.com", "authBase": "https://molthub.com", "minCliVersion": "0.0.5" }
{ "apiBase": "https://clawhub.ai", "authBase": "https://clawhub.ai", "minCliVersion": "0.0.5" }
```
If you self-host, serve this file (or set `MOLTHUB_REGISTRY` explicitly).
If you self-host, serve this file (or set `CLAWHUB_REGISTRY` explicitly; legacy `CLAWDHUB_REGISTRY`).
+20 -20
View File
@@ -8,53 +8,53 @@ read_when:
# Manual testing (CLI)
## Setup
- Ensure logged in: `bun molthub whoami` (or `bun molthub login`).
- Ensure logged in: `bun clawhub whoami` (or `bun clawhub login`).
- Optional: set env
- `MOLTHUB_SITE=https://molthub.com`
- `MOLTHUB_REGISTRY=https://molthub.com`
- `CLAWHUB_SITE=https://clawhub.ai`
- `CLAWHUB_REGISTRY=https://clawhub.ai`
## Smoke
- `bun molthub --help`
- `bun molthub --cli-version`
- `bun molthub whoami`
- `bun clawhub --help`
- `bun clawhub --cli-version`
- `bun clawhub whoami`
## Search
- `bun molthub search gif --limit 5`
- `bun clawhub search gif --limit 5`
## Install / list / update
- `mkdir -p /tmp/molthub-manual && cd /tmp/molthub-manual`
- `bunx molthub@beta install gifgrep --force`
- `bunx molthub@beta list`
- `bunx molthub@beta update gifgrep --force`
- `mkdir -p /tmp/clawhub-manual && cd /tmp/clawhub-manual`
- `bunx clawhub@beta install gifgrep --force`
- `bunx clawhub@beta list`
- `bunx clawhub@beta update gifgrep --force`
## Publish (changelog optional)
- `mkdir -p /tmp/molthub-skill-demo/SKILL && cd /tmp/molthub-skill-demo`
- `mkdir -p /tmp/clawhub-skill-demo/SKILL && cd /tmp/clawhub-skill-demo`
- Create files:
- `SKILL.md`
- `notes.md`
- Publish:
- `bun molthub publish . --slug molthub-manual-<ts> --name "Manual <ts>" --version 1.0.0 --tags latest`
- `bun clawhub publish . --slug clawhub-manual-<ts> --name "Manual <ts>" --version 1.0.0 --tags latest`
- Publish update with empty changelog:
- `bun molthub publish . --slug molthub-manual-<ts> --name "Manual <ts>" --version 1.0.1 --tags latest`
- `bun clawhub publish . --slug clawhub-manual-<ts> --name "Manual <ts>" --version 1.0.1 --tags latest`
## Delete / undelete (owner/admin)
- `bun molthub delete molthub-manual-<ts> --yes`
- `bun clawhub delete clawhub-manual-<ts> --yes`
- Verify hidden:
- `curl -i "https://molthub.com/api/v1/skills/molthub-manual-<ts>"`
- `curl -i "https://clawhub.ai/api/v1/skills/clawhub-manual-<ts>"`
- Restore:
- `bun molthub undelete molthub-manual-<ts> --yes`
- `bun clawhub undelete clawhub-manual-<ts> --yes`
- Cleanup:
- `bun molthub delete molthub-manual-<ts> --yes`
- `bun clawhub delete clawhub-manual-<ts> --yes`
## Sync
- `bun molthub sync --dry-run --all`
- `bun clawhub sync --dry-run --all`
## Playwright (menu smoke)
Run against prod:
```
PLAYWRIGHT_BASE_URL=https://molthub.com bun run test:pw
PLAYWRIGHT_BASE_URL=https://clawhub.ai bun run test:pw
```
Run against a local preview server:
+1 -1
View File
@@ -20,7 +20,7 @@ Example (starter):
```json
{
"name": "MoltHub",
"name": "OpenClaw",
"logo": "public/logo.svg",
"navigation": [
{ "group": "Start", "pages": ["docs/README", "docs/quickstart"] },
+14 -14
View File
@@ -51,29 +51,29 @@ Then paste the printed `JWT_PRIVATE_KEY` + `JWKS` into `.env.local` (and ensure
From this repo:
```bash
bun molthub --help
bun molthub login
bun molthub whoami
bun molthub search gif --limit 5
bun clawhub --help
bun clawhub login
bun clawhub whoami
bun clawhub search gif --limit 5
```
Install a skill into `./skills/<slug>` (if Moltbot is configured, installs into that workspace instead):
Install a skill into `./skills/<slug>` (if Clawdbot is configured, installs into that workspace instead):
```bash
bun molthub install <slug>
bun molthub list
bun clawhub install <slug>
bun clawhub list
```
You can also install into any folder:
```bash
bun molthub install <slug> --workdir /tmp/molthub-demo --dir skills
bun clawhub install <slug> --workdir /tmp/clawhub-demo --dir skills
```
Update:
```bash
bun molthub update --all
bun clawhub update --all
```
## 4) Publish a skill
@@ -81,7 +81,7 @@ bun molthub update --all
Create a folder containing `SKILL.md` (required) plus any supporting text files:
```bash
mkdir -p /tmp/molthub-skill-demo && cd /tmp/molthub-skill-demo
mkdir -p /tmp/clawhub-skill-demo && cd /tmp/clawhub-skill-demo
cat > SKILL.md <<'EOF'
---
name: Demo Skill
@@ -97,8 +97,8 @@ EOF
Publish:
```bash
bun molthub publish . \
--slug molthub-demo-$(date +%s) \
bun clawhub publish . \
--slug clawhub-demo-$(date +%s) \
--name "Demo $(date +%s)" \
--version 1.0.0 \
--tags latest \
@@ -110,11 +110,11 @@ bun molthub publish . \
`sync` scans for local skill folders and publishes the ones that arent “synced” yet.
```bash
bun molthub sync
bun clawhub sync
```
Dry run + non-interactive:
```bash
bun molthub sync --all --dry-run --no-input
bun clawhub sync --all --dry-run --no-input
```
+3 -3
View File
@@ -18,16 +18,16 @@ Required:
Optional:
- any supporting *text-based* files (see “Allowed files”)
- `.molthubignore` (ignore patterns for publish/sync)
- `.clawhubignore` (ignore patterns for publish/sync, legacy `.clawdhubignore`)
- `.gitignore` (also honored)
Local install metadata (written by the CLI):
- `<skill>/.molthub/origin.json`
- `<skill>/.clawhub/origin.json` (legacy `.clawdhub`)
Workdir install state (written by the CLI):
- `<workdir>/.molthub/lock.json`
- `<workdir>/.clawhub/lock.json` (legacy `.clawdhub`)
## `SKILL.md`
+7 -7
View File
@@ -1,18 +1,18 @@
---
summary: "MoltHub spec: skills registry, versioning, vector search, moderation"
summary: "OpenClaw spec: skills registry, versioning, vector search, moderation"
read_when:
- Bootstrapping MoltHub
- Bootstrapping OpenClaw
- Implementing schema/auth/search/versioning
- Reviewing API and upload/download flows
---
# MoltHub — product + implementation spec (v1)
# OpenClaw — product + implementation spec (v1)
## Goals
- onlycrabs.ai mode for sharing `SOUL.md` bundles (host-based entry point).
- Minimal, fast SPA for browsing and publishing agent skills.
- Skills stored in Convex (files + metadata + versions + stats).
- GitHub OAuth login; GitHub App backs up skills to `moltbot/skills`.
- GitHub OAuth login; GitHub App backs up skills to `clawdbot/skills`.
- Vector-based search over skill text + metadata.
- Versioning, tags (`latest` + user tags), changelog, rollback (tag movement).
- Public read access; upload requires auth.
@@ -63,12 +63,12 @@ read_when:
- `softDeletedAt` (nullable)
### Parsed Skill Metadata
From SKILL.md frontmatter + AgentSkills + Moltbot extensions:
From SKILL.md frontmatter + AgentSkills + Clawdis extensions:
- `name`, `description`, `homepage`, `website`, `url`, `emoji`
- `metadata.moltbot`: `always`, `skillKey`, `primaryEnv`, `emoji`, `homepage`, `os`,
- `metadata.clawdis`: `always`, `skillKey`, `primaryEnv`, `emoji`, `homepage`, `os`,
`requires` (`bins`, `anyBins`, `env`, `config`), `install[]`, `nix` (`plugin`, `systems`),
`config` (`requiredEnv`, `stateDirs`, `example`), `cliHelp` (string; `cli --help` output)
- `metadata.moltbot`: alias of `metadata.moltbot` (preferred for nix-moltbot plugin pointers)
- `metadata.clawdbot`: alias of `metadata.clawdis` (preferred for nix-clawdbot plugin pointers)
- Nix plugins are different from regular skills; they bundle the skill pack, the CLI binary, and config flags/requirements together.
- `metadata` in frontmatter is YAML (object) preferred; legacy JSON-string accepted.
+8 -8
View File
@@ -1,5 +1,5 @@
---
summary: 'Install telemetry collected via `molthub sync` + opt-out.'
summary: 'Install telemetry collected via `clawhub sync` + opt-out.'
read_when:
- Working on telemetry / privacy controls
- Questions about what data is collected
@@ -7,22 +7,22 @@ read_when:
# Telemetry
MoltHub uses **minimal telemetry** to compute **install counts** (whats actually in use) and to power better sorting/filtering.
This is based on the CLI `molthub sync` command.
OpenClaw uses **minimal telemetry** to compute **install counts** (whats actually in use) and to power better sorting/filtering.
This is based on the CLI `clawhub sync` command.
## When telemetry is collected
Telemetry is only sent when:
- You are **logged in** in the CLI (we already require auth for sync/publish flows).
- You run `molthub sync`.
- You run `clawhub sync`.
- Telemetry is **not disabled** (see “How to disable” below).
If you are not logged in, nothing is reported.
## What we collect
On each `molthub sync`, the CLI reports a **full snapshot** of what it found, grouped by scan root (“folder/root”).
On each `clawhub sync`, the CLI reports a **full snapshot** of what it found, grouped by scan root (“folder/root”).
For each root we store:
@@ -70,7 +70,7 @@ This is evaluated lazily (on the next telemetry report) to avoid background jobs
## Transparency + user controls
MoltHub provides a private “Installed” tab on your own profile:
OpenClaw provides a private “Installed” tab on your own profile:
- Shows the exact roots + installed skills we store.
- Includes a **JSON export** view.
@@ -85,7 +85,7 @@ Deleting your account also deletes your telemetry data.
Set the environment variable:
```bash
export MOLTHUB_DISABLE_TELEMETRY=1
export CLAWHUB_DISABLE_TELEMETRY=1
```
With this set, the CLI will not send telemetry during `molthub sync`.
With this set, the CLI will not send telemetry during `clawhub sync`.
+7 -7
View File
@@ -6,16 +6,16 @@ read_when:
# Troubleshooting
## `molthub login` opens browser but never completes
## `clawhub login` opens browser but never completes
- Ensure your browser can reach `http://127.0.0.1:<port>/callback` (local firewalls/VPNs can interfere).
- Use headless mode:
- create a token in the web UI (Settings → API tokens)
- `molthub login --token clh_...`
- `clawhub login --token clh_...`
## `whoami` / `publish` returns `Unauthorized` (401)
- Token missing or revoked: check your config file (`MOLTHUB_CONFIG_PATH` override?).
- Token missing or revoked: check your config file (`CLAWHUB_CONFIG_PATH` override?).
- Ensure requests include `Authorization: Bearer ...` (CLI does this automatically).
## `publish` fails with `OPENAI_API_KEY is not configured`
@@ -28,11 +28,11 @@ read_when:
- `sync` looks for folders containing `SKILL.md` (or `skill.md`).
- It scans:
- workdir first
- then fallback roots (legacy `~/moltbot/skills`, `~/moltbot/skills`, etc.)
- then fallback roots (legacy `~/clawdis/skills`, `~/clawdbot/skills`, etc.)
- Provide explicit roots:
```bash
molthub sync --root /path/to/skills
clawhub sync --root /path/to/skills
```
## `update` refuses due to “local changes (no match)”
@@ -40,8 +40,8 @@ molthub sync --root /path/to/skills
- Your local files dont match any published fingerprint.
- Options:
- keep local edits; skip updating
- overwrite: `molthub update <slug> --force`
- publish as fork: copy to new folder/slug then `molthub publish ... --fork-of upstream@version`
- overwrite: `clawhub update <slug> --force`
- publish as fork: copy to new folder/slug then `clawhub publish ... --fork-of upstream@version`
## `GET /api/*` works locally but not on Vercel
+4 -4
View File
@@ -6,7 +6,7 @@ read_when:
# Webhooks (Discord)
MoltHub can post Discord embeds when skills are published or highlighted.
OpenClaw can post Discord embeds when skills are published or highlighted.
## Setup
@@ -14,7 +14,7 @@ Set the webhook URL in the Convex environment:
- `DISCORD_WEBHOOK_URL` (required): Discord webhook URL.
- `DISCORD_WEBHOOK_HIGHLIGHTED_ONLY` (optional): `true` to only send for highlighted skills.
- `SITE_URL` (optional): Base site URL for links (default `https://molthub.com`).
- `SITE_URL` (optional): Base site URL for links (default `https://clawhub.ai`).
## Events
@@ -38,13 +38,13 @@ Discord receives a JSON payload with a single embed:
{
"title": "Demo Skill",
"description": "Nice skill",
"url": "https://molthub.com/owner/demo-skill",
"url": "https://clawhub.ai/owner/demo-skill",
"fields": [
{ "name": "Version", "value": "v1.2.3", "inline": true },
{ "name": "Owner", "value": "@owner", "inline": true },
{ "name": "Tags", "value": "latest, discord", "inline": false }
],
"footer": { "text": "MoltHub" }
"footer": { "text": "OpenClaw" }
}
]
}
@@ -4,16 +4,16 @@ import { spawnSync } from 'node:child_process'
import { mkdir, mkdtemp, rm, writeFile } from 'node:fs/promises'
import { tmpdir } from 'node:os'
import { join } from 'node:path'
import { unzipSync } from 'fflate'
import {
ApiRoutes,
ApiV1SearchResponseSchema,
ApiV1WhoamiResponseSchema,
parseArk,
} from 'molthub-schema'
} from 'clawhub-schema'
import { unzipSync } from 'fflate'
import { Agent, setGlobalDispatcher } from 'undici'
import { describe, expect, it } from 'vitest'
import { readGlobalConfig } from '../packages/molthub/src/config'
import { readGlobalConfig } from '../packages/clawdhub/src/config'
const REQUEST_TIMEOUT_MS = 15_000
@@ -29,13 +29,27 @@ try {
}
function mustGetToken() {
const fromEnv = process.env.MOLTHUB_E2E_TOKEN?.trim()
const fromEnv = process.env.CLAWHUB_E2E_TOKEN?.trim() || process.env.CLAWDHUB_E2E_TOKEN?.trim()
if (fromEnv) return fromEnv
return null
}
function getRegistry() {
return (
process.env.CLAWHUB_REGISTRY?.trim() ||
process.env.CLAWDHUB_REGISTRY?.trim() ||
'https://clawhub.ai'
)
}
function getSite() {
return (
process.env.CLAWHUB_SITE?.trim() || process.env.CLAWDHUB_SITE?.trim() || 'https://clawhub.ai'
)
}
async function makeTempConfig(registry: string, token: string | null) {
const dir = await mkdtemp(join(tmpdir(), 'molthub-e2e-'))
const dir = await mkdtemp(join(tmpdir(), 'clawhub-e2e-'))
const path = join(dir, 'config.json')
await writeFile(
path,
@@ -55,9 +69,9 @@ async function fetchWithTimeout(input: RequestInfo | URL, init?: RequestInit) {
}
}
describe('molthub e2e', () => {
describe('clawhub e2e', () => {
it('prints CLI version via --cli-version', async () => {
const result = spawnSync('bun', ['molthub', '--cli-version'], {
const result = spawnSync('bun', ['clawhub', '--cli-version'], {
cwd: process.cwd(),
encoding: 'utf8',
})
@@ -66,7 +80,7 @@ describe('molthub e2e', () => {
})
it('search endpoint returns a results array (schema parse)', async () => {
const registry = process.env.MOLTHUB_REGISTRY?.trim() || 'https://molthub.com'
const registry = getRegistry()
const url = new URL(ApiRoutes.search, registry)
url.searchParams.set('q', 'gif')
url.searchParams.set('limit', '5')
@@ -81,17 +95,17 @@ describe('molthub e2e', () => {
})
it('cli search does not error on multi-result responses', async () => {
const registry = process.env.MOLTHUB_REGISTRY?.trim() || 'https://molthub.com'
const site = process.env.MOLTHUB_SITE?.trim() || 'https://molthub.com'
const registry = getRegistry()
const site = getSite()
const token = mustGetToken() ?? (await readGlobalConfig())?.token ?? null
const cfg = await makeTempConfig(registry, token)
try {
const workdir = await mkdtemp(join(tmpdir(), 'molthub-e2e-workdir-'))
const workdir = await mkdtemp(join(tmpdir(), 'clawhub-e2e-workdir-'))
const result = spawnSync(
'bun',
[
'molthub',
'clawhub',
'search',
'gif',
'--limit',
@@ -105,7 +119,7 @@ describe('molthub e2e', () => {
],
{
cwd: process.cwd(),
env: { ...process.env, MOLTHUB_CONFIG_PATH: cfg.path, MOLTHUB_DISABLE_TELEMETRY: '1' },
env: { ...process.env, CLAWHUB_CONFIG_PATH: cfg.path, CLAWHUB_DISABLE_TELEMETRY: '1' },
encoding: 'utf8',
},
)
@@ -119,11 +133,11 @@ describe('molthub e2e', () => {
})
it('assumes a logged-in user (whoami succeeds)', async () => {
const registry = process.env.MOLTHUB_REGISTRY?.trim() || 'https://molthub.com'
const site = process.env.MOLTHUB_SITE?.trim() || 'https://molthub.com'
const registry = getRegistry()
const site = getSite()
const token = mustGetToken() ?? (await readGlobalConfig())?.token ?? null
if (!token) {
throw new Error('Missing token. Set MOLTHUB_E2E_TOKEN or run: bun molthub auth login')
throw new Error('Missing token. Set CLAWHUB_E2E_TOKEN or run: bun clawhub auth login')
}
const cfg = await makeTempConfig(registry, token)
@@ -142,10 +156,10 @@ describe('molthub e2e', () => {
const result = spawnSync(
'bun',
['molthub', 'whoami', '--site', site, '--registry', registry],
['clawhub', 'whoami', '--site', site, '--registry', registry],
{
cwd: process.cwd(),
env: { ...process.env, MOLTHUB_CONFIG_PATH: cfg.path, MOLTHUB_DISABLE_TELEMETRY: '1' },
env: { ...process.env, CLAWHUB_CONFIG_PATH: cfg.path, CLAWHUB_DISABLE_TELEMETRY: '1' },
encoding: 'utf8',
},
)
@@ -157,15 +171,15 @@ describe('molthub e2e', () => {
})
it('sync dry-run finds skills from an explicit root', async () => {
const registry = process.env.MOLTHUB_REGISTRY?.trim() || 'https://molthub.com'
const site = process.env.MOLTHUB_SITE?.trim() || 'https://molthub.com'
const registry = getRegistry()
const site = getSite()
const token = mustGetToken() ?? (await readGlobalConfig())?.token ?? null
if (!token) {
throw new Error('Missing token. Set MOLTHUB_E2E_TOKEN or run: bun molthub auth login')
throw new Error('Missing token. Set CLAWHUB_E2E_TOKEN or run: bun clawhub auth login')
}
const cfg = await makeTempConfig(registry, token)
const root = await mkdtemp(join(tmpdir(), 'molthub-e2e-sync-'))
const root = await mkdtemp(join(tmpdir(), 'clawhub-e2e-sync-'))
try {
const skillDir = join(root, 'cool-skill')
await mkdir(skillDir, { recursive: true })
@@ -174,7 +188,7 @@ describe('molthub e2e', () => {
const result = spawnSync(
'bun',
[
'molthub',
'clawhub',
'sync',
'--dry-run',
'--all',
@@ -187,7 +201,7 @@ describe('molthub e2e', () => {
],
{
cwd: process.cwd(),
env: { ...process.env, MOLTHUB_CONFIG_PATH: cfg.path, MOLTHUB_DISABLE_TELEMETRY: '1' },
env: { ...process.env, CLAWHUB_CONFIG_PATH: cfg.path, CLAWHUB_DISABLE_TELEMETRY: '1' },
encoding: 'utf8',
},
)
@@ -200,19 +214,19 @@ describe('molthub e2e', () => {
}
})
it('sync dry-run finds skills from moltbot.json roots', async () => {
const registry = process.env.MOLTHUB_REGISTRY?.trim() || 'https://molthub.com'
const site = process.env.MOLTHUB_SITE?.trim() || 'https://molthub.com'
it('sync dry-run finds skills from clawdbot.json roots', async () => {
const registry = getRegistry()
const site = getSite()
const token = mustGetToken() ?? (await readGlobalConfig())?.token ?? null
if (!token) {
throw new Error('Missing token. Set MOLTHUB_E2E_TOKEN or run: bun molthub auth login')
throw new Error('Missing token. Set CLAWHUB_E2E_TOKEN or run: bun clawhub auth login')
}
const cfg = await makeTempConfig(registry, token)
const root = await mkdtemp(join(tmpdir(), 'molthub-e2e-moltbot-'))
const root = await mkdtemp(join(tmpdir(), 'clawhub-e2e-clawdbot-'))
const stateDir = join(root, 'state')
const configPath = join(root, 'moltbot.json')
const workspace = join(root, 'molt-work')
const configPath = join(root, 'clawdbot.json')
const workspace = join(root, 'clawd-work')
const skillsRoot = join(workspace, 'skills')
const skillDir = join(skillsRoot, 'auto-skill')
@@ -232,15 +246,15 @@ describe('molthub e2e', () => {
const result = spawnSync(
'bun',
['molthub', 'sync', '--dry-run', '--all', '--site', site, '--registry', registry],
['clawhub', 'sync', '--dry-run', '--all', '--site', site, '--registry', registry],
{
cwd: process.cwd(),
env: {
...process.env,
MOLTHUB_CONFIG_PATH: cfg.path,
MOLTHUB_DISABLE_TELEMETRY: '1',
MOLTBOT_CONFIG_PATH: configPath,
MOLTBOT_STATE_DIR: stateDir,
CLAWHUB_CONFIG_PATH: cfg.path,
CLAWHUB_DISABLE_TELEMETRY: '1',
CLAWDBOT_CONFIG_PATH: configPath,
CLAWDBOT_STATE_DIR: stateDir,
},
encoding: 'utf8',
},
@@ -256,16 +270,16 @@ describe('molthub e2e', () => {
})
it('publishes, deletes, and undeletes a skill (logged-in)', async () => {
const registry = process.env.MOLTHUB_REGISTRY?.trim() || 'https://molthub.com'
const site = process.env.MOLTHUB_SITE?.trim() || 'https://molthub.com'
const registry = getRegistry()
const site = getSite()
const token = mustGetToken() ?? (await readGlobalConfig())?.token ?? null
if (!token) {
throw new Error('Missing token. Set MOLTHUB_E2E_TOKEN or run: bun molthub auth login')
throw new Error('Missing token. Set CLAWHUB_E2E_TOKEN or run: bun clawhub auth login')
}
const cfg = await makeTempConfig(registry, token)
const workdir = await mkdtemp(join(tmpdir(), 'molthub-e2e-publish-'))
const installWorkdir = await mkdtemp(join(tmpdir(), 'molthub-e2e-install-'))
const workdir = await mkdtemp(join(tmpdir(), 'clawhub-e2e-publish-'))
const installWorkdir = await mkdtemp(join(tmpdir(), 'clawhub-e2e-install-'))
const slug = `e2e-${Date.now()}`
const skillDir = join(workdir, slug)
@@ -276,7 +290,7 @@ describe('molthub e2e', () => {
const publish1 = spawnSync(
'bun',
[
'molthub',
'clawhub',
'publish',
skillDir,
'--slug',
@@ -296,7 +310,7 @@ describe('molthub e2e', () => {
],
{
cwd: process.cwd(),
env: { ...process.env, MOLTHUB_CONFIG_PATH: cfg.path, MOLTHUB_DISABLE_TELEMETRY: '1' },
env: { ...process.env, CLAWHUB_CONFIG_PATH: cfg.path, CLAWHUB_DISABLE_TELEMETRY: '1' },
encoding: 'utf8',
},
)
@@ -306,7 +320,7 @@ describe('molthub e2e', () => {
const publish2 = spawnSync(
'bun',
[
'molthub',
'clawhub',
'publish',
skillDir,
'--slug',
@@ -326,7 +340,7 @@ describe('molthub e2e', () => {
],
{
cwd: process.cwd(),
env: { ...process.env, MOLTHUB_CONFIG_PATH: cfg.path, MOLTHUB_DISABLE_TELEMETRY: '1' },
env: { ...process.env, CLAWHUB_CONFIG_PATH: cfg.path, CLAWHUB_DISABLE_TELEMETRY: '1' },
encoding: 'utf8',
},
)
@@ -345,7 +359,7 @@ describe('molthub e2e', () => {
const install = spawnSync(
'bun',
[
'molthub',
'clawhub',
'install',
slug,
'--version',
@@ -360,7 +374,7 @@ describe('molthub e2e', () => {
],
{
cwd: process.cwd(),
env: { ...process.env, MOLTHUB_CONFIG_PATH: cfg.path, MOLTHUB_DISABLE_TELEMETRY: '1' },
env: { ...process.env, CLAWHUB_CONFIG_PATH: cfg.path, CLAWHUB_DISABLE_TELEMETRY: '1' },
encoding: 'utf8',
},
)
@@ -368,10 +382,10 @@ describe('molthub e2e', () => {
const list = spawnSync(
'bun',
['molthub', 'list', '--site', site, '--registry', registry, '--workdir', installWorkdir],
['clawhub', 'list', '--site', site, '--registry', registry, '--workdir', installWorkdir],
{
cwd: process.cwd(),
env: { ...process.env, MOLTHUB_CONFIG_PATH: cfg.path, MOLTHUB_DISABLE_TELEMETRY: '1' },
env: { ...process.env, CLAWHUB_CONFIG_PATH: cfg.path, CLAWHUB_DISABLE_TELEMETRY: '1' },
encoding: 'utf8',
},
)
@@ -381,7 +395,7 @@ describe('molthub e2e', () => {
const update = spawnSync(
'bun',
[
'molthub',
'clawhub',
'update',
slug,
'--force',
@@ -394,7 +408,7 @@ describe('molthub e2e', () => {
],
{
cwd: process.cwd(),
env: { ...process.env, MOLTHUB_CONFIG_PATH: cfg.path, MOLTHUB_DISABLE_TELEMETRY: '1' },
env: { ...process.env, CLAWHUB_CONFIG_PATH: cfg.path, CLAWHUB_DISABLE_TELEMETRY: '1' },
encoding: 'utf8',
},
)
@@ -409,7 +423,7 @@ describe('molthub e2e', () => {
const del = spawnSync(
'bun',
[
'molthub',
'clawhub',
'delete',
slug,
'--yes',
@@ -422,7 +436,7 @@ describe('molthub e2e', () => {
],
{
cwd: process.cwd(),
env: { ...process.env, MOLTHUB_CONFIG_PATH: cfg.path, MOLTHUB_DISABLE_TELEMETRY: '1' },
env: { ...process.env, CLAWHUB_CONFIG_PATH: cfg.path, CLAWHUB_DISABLE_TELEMETRY: '1' },
encoding: 'utf8',
},
)
@@ -439,7 +453,7 @@ describe('molthub e2e', () => {
const undelete = spawnSync(
'bun',
[
'molthub',
'clawhub',
'undelete',
slug,
'--yes',
@@ -452,7 +466,7 @@ describe('molthub e2e', () => {
],
{
cwd: process.cwd(),
env: { ...process.env, MOLTHUB_CONFIG_PATH: cfg.path, MOLTHUB_DISABLE_TELEMETRY: '1' },
env: { ...process.env, CLAWHUB_CONFIG_PATH: cfg.path, CLAWHUB_DISABLE_TELEMETRY: '1' },
encoding: 'utf8',
},
)
@@ -466,7 +480,7 @@ describe('molthub e2e', () => {
const cleanup = spawnSync(
'bun',
[
'molthub',
'clawhub',
'delete',
slug,
'--yes',
@@ -479,7 +493,7 @@ describe('molthub e2e', () => {
],
{
cwd: process.cwd(),
env: { ...process.env, MOLTHUB_CONFIG_PATH: cfg.path, MOLTHUB_DISABLE_TELEMETRY: '1' },
env: { ...process.env, CLAWHUB_CONFIG_PATH: cfg.path, CLAWHUB_DISABLE_TELEMETRY: '1' },
encoding: 'utf8',
},
)
+1 -1
View File
@@ -43,7 +43,7 @@ test('header menu routes render', async ({ page }) => {
if (label === 'Search') {
await expect(page).toHaveURL(/\/?(\?|$)/)
await expect(page.locator('h1', { hasText: 'MoltHub' })).toBeVisible()
await expect(page.locator('h1', { hasText: 'OpenClaw' })).toBeVisible()
}
}
})
+3 -3
View File
@@ -1,5 +1,5 @@
{
"name": "molthub",
"name": "clawhub",
"private": true,
"type": "module",
"workspaces": [
@@ -21,7 +21,7 @@
"convex:deploy": "bunx convex deploy --typecheck=disable --yes",
"lint": "bun run lint:biome && bun run lint:oxlint",
"lint:biome": "biome check .",
"lint:oxlint": "oxlint --type-aware --tsconfig ./tsconfig.oxlint.json ./src ./convex ./packages/molthub/src ./packages/schema/src",
"lint:oxlint": "oxlint --type-aware --tsconfig ./tsconfig.oxlint.json ./src ./convex ./packages/clawdhub/src ./packages/schema/src",
"format": "biome format --write ."
},
"dependencies": {
@@ -41,7 +41,7 @@
"@tanstack/react-start": "^1.152.0",
"@tanstack/router-plugin": "^1.151.6",
"@vercel/analytics": "^1.6.1",
"molthub-schema": "workspace:*",
"clawhub-schema": "workspace:*",
"clsx": "^2.1.1",
"convex": "^1.31.6",
"convex-helpers": "^0.1.111",
+57
View File
@@ -0,0 +1,57 @@
# `clawhub`
OpenClaw CLI — install, update, search, and publish agent skills as folders.
## Install
```bash
# From this repo (shortcut script at repo root)
bun clawhub --help
# Once published to npm
# npm i -g clawhub
```
## Auth (publish)
```bash
clawhub login
# or
clawhub auth login
# Headless / token paste
# or (token paste / headless)
clawhub login --token clh_...
```
Notes:
- Browser login opens `https://clawhub.ai/cli/auth` and completes via a loopback callback.
- Token stored in `~/Library/Application Support/clawhub/config.json` on macOS (override via `CLAWHUB_CONFIG_PATH`, legacy `CLAWDHUB_CONFIG_PATH`).
## Examples
```bash
clawhub search "postgres backups"
clawhub install my-skill-pack
clawhub update --all
clawhub update --all --no-input --force
clawhub publish ./my-skill-pack --slug my-skill-pack --name "My Skill Pack" --version 1.2.0 --changelog "Fixes + docs"
```
## Sync (upload local skills)
```bash
# Start anywhere; scans workdir first, then legacy Clawdis/Clawd/OpenClaw/Moltbot locations.
clawhub sync
# Explicit roots + non-interactive dry-run
clawhub sync --root ../clawdis/skills --all --dry-run
```
## Defaults
- Site: `https://clawhub.ai` (override via `--site` or `CLAWHUB_SITE`, legacy `CLAWDHUB_SITE`)
- Registry: discovered from `/.well-known/clawhub.json` on the site (legacy `/.well-known/clawdhub.json`; override via `--registry` or `CLAWHUB_REGISTRY`)
- Workdir: current directory (falls back to Clawdbot workspace if configured; override via `--workdir` or `CLAWHUB_WORKDIR`)
- Install dir: `./skills` under workdir (override via `--dir`)
@@ -1,11 +1,12 @@
{
"name": "molthub",
"version": "0.3.0",
"description": "MoltHub CLI \\u2014 install, update, search, and publish agent skills.",
"name": "clawhub",
"version": "0.4.0",
"description": "OpenClaw CLI \\u2014 install, update, search, and publish agent skills.",
"license": "MIT",
"type": "module",
"bin": {
"molthub": "bin/molthub.js"
"clawhub": "bin/clawdhub.js",
"clawdhub": "bin/clawdhub.js"
},
"files": [
"bin",
@@ -60,7 +60,7 @@ describe('browserAuth', () => {
const response = await fetch(server.redirectUri)
expect(response.status).toBe(200)
const text = await response.text()
expect(text).toContain('MoltHub CLI Login')
expect(text).toContain('OpenClaw CLI Login')
server.close()
})
@@ -127,7 +127,7 @@ const CALLBACK_HTML = `<!doctype html>
<html lang="en">
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>MoltHub CLI Login</title>
<title>OpenClaw CLI Login</title>
<style>
:root { color-scheme: light dark; }
body { font-family: ui-sans-serif, system-ui, -apple-system, Segoe UI, sans-serif; padding: 24px; }
@@ -3,6 +3,7 @@ import { stat } from 'node:fs/promises'
import { join, resolve } from 'node:path'
import { Command } from 'commander'
import { getCliBuildLabel, getCliVersion } from './cli/buildInfo.js'
import { resolveClawdbotDefaultWorkspace } from './cli/clawdbotConfig.js'
import { cmdLoginFlow, cmdLogout, cmdWhoami } from './cli/commands/auth.js'
import { cmdDeleteSkill, cmdUndeleteSkill } from './cli/commands/delete.js'
import { cmdPublish } from './cli/commands/publish.js'
@@ -11,16 +12,15 @@ import { cmdStarSkill } from './cli/commands/star.js'
import { cmdSync } from './cli/commands/sync.js'
import { cmdUnstarSkill } from './cli/commands/unstar.js'
import { configureCommanderHelp, styleEnvBlock, styleTitle } from './cli/helpStyle.js'
import { resolveMoltbotDefaultWorkspace } from './cli/moltbotConfig.js'
import { DEFAULT_REGISTRY, DEFAULT_SITE } from './cli/registry.js'
import type { GlobalOpts } from './cli/types.js'
import { fail } from './cli/ui.js'
import { readGlobalConfig } from './config.js'
const program = new Command()
.name('molthub')
.name('clawhub')
.description(
`${styleTitle(`MoltHub CLI ${getCliBuildLabel()}`)}\n${styleEnvBlock(
`${styleTitle(`OpenClaw CLI ${getCliBuildLabel()}`)}\n${styleEnvBlock(
'install, update, search, and publish agent skills.',
)}`,
)
@@ -34,7 +34,9 @@ const program = new Command()
.showSuggestionAfterError()
.addHelpText(
'after',
styleEnvBlock('\nEnv:\n MOLTHUB_SITE\n MOLTHUB_REGISTRY\n MOLTHUB_WORKDIR\n'),
styleEnvBlock(
'\nEnv:\n CLAWHUB_SITE\n CLAWHUB_REGISTRY\n CLAWHUB_WORKDIR\n (CLAWDHUB_* supported)\n',
),
)
configureCommanderHelp(program)
@@ -43,9 +45,17 @@ async function resolveGlobalOpts(): Promise<GlobalOpts> {
const raw = program.opts<{ workdir?: string; dir?: string; site?: string; registry?: string }>()
const workdir = await resolveWorkdir(raw.workdir)
const dir = resolve(workdir, raw.dir ?? 'skills')
const site = raw.site ?? process.env.MOLTHUB_SITE ?? DEFAULT_SITE
const registrySource = raw.registry ? 'cli' : process.env.MOLTHUB_REGISTRY ? 'env' : 'default'
const registry = raw.registry ?? process.env.MOLTHUB_REGISTRY ?? DEFAULT_REGISTRY
const site = raw.site ?? process.env.CLAWHUB_SITE ?? process.env.CLAWDHUB_SITE ?? DEFAULT_SITE
const registrySource = raw.registry
? 'cli'
: process.env.CLAWHUB_REGISTRY || process.env.CLAWDHUB_REGISTRY
? 'env'
: 'default'
const registry =
raw.registry ??
process.env.CLAWHUB_REGISTRY ??
process.env.CLAWDHUB_REGISTRY ??
DEFAULT_REGISTRY
return { workdir, dir, site, registry, registrySource }
}
@@ -56,22 +66,26 @@ function isInputAllowed() {
async function resolveWorkdir(explicit?: string) {
if (explicit?.trim()) return resolve(explicit.trim())
const envWorkdir = process.env.MOLTHUB_WORKDIR?.trim()
const envWorkdir = process.env.CLAWHUB_WORKDIR?.trim() ?? process.env.CLAWDHUB_WORKDIR?.trim()
if (envWorkdir) return resolve(envWorkdir)
const cwd = resolve(process.cwd())
const hasMarker = await hasMolthubMarker(cwd)
const hasMarker = await hasClawhubMarker(cwd)
if (hasMarker) return cwd
const moltbotWorkspace = await resolveMoltbotDefaultWorkspace()
return moltbotWorkspace ? resolve(moltbotWorkspace) : cwd
const clawdbotWorkspace = await resolveClawdbotDefaultWorkspace()
return clawdbotWorkspace ? resolve(clawdbotWorkspace) : cwd
}
async function hasMolthubMarker(workdir: string) {
const lockfile = join(workdir, '.molthub', 'lock.json')
async function hasClawhubMarker(workdir: string) {
const lockfile = join(workdir, '.clawhub', 'lock.json')
if (await pathExists(lockfile)) return true
const markerDir = join(workdir, '.molthub')
return pathExists(markerDir)
const markerDir = join(workdir, '.clawhub')
if (await pathExists(markerDir)) return true
const legacyLockfile = join(workdir, '.clawdhub', 'lock.json')
if (await pathExists(legacyLockfile)) return true
const legacyMarkerDir = join(workdir, '.clawdhub')
return pathExists(legacyMarkerDir)
}
async function pathExists(path: string) {
@@ -24,7 +24,8 @@ function shortCommit(value: string) {
export function getCliCommit() {
const candidates = [
process.env.MOLTHUB_COMMIT,
process.env.CLAWHUB_COMMIT,
process.env.CLAWDHUB_COMMIT,
process.env.VERCEL_GIT_COMMIT_SHA,
process.env.GITHUB_SHA,
process.env.COMMIT_SHA,
@@ -0,0 +1,203 @@
/* @vitest-environment node */
import { mkdir, mkdtemp, writeFile } from 'node:fs/promises'
import { tmpdir } from 'node:os'
import { join, resolve } from 'node:path'
import { afterEach, describe, expect, it } from 'vitest'
import { resolveClawdbotDefaultWorkspace, resolveClawdbotSkillRoots } from './clawdbotConfig.js'
const originalEnv = { ...process.env }
afterEach(() => {
process.env = { ...originalEnv }
})
describe('resolveClawdbotSkillRoots', () => {
it('reads JSON5 config and resolves per-agent + shared skill roots', async () => {
const base = await mkdtemp(join(tmpdir(), 'clawhub-clawdbot-'))
const home = join(base, 'home')
const stateDir = join(base, 'state')
const configPath = join(base, 'clawdbot.json')
const openclawStateDir = join(base, 'openclaw-state')
process.env.HOME = home
process.env.CLAWDBOT_STATE_DIR = stateDir
process.env.CLAWDBOT_CONFIG_PATH = configPath
process.env.OPENCLAW_STATE_DIR = openclawStateDir
process.env.OPENCLAW_CONFIG_PATH = join(openclawStateDir, 'openclaw.json')
const config = `{
// JSON5 comments + trailing commas supported
agents: {
defaults: { workspace: '~/clawd-main', },
list: [
{ id: 'work', name: 'Work Bot', workspace: '~/clawd-work', },
{ id: 'family', workspace: '~/clawd-family', },
],
},
// legacy entries still supported
agent: { workspace: '~/clawd-legacy', },
routing: {
agents: {
work: { name: 'Work Bot', workspace: '~/clawd-work', },
family: { workspace: '~/clawd-family' },
},
},
skills: {
load: { extraDirs: ['~/shared/skills', '/opt/skills',], },
},
}`
await writeFile(configPath, config, 'utf8')
const { roots, labels } = await resolveClawdbotSkillRoots()
const expectedRoots = [
resolve(stateDir, 'skills'),
resolve(openclawStateDir, 'skills'),
resolve(home, 'clawd-main', 'skills'),
resolve(home, 'clawd-work', 'skills'),
resolve(home, 'clawd-family', 'skills'),
resolve(home, 'shared', 'skills'),
resolve('/opt/skills'),
]
expect(roots).toEqual(expect.arrayContaining(expectedRoots))
expect(labels[resolve(stateDir, 'skills')]).toBe('Shared skills')
expect(labels[resolve(openclawStateDir, 'skills')]).toBe('OpenClaw: Shared skills')
expect(labels[resolve(home, 'clawd-main', 'skills')]).toBe('Agent: main')
expect(labels[resolve(home, 'clawd-work', 'skills')]).toBe('Agent: Work Bot')
expect(labels[resolve(home, 'clawd-family', 'skills')]).toBe('Agent: family')
expect(labels[resolve(home, 'shared', 'skills')]).toBe('Extra: skills')
expect(labels[resolve('/opt/skills')]).toBe('Extra: skills')
})
it('resolves default workspace from agents.defaults and agents.list', async () => {
const base = await mkdtemp(join(tmpdir(), 'clawhub-clawdbot-default-'))
const home = join(base, 'home')
const stateDir = join(base, 'state')
const configPath = join(base, 'clawdbot.json')
const workspaceMain = join(base, 'workspace-main')
const workspaceList = join(base, 'workspace-list')
const openclawStateDir = join(base, 'openclaw-state')
process.env.HOME = home
process.env.CLAWDBOT_STATE_DIR = stateDir
process.env.CLAWDBOT_CONFIG_PATH = configPath
process.env.OPENCLAW_STATE_DIR = openclawStateDir
process.env.OPENCLAW_CONFIG_PATH = join(openclawStateDir, 'openclaw.json')
const config = `{
agents: {
defaults: { workspace: "${workspaceMain}", },
list: [
{ id: 'main', workspace: "${workspaceList}", default: true },
],
},
}`
await writeFile(configPath, config, 'utf8')
const workspace = await resolveClawdbotDefaultWorkspace()
expect(workspace).toBe(resolve(workspaceMain))
})
it('falls back to default agent in agents.list when defaults missing', async () => {
const base = await mkdtemp(join(tmpdir(), 'clawhub-clawdbot-list-'))
const home = join(base, 'home')
const configPath = join(base, 'clawdbot.json')
const workspaceMain = join(base, 'workspace-main')
const workspaceWork = join(base, 'workspace-work')
const openclawStateDir = join(base, 'openclaw-state')
process.env.HOME = home
process.env.CLAWDBOT_CONFIG_PATH = configPath
process.env.OPENCLAW_STATE_DIR = openclawStateDir
process.env.OPENCLAW_CONFIG_PATH = join(openclawStateDir, 'openclaw.json')
const config = `{
agents: {
list: [
{ id: 'main', workspace: "${workspaceMain}", default: true },
{ id: 'work', workspace: "${workspaceWork}" },
],
},
}`
await writeFile(configPath, config, 'utf8')
const workspace = await resolveClawdbotDefaultWorkspace()
expect(workspace).toBe(resolve(workspaceMain))
})
it('respects CLAWDBOT_STATE_DIR and CLAWDBOT_CONFIG_PATH overrides', async () => {
const base = await mkdtemp(join(tmpdir(), 'clawhub-clawdbot-override-'))
const home = join(base, 'home')
const stateDir = join(base, 'custom-state')
const configPath = join(base, 'config', 'clawdbot.json')
const openclawStateDir = join(base, 'openclaw-state')
process.env.HOME = home
process.env.CLAWDBOT_STATE_DIR = stateDir
process.env.CLAWDBOT_CONFIG_PATH = configPath
process.env.OPENCLAW_STATE_DIR = openclawStateDir
process.env.OPENCLAW_CONFIG_PATH = join(openclawStateDir, 'openclaw.json')
const config = `{
agent: { workspace: "${join(base, 'workspace-main')}" },
}`
await mkdir(join(base, 'config'), { recursive: true })
await writeFile(configPath, config, 'utf8')
const { roots, labels } = await resolveClawdbotSkillRoots()
expect(roots).toEqual(
expect.arrayContaining([
resolve(stateDir, 'skills'),
resolve(openclawStateDir, 'skills'),
resolve(join(base, 'workspace-main'), 'skills'),
]),
)
expect(labels[resolve(stateDir, 'skills')]).toBe('Shared skills')
expect(labels[resolve(openclawStateDir, 'skills')]).toBe('OpenClaw: Shared skills')
expect(labels[resolve(join(base, 'workspace-main'), 'skills')]).toBe('Agent: main')
})
it('returns shared skills root when config is missing', async () => {
const base = await mkdtemp(join(tmpdir(), 'clawhub-clawdbot-missing-'))
const stateDir = join(base, 'state')
const configPath = join(base, 'missing', 'clawdbot.json')
const openclawStateDir = join(base, 'openclaw-state')
process.env.CLAWDBOT_STATE_DIR = stateDir
process.env.CLAWDBOT_CONFIG_PATH = configPath
process.env.OPENCLAW_STATE_DIR = openclawStateDir
process.env.OPENCLAW_CONFIG_PATH = join(openclawStateDir, 'openclaw.json')
const { roots, labels } = await resolveClawdbotSkillRoots()
expect(roots).toEqual([resolve(stateDir, 'skills'), resolve(openclawStateDir, 'skills')])
expect(labels[resolve(stateDir, 'skills')]).toBe('Shared skills')
expect(labels[resolve(openclawStateDir, 'skills')]).toBe('OpenClaw: Shared skills')
})
it('supports OpenClaw configuration files', async () => {
const base = await mkdtemp(join(tmpdir(), 'clawhub-openclaw-'))
const stateDir = join(base, 'openclaw-state')
const workspace = join(base, 'openclaw-main')
const configPath = join(stateDir, 'openclaw.json')
process.env.OPENCLAW_STATE_DIR = stateDir
await mkdir(stateDir, { recursive: true })
const config = `{
agents: {
defaults: { workspace: "${workspace}", },
},
}`
await writeFile(configPath, config, 'utf8')
const { roots, labels } = await resolveClawdbotSkillRoots()
expect(roots).toEqual(
expect.arrayContaining([resolve(stateDir, 'skills'), resolve(workspace, 'skills')]),
)
expect(labels[resolve(stateDir, 'skills')]).toBe('OpenClaw: Shared skills')
expect(labels[resolve(workspace, 'skills')]).toBe('OpenClaw: Agent: main')
})
})
+203
View File
@@ -0,0 +1,203 @@
import { readFile } from 'node:fs/promises'
import { homedir } from 'node:os'
import { basename, join, resolve } from 'node:path'
import JSON5 from 'json5'
type ClawdbotConfig = {
agent?: { workspace?: string }
agents?: {
defaults?: { workspace?: string }
list?: Array<{
id?: string
name?: string
workspace?: string
default?: boolean
}>
}
routing?: {
agents?: Record<
string,
{
name?: string
workspace?: string
}
>
}
skills?: {
load?: {
extraDirs?: string[]
}
}
}
export type ClawdbotSkillRoots = {
roots: string[]
labels: Record<string, string>
}
export async function resolveClawdbotSkillRoots(): Promise<ClawdbotSkillRoots> {
const roots: string[] = []
const labels: Record<string, string> = {}
const clawdbotStateDir = resolveClawdbotStateDir()
const sharedSkills = resolveUserPath(join(clawdbotStateDir, 'skills'))
pushRoot(roots, labels, sharedSkills, 'Shared skills')
const openclawStateDir = resolveOpenclawStateDir()
const openclawShared = resolveUserPath(join(openclawStateDir, 'skills'))
pushRoot(roots, labels, openclawShared, 'OpenClaw: Shared skills')
const [clawdbotConfig, openclawConfig] = await Promise.all([
readClawdbotConfig(),
readOpenclawConfig(),
])
if (!clawdbotConfig && !openclawConfig) return { roots, labels }
if (clawdbotConfig) {
addConfigRoots(clawdbotConfig, roots, labels)
}
if (openclawConfig) {
addConfigRoots(openclawConfig, roots, labels, 'OpenClaw')
}
return { roots, labels }
}
export async function resolveClawdbotDefaultWorkspace(): Promise<string | null> {
const config = await readClawdbotConfig()
const openclawConfig = await readOpenclawConfig()
if (!config && !openclawConfig) return null
const defaultsWorkspace = resolveUserPath(
config?.agents?.defaults?.workspace ?? config?.agent?.workspace ?? '',
)
if (defaultsWorkspace) return defaultsWorkspace
const listedAgents = config?.agents?.list ?? []
const defaultAgent =
listedAgents.find((entry) => entry.default) ?? listedAgents.find((entry) => entry.id === 'main')
const listWorkspace = resolveUserPath(defaultAgent?.workspace ?? '')
if (listWorkspace) return listWorkspace
if (!openclawConfig) return null
const openclawDefaults = resolveUserPath(
openclawConfig.agents?.defaults?.workspace ?? openclawConfig.agent?.workspace ?? '',
)
if (openclawDefaults) return openclawDefaults
const openclawAgents = openclawConfig.agents?.list ?? []
const openclawDefaultAgent =
openclawAgents.find((entry) => entry.default) ??
openclawAgents.find((entry) => entry.id === 'main')
const openclawWorkspace = resolveUserPath(openclawDefaultAgent?.workspace ?? '')
return openclawWorkspace || null
}
function resolveClawdbotStateDir() {
const override = process.env.CLAWDBOT_STATE_DIR?.trim()
if (override) return resolveUserPath(override)
return join(homedir(), '.clawdbot')
}
function resolveClawdbotConfigPath() {
const override = process.env.CLAWDBOT_CONFIG_PATH?.trim()
if (override) return resolveUserPath(override)
return join(resolveClawdbotStateDir(), 'clawdbot.json')
}
function resolveOpenclawStateDir() {
const override = process.env.OPENCLAW_STATE_DIR?.trim()
if (override) return resolveUserPath(override)
return join(homedir(), '.openclaw')
}
function resolveOpenclawConfigPath() {
const override = process.env.OPENCLAW_CONFIG_PATH?.trim()
if (override) return resolveUserPath(override)
return join(resolveOpenclawStateDir(), 'openclaw.json')
}
function resolveUserPath(input: string) {
const trimmed = input.trim()
if (!trimmed) return ''
if (trimmed.startsWith('~')) {
return resolve(trimmed.replace(/^~(?=$|[\\/])/, homedir()))
}
return resolve(trimmed)
}
async function readClawdbotConfig(): Promise<ClawdbotConfig | null> {
return readConfigFile(resolveClawdbotConfigPath())
}
async function readOpenclawConfig(): Promise<ClawdbotConfig | null> {
return readConfigFile(resolveOpenclawConfigPath())
}
async function readConfigFile(path: string): Promise<ClawdbotConfig | null> {
try {
const raw = await readFile(path, 'utf8')
const parsed = JSON5.parse(raw)
if (!parsed || typeof parsed !== 'object') return null
return parsed as ClawdbotConfig
} catch {
return null
}
}
function addConfigRoots(
config: ClawdbotConfig,
roots: string[],
labels: Record<string, string>,
labelPrefix?: string,
) {
const prefix = labelPrefix ? `${labelPrefix}: ` : ''
const mainWorkspace = resolveUserPath(
config.agents?.defaults?.workspace ?? config.agent?.workspace ?? '',
)
if (mainWorkspace) {
pushRoot(roots, labels, join(mainWorkspace, 'skills'), `${prefix}Agent: main`)
}
const listedAgents = config.agents?.list ?? []
for (const entry of listedAgents) {
const workspace = resolveUserPath(entry?.workspace ?? '')
if (!workspace) continue
const name = entry?.name?.trim() || entry?.id?.trim() || 'agent'
pushRoot(roots, labels, join(workspace, 'skills'), `${prefix}Agent: ${name}`)
}
const agents = config.routing?.agents ?? {}
for (const [agentId, entry] of Object.entries(agents)) {
const workspace = resolveUserPath(entry?.workspace ?? '')
if (!workspace) continue
const name = entry?.name?.trim() || agentId
pushRoot(roots, labels, join(workspace, 'skills'), `${prefix}Agent: ${name}`)
}
const extraDirs = config.skills?.load?.extraDirs ?? []
for (const dir of extraDirs) {
const resolved = resolveUserPath(String(dir))
if (!resolved) continue
const label = `${prefix}Extra: ${basename(resolved) || resolved}`
pushRoot(roots, labels, resolved, label)
}
}
function pushRoot(roots: string[], labels: Record<string, string>, root: string, label?: string) {
const resolved = resolveUserPath(root)
if (!resolved) return
if (!roots.includes(resolved)) roots.push(resolved)
if (!label) return
const existing = labels[resolved]
if (!existing) {
labels[resolved] = label
return
}
const parts = existing
.split(', ')
.map((part) => part.trim())
.filter(Boolean)
if (parts.includes(label)) return
labels[resolved] = `${existing}, ${label}`
}
@@ -47,7 +47,7 @@ export async function cmdLogin(
) {
if (!tokenFlag && !inputAllowed) fail('Token required (use --token or remove --no-input)')
const token = tokenFlag || (await promptHidden('MoltHub token: '))
const token = tokenFlag || (await promptHidden('OpenClaw token: '))
if (!token) fail('Token required')
const registry = await getRegistry(opts, { cache: true })
@@ -79,7 +79,7 @@ export async function cmdLogout(opts: GlobalOpts) {
export async function cmdWhoami(opts: GlobalOpts) {
const cfg = await readGlobalConfig()
const token = cfg?.token
if (!token) fail('Not logged in. Run: molthub login')
if (!token) fail('Not logged in. Run: clawhub login')
const registry = await getRegistry(opts, { cache: true })
const spinner = createSpinner('Checking token')
@@ -4,11 +4,11 @@ import { afterEach, describe, expect, it, vi } from 'vitest'
import type { GlobalOpts } from '../types'
vi.mock('../../config.js', () => ({
readGlobalConfig: vi.fn(async () => ({ registry: 'https://molthub.com', token: 'tkn' })),
readGlobalConfig: vi.fn(async () => ({ registry: 'https://clawhub.ai', token: 'tkn' })),
}))
vi.mock('../registry.js', () => ({
getRegistry: vi.fn(async () => 'https://molthub.com'),
getRegistry: vi.fn(async () => 'https://clawhub.ai'),
}))
const mockApiRequest = vi.fn()
@@ -35,8 +35,8 @@ function makeOpts(): GlobalOpts {
return {
workdir: '/work',
dir: '/work/skills',
site: 'https://molthub.com',
registry: 'https://molthub.com',
site: 'https://clawhub.ai',
registry: 'https://clawhub.ai',
registrySource: 'default',
}
}
@@ -8,7 +8,7 @@ import { createSpinner, fail, formatError, isInteractive, promptConfirm } from '
async function requireToken() {
const cfg = await readGlobalConfig()
const token = cfg?.token
if (!token) fail('Not logged in. Run: molthub login')
if (!token) fail('Not logged in. Run: clawhub login')
return token
}
@@ -7,10 +7,10 @@ import { afterEach, describe, expect, it, vi } from 'vitest'
import type { GlobalOpts } from '../types'
vi.mock('../../config.js', () => ({
readGlobalConfig: vi.fn(async () => ({ registry: 'https://molthub.com', token: 'tkn' })),
readGlobalConfig: vi.fn(async () => ({ registry: 'https://clawhub.ai', token: 'tkn' })),
}))
const mockGetRegistry = vi.fn(async (_opts: unknown, _params?: unknown) => 'https://molthub.com')
const mockGetRegistry = vi.fn(async (_opts: unknown, _params?: unknown) => 'https://clawhub.ai')
vi.mock('../registry.js', () => ({
getRegistry: (opts: unknown, params?: unknown) => mockGetRegistry(opts, params),
}))
@@ -34,7 +34,7 @@ vi.mock('../ui.js', () => ({
const { cmdPublish } = await import('./publish')
async function makeTmpWorkdir() {
const root = await mkdtemp(join(tmpdir(), 'molthub-publish-'))
const root = await mkdtemp(join(tmpdir(), 'clawhub-publish-'))
return root
}
@@ -42,8 +42,8 @@ function makeOpts(workdir: string): GlobalOpts {
return {
workdir,
dir: join(workdir, 'skills'),
site: 'https://molthub.com',
registry: 'https://molthub.com',
site: 'https://clawhub.ai',
registry: 'https://clawhub.ai',
registrySource: 'default',
}
}
@@ -29,7 +29,7 @@ export async function cmdPublish(
const cfg = await readGlobalConfig()
const token = cfg?.token
if (!token) fail('Not logged in. Run: molthub login')
if (!token) fail('Not logged in. Run: clawhub login')
const registry = await getRegistry(opts, { cache: true })
const slug = options.slug ?? sanitizeSlug(basename(folder))
@@ -11,7 +11,7 @@ vi.mock('../../http.js', () => ({
downloadZip: (...args: unknown[]) => mockDownloadZip(...args),
}))
const mockGetRegistry = vi.fn(async () => 'https://molthub.com')
const mockGetRegistry = vi.fn(async () => 'https://clawhub.ai')
vi.mock('../registry.js', () => ({
getRegistry: () => mockGetRegistry(),
}))
@@ -68,8 +68,8 @@ function makeOpts(): GlobalOpts {
return {
workdir: '/work',
dir: '/work/skills',
site: 'https://molthub.com',
registry: 'https://molthub.com',
site: 'https://clawhub.ai',
registry: 'https://clawhub.ai',
registrySource: 'default',
}
}
@@ -8,7 +8,7 @@ import { createSpinner, fail, formatError, isInteractive, promptConfirm } from '
async function requireToken() {
const cfg = await readGlobalConfig()
const token = cfg?.token
if (!token) fail('Not logged in. Run: molthub login')
if (!token) fail('Not logged in. Run: clawhub login')
return token
}
@@ -27,10 +27,10 @@ vi.mock('@clack/prompts', () => ({
}))
vi.mock('../../config.js', () => ({
readGlobalConfig: vi.fn(async () => ({ registry: 'https://molthub.com', token: 'tkn' })),
readGlobalConfig: vi.fn(async () => ({ registry: 'https://clawhub.ai', token: 'tkn' })),
}))
const mockGetRegistry = vi.fn(async () => 'https://molthub.com')
const mockGetRegistry = vi.fn(async () => 'https://clawhub.ai')
vi.mock('../registry.js', () => ({
getRegistry: () => mockGetRegistry(),
}))
@@ -57,15 +57,15 @@ vi.mock('../scanSkills.js', () => ({
getFallbackSkillRoots: vi.fn(() => []),
}))
const mockResolveMoltbotSkillRoots = vi.fn(
const mockResolveClawdbotSkillRoots = vi.fn(
async () =>
({
roots: [] as string[],
labels: {} as Record<string, string>,
}) as const,
)
vi.mock('../moltbotConfig.js', () => ({
resolveMoltbotSkillRoots: () => mockResolveMoltbotSkillRoots(),
vi.mock('../clawdbotConfig.js', () => ({
resolveClawdbotSkillRoots: () => mockResolveClawdbotSkillRoots(),
}))
vi.mock('../../skills.js', async () => {
@@ -89,8 +89,8 @@ function makeOpts(): GlobalOpts {
return {
workdir: '/work',
dir: '/work/skills',
site: 'https://molthub.com',
registry: 'https://molthub.com',
site: 'https://clawhub.ai',
registry: 'https://clawhub.ai',
registrySource: 'default',
}
}
@@ -230,9 +230,9 @@ describe('cmdSync', () => {
expect(output).toMatch(/dup-skill/)
})
it('prints labeled roots when moltbot roots are detected', async () => {
it('prints labeled roots when clawdbot roots are detected', async () => {
interactive = false
mockResolveMoltbotSkillRoots.mockResolvedValueOnce({
mockResolveClawdbotSkillRoots.mockResolvedValueOnce({
roots: ['/auto'],
labels: { '/auto': 'Agent: Work' },
})
@@ -290,9 +290,9 @@ describe('cmdSync', () => {
expect(update.changelog).toBe('')
})
it('skips telemetry when MOLTHUB_DISABLE_TELEMETRY is set', async () => {
it('skips telemetry when CLAWHUB_DISABLE_TELEMETRY is set', async () => {
interactive = false
process.env.MOLTHUB_DISABLE_TELEMETRY = '1'
process.env.CLAWHUB_DISABLE_TELEMETRY = '1'
mockApiRequest.mockImplementation(async (_registry: string, args: { path: string }) => {
if (args.path === '/api/v1/whoami') return { user: { handle: 'steipete' } }
if (args.path.startsWith('/api/v1/resolve?')) {
@@ -305,6 +305,6 @@ describe('cmdSync', () => {
expect(
mockApiRequest.mock.calls.some((call) => call[1]?.path === '/api/cli/telemetry/sync'),
).toBe(false)
delete process.env.MOLTHUB_DISABLE_TELEMETRY
delete process.env.CLAWHUB_DISABLE_TELEMETRY
})
})
@@ -1,7 +1,7 @@
import { intro, outro } from '@clack/prompts'
import { readGlobalConfig } from '../../config.js'
import { hashSkillFiles, listTextFiles, readSkillOrigin } from '../../skills.js'
import { resolveMoltbotSkillRoots } from '../moltbotConfig.js'
import { resolveClawdbotSkillRoots } from '../clawdbotConfig.js'
import { getFallbackSkillRoots } from '../scanSkills.js'
import type { GlobalOpts } from '../types.js'
import { createSpinner, fail, formatError, isInteractive } from '../ui.js'
@@ -30,22 +30,22 @@ import type { Candidate, LocalSkill, SyncOptions } from './syncTypes.js'
export async function cmdSync(opts: GlobalOpts, options: SyncOptions, inputAllowed: boolean) {
const allowPrompt = isInteractive() && inputAllowed !== false
intro('MoltHub sync')
intro('OpenClaw sync')
const cfg = await readGlobalConfig()
const token = cfg?.token
if (!token) fail('Not logged in. Run: molthub login')
if (!token) fail('Not logged in. Run: clawhub login')
const registry = await getRegistryWithAuth(opts, token)
const selectedRoots = buildScanRoots(opts, options.root)
const moltbotRoots = await resolveMoltbotSkillRoots()
const clawdbotRoots = await resolveClawdbotSkillRoots()
const combinedRoots = Array.from(
new Set([...selectedRoots, ...moltbotRoots.roots].map((root) => root.trim()).filter(Boolean)),
new Set([...selectedRoots, ...clawdbotRoots.roots].map((root) => root.trim()).filter(Boolean)),
)
const concurrency = normalizeConcurrency(options.concurrency)
const spinner = createSpinner('Scanning for local skills')
const primaryScan = await scanRootsWithLabels(combinedRoots, moltbotRoots.labels)
const primaryScan = await scanRootsWithLabels(combinedRoots, clawdbotRoots.labels)
let scan = primaryScan
let telemetryScan = primaryScan
if (primaryScan.skills.length === 0) {
@@ -55,7 +55,7 @@ export async function cmdSync(opts: GlobalOpts, options: SyncOptions, inputAllow
telemetryScan = mergeScan(primaryScan, fallbackScan)
scan = fallbackScan
if (fallbackScan.skills.length === 0)
fail('No skills found (checked workdir and known Moltbot/Molt locations)')
fail('No skills found (checked workdir and known Clawdis/Clawd locations)')
printSection(
`No skills in workdir. Found ${fallbackScan.skills.length} in fallback locations.`,
formatList(fallbackScan.rootsWithSkills, 10),
@@ -58,7 +58,7 @@ export async function reportTelemetryIfEnabled(params: {
}
function isTelemetryDisabled() {
const raw = process.env.MOLTHUB_DISABLE_TELEMETRY
const raw = process.env.CLAWHUB_DISABLE_TELEMETRY ?? process.env.CLAWDHUB_DISABLE_TELEMETRY
if (!raw) return false
return ['1', 'true', 'yes', 'on'].includes(raw.trim().toLowerCase())
}
@@ -8,7 +8,7 @@ import { createSpinner, fail, formatError, isInteractive, promptConfirm } from '
async function requireToken() {
const cfg = await readGlobalConfig()
const token = cfg?.token
if (!token) fail('Not logged in. Run: molthub login')
if (!token) fail('Not logged in. Run: clawhub login')
return token
}
@@ -22,7 +22,7 @@ function makeOpts(overrides: Partial<GlobalOpts> = {}): GlobalOpts {
return {
workdir: '/work',
dir: '/work/skills',
site: 'https://molthub.com',
site: 'https://clawhub.ai',
registry: DEFAULT_REGISTRY,
registrySource: 'default',
...overrides,
@@ -37,8 +37,8 @@ beforeEach(() => {
describe('registry resolution', () => {
it('prefers explicit registry over discovery/cache', async () => {
readGlobalConfig.mockResolvedValue({ registry: 'https://auth.molthub.com' })
discoverRegistryFromSite.mockResolvedValue({ apiBase: 'https://molthub.com' })
readGlobalConfig.mockResolvedValue({ registry: 'https://auth.clawdhub.com' })
discoverRegistryFromSite.mockResolvedValue({ apiBase: 'https://clawhub.ai' })
const registry = await resolveRegistry(
makeOpts({ registry: 'https://custom.example', registrySource: 'cli' }),
@@ -49,14 +49,14 @@ describe('registry resolution', () => {
})
it('ignores legacy registry and updates cache from discovery', async () => {
readGlobalConfig.mockResolvedValue({ registry: 'https://auth.molthub.com', token: 'tkn' })
discoverRegistryFromSite.mockResolvedValue({ apiBase: 'https://molthub.com' })
readGlobalConfig.mockResolvedValue({ registry: 'https://auth.clawdhub.com', token: 'tkn' })
discoverRegistryFromSite.mockResolvedValue({ apiBase: 'https://clawhub.ai' })
const registry = await getRegistry(makeOpts(), { cache: true })
expect(registry).toBe('https://molthub.com')
expect(registry).toBe('https://clawhub.ai')
expect(writeGlobalConfig).toHaveBeenCalledWith({
registry: 'https://molthub.com',
registry: 'https://clawhub.ai',
token: 'tkn',
})
})
@@ -2,9 +2,9 @@ import { readGlobalConfig, writeGlobalConfig } from '../config.js'
import { discoverRegistryFromSite } from '../discovery.js'
import type { GlobalOpts } from './types.js'
export const DEFAULT_SITE = 'https://molthub.com'
export const DEFAULT_REGISTRY = 'https://molthub.com'
const LEGACY_REGISTRY_HOSTS = new Set(['auth.molthub.com'])
export const DEFAULT_SITE = 'https://clawhub.ai'
export const DEFAULT_REGISTRY = 'https://clawhub.ai'
const LEGACY_REGISTRY_HOSTS = new Set(['auth.clawdhub.com', 'auth.clawhub.com', 'auth.clawhub.ai'])
export async function resolveRegistry(opts: GlobalOpts) {
const explicit = opts.registrySource !== 'default' ? opts.registry.trim() : ''
@@ -7,7 +7,7 @@ import { describe, expect, it } from 'vitest'
import { findSkillFolders, getFallbackSkillRoots } from './scanSkills'
async function makeTmpDir() {
return mkdtemp(join(tmpdir(), 'molthub-scan-'))
return mkdtemp(join(tmpdir(), 'clawhub-scan-'))
}
describe('scanSkills', () => {
@@ -57,8 +57,10 @@ describe('scanSkills', () => {
it('includes known legacy roots', () => {
const roots = getFallbackSkillRoots('/tmp/anywhere')
expect(roots.some((p) => p.endsWith('/moltbot/skills'))).toBe(true)
expect(roots.some((p) => p.endsWith('/molt/skills'))).toBe(true)
expect(roots.some((p) => p.endsWith('/clawdis/skills'))).toBe(true)
expect(roots.some((p) => p.endsWith('/clawd/skills'))).toBe(true)
expect(roots.some((p) => p.endsWith('/clawdbot/skills'))).toBe(true)
expect(roots.some((p) => p.endsWith('/openclaw/skills'))).toBe(true)
expect(roots.some((p) => p.endsWith('/moltbot/skills'))).toBe(true)
})
})
@@ -33,21 +33,35 @@ export function getFallbackSkillRoots(workdir: string) {
const home = homedir()
const roots = [
// adjacent repo installs
resolve(workdir, '..', 'moltbot', 'skills'),
resolve(workdir, '..', 'moltbot', 'Skills'),
resolve(workdir, '..', 'clawdis', 'skills'),
resolve(workdir, '..', 'clawdis', 'Skills'),
resolve(workdir, '..', 'clawdbot', 'skills'),
resolve(workdir, '..', 'clawdbot', 'Skills'),
resolve(workdir, '..', 'openclaw', 'skills'),
resolve(workdir, '..', 'openclaw', 'Skills'),
resolve(workdir, '..', 'moltbot', 'skills'),
resolve(workdir, '..', 'moltbot', 'Skills'),
// legacy locations
resolve(home, 'molt', 'skills'),
resolve(home, 'molt', 'Skills'),
resolve(home, '.molt', 'skills'),
resolve(home, '.molt', 'Skills'),
resolve(home, 'clawd', 'skills'),
resolve(home, 'clawd', 'Skills'),
resolve(home, '.clawd', 'skills'),
resolve(home, '.clawd', 'Skills'),
resolve(home, 'moltbot', 'skills'),
resolve(home, 'moltbot', 'Skills'),
resolve(home, '.moltbot', 'skills'),
resolve(home, '.moltbot', 'Skills'),
resolve(home, 'clawdbot', 'skills'),
resolve(home, 'clawdbot', 'Skills'),
resolve(home, '.clawdbot', 'skills'),
resolve(home, '.clawdbot', 'Skills'),
resolve(home, 'clawdis', 'skills'),
resolve(home, 'clawdis', 'Skills'),
resolve(home, '.clawdis', 'skills'),
resolve(home, '.clawdis', 'Skills'),
resolve(home, 'openclaw', 'skills'),
resolve(home, 'openclaw', 'Skills'),
resolve(home, '.openclaw', 'skills'),
resolve(home, '.openclaw', 'Skills'),
resolve(home, 'moltbot', 'skills'),
resolve(home, 'moltbot', 'Skills'),
@@ -55,8 +69,12 @@ export function getFallbackSkillRoots(workdir: string) {
resolve(home, '.moltbot', 'Skills'),
// macOS App Support legacy
resolve(home, 'Library', 'Application Support', 'moltbot', 'skills'),
resolve(home, 'Library', 'Application Support', 'moltbot', 'Skills'),
resolve(home, 'Library', 'Application Support', 'clawdbot', 'skills'),
resolve(home, 'Library', 'Application Support', 'clawdbot', 'Skills'),
resolve(home, 'Library', 'Application Support', 'clawdis', 'skills'),
resolve(home, 'Library', 'Application Support', 'clawdis', 'Skills'),
resolve(home, 'Library', 'Application Support', 'openclaw', 'skills'),
resolve(home, 'Library', 'Application Support', 'openclaw', 'Skills'),
resolve(home, 'Library', 'Application Support', 'moltbot', 'skills'),
resolve(home, 'Library', 'Application Support', 'moltbot', 'Skills'),
]
+58
View File
@@ -0,0 +1,58 @@
import { existsSync } from 'node:fs'
import { mkdir, readFile, writeFile } from 'node:fs/promises'
import { homedir } from 'node:os'
import { dirname, join, resolve } from 'node:path'
import { type GlobalConfig, GlobalConfigSchema, parseArk } from './schema/index.js'
export function getGlobalConfigPath() {
const override =
process.env.CLAWHUB_CONFIG_PATH?.trim() ?? process.env.CLAWDHUB_CONFIG_PATH?.trim()
if (override) return resolve(override)
const home = homedir()
if (process.platform === 'darwin') {
const clawhubPath = join(home, 'Library', 'Application Support', 'clawhub', 'config.json')
const clawdhubPath = join(home, 'Library', 'Application Support', 'clawdhub', 'config.json')
if (existsSync(clawhubPath)) return clawhubPath
if (existsSync(clawdhubPath)) return clawdhubPath
return clawhubPath
}
const xdg = process.env.XDG_CONFIG_HOME
if (xdg) {
const clawhubPath = join(xdg, 'clawhub', 'config.json')
const clawdhubPath = join(xdg, 'clawdhub', 'config.json')
if (existsSync(clawhubPath)) return clawhubPath
if (existsSync(clawdhubPath)) return clawdhubPath
return clawhubPath
}
if (process.platform === 'win32') {
const appData = process.env.APPDATA
if (appData) {
const clawhubPath = join(appData, 'clawhub', 'config.json')
const clawdhubPath = join(appData, 'clawdhub', 'config.json')
if (existsSync(clawhubPath)) return clawhubPath
if (existsSync(clawdhubPath)) return clawdhubPath
return clawhubPath
}
}
const clawhubPath = join(home, '.config', 'clawhub', 'config.json')
const clawdhubPath = join(home, '.config', 'clawdhub', 'config.json')
if (existsSync(clawhubPath)) return clawhubPath
if (existsSync(clawdhubPath)) return clawdhubPath
return clawhubPath
}
export async function readGlobalConfig(): Promise<GlobalConfig | null> {
try {
const raw = await readFile(getGlobalConfigPath(), 'utf8')
const parsed = JSON.parse(raw) as unknown
return parseArk(GlobalConfigSchema, parsed, 'Global config')
} catch {
return null
}
}
export async function writeGlobalConfig(config: GlobalConfig) {
const path = getGlobalConfigPath()
await mkdir(dirname(path), { recursive: true })
await writeFile(path, `${JSON.stringify(config, null, 2)}\n`, 'utf8')
}
+23
View File
@@ -0,0 +1,23 @@
import { parseArk, WellKnownConfigSchema } from './schema/index.js'
export async function discoverRegistryFromSite(siteUrl: string) {
const paths = ['/.well-known/clawhub.json', '/.well-known/clawdhub.json']
for (const path of paths) {
const url = new URL(path, siteUrl)
const response = await fetch(url.toString(), {
method: 'GET',
headers: { Accept: 'application/json' },
})
if (!response.ok) continue
const raw = (await response.json()) as unknown
const parsed = parseArk(WellKnownConfigSchema, raw, 'WellKnown config')
const apiBase = 'apiBase' in parsed ? parsed.apiBase : parsed.registry
if (!apiBase) return null
return {
apiBase,
authBase: parsed.authBase,
minCliVersion: parsed.minCliVersion,
}
}
return null
}
@@ -202,7 +202,7 @@ async function fetchJsonFormViaCurl(url: string, args: FormRequestArgs) {
headers.push('-H', `Authorization: Bearer ${args.token}`)
}
const tempDir = await mkdtemp(join(tmpdir(), 'molthub-upload-'))
const tempDir = await mkdtemp(join(tmpdir(), 'clawhub-upload-'))
try {
const formArgs: string[] = []
for (const [key, value] of args.form.entries()) {
@@ -255,7 +255,7 @@ async function fetchJsonFormViaCurl(url: string, args: FormRequestArgs) {
}
async function fetchBinaryViaCurl(url: string) {
const tempDir = await mkdtemp(join(tmpdir(), 'molthub-download-'))
const tempDir = await mkdtemp(join(tmpdir(), 'clawhub-download-'))
const filePath = join(tempDir, 'payload.bin')
try {
const curlArgs = [
@@ -239,22 +239,22 @@ export const SkillInstallSpecSchema = type({
})
export type SkillInstallSpec = (typeof SkillInstallSpecSchema)[inferred]
export const MoltbotRequiresSchema = type({
export const ClawdisRequiresSchema = type({
bins: 'string[]?',
anyBins: 'string[]?',
env: 'string[]?',
config: 'string[]?',
})
export type MoltbotRequires = (typeof MoltbotRequiresSchema)[inferred]
export type ClawdisRequires = (typeof ClawdisRequiresSchema)[inferred]
export const MoltbotSkillMetadataSchema = type({
export const ClawdisSkillMetadataSchema = type({
always: 'boolean?',
skillKey: 'string?',
primaryEnv: 'string?',
emoji: 'string?',
homepage: 'string?',
os: 'string[]?',
requires: MoltbotRequiresSchema.optional(),
requires: ClawdisRequiresSchema.optional(),
install: SkillInstallSpecSchema.array().optional(),
})
export type MoltbotSkillMetadata = (typeof MoltbotSkillMetadataSchema)[inferred]
export type ClawdisSkillMetadata = (typeof ClawdisSkillMetadataSchema)[inferred]
@@ -4,7 +4,7 @@ import { describe, expect, it } from 'vitest'
import * as schema from '.'
import { isTextContentType, TEXT_FILE_EXTENSION_SET } from './textFiles'
describe('packages/molthub schema textFiles', () => {
describe('packages/clawhub schema textFiles', () => {
it('exports text-file extension set', () => {
expect(TEXT_FILE_EXTENSION_SET.has('md')).toBe(true)
expect(TEXT_FILE_EXTENSION_SET.has('exe')).toBe(false)
@@ -20,7 +20,7 @@ import {
describe('skills', () => {
it('extracts zip into directory and skips traversal', async () => {
const dir = await mkdtemp(join(tmpdir(), 'molthub-'))
const dir = await mkdtemp(join(tmpdir(), 'clawhub-'))
const zip = zipSync({
'SKILL.md': strToU8('hello'),
'../evil.txt': strToU8('nope'),
@@ -32,7 +32,7 @@ describe('skills', () => {
})
it('writes and reads lockfile', async () => {
const workdir = await mkdtemp(join(tmpdir(), 'molthub-work-'))
const workdir = await mkdtemp(join(tmpdir(), 'clawhub-work-'))
await writeLockfile(workdir, {
version: 1,
skills: { demo: { version: '1.0.0', installedAt: 1 } },
@@ -42,18 +42,18 @@ describe('skills', () => {
})
it('returns empty lockfile on invalid json', async () => {
const workdir = await mkdtemp(join(tmpdir(), 'molthub-work-bad-'))
await mkdir(join(workdir, '.molthub'), { recursive: true })
await writeFile(join(workdir, '.molthub', 'lock.json'), '{', 'utf8')
const workdir = await mkdtemp(join(tmpdir(), 'clawhub-work-bad-'))
await mkdir(join(workdir, '.clawhub'), { recursive: true })
await writeFile(join(workdir, '.clawhub', 'lock.json'), '{', 'utf8')
const read = await readLockfile(workdir)
expect(read).toEqual({ version: 1, skills: {} })
})
it('returns empty lockfile on schema mismatch', async () => {
const workdir = await mkdtemp(join(tmpdir(), 'molthub-work-schema-'))
await mkdir(join(workdir, '.molthub'), { recursive: true })
const workdir = await mkdtemp(join(tmpdir(), 'clawhub-work-schema-'))
await mkdir(join(workdir, '.clawhub'), { recursive: true })
await writeFile(
join(workdir, '.molthub', 'lock.json'),
join(workdir, '.clawhub', 'lock.json'),
JSON.stringify({ version: 1, skills: 'nope' }),
'utf8',
)
@@ -62,7 +62,7 @@ describe('skills', () => {
})
it('skips dotfiles and node_modules when listing text files', async () => {
const workdir = await mkdtemp(join(tmpdir(), 'molthub-files-'))
const workdir = await mkdtemp(join(tmpdir(), 'clawhub-files-'))
await writeFile(join(workdir, 'SKILL.md'), 'hi', 'utf8')
await writeFile(join(workdir, '.secret.txt'), 'no', 'utf8')
await mkdir(join(workdir, 'node_modules'), { recursive: true })
@@ -71,10 +71,10 @@ describe('skills', () => {
expect(files.map((file) => file.relPath)).toEqual(['SKILL.md'])
})
it('respects .gitignore and .molthubignore', async () => {
const workdir = await mkdtemp(join(tmpdir(), 'molthub-ignore-'))
it('respects .gitignore and .clawhubignore', async () => {
const workdir = await mkdtemp(join(tmpdir(), 'clawhub-ignore-'))
await writeFile(join(workdir, '.gitignore'), 'ignored.md\n', 'utf8')
await writeFile(join(workdir, '.molthubignore'), 'private.md\n', 'utf8')
await writeFile(join(workdir, '.clawhubignore'), 'private.md\n', 'utf8')
await writeFile(join(workdir, 'SKILL.md'), 'hi', 'utf8')
await writeFile(join(workdir, 'ignored.md'), 'no', 'utf8')
await writeFile(join(workdir, 'private.md'), 'no', 'utf8')
@@ -90,7 +90,7 @@ describe('skills', () => {
})
it('falls back to text/plain for unknown text extensions', async () => {
const workdir = await mkdtemp(join(tmpdir(), 'molthub-env-'))
const workdir = await mkdtemp(join(tmpdir(), 'clawhub-env-'))
await writeFile(join(workdir, 'SKILL.md'), 'hi', 'utf8')
await writeFile(join(workdir, 'config.env'), 'TOKEN=demo', 'utf8')
const files = await listTextFiles(workdir)
@@ -147,26 +147,26 @@ describe('skills', () => {
})
it('returns null for invalid skill origin metadata', async () => {
const workdir = await mkdtemp(join(tmpdir(), 'molthub-origin-'))
const workdir = await mkdtemp(join(tmpdir(), 'clawhub-origin-'))
expect(await readSkillOrigin(workdir)).toBeNull()
await mkdir(join(workdir, '.molthub'), { recursive: true })
await mkdir(join(workdir, '.clawhub'), { recursive: true })
await writeFile(
join(workdir, '.molthub', 'origin.json'),
join(workdir, '.clawhub', 'origin.json'),
JSON.stringify({ version: 2 }),
'utf8',
)
expect(await readSkillOrigin(workdir)).toBeNull()
await writeFile(
join(workdir, '.molthub', 'origin.json'),
join(workdir, '.clawhub', 'origin.json'),
JSON.stringify({ version: 1, registry: 'demo', slug: 'x', installedAt: 1 }),
'utf8',
)
expect(await readSkillOrigin(workdir)).toBeNull()
await writeFile(
join(workdir, '.molthub', 'origin.json'),
join(workdir, '.clawhub', 'origin.json'),
JSON.stringify({
version: 1,
registry: 'demo',
@@ -6,6 +6,11 @@ import ignore from 'ignore'
import mime from 'mime'
import { type Lockfile, LockfileSchema, parseArk, TEXT_FILE_EXTENSION_SET } from './schema/index.js'
const DOT_DIR = '.clawhub'
const LEGACY_DOT_DIR = '.clawdhub'
const DOT_IGNORE = '.clawhubignore'
const LEGACY_DOT_IGNORE = '.clawdhubignore'
export type SkillOrigin = {
version: 1
registry: string
@@ -30,9 +35,10 @@ export async function listTextFiles(root: string) {
const files: Array<{ relPath: string; bytes: Uint8Array; contentType?: string }> = []
const absRoot = resolve(root)
const ig = ignore()
ig.add(['.git/', 'node_modules/', '.molthub/'])
ig.add(['.git/', 'node_modules/', `${DOT_DIR}/`, `${LEGACY_DOT_DIR}/`])
await addIgnoreFile(ig, join(absRoot, '.gitignore'))
await addIgnoreFile(ig, join(absRoot, '.molthubignore'))
await addIgnoreFile(ig, join(absRoot, DOT_IGNORE))
await addIgnoreFile(ig, join(absRoot, LEGACY_DOT_IGNORE))
await walk(absRoot, async (absPath) => {
const relPath = normalizePath(relative(absRoot, absPath))
@@ -87,44 +93,55 @@ export function hashSkillZip(zipBytes: Uint8Array) {
}
export async function readLockfile(workdir: string): Promise<Lockfile> {
const path = join(workdir, '.molthub', 'lock.json')
try {
const raw = await readFile(path, 'utf8')
const parsed = JSON.parse(raw) as unknown
return parseArk(LockfileSchema, parsed, 'Lockfile')
} catch {
return { version: 1, skills: {} }
const paths = [join(workdir, DOT_DIR, 'lock.json'), join(workdir, LEGACY_DOT_DIR, 'lock.json')]
for (const path of paths) {
try {
const raw = await readFile(path, 'utf8')
const parsed = JSON.parse(raw) as unknown
return parseArk(LockfileSchema, parsed, 'Lockfile')
} catch {
// try next
}
}
return { version: 1, skills: {} }
}
export async function writeLockfile(workdir: string, lock: Lockfile) {
const path = join(workdir, '.molthub', 'lock.json')
const path = join(workdir, DOT_DIR, 'lock.json')
await mkdir(dirname(path), { recursive: true })
await writeFile(path, `${JSON.stringify(lock, null, 2)}\n`, 'utf8')
}
export async function readSkillOrigin(skillFolder: string): Promise<SkillOrigin | null> {
const path = join(skillFolder, '.molthub', 'origin.json')
try {
const raw = await readFile(path, 'utf8')
const parsed = JSON.parse(raw) as Partial<SkillOrigin>
if (parsed.version !== 1) return null
if (!parsed.registry || !parsed.slug || !parsed.installedVersion) return null
if (typeof parsed.installedAt !== 'number' || !Number.isFinite(parsed.installedAt)) return null
return {
version: 1,
registry: String(parsed.registry),
slug: String(parsed.slug),
installedVersion: String(parsed.installedVersion),
installedAt: parsed.installedAt,
const paths = [
join(skillFolder, DOT_DIR, 'origin.json'),
join(skillFolder, LEGACY_DOT_DIR, 'origin.json'),
]
for (const path of paths) {
try {
const raw = await readFile(path, 'utf8')
const parsed = JSON.parse(raw) as Partial<SkillOrigin>
if (parsed.version !== 1) return null
if (!parsed.registry || !parsed.slug || !parsed.installedVersion) return null
if (typeof parsed.installedAt !== 'number' || !Number.isFinite(parsed.installedAt)) {
return null
}
return {
version: 1,
registry: String(parsed.registry),
slug: String(parsed.slug),
installedVersion: String(parsed.installedVersion),
installedAt: parsed.installedAt,
}
} catch {
// try next
}
} catch {
return null
}
return null
}
export async function writeSkillOrigin(skillFolder: string, origin: SkillOrigin) {
const path = join(skillFolder, '.molthub', 'origin.json')
const path = join(skillFolder, DOT_DIR, 'origin.json')
await mkdir(dirname(path), { recursive: true })
await writeFile(path, `${JSON.stringify(origin, null, 2)}\n`, 'utf8')
}
-57
View File
@@ -1,57 +0,0 @@
# `molthub`
MoltHub CLI — install, update, search, and publish agent skills as folders.
## Install
```bash
# From this repo (shortcut script at repo root)
bun molthub --help
# Once published to npm
# npm i -g molthub
```
## Auth (publish)
```bash
molthub login
# or
molthub auth login
# Headless / token paste
# or (token paste / headless)
molthub login --token clh_...
```
Notes:
- Browser login opens `https://molthub.com/cli/auth` and completes via a loopback callback.
- Token stored in `~/Library/Application Support/molthub/config.json` on macOS (override via `MOLTHUB_CONFIG_PATH`).
## Examples
```bash
molthub search "postgres backups"
molthub install my-skill-pack
molthub update --all
molthub update --all --no-input --force
molthub publish ./my-skill-pack --slug my-skill-pack --name "My Skill Pack" --version 1.2.0 --changelog "Fixes + docs"
```
## Sync (upload local skills)
```bash
# Start anywhere; scans workdir first, then legacy Moltbot/Molt locations.
molthub sync
# Explicit roots + non-interactive dry-run
molthub sync --root ../moltbot/skills --all --dry-run
```
## Defaults
- Site: `https://molthub.com` (override via `--site` or `MOLTHUB_SITE`)
- Registry: discovered from `/.well-known/molthub.json` on the site (override via `--registry` or `MOLTHUB_REGISTRY`)
- Workdir: current directory (falls back to Moltbot workspace if configured; override via `--workdir` or `MOLTHUB_WORKDIR`)
- Install dir: `./skills` under workdir (override via `--dir`)
@@ -1,159 +0,0 @@
/* @vitest-environment node */
import { mkdir, mkdtemp, writeFile } from 'node:fs/promises'
import { tmpdir } from 'node:os'
import { join, resolve } from 'node:path'
import { afterEach, describe, expect, it } from 'vitest'
import { resolveMoltbotDefaultWorkspace, resolveMoltbotSkillRoots } from './moltbotConfig.js'
const originalEnv = { ...process.env }
afterEach(() => {
process.env = { ...originalEnv }
})
describe('resolveMoltbotSkillRoots', () => {
it('reads JSON5 config and resolves per-agent + shared skill roots', async () => {
const base = await mkdtemp(join(tmpdir(), 'molthub-moltbot-'))
const home = join(base, 'home')
const stateDir = join(base, 'state')
const configPath = join(base, 'moltbot.json')
process.env.HOME = home
process.env.MOLTBOT_STATE_DIR = stateDir
process.env.MOLTBOT_CONFIG_PATH = configPath
const config = `{
// JSON5 comments + trailing commas supported
agents: {
defaults: { workspace: '~/molt-main', },
list: [
{ id: 'work', name: 'Work Bot', workspace: '~/molt-work', },
{ id: 'family', workspace: '~/molt-family', },
],
},
// legacy entries still supported
agent: { workspace: '~/molt-legacy', },
routing: {
agents: {
work: { name: 'Work Bot', workspace: '~/molt-work', },
family: { workspace: '~/molt-family' },
},
},
skills: {
load: { extraDirs: ['~/shared/skills', '/opt/skills',], },
},
}`
await writeFile(configPath, config, 'utf8')
const { roots, labels } = await resolveMoltbotSkillRoots()
const expectedRoots = [
resolve(stateDir, 'skills'),
resolve(home, 'molt-main', 'skills'),
resolve(home, 'molt-work', 'skills'),
resolve(home, 'molt-family', 'skills'),
resolve(home, 'shared', 'skills'),
resolve('/opt/skills'),
]
expect(roots).toEqual(expect.arrayContaining(expectedRoots))
expect(labels[resolve(stateDir, 'skills')]).toBe('Shared skills')
expect(labels[resolve(home, 'molt-main', 'skills')]).toBe('Agent: main')
expect(labels[resolve(home, 'molt-work', 'skills')]).toBe('Agent: Work Bot')
expect(labels[resolve(home, 'molt-family', 'skills')]).toBe('Agent: family')
expect(labels[resolve(home, 'shared', 'skills')]).toBe('Extra: skills')
expect(labels[resolve('/opt/skills')]).toBe('Extra: skills')
})
it('resolves default workspace from agents.defaults and agents.list', async () => {
const base = await mkdtemp(join(tmpdir(), 'molthub-moltbot-default-'))
const home = join(base, 'home')
const stateDir = join(base, 'state')
const configPath = join(base, 'moltbot.json')
const workspaceMain = join(base, 'workspace-main')
const workspaceList = join(base, 'workspace-list')
process.env.HOME = home
process.env.MOLTBOT_STATE_DIR = stateDir
process.env.MOLTBOT_CONFIG_PATH = configPath
const config = `{
agents: {
defaults: { workspace: "${workspaceMain}", },
list: [
{ id: 'main', workspace: "${workspaceList}", default: true },
],
},
}`
await writeFile(configPath, config, 'utf8')
const workspace = await resolveMoltbotDefaultWorkspace()
expect(workspace).toBe(resolve(workspaceMain))
})
it('falls back to default agent in agents.list when defaults missing', async () => {
const base = await mkdtemp(join(tmpdir(), 'molthub-moltbot-list-'))
const home = join(base, 'home')
const configPath = join(base, 'moltbot.json')
const workspaceMain = join(base, 'workspace-main')
const workspaceWork = join(base, 'workspace-work')
process.env.HOME = home
process.env.MOLTBOT_CONFIG_PATH = configPath
const config = `{
agents: {
list: [
{ id: 'main', workspace: "${workspaceMain}", default: true },
{ id: 'work', workspace: "${workspaceWork}" },
],
},
}`
await writeFile(configPath, config, 'utf8')
const workspace = await resolveMoltbotDefaultWorkspace()
expect(workspace).toBe(resolve(workspaceMain))
})
it('respects MOLTBOT_STATE_DIR and MOLTBOT_CONFIG_PATH overrides', async () => {
const base = await mkdtemp(join(tmpdir(), 'molthub-moltbot-override-'))
const home = join(base, 'home')
const stateDir = join(base, 'custom-state')
const configPath = join(base, 'config', 'moltbot.json')
process.env.HOME = home
process.env.MOLTBOT_STATE_DIR = stateDir
process.env.MOLTBOT_CONFIG_PATH = configPath
const config = `{
agent: { workspace: "${join(base, 'workspace-main')}" },
}`
await mkdir(join(base, 'config'), { recursive: true })
await writeFile(configPath, config, 'utf8')
const { roots, labels } = await resolveMoltbotSkillRoots()
expect(roots).toEqual(
expect.arrayContaining([
resolve(stateDir, 'skills'),
resolve(join(base, 'workspace-main'), 'skills'),
]),
)
expect(labels[resolve(stateDir, 'skills')]).toBe('Shared skills')
expect(labels[resolve(join(base, 'workspace-main'), 'skills')]).toBe('Agent: main')
})
it('returns shared skills root when config is missing', async () => {
const base = await mkdtemp(join(tmpdir(), 'molthub-moltbot-missing-'))
const stateDir = join(base, 'state')
const configPath = join(base, 'missing', 'moltbot.json')
process.env.MOLTBOT_STATE_DIR = stateDir
process.env.MOLTBOT_CONFIG_PATH = configPath
const { roots, labels } = await resolveMoltbotSkillRoots()
expect(roots).toEqual([resolve(stateDir, 'skills')])
expect(labels[resolve(stateDir, 'skills')]).toBe('Shared skills')
})
})
-147
View File
@@ -1,147 +0,0 @@
import { readFile } from 'node:fs/promises'
import { homedir } from 'node:os'
import { basename, join, resolve } from 'node:path'
import JSON5 from 'json5'
type MoltbotConfig = {
agent?: { workspace?: string }
agents?: {
defaults?: { workspace?: string }
list?: Array<{
id?: string
name?: string
workspace?: string
default?: boolean
}>
}
routing?: {
agents?: Record<
string,
{
name?: string
workspace?: string
}
>
}
skills?: {
load?: {
extraDirs?: string[]
}
}
}
export type MoltbotSkillRoots = {
roots: string[]
labels: Record<string, string>
}
export async function resolveMoltbotSkillRoots(): Promise<MoltbotSkillRoots> {
const roots: string[] = []
const labels: Record<string, string> = {}
const stateDir = resolveMoltbotStateDir()
const sharedSkills = resolveUserPath(join(stateDir, 'skills'))
pushRoot(roots, labels, sharedSkills, 'Shared skills')
const config = await readMoltbotConfig()
if (!config) return { roots, labels }
const mainWorkspace = resolveUserPath(
config.agents?.defaults?.workspace ?? config.agent?.workspace ?? '',
)
if (mainWorkspace) {
pushRoot(roots, labels, join(mainWorkspace, 'skills'), 'Agent: main')
}
const listedAgents = config.agents?.list ?? []
for (const entry of listedAgents) {
const workspace = resolveUserPath(entry?.workspace ?? '')
if (!workspace) continue
const name = entry?.name?.trim() || entry?.id?.trim() || 'agent'
pushRoot(roots, labels, join(workspace, 'skills'), `Agent: ${name}`)
}
const agents = config.routing?.agents ?? {}
for (const [agentId, entry] of Object.entries(agents)) {
const workspace = resolveUserPath(entry?.workspace ?? '')
if (!workspace) continue
const name = entry?.name?.trim() || agentId
pushRoot(roots, labels, join(workspace, 'skills'), `Agent: ${name}`)
}
const extraDirs = config.skills?.load?.extraDirs ?? []
for (const dir of extraDirs) {
const resolved = resolveUserPath(String(dir))
if (!resolved) continue
const label = `Extra: ${basename(resolved) || resolved}`
pushRoot(roots, labels, resolved, label)
}
return { roots, labels }
}
export async function resolveMoltbotDefaultWorkspace(): Promise<string | null> {
const config = await readMoltbotConfig()
if (!config) return null
const defaultsWorkspace = resolveUserPath(
config.agents?.defaults?.workspace ?? config.agent?.workspace ?? '',
)
if (defaultsWorkspace) return defaultsWorkspace
const listedAgents = config.agents?.list ?? []
const defaultAgent =
listedAgents.find((entry) => entry.default) ?? listedAgents.find((entry) => entry.id === 'main')
const listWorkspace = resolveUserPath(defaultAgent?.workspace ?? '')
return listWorkspace || null
}
function resolveMoltbotStateDir() {
const override = process.env.MOLTBOT_STATE_DIR?.trim()
if (override) return resolveUserPath(override)
return join(homedir(), '.moltbot')
}
function resolveMoltbotConfigPath() {
const override = process.env.MOLTBOT_CONFIG_PATH?.trim()
if (override) return resolveUserPath(override)
return join(resolveMoltbotStateDir(), 'moltbot.json')
}
function resolveUserPath(input: string) {
const trimmed = input.trim()
if (!trimmed) return ''
if (trimmed.startsWith('~')) {
return resolve(trimmed.replace(/^~(?=$|[\\/])/, homedir()))
}
return resolve(trimmed)
}
async function readMoltbotConfig(): Promise<MoltbotConfig | null> {
try {
const raw = await readFile(resolveMoltbotConfigPath(), 'utf8')
const parsed = JSON5.parse(raw)
if (!parsed || typeof parsed !== 'object') return null
return parsed as MoltbotConfig
} catch {
return null
}
}
function pushRoot(roots: string[], labels: Record<string, string>, root: string, label?: string) {
const resolved = resolveUserPath(root)
if (!resolved) return
if (!roots.includes(resolved)) roots.push(resolved)
if (!label) return
const existing = labels[resolved]
if (!existing) {
labels[resolved] = label
return
}
const parts = existing
.split(', ')
.map((part) => part.trim())
.filter(Boolean)
if (parts.includes(label)) return
labels[resolved] = `${existing}, ${label}`
}
-36
View File
@@ -1,36 +0,0 @@
import { mkdir, readFile, writeFile } from 'node:fs/promises'
import { homedir } from 'node:os'
import { dirname, join, resolve } from 'node:path'
import { type GlobalConfig, GlobalConfigSchema, parseArk } from './schema/index.js'
export function getGlobalConfigPath() {
const override = process.env.MOLTHUB_CONFIG_PATH?.trim()
if (override) return resolve(override)
const home = homedir()
if (process.platform === 'darwin') {
return join(home, 'Library', 'Application Support', 'molthub', 'config.json')
}
const xdg = process.env.XDG_CONFIG_HOME
if (xdg) return join(xdg, 'molthub', 'config.json')
if (process.platform === 'win32') {
const appData = process.env.APPDATA
if (appData) return join(appData, 'molthub', 'config.json')
}
return join(home, '.config', 'molthub', 'config.json')
}
export async function readGlobalConfig(): Promise<GlobalConfig | null> {
try {
const raw = await readFile(getGlobalConfigPath(), 'utf8')
const parsed = JSON.parse(raw) as unknown
return parseArk(GlobalConfigSchema, parsed, 'Global config')
} catch {
return null
}
}
export async function writeGlobalConfig(config: GlobalConfig) {
const path = getGlobalConfigPath()
await mkdir(dirname(path), { recursive: true })
await writeFile(path, `${JSON.stringify(config, null, 2)}\n`, 'utf8')
}
-19
View File
@@ -1,19 +0,0 @@
import { parseArk, WellKnownConfigSchema } from './schema/index.js'
export async function discoverRegistryFromSite(siteUrl: string) {
const url = new URL('/.well-known/molthub.json', siteUrl)
const response = await fetch(url.toString(), {
method: 'GET',
headers: { Accept: 'application/json' },
})
if (!response.ok) return null
const raw = (await response.json()) as unknown
const parsed = parseArk(WellKnownConfigSchema, raw, 'WellKnown config')
const apiBase = 'apiBase' in parsed ? parsed.apiBase : parsed.registry
if (!apiBase) return null
return {
apiBase,
authBase: parsed.authBase,
minCliVersion: parsed.minCliVersion,
}
}

Some files were not shown because too many files have changed in this diff Show More