mirror of
https://github.com/moltbot/moltbot.git
synced 2026-05-06 23:55:12 +00:00
build(plugins): externalize acpx release packages
This commit is contained in:
@@ -9,6 +9,8 @@ Docs: https://docs.openclaw.ai
|
||||
- Tools: add a platform-level tool descriptor planner for descriptor-first visibility, generic availability checks, and executor references. Thanks @shakkernerd.
|
||||
- Docs/Codex: clarify that ChatGPT/Codex subscription setups should use `openai/gpt-*` with `agentRuntime.id: "codex"` for native Codex runtime, while `openai-codex/*` remains the PI OAuth route. Thanks @pashpashpash.
|
||||
- Plugins/source checkout: load bundled plugins from the `extensions/*` pnpm workspace tree in source checkouts, so plugin-local dependencies and edits are used directly while packaged installs keep using the built runtime tree. Thanks @vincentkoc.
|
||||
- Plugins/beta: externalize ACPX behind the official `@openclaw/acpx` package so packaged installs keep ACP harness adapter binaries out of core until the ACP backend is installed. Thanks @vincentkoc.
|
||||
- Plugins/beta: externalize diagnostics OpenTelemetry behind the official `@openclaw/diagnostics-otel` package so packaged installs keep the OTEL dependency stack out of core until the plugin is installed. Thanks @vincentkoc.
|
||||
- Plugins/beta: prepare Google Chat, LINE, Matrix, and Mattermost for `2026.5.1-beta.2` npm and ClawHub publishing, and keep publishable plugin dist trees out of the core npm package. Thanks @vincentkoc.
|
||||
- Plugins/beta: prepare BlueBubbles, diagnostics Prometheus, Google Meet, Nextcloud Talk, Nostr, Zalo, and Zalo Personal for `2026.5.1-beta.2` npm and ClawHub publishing. Thanks @vincentkoc.
|
||||
- Plugins/beta: prepare diagnostics OpenTelemetry, Discord, Diffs, Lobster, Memory LanceDB, Microsoft Teams, QQ Bot, Voice Call, and WhatsApp for `2026.5.1-beta.1` npm and ClawHub publishing. Thanks @vincentkoc.
|
||||
|
||||
@@ -1016,7 +1016,7 @@ Notes:
|
||||
- `enabled`: global ACP feature gate (default: `true`; set `false` to hide ACP dispatch and spawn affordances).
|
||||
- `dispatch.enabled`: independent gate for ACP session turn dispatch (default: `true`). Set `false` to keep ACP commands available while blocking execution.
|
||||
- `backend`: default ACP runtime backend id (must match a registered ACP runtime plugin).
|
||||
If `plugins.allow` is set, include the backend plugin id (for example `acpx`) or the bundled default plugin will not load.
|
||||
Install the backend plugin first, and if `plugins.allow` is set, include the backend plugin id (for example `acpx`) or the ACP backend will not load.
|
||||
- `defaultAgent`: fallback ACP target agent id when spawns do not specify an explicit target.
|
||||
- `allowedAgents`: allowlist of agent ids permitted for ACP runtime sessions; empty means no additional restriction.
|
||||
- `maxConcurrentSessions`: maximum concurrently active ACP sessions.
|
||||
|
||||
@@ -7,7 +7,7 @@ read_when:
|
||||
- You need the exact metric names, span names, or attribute shapes to build dashboards or alerts
|
||||
---
|
||||
|
||||
OpenClaw exports diagnostics through the bundled `diagnostics-otel` plugin
|
||||
OpenClaw exports diagnostics through the official `diagnostics-otel` plugin
|
||||
using **OTLP/HTTP (protobuf)**. Any collector or backend that accepts OTLP/HTTP
|
||||
works without code changes. For local file logs and how to read them, see
|
||||
[Logging](/logging).
|
||||
@@ -27,6 +27,12 @@ works without code changes. For local file logs and how to read them, see
|
||||
|
||||
## Quick start
|
||||
|
||||
For packaged installs, install the plugin first:
|
||||
|
||||
```bash
|
||||
openclaw plugins install @openclaw/diagnostics-otel
|
||||
```
|
||||
|
||||
```json5
|
||||
{
|
||||
plugins: {
|
||||
|
||||
@@ -266,7 +266,7 @@ Docker notes:
|
||||
- The Docker runner lives at `scripts/test-live-acp-bind-docker.sh`.
|
||||
- By default, it runs the ACP bind smoke against the aggregate live CLI agents in sequence: `claude`, `codex`, then `gemini`.
|
||||
- Use `OPENCLAW_LIVE_ACP_BIND_AGENTS=claude`, `OPENCLAW_LIVE_ACP_BIND_AGENTS=codex`, `OPENCLAW_LIVE_ACP_BIND_AGENTS=droid`, `OPENCLAW_LIVE_ACP_BIND_AGENTS=gemini`, or `OPENCLAW_LIVE_ACP_BIND_AGENTS=opencode` to narrow the matrix.
|
||||
- It sources `~/.profile`, stages the matching CLI auth material into the container, then installs the requested live CLI (`@anthropic-ai/claude-code`, `@openai/codex`, Factory Droid via `https://app.factory.ai/cli`, `@google/gemini-cli`, or `opencode-ai`) if missing. The ACP backend itself is the bundled embedded `acpx/runtime` package from the `acpx` plugin.
|
||||
- It sources `~/.profile`, stages the matching CLI auth material into the container, then installs the requested live CLI (`@anthropic-ai/claude-code`, `@openai/codex`, Factory Droid via `https://app.factory.ai/cli`, `@google/gemini-cli`, or `opencode-ai`) if missing. The ACP backend itself is the embedded `acpx/runtime` package from the official `acpx` plugin.
|
||||
- The Droid Docker variant stages `~/.factory` for settings, forwards `FACTORY_API_KEY`, and requires that API key because local Factory OAuth/keyring auth is not portable into the container. It uses ACPX's built-in `droid exec --output-format acp` registry entry.
|
||||
- The OpenCode Docker variant is a strict single-agent regression lane. It writes a temporary `OPENCODE_CONFIG_CONTENT` default model from `OPENCLAW_LIVE_ACP_BIND_OPENCODE_MODEL` (default `opencode/kimi-k2.6`) after sourcing `~/.profile`, and `pnpm test:docker:live-acp-bind:opencode` requires a bound assistant transcript instead of accepting the generic post-bind skip.
|
||||
- Direct `acpx` CLI calls are only a manual/workaround path for comparing behavior outside the Gateway. The Docker ACP bind smoke exercises OpenClaw's embedded `acpx` runtime backend.
|
||||
|
||||
@@ -161,13 +161,13 @@ export OTEL_SERVICE_NAME="openclaw-gateway"
|
||||
./scripts/docker/setup.sh
|
||||
```
|
||||
|
||||
The official OpenClaw Docker release image includes the bundled
|
||||
`diagnostics-otel` plugin source. To enable export, allow and enable the
|
||||
`diagnostics-otel` plugin in config, then set
|
||||
`diagnostics.otel.enabled=true` or use the config example in
|
||||
[OpenTelemetry export](/gateway/opentelemetry). Collector auth headers are
|
||||
configured through `diagnostics.otel.headers`, not through Docker environment
|
||||
variables.
|
||||
Install the official `@openclaw/diagnostics-otel` plugin in packaged Docker
|
||||
installs before enabling export. Custom source-built images can still include
|
||||
the local plugin source with `OPENCLAW_EXTENSIONS=diagnostics-otel`. To enable
|
||||
export, allow and enable the `diagnostics-otel` plugin in config, then set
|
||||
`diagnostics.otel.enabled=true` or use the config example in [OpenTelemetry
|
||||
export](/gateway/opentelemetry). Collector auth headers are configured through
|
||||
`diagnostics.otel.headers`, not through Docker environment variables.
|
||||
|
||||
Prometheus metrics use the already-published Gateway port. Enable the
|
||||
`diagnostics-prometheus` plugin, then scrape:
|
||||
|
||||
@@ -126,8 +126,15 @@ See [Configuration Reference](/gateway/configuration-reference).
|
||||
|
||||
## Plugin setup for acpx backend
|
||||
|
||||
Fresh installs ship the bundled `acpx` runtime plugin enabled by default, so ACP
|
||||
usually works without a manual plugin install step.
|
||||
Packaged installs use the official `@openclaw/acpx` runtime plugin for ACP.
|
||||
Install and enable it before using ACP harness sessions:
|
||||
|
||||
```bash
|
||||
openclaw plugins install @openclaw/acpx
|
||||
openclaw config set plugins.entries.acpx.enabled true
|
||||
```
|
||||
|
||||
Source checkouts can also use the local workspace plugin after `pnpm install`.
|
||||
|
||||
Start with:
|
||||
|
||||
@@ -136,10 +143,10 @@ Start with:
|
||||
```
|
||||
|
||||
If you disabled `acpx`, denied it via `plugins.allow` / `plugins.deny`, or want
|
||||
to switch to a local development checkout, use the explicit plugin path:
|
||||
to switch back to the packaged plugin, use the explicit package path:
|
||||
|
||||
```bash
|
||||
openclaw plugins install acpx
|
||||
openclaw plugins install @openclaw/acpx
|
||||
openclaw config set plugins.entries.acpx.enabled true
|
||||
```
|
||||
|
||||
@@ -157,7 +164,7 @@ Then verify backend health:
|
||||
|
||||
### acpx command and version configuration
|
||||
|
||||
By default, the bundled `acpx` plugin registers the embedded ACP backend without
|
||||
By default, the `acpx` plugin registers the embedded ACP backend without
|
||||
spawning an ACP agent during Gateway startup. Run `/acp doctor` for an explicit
|
||||
live probe. Set `OPENCLAW_ACPX_RUNTIME_STARTUP_PROBE=1` only when you need the
|
||||
Gateway to probe the configured agent at startup.
|
||||
@@ -243,7 +250,7 @@ What this does:
|
||||
|
||||
### Runtime timeout configuration
|
||||
|
||||
The bundled `acpx` plugin defaults embedded runtime turns to a 120-second
|
||||
The `acpx` plugin defaults embedded runtime turns to a 120-second
|
||||
timeout. This gives slower harnesses such as Gemini CLI enough time to complete
|
||||
ACP startup and initialization. Override it if your host needs a different
|
||||
runtime limit:
|
||||
|
||||
@@ -39,10 +39,15 @@ directly to existing OpenClaw channel conversations, use
|
||||
|
||||
## Does this work out of the box?
|
||||
|
||||
Usually yes. Fresh installs ship the bundled `acpx` runtime plugin enabled
|
||||
by default with a plugin-local pinned `acpx` binary that OpenClaw probes
|
||||
and self-repairs immediately after the Gateway HTTP listener is live. Run
|
||||
`/acp doctor` for a readiness check.
|
||||
Yes, after installing the official ACP runtime plugin:
|
||||
|
||||
```bash
|
||||
openclaw plugins install @openclaw/acpx
|
||||
openclaw config set plugins.entries.acpx.enabled true
|
||||
```
|
||||
|
||||
Source checkouts can use the local `extensions/acpx` workspace plugin after
|
||||
`pnpm install`. Run `/acp doctor` for a readiness check.
|
||||
|
||||
OpenClaw only teaches agents about ACP spawning when ACP is **truly
|
||||
usable**: ACP must be enabled, dispatch must not be disabled, the current
|
||||
@@ -53,8 +58,8 @@ an unavailable backend.
|
||||
|
||||
<AccordionGroup>
|
||||
<Accordion title="First-run gotchas">
|
||||
- If `plugins.allow` is set, it is a restrictive plugin inventory and **must** include `acpx`; otherwise the bundled default is intentionally blocked and `/acp doctor` reports the missing allowlist entry.
|
||||
- The bundled Codex ACP adapter is staged with the `acpx` plugin and launched locally when possible.
|
||||
- If `plugins.allow` is set, it is a restrictive plugin inventory and **must** include `acpx`; otherwise the installed ACP backend is intentionally blocked and `/acp doctor` reports the missing allowlist entry.
|
||||
- The Codex ACP adapter is staged with the `acpx` plugin and launched locally when possible.
|
||||
- Other target harness adapters may still be fetched on demand with `npx` the first time you use them.
|
||||
- Vendor auth still has to exist on the host for that harness.
|
||||
- If the host has no npm or network access, first-run adapter fetches fail until caches are pre-warmed or the adapter is installed another way.
|
||||
@@ -86,7 +91,7 @@ should call those tools directly.
|
||||
|
||||
## Supported harness targets
|
||||
|
||||
With the bundled `acpx` backend, use these harness ids as `/acp spawn <id>`
|
||||
With the `acpx` backend, use these harness ids as `/acp spawn <id>`
|
||||
or `sessions_spawn({ runtime: "acp", agentId: "<id>" })` targets:
|
||||
|
||||
| Harness id | Typical backend | Notes |
|
||||
@@ -232,7 +237,7 @@ See also [Sub-agents](/tools/subagents).
|
||||
For Claude Code through ACP, the stack is:
|
||||
|
||||
1. OpenClaw ACP session control plane.
|
||||
2. Bundled `acpx` runtime plugin.
|
||||
2. Official `@openclaw/acpx` runtime plugin.
|
||||
3. Claude ACP adapter.
|
||||
4. Claude-side runtime/session machinery.
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ This file applies to work under `extensions/acpx/`.
|
||||
|
||||
## Purpose
|
||||
|
||||
The bundled ACPX extension is a thin OpenClaw wrapper around the published `acpx` package. Keep reusable ACP runtime logic in `openclaw/acpx`, not in this extension.
|
||||
The ACPX extension is a thin OpenClaw wrapper around the published `acpx` package. Keep reusable ACP runtime logic in `openclaw/acpx`, not in this extension.
|
||||
|
||||
## Default Version Policy
|
||||
|
||||
@@ -30,7 +30,7 @@ Use this flow when OpenClaw needs unreleased ACPX changes before the ACPX versio
|
||||
## Lockfile Notes
|
||||
|
||||
- `pnpm-lock.yaml` is the tracked workspace lockfile and must match the ACPX version referenced by `extensions/acpx/package.json`.
|
||||
- `extensions/acpx/package-lock.json` is useful local install metadata for the bundled plugin package.
|
||||
- `extensions/acpx/package-lock.json` is useful local install metadata for the plugin package.
|
||||
- If `extensions/acpx/package-lock.json` is gitignored in this repo state, regenerating it is still useful for local verification, but it will not appear in `git status`.
|
||||
|
||||
## Local Runtime Validation
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
{
|
||||
"name": "@openclaw/acpx",
|
||||
"version": "2026.4.25",
|
||||
"version": "2026.5.1-beta.2",
|
||||
"description": "OpenClaw ACP runtime backend",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/openclaw/openclaw"
|
||||
},
|
||||
"type": "module",
|
||||
"dependencies": {
|
||||
"@agentclientprotocol/claude-agent-acp": "0.31.4",
|
||||
@@ -14,6 +18,21 @@
|
||||
"openclaw": {
|
||||
"extensions": [
|
||||
"./index.ts"
|
||||
]
|
||||
],
|
||||
"install": {
|
||||
"npmSpec": "@openclaw/acpx",
|
||||
"defaultChoice": "npm",
|
||||
"minHostVersion": ">=2026.4.25"
|
||||
},
|
||||
"compat": {
|
||||
"pluginApi": ">=2026.4.25"
|
||||
},
|
||||
"build": {
|
||||
"openclawVersion": "2026.5.1-beta.2"
|
||||
},
|
||||
"release": {
|
||||
"publishToClawHub": true,
|
||||
"publishToNpm": true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -105,7 +105,7 @@ Required behavior when ACP backend is unavailable:
|
||||
|
||||
1. Do not immediately ask the user to pick an alternate path.
|
||||
2. First attempt automatic local repair:
|
||||
- ensure plugin-local pinned acpx is installed in the bundled ACPX plugin package
|
||||
- ensure plugin-local pinned acpx is installed in the ACPX plugin package
|
||||
- verify `${ACPX_CMD} --version`
|
||||
3. After reinstall/repair, restart the gateway and explicitly offer to run that restart for the user.
|
||||
4. Retry ACP thread spawn once after repair.
|
||||
@@ -231,7 +231,7 @@ If your local Cursor install still exposes ACP as `agent acp`, set that as the `
|
||||
### Failure handling
|
||||
|
||||
- `acpx: command not found`:
|
||||
- for thread-spawn ACP requests, install plugin-local pinned acpx in the bundled ACPX plugin package immediately
|
||||
- for thread-spawn ACP requests, install plugin-local pinned acpx in the ACPX plugin package immediately
|
||||
- restart gateway after install and offer to run the restart automatically
|
||||
- then retry once
|
||||
- do not ask for install permission first unless policy explicitly requires it
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@openclaw/diagnostics-otel",
|
||||
"version": "2026.5.1-beta.1",
|
||||
"version": "2026.5.1-beta.2",
|
||||
"description": "OpenClaw diagnostics OpenTelemetry exporter",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@@ -27,11 +27,16 @@
|
||||
"extensions": [
|
||||
"./index.ts"
|
||||
],
|
||||
"install": {
|
||||
"npmSpec": "@openclaw/diagnostics-otel",
|
||||
"defaultChoice": "npm",
|
||||
"minHostVersion": ">=2026.4.25"
|
||||
},
|
||||
"compat": {
|
||||
"pluginApi": ">=2026.4.25"
|
||||
},
|
||||
"build": {
|
||||
"openclawVersion": "2026.5.1-beta.1"
|
||||
"openclawVersion": "2026.5.1-beta.2"
|
||||
},
|
||||
"release": {
|
||||
"publishToClawHub": true,
|
||||
|
||||
@@ -14,6 +14,11 @@
|
||||
"extensions": [
|
||||
"./index.ts"
|
||||
],
|
||||
"install": {
|
||||
"npmSpec": "@openclaw/diagnostics-prometheus",
|
||||
"defaultChoice": "npm",
|
||||
"minHostVersion": ">=2026.4.25"
|
||||
},
|
||||
"compat": {
|
||||
"pluginApi": ">=2026.4.25"
|
||||
},
|
||||
|
||||
@@ -19,6 +19,11 @@
|
||||
"extensions": [
|
||||
"./index.ts"
|
||||
],
|
||||
"install": {
|
||||
"npmSpec": "@openclaw/lobster",
|
||||
"defaultChoice": "npm",
|
||||
"minHostVersion": ">=2026.4.25"
|
||||
},
|
||||
"compat": {
|
||||
"pluginApi": ">=2026.4.25"
|
||||
},
|
||||
|
||||
@@ -29,6 +29,8 @@
|
||||
"./index.ts"
|
||||
],
|
||||
"install": {
|
||||
"npmSpec": "@openclaw/voice-call",
|
||||
"defaultChoice": "npm",
|
||||
"minHostVersion": ">=2026.4.10"
|
||||
},
|
||||
"compat": {
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
"!dist/.runtime-postbuildstamp",
|
||||
"!dist/**/*.map",
|
||||
"!dist/plugin-sdk/.tsbuildinfo",
|
||||
"!dist/extensions/acpx/**",
|
||||
"!dist/extensions/node_modules/**",
|
||||
"!dist/extensions/*/node_modules/**",
|
||||
"!dist/extensions/bluebubbles/**",
|
||||
|
||||
@@ -19,6 +19,8 @@ export type PluginPackageJson = {
|
||||
openclaw?: {
|
||||
extensions?: string[];
|
||||
install?: {
|
||||
defaultChoice?: string;
|
||||
minHostVersion?: string;
|
||||
npmSpec?: string;
|
||||
};
|
||||
release?: {
|
||||
@@ -218,6 +220,7 @@ export function collectPublishablePluginPackageErrors(
|
||||
const errors: string[] = [];
|
||||
const packageName = packageJson.name?.trim() ?? "";
|
||||
const packageVersion = packageJson.version?.trim() ?? "";
|
||||
const installNpmSpec = normalizeOptionalString(packageJson.openclaw?.install?.npmSpec);
|
||||
const repositoryUrl =
|
||||
typeof packageJson.repository === "string"
|
||||
? packageJson.repository.trim()
|
||||
@@ -250,6 +253,9 @@ export function collectPublishablePluginPackageErrors(
|
||||
if (extensions.some((entry) => typeof entry !== "string" || !entry.trim())) {
|
||||
errors.push("openclaw.extensions must contain only non-empty strings.");
|
||||
}
|
||||
if (!installNpmSpec) {
|
||||
errors.push("openclaw.install.npmSpec must be a non-empty string for publishable plugins.");
|
||||
}
|
||||
|
||||
return errors;
|
||||
}
|
||||
|
||||
@@ -98,6 +98,9 @@ describe("collectPublishablePluginPackageErrors", () => {
|
||||
},
|
||||
openclaw: {
|
||||
extensions: ["./index.ts"],
|
||||
install: {
|
||||
npmSpec: "@openclaw/zalo",
|
||||
},
|
||||
release: {
|
||||
publishToNpm: true,
|
||||
},
|
||||
@@ -118,6 +121,9 @@ describe("collectPublishablePluginPackageErrors", () => {
|
||||
private: true,
|
||||
openclaw: {
|
||||
extensions: [""],
|
||||
install: {
|
||||
npmSpec: " ",
|
||||
},
|
||||
release: {
|
||||
publishToNpm: true,
|
||||
},
|
||||
@@ -130,6 +136,7 @@ describe("collectPublishablePluginPackageErrors", () => {
|
||||
`package.json repository.url must be "${OPENCLAW_PLUGIN_NPM_REPOSITORY_URL}" so npm provenance can validate GitHub trusted publishing; found "<missing>".`,
|
||||
'package.json version must match YYYY.M.D, YYYY.M.D-N, or YYYY.M.D-beta.N; found "latest".',
|
||||
"openclaw.extensions must contain only non-empty strings.",
|
||||
"openclaw.install.npmSpec must be a non-empty string for publishable plugins.",
|
||||
]);
|
||||
});
|
||||
|
||||
@@ -143,6 +150,9 @@ describe("collectPublishablePluginPackageErrors", () => {
|
||||
version: "2026.5.1-beta.1",
|
||||
openclaw: {
|
||||
extensions: ["./index.ts"],
|
||||
install: {
|
||||
npmSpec: "@openclaw/twitch",
|
||||
},
|
||||
release: {
|
||||
publishToNpm: true,
|
||||
},
|
||||
@@ -153,6 +163,29 @@ describe("collectPublishablePluginPackageErrors", () => {
|
||||
`package.json repository.url must be "${OPENCLAW_PLUGIN_NPM_REPOSITORY_URL}" so npm provenance can validate GitHub trusted publishing; found "<missing>".`,
|
||||
]);
|
||||
});
|
||||
|
||||
it("requires npm install metadata for publishable plugins", () => {
|
||||
expect(
|
||||
collectPublishablePluginPackageErrors({
|
||||
extensionId: "voice-call",
|
||||
packageDir: bundledPluginRoot("voice-call"),
|
||||
packageJson: {
|
||||
name: "@openclaw/voice-call",
|
||||
version: "2026.5.1-beta.1",
|
||||
repository: {
|
||||
type: "git",
|
||||
url: OPENCLAW_PLUGIN_NPM_REPOSITORY_URL,
|
||||
},
|
||||
openclaw: {
|
||||
extensions: ["./index.ts"],
|
||||
release: {
|
||||
publishToNpm: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
).toEqual(["openclaw.install.npmSpec must be a non-empty string for publishable plugins."]);
|
||||
});
|
||||
});
|
||||
|
||||
describe("collectPublishablePluginPackages", () => {
|
||||
@@ -218,6 +251,9 @@ describe("collectPublishablePluginPackages", () => {
|
||||
},
|
||||
openclaw: {
|
||||
extensions: ["./index.ts"],
|
||||
install: {
|
||||
npmSpec: "@openclaw/demo-plugin",
|
||||
},
|
||||
release: {
|
||||
publishToNpm: true,
|
||||
},
|
||||
@@ -230,6 +266,9 @@ describe("collectPublishablePluginPackages", () => {
|
||||
private: true,
|
||||
openclaw: {
|
||||
extensions: ["./index.ts"],
|
||||
install: {
|
||||
npmSpec: "@openclaw/private-plugin",
|
||||
},
|
||||
release: {
|
||||
publishToNpm: true,
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user