revert: Switch back to tsc for compiling.

This commit is contained in:
cpojer
2026-01-31 18:31:49 +09:00
parent e25fedf932
commit 76361ae3ab
36 changed files with 527 additions and 843 deletions

View File

@@ -94,7 +94,7 @@ jobs:
command: pnpm canvas:a2ui:bundle && bunx vitest run command: pnpm canvas:a2ui:bundle && bunx vitest run
- runtime: bun - runtime: bun
task: build task: build
command: bunx tsdown command: bunx tsc -p tsconfig.json --noEmit false
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v4

View File

@@ -36,4 +36,4 @@ ENV NODE_ENV=production
# This reduces the attack surface by preventing container escape via root privileges # This reduces the attack surface by preventing container escape via root privileges
USER node USER node
CMD ["node", "dist/index.mjs"] CMD ["node", "dist/index.js"]

View File

@@ -5,7 +5,7 @@ enum CommandResolver {
private static let helperName = "openclaw" private static let helperName = "openclaw"
static func gatewayEntrypoint(in root: URL) -> String? { static func gatewayEntrypoint(in root: URL) -> String? {
let distEntry = root.appendingPathComponent("dist/index.mjs").path let distEntry = root.appendingPathComponent("dist/index.js").path
if FileManager().isReadableFile(atPath: distEntry) { return distEntry } if FileManager().isReadableFile(atPath: distEntry) { return distEntry }
let openclawEntry = root.appendingPathComponent("openclaw.mjs").path let openclawEntry = root.appendingPathComponent("openclaw.mjs").path
if FileManager().isReadableFile(atPath: openclawEntry) { return openclawEntry } if FileManager().isReadableFile(atPath: openclawEntry) { return openclawEntry }
@@ -271,7 +271,7 @@ enum CommandResolver {
} }
let missingEntry = """ let missingEntry = """
openclaw entrypoint missing (looked for dist/index.mjs or openclaw.mjs); run pnpm build. openclaw entrypoint missing (looked for dist/index.js or openclaw.mjs); run pnpm build.
""" """
return self.errorCommand(with: missingEntry) return self.errorCommand(with: missingEntry)
@@ -360,10 +360,10 @@ enum CommandResolver {
if command -v openclaw >/dev/null 2>&1; then if command -v openclaw >/dev/null 2>&1; then
CLI="$(command -v openclaw)" CLI="$(command -v openclaw)"
openclaw \(quotedArgs); openclaw \(quotedArgs);
elif [ -n "${PRJ:-}" ] && [ -f "$PRJ/dist/index.mjs" ]; then elif [ -n "${PRJ:-}" ] && [ -f "$PRJ/dist/index.js" ]; then
if command -v node >/dev/null 2>&1; then if command -v node >/dev/null 2>&1; then
CLI="node $PRJ/dist/index.mjs" CLI="node $PRJ/dist/index.js"
node "$PRJ/dist/index.mjs" \(quotedArgs); node "$PRJ/dist/index.js" \(quotedArgs);
else else
echo "Node >=22 required on remote host"; exit 127; echo "Node >=22 required on remote host"; exit 127;
fi fi

View File

@@ -45,7 +45,7 @@ import Testing
@Test func gatewayEntrypointPrefersDistOverBin() throws { @Test func gatewayEntrypointPrefersDistOverBin() throws {
let tmp = URL(fileURLWithPath: NSTemporaryDirectory(), isDirectory: true) let tmp = URL(fileURLWithPath: NSTemporaryDirectory(), isDirectory: true)
.appendingPathComponent(UUID().uuidString, isDirectory: true) .appendingPathComponent(UUID().uuidString, isDirectory: true)
let dist = tmp.appendingPathComponent("dist/index.mjs") let dist = tmp.appendingPathComponent("dist/index.js")
let bin = tmp.appendingPathComponent("bin/openclaw.js") let bin = tmp.appendingPathComponent("bin/openclaw.js")
try FileManager().createDirectory(at: dist.deletingLastPathComponent(), withIntermediateDirectories: true) try FileManager().createDirectory(at: dist.deletingLastPathComponent(), withIntermediateDirectories: true)
try FileManager().createDirectory(at: bin.deletingLastPathComponent(), withIntermediateDirectories: true) try FileManager().createDirectory(at: bin.deletingLastPathComponent(), withIntermediateDirectories: true)

View File

@@ -12,19 +12,19 @@ services:
- ${OPENCLAW_CONFIG_DIR}:/home/node/.openclaw - ${OPENCLAW_CONFIG_DIR}:/home/node/.openclaw
- ${OPENCLAW_WORKSPACE_DIR}:/home/node/.openclaw/workspace - ${OPENCLAW_WORKSPACE_DIR}:/home/node/.openclaw/workspace
ports: ports:
- "${OPENCLAW_GATEWAY_PORT:-18789}:18789" - '${OPENCLAW_GATEWAY_PORT:-18789}:18789'
- "${OPENCLAW_BRIDGE_PORT:-18790}:18790" - '${OPENCLAW_BRIDGE_PORT:-18790}:18790'
init: true init: true
restart: unless-stopped restart: unless-stopped
command: command:
[ [
"node", 'node',
"dist/index.mjs", 'dist/index.js',
"gateway", 'gateway',
"--bind", '--bind',
"${OPENCLAW_GATEWAY_BIND:-lan}", '${OPENCLAW_GATEWAY_BIND:-lan}',
"--port", '--port',
"${OPENCLAW_GATEWAY_PORT:-18789}" '${OPENCLAW_GATEWAY_PORT:-18789}',
] ]
openclaw-cli: openclaw-cli:
@@ -42,4 +42,4 @@ services:
stdin_open: true stdin_open: true
tty: true tty: true
init: true init: true
entrypoint: ["node", "dist/index.mjs"] entrypoint: ['node', 'dist/index.js']

View File

@@ -211,4 +211,4 @@ echo "Token: $OPENCLAW_GATEWAY_TOKEN"
echo "" echo ""
echo "Commands:" echo "Commands:"
echo " ${COMPOSE_HINT} logs -f openclaw-gateway" echo " ${COMPOSE_HINT} logs -f openclaw-gateway"
echo " ${COMPOSE_HINT} exec openclaw-gateway node dist/index.mjs health --token \"$OPENCLAW_GATEWAY_TOKEN\"" echo " ${COMPOSE_HINT} exec openclaw-gateway node dist/index.js health --token \"$OPENCLAW_GATEWAY_TOKEN\""

View File

@@ -1,5 +1,5 @@
--- ---
summary: "Optional Docker-based setup and onboarding for OpenClaw" summary: 'Optional Docker-based setup and onboarding for OpenClaw'
read_when: read_when:
- You want a containerized gateway instead of local installs - You want a containerized gateway instead of local installs
- You are validating the Docker flow - You are validating the Docker flow
@@ -16,6 +16,7 @@ Docker is **optional**. Use it only if you want a containerized gateway or to va
- **Sandboxing note**: agent sandboxing uses Docker too, but it does **not** require the full gateway to run in Docker. See [Sandboxing](/gateway/sandboxing). - **Sandboxing note**: agent sandboxing uses Docker too, but it does **not** require the full gateway to run in Docker. See [Sandboxing](/gateway/sandboxing).
This guide covers: This guide covers:
- Containerized Gateway (full OpenClaw in Docker) - Containerized Gateway (full OpenClaw in Docker)
- Per-session Agent Sandbox (host gateway + Docker-isolated agent tools) - Per-session Agent Sandbox (host gateway + Docker-isolated agent tools)
@@ -37,6 +38,7 @@ From repo root:
``` ```
This script: This script:
- builds the gateway image - builds the gateway image
- runs the onboarding wizard - runs the onboarding wizard
- prints optional provider setup hints - prints optional provider setup hints
@@ -44,15 +46,18 @@ This script:
- generates a gateway token and writes it to `.env` - generates a gateway token and writes it to `.env`
Optional env vars: Optional env vars:
- `OPENCLAW_DOCKER_APT_PACKAGES` — install extra apt packages during build - `OPENCLAW_DOCKER_APT_PACKAGES` — install extra apt packages during build
- `OPENCLAW_EXTRA_MOUNTS` — add extra host bind mounts - `OPENCLAW_EXTRA_MOUNTS` — add extra host bind mounts
- `OPENCLAW_HOME_VOLUME` — persist `/home/node` in a named volume - `OPENCLAW_HOME_VOLUME` — persist `/home/node` in a named volume
After it finishes: After it finishes:
- Open `http://127.0.0.1:18789/` in your browser. - Open `http://127.0.0.1:18789/` in your browser.
- Paste the token into the Control UI (Settings → token). - Paste the token into the Control UI (Settings → token).
It writes config/workspace on the host: It writes config/workspace on the host:
- `~/.openclaw/` - `~/.openclaw/`
- `~/.openclaw/workspace` - `~/.openclaw/workspace`
@@ -81,6 +86,7 @@ export OPENCLAW_EXTRA_MOUNTS="$HOME/.codex:/home/node/.codex:ro,$HOME/github:/ho
``` ```
Notes: Notes:
- Paths must be shared with Docker Desktop on macOS/Windows. - Paths must be shared with Docker Desktop on macOS/Windows.
- If you edit `OPENCLAW_EXTRA_MOUNTS`, rerun `docker-setup.sh` to regenerate the - If you edit `OPENCLAW_EXTRA_MOUNTS`, rerun `docker-setup.sh` to regenerate the
extra compose file. extra compose file.
@@ -110,6 +116,7 @@ export OPENCLAW_EXTRA_MOUNTS="$HOME/.codex:/home/node/.codex:ro,$HOME/github:/ho
``` ```
Notes: Notes:
- If you change `OPENCLAW_HOME_VOLUME`, rerun `docker-setup.sh` to regenerate the - If you change `OPENCLAW_HOME_VOLUME`, rerun `docker-setup.sh` to regenerate the
extra compose file. extra compose file.
- The named volume persists until removed with `docker volume rm <name>`. - The named volume persists until removed with `docker volume rm <name>`.
@@ -129,6 +136,7 @@ export OPENCLAW_DOCKER_APT_PACKAGES="ffmpeg build-essential"
``` ```
Notes: Notes:
- This accepts a space-separated list of apt package names. - This accepts a space-separated list of apt package names.
- If you change `OPENCLAW_DOCKER_APT_PACKAGES`, rerun `docker-setup.sh` to rebuild - If you change `OPENCLAW_DOCKER_APT_PACKAGES`, rerun `docker-setup.sh` to rebuild
the image. the image.
@@ -163,7 +171,7 @@ RUN pnpm ui:build
ENV NODE_ENV=production ENV NODE_ENV=production
CMD ["node","dist/index.mjs"] CMD ["node","dist/index.js"]
``` ```
### Channel setup (optional) ### Channel setup (optional)
@@ -171,16 +179,19 @@ CMD ["node","dist/index.mjs"]
Use the CLI container to configure channels, then restart the gateway if needed. Use the CLI container to configure channels, then restart the gateway if needed.
WhatsApp (QR): WhatsApp (QR):
```bash ```bash
docker compose run --rm openclaw-cli channels login docker compose run --rm openclaw-cli channels login
``` ```
Telegram (bot token): Telegram (bot token):
```bash ```bash
docker compose run --rm openclaw-cli channels add --channel telegram --token "<token>" docker compose run --rm openclaw-cli channels add --channel telegram --token "<token>"
``` ```
Discord (bot token): Discord (bot token):
```bash ```bash
docker compose run --rm openclaw-cli channels add --channel discord --token "<token>" docker compose run --rm openclaw-cli channels add --channel discord --token "<token>"
``` ```
@@ -190,7 +201,7 @@ Docs: [WhatsApp](/channels/whatsapp), [Telegram](/channels/telegram), [Discord](
### Health check ### Health check
```bash ```bash
docker compose exec openclaw-gateway node dist/index.mjs health --token "$OPENCLAW_GATEWAY_TOKEN" docker compose exec openclaw-gateway node dist/index.js health --token "$OPENCLAW_GATEWAY_TOKEN"
``` ```
### E2E smoke test (Docker) ### E2E smoke test (Docker)
@@ -218,6 +229,7 @@ Deep dive: [Sandboxing](/gateway/sandboxing)
When `agents.defaults.sandbox` is enabled, **non-main sessions** run tools inside a Docker When `agents.defaults.sandbox` is enabled, **non-main sessions** run tools inside a Docker
container. The gateway stays on your host, but the tool execution is isolated: container. The gateway stays on your host, but the tool execution is isolated:
- scope: `"agent"` by default (one container + workspace per agent) - scope: `"agent"` by default (one container + workspace per agent)
- scope: `"session"` for per-session isolation - scope: `"session"` for per-session isolation
- per-scope workspace folder mounted at `/workspace` - per-scope workspace folder mounted at `/workspace`
@@ -233,6 +245,7 @@ one container and one workspace.
If you use multi-agent routing, each agent can override sandbox + tool settings: If you use multi-agent routing, each agent can override sandbox + tool settings:
`agents.list[].sandbox` and `agents.list[].tools` (plus `agents.list[].tools.sandbox.tools`). This lets you run `agents.list[].sandbox` and `agents.list[].tools` (plus `agents.list[].tools.sandbox.tools`). This lets you run
mixed access levels in one gateway: mixed access levels in one gateway:
- Full access (personal agent) - Full access (personal agent)
- Read-only tools + read-only workspace (family/work agent) - Read-only tools + read-only workspace (family/work agent)
- No filesystem/shell tools (public agent) - No filesystem/shell tools (public agent)
@@ -255,60 +268,72 @@ precedence, and troubleshooting.
### Enable sandboxing ### Enable sandboxing
If you plan to install packages in `setupCommand`, note: If you plan to install packages in `setupCommand`, note:
- Default `docker.network` is `"none"` (no egress). - Default `docker.network` is `"none"` (no egress).
- `readOnlyRoot: true` blocks package installs. - `readOnlyRoot: true` blocks package installs.
- `user` must be root for `apt-get` (omit `user` or set `user: "0:0"`). - `user` must be root for `apt-get` (omit `user` or set `user: "0:0"`).
OpenClaw auto-recreates containers when `setupCommand` (or docker config) changes OpenClaw auto-recreates containers when `setupCommand` (or docker config) changes
unless the container was **recently used** (within ~5 minutes). Hot containers unless the container was **recently used** (within ~5 minutes). Hot containers
log a warning with the exact `openclaw sandbox recreate ...` command. log a warning with the exact `openclaw sandbox recreate ...` command.
```json5 ```json5
{ {
agents: { agents: {
defaults: { defaults: {
sandbox: { sandbox: {
mode: "non-main", // off | non-main | all mode: 'non-main', // off | non-main | all
scope: "agent", // session | agent | shared (agent is default) scope: 'agent', // session | agent | shared (agent is default)
workspaceAccess: "none", // none | ro | rw workspaceAccess: 'none', // none | ro | rw
workspaceRoot: "~/.openclaw/sandboxes", workspaceRoot: '~/.openclaw/sandboxes',
docker: { docker: {
image: "openclaw-sandbox:bookworm-slim", image: 'openclaw-sandbox:bookworm-slim',
workdir: "/workspace", workdir: '/workspace',
readOnlyRoot: true, readOnlyRoot: true,
tmpfs: ["/tmp", "/var/tmp", "/run"], tmpfs: ['/tmp', '/var/tmp', '/run'],
network: "none", network: 'none',
user: "1000:1000", user: '1000:1000',
capDrop: ["ALL"], capDrop: ['ALL'],
env: { LANG: "C.UTF-8" }, env: { LANG: 'C.UTF-8' },
setupCommand: "apt-get update && apt-get install -y git curl jq", setupCommand: 'apt-get update && apt-get install -y git curl jq',
pidsLimit: 256, pidsLimit: 256,
memory: "1g", memory: '1g',
memorySwap: "2g", memorySwap: '2g',
cpus: 1, cpus: 1,
ulimits: { ulimits: {
nofile: { soft: 1024, hard: 2048 }, nofile: { soft: 1024, hard: 2048 },
nproc: 256 nproc: 256,
}, },
seccompProfile: "/path/to/seccomp.json", seccompProfile: '/path/to/seccomp.json',
apparmorProfile: "openclaw-sandbox", apparmorProfile: 'openclaw-sandbox',
dns: ["1.1.1.1", "8.8.8.8"], dns: ['1.1.1.1', '8.8.8.8'],
extraHosts: ["internal.service:10.0.0.5"] extraHosts: ['internal.service:10.0.0.5'],
}, },
prune: { prune: {
idleHours: 24, // 0 disables idle pruning idleHours: 24, // 0 disables idle pruning
maxAgeDays: 7 // 0 disables max-age pruning maxAgeDays: 7, // 0 disables max-age pruning
} },
} },
} },
}, },
tools: { tools: {
sandbox: { sandbox: {
tools: { tools: {
allow: ["exec", "process", "read", "write", "edit", "sessions_list", "sessions_history", "sessions_send", "sessions_spawn", "session_status"], allow: [
deny: ["browser", "canvas", "nodes", "cron", "discord", "gateway"] 'exec',
} 'process',
} 'read',
} 'write',
'edit',
'sessions_list',
'sessions_history',
'sessions_send',
'sessions_spawn',
'session_status',
],
deny: ['browser', 'canvas', 'nodes', 'cron', 'discord', 'gateway'],
},
},
},
} }
``` ```
@@ -328,6 +353,7 @@ scripts/sandbox-setup.sh
This builds `openclaw-sandbox:bookworm-slim` using `Dockerfile.sandbox`. This builds `openclaw-sandbox:bookworm-slim` using `Dockerfile.sandbox`.
### Sandbox common image (optional) ### Sandbox common image (optional)
If you want a sandbox image with common build tooling (Node, Go, Rust, etc.), build the common image: If you want a sandbox image with common build tooling (Node, Go, Rust, etc.), build the common image:
```bash ```bash
@@ -338,7 +364,11 @@ This builds `openclaw-sandbox-common:bookworm-slim`. To use it:
```json5 ```json5
{ {
agents: { defaults: { sandbox: { docker: { image: "openclaw-sandbox-common:bookworm-slim" } } } } agents: {
defaults: {
sandbox: { docker: { image: 'openclaw-sandbox-common:bookworm-slim' } },
},
},
} }
``` ```
@@ -355,6 +385,7 @@ This builds `openclaw-sandbox-browser:bookworm-slim` using
an optional noVNC observer (headful via Xvfb). an optional noVNC observer (headful via Xvfb).
Notes: Notes:
- Headful (Xvfb) reduces bot blocking vs headless. - Headful (Xvfb) reduces bot blocking vs headless.
- Headless can still be used by setting `agents.defaults.sandbox.browser.headless=true`. - Headless can still be used by setting `agents.defaults.sandbox.browser.headless=true`.
- No full desktop environment (GNOME) is needed; Xvfb provides the display. - No full desktop environment (GNOME) is needed; Xvfb provides the display.
@@ -366,10 +397,10 @@ Use config:
agents: { agents: {
defaults: { defaults: {
sandbox: { sandbox: {
browser: { enabled: true } browser: { enabled: true },
} },
} },
} },
} }
``` ```
@@ -379,13 +410,14 @@ Custom browser image:
{ {
agents: { agents: {
defaults: { defaults: {
sandbox: { browser: { image: "my-openclaw-browser" } } sandbox: { browser: { image: 'my-openclaw-browser' } },
} },
} },
} }
``` ```
When enabled, the agent receives: When enabled, the agent receives:
- a sandbox browser control URL (for the `browser` tool) - a sandbox browser control URL (for the `browser` tool)
- a noVNC URL (if enabled and headless=false) - a noVNC URL (if enabled and headless=false)
@@ -405,9 +437,9 @@ docker build -t my-openclaw-sbx -f Dockerfile.sandbox .
{ {
agents: { agents: {
defaults: { defaults: {
sandbox: { docker: { image: "my-openclaw-sbx" } } sandbox: { docker: { image: 'my-openclaw-sbx' } },
} },
} },
} }
``` ```
@@ -420,10 +452,12 @@ docker build -t my-openclaw-sbx -f Dockerfile.sandbox .
### Pruning strategy ### Pruning strategy
Two knobs: Two knobs:
- `prune.idleHours`: remove containers not used in X hours (0 = disable) - `prune.idleHours`: remove containers not used in X hours (0 = disable)
- `prune.maxAgeDays`: remove containers older than X days (0 = disable) - `prune.maxAgeDays`: remove containers older than X days (0 = disable)
Example: Example:
- Keep busy sessions but cap lifetime: - Keep busy sessions but cap lifetime:
`idleHours: 24`, `maxAgeDays: 7` `idleHours: 24`, `maxAgeDays: 7`
- Never prune: - Never prune:
@@ -431,8 +465,8 @@ Example:
### Security notes ### Security notes
- Hard wall only applies to **tools** (exec/read/write/edit/apply_patch). - Hard wall only applies to **tools** (exec/read/write/edit/apply_patch).
- Host-only tools like browser/camera/canvas are blocked by default. - Host-only tools like browser/camera/canvas are blocked by default.
- Allowing `browser` in sandbox **breaks isolation** (browser runs on host). - Allowing `browser` in sandbox **breaks isolation** (browser runs on host).
## Troubleshooting ## Troubleshooting

View File

@@ -57,7 +57,7 @@ primary_region = "iad"
NODE_OPTIONS = "--max-old-space-size=1536" NODE_OPTIONS = "--max-old-space-size=1536"
[processes] [processes]
app = "node dist/index.mjs gateway --allow-unconfigured --port 3000 --bind lan" app = "node dist/index.js gateway --allow-unconfigured --port 3000 --bind lan"
[http_service] [http_service]
internal_port = 3000 internal_port = 3000
@@ -78,13 +78,13 @@ primary_region = "iad"
**Key settings:** **Key settings:**
| Setting | Why | | Setting | Why |
|---------|-----| | ------------------------------ | --------------------------------------------------------------------------- |
| `--bind lan` | Binds to `0.0.0.0` so Fly's proxy can reach the gateway | | `--bind lan` | Binds to `0.0.0.0` so Fly's proxy can reach the gateway |
| `--allow-unconfigured` | Starts without a config file (you'll create one after) | | `--allow-unconfigured` | Starts without a config file (you'll create one after) |
| `internal_port = 3000` | Must match `--port 3000` (or `OPENCLAW_GATEWAY_PORT`) for Fly health checks | | `internal_port = 3000` | Must match `--port 3000` (or `OPENCLAW_GATEWAY_PORT`) for Fly health checks |
| `memory = "2048mb"` | 512MB is too small; 2GB recommended | | `memory = "2048mb"` | 512MB is too small; 2GB recommended |
| `OPENCLAW_STATE_DIR = "/data"` | Persists state on the volume | | `OPENCLAW_STATE_DIR = "/data"` | Persists state on the volume |
## 3) Set secrets ## 3) Set secrets
@@ -104,6 +104,7 @@ fly secrets set DISCORD_BOT_TOKEN=MTQ...
``` ```
**Notes:** **Notes:**
- Non-loopback binds (`--bind lan`) require `OPENCLAW_GATEWAY_TOKEN` for security. - Non-loopback binds (`--bind lan`) require `OPENCLAW_GATEWAY_TOKEN` for security.
- Treat these tokens like passwords. - Treat these tokens like passwords.
- **Prefer env vars over config file** for all API keys and tokens. This keeps secrets out of `openclaw.json` where they could be accidentally exposed or logged. - **Prefer env vars over config file** for all API keys and tokens. This keeps secrets out of `openclaw.json` where they could be accidentally exposed or logged.
@@ -117,12 +118,14 @@ fly deploy
First deploy builds the Docker image (~2-3 minutes). Subsequent deploys are faster. First deploy builds the Docker image (~2-3 minutes). Subsequent deploys are faster.
After deployment, verify: After deployment, verify:
```bash ```bash
fly status fly status
fly logs fly logs
``` ```
You should see: You should see:
``` ```
[gateway] listening on ws://0.0.0.0:3000 (PID xxx) [gateway] listening on ws://0.0.0.0:3000 (PID xxx)
[discord] logged in to discord as xxx [discord] logged in to discord as xxx
@@ -137,6 +140,7 @@ fly ssh console
``` ```
Create the config directory and file: Create the config directory and file:
```bash ```bash
mkdir -p /data mkdir -p /data
cat > /data/openclaw.json << 'EOF' cat > /data/openclaw.json << 'EOF'
@@ -194,12 +198,14 @@ EOF
**Note:** With `OPENCLAW_STATE_DIR=/data`, the config path is `/data/openclaw.json`. **Note:** With `OPENCLAW_STATE_DIR=/data`, the config path is `/data/openclaw.json`.
**Note:** The Discord token can come from either: **Note:** The Discord token can come from either:
- Environment variable: `DISCORD_BOT_TOKEN` (recommended for secrets) - Environment variable: `DISCORD_BOT_TOKEN` (recommended for secrets)
- Config file: `channels.discord.token` - Config file: `channels.discord.token`
If using env var, no need to add token to config. The gateway reads `DISCORD_BOT_TOKEN` automatically. If using env var, no need to add token to config. The gateway reads `DISCORD_BOT_TOKEN` automatically.
Restart to apply: Restart to apply:
```bash ```bash
exit exit
fly machine restart <machine-id> fly machine restart <machine-id>
@@ -210,6 +216,7 @@ fly machine restart <machine-id>
### Control UI ### Control UI
Open in browser: Open in browser:
```bash ```bash
fly open fly open
``` ```
@@ -250,12 +257,14 @@ Fly can't reach the gateway on the configured port.
Container keeps restarting or getting killed. Signs: `SIGABRT`, `v8::internal::Runtime_AllocateInYoungGeneration`, or silent restarts. Container keeps restarting or getting killed. Signs: `SIGABRT`, `v8::internal::Runtime_AllocateInYoungGeneration`, or silent restarts.
**Fix:** Increase memory in `fly.toml`: **Fix:** Increase memory in `fly.toml`:
```toml ```toml
[[vm]] [[vm]]
memory = "2048mb" memory = "2048mb"
``` ```
Or update an existing machine: Or update an existing machine:
```bash ```bash
fly machine update <machine-id> --vm-memory 2048 -y fly machine update <machine-id> --vm-memory 2048 -y
``` ```
@@ -269,6 +278,7 @@ Gateway refuses to start with "already running" errors.
This happens when the container restarts but the PID lock file persists on the volume. This happens when the container restarts but the PID lock file persists on the volume.
**Fix:** Delete the lock file: **Fix:** Delete the lock file:
```bash ```bash
fly ssh console --command "rm -f /data/gateway.*.lock" fly ssh console --command "rm -f /data/gateway.*.lock"
fly machine restart <machine-id> fly machine restart <machine-id>
@@ -281,6 +291,7 @@ The lock file is at `/data/gateway.*.lock` (not in a subdirectory).
If using `--allow-unconfigured`, the gateway creates a minimal config. Your custom config at `/data/openclaw.json` should be read on restart. If using `--allow-unconfigured`, the gateway creates a minimal config. Your custom config at `/data/openclaw.json` should be read on restart.
Verify the config exists: Verify the config exists:
```bash ```bash
fly ssh console --command "cat /data/openclaw.json" fly ssh console --command "cat /data/openclaw.json"
``` ```
@@ -299,6 +310,7 @@ fly sftp shell
``` ```
**Note:** `fly sftp` may fail if the file already exists. Delete first: **Note:** `fly sftp` may fail if the file already exists. Delete first:
```bash ```bash
fly ssh console --command "rm /data/openclaw.json" fly ssh console --command "rm /data/openclaw.json"
``` ```
@@ -332,10 +344,10 @@ If you need to change the startup command without a full redeploy:
fly machines list fly machines list
# Update command # Update command
fly machine update <machine-id> --command "node dist/index.mjs gateway --port 3000 --bind lan" -y fly machine update <machine-id> --command "node dist/index.js gateway --port 3000 --bind lan" -y
# Or with memory increase # Or with memory increase
fly machine update <machine-id> --vm-memory 2048 --command "node dist/index.mjs gateway --port 3000 --bind lan" -y fly machine update <machine-id> --vm-memory 2048 --command "node dist/index.js gateway --port 3000 --bind lan" -y
``` ```
**Note:** After `fly deploy`, the machine command may reset to what's in `fly.toml`. If you made manual changes, re-apply them after deploy. **Note:** After `fly deploy`, the machine command may reset to what's in `fly.toml`. If you made manual changes, re-apply them after deploy.
@@ -381,6 +393,7 @@ fly ips allocate-v6 --private -a my-openclaw
``` ```
After this, `fly ips list` should show only a `private` type IP: After this, `fly ips list` should show only a `private` type IP:
``` ```
VERSION IP TYPE REGION VERSION IP TYPE REGION
v6 fdaa:x:x:x:x::x private global v6 fdaa:x:x:x:x::x private global
@@ -391,6 +404,7 @@ v6 fdaa:x:x:x:x::x private global
Since there's no public URL, use one of these methods: Since there's no public URL, use one of these methods:
**Option 1: Local proxy (simplest)** **Option 1: Local proxy (simplest)**
```bash ```bash
# Forward local port 3000 to the app # Forward local port 3000 to the app
fly proxy 3000:3000 -a my-openclaw fly proxy 3000:3000 -a my-openclaw
@@ -399,6 +413,7 @@ fly proxy 3000:3000 -a my-openclaw
``` ```
**Option 2: WireGuard VPN** **Option 2: WireGuard VPN**
```bash ```bash
# Create WireGuard config (one-time) # Create WireGuard config (one-time)
fly wireguard create fly wireguard create
@@ -408,6 +423,7 @@ fly wireguard create
``` ```
**Option 3: SSH only** **Option 3: SSH only**
```bash ```bash
fly ssh console -a my-openclaw fly ssh console -a my-openclaw
``` ```
@@ -421,6 +437,7 @@ If you need webhook callbacks (Twilio, Telnyx, etc.) without public exposure:
3. **Outbound-only** - Some providers (Twilio) work fine for outbound calls without webhooks 3. **Outbound-only** - Some providers (Twilio) work fine for outbound calls without webhooks
Example voice-call config with ngrok: Example voice-call config with ngrok:
```json ```json
{ {
"plugins": { "plugins": {
@@ -441,12 +458,12 @@ The ngrok tunnel runs inside the container and provides a public webhook URL wit
### Security benefits ### Security benefits
| Aspect | Public | Private | | Aspect | Public | Private |
|--------|--------|---------| | ----------------- | ------------ | ---------- |
| Internet scanners | Discoverable | Hidden | | Internet scanners | Discoverable | Hidden |
| Direct attacks | Possible | Blocked | | Direct attacks | Possible | Blocked |
| Control UI access | Browser | Proxy/VPN | | Control UI access | Browser | Proxy/VPN |
| Webhook delivery | Direct | Via tunnel | | Webhook delivery | Direct | Via tunnel |
## Notes ## Notes
@@ -459,6 +476,7 @@ The ngrok tunnel runs inside the container and provides a public webhook URL wit
## Cost ## Cost
With the recommended config (`shared-cpu-2x`, 2GB RAM): With the recommended config (`shared-cpu-2x`, 2GB RAM):
- ~$10-15/month depending on usage - ~$10-15/month depending on usage
- Free tier includes some allowance - Free tier includes some allowance

View File

@@ -1,5 +1,5 @@
--- ---
summary: "Run OpenClaw Gateway 24/7 on a GCP Compute Engine VM (Docker) with durable state" summary: 'Run OpenClaw Gateway 24/7 on a GCP Compute Engine VM (Docker) with durable state'
read_when: read_when:
- You want OpenClaw running 24/7 on GCP - You want OpenClaw running 24/7 on GCP
- You want a production-grade, always-on Gateway on your own VM - You want a production-grade, always-on Gateway on your own VM
@@ -25,6 +25,7 @@ Pricing varies by machine type and region; pick the smallest VM that fits your w
- Access the Control UI from your laptop via an SSH tunnel - Access the Control UI from your laptop via an SSH tunnel
The Gateway can be accessed via: The Gateway can be accessed via:
- SSH port forwarding from your laptop - SSH port forwarding from your laptop
- Direct port exposure if you manage firewalling and tokens yourself - Direct port exposure if you manage firewalling and tokens yourself
@@ -36,14 +37,14 @@ For the generic Docker flow, see [Docker](/install/docker).
## Quick path (experienced operators) ## Quick path (experienced operators)
1) Create GCP project + enable Compute Engine API 1. Create GCP project + enable Compute Engine API
2) Create Compute Engine VM (e2-small, Debian 12, 20GB) 2. Create Compute Engine VM (e2-small, Debian 12, 20GB)
3) SSH into the VM 3. SSH into the VM
4) Install Docker 4. Install Docker
5) Clone OpenClaw repository 5. Clone OpenClaw repository
6) Create persistent host directories 6. Create persistent host directories
7) Configure `.env` and `docker-compose.yml` 7. Configure `.env` and `docker-compose.yml`
8) Bake required binaries, build, and launch 8. Bake required binaries, build, and launch
--- ---
@@ -112,9 +113,9 @@ gcloud services enable compute.googleapis.com
**Machine types:** **Machine types:**
| Type | Specs | Cost | Notes | | Type | Specs | Cost | Notes |
|------|-------|------|-------| | -------- | ------------------------ | ------------------ | ------------------ |
| e2-small | 2 vCPU, 2GB RAM | ~$12/mo | Recommended | | e2-small | 2 vCPU, 2GB RAM | ~$12/mo | Recommended |
| e2-micro | 2 vCPU (shared), 1GB RAM | Free tier eligible | May OOM under load | | e2-micro | 2 vCPU (shared), 1GB RAM | Free tier eligible | May OOM under load |
**CLI:** **CLI:**
@@ -263,20 +264,20 @@ services:
ports: ports:
# Recommended: keep the Gateway loopback-only on the VM; access via SSH tunnel. # Recommended: keep the Gateway loopback-only on the VM; access via SSH tunnel.
# To expose it publicly, remove the `127.0.0.1:` prefix and firewall accordingly. # To expose it publicly, remove the `127.0.0.1:` prefix and firewall accordingly.
- "127.0.0.1:${OPENCLAW_GATEWAY_PORT}:18789" - '127.0.0.1:${OPENCLAW_GATEWAY_PORT}:18789'
# Optional: only if you run iOS/Android nodes against this VM and need Canvas host. # Optional: only if you run iOS/Android nodes against this VM and need Canvas host.
# If you expose this publicly, read /gateway/security and firewall accordingly. # If you expose this publicly, read /gateway/security and firewall accordingly.
# - "18793:18793" # - "18793:18793"
command: command:
[ [
"node", 'node',
"dist/index.mjs", 'dist/index.js',
"gateway", 'gateway',
"--bind", '--bind',
"${OPENCLAW_GATEWAY_BIND}", '${OPENCLAW_GATEWAY_BIND}',
"--port", '--port',
"${OPENCLAW_GATEWAY_PORT}" '${OPENCLAW_GATEWAY_PORT}',
] ]
``` ```
@@ -290,6 +291,7 @@ Anything installed at runtime will be lost on restart.
All external binaries required by skills must be installed at image build time. All external binaries required by skills must be installed at image build time.
The examples below show three common binaries only: The examples below show three common binaries only:
- `gog` for Gmail access - `gog` for Gmail access
- `goplaces` for Google Places - `goplaces` for Google Places
- `wacli` for WhatsApp - `wacli` for WhatsApp
@@ -298,6 +300,7 @@ These are examples, not a complete list.
You may install as many binaries as needed using the same pattern. You may install as many binaries as needed using the same pattern.
If you add new skills later that depend on additional binaries, you must: If you add new skills later that depend on additional binaries, you must:
1. Update the Dockerfile 1. Update the Dockerfile
2. Rebuild the image 2. Rebuild the image
3. Restart the containers 3. Restart the containers
@@ -338,7 +341,7 @@ RUN pnpm ui:build
ENV NODE_ENV=production ENV NODE_ENV=production
CMD ["node","dist/index.mjs"] CMD ["node","dist/index.js"]
``` ```
--- ---
@@ -403,18 +406,18 @@ Paste your gateway token.
OpenClaw runs in Docker, but Docker is not the source of truth. OpenClaw runs in Docker, but Docker is not the source of truth.
All long-lived state must survive restarts, rebuilds, and reboots. All long-lived state must survive restarts, rebuilds, and reboots.
| Component | Location | Persistence mechanism | Notes | | Component | Location | Persistence mechanism | Notes |
|---|---|---|---| | ------------------- | --------------------------------- | ---------------------- | -------------------------------- |
| Gateway config | `/home/node/.openclaw/` | Host volume mount | Includes `openclaw.json`, tokens | | Gateway config | `/home/node/.openclaw/` | Host volume mount | Includes `openclaw.json`, tokens |
| Model auth profiles | `/home/node/.openclaw/` | Host volume mount | OAuth tokens, API keys | | Model auth profiles | `/home/node/.openclaw/` | Host volume mount | OAuth tokens, API keys |
| Skill configs | `/home/node/.openclaw/skills/` | Host volume mount | Skill-level state | | Skill configs | `/home/node/.openclaw/skills/` | Host volume mount | Skill-level state |
| Agent workspace | `/home/node/.openclaw/workspace/` | Host volume mount | Code and agent artifacts | | Agent workspace | `/home/node/.openclaw/workspace/` | Host volume mount | Code and agent artifacts |
| WhatsApp session | `/home/node/.openclaw/` | Host volume mount | Preserves QR login | | WhatsApp session | `/home/node/.openclaw/` | Host volume mount | Preserves QR login |
| Gmail keyring | `/home/node/.openclaw/` | Host volume + password | Requires `GOG_KEYRING_PASSWORD` | | Gmail keyring | `/home/node/.openclaw/` | Host volume + password | Requires `GOG_KEYRING_PASSWORD` |
| External binaries | `/usr/local/bin/` | Docker image | Must be baked at build time | | External binaries | `/usr/local/bin/` | Docker image | Must be baked at build time |
| Node runtime | Container filesystem | Docker image | Rebuilt every image build | | Node runtime | Container filesystem | Docker image | Rebuilt every image build |
| OS packages | Container filesystem | Docker image | Do not install at runtime | | OS packages | Container filesystem | Docker image | Do not install at runtime |
| Docker container | Ephemeral | Restartable | Safe to destroy | | Docker container | Ephemeral | Restartable | Safe to destroy |
--- ---
@@ -473,6 +476,7 @@ For personal use, your default user account works fine.
For automation or CI/CD pipelines, create a dedicated service account with minimal permissions: For automation or CI/CD pipelines, create a dedicated service account with minimal permissions:
1. Create a service account: 1. Create a service account:
```bash ```bash
gcloud iam service-accounts create openclaw-deploy \ gcloud iam service-accounts create openclaw-deploy \
--display-name="OpenClaw Deployment" --display-name="OpenClaw Deployment"

View File

@@ -1,5 +1,5 @@
--- ---
summary: "Run OpenClaw Gateway 24/7 on a cheap Hetzner VPS (Docker) with durable state and baked-in binaries" summary: 'Run OpenClaw Gateway 24/7 on a cheap Hetzner VPS (Docker) with durable state and baked-in binaries'
read_when: read_when:
- You want OpenClaw running 24/7 on a cloud VPS (not your laptop) - You want OpenClaw running 24/7 on a cloud VPS (not your laptop)
- You want a production-grade, always-on Gateway on your own VPS - You want a production-grade, always-on Gateway on your own VPS
@@ -10,6 +10,7 @@ read_when:
# OpenClaw on Hetzner (Docker, Production VPS Guide) # OpenClaw on Hetzner (Docker, Production VPS Guide)
## Goal ## Goal
Run a persistent OpenClaw Gateway on a Hetzner VPS using Docker, with durable state, baked-in binaries, and safe restart behavior. Run a persistent OpenClaw Gateway on a Hetzner VPS using Docker, with durable state, baked-in binaries, and safe restart behavior.
If you want “OpenClaw 24/7 for ~$5”, this is the simplest reliable setup. If you want “OpenClaw 24/7 for ~$5”, this is the simplest reliable setup.
@@ -24,6 +25,7 @@ Hetzner pricing changes; pick the smallest Debian/Ubuntu VPS and scale up if you
- Access the Control UI from your laptop via an SSH tunnel - Access the Control UI from your laptop via an SSH tunnel
The Gateway can be accessed via: The Gateway can be accessed via:
- SSH port forwarding from your laptop - SSH port forwarding from your laptop
- Direct port exposure if you manage firewalling and tokens yourself - Direct port exposure if you manage firewalling and tokens yourself
@@ -35,29 +37,29 @@ For the generic Docker flow, see [Docker](/install/docker).
## Quick path (experienced operators) ## Quick path (experienced operators)
1) Provision Hetzner VPS 1. Provision Hetzner VPS
2) Install Docker 2. Install Docker
3) Clone OpenClaw repository 3. Clone OpenClaw repository
4) Create persistent host directories 4. Create persistent host directories
5) Configure `.env` and `docker-compose.yml` 5. Configure `.env` and `docker-compose.yml`
6) Bake required binaries into the image 6. Bake required binaries into the image
7) `docker compose up -d` 7. `docker compose up -d`
8) Verify persistence and Gateway access 8. Verify persistence and Gateway access
--- ---
## What you need ## What you need
- Hetzner VPS with root access - Hetzner VPS with root access
- SSH access from your laptop - SSH access from your laptop
- Basic comfort with SSH + copy/paste - Basic comfort with SSH + copy/paste
- ~20 minutes - ~20 minutes
- Docker and Docker Compose - Docker and Docker Compose
- Model auth credentials - Model auth credentials
- Optional provider credentials - Optional provider credentials
- WhatsApp QR - WhatsApp QR
- Telegram bot token - Telegram bot token
- Gmail OAuth - Gmail OAuth
--- ---
@@ -175,20 +177,20 @@ services:
ports: ports:
# Recommended: keep the Gateway loopback-only on the VPS; access via SSH tunnel. # Recommended: keep the Gateway loopback-only on the VPS; access via SSH tunnel.
# To expose it publicly, remove the `127.0.0.1:` prefix and firewall accordingly. # To expose it publicly, remove the `127.0.0.1:` prefix and firewall accordingly.
- "127.0.0.1:${OPENCLAW_GATEWAY_PORT}:18789" - '127.0.0.1:${OPENCLAW_GATEWAY_PORT}:18789'
# Optional: only if you run iOS/Android nodes against this VPS and need Canvas host. # Optional: only if you run iOS/Android nodes against this VPS and need Canvas host.
# If you expose this publicly, read /gateway/security and firewall accordingly. # If you expose this publicly, read /gateway/security and firewall accordingly.
# - "18793:18793" # - "18793:18793"
command: command:
[ [
"node", 'node',
"dist/index.mjs", 'dist/index.js',
"gateway", 'gateway',
"--bind", '--bind',
"${OPENCLAW_GATEWAY_BIND}", '${OPENCLAW_GATEWAY_BIND}',
"--port", '--port',
"${OPENCLAW_GATEWAY_PORT}" '${OPENCLAW_GATEWAY_PORT}',
] ]
``` ```
@@ -202,6 +204,7 @@ Anything installed at runtime will be lost on restart.
All external binaries required by skills must be installed at image build time. All external binaries required by skills must be installed at image build time.
The examples below show three common binaries only: The examples below show three common binaries only:
- `gog` for Gmail access - `gog` for Gmail access
- `goplaces` for Google Places - `goplaces` for Google Places
- `wacli` for WhatsApp - `wacli` for WhatsApp
@@ -210,6 +213,7 @@ These are examples, not a complete list.
You may install as many binaries as needed using the same pattern. You may install as many binaries as needed using the same pattern.
If you add new skills later that depend on additional binaries, you must: If you add new skills later that depend on additional binaries, you must:
1. Update the Dockerfile 1. Update the Dockerfile
2. Rebuild the image 2. Rebuild the image
3. Restart the containers 3. Restart the containers
@@ -250,7 +254,7 @@ RUN pnpm ui:build
ENV NODE_ENV=production ENV NODE_ENV=production
CMD ["node","dist/index.mjs"] CMD ["node","dist/index.js"]
``` ```
--- ---
@@ -311,15 +315,15 @@ Paste your gateway token.
OpenClaw runs in Docker, but Docker is not the source of truth. OpenClaw runs in Docker, but Docker is not the source of truth.
All long-lived state must survive restarts, rebuilds, and reboots. All long-lived state must survive restarts, rebuilds, and reboots.
| Component | Location | Persistence mechanism | Notes | | Component | Location | Persistence mechanism | Notes |
|---|---|---|---| | ------------------- | --------------------------------- | ---------------------- | -------------------------------- |
| Gateway config | `/home/node/.openclaw/` | Host volume mount | Includes `openclaw.json`, tokens | | Gateway config | `/home/node/.openclaw/` | Host volume mount | Includes `openclaw.json`, tokens |
| Model auth profiles | `/home/node/.openclaw/` | Host volume mount | OAuth tokens, API keys | | Model auth profiles | `/home/node/.openclaw/` | Host volume mount | OAuth tokens, API keys |
| Skill configs | `/home/node/.openclaw/skills/` | Host volume mount | Skill-level state | | Skill configs | `/home/node/.openclaw/skills/` | Host volume mount | Skill-level state |
| Agent workspace | `/home/node/.openclaw/workspace/` | Host volume mount | Code and agent artifacts | | Agent workspace | `/home/node/.openclaw/workspace/` | Host volume mount | Code and agent artifacts |
| WhatsApp session | `/home/node/.openclaw/` | Host volume mount | Preserves QR login | | WhatsApp session | `/home/node/.openclaw/` | Host volume mount | Preserves QR login |
| Gmail keyring | `/home/node/.openclaw/` | Host volume + password | Requires `GOG_KEYRING_PASSWORD` | | Gmail keyring | `/home/node/.openclaw/` | Host volume + password | Requires `GOG_KEYRING_PASSWORD` |
| External binaries | `/usr/local/bin/` | Docker image | Must be baked at build time | | External binaries | `/usr/local/bin/` | Docker image | Must be baked at build time |
| Node runtime | Container filesystem | Docker image | Rebuilt every image build | | Node runtime | Container filesystem | Docker image | Rebuilt every image build |
| OS packages | Container filesystem | Docker image | Do not install at runtime | | OS packages | Container filesystem | Docker image | Do not install at runtime |
| Docker container | Ephemeral | Restartable | Safe to destroy | | Docker container | Ephemeral | Restartable | Safe to destroy |

View File

@@ -1,9 +1,10 @@
--- ---
summary: "OpenClaw plugins/extensions: discovery, config, and safety" summary: 'OpenClaw plugins/extensions: discovery, config, and safety'
read_when: read_when:
- Adding or modifying plugins/extensions - Adding or modifying plugins/extensions
- Documenting plugin install or load rules - Documenting plugin install or load rules
--- ---
# Plugins (Extensions) # Plugins (Extensions)
## Quick start (new to plugins?) ## Quick start (new to plugins?)
@@ -17,19 +18,19 @@ install).
Fast path: Fast path:
1) See whats already loaded: 1. See whats already loaded:
```bash ```bash
openclaw plugins list openclaw plugins list
``` ```
2) Install an official plugin (example: Voice Call): 2. Install an official plugin (example: Voice Call):
```bash ```bash
openclaw plugins install @openclaw/voice-call openclaw plugins install @openclaw/voice-call
``` ```
3) Restart the Gateway, then configure under `plugins.entries.<id>.config`. 3. Restart the Gateway, then configure under `plugins.entries.<id>.config`.
See [Voice Call](/plugins/voice-call) for a concrete example plugin. See [Voice Call](/plugins/voice-call) for a concrete example plugin.
@@ -73,12 +74,13 @@ Plugins can access selected core helpers via `api.runtime`. For telephony TTS:
```ts ```ts
const result = await api.runtime.tts.textToSpeechTelephony({ const result = await api.runtime.tts.textToSpeechTelephony({
text: "Hello from OpenClaw", text: 'Hello from OpenClaw',
cfg: api.config, cfg: api.config,
}); });
``` ```
Notes: Notes:
- Uses core `messages.tts` configuration (OpenAI or ElevenLabs). - Uses core `messages.tts` configuration (OpenAI or ElevenLabs).
- Returns PCM audio buffer + sample rate. Plugins must resample/encode for providers. - Returns PCM audio buffer + sample rate. Plugins must resample/encode for providers.
- Edge TTS is not supported for telephony. - Edge TTS is not supported for telephony.
@@ -87,18 +89,22 @@ Notes:
OpenClaw scans, in order: OpenClaw scans, in order:
1) Config paths 1. Config paths
- `plugins.load.paths` (file or directory) - `plugins.load.paths` (file or directory)
2) Workspace extensions 2. Workspace extensions
- `<workspace>/.openclaw/extensions/*.ts` - `<workspace>/.openclaw/extensions/*.ts`
- `<workspace>/.openclaw/extensions/*/index.ts` - `<workspace>/.openclaw/extensions/*/index.ts`
3) Global extensions 3. Global extensions
- `~/.openclaw/extensions/*.ts` - `~/.openclaw/extensions/*.ts`
- `~/.openclaw/extensions/*/index.ts` - `~/.openclaw/extensions/*/index.ts`
4) Bundled extensions (shipped with OpenClaw, **disabled by default**) 4. Bundled extensions (shipped with OpenClaw, **disabled by default**)
- `<openclaw>/extensions/*` - `<openclaw>/extensions/*`
Bundled plugins must be enabled explicitly via `plugins.entries.<id>.enabled` Bundled plugins must be enabled explicitly via `plugins.entries.<id>.enabled`
@@ -164,6 +170,7 @@ Example:
OpenClaw can also merge **external channel catalogs** (for example, an MPM OpenClaw can also merge **external channel catalogs** (for example, an MPM
registry export). Drop a JSON file at one of: registry export). Drop a JSON file at one of:
- `~/.openclaw/mpm/plugins.json` - `~/.openclaw/mpm/plugins.json`
- `~/.openclaw/mpm/catalog.json` - `~/.openclaw/mpm/catalog.json`
- `~/.openclaw/plugins/catalog.json` - `~/.openclaw/plugins/catalog.json`
@@ -188,17 +195,18 @@ configured id.
{ {
plugins: { plugins: {
enabled: true, enabled: true,
allow: ["voice-call"], allow: ['voice-call'],
deny: ["untrusted-plugin"], deny: ['untrusted-plugin'],
load: { paths: ["~/Projects/oss/voice-call-extension"] }, load: { paths: ['~/Projects/oss/voice-call-extension'] },
entries: { entries: {
"voice-call": { enabled: true, config: { provider: "twilio" } } 'voice-call': { enabled: true, config: { provider: 'twilio' } },
} },
} },
} }
``` ```
Fields: Fields:
- `enabled`: master toggle (default: true) - `enabled`: master toggle (default: true)
- `allow`: allowlist (optional) - `allow`: allowlist (optional)
- `deny`: denylist (optional; deny wins) - `deny`: denylist (optional; deny wins)
@@ -208,6 +216,7 @@ Fields:
Config changes **require a gateway restart**. Config changes **require a gateway restart**.
Validation rules (strict): Validation rules (strict):
- Unknown plugin ids in `entries`, `allow`, `deny`, or `slots` are **errors**. - Unknown plugin ids in `entries`, `allow`, `deny`, or `slots` are **errors**.
- Unknown `channels.<id>` keys are **errors** unless a plugin manifest declares - Unknown `channels.<id>` keys are **errors** unless a plugin manifest declares
the channel id. the channel id.
@@ -224,9 +233,9 @@ Some plugin categories are **exclusive** (only one active at a time). Use
{ {
plugins: { plugins: {
slots: { slots: {
memory: "memory-core" // or "none" to disable memory plugins memory: 'memory-core', // or "none" to disable memory plugins
} },
} },
} }
``` ```
@@ -311,6 +320,7 @@ export default function register(api) {
``` ```
Notes: Notes:
- Hook directories follow the normal hook structure (`HOOK.md` + `handler.ts`). - Hook directories follow the normal hook structure (`HOOK.md` + `handler.ts`).
- Hook eligibility rules still apply (OS/bins/env/config requirements). - Hook eligibility rules still apply (OS/bins/env/config requirements).
- Plugin-managed hooks show up in `openclaw hooks list` with `plugin:<id>`. - Plugin-managed hooks show up in `openclaw hooks list` with `plugin:<id>`.
@@ -330,29 +340,29 @@ Example:
```ts ```ts
api.registerProvider({ api.registerProvider({
id: "acme", id: 'acme',
label: "AcmeAI", label: 'AcmeAI',
auth: [ auth: [
{ {
id: "oauth", id: 'oauth',
label: "OAuth", label: 'OAuth',
kind: "oauth", kind: 'oauth',
run: async (ctx) => { run: async (ctx) => {
// Run OAuth flow and return auth profiles. // Run OAuth flow and return auth profiles.
return { return {
profiles: [ profiles: [
{ {
profileId: "acme:default", profileId: 'acme:default',
credential: { credential: {
type: "oauth", type: 'oauth',
provider: "acme", provider: 'acme',
access: "...", access: '...',
refresh: "...", refresh: '...',
expires: Date.now() + 3600 * 1000, expires: Date.now() + 3600 * 1000,
}, },
}, },
], ],
defaultModel: "acme/opus-1", defaultModel: 'acme/opus-1',
}; };
}, },
}, },
@@ -361,6 +371,7 @@ api.registerProvider({
``` ```
Notes: Notes:
- `run` receives a `ProviderAuthContext` with `prompter`, `runtime`, - `run` receives a `ProviderAuthContext` with `prompter`, `runtime`,
`openUrl`, and `oauth.createVpsAwareHandlers` helpers. `openUrl`, and `oauth.createVpsAwareHandlers` helpers.
- Return `configPatch` when you need to add default models or provider config. - Return `configPatch` when you need to add default models or provider config.
@@ -374,23 +385,26 @@ validated by your channel plugin code.
```ts ```ts
const myChannel = { const myChannel = {
id: "acmechat", id: 'acmechat',
meta: { meta: {
id: "acmechat", id: 'acmechat',
label: "AcmeChat", label: 'AcmeChat',
selectionLabel: "AcmeChat (API)", selectionLabel: 'AcmeChat (API)',
docsPath: "/channels/acmechat", docsPath: '/channels/acmechat',
blurb: "demo channel plugin.", blurb: 'demo channel plugin.',
aliases: ["acme"], aliases: ['acme'],
}, },
capabilities: { chatTypes: ["direct"] }, capabilities: { chatTypes: ['direct'] },
config: { config: {
listAccountIds: (cfg) => Object.keys(cfg.channels?.acmechat?.accounts ?? {}), listAccountIds: (cfg) =>
Object.keys(cfg.channels?.acmechat?.accounts ?? {}),
resolveAccount: (cfg, accountId) => resolveAccount: (cfg, accountId) =>
(cfg.channels?.acmechat?.accounts?.[accountId ?? "default"] ?? { accountId }), cfg.channels?.acmechat?.accounts?.[accountId ?? 'default'] ?? {
accountId,
},
}, },
outbound: { outbound: {
deliveryMode: "direct", deliveryMode: 'direct',
sendText: async () => ({ ok: true }), sendText: async () => ({ ok: true }),
}, },
}; };
@@ -401,6 +415,7 @@ export default function (api) {
``` ```
Notes: Notes:
- Put config under `channels.<id>` (not `plugins.entries`). - Put config under `channels.<id>` (not `plugins.entries`).
- `meta.label` is used for labels in CLI/UI lists. - `meta.label` is used for labels in CLI/UI lists.
- `meta.aliases` adds alternate ids for normalization and CLI inputs. - `meta.aliases` adds alternate ids for normalization and CLI inputs.
@@ -412,27 +427,32 @@ Notes:
Use this when you want a **new chat surface** (a “messaging channel”), not a model provider. Use this when you want a **new chat surface** (a “messaging channel”), not a model provider.
Model provider docs live under `/providers/*`. Model provider docs live under `/providers/*`.
1) Pick an id + config shape 1. Pick an id + config shape
- All channel config lives under `channels.<id>`. - All channel config lives under `channels.<id>`.
- Prefer `channels.<id>.accounts.<accountId>` for multiaccount setups. - Prefer `channels.<id>.accounts.<accountId>` for multiaccount setups.
2) Define the channel metadata 2. Define the channel metadata
- `meta.label`, `meta.selectionLabel`, `meta.docsPath`, `meta.blurb` control CLI/UI lists. - `meta.label`, `meta.selectionLabel`, `meta.docsPath`, `meta.blurb` control CLI/UI lists.
- `meta.docsPath` should point at a docs page like `/channels/<id>`. - `meta.docsPath` should point at a docs page like `/channels/<id>`.
- `meta.preferOver` lets a plugin replace another channel (auto-enable prefers it). - `meta.preferOver` lets a plugin replace another channel (auto-enable prefers it).
- `meta.detailLabel` and `meta.systemImage` are used by UIs for detail text/icons. - `meta.detailLabel` and `meta.systemImage` are used by UIs for detail text/icons.
3) Implement the required adapters 3. Implement the required adapters
- `config.listAccountIds` + `config.resolveAccount` - `config.listAccountIds` + `config.resolveAccount`
- `capabilities` (chat types, media, threads, etc.) - `capabilities` (chat types, media, threads, etc.)
- `outbound.deliveryMode` + `outbound.sendText` (for basic send) - `outbound.deliveryMode` + `outbound.sendText` (for basic send)
4) Add optional adapters as needed 4. Add optional adapters as needed
- `setup` (wizard), `security` (DM policy), `status` (health/diagnostics) - `setup` (wizard), `security` (DM policy), `status` (health/diagnostics)
- `gateway` (start/stop/login), `mentions`, `threading`, `streaming` - `gateway` (start/stop/login), `mentions`, `threading`, `streaming`
- `actions` (message actions), `commands` (native command behavior) - `actions` (message actions), `commands` (native command behavior)
5) Register the channel in your plugin 5. Register the channel in your plugin
- `api.registerChannel({ plugin })` - `api.registerChannel({ plugin })`
Minimal config example: Minimal config example:
@@ -442,10 +462,10 @@ Minimal config example:
channels: { channels: {
acmechat: { acmechat: {
accounts: { accounts: {
default: { token: "ACME_TOKEN", enabled: true } default: { token: 'ACME_TOKEN', enabled: true },
} },
} },
} },
} }
``` ```
@@ -453,23 +473,26 @@ Minimal channel plugin (outboundonly):
```ts ```ts
const plugin = { const plugin = {
id: "acmechat", id: 'acmechat',
meta: { meta: {
id: "acmechat", id: 'acmechat',
label: "AcmeChat", label: 'AcmeChat',
selectionLabel: "AcmeChat (API)", selectionLabel: 'AcmeChat (API)',
docsPath: "/channels/acmechat", docsPath: '/channels/acmechat',
blurb: "AcmeChat messaging channel.", blurb: 'AcmeChat messaging channel.',
aliases: ["acme"], aliases: ['acme'],
}, },
capabilities: { chatTypes: ["direct"] }, capabilities: { chatTypes: ['direct'] },
config: { config: {
listAccountIds: (cfg) => Object.keys(cfg.channels?.acmechat?.accounts ?? {}), listAccountIds: (cfg) =>
Object.keys(cfg.channels?.acmechat?.accounts ?? {}),
resolveAccount: (cfg, accountId) => resolveAccount: (cfg, accountId) =>
(cfg.channels?.acmechat?.accounts?.[accountId ?? "default"] ?? { accountId }), cfg.channels?.acmechat?.accounts?.[accountId ?? 'default'] ?? {
accountId,
},
}, },
outbound: { outbound: {
deliveryMode: "direct", deliveryMode: 'direct',
sendText: async ({ text }) => { sendText: async ({ text }) => {
// deliver `text` to your channel here // deliver `text` to your channel here
return { ok: true }; return { ok: true };
@@ -493,7 +516,7 @@ See the dedicated guide: [Plugin agent tools](/plugins/agent-tools).
```ts ```ts
export default function (api) { export default function (api) {
api.registerGatewayMethod("myplugin.status", ({ respond }) => { api.registerGatewayMethod('myplugin.status', ({ respond }) => {
respond(true, { ok: true }); respond(true, { ok: true });
}); });
} }
@@ -503,11 +526,14 @@ export default function (api) {
```ts ```ts
export default function (api) { export default function (api) {
api.registerCli(({ program }) => { api.registerCli(
program.command("mycmd").action(() => { ({ program }) => {
console.log("Hello"); program.command('mycmd').action(() => {
}); console.log('Hello');
}, { commands: ["mycmd"] }); });
},
{ commands: ['mycmd'] },
);
} }
``` ```
@@ -520,8 +546,8 @@ that don't need LLM processing.
```ts ```ts
export default function (api) { export default function (api) {
api.registerCommand({ api.registerCommand({
name: "mystatus", name: 'mystatus',
description: "Show plugin status", description: 'Show plugin status',
handler: (ctx) => ({ handler: (ctx) => ({
text: `Plugin is running! Channel: ${ctx.channel}`, text: `Plugin is running! Channel: ${ctx.channel}`,
}), }),
@@ -550,12 +576,12 @@ Example with authorization and arguments:
```ts ```ts
api.registerCommand({ api.registerCommand({
name: "setmode", name: 'setmode',
description: "Set plugin mode", description: 'Set plugin mode',
acceptsArgs: true, acceptsArgs: true,
requireAuth: true, requireAuth: true,
handler: async (ctx) => { handler: async (ctx) => {
const mode = ctx.args?.trim() || "default"; const mode = ctx.args?.trim() || 'default';
await saveMode(mode); await saveMode(mode);
return { text: `Mode set to: ${mode}` }; return { text: `Mode set to: ${mode}` };
}, },
@@ -563,6 +589,7 @@ api.registerCommand({
``` ```
Notes: Notes:
- Plugin commands are processed **before** built-in commands and the AI agent - Plugin commands are processed **before** built-in commands and the AI agent
- Commands are registered globally and work across all channels - Commands are registered globally and work across all channels
- Command names are case-insensitive (`/MyStatus` matches `/mystatus`) - Command names are case-insensitive (`/MyStatus` matches `/mystatus`)
@@ -575,9 +602,9 @@ Notes:
```ts ```ts
export default function (api) { export default function (api) {
api.registerService({ api.registerService({
id: "my-service", id: 'my-service',
start: () => api.logger.info("ready"), start: () => api.logger.info('ready'),
stop: () => api.logger.info("bye"), stop: () => api.logger.info('bye'),
}); });
} }
``` ```
@@ -635,4 +662,4 @@ Plugins run in-process with the Gateway. Treat them as trusted code:
Plugins can (and should) ship tests: Plugins can (and should) ship tests:
- In-repo plugins can keep Vitest tests under `src/**` (example: `src/plugins/voice-call.plugin.test.ts`). - In-repo plugins can keep Vitest tests under `src/**` (example: `src/plugins/voice-call.plugin.test.ts`).
- Separately published plugins should run their own CI (lint/build/test) and validate `openclaw.extensions` points at the built entrypoint (`dist/index.mjs`). - Separately published plugins should run their own CI (lint/build/test) and validate `openclaw.extensions` points at the built entrypoint (`dist/index.js`).

View File

@@ -9,20 +9,20 @@
# #
# See https://fly.io/docs/reference/configuration/ # See https://fly.io/docs/reference/configuration/
app = "my-openclaw" # change to your app name app = "my-openclaw" # change to your app name
primary_region = "iad" # change to your closest region primary_region = "iad" # change to your closest region
[build] [build]
dockerfile = "Dockerfile" dockerfile = "Dockerfile"
[env] [env]
NODE_ENV = "production" NODE_ENV = "production"
OPENCLAW_PREFER_PNPM = "1" OPENCLAW_PREFER_PNPM = "1"
OPENCLAW_STATE_DIR = "/data" OPENCLAW_STATE_DIR = "/data"
NODE_OPTIONS = "--max-old-space-size=1536" NODE_OPTIONS = "--max-old-space-size=1536"
[processes] [processes]
app = "node dist/index.mjs gateway --allow-unconfigured --port 3000 --bind lan" app = "node dist/index.js gateway --allow-unconfigured --port 3000 --bind lan"
# NOTE: No [http_service] block = no public ingress allocated. # NOTE: No [http_service] block = no public ingress allocated.
# The gateway will only be accessible via: # The gateway will only be accessible via:
@@ -31,9 +31,9 @@ primary_region = "iad" # change to your closest region
# - fly ssh console # - fly ssh console
[[vm]] [[vm]]
size = "shared-cpu-2x" size = "shared-cpu-2x"
memory = "2048mb" memory = "2048mb"
[mounts] [mounts]
source = "openclaw_data" source = "openclaw_data"
destination = "/data" destination = "/data"

View File

@@ -2,33 +2,33 @@
# See https://fly.io/docs/reference/configuration/ # See https://fly.io/docs/reference/configuration/
app = "openclaw" app = "openclaw"
primary_region = "iad" # change to your closest region primary_region = "iad" # change to your closest region
[build] [build]
dockerfile = "Dockerfile" dockerfile = "Dockerfile"
[env] [env]
NODE_ENV = "production" NODE_ENV = "production"
# Fly uses x86, but keep this for consistency # Fly uses x86, but keep this for consistency
OPENCLAW_PREFER_PNPM = "1" OPENCLAW_PREFER_PNPM = "1"
OPENCLAW_STATE_DIR = "/data" OPENCLAW_STATE_DIR = "/data"
NODE_OPTIONS = "--max-old-space-size=1536" NODE_OPTIONS = "--max-old-space-size=1536"
[processes] [processes]
app = "node dist/index.mjs gateway --allow-unconfigured --port 3000 --bind lan" app = "node dist/index.js gateway --allow-unconfigured --port 3000 --bind lan"
[http_service] [http_service]
internal_port = 3000 internal_port = 3000
force_https = true force_https = true
auto_stop_machines = false # Keep running for persistent connections auto_stop_machines = false # Keep running for persistent connections
auto_start_machines = true auto_start_machines = true
min_machines_running = 1 min_machines_running = 1
processes = ["app"] processes = ["app"]
[[vm]] [[vm]]
size = "shared-cpu-2x" size = "shared-cpu-2x"
memory = "2048mb" memory = "2048mb"
[mounts] [mounts]
source = "openclaw_data" source = "openclaw_data"
destination = "/data" destination = "/data"

View File

@@ -1,6 +1,6 @@
#!/usr/bin/env node #!/usr/bin/env node
import module from "node:module"; import module from 'node:module';
// https://nodejs.org/api/module.html#module-compile-cache // https://nodejs.org/api/module.html#module-compile-cache
if (module.enableCompileCache && !process.env.NODE_DISABLE_COMPILE_CACHE) { if (module.enableCompileCache && !process.env.NODE_DISABLE_COMPILE_CACHE) {
@@ -11,4 +11,4 @@ if (module.enableCompileCache && !process.env.NODE_DISABLE_COMPILE_CACHE) {
} }
} }
await import("./dist/entry.mjs"); await import('./dist/entry.js');

View File

@@ -3,9 +3,9 @@
"version": "2026.1.29", "version": "2026.1.29",
"description": "WhatsApp gateway CLI (Baileys web) with Pi RPC agent", "description": "WhatsApp gateway CLI (Baileys web) with Pi RPC agent",
"type": "module", "type": "module",
"main": "dist/index.mjs", "main": "dist/index.js",
"exports": { "exports": {
".": "./dist/index.mjs", ".": "./dist/index.js",
"./plugin-sdk": "./dist/plugin-sdk/index.js", "./plugin-sdk": "./dist/plugin-sdk/index.js",
"./plugin-sdk/*": "./dist/plugin-sdk/*", "./plugin-sdk/*": "./dist/plugin-sdk/*",
"./cli-entry": "./openclaw.mjs" "./cli-entry": "./openclaw.mjs"
@@ -85,7 +85,7 @@
"docs:bin": "node scripts/build-docs-list.mjs", "docs:bin": "node scripts/build-docs-list.mjs",
"docs:dev": "cd docs && mint dev", "docs:dev": "cd docs && mint dev",
"docs:build": "cd docs && pnpm dlx --reporter append-only mint broken-links", "docs:build": "cd docs && pnpm dlx --reporter append-only mint broken-links",
"build": "pnpm canvas:a2ui:bundle && tsdown && node --import tsx scripts/canvas-a2ui-copy.ts && node --import tsx scripts/copy-hook-metadata.ts && node --import tsx scripts/write-build-info.ts", "build": "pnpm canvas:a2ui:bundle && tsc -p tsconfig.json --noEmit false && node --import tsx scripts/canvas-a2ui-copy.ts && node --import tsx scripts/copy-hook-metadata.ts && node --import tsx scripts/write-build-info.ts",
"plugins:sync": "node --import tsx scripts/sync-plugin-versions.ts", "plugins:sync": "node --import tsx scripts/sync-plugin-versions.ts",
"release:check": "node --import tsx scripts/release-check.ts", "release:check": "node --import tsx scripts/release-check.ts",
"ui:install": "node scripts/ui.js install", "ui:install": "node scripts/ui.js install",
@@ -227,7 +227,6 @@
"oxlint": "^1.42.0", "oxlint": "^1.42.0",
"oxlint-tsgolint": "^0.11.4", "oxlint-tsgolint": "^0.11.4",
"rolldown": "1.0.0-rc.2", "rolldown": "1.0.0-rc.2",
"tsdown": "^0.20.1",
"tsx": "^4.21.0", "tsx": "^4.21.0",
"typescript": "^5.9.3", "typescript": "^5.9.3",
"vitest": "^4.0.18" "vitest": "^4.0.18"

424
pnpm-lock.yaml generated
View File

@@ -220,9 +220,6 @@ importers:
rolldown: rolldown:
specifier: 1.0.0-rc.2 specifier: 1.0.0-rc.2
version: 1.0.0-rc.2 version: 1.0.0-rc.2
tsdown:
specifier: ^0.20.1
version: 0.20.1(@typescript/native-preview@7.0.0-dev.20260130.1)(typescript@5.9.3)
tsx: tsx:
specifier: ^4.21.0 specifier: ^4.21.0
version: 4.21.0 version: 4.21.0
@@ -663,36 +660,19 @@ packages:
resolution: {integrity: sha512-XTmhdItcBckcVVTy65Xp+42xG4LX5GK+9AqAsXPXk4IqUNv+LyQo5TMwNjuFYBfAB2GTG9iSQGk+QLc03vhf3w==} resolution: {integrity: sha512-XTmhdItcBckcVVTy65Xp+42xG4LX5GK+9AqAsXPXk4IqUNv+LyQo5TMwNjuFYBfAB2GTG9iSQGk+QLc03vhf3w==}
engines: {node: '>=16'} engines: {node: '>=16'}
'@babel/generator@8.0.0-beta.4':
resolution: {integrity: sha512-5xRfRZk6wx1BRu2XnTE8cTh2mx1ixrZ3/vpn7p/RCJpgctL6pexVVHE3eqtwlYvHhPAuOYCAlnsAyXpBdmfh5Q==}
engines: {node: ^20.19.0 || >=22.12.0}
'@babel/helper-string-parser@7.27.1': '@babel/helper-string-parser@7.27.1':
resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==} resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==}
engines: {node: '>=6.9.0'} engines: {node: '>=6.9.0'}
'@babel/helper-string-parser@8.0.0-beta.4':
resolution: {integrity: sha512-FGwbdQ/I2nJXXfyxa7dT0Fr/zPWwgX7m+hNVj0HrIHYJtyLxSQeQY1Kd8QkAYviQJV3OWFlRLuGd5epF03bdQg==}
engines: {node: ^20.19.0 || >=22.12.0}
'@babel/helper-validator-identifier@7.28.5': '@babel/helper-validator-identifier@7.28.5':
resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==} resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==}
engines: {node: '>=6.9.0'} engines: {node: '>=6.9.0'}
'@babel/helper-validator-identifier@8.0.0-beta.4':
resolution: {integrity: sha512-6t0IaUEzlinbLmsGIvBZIHEJGjuchx+cMj+FbS78zL17tucYervgbwO07V5/CgBenVraontpmyMCTVyqCfxhFQ==}
engines: {node: ^20.19.0 || >=22.12.0}
'@babel/parser@7.28.6': '@babel/parser@7.28.6':
resolution: {integrity: sha512-TeR9zWR18BvbfPmGbLampPMW+uW1NZnJlRuuHso8i87QZNq2JRF9i6RgxRqtEq+wQGsS19NNTWr2duhnE49mfQ==} resolution: {integrity: sha512-TeR9zWR18BvbfPmGbLampPMW+uW1NZnJlRuuHso8i87QZNq2JRF9i6RgxRqtEq+wQGsS19NNTWr2duhnE49mfQ==}
engines: {node: '>=6.0.0'} engines: {node: '>=6.0.0'}
hasBin: true hasBin: true
'@babel/parser@8.0.0-beta.4':
resolution: {integrity: sha512-fBcUqUN3eenLyg25QFkOwY1lmV6L0RdG92g6gxyS2CVCY8kHdibkQz1+zV3bLzxcvNnfHoi3i9n5Dci+g93acg==}
engines: {node: ^20.19.0 || >=22.12.0}
hasBin: true
'@babel/runtime@7.28.6': '@babel/runtime@7.28.6':
resolution: {integrity: sha512-05WQkdpL9COIMz4LjTxGpPNCdlpyimKppYNoJ5Di5EUObifl8t4tuLuUBBZEpoLYOmfvIWrsp9fCl0HoPRVTdA==} resolution: {integrity: sha512-05WQkdpL9COIMz4LjTxGpPNCdlpyimKppYNoJ5Di5EUObifl8t4tuLuUBBZEpoLYOmfvIWrsp9fCl0HoPRVTdA==}
engines: {node: '>=6.9.0'} engines: {node: '>=6.9.0'}
@@ -701,10 +681,6 @@ packages:
resolution: {integrity: sha512-0ZrskXVEHSWIqZM/sQZ4EV3jZJXRkio/WCxaqKZP1g//CEWEPSfeZFcms4XeKBCHU0ZKnIkdJeU/kF+eRp5lBg==} resolution: {integrity: sha512-0ZrskXVEHSWIqZM/sQZ4EV3jZJXRkio/WCxaqKZP1g//CEWEPSfeZFcms4XeKBCHU0ZKnIkdJeU/kF+eRp5lBg==}
engines: {node: '>=6.9.0'} engines: {node: '>=6.9.0'}
'@babel/types@8.0.0-beta.4':
resolution: {integrity: sha512-xjk2xqYp25ePzAs0I08hN2lrbUDDQFfCjwq6MIEa8HwHa0WK8NfNtdvtXod8Ku2CbE1iui7qwWojGvjQiyrQeA==}
engines: {node: ^20.19.0 || >=22.12.0}
'@bcoe/v8-coverage@1.0.2': '@bcoe/v8-coverage@1.0.2':
resolution: {integrity: sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA==} resolution: {integrity: sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA==}
engines: {node: '>=18'} engines: {node: '>=18'}
@@ -1145,9 +1121,6 @@ packages:
resolution: {integrity: sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==} resolution: {integrity: sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==}
engines: {node: '>=18.0.0'} engines: {node: '>=18.0.0'}
'@jridgewell/gen-mapping@0.3.13':
resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==}
'@jridgewell/resolve-uri@3.1.2': '@jridgewell/resolve-uri@3.1.2':
resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==}
engines: {node: '>=6.0.0'} engines: {node: '>=6.0.0'}
@@ -1822,9 +1795,6 @@ packages:
resolution: {integrity: sha512-R5R9tb2AXs2IRLNKLBJDynhkfmx7mX0vi8NkhZb3gUkPWHn6HXk5J8iQ/dql0U3ApfWym4kXXmBDRGO+oeOfjg==} resolution: {integrity: sha512-R5R9tb2AXs2IRLNKLBJDynhkfmx7mX0vi8NkhZb3gUkPWHn6HXk5J8iQ/dql0U3ApfWym4kXXmBDRGO+oeOfjg==}
engines: {node: '>=14'} engines: {node: '>=14'}
'@oxc-project/types@0.110.0':
resolution: {integrity: sha512-6Ct21OIlrEnFEJk5LT4e63pk3btsI6/TusD/GStLi7wYlGJNOl1GI9qvXAnRAxQU9zqA2Oz+UwhfTOU2rPZVow==}
'@oxc-project/types@0.111.0': '@oxc-project/types@0.111.0':
resolution: {integrity: sha512-bh54LJMafgRGl2cPQ/QM+tI5rWaShm/wK9KywEj/w36MhiPKXYM67H2y3q+9pr4YO7ufwg2AKdBAZkhHBD8ClA==} resolution: {integrity: sha512-bh54LJMafgRGl2cPQ/QM+tI5rWaShm/wK9KywEj/w36MhiPKXYM67H2y3q+9pr4YO7ufwg2AKdBAZkhHBD8ClA==}
@@ -1978,9 +1948,6 @@ packages:
'@protobufjs/utf8@1.1.0': '@protobufjs/utf8@1.1.0':
resolution: {integrity: sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==} resolution: {integrity: sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==}
'@quansync/fs@1.0.0':
resolution: {integrity: sha512-4TJ3DFtlf1L5LDMaM6CanJ/0lckGNtJcMjQ1NAV6zDmA0tEHKZtxNKin8EgPaVX1YzljbxckyT2tJrpQKAtngQ==}
'@reflink/reflink-darwin-arm64@0.1.19': '@reflink/reflink-darwin-arm64@0.1.19':
resolution: {integrity: sha512-ruy44Lpepdk1FqDz38vExBY/PVUsjxZA+chd9wozjUH9JjuDT/HEaQYA6wYN9mf041l0yLVar6BCZuWABJvHSA==} resolution: {integrity: sha512-ruy44Lpepdk1FqDz38vExBY/PVUsjxZA+chd9wozjUH9JjuDT/HEaQYA6wYN9mf041l0yLVar6BCZuWABJvHSA==}
engines: {node: '>= 10'} engines: {node: '>= 10'}
@@ -2033,163 +2000,83 @@ packages:
resolution: {integrity: sha512-DmCG8GzysnCZ15bres3N5AHCmwBwYgp0As6xjhQ47rAUTUXxJiK+lLUxaGsX3hd/30qUpVElh05PbGuxRPgJwA==} resolution: {integrity: sha512-DmCG8GzysnCZ15bres3N5AHCmwBwYgp0As6xjhQ47rAUTUXxJiK+lLUxaGsX3hd/30qUpVElh05PbGuxRPgJwA==}
engines: {node: '>= 10'} engines: {node: '>= 10'}
'@rolldown/binding-android-arm64@1.0.0-rc.1':
resolution: {integrity: sha512-He6ZoCfv5D7dlRbrhNBkuMVIHd0GDnjJwbICE1OWpG7G3S2gmJ+eXkcNLJjzjNDpeI2aRy56ou39AJM9AD8YFA==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [arm64]
os: [android]
'@rolldown/binding-android-arm64@1.0.0-rc.2': '@rolldown/binding-android-arm64@1.0.0-rc.2':
resolution: {integrity: sha512-AGV80viZ4Hil4C16GFH+PSwq10jclV9oyRFhD+5HdowPOCJ+G+99N5AClQvMkUMIahTY8cX0SQpKEEWcCg6fSA==} resolution: {integrity: sha512-AGV80viZ4Hil4C16GFH+PSwq10jclV9oyRFhD+5HdowPOCJ+G+99N5AClQvMkUMIahTY8cX0SQpKEEWcCg6fSA==}
engines: {node: ^20.19.0 || >=22.12.0} engines: {node: ^20.19.0 || >=22.12.0}
cpu: [arm64] cpu: [arm64]
os: [android] os: [android]
'@rolldown/binding-darwin-arm64@1.0.0-rc.1':
resolution: {integrity: sha512-YzJdn08kSOXnj85ghHauH2iHpOJ6eSmstdRTLyaziDcUxe9SyQJgGyx/5jDIhDvtOcNvMm2Ju7m19+S/Rm1jFg==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [arm64]
os: [darwin]
'@rolldown/binding-darwin-arm64@1.0.0-rc.2': '@rolldown/binding-darwin-arm64@1.0.0-rc.2':
resolution: {integrity: sha512-PYR+PQu1mMmQiiKHN2JiOctvH32Xc/Mf+Su2RSmWtC9BbIqlqsVWjbulnShk0imjRim0IsbkMMCN5vYQwiuqaA==} resolution: {integrity: sha512-PYR+PQu1mMmQiiKHN2JiOctvH32Xc/Mf+Su2RSmWtC9BbIqlqsVWjbulnShk0imjRim0IsbkMMCN5vYQwiuqaA==}
engines: {node: ^20.19.0 || >=22.12.0} engines: {node: ^20.19.0 || >=22.12.0}
cpu: [arm64] cpu: [arm64]
os: [darwin] os: [darwin]
'@rolldown/binding-darwin-x64@1.0.0-rc.1':
resolution: {integrity: sha512-cIvAbqM+ZVV6lBSKSBtlNqH5iCiW933t1q8j0H66B3sjbe8AxIRetVqfGgcHcJtMzBIkIALlL9fcDrElWLJQcQ==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [x64]
os: [darwin]
'@rolldown/binding-darwin-x64@1.0.0-rc.2': '@rolldown/binding-darwin-x64@1.0.0-rc.2':
resolution: {integrity: sha512-X2G36Z6oh5ynoYpE2JAyG+uQ4kO/3N7XydM/I98FNk8VVgDKjajFF+v7TXJ2FMq6xa7Xm0UIUKHW2MRQroqoUA==} resolution: {integrity: sha512-X2G36Z6oh5ynoYpE2JAyG+uQ4kO/3N7XydM/I98FNk8VVgDKjajFF+v7TXJ2FMq6xa7Xm0UIUKHW2MRQroqoUA==}
engines: {node: ^20.19.0 || >=22.12.0} engines: {node: ^20.19.0 || >=22.12.0}
cpu: [x64] cpu: [x64]
os: [darwin] os: [darwin]
'@rolldown/binding-freebsd-x64@1.0.0-rc.1':
resolution: {integrity: sha512-rVt+B1B/qmKwCl1XD02wKfgh3vQPXRXdB/TicV2w6g7RVAM1+cZcpigwhLarqiVCxDObFZ7UgXCxPC7tpDoRog==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [x64]
os: [freebsd]
'@rolldown/binding-freebsd-x64@1.0.0-rc.2': '@rolldown/binding-freebsd-x64@1.0.0-rc.2':
resolution: {integrity: sha512-XpiFTsl9qjiDfrmJF6CE3dgj1nmSbxUIT+p2HIbXV6WOj/32btO8FKkWSsOphUwVinEt3R8HVkVrcLtFNruMMQ==} resolution: {integrity: sha512-XpiFTsl9qjiDfrmJF6CE3dgj1nmSbxUIT+p2HIbXV6WOj/32btO8FKkWSsOphUwVinEt3R8HVkVrcLtFNruMMQ==}
engines: {node: ^20.19.0 || >=22.12.0} engines: {node: ^20.19.0 || >=22.12.0}
cpu: [x64] cpu: [x64]
os: [freebsd] os: [freebsd]
'@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.1':
resolution: {integrity: sha512-69YKwJJBOFprQa1GktPgbuBOfnn+EGxu8sBJ1TjPER+zhSpYeaU4N07uqmyBiksOLGXsMegymuecLobfz03h8Q==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [arm]
os: [linux]
'@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.2': '@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.2':
resolution: {integrity: sha512-zjYZ99e47Wlygs4hW+sQ+kshlO8ake9OoY2ecnJ9cwpDGiiIB9rQ3LgP3kt8j6IeVyMSksu//VEhc8Mrd1lRIw==} resolution: {integrity: sha512-zjYZ99e47Wlygs4hW+sQ+kshlO8ake9OoY2ecnJ9cwpDGiiIB9rQ3LgP3kt8j6IeVyMSksu//VEhc8Mrd1lRIw==}
engines: {node: ^20.19.0 || >=22.12.0} engines: {node: ^20.19.0 || >=22.12.0}
cpu: [arm] cpu: [arm]
os: [linux] os: [linux]
'@rolldown/binding-linux-arm64-gnu@1.0.0-rc.1':
resolution: {integrity: sha512-9JDhHUf3WcLfnViFWm+TyorqUtnSAHaCzlSNmMOq824prVuuzDOK91K0Hl8DUcEb9M5x2O+d2/jmBMsetRIn3g==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [arm64]
os: [linux]
'@rolldown/binding-linux-arm64-gnu@1.0.0-rc.2': '@rolldown/binding-linux-arm64-gnu@1.0.0-rc.2':
resolution: {integrity: sha512-Piso04EZ9IHV1aZSsLQVMOPTiCq4Ps2UPL3pchjNXHGJGFiB9U42s22LubPaEBFS+i6tCawS5EarIwex1zC4BA==} resolution: {integrity: sha512-Piso04EZ9IHV1aZSsLQVMOPTiCq4Ps2UPL3pchjNXHGJGFiB9U42s22LubPaEBFS+i6tCawS5EarIwex1zC4BA==}
engines: {node: ^20.19.0 || >=22.12.0} engines: {node: ^20.19.0 || >=22.12.0}
cpu: [arm64] cpu: [arm64]
os: [linux] os: [linux]
'@rolldown/binding-linux-arm64-musl@1.0.0-rc.1':
resolution: {integrity: sha512-UvApLEGholmxw/HIwmUnLq3CwdydbhaHHllvWiCTNbyGom7wTwOtz5OAQbAKZYyiEOeIXZNPkM7nA4Dtng7CLw==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [arm64]
os: [linux]
'@rolldown/binding-linux-arm64-musl@1.0.0-rc.2': '@rolldown/binding-linux-arm64-musl@1.0.0-rc.2':
resolution: {integrity: sha512-OwJCeMZlmjKsN9pfJfTmqYpe3JC+L6RO87+hu9ajRLr1Lh6cM2FRQ8e48DLRyRDww8Ti695XQvqEANEMmsuzLw==} resolution: {integrity: sha512-OwJCeMZlmjKsN9pfJfTmqYpe3JC+L6RO87+hu9ajRLr1Lh6cM2FRQ8e48DLRyRDww8Ti695XQvqEANEMmsuzLw==}
engines: {node: ^20.19.0 || >=22.12.0} engines: {node: ^20.19.0 || >=22.12.0}
cpu: [arm64] cpu: [arm64]
os: [linux] os: [linux]
'@rolldown/binding-linux-x64-gnu@1.0.0-rc.1':
resolution: {integrity: sha512-uVctNgZHiGnJx5Fij7wHLhgw4uyZBVi6mykeWKOqE7bVy9Hcxn0fM/IuqdMwk6hXlaf9fFShDTFz2+YejP+x0A==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [x64]
os: [linux]
'@rolldown/binding-linux-x64-gnu@1.0.0-rc.2': '@rolldown/binding-linux-x64-gnu@1.0.0-rc.2':
resolution: {integrity: sha512-uQqBmA8dTWbKvfqbeSsXNUssRGfdgQCc0hkGfhQN7Pf85wG2h0Fd/z2d+ykyT4YbcsjQdgEGxBNsg3v4ekOuEA==} resolution: {integrity: sha512-uQqBmA8dTWbKvfqbeSsXNUssRGfdgQCc0hkGfhQN7Pf85wG2h0Fd/z2d+ykyT4YbcsjQdgEGxBNsg3v4ekOuEA==}
engines: {node: ^20.19.0 || >=22.12.0} engines: {node: ^20.19.0 || >=22.12.0}
cpu: [x64] cpu: [x64]
os: [linux] os: [linux]
'@rolldown/binding-linux-x64-musl@1.0.0-rc.1':
resolution: {integrity: sha512-T6Eg0xWwcxd/MzBcuv4Z37YVbUbJxy5cMNnbIt/Yr99wFwli30O4BPlY8hKeGyn6lWNtU0QioBS46lVzDN38bg==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [x64]
os: [linux]
'@rolldown/binding-linux-x64-musl@1.0.0-rc.2': '@rolldown/binding-linux-x64-musl@1.0.0-rc.2':
resolution: {integrity: sha512-ItZabVsICCYWHbP+jcAgNzjPAYg5GIVQp/NpqT6iOgWctaMYtobClc5m0kNtxwqfNrLXoyt998xUey4AvcxnGQ==} resolution: {integrity: sha512-ItZabVsICCYWHbP+jcAgNzjPAYg5GIVQp/NpqT6iOgWctaMYtobClc5m0kNtxwqfNrLXoyt998xUey4AvcxnGQ==}
engines: {node: ^20.19.0 || >=22.12.0} engines: {node: ^20.19.0 || >=22.12.0}
cpu: [x64] cpu: [x64]
os: [linux] os: [linux]
'@rolldown/binding-openharmony-arm64@1.0.0-rc.1':
resolution: {integrity: sha512-PuGZVS2xNJyLADeh2F04b+Cz4NwvpglbtWACgrDOa5YDTEHKwmiTDjoD5eZ9/ptXtcpeFrMqD2H4Zn33KAh1Eg==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [arm64]
os: [openharmony]
'@rolldown/binding-openharmony-arm64@1.0.0-rc.2': '@rolldown/binding-openharmony-arm64@1.0.0-rc.2':
resolution: {integrity: sha512-U4UYANwafcMXSUC0VqdrqTAgCo2v8T7SiuTYwVFXgia0KOl8jiv3okwCFqeZNuw/G6EWDiqhT8kK1DLgyLsxow==} resolution: {integrity: sha512-U4UYANwafcMXSUC0VqdrqTAgCo2v8T7SiuTYwVFXgia0KOl8jiv3okwCFqeZNuw/G6EWDiqhT8kK1DLgyLsxow==}
engines: {node: ^20.19.0 || >=22.12.0} engines: {node: ^20.19.0 || >=22.12.0}
cpu: [arm64] cpu: [arm64]
os: [openharmony] os: [openharmony]
'@rolldown/binding-wasm32-wasi@1.0.0-rc.1':
resolution: {integrity: sha512-2mOxY562ihHlz9lEXuaGEIDCZ1vI+zyFdtsoa3M62xsEunDXQE+DVPO4S4x5MPK9tKulG/aFcA/IH5eVN257Cw==}
engines: {node: '>=14.0.0'}
cpu: [wasm32]
'@rolldown/binding-wasm32-wasi@1.0.0-rc.2': '@rolldown/binding-wasm32-wasi@1.0.0-rc.2':
resolution: {integrity: sha512-ZIWCjQsMon4tqRoao0Vzowjwx0cmFT3kublh2nNlgeasIJMWlIGHtr0d4fPypm57Rqx4o1h4L8SweoK2q6sMGA==} resolution: {integrity: sha512-ZIWCjQsMon4tqRoao0Vzowjwx0cmFT3kublh2nNlgeasIJMWlIGHtr0d4fPypm57Rqx4o1h4L8SweoK2q6sMGA==}
engines: {node: '>=14.0.0'} engines: {node: '>=14.0.0'}
cpu: [wasm32] cpu: [wasm32]
'@rolldown/binding-win32-arm64-msvc@1.0.0-rc.1':
resolution: {integrity: sha512-oQVOP5cfAWZwRD0Q3nGn/cA9FW3KhMMuQ0NIndALAe6obqjLhqYVYDiGGRGrxvnjJsVbpLwR14gIUYnpIcHR1g==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [arm64]
os: [win32]
'@rolldown/binding-win32-arm64-msvc@1.0.0-rc.2': '@rolldown/binding-win32-arm64-msvc@1.0.0-rc.2':
resolution: {integrity: sha512-NIo7vwRUPEzZ4MuZGr5YbDdjJ84xdiG+YYf8ZBfTgvIsk9wM0sZamJPEXvaLkzVIHpOw5uqEHXS85Gqqb7aaqQ==} resolution: {integrity: sha512-NIo7vwRUPEzZ4MuZGr5YbDdjJ84xdiG+YYf8ZBfTgvIsk9wM0sZamJPEXvaLkzVIHpOw5uqEHXS85Gqqb7aaqQ==}
engines: {node: ^20.19.0 || >=22.12.0} engines: {node: ^20.19.0 || >=22.12.0}
cpu: [arm64] cpu: [arm64]
os: [win32] os: [win32]
'@rolldown/binding-win32-x64-msvc@1.0.0-rc.1':
resolution: {integrity: sha512-Ydsxxx++FNOuov3wCBPaYjZrEvKOOGq3k+BF4BPridhg2pENfitSRD2TEuQ8i33bp5VptuNdC9IzxRKU031z5A==}
engines: {node: ^20.19.0 || >=22.12.0}
cpu: [x64]
os: [win32]
'@rolldown/binding-win32-x64-msvc@1.0.0-rc.2': '@rolldown/binding-win32-x64-msvc@1.0.0-rc.2':
resolution: {integrity: sha512-bLKzyLFbvngeNPZocuLo3LILrKwCrkyMxmRXs6fZYDrvh7cyZRw9v56maDL9ipPas0OOmQK1kAKYwvTs30G21Q==} resolution: {integrity: sha512-bLKzyLFbvngeNPZocuLo3LILrKwCrkyMxmRXs6fZYDrvh7cyZRw9v56maDL9ipPas0OOmQK1kAKYwvTs30G21Q==}
engines: {node: ^20.19.0 || >=22.12.0} engines: {node: ^20.19.0 || >=22.12.0}
cpu: [x64] cpu: [x64]
os: [win32] os: [win32]
'@rolldown/pluginutils@1.0.0-rc.1':
resolution: {integrity: sha512-UTBjtTxVOhodhzFVp/ayITaTETRHPUPYZPXQe0WU0wOgxghMojXxYjOiPOauKIYNWJAWS2fd7gJgGQK8GU8vDA==}
'@rolldown/pluginutils@1.0.0-rc.2': '@rolldown/pluginutils@1.0.0-rc.2':
resolution: {integrity: sha512-izyXV/v+cHiRfozX62W9htOAvwMo4/bXKDrQ+vom1L1qRuexPock/7VZDAhnpHCLNejd3NJ6hiab+tO0D44Rgw==} resolution: {integrity: sha512-izyXV/v+cHiRfozX62W9htOAvwMo4/bXKDrQ+vom1L1qRuexPock/7VZDAhnpHCLNejd3NJ6hiab+tO0D44Rgw==}
@@ -2649,9 +2536,6 @@ packages:
'@types/http-errors@2.0.5': '@types/http-errors@2.0.5':
resolution: {integrity: sha512-r8Tayk8HJnX0FztbZN7oVqGccWgw98T/0neJphO91KkmOzug1KkofZURD4UaD5uH8AqcFLfdPErnBod0u71/qg==} resolution: {integrity: sha512-r8Tayk8HJnX0FztbZN7oVqGccWgw98T/0neJphO91KkmOzug1KkofZURD4UaD5uH8AqcFLfdPErnBod0u71/qg==}
'@types/jsesc@2.5.1':
resolution: {integrity: sha512-9VN+6yxLOPLOav+7PwjZbxiID2bVaeq0ED4qSQmdQTdjnXJSaCVKTR58t15oqH1H5t8Ng2ZX1SabJVoN9Q34bw==}
'@types/jsonwebtoken@9.0.10': '@types/jsonwebtoken@9.0.10':
resolution: {integrity: sha512-asx5hIG9Qmf/1oStypjanR7iKTv0gXQ1Ov/jfrX6kS/EO0OFni8orbmGCn0672NHR3kXHwpAwR+B368ZGN/2rA==} resolution: {integrity: sha512-asx5hIG9Qmf/1oStypjanR7iKTv0gXQ1Ov/jfrX6kS/EO0OFni8orbmGCn0672NHR3kXHwpAwR+B368ZGN/2rA==}
@@ -2928,10 +2812,6 @@ packages:
resolution: {integrity: sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==} resolution: {integrity: sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==}
engines: {node: '>=12'} engines: {node: '>=12'}
ansis@4.2.0:
resolution: {integrity: sha512-HqZ5rWlFjGiV0tDm3UxxgNRqsOTniqoKZu0pIAfh7TZQMGuZK+hH0drySty0si0QXj1ieop4+SkSfPZBPPkHig==}
engines: {node: '>=14'}
any-promise@1.3.0: any-promise@1.3.0:
resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==} resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==}
@@ -2972,10 +2852,6 @@ packages:
resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==}
engines: {node: '>=12'} engines: {node: '>=12'}
ast-kit@3.0.0-beta.1:
resolution: {integrity: sha512-trmleAnZ2PxN/loHWVhhx1qeOHSRXq4TDsBBxq3GqeJitfk3+jTQ+v/C1km/KYq9M7wKqCewMh+/NAvVH7m+bw==}
engines: {node: '>=20.19.0'}
ast-types@0.13.4: ast-types@0.13.4:
resolution: {integrity: sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w==} resolution: {integrity: sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w==}
engines: {node: '>=4'} engines: {node: '>=4'}
@@ -3041,9 +2917,6 @@ packages:
bignumber.js@9.3.1: bignumber.js@9.3.1:
resolution: {integrity: sha512-Ko0uX15oIUS7wJ3Rb30Fs6SkVbLmPBAKdlm7q9+ak9bbIeFf0MwuBsQV6z7+X768/cHsfg+WlysDWJcmthjsjQ==} resolution: {integrity: sha512-Ko0uX15oIUS7wJ3Rb30Fs6SkVbLmPBAKdlm7q9+ak9bbIeFf0MwuBsQV6z7+X768/cHsfg+WlysDWJcmthjsjQ==}
birpc@4.0.0:
resolution: {integrity: sha512-LShSxJP0KTmd101b6DRyGBj57LZxSDYWKitQNW/mi8GRMvZb078Uf9+pveax1DrVL89vm7mWe+TovdI/UDOuPw==}
bluebird@3.7.2: bluebird@3.7.2:
resolution: {integrity: sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==} resolution: {integrity: sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==}
@@ -3083,10 +2956,6 @@ packages:
resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==}
engines: {node: '>= 0.8'} engines: {node: '>= 0.8'}
cac@6.7.14:
resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==}
engines: {node: '>=8'}
cacheable@2.3.2: cacheable@2.3.2:
resolution: {integrity: sha512-w+ZuRNmex9c1TR9RcsxbfTKCjSL0rh1WA5SABbrWprIHeNBdmyQLSYonlDy9gpD+63XT8DgZ/wNh1Smvc9WnJA==} resolution: {integrity: sha512-w+ZuRNmex9c1TR9RcsxbfTKCjSL0rh1WA5SABbrWprIHeNBdmyQLSYonlDy9gpD+63XT8DgZ/wNh1Smvc9WnJA==}
@@ -3287,9 +3156,6 @@ packages:
resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==} resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==}
engines: {node: '>=0.10.0'} engines: {node: '>=0.10.0'}
defu@6.1.4:
resolution: {integrity: sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==}
degenerator@5.0.1: degenerator@5.0.1:
resolution: {integrity: sha512-TllpMR/t0M5sqCXfj85i4XaAzxmS5tVA16dqvdkMwGmzI+dXLXnw3J+3Vdv7VKw+ThlTMboK6i9rnZ6Nntj5CQ==} resolution: {integrity: sha512-TllpMR/t0M5sqCXfj85i4XaAzxmS5tVA16dqvdkMwGmzI+dXLXnw3J+3Vdv7VKw+ThlTMboK6i9rnZ6Nntj5CQ==}
engines: {node: '>= 14'} engines: {node: '>= 14'}
@@ -3343,15 +3209,6 @@ packages:
resolution: {integrity: sha512-JVUnt+DUIzu87TABbhPmNfVdBDt18BLOWjMUFJMSi/Qqg7NTYtabbvSNJGOJ7afbRuv9D/lngizHtP7QyLQ+9w==} resolution: {integrity: sha512-JVUnt+DUIzu87TABbhPmNfVdBDt18BLOWjMUFJMSi/Qqg7NTYtabbvSNJGOJ7afbRuv9D/lngizHtP7QyLQ+9w==}
engines: {node: '>=12'} engines: {node: '>=12'}
dts-resolver@2.1.3:
resolution: {integrity: sha512-bihc7jPC90VrosXNzK0LTE2cuLP6jr0Ro8jk+kMugHReJVLIpHz/xadeq3MhuwyO4TD4OA3L1Q8pBBFRc08Tsw==}
engines: {node: '>=20.19.0'}
peerDependencies:
oxc-resolver: '>=11.0.0'
peerDependenciesMeta:
oxc-resolver:
optional: true
dunder-proto@1.0.1: dunder-proto@1.0.1:
resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==}
engines: {node: '>= 0.4'} engines: {node: '>= 0.4'}
@@ -3377,10 +3234,6 @@ packages:
emoji-regex@9.2.2: emoji-regex@9.2.2:
resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==}
empathic@2.0.0:
resolution: {integrity: sha512-i6UzDscO/XfAcNYD75CfICkmfLedpyPDdozrLMmQc5ORaQcdMoc21OnlEylMIqI7U8eniKrPMxxtj8k0vhmJhA==}
engines: {node: '>=14'}
encodeurl@2.0.0: encodeurl@2.0.0:
resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==} resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==}
engines: {node: '>= 0.8'} engines: {node: '>= 0.8'}
@@ -3719,9 +3572,6 @@ packages:
resolution: {integrity: sha512-U7tt8JsyrxSRKspfhtLET79pU8K+tInj5QZXs1jSugO1Vq5dFj3kmZsRldo29mTBfcjDRVRXrEZ6LS63Cog9ZA==} resolution: {integrity: sha512-U7tt8JsyrxSRKspfhtLET79pU8K+tInj5QZXs1jSugO1Vq5dFj3kmZsRldo29mTBfcjDRVRXrEZ6LS63Cog9ZA==}
engines: {node: '>=16.9.0'} engines: {node: '>=16.9.0'}
hookable@6.0.1:
resolution: {integrity: sha512-uKGyY8BuzN/a5gvzvA+3FVWo0+wUjgtfSdnmjtrOVwQCZPHpHDH2WRO3VZSOeluYrHoDCiXFffZXs8Dj1ULWtw==}
hookified@1.15.0: hookified@1.15.0:
resolution: {integrity: sha512-51w+ZZGt7Zw5q7rM3nC4t3aLn/xvKDETsXqMczndvwyVQhAHfUmUuFBRFcos8Iyebtk7OAE9dL26wFNzZVVOkw==} resolution: {integrity: sha512-51w+ZZGt7Zw5q7rM3nC4t3aLn/xvKDETsXqMczndvwyVQhAHfUmUuFBRFcos8Iyebtk7OAE9dL26wFNzZVVOkw==}
@@ -3781,10 +3631,6 @@ packages:
import-in-the-middle@2.0.6: import-in-the-middle@2.0.6:
resolution: {integrity: sha512-3vZV3jX0XRFW3EJDTwzWoZa+RH1b8eTTx6YOCjglrLyPuepwoBti1k3L2dKwdCUrnVEfc5CuRuGstaC/uQJJaw==} resolution: {integrity: sha512-3vZV3jX0XRFW3EJDTwzWoZa+RH1b8eTTx6YOCjglrLyPuepwoBti1k3L2dKwdCUrnVEfc5CuRuGstaC/uQJJaw==}
import-without-cache@0.2.5:
resolution: {integrity: sha512-B6Lc2s6yApwnD2/pMzFh/d5AVjdsDXjgkeJ766FmFuJELIGHNycKRj+l3A39yZPM4CchqNCB4RITEAYB1KUM6A==}
engines: {node: '>=20.19.0'}
inherits@2.0.4: inherits@2.0.4:
resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==}
@@ -3892,11 +3738,6 @@ packages:
jsbn@0.1.1: jsbn@0.1.1:
resolution: {integrity: sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==} resolution: {integrity: sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==}
jsesc@3.1.0:
resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==}
engines: {node: '>=6'}
hasBin: true
json-bigint@1.0.0: json-bigint@1.0.0:
resolution: {integrity: sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==} resolution: {integrity: sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==}
@@ -4698,9 +4539,6 @@ packages:
resolution: {integrity: sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==} resolution: {integrity: sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==}
engines: {node: '>=0.6'} engines: {node: '>=0.6'}
quansync@1.0.0:
resolution: {integrity: sha512-5xZacEEufv3HSTPQuchrvV6soaiACMFnq1H8wkVioctoH3TRha9Sz66lOxRwPK/qZj7HPiSveih9yAyh98gvqA==}
quick-format-unescaped@4.0.4: quick-format-unescaped@4.0.4:
resolution: {integrity: sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==} resolution: {integrity: sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==}
@@ -4787,30 +4625,6 @@ packages:
resolution: {integrity: sha512-l0OE8wL34P4nJH/H2ffoaniAokM2qSmrtXHmlpvYr5AVVX8msAyW0l8NVJFDxlSK4u3Uh/f41cQheDVdnYijwQ==} resolution: {integrity: sha512-l0OE8wL34P4nJH/H2ffoaniAokM2qSmrtXHmlpvYr5AVVX8msAyW0l8NVJFDxlSK4u3Uh/f41cQheDVdnYijwQ==}
hasBin: true hasBin: true
rolldown-plugin-dts@0.21.8:
resolution: {integrity: sha512-czOQoe6eZpRKCv9P+ijO/v4A2TwQjASAV7qezUxRZSua06Yb2REPIZv/mbfXiZDP1ZfI7Ez7re7qfK9F9u0Epw==}
engines: {node: '>=20.19.0'}
peerDependencies:
'@ts-macro/tsc': ^0.3.6
'@typescript/native-preview': '>=7.0.0-dev.20250601.1'
rolldown: ^1.0.0-beta.57
typescript: ^5.0.0
vue-tsc: ~3.2.0
peerDependenciesMeta:
'@ts-macro/tsc':
optional: true
'@typescript/native-preview':
optional: true
typescript:
optional: true
vue-tsc:
optional: true
rolldown@1.0.0-rc.1:
resolution: {integrity: sha512-M3AeZjYE6UclblEf531Hch0WfVC/NOL43Cc+WdF3J50kk5/fvouHhDumSGTh0oRjbZ8C4faaVr5r6Nx1xMqDGg==}
engines: {node: ^20.19.0 || >=22.12.0}
hasBin: true
rolldown@1.0.0-rc.2: rolldown@1.0.0-rc.2:
resolution: {integrity: sha512-1g/8Us9J8sgJGn3hZfBecX1z4U3y5KO7V/aV2U1M/9UUzLNqHA8RfFQ/NPT7HLxOIldyIgrcjaYTRvA81KhJIg==} resolution: {integrity: sha512-1g/8Us9J8sgJGn3hZfBecX1z4U3y5KO7V/aV2U1M/9UUzLNqHA8RfFQ/NPT7HLxOIldyIgrcjaYTRvA81KhJIg==}
engines: {node: ^20.19.0 || >=22.12.0} engines: {node: ^20.19.0 || >=22.12.0}
@@ -5134,38 +4948,9 @@ packages:
tr46@0.0.3: tr46@0.0.3:
resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==}
tree-kill@1.2.2:
resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==}
hasBin: true
ts-algebra@2.0.0: ts-algebra@2.0.0:
resolution: {integrity: sha512-FPAhNPFMrkwz76P7cdjdmiShwMynZYN6SgOujD1urY4oNm80Ou9oMdmbR45LotcKOXoy7wSmHkRFE6Mxbrhefw==} resolution: {integrity: sha512-FPAhNPFMrkwz76P7cdjdmiShwMynZYN6SgOujD1urY4oNm80Ou9oMdmbR45LotcKOXoy7wSmHkRFE6Mxbrhefw==}
tsdown@0.20.1:
resolution: {integrity: sha512-Wo1BzqNQVZ6SFQV8rjQBwMmNubO+yV3F+vp2WNTjEaS4S5CT1C1dHtUbeFMrCEasZpGy5w6TshpehNnfTe8QBQ==}
engines: {node: '>=20.19.0'}
hasBin: true
peerDependencies:
'@arethetypeswrong/core': ^0.18.1
'@vitejs/devtools': '*'
publint: ^0.3.0
typescript: ^5.0.0
unplugin-lightningcss: ^0.4.0
unplugin-unused: ^0.5.0
peerDependenciesMeta:
'@arethetypeswrong/core':
optional: true
'@vitejs/devtools':
optional: true
publint:
optional: true
typescript:
optional: true
unplugin-lightningcss:
optional: true
unplugin-unused:
optional: true
tslib@2.8.1: tslib@2.8.1:
resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==}
@@ -5219,9 +5004,6 @@ packages:
resolution: {integrity: sha512-rvKSBiC5zqCCiDZ9kAOszZcDvdAHwwIKJG33Ykj43OKcWsnmcBRL09YTU4nOeHZ8Y2a7l1MgTd08SBe9A8Qj6A==} resolution: {integrity: sha512-rvKSBiC5zqCCiDZ9kAOszZcDvdAHwwIKJG33Ykj43OKcWsnmcBRL09YTU4nOeHZ8Y2a7l1MgTd08SBe9A8Qj6A==}
engines: {node: '>=18'} engines: {node: '>=18'}
unconfig-core@7.4.2:
resolution: {integrity: sha512-VgPCvLWugINbXvMQDf8Jh0mlbvNjNC6eSUziHsBCMpxR05OPrNrvDnyatdMjRgcHaaNsCqz+wjNXxNw1kRLHUg==}
undici-types@6.21.0: undici-types@6.21.0:
resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==}
@@ -5246,16 +5028,6 @@ packages:
resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==}
engines: {node: '>= 0.8'} engines: {node: '>= 0.8'}
unrun@0.2.26:
resolution: {integrity: sha512-A3DQLBcDyTui4Hlaoojkldg+8x+CIR+tcSHY0wzW+CgB4X/DNyH58jJpXp1B/EkE+yG6tU8iH1mWsLtwFU3IQg==}
engines: {node: '>=20.19.0'}
hasBin: true
peerDependencies:
synckit: ^0.11.11
peerDependenciesMeta:
synckit:
optional: true
uri-js@4.4.1: uri-js@4.4.1:
resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==}
@@ -5979,31 +5751,14 @@ snapshots:
jsonwebtoken: 9.0.3 jsonwebtoken: 9.0.3
uuid: 8.3.2 uuid: 8.3.2
'@babel/generator@8.0.0-beta.4':
dependencies:
'@babel/parser': 8.0.0-beta.4
'@babel/types': 8.0.0-beta.4
'@jridgewell/gen-mapping': 0.3.13
'@jridgewell/trace-mapping': 0.3.31
'@types/jsesc': 2.5.1
jsesc: 3.1.0
'@babel/helper-string-parser@7.27.1': {} '@babel/helper-string-parser@7.27.1': {}
'@babel/helper-string-parser@8.0.0-beta.4': {}
'@babel/helper-validator-identifier@7.28.5': {} '@babel/helper-validator-identifier@7.28.5': {}
'@babel/helper-validator-identifier@8.0.0-beta.4': {}
'@babel/parser@7.28.6': '@babel/parser@7.28.6':
dependencies: dependencies:
'@babel/types': 7.28.6 '@babel/types': 7.28.6
'@babel/parser@8.0.0-beta.4':
dependencies:
'@babel/types': 8.0.0-beta.4
'@babel/runtime@7.28.6': {} '@babel/runtime@7.28.6': {}
'@babel/types@7.28.6': '@babel/types@7.28.6':
@@ -6011,11 +5766,6 @@ snapshots:
'@babel/helper-string-parser': 7.27.1 '@babel/helper-string-parser': 7.27.1
'@babel/helper-validator-identifier': 7.28.5 '@babel/helper-validator-identifier': 7.28.5
'@babel/types@8.0.0-beta.4':
dependencies:
'@babel/helper-string-parser': 8.0.0-beta.4
'@babel/helper-validator-identifier': 8.0.0-beta.4
'@bcoe/v8-coverage@1.0.2': {} '@bcoe/v8-coverage@1.0.2': {}
'@borewit/text-codec@0.2.1': {} '@borewit/text-codec@0.2.1': {}
@@ -6403,11 +6153,6 @@ snapshots:
dependencies: dependencies:
minipass: 7.1.2 minipass: 7.1.2
'@jridgewell/gen-mapping@0.3.13':
dependencies:
'@jridgewell/sourcemap-codec': 1.5.5
'@jridgewell/trace-mapping': 0.3.31
'@jridgewell/resolve-uri@3.1.2': {} '@jridgewell/resolve-uri@3.1.2': {}
'@jridgewell/sourcemap-codec@1.5.5': {} '@jridgewell/sourcemap-codec@1.5.5': {}
@@ -6473,7 +6218,7 @@ snapshots:
dependencies: dependencies:
'@types/node': 24.10.9 '@types/node': 24.10.9
optionalDependencies: optionalDependencies:
axios: 1.13.4 axios: 1.13.4(debug@4.4.3)
transitivePeerDependencies: transitivePeerDependencies:
- debug - debug
@@ -6670,7 +6415,7 @@ snapshots:
'@azure/core-auth': 1.10.1 '@azure/core-auth': 1.10.1
'@azure/msal-node': 3.8.6 '@azure/msal-node': 3.8.6
'@microsoft/agents-activity': 1.2.3 '@microsoft/agents-activity': 1.2.3
axios: 1.13.4 axios: 1.13.4(debug@4.4.3)
jsonwebtoken: 9.0.3 jsonwebtoken: 9.0.3
jwks-rsa: 3.2.2 jwks-rsa: 3.2.2
object-path: 0.11.8 object-path: 0.11.8
@@ -7171,8 +6916,6 @@ snapshots:
'@opentelemetry/semantic-conventions@1.39.0': {} '@opentelemetry/semantic-conventions@1.39.0': {}
'@oxc-project/types@0.110.0': {}
'@oxc-project/types@0.111.0': {} '@oxc-project/types@0.111.0': {}
'@oxfmt/darwin-arm64@0.27.0': '@oxfmt/darwin-arm64@0.27.0':
@@ -7271,10 +7014,6 @@ snapshots:
'@protobufjs/utf8@1.1.0': {} '@protobufjs/utf8@1.1.0': {}
'@quansync/fs@1.0.0':
dependencies:
quansync: 1.0.0
'@reflink/reflink-darwin-arm64@0.1.19': '@reflink/reflink-darwin-arm64@0.1.19':
optional: true optional: true
@@ -7311,90 +7050,47 @@ snapshots:
'@reflink/reflink-win32-x64-msvc': 0.1.19 '@reflink/reflink-win32-x64-msvc': 0.1.19
optional: true optional: true
'@rolldown/binding-android-arm64@1.0.0-rc.1':
optional: true
'@rolldown/binding-android-arm64@1.0.0-rc.2': '@rolldown/binding-android-arm64@1.0.0-rc.2':
optional: true optional: true
'@rolldown/binding-darwin-arm64@1.0.0-rc.1':
optional: true
'@rolldown/binding-darwin-arm64@1.0.0-rc.2': '@rolldown/binding-darwin-arm64@1.0.0-rc.2':
optional: true optional: true
'@rolldown/binding-darwin-x64@1.0.0-rc.1':
optional: true
'@rolldown/binding-darwin-x64@1.0.0-rc.2': '@rolldown/binding-darwin-x64@1.0.0-rc.2':
optional: true optional: true
'@rolldown/binding-freebsd-x64@1.0.0-rc.1':
optional: true
'@rolldown/binding-freebsd-x64@1.0.0-rc.2': '@rolldown/binding-freebsd-x64@1.0.0-rc.2':
optional: true optional: true
'@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.1':
optional: true
'@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.2': '@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.2':
optional: true optional: true
'@rolldown/binding-linux-arm64-gnu@1.0.0-rc.1':
optional: true
'@rolldown/binding-linux-arm64-gnu@1.0.0-rc.2': '@rolldown/binding-linux-arm64-gnu@1.0.0-rc.2':
optional: true optional: true
'@rolldown/binding-linux-arm64-musl@1.0.0-rc.1':
optional: true
'@rolldown/binding-linux-arm64-musl@1.0.0-rc.2': '@rolldown/binding-linux-arm64-musl@1.0.0-rc.2':
optional: true optional: true
'@rolldown/binding-linux-x64-gnu@1.0.0-rc.1':
optional: true
'@rolldown/binding-linux-x64-gnu@1.0.0-rc.2': '@rolldown/binding-linux-x64-gnu@1.0.0-rc.2':
optional: true optional: true
'@rolldown/binding-linux-x64-musl@1.0.0-rc.1':
optional: true
'@rolldown/binding-linux-x64-musl@1.0.0-rc.2': '@rolldown/binding-linux-x64-musl@1.0.0-rc.2':
optional: true optional: true
'@rolldown/binding-openharmony-arm64@1.0.0-rc.1':
optional: true
'@rolldown/binding-openharmony-arm64@1.0.0-rc.2': '@rolldown/binding-openharmony-arm64@1.0.0-rc.2':
optional: true optional: true
'@rolldown/binding-wasm32-wasi@1.0.0-rc.1':
dependencies:
'@napi-rs/wasm-runtime': 1.1.1
optional: true
'@rolldown/binding-wasm32-wasi@1.0.0-rc.2': '@rolldown/binding-wasm32-wasi@1.0.0-rc.2':
dependencies: dependencies:
'@napi-rs/wasm-runtime': 1.1.1 '@napi-rs/wasm-runtime': 1.1.1
optional: true optional: true
'@rolldown/binding-win32-arm64-msvc@1.0.0-rc.1':
optional: true
'@rolldown/binding-win32-arm64-msvc@1.0.0-rc.2': '@rolldown/binding-win32-arm64-msvc@1.0.0-rc.2':
optional: true optional: true
'@rolldown/binding-win32-x64-msvc@1.0.0-rc.1':
optional: true
'@rolldown/binding-win32-x64-msvc@1.0.0-rc.2': '@rolldown/binding-win32-x64-msvc@1.0.0-rc.2':
optional: true optional: true
'@rolldown/pluginutils@1.0.0-rc.1': {}
'@rolldown/pluginutils@1.0.0-rc.2': {} '@rolldown/pluginutils@1.0.0-rc.2': {}
'@rollup/rollup-android-arm-eabi@4.57.1': '@rollup/rollup-android-arm-eabi@4.57.1':
@@ -7502,7 +7198,7 @@ snapshots:
'@slack/types': 2.19.0 '@slack/types': 2.19.0
'@slack/web-api': 7.13.0 '@slack/web-api': 7.13.0
'@types/express': 5.0.6 '@types/express': 5.0.6
axios: 1.13.4 axios: 1.13.4(debug@4.4.3)
express: 5.2.1 express: 5.2.1
path-to-regexp: 8.3.0 path-to-regexp: 8.3.0
raw-body: 3.0.2 raw-body: 3.0.2
@@ -7548,7 +7244,7 @@ snapshots:
'@slack/types': 2.19.0 '@slack/types': 2.19.0
'@types/node': 25.1.0 '@types/node': 25.1.0
'@types/retry': 0.12.0 '@types/retry': 0.12.0
axios: 1.13.4 axios: 1.13.4(debug@4.4.3)
eventemitter3: 5.0.4 eventemitter3: 5.0.4
form-data: 4.0.5 form-data: 4.0.5
is-electron: 2.2.2 is-electron: 2.2.2
@@ -8006,8 +7702,6 @@ snapshots:
'@types/http-errors@2.0.5': {} '@types/http-errors@2.0.5': {}
'@types/jsesc@2.5.1': {}
'@types/jsonwebtoken@9.0.10': '@types/jsonwebtoken@9.0.10':
dependencies: dependencies:
'@types/ms': 2.1.0 '@types/ms': 2.1.0
@@ -8351,8 +8045,6 @@ snapshots:
ansi-styles@6.2.3: {} ansi-styles@6.2.3: {}
ansis@4.2.0: {}
any-promise@1.3.0: {} any-promise@1.3.0: {}
apache-arrow@18.1.0: apache-arrow@18.1.0:
@@ -8390,12 +8082,6 @@ snapshots:
assertion-error@2.0.1: {} assertion-error@2.0.1: {}
ast-kit@3.0.0-beta.1:
dependencies:
'@babel/parser': 8.0.0-beta.4
estree-walker: 3.0.3
pathe: 2.0.3
ast-types@0.13.4: ast-types@0.13.4:
dependencies: dependencies:
tslib: 2.8.1 tslib: 2.8.1
@@ -8442,14 +8128,6 @@ snapshots:
aws4@1.13.2: {} aws4@1.13.2: {}
axios@1.13.4:
dependencies:
follow-redirects: 1.15.11
form-data: 4.0.5
proxy-from-env: 1.1.0
transitivePeerDependencies:
- debug
axios@1.13.4(debug@4.4.3): axios@1.13.4(debug@4.4.3):
dependencies: dependencies:
follow-redirects: 1.15.11(debug@4.4.3) follow-redirects: 1.15.11(debug@4.4.3)
@@ -8476,8 +8154,6 @@ snapshots:
bignumber.js@9.3.1: {} bignumber.js@9.3.1: {}
birpc@4.0.0: {}
bluebird@3.7.2: {} bluebird@3.7.2: {}
body-parser@1.20.4: body-parser@1.20.4:
@@ -8534,8 +8210,6 @@ snapshots:
bytes@3.1.2: {} bytes@3.1.2: {}
cac@6.7.14: {}
cacheable@2.3.2: cacheable@2.3.2:
dependencies: dependencies:
'@cacheable/memory': 2.0.7 '@cacheable/memory': 2.0.7
@@ -8722,8 +8396,6 @@ snapshots:
deepmerge@4.3.1: {} deepmerge@4.3.1: {}
defu@6.1.4: {}
degenerator@5.0.1: degenerator@5.0.1:
dependencies: dependencies:
ast-types: 0.13.4 ast-types: 0.13.4
@@ -8770,8 +8442,6 @@ snapshots:
dotenv@17.2.3: {} dotenv@17.2.3: {}
dts-resolver@2.1.3: {}
dunder-proto@1.0.1: dunder-proto@1.0.1:
dependencies: dependencies:
call-bind-apply-helpers: 1.0.2 call-bind-apply-helpers: 1.0.2
@@ -8797,8 +8467,6 @@ snapshots:
emoji-regex@9.2.2: {} emoji-regex@9.2.2: {}
empathic@2.0.0: {}
encodeurl@2.0.0: {} encodeurl@2.0.0: {}
entities@4.5.0: {} entities@4.5.0: {}
@@ -9025,8 +8693,6 @@ snapshots:
flatbuffers@24.12.23: {} flatbuffers@24.12.23: {}
follow-redirects@1.15.11: {}
follow-redirects@1.15.11(debug@4.4.3): follow-redirects@1.15.11(debug@4.4.3):
optionalDependencies: optionalDependencies:
debug: 4.4.3 debug: 4.4.3
@@ -9241,8 +8907,6 @@ snapshots:
hono@4.11.4: hono@4.11.4:
optional: true optional: true
hookable@6.0.1: {}
hookified@1.15.0: {} hookified@1.15.0: {}
html-escaper@2.0.2: {} html-escaper@2.0.2: {}
@@ -9322,8 +8986,6 @@ snapshots:
cjs-module-lexer: 2.2.0 cjs-module-lexer: 2.2.0
module-details-from-path: 1.0.4 module-details-from-path: 1.0.4
import-without-cache@0.2.5: {}
inherits@2.0.4: {} inherits@2.0.4: {}
ini@1.3.8: {} ini@1.3.8: {}
@@ -9432,8 +9094,6 @@ snapshots:
jsbn@0.1.1: {} jsbn@0.1.1: {}
jsesc@3.1.0: {}
json-bigint@1.0.0: json-bigint@1.0.0:
dependencies: dependencies:
bignumber.js: 9.3.1 bignumber.js: 9.3.1
@@ -10283,8 +9943,6 @@ snapshots:
qs@6.5.3: {} qs@6.5.3: {}
quansync@1.0.0: {}
quick-format-unescaped@4.0.4: {} quick-format-unescaped@4.0.4: {}
range-parser@1.2.1: {} range-parser@1.2.1: {}
@@ -10394,42 +10052,6 @@ snapshots:
dependencies: dependencies:
glob: 10.5.0 glob: 10.5.0
rolldown-plugin-dts@0.21.8(@typescript/native-preview@7.0.0-dev.20260130.1)(rolldown@1.0.0-rc.1)(typescript@5.9.3):
dependencies:
'@babel/generator': 8.0.0-beta.4
'@babel/parser': 8.0.0-beta.4
'@babel/types': 8.0.0-beta.4
ast-kit: 3.0.0-beta.1
birpc: 4.0.0
dts-resolver: 2.1.3
get-tsconfig: 4.13.1
obug: 2.1.1
rolldown: 1.0.0-rc.1
optionalDependencies:
'@typescript/native-preview': 7.0.0-dev.20260130.1
typescript: 5.9.3
transitivePeerDependencies:
- oxc-resolver
rolldown@1.0.0-rc.1:
dependencies:
'@oxc-project/types': 0.110.0
'@rolldown/pluginutils': 1.0.0-rc.1
optionalDependencies:
'@rolldown/binding-android-arm64': 1.0.0-rc.1
'@rolldown/binding-darwin-arm64': 1.0.0-rc.1
'@rolldown/binding-darwin-x64': 1.0.0-rc.1
'@rolldown/binding-freebsd-x64': 1.0.0-rc.1
'@rolldown/binding-linux-arm-gnueabihf': 1.0.0-rc.1
'@rolldown/binding-linux-arm64-gnu': 1.0.0-rc.1
'@rolldown/binding-linux-arm64-musl': 1.0.0-rc.1
'@rolldown/binding-linux-x64-gnu': 1.0.0-rc.1
'@rolldown/binding-linux-x64-musl': 1.0.0-rc.1
'@rolldown/binding-openharmony-arm64': 1.0.0-rc.1
'@rolldown/binding-wasm32-wasi': 1.0.0-rc.1
'@rolldown/binding-win32-arm64-msvc': 1.0.0-rc.1
'@rolldown/binding-win32-x64-msvc': 1.0.0-rc.1
rolldown@1.0.0-rc.2: rolldown@1.0.0-rc.2:
dependencies: dependencies:
'@oxc-project/types': 0.111.0 '@oxc-project/types': 0.111.0
@@ -10865,37 +10487,8 @@ snapshots:
tr46@0.0.3: {} tr46@0.0.3: {}
tree-kill@1.2.2: {}
ts-algebra@2.0.0: {} ts-algebra@2.0.0: {}
tsdown@0.20.1(@typescript/native-preview@7.0.0-dev.20260130.1)(typescript@5.9.3):
dependencies:
ansis: 4.2.0
cac: 6.7.14
defu: 6.1.4
empathic: 2.0.0
hookable: 6.0.1
import-without-cache: 0.2.5
obug: 2.1.1
picomatch: 4.0.3
rolldown: 1.0.0-rc.1
rolldown-plugin-dts: 0.21.8(@typescript/native-preview@7.0.0-dev.20260130.1)(rolldown@1.0.0-rc.1)(typescript@5.9.3)
semver: 7.7.3
tinyexec: 1.0.2
tinyglobby: 0.2.15
tree-kill: 1.2.2
unconfig-core: 7.4.2
unrun: 0.2.26
optionalDependencies:
typescript: 5.9.3
transitivePeerDependencies:
- '@ts-macro/tsc'
- '@typescript/native-preview'
- oxc-resolver
- synckit
- vue-tsc
tslib@2.8.1: {} tslib@2.8.1: {}
tslog@4.10.2: {} tslog@4.10.2: {}
@@ -10938,11 +10531,6 @@ snapshots:
uint8array-extras@1.5.0: {} uint8array-extras@1.5.0: {}
unconfig-core@7.4.2:
dependencies:
'@quansync/fs': 1.0.0
quansync: 1.0.0
undici-types@6.21.0: {} undici-types@6.21.0: {}
undici-types@7.16.0: {} undici-types@7.16.0: {}
@@ -10957,10 +10545,6 @@ snapshots:
unpipe@1.0.0: {} unpipe@1.0.0: {}
unrun@0.2.26:
dependencies:
rolldown: 1.0.0-rc.1
uri-js@4.4.1: uri-js@4.4.1:
dependencies: dependencies:
punycode: 2.3.1 punycode: 2.3.1

View File

@@ -31,7 +31,7 @@ echo "Starting gateway container..."
-e "OPENCLAW_SKIP_CRON=1" \ -e "OPENCLAW_SKIP_CRON=1" \
-e "OPENCLAW_SKIP_CANVAS_HOST=1" \ -e "OPENCLAW_SKIP_CANVAS_HOST=1" \
"$IMAGE_NAME" \ "$IMAGE_NAME" \
bash -lc "node dist/index.mjs gateway --port $PORT --bind lan --allow-unconfigured > /tmp/gateway-net-e2e.log 2>&1" bash -lc "node dist/index.js gateway --port $PORT --bind lan --allow-unconfigured > /tmp/gateway-net-e2e.log 2>&1"
echo "Waiting for gateway to come up..." echo "Waiting for gateway to come up..."
for _ in $(seq 1 20); do for _ in $(seq 1 20); do

View File

@@ -83,7 +83,7 @@ TRASH
} }
start_gateway() { start_gateway() {
node dist/index.mjs gateway --port 18789 --bind loopback --allow-unconfigured > /tmp/gateway-e2e.log 2>&1 & node dist/index.js gateway --port 18789 --bind loopback --allow-unconfigured > /tmp/gateway-e2e.log 2>&1 &
GATEWAY_PID="$!" GATEWAY_PID="$!"
} }
@@ -185,7 +185,7 @@ TRASH
local validate_fn="${4:-}" local validate_fn="${4:-}"
# Default onboarding command wrapper. # Default onboarding command wrapper.
run_wizard_cmd "$case_name" "$home_dir" "node dist/index.mjs onboard $ONBOARD_FLAGS" "$send_fn" true "$validate_fn" run_wizard_cmd "$case_name" "$home_dir" "node dist/index.js onboard $ONBOARD_FLAGS" "$send_fn" true "$validate_fn"
} }
make_home() { make_home() {
@@ -268,7 +268,7 @@ TRASH
home_dir="$(make_home local-basic)" home_dir="$(make_home local-basic)"
export HOME="$home_dir" export HOME="$home_dir"
mkdir -p "$HOME" mkdir -p "$HOME"
node dist/index.mjs onboard \ node dist/index.js onboard \
--non-interactive \ --non-interactive \
--accept-risk \ --accept-risk \
--flow quickstart \ --flow quickstart \
@@ -345,7 +345,7 @@ NODE
export HOME="$home_dir" export HOME="$home_dir"
mkdir -p "$HOME" mkdir -p "$HOME"
# Smoke test non-interactive remote config write. # Smoke test non-interactive remote config write.
node dist/index.mjs onboard --non-interactive --accept-risk \ node dist/index.js onboard --non-interactive --accept-risk \
--mode remote \ --mode remote \
--remote-url ws://gateway.local:18789 \ --remote-url ws://gateway.local:18789 \
--remote-token remote-token \ --remote-token remote-token \
@@ -398,7 +398,7 @@ NODE
} }
JSON JSON
node dist/index.mjs onboard \ node dist/index.js onboard \
--non-interactive \ --non-interactive \
--accept-risk \ --accept-risk \
--flow quickstart \ --flow quickstart \
@@ -441,7 +441,7 @@ NODE
local home_dir local home_dir
home_dir="$(make_home channels)" home_dir="$(make_home channels)"
# Channels-only configure flow. # Channels-only configure flow.
run_wizard_cmd channels "$home_dir" "node dist/index.mjs configure --section channels" send_channels_flow run_wizard_cmd channels "$home_dir" "node dist/index.js configure --section channels" send_channels_flow
config_path="$HOME/.openclaw/openclaw.json" config_path="$HOME/.openclaw/openclaw.json"
assert_file "$config_path" assert_file "$config_path"
@@ -492,7 +492,7 @@ NODE
} }
JSON JSON
run_wizard_cmd skills "$home_dir" "node dist/index.mjs configure --section skills" send_skills_flow run_wizard_cmd skills "$home_dir" "node dist/index.js configure --section skills" send_skills_flow
config_path="$HOME/.openclaw/openclaw.json" config_path="$HOME/.openclaw/openclaw.json"
assert_file "$config_path" assert_file "$config_path"

View File

@@ -29,7 +29,7 @@ module.exports = {
}; };
JS JS
node dist/index.mjs plugins list --json > /tmp/plugins.json node dist/index.js plugins list --json > /tmp/plugins.json
node - <<'"'"'NODE'"'"' node - <<'"'"'NODE'"'"'
const fs = require("node:fs"); const fs = require("node:fs");
@@ -81,8 +81,8 @@ module.exports = {
JS JS
tar -czf /tmp/demo-plugin-tgz.tgz -C "$pack_dir" package tar -czf /tmp/demo-plugin-tgz.tgz -C "$pack_dir" package
node dist/index.mjs plugins install /tmp/demo-plugin-tgz.tgz node dist/index.js plugins install /tmp/demo-plugin-tgz.tgz
node dist/index.mjs plugins list --json > /tmp/plugins2.json node dist/index.js plugins list --json > /tmp/plugins2.json
node - <<'"'"'NODE'"'"' node - <<'"'"'NODE'"'"'
const fs = require("node:fs"); const fs = require("node:fs");
@@ -118,8 +118,8 @@ module.exports = {
}; };
JS JS
node dist/index.mjs plugins install "$dir_plugin" node dist/index.js plugins install "$dir_plugin"
node dist/index.mjs plugins list --json > /tmp/plugins3.json node dist/index.js plugins list --json > /tmp/plugins3.json
node - <<'"'"'NODE'"'"' node - <<'"'"'NODE'"'"'
const fs = require("node:fs"); const fs = require("node:fs");
@@ -156,8 +156,8 @@ module.exports = {
}; };
JS JS
node dist/index.mjs plugins install "file:$file_pack_dir/package" node dist/index.js plugins install "file:$file_pack_dir/package"
node dist/index.mjs plugins list --json > /tmp/plugins4.json node dist/index.js plugins list --json > /tmp/plugins4.json
node - <<'"'"'NODE'"'"' node - <<'"'"'NODE'"'"'
const fs = require("node:fs"); const fs = require("node:fs");

View File

@@ -110,8 +110,8 @@ merge_framework_machos() {
echo "📦 Ensuring deps (pnpm install)" echo "📦 Ensuring deps (pnpm install)"
(cd "$ROOT_DIR" && pnpm install --no-frozen-lockfile --config.node-linker=hoisted) (cd "$ROOT_DIR" && pnpm install --no-frozen-lockfile --config.node-linker=hoisted)
if [[ "${SKIP_TSC:-0}" != "1" ]]; then if [[ "${SKIP_TSC:-0}" != "1" ]]; then
echo "📦 Building JS (pnpm tsdown)" echo "📦 Building JS (pnpm tsc)"
(cd "$ROOT_DIR" && pnpm tsdown) (cd "$ROOT_DIR" && pnpm tsc -p tsconfig.json --noEmit false)
else else
echo "📦 Skipping TS build (SKIP_TSC=1)" echo "📦 Skipping TS build (SKIP_TSC=1)"
fi fi

View File

@@ -1,34 +1,36 @@
import fs from "node:fs"; import fs from 'node:fs';
import path from "node:path"; import path from 'node:path';
import { spawnSync } from "node:child_process"; import { spawnSync } from 'node:child_process';
import { fileURLToPath } from "node:url"; import { fileURLToPath } from 'node:url';
import { setupGitHooks } from "./setup-git-hooks.js"; import { setupGitHooks } from './setup-git-hooks.js';
function detectPackageManager(ua = process.env.npm_config_user_agent ?? "") { function detectPackageManager(ua = process.env.npm_config_user_agent ?? '') {
// Examples: // Examples:
// - "pnpm/10.23.0 npm/? node/v22.21.1 darwin arm64" // - "pnpm/10.23.0 npm/? node/v22.21.1 darwin arm64"
// - "npm/10.9.4 node/v22.12.0 linux x64" // - "npm/10.9.4 node/v22.12.0 linux x64"
// - "bun/1.2.2" // - "bun/1.2.2"
const normalized = String(ua).trim(); const normalized = String(ua).trim();
if (normalized.startsWith("pnpm/")) return "pnpm"; if (normalized.startsWith('pnpm/')) return 'pnpm';
if (normalized.startsWith("bun/")) return "bun"; if (normalized.startsWith('bun/')) return 'bun';
if (normalized.startsWith("npm/")) return "npm"; if (normalized.startsWith('npm/')) return 'npm';
if (normalized.startsWith("yarn/")) return "yarn"; if (normalized.startsWith('yarn/')) return 'yarn';
return "unknown"; return 'unknown';
} }
function shouldApplyPnpmPatchedDependenciesFallback(pm = detectPackageManager()) { function shouldApplyPnpmPatchedDependenciesFallback(
pm = detectPackageManager(),
) {
// pnpm already applies pnpm.patchedDependencies itself; re-applying would fail. // pnpm already applies pnpm.patchedDependencies itself; re-applying would fail.
return pm !== "pnpm"; return pm !== 'pnpm';
} }
function getRepoRoot() { function getRepoRoot() {
const here = path.dirname(fileURLToPath(import.meta.url)); const here = path.dirname(fileURLToPath(import.meta.url));
return path.resolve(here, ".."); return path.resolve(here, '..');
} }
function ensureExecutable(targetPath) { function ensureExecutable(targetPath) {
if (process.platform === "win32") return; if (process.platform === 'win32') return;
if (!fs.existsSync(targetPath)) return; if (!fs.existsSync(targetPath)) return;
try { try {
const mode = fs.statSync(targetPath).mode & 0o777; const mode = fs.statSync(targetPath).mode & 0o777;
@@ -40,29 +42,32 @@ function ensureExecutable(targetPath) {
} }
function hasGit(repoRoot) { function hasGit(repoRoot) {
const result = spawnSync("git", ["--version"], { cwd: repoRoot, stdio: "ignore" }); const result = spawnSync('git', ['--version'], {
cwd: repoRoot,
stdio: 'ignore',
});
return result.status === 0; return result.status === 0;
} }
function extractPackageName(key) { function extractPackageName(key) {
if (key.startsWith("@")) { if (key.startsWith('@')) {
const idx = key.indexOf("@", 1); const idx = key.indexOf('@', 1);
if (idx === -1) return key; if (idx === -1) return key;
return key.slice(0, idx); return key.slice(0, idx);
} }
const idx = key.lastIndexOf("@"); const idx = key.lastIndexOf('@');
if (idx <= 0) return key; if (idx <= 0) return key;
return key.slice(0, idx); return key.slice(0, idx);
} }
function stripPrefix(p) { function stripPrefix(p) {
if (p.startsWith("a/") || p.startsWith("b/")) return p.slice(2); if (p.startsWith('a/') || p.startsWith('b/')) return p.slice(2);
return p; return p;
} }
function parseRange(segment) { function parseRange(segment) {
// segment: "-12,5" or "+7" // segment: "-12,5" or "+7"
const [startRaw, countRaw] = segment.slice(1).split(","); const [startRaw, countRaw] = segment.slice(1).split(',');
const start = Number.parseInt(startRaw, 10); const start = Number.parseInt(startRaw, 10);
const count = countRaw ? Number.parseInt(countRaw, 10) : 1; const count = countRaw ? Number.parseInt(countRaw, 10) : 1;
if (Number.isNaN(start) || Number.isNaN(count)) { if (Number.isNaN(start) || Number.isNaN(count)) {
@@ -72,12 +77,12 @@ function parseRange(segment) {
} }
function parsePatch(patchText) { function parsePatch(patchText) {
const lines = patchText.split("\n"); const lines = patchText.split('\n');
const files = []; const files = [];
let i = 0; let i = 0;
while (i < lines.length) { while (i < lines.length) {
if (!lines[i].startsWith("diff --git ")) { if (!lines[i].startsWith('diff --git ')) {
i += 1; i += 1;
continue; continue;
} }
@@ -86,20 +91,22 @@ function parsePatch(patchText) {
i += 1; i += 1;
// Skip index line(s) // Skip index line(s)
while (i < lines.length && lines[i].startsWith("index ")) i += 1; while (i < lines.length && lines[i].startsWith('index ')) i += 1;
if (i < lines.length && lines[i].startsWith("--- ")) { if (i < lines.length && lines[i].startsWith('--- ')) {
file.oldPath = stripPrefix(lines[i].slice(4).trim()); file.oldPath = stripPrefix(lines[i].slice(4).trim());
i += 1; i += 1;
} }
if (i < lines.length && lines[i].startsWith("+++ ")) { if (i < lines.length && lines[i].startsWith('+++ ')) {
file.newPath = stripPrefix(lines[i].slice(4).trim()); file.newPath = stripPrefix(lines[i].slice(4).trim());
i += 1; i += 1;
} }
while (i < lines.length && lines[i].startsWith("@@")) { while (i < lines.length && lines[i].startsWith('@@')) {
const header = lines[i]; const header = lines[i];
const match = /^@@\s+(-\d+(?:,\d+)?)\s+(\+\d+(?:,\d+)?)\s+@@/.exec(header); const match = /^@@\s+(-\d+(?:,\d+)?)\s+(\+\d+(?:,\d+)?)\s+@@/.exec(
header,
);
if (!match) throw new Error(`invalid hunk header: ${header}`); if (!match) throw new Error(`invalid hunk header: ${header}`);
const oldRange = parseRange(match[1]); const oldRange = parseRange(match[1]);
const newRange = parseRange(match[2]); const newRange = parseRange(match[2]);
@@ -108,12 +115,12 @@ function parsePatch(patchText) {
const hunkLines = []; const hunkLines = [];
while (i < lines.length) { while (i < lines.length) {
const line = lines[i]; const line = lines[i];
if (line.startsWith("@@") || line.startsWith("diff --git ")) break; if (line.startsWith('@@') || line.startsWith('diff --git ')) break;
if (line === "") { if (line === '') {
i += 1; i += 1;
continue; continue;
} }
if (line.startsWith("\\ No newline at end of file")) { if (line.startsWith('\\ No newline at end of file')) {
i += 1; i += 1;
continue; continue;
} }
@@ -142,16 +149,16 @@ function readFileLines(targetPath) {
if (!fs.existsSync(targetPath)) { if (!fs.existsSync(targetPath)) {
throw new Error(`target file missing: ${targetPath}`); throw new Error(`target file missing: ${targetPath}`);
} }
const raw = fs.readFileSync(targetPath, "utf-8"); const raw = fs.readFileSync(targetPath, 'utf-8');
const hasTrailingNewline = raw.endsWith("\n"); const hasTrailingNewline = raw.endsWith('\n');
const parts = raw.split("\n"); const parts = raw.split('\n');
if (hasTrailingNewline) parts.pop(); if (hasTrailingNewline) parts.pop();
return { lines: parts, hasTrailingNewline }; return { lines: parts, hasTrailingNewline };
} }
function writeFileLines(targetPath, lines, hadTrailingNewline) { function writeFileLines(targetPath, lines, hadTrailingNewline) {
const content = lines.join("\n") + (hadTrailingNewline ? "\n" : ""); const content = lines.join('\n') + (hadTrailingNewline ? '\n' : '');
fs.writeFileSync(targetPath, content, "utf-8"); fs.writeFileSync(targetPath, content, 'utf-8');
} }
function applyHunk(lines, hunk, offset) { function applyHunk(lines, hunk, offset) {
@@ -159,7 +166,7 @@ function applyHunk(lines, hunk, offset) {
const expected = []; const expected = [];
for (const raw of hunk.lines) { for (const raw of hunk.lines) {
const marker = raw[0]; const marker = raw[0];
if (marker === " " || marker === "+") { if (marker === ' ' || marker === '+') {
expected.push(raw.slice(1)); expected.push(raw.slice(1));
} }
} }
@@ -180,21 +187,21 @@ function applyHunk(lines, hunk, offset) {
for (const raw of hunk.lines) { for (const raw of hunk.lines) {
const marker = raw[0]; const marker = raw[0];
const text = raw.slice(1); const text = raw.slice(1);
if (marker === " ") { if (marker === ' ') {
if (lines[cursor] !== text) { if (lines[cursor] !== text) {
throw new Error( throw new Error(
`context mismatch at line ${cursor + 1}: expected "${text}", found "${lines[cursor] ?? "<eof>"}"`, `context mismatch at line ${cursor + 1}: expected "${text}", found "${lines[cursor] ?? '<eof>'}"`,
); );
} }
cursor += 1; cursor += 1;
} else if (marker === "-") { } else if (marker === '-') {
if (lines[cursor] !== text) { if (lines[cursor] !== text) {
throw new Error( throw new Error(
`delete mismatch at line ${cursor + 1}: expected "${text}", found "${lines[cursor] ?? "<eof>"}"`, `delete mismatch at line ${cursor + 1}: expected "${text}", found "${lines[cursor] ?? '<eof>'}"`,
); );
} }
lines.splice(cursor, 1); lines.splice(cursor, 1);
} else if (marker === "+") { } else if (marker === '+') {
lines.splice(cursor, 0, text); lines.splice(cursor, 0, text);
cursor += 1; cursor += 1;
} else { } else {
@@ -207,11 +214,11 @@ function applyHunk(lines, hunk, offset) {
} }
function applyPatchToFile(targetDir, filePatch) { function applyPatchToFile(targetDir, filePatch) {
if (filePatch.newPath === "/dev/null") { if (filePatch.newPath === '/dev/null') {
// deletion not needed for our patches // deletion not needed for our patches
return; return;
} }
const relPath = stripPrefix(filePatch.newPath ?? filePatch.oldPath ?? ""); const relPath = stripPrefix(filePatch.newPath ?? filePatch.oldPath ?? '');
const targetPath = path.join(targetDir, relPath); const targetPath = path.join(targetDir, relPath);
const { lines, hasTrailingNewline } = readFileLines(targetPath); const { lines, hasTrailingNewline } = readFileLines(targetPath);
@@ -225,7 +232,10 @@ function applyPatchToFile(targetDir, filePatch) {
function applyPatchSet({ patchText, targetDir }) { function applyPatchSet({ patchText, targetDir }) {
let resolvedTarget = path.resolve(targetDir); let resolvedTarget = path.resolve(targetDir);
if (!fs.existsSync(resolvedTarget) || !fs.statSync(resolvedTarget).isDirectory()) { if (
!fs.existsSync(resolvedTarget) ||
!fs.statSync(resolvedTarget).isDirectory()
) {
console.warn(`[postinstall] skip missing target: ${resolvedTarget}`); console.warn(`[postinstall] skip missing target: ${resolvedTarget}`);
return; return;
} }
@@ -244,28 +254,28 @@ function applyPatchFile({ patchPath, targetDir }) {
if (!fs.existsSync(absPatchPath)) { if (!fs.existsSync(absPatchPath)) {
throw new Error(`missing patch: ${absPatchPath}`); throw new Error(`missing patch: ${absPatchPath}`);
} }
const patchText = fs.readFileSync(absPatchPath, "utf-8"); const patchText = fs.readFileSync(absPatchPath, 'utf-8');
applyPatchSet({ patchText, targetDir }); applyPatchSet({ patchText, targetDir });
} }
function trySetupCompletion(repoRoot) { function trySetupCompletion(repoRoot) {
// Skip in CI or if explicitly disabled // Skip in CI or if explicitly disabled
if (process.env.CI || process.env.OPENCLAW_SKIP_COMPLETION_SETUP) return; if (process.env.CI || process.env.OPENCLAW_SKIP_COMPLETION_SETUP) return;
const binPath = path.join(repoRoot, "openclaw.mjs"); const binPath = path.join(repoRoot, 'openclaw.mjs');
if (!fs.existsSync(binPath)) return; if (!fs.existsSync(binPath)) return;
// In development, dist might not exist yet during postinstall // In development, dist might not exist yet during postinstall
const distEntry = path.join(repoRoot, "dist", "index.js"); const distEntry = path.join(repoRoot, 'dist', 'index.js');
if (!fs.existsSync(distEntry)) return; if (!fs.existsSync(distEntry)) return;
try { try {
// Run with OPENCLAW_SKIP_POSTINSTALL to avoid any weird recursion, // Run with OPENCLAW_SKIP_POSTINSTALL to avoid any weird recursion,
// though distinct from this script. // though distinct from this script.
spawnSync(process.execPath, [binPath, "completion", "--install", "--yes"], { spawnSync(process.execPath, [binPath, 'completion', '--install', '--yes'], {
cwd: repoRoot, cwd: repoRoot,
stdio: "inherit", stdio: 'inherit',
env: { ...process.env, OPENCLAW_SKIP_POSTINSTALL: "1" }, env: { ...process.env, OPENCLAW_SKIP_POSTINSTALL: '1' },
}); });
} catch (err) { } catch (err) {
// Ignore errors to not break install // Ignore errors to not break install
@@ -276,7 +286,7 @@ function main() {
const repoRoot = getRepoRoot(); const repoRoot = getRepoRoot();
process.chdir(repoRoot); process.chdir(repoRoot);
ensureExecutable(path.join(repoRoot, "dist", "entry.mjs")); ensureExecutable(path.join(repoRoot, 'dist', '/entry.js'));
setupGitHooks({ repoRoot }); setupGitHooks({ repoRoot });
trySetupCompletion(repoRoot); trySetupCompletion(repoRoot);
@@ -284,18 +294,18 @@ function main() {
return; return;
} }
const pkgPath = path.join(repoRoot, "package.json"); const pkgPath = path.join(repoRoot, 'package.json');
const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf-8")); const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'));
const patched = pkg?.pnpm?.patchedDependencies ?? {}; const patched = pkg?.pnpm?.patchedDependencies ?? {};
// Bun does not support pnpm.patchedDependencies. Apply these patch files to // Bun does not support pnpm.patchedDependencies. Apply these patch files to
// node_modules packages as a best-effort compatibility layer. // node_modules packages as a best-effort compatibility layer.
for (const [key, relPatchPath] of Object.entries(patched)) { for (const [key, relPatchPath] of Object.entries(patched)) {
if (typeof relPatchPath !== "string" || !relPatchPath.trim()) continue; if (typeof relPatchPath !== 'string' || !relPatchPath.trim()) continue;
const pkgName = extractPackageName(String(key)); const pkgName = extractPackageName(String(key));
if (!pkgName) continue; if (!pkgName) continue;
applyPatchFile({ applyPatchFile({
targetDir: path.join("node_modules", ...pkgName.split("/")), targetDir: path.join('node_modules', ...pkgName.split('/')),
patchPath: relPatchPath, patchPath: relPatchPath,
}); });
} }
@@ -303,10 +313,10 @@ function main() {
try { try {
const skip = const skip =
process.env.OPENCLAW_SKIP_POSTINSTALL === "1" || process.env.OPENCLAW_SKIP_POSTINSTALL === '1' ||
process.env.CLAWDBOT_SKIP_POSTINSTALL === "1" || process.env.CLAWDBOT_SKIP_POSTINSTALL === '1' ||
process.env.VITEST === "true" || process.env.VITEST === 'true' ||
process.env.NODE_ENV === "test"; process.env.NODE_ENV === 'test';
if (!skip) { if (!skip) {
main(); main();

View File

@@ -1,21 +1,24 @@
#!/usr/bin/env node #!/usr/bin/env node
import { spawn } from "node:child_process"; import { spawn } from 'node:child_process';
import fs from "node:fs"; import fs from 'node:fs';
import path from "node:path"; import path from 'node:path';
import process from "node:process"; import process from 'node:process';
const args = process.argv.slice(2); const args = process.argv.slice(2);
const env = { ...process.env }; const env = { ...process.env };
const cwd = process.cwd(); const cwd = process.cwd();
const compilerOverride = env.OPENCLAW_TS_COMPILER ?? env.CLAWDBOT_TS_COMPILER; const compilerOverride = env.OPENCLAW_TS_COMPILER ?? env.CLAWDBOT_TS_COMPILER;
const compiler = compilerOverride === "tsc" ? "tsc" : "tsgo"; const compiler = compilerOverride === 'tsc' ? 'tsc' : 'tsgo';
const projectArgs = ["--project", "tsconfig.json"]; const projectArgs = ['--project', 'tsconfig.json'];
const distRoot = path.join(cwd, "dist"); const distRoot = path.join(cwd, 'dist');
const distEntry = path.join(distRoot, "entry.mjs"); const distEntry = path.join(distRoot, '/entry.js');
const buildStampPath = path.join(distRoot, ".buildstamp"); const buildStampPath = path.join(distRoot, '.buildstamp');
const srcRoot = path.join(cwd, "src"); const srcRoot = path.join(cwd, 'src');
const configFiles = [path.join(cwd, "tsconfig.json"), path.join(cwd, "package.json")]; const configFiles = [
path.join(cwd, 'tsconfig.json'),
path.join(cwd, 'package.json'),
];
const statMtime = (filePath) => { const statMtime = (filePath) => {
try { try {
@@ -27,10 +30,10 @@ const statMtime = (filePath) => {
const isExcludedSource = (filePath) => { const isExcludedSource = (filePath) => {
const relativePath = path.relative(srcRoot, filePath); const relativePath = path.relative(srcRoot, filePath);
if (relativePath.startsWith("..")) return false; if (relativePath.startsWith('..')) return false;
return ( return (
relativePath.endsWith(".test.ts") || relativePath.endsWith('.test.ts') ||
relativePath.endsWith(".test.tsx") || relativePath.endsWith('.test.tsx') ||
relativePath.endsWith(`test-helpers.ts`) relativePath.endsWith(`test-helpers.ts`)
); );
}; };
@@ -66,7 +69,7 @@ const findLatestMtime = (dirPath, shouldSkip) => {
}; };
const shouldBuild = () => { const shouldBuild = () => {
if (env.OPENCLAW_FORCE_BUILD === "1") return true; if (env.OPENCLAW_FORCE_BUILD === '1') return true;
const stampMtime = statMtime(buildStampPath); const stampMtime = statMtime(buildStampPath);
if (stampMtime == null) return true; if (stampMtime == null) return true;
if (statMtime(distEntry) == null) return true; if (statMtime(distEntry) == null) return true;
@@ -82,18 +85,18 @@ const shouldBuild = () => {
}; };
const logRunner = (message) => { const logRunner = (message) => {
if (env.OPENCLAW_RUNNER_LOG === "0") return; if (env.OPENCLAW_RUNNER_LOG === '0') return;
process.stderr.write(`[openclaw] ${message}\n`); process.stderr.write(`[openclaw] ${message}\n`);
}; };
const runNode = () => { const runNode = () => {
const nodeProcess = spawn(process.execPath, ["openclaw.mjs", ...args], { const nodeProcess = spawn(process.execPath, ['openclaw.mjs', ...args], {
cwd, cwd,
env, env,
stdio: "inherit", stdio: 'inherit',
}); });
nodeProcess.on("exit", (exitCode, exitSignal) => { nodeProcess.on('exit', (exitCode, exitSignal) => {
if (exitSignal) { if (exitSignal) {
process.exit(1); process.exit(1);
} }
@@ -107,25 +110,29 @@ const writeBuildStamp = () => {
fs.writeFileSync(buildStampPath, `${Date.now()}\n`); fs.writeFileSync(buildStampPath, `${Date.now()}\n`);
} catch (error) { } catch (error) {
// Best-effort stamp; still allow the runner to start. // Best-effort stamp; still allow the runner to start.
logRunner(`Failed to write build stamp: ${error?.message ?? "unknown error"}`); logRunner(
`Failed to write build stamp: ${error?.message ?? 'unknown error'}`,
);
} }
}; };
if (!shouldBuild()) { if (!shouldBuild()) {
runNode(); runNode();
} else { } else {
logRunner("Building TypeScript (dist is stale)."); logRunner('Building TypeScript (dist is stale).');
const pnpmArgs = ["exec", compiler, ...projectArgs]; const pnpmArgs = ['exec', compiler, ...projectArgs];
const buildCmd = process.platform === "win32" ? "cmd.exe" : "pnpm"; const buildCmd = process.platform === 'win32' ? 'cmd.exe' : 'pnpm';
const buildArgs = const buildArgs =
process.platform === "win32" ? ["/d", "/s", "/c", "pnpm", ...pnpmArgs] : pnpmArgs; process.platform === 'win32'
? ['/d', '/s', '/c', 'pnpm', ...pnpmArgs]
: pnpmArgs;
const build = spawn(buildCmd, buildArgs, { const build = spawn(buildCmd, buildArgs, {
cwd, cwd,
env, env,
stdio: "inherit", stdio: 'inherit',
}); });
build.on("exit", (code, signal) => { build.on('exit', (code, signal) => {
if (signal) { if (signal) {
process.exit(1); process.exit(1);
} }

View File

@@ -16,7 +16,7 @@ if (initialBuild.status !== 0) {
process.exit(initialBuild.status ?? 1); process.exit(initialBuild.status ?? 1);
} }
const compilerProcess = spawn("pnpm", ["tsdown", '--watch', 'src/'], { const compilerProcess = spawn("pnpm", ["tsc", '-p', 'tsconfig.json', '--noEmit', 'false', '--watch'], {
cwd, cwd,
env, env,
stdio: "inherit", stdio: "inherit",

View File

@@ -24,7 +24,7 @@ describe("ensureSkillsWatcher", () => {
expect(ignored.some((re) => re.test("/tmp/workspace/skills/node_modules/pkg/index.js"))).toBe( expect(ignored.some((re) => re.test("/tmp/workspace/skills/node_modules/pkg/index.js"))).toBe(
true, true,
); );
expect(ignored.some((re) => re.test("/tmp/workspace/skills/dist/index.mjs"))).toBe(true); expect(ignored.some((re) => re.test("/tmp/workspace/skills/dist/index.js"))).toBe(true);
expect(ignored.some((re) => re.test("/tmp/workspace/skills/.git/config"))).toBe(true); expect(ignored.some((re) => re.test("/tmp/workspace/skills/.git/config"))).toBe(true);
expect(ignored.some((re) => re.test("/tmp/.hidden/skills/index.md"))).toBe(false); expect(ignored.some((re) => re.test("/tmp/.hidden/skills/index.md"))).toBe(false);
}); });

View File

@@ -43,7 +43,7 @@ describe("browser CLI --browser-profile flag", () => {
}); });
it("does not conflict with global --profile flag", () => { it("does not conflict with global --profile flag", () => {
// The global --profile flag is handled by entry.mjs before Commander // The global --profile flag is handled by /entry.js before Commander
// This test verifies --browser-profile is a separate option // This test verifies --browser-profile is a separate option
const program = new Command(); const program = new Command();
program.name("test"); program.name("test");

View File

@@ -4,22 +4,22 @@ import { rewriteUpdateFlagArgv } from "./run-main.js";
describe("rewriteUpdateFlagArgv", () => { describe("rewriteUpdateFlagArgv", () => {
it("leaves argv unchanged when --update is absent", () => { it("leaves argv unchanged when --update is absent", () => {
const argv = ["node", "entry.mjs", "status"]; const argv = ["node", "entry.js", "status"];
expect(rewriteUpdateFlagArgv(argv)).toBe(argv); expect(rewriteUpdateFlagArgv(argv)).toBe(argv);
}); });
it("rewrites --update into the update command", () => { it("rewrites --update into the update command", () => {
expect(rewriteUpdateFlagArgv(["node", "entry.mjs", "--update"])).toEqual([ expect(rewriteUpdateFlagArgv(["node", "entry.js", "--update"])).toEqual([
"node", "node",
"entry.mjs", "entry.js",
"update", "update",
]); ]);
}); });
it("preserves global flags that appear before --update", () => { it("preserves global flags that appear before --update", () => {
expect(rewriteUpdateFlagArgv(["node", "entry.mjs", "--profile", "p", "--update"])).toEqual([ expect(rewriteUpdateFlagArgv(["node", "entry.js", "--profile", "p", "--update"])).toEqual([
"node", "node",
"entry.mjs", "entry.js",
"--profile", "--profile",
"p", "p",
"update", "update",
@@ -27,9 +27,9 @@ describe("rewriteUpdateFlagArgv", () => {
}); });
it("keeps update options after the rewritten command", () => { it("keeps update options after the rewritten command", () => {
expect(rewriteUpdateFlagArgv(["node", "entry.mjs", "--update", "--json"])).toEqual([ expect(rewriteUpdateFlagArgv(["node", "entry.js", "--update", "--json"])).toEqual([
"node", "node",
"entry.mjs", "entry.js",
"update", "update",
"--json", "--json",
]); ]);

View File

@@ -747,7 +747,7 @@ export async function updateCommand(opts: UpdateCommandOptions): Promise<void> {
let afterVersion = beforeVersion; let afterVersion = beforeVersion;
if (pkgRoot) { if (pkgRoot) {
afterVersion = await readPackageVersion(pkgRoot); afterVersion = await readPackageVersion(pkgRoot);
const entryPath = path.join(pkgRoot, "dist", "entry.mjs"); const entryPath = path.join(pkgRoot, "dist", "entry.js");
if (await pathExists(entryPath)) { if (await pathExists(entryPath)) {
const doctorStep = await runUpdateStep({ const doctorStep = await runUpdateStep({
name: `${CLI_NAME} doctor`, name: `${CLI_NAME} doctor`,
@@ -969,7 +969,9 @@ export async function updateCommand(opts: UpdateCommandOptions): Promise<void> {
try { try {
const { doctorCommand } = await import("../commands/doctor.js"); const { doctorCommand } = await import("../commands/doctor.js");
const interactiveDoctor = Boolean(process.stdin.isTTY) && !opts.json && opts.yes !== true; const interactiveDoctor = Boolean(process.stdin.isTTY) && !opts.json && opts.yes !== true;
await doctorCommand(defaultRuntime, { nonInteractive: !interactiveDoctor }); await doctorCommand(defaultRuntime, {
nonInteractive: !interactiveDoctor,
});
} catch (err) { } catch (err) {
defaultRuntime.log(theme.warn(`Doctor failed: ${String(err)}`)); defaultRuntime.log(theme.warn(`Doctor failed: ${String(err)}`));
} finally { } finally {
@@ -1220,7 +1222,9 @@ ${theme.muted("Docs:")} ${formatDocsLink("/cli/update", "docs.openclaw.ai/cli/up
) )
.action(async (opts) => { .action(async (opts) => {
try { try {
await updateWizardCommand({ timeout: opts.timeout as string | undefined }); await updateWizardCommand({
timeout: opts.timeout as string | undefined,
});
} catch (err) { } catch (err) {
defaultRuntime.error(String(err)); defaultRuntime.error(String(err));
defaultRuntime.exit(1); defaultRuntime.exit(1);

View File

@@ -103,7 +103,12 @@ vi.mock("../memory/manager.js", () => ({
sourceCounts: [{ source: "memory", files: 2, chunks: 3 }], sourceCounts: [{ source: "memory", files: 2, chunks: 3 }],
cache: { enabled: true, entries: 10, maxEntries: 500 }, cache: { enabled: true, entries: 10, maxEntries: 500 },
fts: { enabled: true, available: true }, fts: { enabled: true, available: true },
vector: { enabled: true, available: true, extensionPath: "/opt/vec0.dylib", dims: 1024 }, vector: {
enabled: true,
available: true,
extensionPath: "/opt/vec0.dylib",
dims: 1024,
},
}), }),
close: vi.fn(async () => {}), close: vi.fn(async () => {}),
__agentId: agentId, __agentId: agentId,
@@ -254,7 +259,7 @@ vi.mock("../daemon/service.js", () => ({
isLoaded: async () => true, isLoaded: async () => true,
readRuntime: async () => ({ status: "running", pid: 1234 }), readRuntime: async () => ({ status: "running", pid: 1234 }),
readCommand: async () => ({ readCommand: async () => ({
programArguments: ["node", "dist/entry.mjs", "gateway"], programArguments: ["node", "dist/entry.js", "gateway"],
sourcePath: "/tmp/Library/LaunchAgents/bot.molt.gateway.plist", sourcePath: "/tmp/Library/LaunchAgents/bot.molt.gateway.plist",
}), }),
}), }),
@@ -267,7 +272,7 @@ vi.mock("../daemon/node-service.js", () => ({
isLoaded: async () => true, isLoaded: async () => true,
readRuntime: async () => ({ status: "running", pid: 4321 }), readRuntime: async () => ({ status: "running", pid: 4321 }),
readCommand: async () => ({ readCommand: async () => ({
programArguments: ["node", "dist/entry.mjs", "node-host"], programArguments: ["node", "dist/entry.js", "node-host"],
sourcePath: "/tmp/Library/LaunchAgents/bot.molt.node.plist", sourcePath: "/tmp/Library/LaunchAgents/bot.molt.node.plist",
}), }),
}), }),

View File

@@ -24,7 +24,7 @@ afterEach(() => {
describe("resolveGatewayProgramArguments", () => { describe("resolveGatewayProgramArguments", () => {
it("uses realpath-resolved dist entry when running via npx shim", async () => { it("uses realpath-resolved dist entry when running via npx shim", async () => {
const argv1 = path.resolve("/tmp/.npm/_npx/63c3/node_modules/.bin/openclaw"); const argv1 = path.resolve("/tmp/.npm/_npx/63c3/node_modules/.bin/openclaw");
const entryPath = path.resolve("/tmp/.npm/_npx/63c3/node_modules/openclaw/dist/entry.mjs"); const entryPath = path.resolve("/tmp/.npm/_npx/63c3/node_modules/openclaw/dist/entry.js");
process.argv = ["node", argv1]; process.argv = ["node", argv1];
fsMocks.realpath.mockResolvedValue(entryPath); fsMocks.realpath.mockResolvedValue(entryPath);
fsMocks.access.mockImplementation(async (target: string) => { fsMocks.access.mockImplementation(async (target: string) => {
@@ -49,10 +49,10 @@ describe("resolveGatewayProgramArguments", () => {
// Simulates pnpm global install where node_modules/openclaw is a symlink // Simulates pnpm global install where node_modules/openclaw is a symlink
// to .pnpm/openclaw@X.Y.Z/node_modules/openclaw // to .pnpm/openclaw@X.Y.Z/node_modules/openclaw
const symlinkPath = path.resolve( const symlinkPath = path.resolve(
"/Users/test/Library/pnpm/global/5/node_modules/openclaw/dist/entry.mjs", "/Users/test/Library/pnpm/global/5/node_modules/openclaw/dist/entry.js",
); );
const realpathResolved = path.resolve( const realpathResolved = path.resolve(
"/Users/test/Library/pnpm/global/5/node_modules/.pnpm/openclaw@2026.1.21-2/node_modules/openclaw/dist/entry.mjs", "/Users/test/Library/pnpm/global/5/node_modules/.pnpm/openclaw@2026.1.21-2/node_modules/openclaw/dist/entry.js",
); );
process.argv = ["node", symlinkPath]; process.argv = ["node", symlinkPath];
fsMocks.realpath.mockResolvedValue(realpathResolved); fsMocks.realpath.mockResolvedValue(realpathResolved);
@@ -67,7 +67,7 @@ describe("resolveGatewayProgramArguments", () => {
it("falls back to node_modules package dist when .bin path is not resolved", async () => { it("falls back to node_modules package dist when .bin path is not resolved", async () => {
const argv1 = path.resolve("/tmp/.npm/_npx/63c3/node_modules/.bin/openclaw"); const argv1 = path.resolve("/tmp/.npm/_npx/63c3/node_modules/.bin/openclaw");
const indexPath = path.resolve("/tmp/.npm/_npx/63c3/node_modules/openclaw/dist/index.mjs"); const indexPath = path.resolve("/tmp/.npm/_npx/63c3/node_modules/openclaw/dist/index.js");
process.argv = ["node", argv1]; process.argv = ["node", argv1];
fsMocks.realpath.mockRejectedValue(new Error("no realpath")); fsMocks.realpath.mockRejectedValue(new Error("no realpath"));
fsMocks.access.mockImplementation(async (target: string) => { fsMocks.access.mockImplementation(async (target: string) => {

View File

@@ -47,7 +47,7 @@ export async function resolveControlUiDistIndexPath(
} }
const normalized = path.resolve(argv1); const normalized = path.resolve(argv1);
// Case 1: entrypoint is directly inside dist/ (e.g., dist/entry.mjs) // Case 1: entrypoint is directly inside dist/ (e.g., dist/entry.js)
const distDir = path.dirname(normalized); const distDir = path.dirname(normalized);
if (path.basename(distDir) === "dist") { if (path.basename(distDir) === "dist") {
return path.join(distDir, "control-ui", "index.html"); return path.join(distDir, "control-ui", "index.html");

View File

@@ -73,8 +73,8 @@ function isGatewayArgv(args: string[]): boolean {
} }
const entryCandidates = [ const entryCandidates = [
"dist/index.mjs", "dist/index.js",
"dist/entry.mjs", "dist/entry.js",
"openclaw.mjs", "openclaw.mjs",
"scripts/run-node.mjs", "scripts/run-node.mjs",
"src/index.ts", "src/index.ts",

View File

@@ -6,8 +6,8 @@ describe("isMainModule", () => {
it("returns true when argv[1] matches current file", () => { it("returns true when argv[1] matches current file", () => {
expect( expect(
isMainModule({ isMainModule({
currentFile: "/repo/dist/index.mjs", currentFile: "/repo/dist/index.js",
argv: ["node", "/repo/dist/index.mjs"], argv: ["node", "/repo/dist/index.js"],
cwd: "/repo", cwd: "/repo",
env: {}, env: {},
}), }),
@@ -17,10 +17,10 @@ describe("isMainModule", () => {
it("returns true under PM2 when pm_exec_path matches current file", () => { it("returns true under PM2 when pm_exec_path matches current file", () => {
expect( expect(
isMainModule({ isMainModule({
currentFile: "/repo/dist/index.mjs", currentFile: "/repo/dist/index.js",
argv: ["node", "/pm2/lib/ProcessContainerFork.js"], argv: ["node", "/pm2/lib/ProcessContainerFork.js"],
cwd: "/repo", cwd: "/repo",
env: { pm_exec_path: "/repo/dist/index.mjs", pm_id: "0" }, env: { pm_exec_path: "/repo/dist/index.js", pm_id: "0" },
}), }),
).toBe(true); ).toBe(true);
}); });
@@ -28,7 +28,7 @@ describe("isMainModule", () => {
it("returns false when running under PM2 but this module is imported", () => { it("returns false when running under PM2 but this module is imported", () => {
expect( expect(
isMainModule({ isMainModule({
currentFile: "/repo/node_modules/openclaw/dist/index.mjs", currentFile: "/repo/node_modules/openclaw/dist/index.js",
argv: ["node", "/repo/app.js"], argv: ["node", "/repo/app.js"],
cwd: "/repo", cwd: "/repo",
env: { pm_exec_path: "/repo/app.js", pm_id: "0" }, env: { pm_exec_path: "/repo/app.js", pm_id: "0" },

View File

@@ -37,7 +37,7 @@ describe("ports helpers", () => {
expect( expect(
classifyPortListener( classifyPortListener(
{ {
commandLine: "node /Users/me/Projects/openclaw/dist/entry.mjs gateway", commandLine: "node /Users/me/Projects/openclaw/dist/entry.js gateway",
}, },
18789, 18789,
), ),

View File

@@ -102,11 +102,11 @@ describe("installPluginFromArchive", () => {
JSON.stringify({ JSON.stringify({
name: "@openclaw/voice-call", name: "@openclaw/voice-call",
version: "0.0.1", version: "0.0.1",
openclaw: { extensions: ["./dist/index.mjs"] }, openclaw: { extensions: ["./dist/index.js"] },
}), }),
"utf-8", "utf-8",
); );
fs.writeFileSync(path.join(pkgDir, "dist", "index.mjs"), "export {};", "utf-8"); fs.writeFileSync(path.join(pkgDir, "dist", "index.js"), "export {};", "utf-8");
const archivePath = packToArchive({ const archivePath = packToArchive({
pkgDir, pkgDir,
@@ -127,7 +127,7 @@ describe("installPluginFromArchive", () => {
expect(result.pluginId).toBe("voice-call"); expect(result.pluginId).toBe("voice-call");
expect(result.targetDir).toBe(path.join(stateDir, "extensions", "voice-call")); expect(result.targetDir).toBe(path.join(stateDir, "extensions", "voice-call"));
expect(fs.existsSync(path.join(result.targetDir, "package.json"))).toBe(true); expect(fs.existsSync(path.join(result.targetDir, "package.json"))).toBe(true);
expect(fs.existsSync(path.join(result.targetDir, "dist", "index.mjs"))).toBe(true); expect(fs.existsSync(path.join(result.targetDir, "dist", "index.js"))).toBe(true);
}); });
it("rejects installing when plugin already exists", async () => { it("rejects installing when plugin already exists", async () => {
@@ -140,7 +140,7 @@ describe("installPluginFromArchive", () => {
JSON.stringify({ JSON.stringify({
name: "@openclaw/voice-call", name: "@openclaw/voice-call",
version: "0.0.1", version: "0.0.1",
openclaw: { extensions: ["./dist/index.mjs"] }, openclaw: { extensions: ["./dist/index.js"] },
}), }),
"utf-8", "utf-8",
); );
@@ -182,10 +182,10 @@ describe("installPluginFromArchive", () => {
JSON.stringify({ JSON.stringify({
name: "@openclaw/zipper", name: "@openclaw/zipper",
version: "0.0.1", version: "0.0.1",
openclaw: { extensions: ["./dist/index.mjs"] }, openclaw: { extensions: ["./dist/index.js"] },
}), }),
); );
zip.file("package/dist/index.mjs", "export {};"); zip.file("package/dist/index.js", "export {};");
const buffer = await zip.generateAsync({ type: "nodebuffer" }); const buffer = await zip.generateAsync({ type: "nodebuffer" });
fs.writeFileSync(archivePath, buffer); fs.writeFileSync(archivePath, buffer);
@@ -203,7 +203,7 @@ describe("installPluginFromArchive", () => {
expect(result.pluginId).toBe("zipper"); expect(result.pluginId).toBe("zipper");
expect(result.targetDir).toBe(path.join(stateDir, "extensions", "zipper")); expect(result.targetDir).toBe(path.join(stateDir, "extensions", "zipper"));
expect(fs.existsSync(path.join(result.targetDir, "package.json"))).toBe(true); expect(fs.existsSync(path.join(result.targetDir, "package.json"))).toBe(true);
expect(fs.existsSync(path.join(result.targetDir, "dist", "index.mjs"))).toBe(true); expect(fs.existsSync(path.join(result.targetDir, "dist", "index.js"))).toBe(true);
}); });
it("allows updates when mode is update", async () => { it("allows updates when mode is update", async () => {
@@ -216,7 +216,7 @@ describe("installPluginFromArchive", () => {
JSON.stringify({ JSON.stringify({
name: "@openclaw/voice-call", name: "@openclaw/voice-call",
version: "0.0.1", version: "0.0.1",
openclaw: { extensions: ["./dist/index.mjs"] }, openclaw: { extensions: ["./dist/index.js"] },
}), }),
"utf-8", "utf-8",
); );
@@ -234,7 +234,7 @@ describe("installPluginFromArchive", () => {
JSON.stringify({ JSON.stringify({
name: "@openclaw/voice-call", name: "@openclaw/voice-call",
version: "0.0.2", version: "0.0.2",
openclaw: { extensions: ["./dist/index.mjs"] }, openclaw: { extensions: ["./dist/index.js"] },
}), }),
"utf-8", "utf-8",
); );

View File

@@ -114,7 +114,7 @@ const spawnGatewayInstance = async (name: string): Promise<GatewayInstance> => {
child = spawn( child = spawn(
"node", "node",
[ [
"dist/index.mjs", "dist/index.js",
"gateway", "gateway",
"--port", "--port",
String(port), String(port),
@@ -201,7 +201,7 @@ const stopGatewayInstance = async (inst: GatewayInstance) => {
const runCliJson = async (args: string[], env: NodeJS.ProcessEnv): Promise<unknown> => { const runCliJson = async (args: string[], env: NodeJS.ProcessEnv): Promise<unknown> => {
const stdout: string[] = []; const stdout: string[] = [];
const stderr: string[] = []; const stderr: string[] = [];
const child = spawn("node", ["dist/index.mjs", ...args], { const child = spawn("node", ["dist/index.js", ...args], {
cwd: process.cwd(), cwd: process.cwd(),
env: { ...process.env, ...env }, env: { ...process.env, ...env },
stdio: ["ignore", "pipe", "pipe"], stdio: ["ignore", "pipe", "pipe"],

View File

@@ -1,12 +0,0 @@
import { defineConfig } from 'tsdown'
export default defineConfig([
{
entry: 'src/index.ts',
platform: 'node',
},
{
entry: 'src/entry.ts',
platform: 'node',
},
])