openclaw-channel-claw-task-ops 0.1.3 → 0.1.4

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
@@ -2,140 +2,154 @@
2
2
 
3
3
  OpenClaw 渠道插件:从 Claw Task Ops 拉取任务,交由 OpenClaw Agent 处理,并将处理结果和日志反馈回去。
4
4
 
5
- ## 接入方式
5
+ - 入站:轮询 HSF HTTP 网关拉取 pending 任务,自动更新为 processing
6
+ - 出站:Agent 处理结果通过 HSF 反馈,日志写入 claw_task_log
7
+ - 自动注册:插件启动时自动注册实例,定时心跳更新在线状态
6
8
 
7
- ### 1. 安装插件
9
+ ## 安装
8
10
 
9
11
  ```bash
10
- npm install openclaw-channel-claw-task-ops
12
+ openclaw plugins install openclaw-channel-claw-task-ops
11
13
  ```
12
14
 
13
- ### 2. 配置 OpenClaw
15
+ 安装后重启网关:
14
16
 
15
- 在 OpenClaw 配置文件中添加渠道配置:
17
+ ```bash
18
+ openclaw gateway restart
19
+ ```
20
+
21
+ ## 更新
22
+
23
+ ```bash
24
+ openclaw plugins update openclaw-channel-claw-task-ops
25
+ openclaw gateway restart
26
+ ```
16
27
 
17
- ```yaml
18
- channels:
19
- claw-task-ops:
20
- enabled: true
21
- gatewayBaseUrl: "https://pre-lantu.alibaba-inc.com"
22
- instanceId: "your_claw_instance_id"
23
- pollIntervalSec: 10
24
- pullLimit: 5
28
+ ## 卸载
29
+
30
+ ```bash
31
+ openclaw plugins uninstall openclaw-channel-claw-task-ops
32
+ openclaw gateway restart
25
33
  ```
26
34
 
27
- 配置说明:
28
- - `gatewayBaseUrl`: HSF HTTP 网关地址
29
- - `instanceId`: Claw 实例 ID(在 Claw Task Ops 管理界面创建)
30
- - `pollIntervalSec`: 轮询间隔(秒),默认 10
31
- - `pullLimit`: 每次拉取的最大任务数,默认 5
32
-
33
- ### 3. 在 openclaw.config.yaml 中注册插件
34
-
35
- ```yaml
36
- plugins:
37
- entries:
38
- claw-task-ops:
39
- package: openclaw-channel-claw-task-ops
40
- config:
41
- gatewayBaseUrl: "https://pre-lantu.alibaba-inc.com"
42
- instanceId: "your_claw_instance_id"
35
+ ## 配置(channels.claw-task-ops)
36
+
37
+ ```json
38
+ {
39
+ "channels": {
40
+ "claw-task-ops": {
41
+ "gatewayBaseUrl": "https://pre-clawtask.alibaba-inc.com",
42
+ "instanceId": "my_claw_instance",
43
+ "instanceName": "我的Claw实例",
44
+ "instanceDescription": "处理数据同步任务",
45
+ "authorizedUsers": ["12345", "67890"],
46
+ "accessToken": "your-secret-token"
47
+ }
48
+ }
49
+ }
43
50
  ```
44
51
 
52
+ | 参数 | 必填 | 默认值 | 说明 |
53
+ |------|------|--------|------|
54
+ | `gatewayBaseUrl` | 是 | - | HSF HTTP 网关地址 |
55
+ | `instanceId` | 是 | - | 实例唯一标识 |
56
+ | `instanceName` | 否 | = instanceId | 实例显示名称 |
57
+ | `instanceDescription` | 否 | 空 | 实例描述 |
58
+ | `authorizedUsers` | 否 | 空(不限制) | 授权用户工号列表,控制管理界面访问权限 |
59
+ | `accessToken` | 否 | 空(不校验) | 投递令牌,HTTP/HSF 投递任务时需携带 |
60
+
61
+ ## 自动注册与权限管理
62
+
63
+ 插件启动后会自动向后端注册实例。如果 `instanceId` 对应的实例不存在,后端会自动创建;如果已存在,则更新状态为 running 并刷新 `lastOnlineTime`。此后每次轮询都会更新 `lastOnlineTime` 作为心跳。
64
+
65
+ - **authorizedUsers**:配置后仅列表中的工号用户可在管理界面查看和操作该实例,未授权用户会看到「无权限」提示。为空或不配置时所有人可访问。
66
+ - **accessToken**:配置后通过 HTTP/HSF 投递任务时必须携带此 token,后端会校验 token 与实例配置是否一致,不一致则拒绝投递。未配置时不校验。
67
+
45
68
  ## 投递任务
46
69
 
47
- ### 方式一:通过管理界面
48
-
49
- 1. 访问 Claw Task Ops 管理界面
50
- 2. 进入目标实例
51
- 3. 点击「新建任务」
52
- 4. 填写任务信息(名称、类型、优先级、载荷)
53
- 5. 提交后任务进入 pending 状态,等待 OpenClaw 拉取处理
54
-
55
- ### 方式二:通过 API 直接投递
56
-
57
- 使用通用仓储 API 直接写入任务数据:
58
-
59
- ```javascript
60
- // 投递任务
61
- const taskId = `claw_task_${Date.now()}`;
62
- await fetch('/luyou/lp/data/save/claw_task_info', {
63
- method: 'POST',
64
- headers: { 'Content-Type': 'application/json' },
65
- body: JSON.stringify({
66
- dataKey: taskId,
67
- dataValue: {
68
- taskId,
69
- instanceId: 'your_claw_instance_id',
70
- taskName: '数据同步任务',
71
- taskType: 'data_sync',
72
- priority: 'high', // high | medium | low
73
- status: 'pending', // 必须为 pending,插件才会拉取
74
- payload: { key: 'value' },
75
- operator: '张三',
76
- operatorId: '12345',
77
- createdTime: new Date().toISOString(),
78
- updatedTime: new Date().toISOString(),
79
- deleted: 0,
70
+ ### 通过 HTTP 接口投递
71
+
72
+ ```bash
73
+ curl -X POST 'https://pre-clawtask.alibaba-inc.com/luyou/public/gateway/executeHsf.json' \
74
+ -H 'Content-Type: application/json' \
75
+ -d '{
76
+ "appName": "onetouch-logistics-operation",
77
+ "hsfName": "com.alibaba.onetouch.logistics.compass.service.ClawTaskOpsRemoteService#submitTask(com.alibaba.onetouch.logistics.compass.dto.claw.ClawTaskDTO,java.lang.String)~com.alibaba.onetouch.basedata.api.Result",
78
+ "args": [
79
+ {
80
+ "instanceId": "your_claw_instance_id",
81
+ "taskName": "数据同步任务",
82
+ "taskType": "data_sync",
83
+ "priority": "high",
84
+ "payload": { "sourceTable": "orders", "targetTable": "orders_backup" },
85
+ "operator": "张三",
86
+ "operatorId": "12345"
80
87
  },
81
- searchBy: {
82
- taskId,
83
- instanceId: 'your_claw_instance_id',
84
- status: 'pending',
85
- priority: 'high',
86
- deleted: '0',
87
- }
88
- })
89
- });
88
+ "your-secret-token"
89
+ ]
90
+ }'
91
+ ```
92
+
93
+ `args` 第二个参数为 `accessToken`,需与实例配置的 token 一致。`taskId` 和 `status` 可不传,后端自动生成。
94
+
95
+ ### 通过 HSF 接口投递(Java)
96
+
97
+ 引入 compass-sdk 依赖([查询最新版本](https://artlab.alibaba-inc.com/GAResult?GroupId=com.alibaba.onetouch&Artifact=compass-sdk)):
98
+
99
+ ```xml
100
+ <dependency>
101
+ <groupId>com.alibaba.onetouch</groupId>
102
+ <artifactId>compass-sdk</artifactId>
103
+ <version>最新版本</version>
104
+ </dependency>
90
105
  ```
91
106
 
92
- ### 方式三:通过 HSF 接口投递(后端调用)
107
+ 配置 HSF Consumer 并调用:
93
108
 
94
109
  ```java
95
- // 直接使用 CompassDataWarehouseRepository 写入
96
- ClawTaskDTO task = new ClawTaskDTO();
97
- task.setTaskId("claw_task_" + System.currentTimeMillis());
98
- task.setInstanceId("your_claw_instance_id");
99
- task.setTaskName("报表生成任务");
100
- task.setTaskType("report");
101
- task.setPriority("medium");
102
- task.setStatus("pending");
103
- task.setPayload(Map.of("reportType", "daily"));
104
- task.setOperator("系统");
105
- task.setOperatorId("system");
106
- task.setCreatedTime(Instant.now().toString());
107
- task.setDeleted(0);
108
- task.setDataKey(task.getTaskId());
109
- task.setWarehouseName(ClawTaskDTO.WAREHOUSE_NAME);
110
- task.setSearchBy(Map.of(
111
- "taskId", task.getTaskId(),
112
- "instanceId", task.getInstanceId(),
113
- "status", "pending",
114
- "priority", "medium",
115
- "deleted", "0"
116
- ));
117
-
118
- compassDataWarehouseRepository.saveData(task);
110
+ @HSFConsumer(serviceInterface = ClawTaskOpsRemoteService.class, serviceVersion = "1.0.0")
111
+ private ClawTaskOpsRemoteService clawTaskOpsRemoteService;
112
+
113
+ public String deliverTask() {
114
+ ClawTaskDTO task = new ClawTaskDTO();
115
+ task.setInstanceId("your_claw_instance_id");
116
+ task.setTaskName("报表生成任务");
117
+ task.setTaskType("report");
118
+ task.setPriority("medium");
119
+ task.setPayload(Map.of("reportType", "daily"));
120
+ task.setOperator("系统");
121
+ task.setOperatorId("system");
122
+
123
+ Result<ClawTaskDTO> result = clawTaskOpsRemoteService.submitTask(task, "your-secret-token");
124
+ return result.getData().getTaskId();
125
+ }
119
126
  ```
120
127
 
121
128
  ## 处理流程
122
129
 
123
130
  ```
124
- 投递任务 (status=pending)
125
-
126
- 插件轮询拉取 状态变更为 processing
127
-
128
- OpenClaw Agent 处理任务
129
-
130
- 处理日志写入 claw_task_log
131
-
132
- 反馈结果 状态变更为 completed/failed
131
+ 1. 投递任务 (HTTP / HSF / 管理界面)
132
+
133
+ 2. 进入队列 (status = pending)
134
+
135
+ 3. 插件拉取 (状态变更为 processing)
136
+
137
+ 4. Agent 处理 (OpenClaw 执行任务)
138
+
139
+ 5. 写入日志 (过程记录到跟进日志)
140
+
141
+ 6. 反馈结果 (status → completed / failed)
133
142
  ```
134
143
 
135
- ## 推包脚本
144
+ ## HSF 接口一览
136
145
 
137
- ```bash
138
- cd packages/openclaw-channel-claw-task-ops
139
- npm run build
140
- npm publish
141
- ```
146
+ 接口:`com.alibaba.onetouch.logistics.compass.service.ClawTaskOpsRemoteService`
147
+ HSF 版本:1.0.0 | 应用:onetouch-logistics-operation
148
+
149
+ | 方法 | 参数 | 说明 |
150
+ |------|------|------|
151
+ | `submitTask` | ClawTaskDTO, String accessToken | 投递任务(需校验 accessToken) |
152
+ | `pullTasks` | String instanceId, int limit | 拉取 pending 任务,自动更新为 processing |
153
+ | `feedbackTask` | String taskId, String status, String result | 反馈任务结果(completed / failed) |
154
+ | `addTaskLog` | ClawTaskLogDTO | 添加任务处理日志 |
155
+ | `registerInstance` | String id, String name, String desc, Map extConfig | 注册/心跳实例(含授权配置) |
@@ -1,9 +1,3 @@
1
1
  import { type OpenClawPluginApi } from "openclaw/plugin-sdk/irc";
2
- /**
3
- * 注册任务消费者:
4
- * 1. 启动时自动注册实例到后端(不存在则创建,已存在则更新为 running)
5
- * 2. 每次轮询时通过 registerInstance 心跳更新 lastOnlineTime
6
- * 3. 拉取 pending 任务分发给 OpenClaw 处理
7
- */
8
2
  export declare function registerClawTaskOpsConsumer(api: OpenClawPluginApi): void;
9
3
  //# sourceMappingURL=consumer.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"consumer.d.ts","sourceRoot":"","sources":["../../src/consumer.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAajE;;;;;GAKG;AACH,wBAAgB,2BAA2B,CAAC,GAAG,EAAE,iBAAiB,GAAG,IAAI,CAyExE"}
1
+ {"version":3,"file":"consumer.d.ts","sourceRoot":"","sources":["../../src/consumer.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAajE,wBAAgB,2BAA2B,CAAC,GAAG,EAAE,iBAAiB,GAAG,IAAI,CAwFxE"}
@@ -8,17 +8,12 @@ const RECONNECT_MS_MAX = 60_000;
8
8
  function sleep(ms) {
9
9
  return new Promise((r) => setTimeout(r, ms));
10
10
  }
11
- /**
12
- * 注册任务消费者:
13
- * 1. 启动时自动注册实例到后端(不存在则创建,已存在则更新为 running)
14
- * 2. 每次轮询时通过 registerInstance 心跳更新 lastOnlineTime
15
- * 3. 拉取 pending 任务分发给 OpenClaw 处理
16
- */
17
11
  export function registerClawTaskOpsConsumer(api) {
18
12
  attachLogger(api);
19
13
  logInfo("consumer_register_ok (polling loop starting)");
20
14
  let stopped = false;
21
15
  let reconnectDelay = RECONNECT_MS_MIN;
16
+ let pollCount = 0;
22
17
  const loop = async () => {
23
18
  while (!stopped) {
24
19
  const cfg = api.runtime.config.loadConfig();
@@ -33,29 +28,39 @@ export function registerClawTaskOpsConsumer(api) {
33
28
  continue;
34
29
  }
35
30
  reconnectDelay = RECONNECT_MS_MIN;
36
- // 每次轮询都调用 registerInstance 作为心跳,更新 lastOnlineTime + 自动注册
37
- // 同时传入 authorizedUsers accessToken
38
- await registerInstance(account.gatewayBaseUrl, account.instanceId, account.instanceName, account.instanceDescription, {
31
+ pollCount++;
32
+ logInfo(`poll_cycle_start #${pollCount} instanceId=${account.instanceId} gateway=${account.gatewayBaseUrl} interval=${account.pollIntervalSec}s`);
33
+ // 心跳注册
34
+ const heartbeatOk = await registerInstance(account.gatewayBaseUrl, account.instanceId, account.instanceName, account.instanceDescription, {
39
35
  authorizedUsers: account.authorizedUsers,
40
36
  accessToken: account.accessToken,
41
37
  });
38
+ if (!heartbeatOk) {
39
+ logWarn(`poll_cycle_skip #${pollCount} heartbeat failed, skip pullTasks`);
40
+ await sleep(account.pollIntervalSec * 1000);
41
+ continue;
42
+ }
43
+ // 拉取任务
42
44
  try {
43
45
  const tasks = await pullTasks(account.gatewayBaseUrl, account.instanceId, account.pullLimit);
44
46
  if (tasks.length > 0) {
45
- logInfo(`consumer_pulled count=${tasks.length} instanceId=${account.instanceId}`);
47
+ logInfo(`poll_cycle_dispatch #${pollCount} dispatching ${tasks.length} task(s)`);
46
48
  for (const task of tasks) {
47
49
  try {
50
+ logInfo(`dispatch_begin taskId=${task.taskId} taskName=${task.taskName} priority=${task.priority}`);
48
51
  await dispatchTaskInbound({ api, cfg, account, task });
52
+ logInfo(`dispatch_end taskId=${task.taskId} status=ok`);
49
53
  }
50
54
  catch (e) {
51
- logError(`dispatch_task_error taskId=${task.taskId} err=${String(e)}`);
55
+ logError(`dispatch_end taskId=${task.taskId} status=error err=${String(e)}`);
52
56
  }
53
57
  }
54
58
  }
55
59
  }
56
60
  catch (e) {
57
- logError(`consumer_poll_error err=${String(e)}`);
61
+ logError(`poll_cycle_error #${pollCount} err=${String(e)}`);
58
62
  }
63
+ logInfo(`poll_cycle_done #${pollCount} next in ${account.pollIntervalSec}s`);
59
64
  await sleep(account.pollIntervalSec * 1000);
60
65
  }
61
66
  };
@@ -1,6 +1,6 @@
1
1
  import type { ClawTaskPayload } from "./types.js";
2
2
  /**
3
- * 注册实例(自动注册 + 心跳更新 lastOnlineTime),同时传入 authorizedUsers 和 accessToken
3
+ * 注册实例(自动注册 + 心跳更新 lastOnlineTime
4
4
  */
5
5
  export declare function registerInstance(gatewayBaseUrl: string, instanceId: string, name: string, description: string, extConfig: {
6
6
  authorizedUsers?: string[];
@@ -1 +1 @@
1
- {"version":3,"file":"hsf-client.d.ts","sourceRoot":"","sources":["../../src/hsf-client.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAoDlD;;GAEG;AACH,wBAAsB,gBAAgB,CACpC,cAAc,EAAE,MAAM,EACtB,UAAU,EAAE,MAAM,EAClB,IAAI,EAAE,MAAM,EACZ,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE;IAAE,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAA;CAAE,GAC9D,OAAO,CAAC,OAAO,CAAC,CASlB;AAED;;GAEG;AACH,wBAAsB,SAAS,CAC7B,cAAc,EAAE,MAAM,EACtB,UAAU,EAAE,MAAM,EAClB,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,eAAe,EAAE,CAAC,CAU5B;AAED;;GAEG;AACH,wBAAsB,YAAY,CAChC,cAAc,EAAE,MAAM,EACtB,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,GAAG,IAAI,GACpB,OAAO,CAAC,OAAO,CAAC,CASlB;AAED;;GAEG;AACH,wBAAsB,UAAU,CAC9B,cAAc,EAAE,MAAM,EACtB,MAAM,EAAE,MAAM,EACd,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,OAAO,CAAC,CAWlB"}
1
+ {"version":3,"file":"hsf-client.d.ts","sourceRoot":"","sources":["../../src/hsf-client.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAyElD;;GAEG;AACH,wBAAsB,gBAAgB,CACpC,cAAc,EAAE,MAAM,EACtB,UAAU,EAAE,MAAM,EAClB,IAAI,EAAE,MAAM,EACZ,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE;IAAE,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAA;CAAE,GAC9D,OAAO,CAAC,OAAO,CAAC,CAUlB;AAED;;GAEG;AACH,wBAAsB,SAAS,CAC7B,cAAc,EAAE,MAAM,EACtB,UAAU,EAAE,MAAM,EAClB,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,eAAe,EAAE,CAAC,CAgB5B;AAED;;GAEG;AACH,wBAAsB,YAAY,CAChC,cAAc,EAAE,MAAM,EACtB,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,GAAG,IAAI,GACpB,OAAO,CAAC,OAAO,CAAC,CAUlB;AAED;;GAEG;AACH,wBAAsB,UAAU,CAC9B,cAAc,EAAE,MAAM,EACtB,MAAM,EAAE,MAAM,EACd,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,OAAO,CAAC,CAWlB"}
@@ -1,46 +1,66 @@
1
1
  import { HSF_ADD_TASK_LOG, HSF_APP_NAME, HSF_FEEDBACK_TASK, HSF_GATEWAY_PATH, HSF_PULL_TASKS, HSF_REGISTER_INSTANCE, } from "./constants.js";
2
2
  import { logError, logInfo, logWarn } from "./logging.js";
3
+ /** 从 hsfName 中提取方法名,如 ...#submitTask(...)~... → submitTask */
4
+ function methodNameFrom(hsfName) {
5
+ const m = hsfName.match(/#(\w+)\(/);
6
+ return m ? m[1] : hsfName;
7
+ }
3
8
  /**
4
- * 通用 HSF HTTP 网关调用
9
+ * 通用 HSF HTTP 网关调用(含详细日志)
5
10
  */
6
11
  async function callHsf(gatewayBaseUrl, hsfName, args) {
7
12
  const url = `${gatewayBaseUrl}${HSF_GATEWAY_PATH}`;
8
- const response = await fetch(url, {
9
- method: "POST",
10
- headers: { "Content-Type": "application/json" },
11
- body: JSON.stringify({
12
- appName: HSF_APP_NAME,
13
- hsfName,
14
- args,
15
- }),
16
- });
13
+ const method = methodNameFrom(hsfName);
14
+ const t0 = Date.now();
15
+ logInfo(`hsf_request method=${method} url=${url}`);
16
+ let response;
17
+ try {
18
+ response = await fetch(url, {
19
+ method: "POST",
20
+ headers: { "Content-Type": "application/json" },
21
+ body: JSON.stringify({ appName: HSF_APP_NAME, hsfName, args }),
22
+ });
23
+ }
24
+ catch (e) {
25
+ logError(`hsf_network_error method=${method} url=${url} err=${String(e)}`);
26
+ throw e;
27
+ }
28
+ const durationMs = Date.now() - t0;
17
29
  if (!response.ok) {
30
+ logError(`hsf_http_error method=${method} status=${response.status} duration=${durationMs}ms`);
18
31
  throw new Error(`HTTP ${response.status}: ${response.statusText}`);
19
32
  }
20
33
  const result = (await response.json());
21
34
  if (result.code !== 0) {
22
- throw new Error(result.message || result.data?.result?.message || "HSF 调用失败");
35
+ const errMsg = result.message || result.data?.result?.message || "HSF 调用失败";
36
+ logError(`hsf_gateway_error method=${method} code=${result.code} message=${errMsg} duration=${durationMs}ms`);
37
+ throw new Error(errMsg);
23
38
  }
24
39
  if (result.data?.result) {
25
40
  const biz = result.data.result;
26
41
  if (!biz.success && biz.code !== "SUCCESS" && biz.code !== 0) {
27
- throw new Error(biz.message || "HSF 业务调用失败");
42
+ const bizMsg = biz.message || "HSF 业务调用失败";
43
+ logError(`hsf_biz_error method=${method} code=${biz.code} message=${bizMsg} duration=${durationMs}ms`);
44
+ throw new Error(bizMsg);
28
45
  }
46
+ logInfo(`hsf_response method=${method} success=true duration=${durationMs}ms`);
29
47
  return biz.data;
30
48
  }
49
+ logInfo(`hsf_response method=${method} success=true duration=${durationMs}ms`);
31
50
  return result.data;
32
51
  }
33
52
  /**
34
- * 注册实例(自动注册 + 心跳更新 lastOnlineTime),同时传入 authorizedUsers 和 accessToken
53
+ * 注册实例(自动注册 + 心跳更新 lastOnlineTime
35
54
  */
36
55
  export async function registerInstance(gatewayBaseUrl, instanceId, name, description, extConfig) {
37
56
  try {
38
- await callHsf(gatewayBaseUrl, HSF_REGISTER_INSTANCE, [instanceId, name, description, extConfig]);
39
- logInfo(`registerInstance ok instanceId=${instanceId}`);
57
+ logInfo(`heartbeat_start instanceId=${instanceId} name=${name}`);
58
+ const data = await callHsf(gatewayBaseUrl, HSF_REGISTER_INSTANCE, [instanceId, name, description, extConfig]);
59
+ logInfo(`heartbeat_ok instanceId=${instanceId} response=${JSON.stringify(data ?? null).slice(0, 200)}`);
40
60
  return true;
41
61
  }
42
62
  catch (e) {
43
- logWarn(`registerInstance failed instanceId=${instanceId} err=${String(e)}`);
63
+ logWarn(`heartbeat_fail instanceId=${instanceId} err=${String(e)}`);
44
64
  return false;
45
65
  }
46
66
  }
@@ -49,13 +69,20 @@ export async function registerInstance(gatewayBaseUrl, instanceId, name, descrip
49
69
  */
50
70
  export async function pullTasks(gatewayBaseUrl, instanceId, limit) {
51
71
  try {
72
+ logInfo(`pullTasks_start instanceId=${instanceId} limit=${limit}`);
52
73
  const data = await callHsf(gatewayBaseUrl, HSF_PULL_TASKS, [instanceId, limit]);
53
74
  const tasks = data ?? [];
54
- logInfo(`pullTasks ok instanceId=${instanceId} count=${tasks.length}`);
75
+ if (tasks.length > 0) {
76
+ const taskIds = tasks.map(t => t.taskId).join(", ");
77
+ logInfo(`pullTasks_ok instanceId=${instanceId} count=${tasks.length} taskIds=[${taskIds}]`);
78
+ }
79
+ else {
80
+ logInfo(`pullTasks_ok instanceId=${instanceId} count=0 (队列为空)`);
81
+ }
55
82
  return tasks;
56
83
  }
57
84
  catch (e) {
58
- logWarn(`pullTasks failed instanceId=${instanceId} err=${String(e)}`);
85
+ logWarn(`pullTasks_fail instanceId=${instanceId} err=${String(e)}`);
59
86
  return [];
60
87
  }
61
88
  }
@@ -64,12 +91,13 @@ export async function pullTasks(gatewayBaseUrl, instanceId, limit) {
64
91
  */
65
92
  export async function feedbackTask(gatewayBaseUrl, taskId, status, result) {
66
93
  try {
94
+ logInfo(`feedbackTask_start taskId=${taskId} status=${status}`);
67
95
  await callHsf(gatewayBaseUrl, HSF_FEEDBACK_TASK, [taskId, status, result]);
68
- logInfo(`feedbackTask ok taskId=${taskId} status=${status}`);
96
+ logInfo(`feedbackTask_ok taskId=${taskId} status=${status}`);
69
97
  return true;
70
98
  }
71
99
  catch (e) {
72
- logError(`feedbackTask failed taskId=${taskId} err=${String(e)}`);
100
+ logError(`feedbackTask_fail taskId=${taskId} err=${String(e)}`);
73
101
  return false;
74
102
  }
75
103
  }
@@ -81,11 +109,11 @@ export async function addTaskLog(gatewayBaseUrl, taskId, instanceId, logType, co
81
109
  await callHsf(gatewayBaseUrl, HSF_ADD_TASK_LOG, [
82
110
  { taskId, instanceId, logType, content, operator: "openclaw", operatorId: "openclaw" },
83
111
  ]);
84
- logInfo(`addTaskLog ok taskId=${taskId} logType=${logType}`);
112
+ logInfo(`addTaskLog_ok taskId=${taskId} logType=${logType}`);
85
113
  return true;
86
114
  }
87
115
  catch (e) {
88
- logWarn(`addTaskLog failed taskId=${taskId} err=${String(e)}`);
116
+ logWarn(`addTaskLog_fail taskId=${taskId} err=${String(e)}`);
89
117
  return false;
90
118
  }
91
119
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "openclaw-channel-claw-task-ops",
3
- "version": "0.1.3",
3
+ "version": "0.1.4",
4
4
  "description": "OpenClaw channel plugin for Claw Task Ops: pulls tasks via HSF HTTP gateway, processes them, and feeds back logs",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",