@coclaw/openclaw-coclaw 0.21.2 → 0.21.3

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/index.js CHANGED
@@ -5,6 +5,7 @@ import { notBound, bindOk, unbindOk, claimCodeCreated } from './src/common/messa
5
5
  import { coclawChannelPlugin } from './src/channel-plugin.js';
6
6
  import { ensureAgentSession, gatewayAgentRpc, restartRealtimeBridge, stopRealtimeBridge, waitForSessionsReady, broadcastPluginEvent } from './src/realtime-bridge.js';
7
7
  import { getHostName, readSettings, writeName, MAX_NAME_LENGTH } from './src/settings.js';
8
+ import { readConfig } from './src/config.js';
8
9
  import { setRuntime } from './src/runtime.js';
9
10
  import { createSessionManager } from './src/session-manager/manager.js';
10
11
  import { TopicManager } from './src/topic-manager/manager.js';
@@ -157,6 +158,13 @@ const plugin = {
157
158
  setRuntime(api.runtime);
158
159
  const logger = api?.logger ?? console;
159
160
  installAbortRegistryDiag(logger);
161
+
162
+ // 未 bind 时打条提示,便于 hub 装机用户看到下一步动作
163
+ readConfig().then((cfg) => {
164
+ if (!cfg?.token) {
165
+ logger.info?.('[coclaw] not bound — run `openclaw coclaw enroll` to connect to CoClaw');
166
+ }
167
+ }).catch(() => {});
160
168
  const manager = createSessionManager({ logger });
161
169
  const topicManager = new TopicManager({ logger });
162
170
  const chatHistoryManager = new ChatHistoryManager({ logger });
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "id": "openclaw-coclaw",
3
3
  "name": "CoClaw",
4
- "description": "OpenClaw CoClaw channel plugin for remote chat",
4
+ "description": "OpenClaw CoClaw channel plugin for remote chat. Run `openclaw coclaw enroll` after install to connect to CoClaw.",
5
5
  "activation": {
6
6
  "onStartup": true
7
7
  },
@@ -11,9 +11,6 @@
11
11
  "properties": {
12
12
  "serverUrl": {
13
13
  "type": "string"
14
- },
15
- "gatewayWsUrl": {
16
- "type": "string"
17
14
  }
18
15
  }
19
16
  }
package/package.json CHANGED
@@ -1,9 +1,9 @@
1
1
  {
2
2
  "name": "@coclaw/openclaw-coclaw",
3
- "version": "0.21.2",
3
+ "version": "0.21.3",
4
4
  "type": "module",
5
5
  "license": "Apache-2.0",
6
- "description": "OpenClaw CoClaw channel plugin for remote chat",
6
+ "description": "OpenClaw CoClaw channel plugin for remote chat. Run `openclaw coclaw enroll` after install to connect to CoClaw.",
7
7
  "repository": {
8
8
  "type": "git",
9
9
  "url": "https://github.com/coclaw/coclaw.git",
@@ -25,8 +25,17 @@ const SERVER_HB_PING_MS = 25_000;
25
25
  const SERVER_HB_TIMEOUT_MS = 45_000;
26
26
  const SERVER_HB_MAX_MISS = 3; // 连续 3 次无响应才断连(~135s)。上游主线程 spike 实测最坏 ~89.5s(issue #75069),余量 ~1.5x
27
27
  // gateway 握手失败的指数退避表:每个元素是"上一次失败"之后、"下一次尝试"之前的等待时间。
28
- // 最多 5 次重试(加上首次尝试共 6 次),全部失败后进入 gave-up 终态,不再自动尝试。
29
- const GATEWAY_RETRY_DELAYS_MS = [5_000, 10_000, 20_000, 20_000, 20_000];
28
+ // 最多 N 次重试(N=length;加上首次尝试共 N+1 次),全部失败后进入 gave-up 终态,
29
+ // 终态后必须 stop+start 才能恢复(无运行期自动复活)——所以预算要够覆盖慢启动场景。
30
+ // 表前置 4 档(1s + 3×1.5s)专门压低"server 启动期 sidecars 还没就绪"窗口(推荐
31
+ // retryAfterMs=500);尾段 9 × 20s 把总预算拉到 ~200s(>3 分钟),覆盖 profile 初始化、
32
+ // 笔记本刚开机磁盘忙、pion 子进程首次 spawn 等慢启动场景,避免误判"放弃"。
33
+ // export 是为了让测试 helper 通过同一份常量识别 retry timer,避免硬编码副本与生产代码漂移。
34
+ export const GATEWAY_RETRY_DELAYS_MS = [
35
+ 1_000, 1_500, 1_500, 1_500,
36
+ 5_000, 10_000,
37
+ 20_000, 20_000, 20_000, 20_000, 20_000, 20_000, 20_000, 20_000, 20_000,
38
+ ];
30
39
  // v3 握手失败时,只有错误消息匹配此正则才回退到不带 device 的 legacy 握手。
31
40
  // 严格限定在"签名/设备/scope/协议"相关错误,避免对网络/内部错误做无意义的降级尝试。
32
41
  const GATEWAY_HANDSHAKE_FALLBACK_PATTERN = /signature|device|scope|protocol/i;
@@ -90,20 +99,26 @@ function maskUrlToken(url) {
90
99
  }
91
100
 
92
101
  // 仅在未注入 resolveGatewayAuthToken 时使用,依赖 runtime / 环境变量
102
+ // 优先级:config.gateway.auth.token > env OPENCLAW_GATEWAY_TOKEN
103
+ // 与上游 server 的 auth-surface-resolution 同方向:config 主、env 兜底。
104
+ // env 路径保留是为 ensureGatewayStartupAuth 的 env-only 边角(token 由 env 提供时
105
+ // 上游不会写回 cfg),cfg 读不到时仍能拿到正确 token。
93
106
  export function defaultResolveGatewayAuthToken() {
94
- const envToken = process.env.OPENCLAW_GATEWAY_TOKEN?.trim();
95
- if (envToken) {
96
- return envToken;
97
- }
98
107
  try {
99
108
  const cfg = getClawConfig();
100
109
  const token = cfg?.gateway?.auth?.token;
101
- return typeof token === 'string' && token.trim() ? token.trim() : '';
110
+ if (typeof token === 'string' && token.trim()) {
111
+ return token.trim();
112
+ }
102
113
  }
103
114
  catch (err) {
104
115
  console.warn?.(`[coclaw] resolve gateway auth token failed: ${String(err?.message ?? err)}`);
105
- return '';
106
116
  }
117
+ const envToken = process.env.OPENCLAW_GATEWAY_TOKEN?.trim();
118
+ if (envToken) {
119
+ return envToken;
120
+ }
121
+ return '';
107
122
  }
108
123
 
109
124
  /**
@@ -247,9 +262,7 @@ export class RealtimeBridge {
247
262
  }
248
263
 
249
264
  __resolveGatewayWsUrl() {
250
- return this.pluginConfig?.gatewayWsUrl
251
- ?? process.env.COCLAW_GATEWAY_WS_URL
252
- ?? DEFAULT_GATEWAY_WS_URL;
265
+ return process.env.COCLAW_GATEWAY_WS_URL ?? DEFAULT_GATEWAY_WS_URL;
253
266
  }
254
267
 
255
268
  async __clearTokenLocal(unboundClawId) {