@workclaw/openclaw-workclaw 1.0.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.
Files changed (48) hide show
  1. package/README.md +325 -0
  2. package/index.ts +298 -0
  3. package/openclaw.plugin.json +10 -0
  4. package/package.json +43 -0
  5. package/skills/openclaw-workclaw-cron/SKILL.md +458 -0
  6. package/src/accounts.ts +287 -0
  7. package/src/api/accounts-api.ts +157 -0
  8. package/src/api/prompts-api.ts +123 -0
  9. package/src/api/session-api.ts +247 -0
  10. package/src/api/skills-api.ts +74 -0
  11. package/src/api/workspace.ts +43 -0
  12. package/src/channel.ts +227 -0
  13. package/src/config-schema.ts +110 -0
  14. package/src/connection/workclaw-client.ts +656 -0
  15. package/src/gateway/agent-handlers.ts +557 -0
  16. package/src/gateway/config-writer.ts +311 -0
  17. package/src/gateway/message-context.ts +422 -0
  18. package/src/gateway/message-dispatcher.ts +601 -0
  19. package/src/gateway/reconnect.ts +149 -0
  20. package/src/gateway/skills-handler.ts +759 -0
  21. package/src/gateway/skills-list-handler.ts +332 -0
  22. package/src/gateway/tools-list-handler.ts +162 -0
  23. package/src/gateway/workclaw-gateway.ts +521 -0
  24. package/src/media/upload.ts +168 -0
  25. package/src/outbound/index.ts +183 -0
  26. package/src/outbound/workclaw-sender.ts +157 -0
  27. package/src/runtime.ts +400 -0
  28. package/src/send.ts +1 -0
  29. package/src/tools/openclaw-workclaw-cron/api/index.ts +326 -0
  30. package/src/tools/openclaw-workclaw-cron/index.ts +39 -0
  31. package/src/tools/openclaw-workclaw-cron/src/add/params.ts +176 -0
  32. package/src/tools/openclaw-workclaw-cron/src/add/sync.ts +188 -0
  33. package/src/tools/openclaw-workclaw-cron/src/disable/params.ts +100 -0
  34. package/src/tools/openclaw-workclaw-cron/src/disable/sync.ts +127 -0
  35. package/src/tools/openclaw-workclaw-cron/src/enable/params.ts +100 -0
  36. package/src/tools/openclaw-workclaw-cron/src/enable/sync.ts +127 -0
  37. package/src/tools/openclaw-workclaw-cron/src/notify/sync.ts +148 -0
  38. package/src/tools/openclaw-workclaw-cron/src/remove/params.ts +109 -0
  39. package/src/tools/openclaw-workclaw-cron/src/remove/sync.ts +127 -0
  40. package/src/tools/openclaw-workclaw-cron/src/update/params.ts +197 -0
  41. package/src/tools/openclaw-workclaw-cron/src/update/sync.ts +161 -0
  42. package/src/tools/openclaw-workclaw-cron/types/index.ts +55 -0
  43. package/src/tools/openclaw-workclaw-cron/utils/index.ts +141 -0
  44. package/src/types.ts +60 -0
  45. package/src/utils/content.ts +40 -0
  46. package/templates/IDENTITY.md +14 -0
  47. package/templates/SOUL.md +0 -0
  48. package/tsconfig.json +11 -0
@@ -0,0 +1,311 @@
1
+ /**
2
+ * Config Writer - handles writing account config to openclaw.json
3
+ */
4
+
5
+ import { existsSync } from 'node:fs'
6
+ import { readFile, writeFile } from 'node:fs/promises'
7
+ import { homedir } from 'node:os'
8
+ import { join } from 'node:path'
9
+ import process from 'node:process'
10
+
11
+ interface ConfigLogger {
12
+ info?: (msg: string) => void
13
+ error?: (msg: string) => void
14
+ }
15
+
16
+ /**
17
+ * Find the actual openclaw.json config path.
18
+ */
19
+ function findConfigPath(): string {
20
+ // Prefer homedir config over cwd, since cwd might be the project directory
21
+ // which could have a stale or unrelated openclaw.json
22
+ const configPaths = [
23
+ join(homedir(), '.openclaw', 'openclaw.json'),
24
+ join(homedir(), '.openclaw', 'config.json'),
25
+ join(process.cwd(), 'openclaw.json'),
26
+ join(process.cwd(), 'config.json'),
27
+ ]
28
+
29
+ const found = configPaths.find(p => existsSync(p))
30
+ return found ?? join(homedir(), '.openclaw', 'openclaw.json')
31
+ }
32
+
33
+ /**
34
+ * Write a new config to the openclaw.json file.
35
+ */
36
+ export async function writeConfigFile(
37
+ newConfig: any,
38
+ cfg: any,
39
+ log?: ConfigLogger,
40
+ ): Promise<void> {
41
+ const configPath = findConfigPath()
42
+
43
+ try {
44
+ let existingConfig: any = {}
45
+ if (existsSync(configPath)) {
46
+ try {
47
+ const content = await readFile(configPath, 'utf-8')
48
+ existingConfig = JSON.parse(content)
49
+ }
50
+ catch (parseErr) {
51
+ log?.error?.(`[WriteConfig] Failed to parse existing config: ${String(parseErr)}`)
52
+ }
53
+ }
54
+
55
+ const mergedConfig = { ...existingConfig, ...newConfig }
56
+ await writeFile(configPath, JSON.stringify(mergedConfig, null, 2), 'utf-8')
57
+ log?.info?.(`[WriteConfig] Config written to ${configPath}`)
58
+ Object.assign(cfg, newConfig)
59
+ }
60
+ catch (err) {
61
+ log?.error?.(`[WriteConfig] Failed to write config: ${String(err)}`)
62
+ Object.assign(cfg, newConfig)
63
+ throw err
64
+ }
65
+ }
66
+
67
+ /**
68
+ * Save openConversationId to account config.
69
+ */
70
+ export async function saveOpenConversationId(
71
+ accountId: string,
72
+ openConversationId: string,
73
+ cfg: any,
74
+ log?: ConfigLogger,
75
+ ): Promise<void> {
76
+ try {
77
+ const configPath = findConfigPath()
78
+ let existingConfig: any = {}
79
+ if (existsSync(configPath)) {
80
+ try {
81
+ const content = await readFile(configPath, 'utf-8')
82
+ existingConfig = JSON.parse(content)
83
+ }
84
+ catch (parseErr) {
85
+ log?.error?.(`SaveConversation: Failed to parse existing config: ${String(parseErr)}`)
86
+ }
87
+ }
88
+
89
+ const channels = existingConfig?.channels && typeof existingConfig.channels === 'object' ? existingConfig.channels : {}
90
+ const openclawWorkclaw
91
+ = channels['openclaw-workclaw'] && typeof channels['openclaw-workclaw'] === 'object' ? channels['openclaw-workclaw'] : {}
92
+ const accounts
93
+ = openclawWorkclaw.accounts && typeof openclawWorkclaw.accounts === 'object' ? { ...openclawWorkclaw.accounts } : {}
94
+
95
+ let savedToAccount: string | null = null
96
+
97
+ if (accounts[accountId]) {
98
+ accounts[accountId] = {
99
+ ...accounts[accountId],
100
+ openConversationId,
101
+ }
102
+ savedToAccount = accountId
103
+ }
104
+ else {
105
+ const defaultAccount = accounts.default
106
+ if (defaultAccount) {
107
+ defaultAccount.openConversationId = openConversationId
108
+ savedToAccount = 'default'
109
+ log?.info?.(`SaveConversation: Saved openConversationId ${openConversationId} to default account`)
110
+ }
111
+ else {
112
+ log?.info?.(`SaveConversation: Account ${accountId} not found, default account also missing`)
113
+ }
114
+ }
115
+
116
+ if (!savedToAccount) {
117
+ return
118
+ }
119
+
120
+ const mergedConfig = {
121
+ ...existingConfig,
122
+ channels: {
123
+ ...channels,
124
+ 'openclaw-workclaw': {
125
+ ...openclawWorkclaw,
126
+ accounts,
127
+ },
128
+ },
129
+ }
130
+
131
+ await writeFile(configPath, JSON.stringify(mergedConfig, null, 2), 'utf-8')
132
+ log?.info?.(`SaveConversation: Saved openConversationId to ${configPath} for account ${savedToAccount}`)
133
+ Object.assign(cfg, mergedConfig)
134
+ }
135
+ catch (err) {
136
+ log?.error?.(`SaveConversation: Failed to write config: ${String(err)}`)
137
+ throw err
138
+ }
139
+ }
140
+
141
+ /**
142
+ * Save userId to openclawWorkclaw config.
143
+ */
144
+ export async function saveWorkClawUserId(
145
+ accountId: string,
146
+ userId: string | number,
147
+ cfg: any,
148
+ log?: ConfigLogger,
149
+ ): Promise<void> {
150
+ try {
151
+ const configPath = findConfigPath()
152
+ let existingConfig: any = {}
153
+ if (existsSync(configPath)) {
154
+ try {
155
+ const content = await readFile(configPath, 'utf-8')
156
+ existingConfig = JSON.parse(content)
157
+ }
158
+ catch (parseErr) {
159
+ log?.error?.(`SaveUserId: Failed to parse existing config: ${String(parseErr)}`)
160
+ }
161
+ }
162
+
163
+ const channels = existingConfig?.channels && typeof existingConfig.channels === 'object' ? existingConfig.channels : {}
164
+ const openclawWorkclaw
165
+ = channels['openclaw-workclaw'] && typeof channels['openclaw-workclaw'] === 'object' ? channels['openclaw-workclaw'] : {}
166
+
167
+ const mergedConfig = {
168
+ ...existingConfig,
169
+ channels: {
170
+ ...channels,
171
+ 'openclaw-workclaw': {
172
+ ...openclawWorkclaw,
173
+ userId,
174
+ },
175
+ },
176
+ }
177
+
178
+ await writeFile(configPath, JSON.stringify(mergedConfig, null, 2), 'utf-8')
179
+ log?.info?.(`SaveUserId: Saved userId ${userId} to ${configPath} for account ${accountId}`)
180
+ Object.assign(cfg, mergedConfig)
181
+ }
182
+ catch (err) {
183
+ log?.error?.(`SaveUserId: Failed to write config: ${String(err)}`)
184
+ throw err
185
+ }
186
+ }
187
+
188
+ /**
189
+ * Save agentId to account config.
190
+ */
191
+ export async function saveWorkClawAgentId(
192
+ accountId: string,
193
+ agentId: string | number,
194
+ cfg: any,
195
+ log?: ConfigLogger,
196
+ ): Promise<void> {
197
+ try {
198
+ const configPath = findConfigPath()
199
+ let existingConfig: any = {}
200
+ if (existsSync(configPath)) {
201
+ try {
202
+ const content = await readFile(configPath, 'utf-8')
203
+ existingConfig = JSON.parse(content)
204
+ }
205
+ catch (parseErr) {
206
+ log?.error?.(`SaveAgentId: Failed to parse existing config: ${String(parseErr)}`)
207
+ }
208
+ }
209
+
210
+ const channels = existingConfig?.channels && typeof existingConfig.channels === 'object' ? existingConfig.channels : {}
211
+ const openclawWorkclaw
212
+ = channels['openclaw-workclaw'] && typeof channels['openclaw-workclaw'] === 'object' ? channels['openclaw-workclaw'] : {}
213
+ const accounts
214
+ = openclawWorkclaw.accounts && typeof openclawWorkclaw.accounts === 'object' ? { ...openclawWorkclaw.accounts } : {}
215
+
216
+ let savedToAccount: string | null = null
217
+
218
+ if (accounts[accountId]) {
219
+ accounts[accountId] = {
220
+ ...accounts[accountId],
221
+ agentId,
222
+ }
223
+ savedToAccount = accountId
224
+ }
225
+ else {
226
+ const defaultAccount = accounts.default
227
+ if (defaultAccount) {
228
+ if (!defaultAccount.agentId) {
229
+ defaultAccount.agentId = agentId
230
+ savedToAccount = 'default'
231
+ log?.info?.(`SaveAgentId: Saved agentId ${agentId} to default account`)
232
+ }
233
+ }
234
+ else {
235
+ log?.info?.(`SaveAgentId: Account ${accountId} not found, default account also missing`)
236
+ }
237
+ }
238
+
239
+ if (!savedToAccount) {
240
+ return
241
+ }
242
+
243
+ const mergedConfig = {
244
+ ...existingConfig,
245
+ channels: {
246
+ ...channels,
247
+ 'openclaw-workclaw': {
248
+ ...openclawWorkclaw,
249
+ accounts,
250
+ },
251
+ },
252
+ }
253
+
254
+ await writeFile(configPath, JSON.stringify(mergedConfig, null, 2), 'utf-8')
255
+ log?.info?.(`SaveAgentId: Saved agentId ${agentId} to ${configPath} for account ${savedToAccount}`)
256
+ Object.assign(cfg, mergedConfig)
257
+ }
258
+ catch (err) {
259
+ log?.error?.(`SaveAgentId: Failed to write config: ${String(err)}`)
260
+ throw err
261
+ }
262
+ }
263
+
264
+ /**
265
+ * Save apiKey to models configuration
266
+ */
267
+ export async function saveWorkClawApiKey(
268
+ apiKey: string,
269
+ cfg: any,
270
+ log?: ConfigLogger,
271
+ ): Promise<void> {
272
+ try {
273
+ const configPath = findConfigPath()
274
+ let existingConfig: any = {}
275
+ if (existsSync(configPath)) {
276
+ try {
277
+ const content = await readFile(configPath, 'utf-8')
278
+ existingConfig = JSON.parse(content)
279
+ }
280
+ catch (parseErr) {
281
+ log?.error?.(`SaveApiKey: Failed to parse existing config: ${String(parseErr)}`)
282
+ }
283
+ }
284
+
285
+ const existingModels = existingConfig.models || {}
286
+ const existingProviders = existingModels.providers || {}
287
+ const existingSophnetMinimax = existingProviders['sophnet-minimax'] || {}
288
+
289
+ const mergedConfig = {
290
+ ...existingConfig,
291
+ models: {
292
+ ...existingModels,
293
+ providers: {
294
+ ...existingProviders,
295
+ 'sophnet-minimax': {
296
+ ...existingSophnetMinimax,
297
+ apiKey,
298
+ },
299
+ },
300
+ },
301
+ }
302
+
303
+ await writeFile(configPath, JSON.stringify(mergedConfig, null, 2), 'utf-8')
304
+ log?.info?.(`SaveApiKey: Saved apiKey to ${configPath}`)
305
+ Object.assign(cfg, mergedConfig)
306
+ }
307
+ catch (err) {
308
+ log?.error?.(`SaveApiKey: Failed to write config: ${String(err)}`)
309
+ throw err
310
+ }
311
+ }