@workclaw/openclaw-workclaw 1.0.17 → 1.0.18

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.
Files changed (51) hide show
  1. package/README.md +21 -1
  2. package/index.ts +210 -210
  3. package/openclaw.plugin.json +1 -0
  4. package/package.json +11 -4
  5. package/setup-entry.ts +6 -0
  6. package/skills/openclaw-workclaw-cron/SKILL.md +45 -28
  7. package/src/accounts.ts +62 -37
  8. package/src/api/accounts-api.ts +88 -89
  9. package/src/api/prompts-api.ts +70 -77
  10. package/src/api/session-api.ts +99 -108
  11. package/src/api/skills-api.ts +35 -37
  12. package/src/api/workspace.ts +27 -29
  13. package/src/channel.ts +200 -202
  14. package/src/config-schema.ts +9 -9
  15. package/src/connection/workclaw-client.ts +554 -567
  16. package/src/gateway/agent-handlers.ts +392 -426
  17. package/src/gateway/config-writer.ts +228 -243
  18. package/src/gateway/message-context.ts +534 -362
  19. package/src/gateway/message-dispatcher.ts +529 -489
  20. package/src/gateway/reconnect.ts +217 -113
  21. package/src/gateway/skills-handler.ts +408 -472
  22. package/src/gateway/skills-list-handler.ts +9 -9
  23. package/src/gateway/tools-list-handler.ts +70 -72
  24. package/src/gateway/workclaw-gateway.ts +328 -486
  25. package/src/media/upload.ts +83 -94
  26. package/src/outbound/index.ts +57 -55
  27. package/src/outbound/workclaw-sender.ts +134 -133
  28. package/src/runtime.ts +291 -194
  29. package/src/send.ts +1 -1
  30. package/src/tools/openclaw-workclaw-cron/api/index.ts +6 -6
  31. package/src/tools/openclaw-workclaw-cron/src/add/params.ts +20 -19
  32. package/src/tools/openclaw-workclaw-cron/src/add/sync.ts +2 -2
  33. package/src/tools/openclaw-workclaw-cron/src/disable/params.ts +1 -1
  34. package/src/tools/openclaw-workclaw-cron/src/disable/sync.ts +3 -3
  35. package/src/tools/openclaw-workclaw-cron/src/enable/params.ts +1 -1
  36. package/src/tools/openclaw-workclaw-cron/src/enable/sync.ts +3 -3
  37. package/src/tools/openclaw-workclaw-cron/src/notify/sync.ts +2 -2
  38. package/src/tools/openclaw-workclaw-cron/src/remove/params.ts +1 -1
  39. package/src/tools/openclaw-workclaw-cron/src/remove/sync.ts +3 -3
  40. package/src/tools/openclaw-workclaw-cron/src/update/params.ts +195 -197
  41. package/src/tools/openclaw-workclaw-cron/src/update/sync.ts +4 -4
  42. package/src/tools/openclaw-workclaw-system/src/get/index.ts +2 -2
  43. package/src/tools/openclaw-workclaw-system/src/token/index.ts +4 -4
  44. package/src/types.ts +38 -40
  45. package/src/utils/content.ts +16 -21
  46. package/tests/accounts.test.ts +285 -0
  47. package/tests/message-context.test.ts +313 -0
  48. package/tests/reconnect.test.ts +257 -0
  49. package/tests/workclaw-client.test.ts +112 -0
  50. package/tsconfig.json +8 -5
  51. package/vitest.config.ts +8 -0
@@ -4,6 +4,11 @@
4
4
  */
5
5
  import { readFileSync } from 'node:fs'
6
6
 
7
+ import { execSync } from "child_process";
8
+ import { homedir } from "node:os";
9
+ import { join } from "node:path";
10
+ import { existsSync, readdirSync, statSync } from "node:fs";
11
+
7
12
  export interface SkillsListEvent {
8
13
  agentId: string | number
9
14
  userId: string | number
@@ -83,10 +88,8 @@ async function fetchSkillsFromOpenClaw(
83
88
 
84
89
  try {
85
90
  // 使用 OpenClaw CLI 获取 skills 列表(全局技能)
86
- const { execSync } = await import('node:child_process')
87
-
88
- const result = execSync('openclaw skills list', {
89
- encoding: 'utf-8',
91
+ const result = execSync("openclaw skills list", {
92
+ encoding: "utf-8",
90
93
  timeout: 30000, // 30秒超时
91
94
  })
92
95
 
@@ -123,13 +126,10 @@ async function fetchAgentWorkspaceSkills(
123
126
 
124
127
  try {
125
128
  // 智能体工作区路径
126
- const { homedir } = await import('node:os')
127
- const { join } = await import('node:path')
128
- const agentWorkspace = join(homedir(), '.openclaw', 'agents', `openclaw-workclaw-${agentId}`)
129
- const skillsDir = join(agentWorkspace, 'skills')
129
+ const agentWorkspace = join(homedir(), ".openclaw", "agents", `openclaw-workclaw-${agentId}`);
130
+ const skillsDir = join(agentWorkspace, "skills");
130
131
 
131
132
  // 检查技能目录是否存在
132
- const { existsSync, readdirSync, statSync } = await import('node:fs')
133
133
  if (!existsSync(skillsDir)) {
134
134
  log?.info?.(`SkillsList: No skills directory found in agent workspace: ${skillsDir}`)
135
135
  return skills
@@ -4,66 +4,68 @@
4
4
  * 从 OpenClaw 获取 tools 列表并通过 HTTP 回调返回
5
5
  */
6
6
 
7
- import { fetch } from 'undici'
7
+ import { fetch } from "undici";
8
+ import { readFile } from "node:fs/promises";
9
+ import { homedir } from "node:os";
10
+ import path from "node:path";
8
11
 
9
12
  export interface ToolsListEvent {
10
- agentId: string | number
11
- userId: string | number
13
+ agentId: string | number;
14
+ userId: string | number;
12
15
  }
13
16
 
14
17
  export interface ToolItem {
15
- typeStr: string
16
- name: string
17
- description: string
18
+ typeStr: string;
19
+ name: string;
20
+ description: string;
18
21
  }
19
22
 
20
23
  export interface ToolsListCallbackPayload {
21
- userId: number
22
- agentId: number
23
- dataList: ToolItem[]
24
+ userId: number;
25
+ agentId: number;
26
+ dataList: ToolItem[];
24
27
  }
25
28
 
26
29
  /**
27
30
  * 处理 TOOLS_LIST 事件
28
- * @param event - 事件数据
29
- * @param baseUrl - 回调基础 URL
30
- * @param token - 鉴权 token
31
- * @param log - 日志对象(可选)
31
+ * @param event 事件数据
32
+ * @param baseUrl 回调基础 URL
33
+ * @param token 鉴权 token
34
+ * @param log 日志函数
32
35
  */
33
36
  export async function handleToolsListEvent(
34
37
  event: ToolsListEvent,
35
38
  baseUrl: string,
36
39
  token: string,
37
40
  log?: {
38
- info?: (msg: string) => void
39
- error?: (msg: string) => void
41
+ info?: (msg: string) => void;
42
+ error?: (msg: string) => void;
40
43
  },
41
44
  ): Promise<void> {
42
- const agentId = Number(event.agentId)
43
- const userId = Number(event.userId)
45
+ const agentId = Number(event.agentId);
46
+ const userId = Number(event.userId);
44
47
 
45
- log?.info?.(`ToolsList: Handling TOOLS_LIST event for agentId: ${agentId}, userId: ${userId}`)
48
+ log?.info?.(`ToolsList: Handling TOOLS_LIST event for agentId: ${agentId}, userId: ${userId}`);
46
49
 
47
50
  try {
48
51
  // 从 OpenClaw 获取 tools 列表
49
- const tools = await fetchToolsFromOpenClaw(agentId, userId, log)
52
+ const tools = await fetchToolsFromOpenClaw(agentId, userId, log);
50
53
 
51
54
  // 构建回调 payload
52
55
  const callbackPayload: ToolsListCallbackPayload = {
53
56
  userId,
54
57
  agentId,
55
58
  dataList: tools,
56
- }
59
+ };
57
60
 
58
61
  // 发送回调
59
- const callbackUrl = `${baseUrl.replace(/\/$/, '')}/open-apis/v1/claw/push/tools`
60
- await sendToolsListCallback(callbackUrl, callbackPayload, token, log)
62
+ const callbackUrl = `${baseUrl.replace(/\/$/, "")}/open-apis/v1/claw/push/tools`;
63
+ await sendToolsListCallback(callbackUrl, callbackPayload, token, log);
61
64
 
62
- log?.info?.(`ToolsList: Successfully processed TOOLS_LIST event, sent ${tools.length} tools`)
63
- }
64
- catch (error) {
65
- log?.error?.(`ToolsList: Failed to handle TOOLS_LIST event: ${String(error)}`)
66
- throw error
65
+ log?.info?.(`ToolsList: Successfully processed TOOLS_LIST event, sent ${tools.length} tools`);
66
+ } catch (error) {
67
+ log?.error?.(`ToolsList: Failed to handle TOOLS_LIST event: ${String(error)}`);
68
+ throw error;
67
69
  }
68
70
  }
69
71
 
@@ -73,60 +75,56 @@ export async function handleToolsListEvent(
73
75
  */
74
76
  async function fetchToolsFromOpenClaw(
75
77
  agentId: number,
76
- _userId: number,
78
+ userId: number,
77
79
  log?: {
78
- info?: (msg: string) => void
79
- error?: (msg: string) => void
80
+ info?: (msg: string) => void;
81
+ error?: (msg: string) => void;
80
82
  },
81
83
  ): Promise<ToolItem[]> {
82
- log?.info?.(`ToolsList: Fetching tools from OpenClaw for agentId: ${agentId}`)
84
+ log?.info?.(`ToolsList: Fetching tools from OpenClaw for agentId: ${agentId}`);
83
85
 
84
86
  // OpenClaw 所有内置工具列表
85
87
  const allTools: ToolItem[] = [
86
- { typeStr: 'function', name: 'web_search', description: 'Search the web for information using Brave Search API.' },
87
- { typeStr: 'function', name: 'web_fetch', description: 'Fetch and read content from a URL.' },
88
- { typeStr: 'function', name: 'sessions_list', description: 'List all active agent sessions.' },
89
- { typeStr: 'function', name: 'sessions_history', description: 'Get the history of a specific session.' },
90
- { typeStr: 'function', name: 'memory_search', description: 'Search memory for past conversations and information.' },
91
- { typeStr: 'function', name: 'memory_get', description: 'Get specific memory by ID.' },
92
- { typeStr: 'function', name: 'gateway', description: 'Gateway control operations.' },
93
- { typeStr: 'function', name: 'exec', description: 'Execute shell commands.' },
94
- ]
88
+ { typeStr: "function", name: "web_search", description: "Search the web for information using Brave Search API." },
89
+ { typeStr: "function", name: "web_fetch", description: "Fetch and read content from a URL." },
90
+ { typeStr: "function", name: "sessions_list", description: "List all active agent sessions." },
91
+ { typeStr: "function", name: "sessions_history", description: "Get the history of a specific session." },
92
+ { typeStr: "function", name: "memory_search", description: "Search memory for past conversations and information." },
93
+ { typeStr: "function", name: "memory_get", description: "Get specific memory by ID." },
94
+ { typeStr: "function", name: "gateway", description: "Gateway control operations." },
95
+ { typeStr: "function", name: "exec", description: "Execute shell commands." },
96
+ ];
95
97
 
96
98
  try {
97
99
  // 读取 OpenClaw 配置文件
98
- const { readFile } = await import('node:fs/promises')
99
- const { homedir } = await import('node:os')
100
- const path = await import('node:path')
101
-
102
- const configPath = path.join(homedir(), '.openclaw', 'openclaw.json')
103
- const configContent = await readFile(configPath, 'utf-8')
104
- const config = JSON.parse(configContent)
100
+ const configPath = path.join(homedir(), ".openclaw", "openclaw.json");
101
+ const configContent = await readFile(configPath, "utf-8");
102
+ const config = JSON.parse(configContent);
105
103
 
106
104
  // 查找对应的 agent 配置
107
- const agentConfig = config.agents?.list?.find((agent: any) =>
108
- String(agent.id) === String(agentId)
109
- || agent.id === `openclaw-workclaw-${agentId}`,
110
- )
105
+ const agentConfig = config.agents?.list?.find((agent: any) =>
106
+ String(agent.id) === String(agentId) ||
107
+ agent.id === `openclaw-workclaw-${agentId}`
108
+ );
111
109
 
112
110
  // 获取 tools.allow 配置
113
- const allowTools = agentConfig?.tools?.allow
111
+ const allowTools = agentConfig?.tools?.allow;
114
112
 
115
113
  // 如果没有 allow 配置,或者 allow 是 ["*"],返回所有工具
116
- if (!allowTools || allowTools.length === 0 || allowTools.includes('*')) {
117
- log?.info?.(`ToolsList: Agent has no allow restriction or allow=[*], returning all ${allTools.length} tools`)
118
- return allTools
114
+ if (!allowTools || allowTools.length === 0 || allowTools.includes("*")) {
115
+ log?.info?.(`ToolsList: Agent has no allow restriction or allow=[*], returning all ${allTools.length} tools`);
116
+ return allTools;
119
117
  }
120
118
 
121
119
  // 如果有具体的 allow 列表,只返回列表中的工具
122
- const filteredTools = allTools.filter(tool => allowTools.includes(tool.name))
123
- log?.info?.(`ToolsList: Agent allow=${JSON.stringify(allowTools)}, returning ${filteredTools.length} tools`)
124
- return filteredTools
125
- }
126
- catch (error) {
127
- log?.error?.(`ToolsList: Error reading agent config: ${String(error)}, returning all tools`)
120
+ const filteredTools = allTools.filter(tool => allowTools.includes(tool.name));
121
+ log?.info?.(`ToolsList: Agent allow=${JSON.stringify(allowTools)}, returning ${filteredTools.length} tools`);
122
+ return filteredTools;
123
+
124
+ } catch (error) {
125
+ log?.error?.(`ToolsList: Error reading agent config: ${String(error)}, returning all tools`);
128
126
  // 如果读取配置失败,返回所有工具
129
- return allTools
127
+ return allTools;
130
128
  }
131
129
  }
132
130
 
@@ -138,25 +136,25 @@ async function sendToolsListCallback(
138
136
  payload: ToolsListCallbackPayload,
139
137
  token: string,
140
138
  log?: {
141
- info?: (msg: string) => void
142
- error?: (msg: string) => void
139
+ info?: (msg: string) => void;
140
+ error?: (msg: string) => void;
143
141
  },
144
142
  ): Promise<void> {
145
- log?.info?.(`ToolsList: Sending callback to ${callbackUrl}`)
143
+ log?.info?.(`ToolsList: Sending callback to ${callbackUrl}`);
146
144
 
147
145
  const response = await fetch(callbackUrl, {
148
- method: 'POST',
146
+ method: "POST",
149
147
  headers: {
150
- 'Content-Type': 'application/json',
151
- 'Authorization': `Bearer ${token}`,
148
+ "Content-Type": "application/json",
149
+ "Authorization": `Bearer ${token}`,
152
150
  },
153
151
  body: JSON.stringify(payload),
154
- })
152
+ });
155
153
 
156
154
  if (!response.ok) {
157
- const errorText = await response.text()
158
- throw new Error(`Callback failed: ${response.status} ${response.statusText} - ${errorText}`)
155
+ const errorText = await response.text();
156
+ throw new Error(`Callback failed: ${response.status} ${response.statusText} - ${errorText}`);
159
157
  }
160
158
 
161
- log?.info?.(`ToolsList: Callback sent successfully: ${response.status}`)
159
+ log?.info?.(`ToolsList: Callback sent successfully: ${response.status}`);
162
160
  }