@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.
- package/README.md +325 -0
- package/index.ts +298 -0
- package/openclaw.plugin.json +10 -0
- package/package.json +43 -0
- package/skills/openclaw-workclaw-cron/SKILL.md +458 -0
- package/src/accounts.ts +287 -0
- package/src/api/accounts-api.ts +157 -0
- package/src/api/prompts-api.ts +123 -0
- package/src/api/session-api.ts +247 -0
- package/src/api/skills-api.ts +74 -0
- package/src/api/workspace.ts +43 -0
- package/src/channel.ts +227 -0
- package/src/config-schema.ts +110 -0
- package/src/connection/workclaw-client.ts +656 -0
- package/src/gateway/agent-handlers.ts +557 -0
- package/src/gateway/config-writer.ts +311 -0
- package/src/gateway/message-context.ts +422 -0
- package/src/gateway/message-dispatcher.ts +601 -0
- package/src/gateway/reconnect.ts +149 -0
- package/src/gateway/skills-handler.ts +759 -0
- package/src/gateway/skills-list-handler.ts +332 -0
- package/src/gateway/tools-list-handler.ts +162 -0
- package/src/gateway/workclaw-gateway.ts +521 -0
- package/src/media/upload.ts +168 -0
- package/src/outbound/index.ts +183 -0
- package/src/outbound/workclaw-sender.ts +157 -0
- package/src/runtime.ts +400 -0
- package/src/send.ts +1 -0
- package/src/tools/openclaw-workclaw-cron/api/index.ts +326 -0
- package/src/tools/openclaw-workclaw-cron/index.ts +39 -0
- package/src/tools/openclaw-workclaw-cron/src/add/params.ts +176 -0
- package/src/tools/openclaw-workclaw-cron/src/add/sync.ts +188 -0
- package/src/tools/openclaw-workclaw-cron/src/disable/params.ts +100 -0
- package/src/tools/openclaw-workclaw-cron/src/disable/sync.ts +127 -0
- package/src/tools/openclaw-workclaw-cron/src/enable/params.ts +100 -0
- package/src/tools/openclaw-workclaw-cron/src/enable/sync.ts +127 -0
- package/src/tools/openclaw-workclaw-cron/src/notify/sync.ts +148 -0
- package/src/tools/openclaw-workclaw-cron/src/remove/params.ts +109 -0
- package/src/tools/openclaw-workclaw-cron/src/remove/sync.ts +127 -0
- package/src/tools/openclaw-workclaw-cron/src/update/params.ts +197 -0
- package/src/tools/openclaw-workclaw-cron/src/update/sync.ts +161 -0
- package/src/tools/openclaw-workclaw-cron/types/index.ts +55 -0
- package/src/tools/openclaw-workclaw-cron/utils/index.ts +141 -0
- package/src/types.ts +60 -0
- package/src/utils/content.ts +40 -0
- package/templates/IDENTITY.md +14 -0
- package/templates/SOUL.md +0 -0
- 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
|
+
}
|