@workclaw/openclaw-workclaw 1.0.25 → 1.0.27

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 (161) hide show
  1. package/dist/api.d.ts +4 -0
  2. package/dist/api.d.ts.map +1 -0
  3. package/dist/api.js +379 -0
  4. package/dist/channel-DSvR6Irx.js +50017 -0
  5. package/dist/cron-tasks-handler-C-mP3VmV.js +152 -0
  6. package/dist/index.d.ts +12 -0
  7. package/dist/index.d.ts.map +1 -0
  8. package/dist/index.js +2088 -0
  9. package/dist/jiti-4i2h0FGP.js +4814 -0
  10. package/dist/setup-entry.d.ts +3 -0
  11. package/dist/setup-entry.d.ts.map +1 -0
  12. package/dist/setup-entry.js +182 -0
  13. package/dist/src/accounts.d.ts +67 -0
  14. package/dist/src/accounts.d.ts.map +1 -0
  15. package/dist/src/api/accounts-api.d.ts +3 -0
  16. package/dist/src/api/accounts-api.d.ts.map +1 -0
  17. package/dist/src/api/prompts-api.d.ts +3 -0
  18. package/dist/src/api/prompts-api.d.ts.map +1 -0
  19. package/dist/src/api/session-api.d.ts +3 -0
  20. package/dist/src/api/session-api.d.ts.map +1 -0
  21. package/dist/src/api/skills-api.d.ts +3 -0
  22. package/dist/src/api/skills-api.d.ts.map +1 -0
  23. package/dist/src/api/workspace.d.ts +4 -0
  24. package/dist/src/api/workspace.d.ts.map +1 -0
  25. package/dist/src/channel.d.ts +12 -0
  26. package/dist/src/channel.d.ts.map +1 -0
  27. package/dist/src/config-schema.d.ts +88 -0
  28. package/dist/src/config-schema.d.ts.map +1 -0
  29. package/dist/src/connection/workclaw-client.d.ts +149 -0
  30. package/dist/src/connection/workclaw-client.d.ts.map +1 -0
  31. package/dist/src/gateway/agent-handlers.d.ts +13 -0
  32. package/dist/src/gateway/agent-handlers.d.ts.map +1 -0
  33. package/dist/src/gateway/config-writer.d.ts +72 -0
  34. package/dist/src/gateway/config-writer.d.ts.map +1 -0
  35. package/dist/src/gateway/cron-tasks-handler.d.ts +20 -0
  36. package/dist/src/gateway/cron-tasks-handler.d.ts.map +1 -0
  37. package/dist/src/gateway/message-context.d.ts +81 -0
  38. package/dist/src/gateway/message-context.d.ts.map +1 -0
  39. package/dist/src/gateway/message-dispatcher.d.ts +17 -0
  40. package/dist/src/gateway/message-dispatcher.d.ts.map +1 -0
  41. package/dist/src/gateway/reconnect.d.ts +25 -0
  42. package/dist/src/gateway/reconnect.d.ts.map +1 -0
  43. package/dist/src/gateway/skills-handler.d.ts +30 -0
  44. package/dist/src/gateway/skills-handler.d.ts.map +1 -0
  45. package/dist/src/gateway/skills-list-handler.d.ts +28 -0
  46. package/dist/src/gateway/skills-list-handler.d.ts.map +1 -0
  47. package/dist/src/gateway/tools-list-handler.d.ts +31 -0
  48. package/dist/src/gateway/tools-list-handler.d.ts.map +1 -0
  49. package/dist/src/gateway/workclaw-gateway.d.ts +11 -0
  50. package/dist/src/gateway/workclaw-gateway.d.ts.map +1 -0
  51. package/dist/src/media/upload.d.ts +14 -0
  52. package/dist/src/media/upload.d.ts.map +1 -0
  53. package/dist/src/outbound/index.d.ts +39 -0
  54. package/dist/src/outbound/index.d.ts.map +1 -0
  55. package/dist/src/outbound/workclaw-sender.d.ts +38 -0
  56. package/dist/src/outbound/workclaw-sender.d.ts.map +1 -0
  57. package/dist/src/runtime.d.ts +118 -0
  58. package/dist/src/runtime.d.ts.map +1 -0
  59. package/dist/src/secret-contract-api.d.ts +5 -0
  60. package/dist/src/secret-contract-api.d.ts.map +1 -0
  61. package/{src/send.ts → dist/src/send.d.ts} +2 -1
  62. package/dist/src/send.d.ts.map +1 -0
  63. package/dist/src/setup-api.d.ts +4 -0
  64. package/dist/src/setup-api.d.ts.map +1 -0
  65. package/dist/src/setup-core.d.ts +4 -0
  66. package/dist/src/setup-core.d.ts.map +1 -0
  67. package/dist/src/setup-surface.d.ts +8 -0
  68. package/dist/src/setup-surface.d.ts.map +1 -0
  69. package/dist/src/tools/openclaw-workclaw-cron/api/index.d.ts +91 -0
  70. package/dist/src/tools/openclaw-workclaw-cron/api/index.d.ts.map +1 -0
  71. package/dist/src/tools/openclaw-workclaw-cron/index.d.ts +11 -0
  72. package/dist/src/tools/openclaw-workclaw-cron/index.d.ts.map +1 -0
  73. package/dist/src/tools/openclaw-workclaw-cron/src/add/params.d.ts +14 -0
  74. package/dist/src/tools/openclaw-workclaw-cron/src/add/params.d.ts.map +1 -0
  75. package/dist/src/tools/openclaw-workclaw-cron/src/add/sync.d.ts +16 -0
  76. package/dist/src/tools/openclaw-workclaw-cron/src/add/sync.d.ts.map +1 -0
  77. package/dist/src/tools/openclaw-workclaw-cron/src/disable/params.d.ts +12 -0
  78. package/dist/src/tools/openclaw-workclaw-cron/src/disable/params.d.ts.map +1 -0
  79. package/dist/src/tools/openclaw-workclaw-cron/src/disable/sync.d.ts +12 -0
  80. package/dist/src/tools/openclaw-workclaw-cron/src/disable/sync.d.ts.map +1 -0
  81. package/dist/src/tools/openclaw-workclaw-cron/src/enable/params.d.ts +12 -0
  82. package/dist/src/tools/openclaw-workclaw-cron/src/enable/params.d.ts.map +1 -0
  83. package/dist/src/tools/openclaw-workclaw-cron/src/enable/sync.d.ts +12 -0
  84. package/dist/src/tools/openclaw-workclaw-cron/src/enable/sync.d.ts.map +1 -0
  85. package/dist/src/tools/openclaw-workclaw-cron/src/notify/sync.d.ts +13 -0
  86. package/dist/src/tools/openclaw-workclaw-cron/src/notify/sync.d.ts.map +1 -0
  87. package/dist/src/tools/openclaw-workclaw-cron/src/remove/params.d.ts +12 -0
  88. package/dist/src/tools/openclaw-workclaw-cron/src/remove/params.d.ts.map +1 -0
  89. package/dist/src/tools/openclaw-workclaw-cron/src/remove/sync.d.ts +12 -0
  90. package/dist/src/tools/openclaw-workclaw-cron/src/remove/sync.d.ts.map +1 -0
  91. package/dist/src/tools/openclaw-workclaw-cron/src/update/params.d.ts +15 -0
  92. package/dist/src/tools/openclaw-workclaw-cron/src/update/params.d.ts.map +1 -0
  93. package/dist/src/tools/openclaw-workclaw-cron/src/update/sync.d.ts +16 -0
  94. package/dist/src/tools/openclaw-workclaw-cron/src/update/sync.d.ts.map +1 -0
  95. package/dist/src/tools/openclaw-workclaw-cron/types/index.d.ts +53 -0
  96. package/dist/src/tools/openclaw-workclaw-cron/types/index.d.ts.map +1 -0
  97. package/dist/src/tools/openclaw-workclaw-cron/utils/index.d.ts +41 -0
  98. package/dist/src/tools/openclaw-workclaw-cron/utils/index.d.ts.map +1 -0
  99. package/dist/src/tools/openclaw-workclaw-system/index.d.ts +11 -0
  100. package/dist/src/tools/openclaw-workclaw-system/index.d.ts.map +1 -0
  101. package/dist/src/tools/openclaw-workclaw-system/src/get/index.d.ts +6 -0
  102. package/dist/src/tools/openclaw-workclaw-system/src/get/index.d.ts.map +1 -0
  103. package/dist/src/tools/openclaw-workclaw-system/src/token/index.d.ts +6 -0
  104. package/dist/src/tools/openclaw-workclaw-system/src/token/index.d.ts.map +1 -0
  105. package/dist/src/types.d.ts +39 -0
  106. package/dist/src/types.d.ts.map +1 -0
  107. package/dist/src/utils/content.d.ts +16 -0
  108. package/dist/src/utils/content.d.ts.map +1 -0
  109. package/openclaw.plugin.json +11 -0
  110. package/package.json +69 -45
  111. package/api.ts +0 -3
  112. package/index.ts +0 -325
  113. package/setup-entry.ts +0 -13
  114. package/src/accounts.ts +0 -360
  115. package/src/api/accounts-api.ts +0 -156
  116. package/src/api/prompts-api.ts +0 -122
  117. package/src/api/session-api.ts +0 -246
  118. package/src/api/skills-api.ts +0 -74
  119. package/src/api/workspace.ts +0 -45
  120. package/src/channel.ts +0 -226
  121. package/src/config-schema.ts +0 -60
  122. package/src/connection/workclaw-client.ts +0 -618
  123. package/src/gateway/agent-handlers.ts +0 -551
  124. package/src/gateway/config-writer.ts +0 -378
  125. package/src/gateway/cron-tasks-handler.ts +0 -230
  126. package/src/gateway/message-context.ts +0 -645
  127. package/src/gateway/message-dispatcher.ts +0 -688
  128. package/src/gateway/reconnect.ts +0 -260
  129. package/src/gateway/skills-handler.ts +0 -805
  130. package/src/gateway/skills-list-handler.ts +0 -332
  131. package/src/gateway/tools-list-handler.ts +0 -161
  132. package/src/gateway/workclaw-gateway.ts +0 -304
  133. package/src/media/upload.ts +0 -168
  134. package/src/outbound/index.ts +0 -191
  135. package/src/outbound/workclaw-sender.ts +0 -161
  136. package/src/runtime.ts +0 -520
  137. package/src/secret-contract-api.ts +0 -4
  138. package/src/setup-api.ts +0 -3
  139. package/src/setup-core.ts +0 -25
  140. package/src/setup-surface.ts +0 -498
  141. package/src/tools/openclaw-workclaw-cron/api/index.ts +0 -326
  142. package/src/tools/openclaw-workclaw-cron/index.ts +0 -39
  143. package/src/tools/openclaw-workclaw-cron/src/add/params.ts +0 -177
  144. package/src/tools/openclaw-workclaw-cron/src/add/sync.ts +0 -188
  145. package/src/tools/openclaw-workclaw-cron/src/disable/params.ts +0 -100
  146. package/src/tools/openclaw-workclaw-cron/src/disable/sync.ts +0 -127
  147. package/src/tools/openclaw-workclaw-cron/src/enable/params.ts +0 -100
  148. package/src/tools/openclaw-workclaw-cron/src/enable/sync.ts +0 -127
  149. package/src/tools/openclaw-workclaw-cron/src/notify/sync.ts +0 -148
  150. package/src/tools/openclaw-workclaw-cron/src/remove/params.ts +0 -109
  151. package/src/tools/openclaw-workclaw-cron/src/remove/sync.ts +0 -127
  152. package/src/tools/openclaw-workclaw-cron/src/update/params.ts +0 -195
  153. package/src/tools/openclaw-workclaw-cron/src/update/sync.ts +0 -161
  154. package/src/tools/openclaw-workclaw-cron/types/index.ts +0 -55
  155. package/src/tools/openclaw-workclaw-cron/utils/index.ts +0 -141
  156. package/src/tools/openclaw-workclaw-system/index.ts +0 -17
  157. package/src/tools/openclaw-workclaw-system/src/get/index.ts +0 -77
  158. package/src/tools/openclaw-workclaw-system/src/token/index.ts +0 -93
  159. package/src/types.ts +0 -50
  160. package/src/utils/content.ts +0 -40
  161. package/tsconfig.json +0 -34
@@ -1,378 +0,0 @@
1
- /**
2
- * Config Writer - handles writing account config to openclaw.json
3
- *
4
- * NOTE: Only agent creation/initialization writes to openclaw.json via writeConfigFile.
5
- * Runtime dynamic data (openConversationId) is stored in a separate state file
6
- * to avoid triggering openclaw's config watcher, which would re-parse env vars
7
- * and potentially overwrite already-resolved values like ${MODEL_API_KEY}.
8
- */
9
-
10
- import { execSync } from 'node:child_process'
11
- import { existsSync, readFileSync } from 'node:fs'
12
- import { mkdir, readFile, rename, writeFile } from 'node:fs/promises'
13
- import { homedir } from 'node:os'
14
- import { join } from 'node:path'
15
- import { getWorkclawRuntime } from '../runtime.js'
16
-
17
- /** 修复目录所有权(仅非 Windows 环境) */
18
- function fixOwner(dir: string): void {
19
- if (process.platform === 'win32')
20
- return
21
- try { execSync(`chown -R node:node "${dir}"`, { stdio: 'ignore' }) }
22
- catch {}
23
- }
24
-
25
- interface ConfigLogger {
26
- info?: (msg: string) => void
27
- error?: (msg: string) => void
28
- }
29
-
30
- const STATE_DIR = join('workclaw', 'data')
31
-
32
- // 写入节流时间(避免频繁写入)
33
- const SAVE_THROTTLE_MS = 1000
34
-
35
- // 每个账户的上次写入时间,key 格式: accountId:userId
36
- const lastSaveTimeMap = new Map<string, number>()
37
-
38
- /**
39
- * Find the actual openclaw.json config path.
40
- */
41
- function findConfigPath(): string {
42
- // Prefer homedir config over cwd, since cwd might be the project directory
43
- // which could have a stale or unrelated openclaw.json
44
- const configPaths = [
45
- join(homedir(), '.openclaw', 'openclaw.json'),
46
- join(homedir(), '.openclaw', 'config.json'),
47
- join(process.cwd(), 'openclaw.json'),
48
- join(process.cwd(), 'config.json'),
49
- ]
50
-
51
- const found = configPaths.find(p => existsSync(p))
52
- return found ?? join(homedir(), '.openclaw', 'openclaw.json')
53
- }
54
-
55
- /**
56
- * Get the state directory for workclaw runtime data.
57
- * Uses ~/.openclaw as the canonical base, consistent with openclaw's recommended layout.
58
- */
59
- function findStateDir(): string {
60
- const stateDir = join(homedir(), '.openclaw')
61
- return join(stateDir, STATE_DIR)
62
- }
63
-
64
- function getStateFilePath(): string {
65
- return join(findStateDir(), 'conversations.json')
66
- }
67
-
68
- /**
69
- * Write a new config to the openclaw.json file.
70
- */
71
- export async function writeConfigFile(
72
- newConfig: any,
73
- cfg: any,
74
- log?: ConfigLogger,
75
- ): Promise<void> {
76
- try {
77
- const runtime = getWorkclawRuntime()
78
- const configApi = runtime.config as {
79
- writeConfigFile: (cfg: unknown) => Promise<void>
80
- }
81
- await configApi.writeConfigFile(newConfig)
82
- log?.info?.(`[WriteConfig] Config written via runtime.config.writeConfigFile`)
83
- Object.assign(cfg, newConfig)
84
- }
85
- catch (err) {
86
- log?.error?.(`[WriteConfig] Failed to write config: ${String(err)}`)
87
- throw err
88
- }
89
- }
90
-
91
- /**
92
- * Load openConversationId from the separate state file.
93
- *
94
- * Key format: accountId:userId
95
- *
96
- * Called at runtime to restore openConversationId after process restart,
97
- * since cfg is reloaded from openclaw.json which does not contain this value.
98
- */
99
- export function loadOpenConversationId(accountId: string, userId: string): string | null {
100
- const statePath = getStateFilePath()
101
- const key = `${accountId}:${userId}`
102
- try {
103
- if (!existsSync(statePath))
104
- return null
105
- const content = readFileSync(statePath, 'utf-8')
106
- const state = JSON.parse(content) as Record<string, Record<string, string>>
107
- return state[key]?.openConversationId ?? null
108
- }
109
- catch {
110
- return null
111
- }
112
- }
113
-
114
- /**
115
- * Save openConversationId to a separate state file (with write throttling).
116
- *
117
- * Key format: accountId:userId
118
- * Throttling: if called multiple times within 1 second, only the last value is saved.
119
- * This avoids excessive disk writes from high-frequency messages.
120
- *
121
- * Stored in ~/.openclaw/workclaw-state/conversations.json (separate from openclaw.json)
122
- * to avoid triggering openclaw's config watcher which would re-parse env vars.
123
- */
124
- export async function saveOpenConversationId(
125
- accountId: string,
126
- userId: string,
127
- openConversationId: string,
128
- cfg: any,
129
- log?: ConfigLogger,
130
- ): Promise<void> {
131
- const key = `${accountId}:${userId}`
132
-
133
- // Also update cfg memory immediately
134
- const workclawCfg = cfg?.channels?.['openclaw-workclaw']
135
- if (workclawCfg?.accounts?.[accountId]) {
136
- workclawCfg.accounts[accountId].openConversationId = openConversationId
137
- }
138
-
139
- // Throttle: skip if written recently
140
- const lastSaveTime = lastSaveTimeMap.get(key) ?? 0
141
- const now = Date.now()
142
- if (now - lastSaveTime < SAVE_THROTTLE_MS) {
143
- return
144
- }
145
-
146
- // Write immediately — never lose a pending value on crash
147
- await doSaveOpenConversationId(key, openConversationId, log)
148
- lastSaveTimeMap.set(key, now)
149
- }
150
-
151
- async function doSaveOpenConversationId(
152
- key: string,
153
- openConversationId: string,
154
- log?: ConfigLogger,
155
- ): Promise<void> {
156
- try {
157
- const statePath = getStateFilePath()
158
- let state: Record<string, Record<string, string>> = {}
159
-
160
- if (existsSync(statePath)) {
161
- try {
162
- const content = await readFile(statePath, 'utf-8')
163
- state = JSON.parse(content)
164
- }
165
- catch (parseErr) {
166
- log?.error?.(`SaveConversation: Failed to parse state file: ${String(parseErr)}`)
167
- }
168
- }
169
-
170
- if (!state[key])
171
- state[key] = {}
172
- // Skip write only when the value is the same (and not empty/null)
173
- const existing = state[key].openConversationId
174
- if (existing === openConversationId && existing != null && existing !== '') {
175
- return
176
- }
177
- state[key].openConversationId = openConversationId
178
-
179
- // Ensure state dir exists
180
- const stateDir = findStateDir()
181
- if (!existsSync(stateDir)) {
182
- try {
183
- await mkdir(stateDir, { recursive: true, mode: 0o755 })
184
- }
185
- catch (mkdirErr: any) {
186
- if (mkdirErr.code === 'EACCES' || mkdirErr.code === 'EPERM') {
187
- // Docker/non-root: retry with loose permissions
188
- await mkdir(stateDir, { recursive: true, mode: 0o777 })
189
- }
190
- else {
191
- throw mkdirErr
192
- }
193
- }
194
- // 修复权限(目录可能已存在但权限不对)
195
- fixOwner(stateDir)
196
- }
197
-
198
- // Atomic write: write to tmp file then rename
199
- const tmpPath = `${statePath}.tmp`
200
- await writeFile(tmpPath, JSON.stringify(state, null, 2), 'utf-8')
201
- await rename(tmpPath, statePath)
202
- log?.info?.(`SaveConversation: Saved openConversationId for key ${key}`)
203
- }
204
- catch (err) {
205
- log?.error?.(`SaveConversation: Failed to write state file: ${String(err)}`)
206
- }
207
- }
208
-
209
- /**
210
- * Initialize workclaw agent config in one shot (hardware device init).
211
- *
212
- * Sets apiKey, agentId, userId and persists to openclaw.json in a single write.
213
- *
214
- * NOTE: If apiKey already contains a SecretRef (type: "env"|"file"|"exec"),
215
- * it is preserved and NOT overwritten, since OpenClaw handles SecretRef resolution.
216
- */
217
- export async function initWorkclawAgent(
218
- params: {
219
- apiKey?: string
220
- agentId?: string
221
- userId?: string
222
- accountId?: string
223
- },
224
- cfg: any,
225
- log?: ConfigLogger,
226
- ): Promise<void> {
227
- try {
228
- const workclawCfg = cfg?.channels?.['openclaw-workclaw']
229
- if (!workclawCfg)
230
- return
231
-
232
- if (params.apiKey) {
233
- // Check if existing value is a SecretRef object - if so, skip to preserve it
234
- const existingApiKey = cfg.models?.providers?.['sophnet-minimax']?.apiKey
235
- if (existingApiKey && typeof existingApiKey === 'object' && existingApiKey.type) {
236
- log?.info?.(`initWorkclawAgent: apiKey is SecretRef (type=${existingApiKey.type}), skipping overwrite`)
237
- }
238
- else {
239
- if (!cfg.models)
240
- cfg.models = {}
241
- if (!cfg.models.providers)
242
- cfg.models.providers = {}
243
- if (!cfg.models.providers['sophnet-minimax'])
244
- cfg.models.providers['sophnet-minimax'] = {}
245
- cfg.models.providers['sophnet-minimax'].apiKey = params.apiKey
246
- log?.info?.(`initWorkclawAgent: apiKey set (plain value)`)
247
- }
248
- }
249
-
250
- if (params.agentId) {
251
- const accountId = params.accountId || 'default'
252
- const accounts = workclawCfg.accounts ?? {}
253
- workclawCfg.accounts = accounts
254
- if (!accounts[accountId])
255
- accounts[accountId] = {}
256
- accounts[accountId].agentId = params.agentId
257
- log?.info?.(`initWorkclawAgent: agentId=${params.agentId} set for ${accountId}`)
258
- }
259
-
260
- if (params.userId) {
261
- workclawCfg.userId = params.userId
262
- log?.info?.(`initWorkclawAgent: userId=${params.userId} set`)
263
- }
264
-
265
- // Single write to persist all
266
- await writeConfigFile(cfg, cfg, log)
267
- log?.info?.(`initWorkclawAgent: all config persisted`)
268
- }
269
- catch (err) {
270
- log?.error?.(`initWorkclawAgent: failed: ${String(err)}`)
271
- throw err
272
- }
273
- }
274
-
275
- /**
276
- * Save userId to cfg memory and persist to openclaw.json.
277
- *
278
- * Used during hardware device initialization to persist the default userId.
279
- */
280
- export async function saveWorkClawUserId(
281
- accountId: string,
282
- userId: string | number,
283
- cfg: any,
284
- log?: ConfigLogger,
285
- ): Promise<void> {
286
- try {
287
- const workclawCfg = cfg?.channels?.['openclaw-workclaw']
288
- if (!workclawCfg)
289
- return
290
- workclawCfg.userId = userId
291
- log?.info?.(`SaveUserId: Saved userId ${userId} for account ${accountId}`)
292
-
293
- // Persist to openclaw.json via framework API
294
- await writeConfigFile(cfg, cfg, log)
295
- }
296
- catch (err) {
297
- log?.error?.(`SaveUserId: Failed to update cfg: ${String(err)}`)
298
- throw err
299
- }
300
- }
301
-
302
- /**
303
- * Save agentId to cfg memory and persist to openclaw.json.
304
- *
305
- * Used during hardware device initialization to persist the default agentId.
306
- */
307
- export async function saveWorkClawAgentId(
308
- accountId: string,
309
- agentId: string | number,
310
- cfg: any,
311
- log?: ConfigLogger,
312
- ): Promise<void> {
313
- try {
314
- const workclawCfg = cfg?.channels?.['openclaw-workclaw']
315
- if (!workclawCfg)
316
- return
317
-
318
- const accounts = workclawCfg.accounts
319
- let savedToAccount: string | null = null
320
-
321
- if (accounts?.[accountId]) {
322
- accounts[accountId].agentId = agentId
323
- savedToAccount = accountId
324
- }
325
- else if (accounts?.default) {
326
- if (!accounts.default.agentId) {
327
- accounts.default.agentId = agentId
328
- savedToAccount = 'default'
329
- log?.info?.(`SaveAgentId: Saved agentId ${agentId} to default account`)
330
- }
331
- }
332
- else {
333
- log?.info?.(`SaveAgentId: Account ${accountId} not found, default account also missing`)
334
- }
335
-
336
- if (savedToAccount) {
337
- log?.info?.(`SaveAgentId: Saved agentId ${agentId} for account ${savedToAccount}`)
338
- }
339
-
340
- // Persist to openclaw.json via framework API
341
- await writeConfigFile(cfg, cfg, log)
342
- }
343
- catch (err) {
344
- log?.error?.(`SaveAgentId: Failed to update cfg: ${String(err)}`)
345
- throw err
346
- }
347
- }
348
-
349
- /**
350
- * Save apiKey to cfg memory only.
351
- *
352
- * Does NOT write to openclaw.json to avoid triggering openclaw's config watcher,
353
- * which would re-parse env vars (e.g. ${MODEL_API_KEY}) and potentially
354
- * overwrite resolved values in the runtime cfg.
355
- */
356
- export async function saveWorkClawApiKey(
357
- apiKey: string,
358
- cfg: any,
359
- log?: ConfigLogger,
360
- ): Promise<void> {
361
- try {
362
- if (!cfg.models)
363
- cfg.models = {}
364
- if (!cfg.models.providers)
365
- cfg.models.providers = {}
366
- if (!cfg.models.providers['sophnet-minimax'])
367
- cfg.models.providers['sophnet-minimax'] = {}
368
- cfg.models.providers['sophnet-minimax'].apiKey = apiKey
369
- log?.info?.(`SaveApiKey: Saved apiKey to cfg`)
370
-
371
- // Persist to openclaw.json via framework API
372
- await writeConfigFile(cfg, cfg, log)
373
- }
374
- catch (err) {
375
- log?.error?.(`SaveApiKey: Failed to update cfg: ${String(err)}`)
376
- throw err
377
- }
378
- }
@@ -1,230 +0,0 @@
1
- import { exec } from 'node:child_process'
2
- import { promisify } from 'node:util'
3
-
4
- const execAsync = promisify(exec)
5
-
6
- // --- 类型定义 ---
7
- export interface ParsedTaskData {
8
- clawJobId?: string | null
9
- agentIds: string[]
10
- dotype: 'add' | 'remove' | 'edit' | 'search'
11
- name: string
12
- expr: string
13
- mainId: string
14
- userId: string
15
- }
16
-
17
- interface Logger {
18
- info?: (msg: string) => void
19
- warn?: (msg: string) => void
20
- error?: (msg: string) => void
21
- }
22
-
23
- // --- 核心公共工具函数 ---
24
-
25
- /**
26
- * 1. 统一命令执行器
27
- * @param ignoreError 如果为 true,即便命令执行失败也不会抛出异常(用于 disable/enable 等非关键步骤)
28
- */
29
- async function runCli(command: string, log?: Logger, ignoreError = false): Promise<{ stdout: string, success: boolean }> {
30
- log?.info?.(`[CLI] Executing: ${command}`)
31
- try {
32
- const { stdout, stderr } = await execAsync(command, {
33
- timeout: 60000,
34
- maxBuffer: 10 * 1024 * 1024,
35
- })
36
- if (stderr)
37
- log?.info?.(`[CLI] stderr: ${stderr}`)
38
- return { stdout: stdout.trim(), success: true }
39
- }
40
- catch (error: any) {
41
- const errorMsg = error?.stderr || error?.message || 'unknown error'
42
- log?.error?.(`[CLI] Command failed: ${command} -> ${errorMsg}`)
43
- if (ignoreError)
44
- return { stdout: errorMsg, success: false }
45
- throw new Error(errorMsg)
46
- }
47
- }
48
-
49
- /**
50
- * 2. 统一回调发送器
51
- * 封装了复杂的后端数据结构,减少各处的重复代码
52
- */
53
- async function sendTaskResult(
54
- url: string,
55
- token: string,
56
- taskData: ParsedTaskData,
57
- status: { success: boolean, message: string, dataListOverride?: any[] },
58
- log?: Logger,
59
- ) {
60
- const { agentIds, dotype, userId, mainId, clawJobId, name, expr } = taskData
61
-
62
- const payload = {
63
- appKey: '',
64
- userId,
65
- agentId: mainId,
66
- agentIds,
67
- dotype,
68
- doStatus: status.success,
69
- doErrorMsg: status.success ? '' : status.message,
70
- dataList: status.dataListOverride || [{
71
- messageId: 0,
72
- clawJobId,
73
- name,
74
- kind: '',
75
- expr,
76
- message: status.success ? status.message : '',
77
- agentId: mainId,
78
- nextRunAtMs: 0,
79
- }],
80
- }
81
-
82
- try {
83
- log?.info?.(`[Callback] Sending status to ${url}`)
84
- const response = await fetch(url, {
85
- method: 'POST',
86
- headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}` },
87
- body: JSON.stringify(payload),
88
- })
89
- if (!response.ok)
90
- log?.error?.(`[Callback] Http error: ${response.status}`)
91
- }
92
- catch (err) {
93
- log?.error?.(`[Callback] Network error: ${String(err)}`)
94
- }
95
- }
96
-
97
- /**
98
- * 3. 参数安全拼接工具
99
- */
100
- const buildCmd = (args: string[]) => args.map(a => (a && a.includes(' ') ? `"${a}"` : a)).join(' ')
101
-
102
- // --- 业务处理器 ---
103
-
104
- /**
105
- * 创建任务
106
- */
107
- async function handleTaskCreate(taskData: ParsedTaskData, token: string, url: string, log?: Logger) {
108
- try {
109
- const cmd = buildCmd(['openclaw', 'cron', 'add', '--name', taskData.name, '--cron', taskData.expr, '--command', 'echo "Task executed"'])
110
- const { stdout } = await runCli(cmd, log)
111
- await sendTaskResult(url, token, taskData, { success: true, message: '创建成功' }, log)
112
- }
113
- catch (e: any) {
114
- await sendTaskResult(url, token, taskData, { success: false, message: `创建失败: ${e.message}` }, log)
115
- throw e
116
- }
117
- }
118
-
119
- /**
120
- * 修改任务 (禁用 -> 修改 -> 启用)
121
- */
122
- async function handleTaskUpdate(taskData: ParsedTaskData, token: string, url: string, log?: Logger) {
123
- const taskId = taskData.clawJobId
124
- if (!taskId)
125
- throw new Error('clawJobId为空无法修改')
126
-
127
- try {
128
- // 1. 尝试禁用 (忽略失败)
129
- await runCli(`openclaw cron disable ${taskId}`, log, true)
130
- await new Promise(r => setTimeout(r, 500))
131
-
132
- // 2. 执行更新 (核心逻辑)
133
- const args = ['openclaw', 'cron', 'edit', taskId]
134
- if (taskData.name)
135
- args.push('--name', taskData.name)
136
- if (taskData.expr)
137
- args.push('--cron', taskData.expr)
138
- await runCli(buildCmd(args), log)
139
-
140
- // 3. 尝试启用 (忽略失败)
141
- await runCli(`openclaw cron enable ${taskId}`, log, true)
142
-
143
- await sendTaskResult(url, token, taskData, { success: true, message: '更新成功' }, log)
144
- }
145
- catch (e: any) {
146
- await sendTaskResult(url, token, taskData, { success: false, message: `更新失败: ${e.message}` }, log)
147
- throw e
148
- }
149
- }
150
-
151
- /**
152
- * 删除任务
153
- */
154
- async function handleTaskDelete(taskData: ParsedTaskData, token: string, url: string, log?: Logger) {
155
- const taskId = taskData.clawJobId
156
- if (!taskId)
157
- throw new Error('clawJobId为空无法删除')
158
-
159
- try {
160
- await runCli(`openclaw cron disable ${taskId}`, log, true)
161
- await runCli(`openclaw cron rm ${taskId}`, log)
162
- await sendTaskResult(url, token, taskData, { success: true, message: '删除成功' }, log)
163
- }
164
- catch (e: any) {
165
- // 特殊处理:如果本身就不存在,也视为成功
166
- const msg = e.message
167
- const isAlreadyGone = msg.includes('not found') || msg.includes('gateway timeout')
168
- await sendTaskResult(url, token, taskData, {
169
- success: isAlreadyGone,
170
- message: isAlreadyGone ? '任务已不存在' : `删除失败: ${msg}`,
171
- }, log)
172
- }
173
- }
174
-
175
- /**
176
- * 查询任务 (增加了回调处理)
177
- */
178
- async function handleTaskSearch(taskData: ParsedTaskData, token: string, url: string, log?: Logger) {
179
- try {
180
- const { stdout } = await runCli('openclaw cron list', log)
181
- let tasks = []
182
- try { tasks = JSON.parse(stdout) }
183
- catch { /* 容错非JSON输出 */ }
184
-
185
- // 处理 search 回调:将查询到的列表放入 dataList
186
- const dataList = Array.isArray(tasks)
187
- ? tasks.map(t => ({
188
- clawJobId: t.id || t.clawJobId,
189
- name: t.name,
190
- expr: t.cron || t.expr,
191
- agentId: t.agentId || taskData.mainId,
192
- }))
193
- : []
194
-
195
- await sendTaskResult(url, token, taskData, {
196
- success: true,
197
- message: '查询成功',
198
- dataListOverride: dataList,
199
- }, log)
200
-
201
- return tasks
202
- }
203
- catch (e: any) {
204
- await sendTaskResult(url, token, taskData, { success: false, message: `查询失败: ${e.message}` }, log)
205
- throw e
206
- }
207
- }
208
-
209
- // --- 主入口 ---
210
- export async function handleCronTaskEvent(
211
- backendEvent: { dotype: string, data: any },
212
- token: string,
213
- baseUrl: string,
214
- appKey: string,
215
- log?: Logger,
216
- ): Promise<void> {
217
- const taskData: ParsedTaskData = backendEvent.data
218
- const callbackUrl = `${baseUrl}/open-apis/v1/claw/do/cron/result`
219
-
220
- log?.info?.(`[Event] Processing ${taskData.dotype}`)
221
-
222
- switch (taskData.dotype) {
223
- case 'add': await handleTaskCreate(taskData, token, callbackUrl, log); break
224
- case 'remove': await handleTaskDelete(taskData, token, callbackUrl, log); break
225
- case 'edit': await handleTaskUpdate(taskData, token, callbackUrl, log); break
226
- case 'search': await handleTaskSearch(taskData, token, callbackUrl, log); break
227
- default:
228
- log?.warn?.(`Unknown dotype: ${taskData.dotype}`)
229
- }
230
- }