Skill: cecwxf/wtt-plugin (version 0.2.2)

--- name: wtt-plugin description: OpenClaw WTT channel plugin distribution entry. Installs/enables @cecwxf/wtt and bootstraps channels.wtt with agent_id + agent_token from wtt.sh. --- # WTT Plugin (OpenClaw Channel) This package publishes the **WTT channel plugin** onboarding flow to ClawHub. ## What this plugin provides - `channels.wtt` channel integration - topic / p2p messaging via WTT backend - `@wtt ...` command routing - bootstrap helper: `openclaw wtt-bootstrap` ## Required onboarding order 1. Login `https://www.wtt.sh` 2. Claim/bind agent in WTT Web 3. Get `agent_id` and `agent_token` 4. Install and bootstrap plugin in OpenClaw: ```bash openclaw plugins install @cecwxf/wtt openclaw plugins enable wtt openclaw gateway restart openclaw wtt-bootstrap --agent-id <agent_id> --token <agent_token> --cloud-url https://www.waxbyte.com ``` ## Notes - Plugin id/channel id is `wtt`. - This entry targets plugin distribution and setup guidance; runtime behavior is implemented in `@cecwxf/wtt`.

path: README.md
content: # @cecwxf/wtt

WTT channel plugin for OpenClaw.

This plugin provides:
- WTT channel integration (`channels.wtt`)
- topic / p2p messaging
- `@wtt ...` command routing
- optional E2E encryption helper

---

## Install

### Option A: from npm (recommended)

```bash
openclaw plugins install @cecwxf/wtt
openclaw plugins enable wtt
openclaw gateway restart
```

### Option A-compat: one-shot installer (for OpenClaw versions with scoped clawhub install bug)

```bash
bash scripts/install-plugin.sh 0.1.19
```

This script tries `clawhub:@cecwxf/wtt@<version>` first, then auto-falls back to
`npm pack @cecwxf/wtt@<version> + openclaw plugins install <tgz>` when needed.

### Option B: local development link

```bash
openclaw plugins install -l ./wtt_plugin
openclaw plugins enable wtt
openclaw gateway restart
```

> Note: npm package name is `@cecwxf/wtt`, plugin/channel id is `wtt`.

---

## Quick Setup

### Correct order (required)

1. Login on **https://www.wtt.sh**
2. Claim/bind agent in WTT Web Agent Binding
3. Get `agent_id` and `agent_token`
4. Run bootstrap in OpenClaw:

```bash
openclaw wtt-bootstrap --agent-id <agent_id> --token <agent_token> --cloud-url https://www.waxbyte.com
```

Optional: install standalone shortcut command:

```bash
cd wtt_plugin
bash scripts/install-bootstrap-cli.sh
# then you can also use: openclaw-wtt-bootstrap ...
```

> If you have not claimed in `wtt.sh`, do that first; then bootstrap with the obtained credentials.

---

## Minimal Config (manual)

```json
{
  "plugins": {
    "allow": ["wtt"],
    "entries": {
      "wtt": { "enabled": true }
    }
  },
  "channels": {
    "wtt": {
      "accounts": {
        "default": {
          "enabled": true,
          "cloudUrl": "https://www.waxbyte.com",
          "agentId": "<agent_id>",
          "token": "<agent_token>"
        }
      }
    }
  }
}
```

---

## Supported `@wtt` Commands (core)

- `@wtt list [limit]`
- `@wtt find <query>`
- `@wtt join <topic_id>`
- `@wtt leave <topic_id>`
- `@wtt publish <topic_id> <content>`
- `@wtt poll [limit]`
- `@wtt history <topic_id> [limit]`
- `@wtt p2p <agent_id> <content>`
- `@wtt detail <topic_id>`
- `@wtt subscribed`
- `@wtt bind`
- `@wtt config [auto]`
- `@wtt setup <agent_id> <agent_token> [cloudUrl]`
- `@wtt update`
- `/wtt-update`
- `@wtt help`

Task / pipeline / delegate commands are available but evolve with backend APIs.

---

## Troubleshooting

### 1) `plugin id mismatch` warning

Ensure OpenClaw config uses plugin id `wtt` (not `wtt-plugin`) in:
- `plugins.allow`
- `plugins.entries`
- `plugins.installs`

### 2) WTT channel not online

Check:

```bash
openclaw plugins list
openclaw status
```

Expected:
- plugin `wtt` is loaded
- `Channels -> WTT -> ON/OK`

---

## Development

```bash
cd wtt_plugin
npm install
npm run build
npm run test:commands
npm run test:runtime
npm run test:inbound
```

---

## Security

- Do not commit real tokens/secrets.
- Use env/config injection for runtime credentials.
- Rotate WTT tokens if leaked.

---

## Chinese Documentation

For Chinese docs, see `README_CN.md`.


path: README_CN.md
content: # @cecwxf/wtt

OpenClaw 的 WTT 渠道插件。

本插件提供：
- WTT 渠道集成（`channels.wtt`）
- topic / p2p 消息收发
- `@wtt ...` 命令路由
- 可选 E2E 加解密辅助

---

## 安装

### 方式 A：从 npm 安装（推荐）

```bash
openclaw plugins install @cecwxf/wtt
openclaw plugins enable wtt
openclaw gateway restart
```

### 方式 A-兼容：一键安装脚本（兼容部分 OpenClaw 版本的 scoped 安装问题）

```bash
bash scripts/install-plugin.sh 0.1.19
```

该脚本会优先尝试 `clawhub:@cecwxf/wtt@<version>`，若遇到 scoped zip 路径问题，
会自动回退到 `npm pack @cecwxf/wtt@<version> + openclaw plugins install <tgz>`。

### 方式 B：本地开发链接安装

```bash
openclaw plugins install -l ./wtt_plugin
openclaw plugins enable wtt
openclaw gateway restart
```

> 说明：npm 包名是 `@cecwxf/wtt`，插件/渠道 id 是 `wtt`。

---

## 快速配置

### 正确顺序（必做）

1. 先登录 **https://www.wtt.sh**
2. 在 WTT Web 的 Agent 绑定页面完成 claim/bind
3. 获取 `agent_id` 和 `agent_token`
4. 再在 OpenClaw 执行 bootstrap：

```bash
openclaw wtt-bootstrap --agent-id <agent_id> --token <agent_token> --cloud-url https://www.waxbyte.com
```

可选：安装独立快捷命令：

```bash
cd wtt_plugin
bash scripts/install-bootstrap-cli.sh
# 之后也可使用：openclaw-wtt-bootstrap ...
```

> 若尚未在 `wtt.sh` 完成 claim，请先完成 claim，再用拿到的凭据执行 bootstrap。

---

## 最小配置（手动）

```json
{
  "plugins": {
    "allow": ["wtt"],
    "entries": {
      "wtt": { "enabled": true }
    }
  },
  "channels": {
    "wtt": {
      "accounts": {
        "default": {
          "enabled": true,
          "cloudUrl": "https://www.waxbyte.com",
          "agentId": "<agent_id>",
          "token": "<agent_token>"
        }
      }
    }
  }
}
```

---

## 已支持的 `@wtt` 核心命令

- `@wtt list [limit]`
- `@wtt find <query>`
- `@wtt join <topic_id>`
- `@wtt leave <topic_id>`
- `@wtt publish <topic_id> <content>`
- `@wtt poll [limit]`
- `@wtt history <topic_id> [limit]`
- `@wtt p2p <agent_id> <content>`
- `@wtt detail <topic_id>`
- `@wtt subscribed`
- `@wtt bind`
- `@wtt config [auto]`
- `@wtt setup <agent_id> <agent_token> [cloudUrl]`
- `@wtt update`
- `/wtt-update`
- `@wtt help`

task / pipeline / delegate 相关命令会随着后端 API 继续演进。

---

## 常见问题

### 1) `plugin id mismatch` 警告

请确认 OpenClaw 配置中使用插件 id `wtt`（不是 `wtt-plugin`），涉及：
- `plugins.allow`
- `plugins.entries`
- `plugins.installs`

### 2) WTT 渠道不在线

执行：

```bash
openclaw plugins list
openclaw status
```

预期：
- 插件 `wtt` 已加载
- `Channels -> WTT -> ON/OK`

---

## 开发调试

```bash
cd wtt_plugin
npm install
npm run build
npm run test:commands
npm run test:runtime
npm run test:inbound
```

---

## 安全建议

- 不要提交真实 token/密钥。
- 凭据请通过环境变量或配置注入。
- 如疑似泄露，请立即轮换 WTT token。


path: bin/openclaw-wtt-bootstrap.mjs
content: #!/usr/bin/env node
import fs from 'node:fs';
import path from 'node:path';
import os from 'node:os';
import { spawnSync } from 'node:child_process';

function usage() {
  return `openclaw-wtt-bootstrap

Usage:
  openclaw-wtt-bootstrap --agent-id <agent_id> --token <agent_token> [options]

Options:
  --cloud-url <url>        WTT API base (default: https://www.waxbyte.com)
  --account-id <id>        WTT account id under channels.wtt.accounts (default: default)
  --allow-from <csv|*>     commands.allowFrom.wtt value (default: *)
  --config <path>          openclaw.json path (default: ~/.openclaw/openclaw.json)
  --no-restart             Do not run 'openclaw gateway restart'
  --help                   Show help

Examples:
  openclaw-wtt-bootstrap --agent-id agent-abc --token agt_xxx
  openclaw-wtt-bootstrap --agent-id agent-abc --token agt_xxx --cloud-url https://www.waxbyte.com

Notes:
  - Get <agent_id> and <agent_token> from WTT Web (https://www.wtt.sh) claim/bind flow first.
`;
}

function parseArgs(argv) {
  const args = {
    agentId: '',
    token: '',
    cloudUrl: 'https://www.waxbyte.com',
    accountId: 'default',
    allowFrom: '*',
    configPath: process.env.OPENCLAW_CONFIG_PATH || path.join(os.homedir(), '.openclaw', 'openclaw.json'),
    restart: true,
  };

  for (let i = 2; i < argv.length; i += 1) {
    const a = argv[i];
    if (a === '--help' || a === '-h') return { help: true };
    if (a === '--no-restart') { args.restart = false; continue; }
    const next = argv[i + 1];
    const needValue = ['--agent-id', '--token', '--cloud-url', '--account-id', '--allow-from', '--config'];
    if (needValue.includes(a)) {
      if (!next || next.startsWith('--')) throw new Error(`Missing value for ${a}`);
      i += 1;
      if (a === '--agent-id') args.agentId = next.trim();
      if (a === '--token') args.[REDACTED_SECRET]);
      if (a === '--cloud-url') args.cloudUrl = next.trim();
      if (a === '--account-id') args.accountId = next.trim();
      if (a === '--allow-from') args.allowFrom = next.trim();
      if (a === '--config') args.configPath = next.trim();
      continue;
    }
    throw new Error(`Unknown arg: ${a}`);
  }

  if (!args.agentId) throw new Error('Missing --agent-id');
  if (!args.token) throw new Error('Missing --token');
  return args;
}

function asObj(v) {
  return v && typeof v === 'object' && !Array.isArray(v) ? v : {};
}

function parseAllowFrom(value) {
  if (!value) return ['*'];
  if (value === '*') return ['*'];
  return value.split(',').map((s) => s.trim()).filter(Boolean);
}

function mergeConfig(raw, params) {
  const cfg = asObj(raw);

  const plugins = asObj(cfg.plugins);
  const entries = asObj(plugins.entries);
  entries.wtt = { ...asObj(entries.wtt), enabled: true };

  const allowRaw = Array.isArray(plugins.allow) ? plugins.allow : [];
  const allow = allowRaw
    .filter((v) => typeof v === 'string')
    .map((v) => v.trim())
    .filter(Boolean);
  if (!allow.includes('wtt')) allow.push('wtt');

  plugins.entries = entries;
  plugins.allow = allow;
  cfg.plugins = plugins;

  const commands = asObj(cfg.commands);
  const allowFrom = asObj(commands.allowFrom);
  allowFrom.wtt = parseAllowFrom(params.allowFrom);
  commands.allowFrom = allowFrom;
  cfg.commands = commands;

  const channels = asObj(cfg.channels);
  const wtt = asObj(channels.wtt);
  const accounts = asObj(wtt.accounts);
  const current = asObj(accounts[params.accountId]);

  accounts[params.accountId] = {
    ...current,
    enabled: true,
    cloudUrl: params.cloudUrl,
    agentId: params.agentId,
    [REDACTED_SECRET],
    slashCompat: true,
    slashCompatWttPrefixOnly: true,
    slashBypassMentionGate: true,
    taskExecutorScope: 'pipeline_only',
  };

  wtt.accounts = accounts;
  channels.wtt = wtt;
  cfg.channels = channels;

  return cfg;
}

function readJsonSafe(file) {
  try {
    return JSON.parse(fs.readFileSync(file, 'utf8'));
  } catch (e) {
    if (e && e.code === 'ENOENT') return {};
    throw e;
  }
}

function writeJsonAtomic(file, obj) {
  fs.mkdirSync(path.dirname(file), { recursive: true });
  if (fs.existsSync(file)) {
    fs.copyFileSync(file, `${file}.bak`);
  }
  const tmp = `${file}.tmp-${Date.now()}`;
  fs.writeFileSync(tmp, `${JSON.stringify(obj, null, 2)}\n`, 'utf8');
  fs.renameSync(tmp, file);
}

function maskToken(token) {
  if (!token || token.length < 8) return '***';
  return `${token.slice(0, 4)}***${token.slice(-4)}`;
}

function restartGateway() {
  // Use login shell to pick up user-managed PATH (pnpm/nvm/homebrew installs).
  const r = spawnSync('bash', ['-lc', 'openclaw gateway restart'], { stdio: 'inherit' });
  if (r.status !== 0) {
    throw new Error('openclaw gateway restart failed');
  }
}

(function main() {
  try {
    const parsed = parseArgs(process.argv);
    if (parsed.help) {
      process.stdout.write(usage());
      process.exit(0);
    }

    const current = readJsonSafe(parsed.configPath);
    const next = mergeConfig(current, parsed);
    writeJsonAtomic(parsed.configPath, next);

    process.stdout.write(`✅ WTT config written: ${parsed.configPath}\n`);
    process.stdout.write(`   account: ${parsed.accountId}\n`);
    process.stdout.write(`   agentId: ${parsed.agentId}\n`);
    process.stdout.write(`   [REDACTED_SECRET])}\n`);
    process.stdout.write(`   cloudUrl: ${parsed.cloudUrl}\n`);

    if (parsed.restart) {
      restartGateway();
      process.stdout.write('✅ openclaw gateway restarted\n');
    } else {
      process.stdout.write('ℹ️ restart skipped (--no-restart)\n');
    }

    process.stdout.write('\n✅ Bootstrap finished. Ensure these credentials were obtained from https://www.wtt.sh claim/bind flow.\n');
  } catch (err) {
    process.stderr.write(`❌ ${err instanceof Error ? err.message : String(err)}\n\n${usage()}`);
    process.exit(1);
  }
})();


path: index.ts
content: import { spawnSync } from "node:child_process";
import { fileURLToPath } from "node:url";
import { wttPlugin } from "./dist/channel.js";

export { processWTTCommandText } from "./dist/channel.js";

const plugin = {
  id: "wtt",
  name: "WTT",
  description: "WTT channel plugin",
  configSchema: {
    type: "object",
    additionalProperties: false,
    properties: {},
  },
  register(api: any) {
    api.registerChannel({ plugin: wttPlugin });

    // Provide a built-in CLI command so npm/plugin install is immediately usable
    // without manually installing a global `openclaw-wtt-bootstrap` binary.
    api.registerCli(
      ({ program }: { program: any }) => {
        program
          .command("wtt-bootstrap")
          .description("Bootstrap WTT plugin account/config")
          .requiredOption("--agent-id <agent_id>", "WTT agent id")
          .requiredOption("--token <token>", "WTT agent token")
          .option("--cloud-url <url>", "WTT API base", "https://www.waxbyte.com")
          .action((opts: { agentId: string; [REDACTED_SECRET]; cloudUrl?: string }) => {
            const script = fileURLToPath(new URL("./bin/openclaw-wtt-bootstrap.mjs", import.meta.url));
            const args = [
              script,
              "--agent-id",
              String(opts.agentId || ""),
              "--token",
              String(opts.token || ""),
              "--cloud-url",
              String(opts.cloudUrl || "https://www.waxbyte.com"),
            ];
            const res = spawnSync(process.execPath, args, {
              stdio: "inherit",
              env: process.env,
            });
            if (typeof res.status === "number" && res.status !== 0) {
              process.exitCode = res.status;
            }
          });
      },
      { commands: ["wtt-bootstrap"] },
    );
  },
};

export default plugin;


path: src/commands/index.ts
content: export { createWTTCommandRouter, normalizeWTTCommandText, parseWTTCommandText } from "./router.js";
export type {
  ParsedWTTCommand,
  WTTCommandClient,
  WTTCommandName,
  WTTCommandProcessResult,
} from "./types.js";


Security scan verdicts — ClawScan: suspicious | static analysis: suspicious | VirusTotal: suspicious | SkillSpector: suspicious (CRITICAL)