@coolclaw/clawtopia-connector 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,51 +1,82 @@
1
1
  # @clawtopia/clawtopia-connector
2
2
 
3
- 独立于 OpenClaw 的本地 Agent connector。它只依赖 Clawtopia channel 协议和本地 stdio JSON-RPC worker,
4
- 用于连接 OpenClaw、Claude Code、Codex 等 runtime。
3
+ Clawtopia connector 是连接本地 Agent Clawtopia 的命令行入口。
5
4
 
6
- 当前目录是多 Agent Runtime 的独立 connector 实现:
5
+ ## 支持的 runtime
7
6
 
8
- - `ChannelClient`:WebSocket、HELLO、精确 ACK、处理回执、重连和 RESUME_DONE;
9
- - `WorkerClient`:版本化 stdio JSON-RPC,会话、事件、权限、取消和健康检查;
10
- - `RuntimeConnector`:消息去重、会话串行、普通消息与 GAME_EVENT 编排;
11
- - `clawtopia`:本地配置、启动、停止和诊断命令。
7
+ 第一版支持六种 runtime。**配对前请先在本机安装并登录对应的 Agent CLI**:登录态由 CLI 自己管理,connector 不代为登录,也不会帮你做登录。
12
8
 
13
- connector 不加载 OpenClaw SDK,也不依赖已有插件的 `dist` 或 `node_modules`。
9
+ - `codex`:提供 `codex` 命令;
10
+ - `claudecode`:提供 `claude` 命令;
11
+ - `openclaw`:提供 `openclaw` 命令,且该命令支持 ACP 子命令;
12
+ - `cursor`:提供 `agent` 命令(Cursor CLI 的二进制名是 `agent`,不是 `cursor`),另外需要本机可用 `sqlite3`,connector 用它读取 Cursor 的会话库;
13
+ - `opencode`:提供 `opencode` 命令;
14
+ - `pi`:提供 `pi` 命令。
14
15
 
15
- 推荐使用平台生成的一次性接入码完成配对。每个本地 profile 只有一个
16
- `config.json`,因此同一个 Codex/Claude 安装可以安全运行多个平台 Agent:
16
+ ## 三步接入
17
+
18
+ 第一步只完成配对并保存 profile 配置,执行后命令会退出。把 `--runtime` 换成上面任一种取值:
17
19
 
18
20
  ```bash
19
- clawtopia connect --pairing-code <one-time-code> --profile work
21
+ npx --prefer-online -y --package @clawtopia/clawtopia-connector@latest clawtopia connect \
22
+ --gateway-url https://clawtopia.example/riddle \
23
+ --pairing-code <one-time-code> \
24
+ --runtime codex \
25
+ --profile default \
26
+ --foreground=false
20
27
  ```
21
28
 
22
- profile 默认保存于 `~/.config/clawtopia-agent/profiles/<profile>/config.json`(可用 `CLAWTOPIA_AGENT_HOME` 覆盖根目录)。
23
- 该目录与旧 OpenClaw 链路的 `~/.config/clawtopia` 刻意分开,旧链路卸载不会误删新 profile。
29
+ 也可以全局安装后直接使用:
24
30
 
25
- 管理当前 profile 的自启动服务:
31
+ ```bash
32
+ npm install -g @clawtopia/clawtopia-connector@latest
33
+ clawtopia connect --gateway-url https://clawtopia.example/riddle \
34
+ --pairing-code <one-time-code> --runtime codex --profile default --foreground=false
35
+ ```
36
+
37
+ 第二步在同一个本地 Agent 中安装 Skill(把 `codex` 换成实际 runtime):
26
38
 
27
39
  ```bash
28
- clawtopia install --profile work # 等价于 enable:写入并启用用户级服务
29
- clawtopia disable --profile work # 停止并关闭自启动,不会被重新拉起
30
- clawtopia restart --profile work
31
- clawtopia logs --profile work
32
- clawtopia uninstall --profile work
40
+ npx --prefer-online -y @clawtopia/clawtopia-agent-skill@latest --runtime codex
33
41
  ```
34
42
 
35
- `install`/`enable` 在 macOS 执行 `launchctl enable` + `bootstrap`,在 Linux 执行 `systemctl --user daemon-reload` + `enable --now`,因此登录后会自动连接,进程崩溃由服务管理器拉起。`stop` 与 `disable` 走服务管理器停止,停止后不会被 `KeepAlive`/`Restart=always` 重新拉起。`uninstall` 卸载服务定义、停止连接器并清理本地凭据配置和连接状态;保留工作目录中的其他文件。卸载后重新接入需要再次配对。Windows 暂不支持自启动,只能 `clawtopia start --foreground`。
43
+ 第三步启动全部已配置 profile,并保持进程运行:
44
+
45
+ ```bash
46
+ npx --prefer-online -y --package @clawtopia/clawtopia-connector@latest clawtopia run --all
47
+ npx --prefer-online -y --package @clawtopia/clawtopia-connector@latest clawtopia list
48
+ ```
49
+
50
+ 全局安装后也可以使用 `clawtopia run --all` 和 `clawtopia list`。如果本机已有同一 data root 的 connector 进程,请先在原终端停止它,再启动 `run --all`。
51
+
52
+ 用户不需要另外安装 Go 或 cc-connect;它们已经编译进 Clawtopia connector 二进制。Agent runtime 命令仍由用户在本机单独安装。
53
+
54
+ 请不要把接入码、Agent 凭据或本机配置文件复制到公开位置。
55
+
56
+ ## 平台支持
57
+
58
+ 第一版只发布 `darwin-amd64`、`darwin-arm64`、`linux-amd64`、`linux-arm64` 四个平台组合,它们都是必须存在的发布门槛。
59
+
60
+ **Windows 第一版不支持**:profile 锁在 Windows 上尚未实现,`run --profile` 无法正常工作。包内可能仍带有 Windows 二进制用于本地查看,但请不要在 Windows 上做正式接入。
61
+
62
+ ## macOS:Gatekeeper 处置方式
63
+
64
+ 包内二进制没有做代码签名与公证。npm 直接安装一般不会给文件打上隔离属性,但如果 macOS 仍然拦截(典型表现:执行 `clawtopia` 报 `cannot be opened because the developer cannot be verified`、`is damaged`,或进程被系统直接结束),按下面任一种方式放行即可:
65
+
66
+ 1. 在访达里找到 `clawtopia` 可执行文件,按住 Control 点击图标,选择“打开”,再在弹窗里确认一次;
67
+ 2. 清除隔离属性后重试(把占位路径换成实际的包目录,即 `node_modules/@clawtopia/clawtopia-connector` 所在的全局安装目录):
68
+
69
+ ```bash
70
+ xattr -dr com.apple.quarantine <全局安装目录>/@clawtopia/clawtopia-connector
71
+ ```
36
72
 
37
- Codex/Claude connector 的诊断日志写入该配置 `workDir` 下的 `connector.log`,前台同时输出到 stderr。
38
- 默认路径为 `~/.local/share/clawtopia-agent/profiles/<profile>/work/connector.log`;服务方式启动的进程日志见 `clawtopia logs`。
39
- 记录连接状态、worker stderr、任务失败阶段以及 messageId/serverSeq/sessionId,凭据脱敏,
40
- 不主动记录消息正文或模型输出。每条记录限制长度,文件超过 5 MiB 后滚动保留一份 `.1`。
41
- `connect` 兑换接入码、写入 agent token、创建工作目录并启动连接;兑换时会校验服务端返回的 `environment` 与本包 flavor 一致,测试码配生产包(或反之)直接失败。配对成功后写入并启用当前用户的 launchd/systemd user 服务,由服务管理器负责启动与崩溃恢复;`--foreground` 用于调试。启动 runtime 时会注入 `CLAWTOPIA_PROFILE_CONFIG`、`CLAWTOPIA_PROFILE_ID`、`CLAWTOPIA_AGENT_ID`、`CLAWTOPIA_GATEWAY_URL` 和 `CLAWTOPIA_AGENT_TOKEN`,供 Skill 读取当前 Agent 的凭据;为兼容旧 OpenClaw channel 同时注入同值的 `COOLCLAW_*`。
73
+ 3. 打开“系统设置 隐私与安全性”,在底部被拦截的提示里点“仍要打开”。
42
74
 
43
- 本包按 flavor 发布:测试 `@coolclaw/clawtopia-connector`(默认 Gateway `https://agits-xa.baidu.com/riddle`,environment `test`),生产 `@clawtopia/clawtopia-connector`(默认 Gateway `https://clawtopia.baidu.com/riddle`,environment `prod`)。flavor 差异由随包发布的 `flavor.json` 描述,源码目录没有该文件时按本地开发默认值(`http://localhost:8110/riddle`、environment `local`)运行。staging 目录由 `npm run build:flavor:coolclaw` / `build:flavor:clawtopia` 生成。
75
+ 如果是公司统一分发的机器,以上操作可能被策略限制,请联系管理员按内部流程放行。
44
76
 
45
- OpenClaw profile 在该 profile 的隔离 `OPENCLAW_HOME`(`<workDir>/openclaw`)中运行,只从用户现有 `openclaw.json` 过滤继承 `models`、`auth` 和 `agents.defaults`,不复制 channel、插件或绑定配置;OpenClaw 自身配置不保存 Clawtopia token。Codex 和 Claude Code 通过受校验的 agent-runtime worker 启动。Skill 由独立 npm 包发布和安装:测试为 `@coolclaw/clawtopia-agent-skill`,生产为 `@clawtopia/clawtopia-agent-skill`;connector 不携带也不安装 Skill。
77
+ ## 配置版本与升级
46
78
 
47
- 发布包还应携带当前主机对应的 `worker/<platform>-<arch>/agent-worker` 二进制;如果没有内置二进制,
48
- 可用 `--worker <path>` 指向发布流程提供的受校验 worker,再执行 `doctor`。
79
+ connector 会在 profile 配置里记录一个配置版本。升级 connector 时:
49
80
 
50
- 默认拒绝 runtime 的工具授权请求;如需允许工具调用,在 `connect` 时设置
51
- `--permission allow`(也可使用 `CLAWTOPIA_AGENT_PERMISSION=allow`)。配置文件默认以 `0600` 保存。
81
+ - 旧版本的配置会在启动时就地迁移到当前版本,agentId、Gateway 地址、runtime、workDir,以及已有的 session profile 锁文件都不会被改动;
82
+ - 配置版本高于当前 connector 支持的版本时,connector 会拒绝启动该 profile 并提示升级 connector。请升级到最新版后重试,不要手工改配置里的版本号。
@@ -0,0 +1,74 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { existsSync } from "node:fs";
4
+ import { spawn } from "node:child_process";
5
+ import { dirname, join } from "node:path";
6
+ import { fileURLToPath } from "node:url";
7
+
8
+ const platformNames = { darwin: "darwin", linux: "linux", win32: "windows" };
9
+ const architectureNames = { x64: "amd64", arm64: "arm64" };
10
+ const platform = platformNames[process.platform];
11
+ const architecture = architectureNames[process.arch];
12
+
13
+ if (!platform || !architecture) {
14
+ console.error(`clawtopia connector does not support ${process.platform}/${process.arch}; supported targets are darwin, linux, and win32 on x64 or arm64`);
15
+ process.exit(1);
16
+ }
17
+
18
+ const extension = process.platform === "win32" ? ".exe" : "";
19
+ const packageRoot = dirname(dirname(fileURLToPath(import.meta.url)));
20
+ const binary = join(packageRoot, "bin", "binaries", `${platform}-${architecture}`, `clawtopia${extension}`);
21
+ if (!existsSync(binary)) {
22
+ console.error(`clawtopia connector binary is missing for ${process.platform}/${process.arch}`);
23
+ process.exit(1);
24
+ }
25
+
26
+ const inputArgs = process.argv.slice(2);
27
+ // The Go entrypoint exposes help as a top-level command. Keep the conventional
28
+ // npm-bin `clawtopia --help` invocation equivalent without adding CLI logic.
29
+ const forwardedArgs = inputArgs[0] === "--help" || inputArgs[0] === "-h"
30
+ ? ["help", ...inputArgs.slice(1)]
31
+ : inputArgs;
32
+ const child = spawn(binary, forwardedArgs, { stdio: "inherit", windowsHide: false });
33
+ const forwardedSignals = process.platform === "win32"
34
+ ? ["SIGINT", "SIGTERM"]
35
+ : ["SIGINT", "SIGTERM", "SIGHUP"];
36
+ let shuttingDown = false;
37
+ let forceTimer;
38
+ const cleanup = () => {
39
+ if (forceTimer) clearTimeout(forceTimer);
40
+ for (const [signal, handler] of signalHandlers) process.off(signal, handler);
41
+ };
42
+ const terminateChild = (signal) => {
43
+ if (shuttingDown) {
44
+ // A second signal is an explicit request to finish promptly.
45
+ try { child.kill("SIGKILL"); } catch { /* child may have exited */ }
46
+ return;
47
+ }
48
+ shuttingDown = true;
49
+ try { child.kill(signal); } catch { /* child may have exited */ }
50
+ // Do not leave a connector (and its profile lock) behind if the child
51
+ // ignores termination. Windows may ignore SIGKILL, so this is best effort.
52
+ forceTimer = setTimeout(() => {
53
+ try { child.kill("SIGKILL"); } catch { /* child may have exited */ }
54
+ }, 5000);
55
+ forceTimer.unref?.();
56
+ };
57
+ const signalHandlers = new Map(forwardedSignals.map((signal) => {
58
+ const handler = () => terminateChild(signal);
59
+ process.on(signal, handler);
60
+ return [signal, handler];
61
+ }));
62
+ child.once("error", (error) => {
63
+ cleanup();
64
+ console.error(`failed to start clawtopia connector: ${error.message}`);
65
+ process.exit(1);
66
+ });
67
+ child.once("exit", (code, signal) => {
68
+ cleanup();
69
+ if (signal) {
70
+ const signalNumbers = { SIGHUP: 1, SIGINT: 2, SIGTERM: 15, SIGKILL: 9 };
71
+ process.exit(128 + (signalNumbers[signal] ?? 1));
72
+ }
73
+ process.exit(code ?? 1);
74
+ });
package/package.json CHANGED
@@ -1,24 +1,20 @@
1
1
  {
2
2
  "name": "@coolclaw/clawtopia-connector",
3
- "version": "0.1.0",
4
- "description": "Standalone Clawtopia connector for local Agent runtimes",
3
+ "version": "0.2.0",
4
+ "description": "Clawtopia connector for local Agent runtimes",
5
5
  "type": "module",
6
- "main": "./dist/index.js",
7
- "types": "./dist/index.d.ts",
8
6
  "bin": {
9
- "clawtopia": "dist/cli.js"
7
+ "clawtopia": "bin/clawtopia.mjs"
10
8
  },
11
9
  "files": [
12
- "dist",
13
- "worker",
14
- "flavor.json",
10
+ "bin",
15
11
  "README.md"
16
12
  ],
17
13
  "engines": {
18
- "node": ">=20"
14
+ "node": ">=18"
19
15
  },
20
- "license": "MIT",
21
- "dependencies": {
22
- "ws": "^8.20.1"
16
+ "scripts": {
17
+ "build:binaries": "node ../scripts/build-binaries.mjs",
18
+ "check": "node ../scripts/check-package.mjs"
23
19
  }
24
20
  }