rol-websocket-channel 1.4.2 → 1.4.8
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/{MQTT-API /346/226/260/345/242/236/346/226/207/344/273/266/345/212/237/350/203/275.md" → MQTT-API 5-6.md } +89 -1
- package/dist/index.js +617 -617
- package/dist/message-handler.js +515 -503
- package/dist/src/admin/cli.js +43 -43
- package/dist/src/admin/jsonrpc.js +60 -60
- package/dist/src/admin/lib/fs.js +30 -30
- package/dist/src/admin/lib/paths.js +80 -80
- package/dist/src/admin/methods/admin.js +60 -60
- package/dist/src/admin/methods/agents-extended.js +251 -251
- package/dist/src/admin/methods/artifacts.js +736 -642
- package/dist/src/admin/methods/artifacts.test.js +210 -191
- package/dist/src/admin/methods/cron.js +250 -250
- package/dist/src/admin/methods/index.js +104 -102
- package/dist/src/admin/methods/mem9.js +309 -270
- package/dist/src/admin/methods/mem9.test.js +34 -0
- package/dist/src/admin/methods/memory.js +363 -363
- package/dist/src/admin/methods/models-extended.js +190 -190
- package/dist/src/admin/methods/models.js +195 -195
- package/dist/src/admin/methods/pairing.js +268 -268
- package/dist/src/admin/methods/sessions-extended.js +215 -215
- package/dist/src/admin/methods/sessions.js +75 -75
- package/dist/src/admin/methods/skills-extended.js +157 -157
- package/dist/src/admin/methods/skills-toggle.js +183 -183
- package/dist/src/admin/methods/skills.js +528 -528
- package/dist/src/admin/methods/system.js +271 -180
- package/dist/src/admin/methods/usage.js +1170 -1170
- package/dist/src/admin/types.js +1 -1
- package/dist/src/mqtt/connection-manager.js +209 -209
- package/dist/src/mqtt/index.js +5 -5
- package/dist/src/mqtt/mqtt-client.js +110 -110
- package/dist/src/mqtt/mqtt.test.js +418 -418
- package/dist/src/mqtt/types.js +2 -2
- package/dist/src/shared/context.js +24 -24
- package/dist/src/shared/wrapper.js +23 -23
- package/message-handler.ts +15 -1
- package/openclaw.plugin.json +73 -0
- package/package.json +1 -1
- package/src/admin/methods/artifacts.test.ts +35 -0
- package/src/admin/methods/artifacts.ts +140 -2
- package/src/admin/methods/index.ts +3 -1
- package/src/admin/methods/mem9.test.ts +39 -0
- package/src/admin/methods/mem9.ts +48 -1
- package/src/admin/methods/system.ts +129 -1
|
@@ -1,250 +1,250 @@
|
|
|
1
|
-
import { execFile } from 'node:child_process';
|
|
2
|
-
import { promisify } from 'node:util';
|
|
3
|
-
import { JsonRpcException, JSON_RPC_ERRORS } from '../jsonrpc.js';
|
|
4
|
-
const execFileAsync = promisify(execFile);
|
|
5
|
-
export const listCron = async (_params, context) => {
|
|
6
|
-
return await runOpenClawCronCommand(['cron', 'list'], context);
|
|
7
|
-
};
|
|
8
|
-
export const getCronStatus = async (_params, context) => {
|
|
9
|
-
return await runOpenClawCronCommand(['cron', 'status'], context);
|
|
10
|
-
};
|
|
11
|
-
export const listCronRuns = async (params, context) => {
|
|
12
|
-
const objectParams = expectObject(params);
|
|
13
|
-
const id = expectString(objectParams.id, 'id');
|
|
14
|
-
const args = ['cron', 'runs', '--id', id];
|
|
15
|
-
appendOptionalPositiveInteger(args, '--limit', objectParams.limit, 'limit');
|
|
16
|
-
return await runOpenClawCronCommand(args, context);
|
|
17
|
-
};
|
|
18
|
-
export const addCron = async (params, context) => {
|
|
19
|
-
const objectParams = expectObject(params);
|
|
20
|
-
const name = expectString(objectParams.name, 'name');
|
|
21
|
-
const scheduleKey = expectSingleSchedule(objectParams);
|
|
22
|
-
const scheduleValue = expectString(objectParams[scheduleKey], scheduleKey);
|
|
23
|
-
const session = expectSession(objectParams.session);
|
|
24
|
-
const contentKey = expectContentForSession(objectParams, session);
|
|
25
|
-
const contentValue = expectString(objectParams[contentKey], contentKey);
|
|
26
|
-
const args = [
|
|
27
|
-
'cron',
|
|
28
|
-
'add',
|
|
29
|
-
'--name',
|
|
30
|
-
name,
|
|
31
|
-
`--${scheduleKey}`,
|
|
32
|
-
scheduleValue,
|
|
33
|
-
'--session',
|
|
34
|
-
session,
|
|
35
|
-
`--${toKebabCase(contentKey)}`,
|
|
36
|
-
contentValue
|
|
37
|
-
];
|
|
38
|
-
appendOptionalString(args, '--description', objectParams.description);
|
|
39
|
-
appendOptionalString(args, '--agent', objectParams.agent);
|
|
40
|
-
appendOptionalString(args, '--model', objectParams.model);
|
|
41
|
-
appendOptionalString(args, '--thinking', objectParams.thinking);
|
|
42
|
-
appendOptionalString(args, '--channel', objectParams.channel);
|
|
43
|
-
appendOptionalString(args, '--to', objectParams.to);
|
|
44
|
-
appendOptionalString(args, '--tz', objectParams.tz);
|
|
45
|
-
appendOptionalPositiveInteger(args, '--timeout', objectParams.timeout, 'timeout');
|
|
46
|
-
appendOptionalTools(args, objectParams.tools);
|
|
47
|
-
appendOptionalBooleanFlag(args, '--announce', objectParams.announce);
|
|
48
|
-
appendOptionalBooleanFlag(args, '--disabled', objectParams.disabled);
|
|
49
|
-
return await runOpenClawCronCommand(args, context);
|
|
50
|
-
};
|
|
51
|
-
export const renameCron = async (params, context) => {
|
|
52
|
-
const objectParams = expectObject(params);
|
|
53
|
-
const id = expectString(objectParams.id, 'id');
|
|
54
|
-
const args = ['cron', 'edit', id];
|
|
55
|
-
appendOptionalString(args, '--name', objectParams.name);
|
|
56
|
-
appendOptionalString(args, '--description', objectParams.description);
|
|
57
|
-
assertHasPatchArgs(args, 3, "At least one field is required: 'name' or 'description'");
|
|
58
|
-
return await runOpenClawCronCommand(args, context);
|
|
59
|
-
};
|
|
60
|
-
export const rescheduleCron = async (params, context) => {
|
|
61
|
-
const objectParams = expectObject(params);
|
|
62
|
-
const id = expectString(objectParams.id, 'id');
|
|
63
|
-
const scheduleKey = expectSingleSchedule(objectParams);
|
|
64
|
-
const scheduleValue = expectString(objectParams[scheduleKey], scheduleKey);
|
|
65
|
-
const args = ['cron', 'edit', id, `--${scheduleKey}`, scheduleValue];
|
|
66
|
-
appendOptionalString(args, '--tz', objectParams.tz);
|
|
67
|
-
return await runOpenClawCronCommand(args, context);
|
|
68
|
-
};
|
|
69
|
-
export const setCronContent = async (params, context) => {
|
|
70
|
-
const objectParams = expectObject(params);
|
|
71
|
-
const id = expectString(objectParams.id, 'id');
|
|
72
|
-
const session = expectSession(objectParams.session);
|
|
73
|
-
const contentKey = expectContentForSession(objectParams, session);
|
|
74
|
-
const contentValue = expectString(objectParams[contentKey], contentKey);
|
|
75
|
-
const args = [
|
|
76
|
-
'cron',
|
|
77
|
-
'edit',
|
|
78
|
-
id,
|
|
79
|
-
'--session',
|
|
80
|
-
session,
|
|
81
|
-
`--${toKebabCase(contentKey)}`,
|
|
82
|
-
contentValue
|
|
83
|
-
];
|
|
84
|
-
return await runOpenClawCronCommand(args, context);
|
|
85
|
-
};
|
|
86
|
-
export const updateCronMessage = async (params, context) => {
|
|
87
|
-
const objectParams = expectObject(params);
|
|
88
|
-
const id = expectString(objectParams.id, 'id');
|
|
89
|
-
const message = expectString(objectParams.message, 'message');
|
|
90
|
-
return await runOpenClawCronCommand([
|
|
91
|
-
'cron',
|
|
92
|
-
'edit',
|
|
93
|
-
id,
|
|
94
|
-
'--session',
|
|
95
|
-
'isolated',
|
|
96
|
-
'--message',
|
|
97
|
-
message
|
|
98
|
-
], context);
|
|
99
|
-
};
|
|
100
|
-
export const updateCronSystemEvent = async (params, context) => {
|
|
101
|
-
const objectParams = expectObject(params);
|
|
102
|
-
const id = expectString(objectParams.id, 'id');
|
|
103
|
-
const systemEvent = expectString(objectParams.systemEvent, 'systemEvent');
|
|
104
|
-
return await runOpenClawCronCommand([
|
|
105
|
-
'cron',
|
|
106
|
-
'edit',
|
|
107
|
-
id,
|
|
108
|
-
'--session',
|
|
109
|
-
'main',
|
|
110
|
-
'--system-event',
|
|
111
|
-
systemEvent
|
|
112
|
-
], context);
|
|
113
|
-
};
|
|
114
|
-
export const enableCron = async (params, context) => {
|
|
115
|
-
return await runCronById('enable', params, context);
|
|
116
|
-
};
|
|
117
|
-
export const disableCron = async (params, context) => {
|
|
118
|
-
return await runCronById('disable', params, context);
|
|
119
|
-
};
|
|
120
|
-
export const runCron = async (params, context) => {
|
|
121
|
-
return await runCronById('run', params, context);
|
|
122
|
-
};
|
|
123
|
-
export const removeCron = async (params, context) => {
|
|
124
|
-
return await runCronById('rm', params, context);
|
|
125
|
-
};
|
|
126
|
-
async function runCronById(commandName, params, context) {
|
|
127
|
-
const objectParams = expectObject(params);
|
|
128
|
-
const id = expectString(objectParams.id, 'id');
|
|
129
|
-
return await runOpenClawCronCommand(['cron', commandName, id], context);
|
|
130
|
-
}
|
|
131
|
-
async function runOpenClawCronCommand(args, context) {
|
|
132
|
-
const command = process.env.OPENCLAW_BIN || 'openclaw';
|
|
133
|
-
try {
|
|
134
|
-
const { stdout, stderr } = await execFileAsync(command, args, { cwd: context.projectRoot });
|
|
135
|
-
return {
|
|
136
|
-
ok: true,
|
|
137
|
-
command,
|
|
138
|
-
args,
|
|
139
|
-
stdout,
|
|
140
|
-
stderr,
|
|
141
|
-
parsed: parseJsonOutput(stdout)
|
|
142
|
-
};
|
|
143
|
-
}
|
|
144
|
-
catch (err) {
|
|
145
|
-
throw new JsonRpcException(JSON_RPC_ERRORS.internalError, `OpenClaw cron command failed: ${err instanceof Error ? err.message : String(err)}`, {
|
|
146
|
-
command,
|
|
147
|
-
args,
|
|
148
|
-
stdout: typeof err?.stdout === 'string' ? err.stdout : '',
|
|
149
|
-
stderr: typeof err?.stderr === 'string' ? err.stderr : ''
|
|
150
|
-
});
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
function expectObject(value) {
|
|
154
|
-
if (!value || Array.isArray(value) || typeof value !== 'object') {
|
|
155
|
-
throw new JsonRpcException(JSON_RPC_ERRORS.invalidParams, 'Params must be an object');
|
|
156
|
-
}
|
|
157
|
-
return value;
|
|
158
|
-
}
|
|
159
|
-
function expectString(value, fieldName) {
|
|
160
|
-
if (typeof value !== 'string' || value.trim().length === 0) {
|
|
161
|
-
throw new JsonRpcException(JSON_RPC_ERRORS.invalidParams, `Field '${fieldName}' must be a non-empty string`);
|
|
162
|
-
}
|
|
163
|
-
return value.trim();
|
|
164
|
-
}
|
|
165
|
-
function expectSession(value) {
|
|
166
|
-
const session = expectString(value, 'session');
|
|
167
|
-
if (session !== 'main' && session !== 'isolated') {
|
|
168
|
-
throw new JsonRpcException(JSON_RPC_ERRORS.invalidParams, "Field 'session' must be one of: main, isolated");
|
|
169
|
-
}
|
|
170
|
-
return session;
|
|
171
|
-
}
|
|
172
|
-
function expectSingleSchedule(params) {
|
|
173
|
-
const keys = ['at', 'every', 'cron'];
|
|
174
|
-
const present = keys.filter((key) => typeof params[key] === 'string' && String(params[key]).trim().length > 0);
|
|
175
|
-
if (present.length !== 1) {
|
|
176
|
-
throw new JsonRpcException(JSON_RPC_ERRORS.invalidParams, "Exactly one schedule field is required: 'at', 'every', or 'cron'");
|
|
177
|
-
}
|
|
178
|
-
return present[0];
|
|
179
|
-
}
|
|
180
|
-
function expectContentForSession(params, session) {
|
|
181
|
-
const requiredKey = session === 'isolated' ? 'message' : 'systemEvent';
|
|
182
|
-
const forbiddenKey = session === 'isolated' ? 'systemEvent' : 'message';
|
|
183
|
-
if (typeof params[requiredKey] !== 'string' || String(params[requiredKey]).trim().length === 0) {
|
|
184
|
-
throw new JsonRpcException(JSON_RPC_ERRORS.invalidParams, `Field '${requiredKey}' is required when session is '${session}'`);
|
|
185
|
-
}
|
|
186
|
-
if (typeof params[forbiddenKey] === 'string' && String(params[forbiddenKey]).trim().length > 0) {
|
|
187
|
-
throw new JsonRpcException(JSON_RPC_ERRORS.invalidParams, `Field '${forbiddenKey}' cannot be used when session is '${session}'`);
|
|
188
|
-
}
|
|
189
|
-
return requiredKey;
|
|
190
|
-
}
|
|
191
|
-
function appendOptionalString(args, flag, value) {
|
|
192
|
-
if (typeof value !== 'string') {
|
|
193
|
-
return;
|
|
194
|
-
}
|
|
195
|
-
const trimmed = value.trim();
|
|
196
|
-
if (trimmed.length > 0) {
|
|
197
|
-
args.push(flag, trimmed);
|
|
198
|
-
}
|
|
199
|
-
}
|
|
200
|
-
function appendOptionalPositiveInteger(args, flag, value, fieldName) {
|
|
201
|
-
if (value === undefined || value === null) {
|
|
202
|
-
return;
|
|
203
|
-
}
|
|
204
|
-
if (typeof value !== 'number' || !Number.isInteger(value) || value <= 0) {
|
|
205
|
-
throw new JsonRpcException(JSON_RPC_ERRORS.invalidParams, `Field '${fieldName}' must be a positive integer`);
|
|
206
|
-
}
|
|
207
|
-
args.push(flag, String(value));
|
|
208
|
-
}
|
|
209
|
-
function appendOptionalBooleanFlag(args, flag, value) {
|
|
210
|
-
if (value === true) {
|
|
211
|
-
args.push(flag);
|
|
212
|
-
}
|
|
213
|
-
}
|
|
214
|
-
function appendOptionalTools(args, value) {
|
|
215
|
-
if (value === undefined || value === null) {
|
|
216
|
-
return;
|
|
217
|
-
}
|
|
218
|
-
if (typeof value === 'string') {
|
|
219
|
-
const trimmed = value.trim();
|
|
220
|
-
if (trimmed.length > 0) {
|
|
221
|
-
args.push('--tools', trimmed);
|
|
222
|
-
}
|
|
223
|
-
return;
|
|
224
|
-
}
|
|
225
|
-
if (Array.isArray(value) && value.every((item) => typeof item === 'string' && item.trim().length > 0)) {
|
|
226
|
-
args.push('--tools', value.map((item) => String(item).trim()).join(','));
|
|
227
|
-
return;
|
|
228
|
-
}
|
|
229
|
-
throw new JsonRpcException(JSON_RPC_ERRORS.invalidParams, "Field 'tools' must be a non-empty string or string array");
|
|
230
|
-
}
|
|
231
|
-
function assertHasPatchArgs(args, baseLength, message) {
|
|
232
|
-
if (args.length <= baseLength) {
|
|
233
|
-
throw new JsonRpcException(JSON_RPC_ERRORS.invalidParams, message);
|
|
234
|
-
}
|
|
235
|
-
}
|
|
236
|
-
function parseJsonOutput(stdout) {
|
|
237
|
-
const trimmed = stdout.trim();
|
|
238
|
-
if (!trimmed) {
|
|
239
|
-
return null;
|
|
240
|
-
}
|
|
241
|
-
try {
|
|
242
|
-
return JSON.parse(trimmed);
|
|
243
|
-
}
|
|
244
|
-
catch {
|
|
245
|
-
return null;
|
|
246
|
-
}
|
|
247
|
-
}
|
|
248
|
-
function toKebabCase(value) {
|
|
249
|
-
return value.replace(/[A-Z]/g, (match) => `-${match.toLowerCase()}`);
|
|
250
|
-
}
|
|
1
|
+
import { execFile } from 'node:child_process';
|
|
2
|
+
import { promisify } from 'node:util';
|
|
3
|
+
import { JsonRpcException, JSON_RPC_ERRORS } from '../jsonrpc.js';
|
|
4
|
+
const execFileAsync = promisify(execFile);
|
|
5
|
+
export const listCron = async (_params, context) => {
|
|
6
|
+
return await runOpenClawCronCommand(['cron', 'list'], context);
|
|
7
|
+
};
|
|
8
|
+
export const getCronStatus = async (_params, context) => {
|
|
9
|
+
return await runOpenClawCronCommand(['cron', 'status'], context);
|
|
10
|
+
};
|
|
11
|
+
export const listCronRuns = async (params, context) => {
|
|
12
|
+
const objectParams = expectObject(params);
|
|
13
|
+
const id = expectString(objectParams.id, 'id');
|
|
14
|
+
const args = ['cron', 'runs', '--id', id];
|
|
15
|
+
appendOptionalPositiveInteger(args, '--limit', objectParams.limit, 'limit');
|
|
16
|
+
return await runOpenClawCronCommand(args, context);
|
|
17
|
+
};
|
|
18
|
+
export const addCron = async (params, context) => {
|
|
19
|
+
const objectParams = expectObject(params);
|
|
20
|
+
const name = expectString(objectParams.name, 'name');
|
|
21
|
+
const scheduleKey = expectSingleSchedule(objectParams);
|
|
22
|
+
const scheduleValue = expectString(objectParams[scheduleKey], scheduleKey);
|
|
23
|
+
const session = expectSession(objectParams.session);
|
|
24
|
+
const contentKey = expectContentForSession(objectParams, session);
|
|
25
|
+
const contentValue = expectString(objectParams[contentKey], contentKey);
|
|
26
|
+
const args = [
|
|
27
|
+
'cron',
|
|
28
|
+
'add',
|
|
29
|
+
'--name',
|
|
30
|
+
name,
|
|
31
|
+
`--${scheduleKey}`,
|
|
32
|
+
scheduleValue,
|
|
33
|
+
'--session',
|
|
34
|
+
session,
|
|
35
|
+
`--${toKebabCase(contentKey)}`,
|
|
36
|
+
contentValue
|
|
37
|
+
];
|
|
38
|
+
appendOptionalString(args, '--description', objectParams.description);
|
|
39
|
+
appendOptionalString(args, '--agent', objectParams.agent);
|
|
40
|
+
appendOptionalString(args, '--model', objectParams.model);
|
|
41
|
+
appendOptionalString(args, '--thinking', objectParams.thinking);
|
|
42
|
+
appendOptionalString(args, '--channel', objectParams.channel);
|
|
43
|
+
appendOptionalString(args, '--to', objectParams.to);
|
|
44
|
+
appendOptionalString(args, '--tz', objectParams.tz);
|
|
45
|
+
appendOptionalPositiveInteger(args, '--timeout', objectParams.timeout, 'timeout');
|
|
46
|
+
appendOptionalTools(args, objectParams.tools);
|
|
47
|
+
appendOptionalBooleanFlag(args, '--announce', objectParams.announce);
|
|
48
|
+
appendOptionalBooleanFlag(args, '--disabled', objectParams.disabled);
|
|
49
|
+
return await runOpenClawCronCommand(args, context);
|
|
50
|
+
};
|
|
51
|
+
export const renameCron = async (params, context) => {
|
|
52
|
+
const objectParams = expectObject(params);
|
|
53
|
+
const id = expectString(objectParams.id, 'id');
|
|
54
|
+
const args = ['cron', 'edit', id];
|
|
55
|
+
appendOptionalString(args, '--name', objectParams.name);
|
|
56
|
+
appendOptionalString(args, '--description', objectParams.description);
|
|
57
|
+
assertHasPatchArgs(args, 3, "At least one field is required: 'name' or 'description'");
|
|
58
|
+
return await runOpenClawCronCommand(args, context);
|
|
59
|
+
};
|
|
60
|
+
export const rescheduleCron = async (params, context) => {
|
|
61
|
+
const objectParams = expectObject(params);
|
|
62
|
+
const id = expectString(objectParams.id, 'id');
|
|
63
|
+
const scheduleKey = expectSingleSchedule(objectParams);
|
|
64
|
+
const scheduleValue = expectString(objectParams[scheduleKey], scheduleKey);
|
|
65
|
+
const args = ['cron', 'edit', id, `--${scheduleKey}`, scheduleValue];
|
|
66
|
+
appendOptionalString(args, '--tz', objectParams.tz);
|
|
67
|
+
return await runOpenClawCronCommand(args, context);
|
|
68
|
+
};
|
|
69
|
+
export const setCronContent = async (params, context) => {
|
|
70
|
+
const objectParams = expectObject(params);
|
|
71
|
+
const id = expectString(objectParams.id, 'id');
|
|
72
|
+
const session = expectSession(objectParams.session);
|
|
73
|
+
const contentKey = expectContentForSession(objectParams, session);
|
|
74
|
+
const contentValue = expectString(objectParams[contentKey], contentKey);
|
|
75
|
+
const args = [
|
|
76
|
+
'cron',
|
|
77
|
+
'edit',
|
|
78
|
+
id,
|
|
79
|
+
'--session',
|
|
80
|
+
session,
|
|
81
|
+
`--${toKebabCase(contentKey)}`,
|
|
82
|
+
contentValue
|
|
83
|
+
];
|
|
84
|
+
return await runOpenClawCronCommand(args, context);
|
|
85
|
+
};
|
|
86
|
+
export const updateCronMessage = async (params, context) => {
|
|
87
|
+
const objectParams = expectObject(params);
|
|
88
|
+
const id = expectString(objectParams.id, 'id');
|
|
89
|
+
const message = expectString(objectParams.message, 'message');
|
|
90
|
+
return await runOpenClawCronCommand([
|
|
91
|
+
'cron',
|
|
92
|
+
'edit',
|
|
93
|
+
id,
|
|
94
|
+
'--session',
|
|
95
|
+
'isolated',
|
|
96
|
+
'--message',
|
|
97
|
+
message
|
|
98
|
+
], context);
|
|
99
|
+
};
|
|
100
|
+
export const updateCronSystemEvent = async (params, context) => {
|
|
101
|
+
const objectParams = expectObject(params);
|
|
102
|
+
const id = expectString(objectParams.id, 'id');
|
|
103
|
+
const systemEvent = expectString(objectParams.systemEvent, 'systemEvent');
|
|
104
|
+
return await runOpenClawCronCommand([
|
|
105
|
+
'cron',
|
|
106
|
+
'edit',
|
|
107
|
+
id,
|
|
108
|
+
'--session',
|
|
109
|
+
'main',
|
|
110
|
+
'--system-event',
|
|
111
|
+
systemEvent
|
|
112
|
+
], context);
|
|
113
|
+
};
|
|
114
|
+
export const enableCron = async (params, context) => {
|
|
115
|
+
return await runCronById('enable', params, context);
|
|
116
|
+
};
|
|
117
|
+
export const disableCron = async (params, context) => {
|
|
118
|
+
return await runCronById('disable', params, context);
|
|
119
|
+
};
|
|
120
|
+
export const runCron = async (params, context) => {
|
|
121
|
+
return await runCronById('run', params, context);
|
|
122
|
+
};
|
|
123
|
+
export const removeCron = async (params, context) => {
|
|
124
|
+
return await runCronById('rm', params, context);
|
|
125
|
+
};
|
|
126
|
+
async function runCronById(commandName, params, context) {
|
|
127
|
+
const objectParams = expectObject(params);
|
|
128
|
+
const id = expectString(objectParams.id, 'id');
|
|
129
|
+
return await runOpenClawCronCommand(['cron', commandName, id], context);
|
|
130
|
+
}
|
|
131
|
+
async function runOpenClawCronCommand(args, context) {
|
|
132
|
+
const command = process.env.OPENCLAW_BIN || 'openclaw';
|
|
133
|
+
try {
|
|
134
|
+
const { stdout, stderr } = await execFileAsync(command, args, { cwd: context.projectRoot });
|
|
135
|
+
return {
|
|
136
|
+
ok: true,
|
|
137
|
+
command,
|
|
138
|
+
args,
|
|
139
|
+
stdout,
|
|
140
|
+
stderr,
|
|
141
|
+
parsed: parseJsonOutput(stdout)
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
catch (err) {
|
|
145
|
+
throw new JsonRpcException(JSON_RPC_ERRORS.internalError, `OpenClaw cron command failed: ${err instanceof Error ? err.message : String(err)}`, {
|
|
146
|
+
command,
|
|
147
|
+
args,
|
|
148
|
+
stdout: typeof err?.stdout === 'string' ? err.stdout : '',
|
|
149
|
+
stderr: typeof err?.stderr === 'string' ? err.stderr : ''
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
function expectObject(value) {
|
|
154
|
+
if (!value || Array.isArray(value) || typeof value !== 'object') {
|
|
155
|
+
throw new JsonRpcException(JSON_RPC_ERRORS.invalidParams, 'Params must be an object');
|
|
156
|
+
}
|
|
157
|
+
return value;
|
|
158
|
+
}
|
|
159
|
+
function expectString(value, fieldName) {
|
|
160
|
+
if (typeof value !== 'string' || value.trim().length === 0) {
|
|
161
|
+
throw new JsonRpcException(JSON_RPC_ERRORS.invalidParams, `Field '${fieldName}' must be a non-empty string`);
|
|
162
|
+
}
|
|
163
|
+
return value.trim();
|
|
164
|
+
}
|
|
165
|
+
function expectSession(value) {
|
|
166
|
+
const session = expectString(value, 'session');
|
|
167
|
+
if (session !== 'main' && session !== 'isolated') {
|
|
168
|
+
throw new JsonRpcException(JSON_RPC_ERRORS.invalidParams, "Field 'session' must be one of: main, isolated");
|
|
169
|
+
}
|
|
170
|
+
return session;
|
|
171
|
+
}
|
|
172
|
+
function expectSingleSchedule(params) {
|
|
173
|
+
const keys = ['at', 'every', 'cron'];
|
|
174
|
+
const present = keys.filter((key) => typeof params[key] === 'string' && String(params[key]).trim().length > 0);
|
|
175
|
+
if (present.length !== 1) {
|
|
176
|
+
throw new JsonRpcException(JSON_RPC_ERRORS.invalidParams, "Exactly one schedule field is required: 'at', 'every', or 'cron'");
|
|
177
|
+
}
|
|
178
|
+
return present[0];
|
|
179
|
+
}
|
|
180
|
+
function expectContentForSession(params, session) {
|
|
181
|
+
const requiredKey = session === 'isolated' ? 'message' : 'systemEvent';
|
|
182
|
+
const forbiddenKey = session === 'isolated' ? 'systemEvent' : 'message';
|
|
183
|
+
if (typeof params[requiredKey] !== 'string' || String(params[requiredKey]).trim().length === 0) {
|
|
184
|
+
throw new JsonRpcException(JSON_RPC_ERRORS.invalidParams, `Field '${requiredKey}' is required when session is '${session}'`);
|
|
185
|
+
}
|
|
186
|
+
if (typeof params[forbiddenKey] === 'string' && String(params[forbiddenKey]).trim().length > 0) {
|
|
187
|
+
throw new JsonRpcException(JSON_RPC_ERRORS.invalidParams, `Field '${forbiddenKey}' cannot be used when session is '${session}'`);
|
|
188
|
+
}
|
|
189
|
+
return requiredKey;
|
|
190
|
+
}
|
|
191
|
+
function appendOptionalString(args, flag, value) {
|
|
192
|
+
if (typeof value !== 'string') {
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
195
|
+
const trimmed = value.trim();
|
|
196
|
+
if (trimmed.length > 0) {
|
|
197
|
+
args.push(flag, trimmed);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
function appendOptionalPositiveInteger(args, flag, value, fieldName) {
|
|
201
|
+
if (value === undefined || value === null) {
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
204
|
+
if (typeof value !== 'number' || !Number.isInteger(value) || value <= 0) {
|
|
205
|
+
throw new JsonRpcException(JSON_RPC_ERRORS.invalidParams, `Field '${fieldName}' must be a positive integer`);
|
|
206
|
+
}
|
|
207
|
+
args.push(flag, String(value));
|
|
208
|
+
}
|
|
209
|
+
function appendOptionalBooleanFlag(args, flag, value) {
|
|
210
|
+
if (value === true) {
|
|
211
|
+
args.push(flag);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
function appendOptionalTools(args, value) {
|
|
215
|
+
if (value === undefined || value === null) {
|
|
216
|
+
return;
|
|
217
|
+
}
|
|
218
|
+
if (typeof value === 'string') {
|
|
219
|
+
const trimmed = value.trim();
|
|
220
|
+
if (trimmed.length > 0) {
|
|
221
|
+
args.push('--tools', trimmed);
|
|
222
|
+
}
|
|
223
|
+
return;
|
|
224
|
+
}
|
|
225
|
+
if (Array.isArray(value) && value.every((item) => typeof item === 'string' && item.trim().length > 0)) {
|
|
226
|
+
args.push('--tools', value.map((item) => String(item).trim()).join(','));
|
|
227
|
+
return;
|
|
228
|
+
}
|
|
229
|
+
throw new JsonRpcException(JSON_RPC_ERRORS.invalidParams, "Field 'tools' must be a non-empty string or string array");
|
|
230
|
+
}
|
|
231
|
+
function assertHasPatchArgs(args, baseLength, message) {
|
|
232
|
+
if (args.length <= baseLength) {
|
|
233
|
+
throw new JsonRpcException(JSON_RPC_ERRORS.invalidParams, message);
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
function parseJsonOutput(stdout) {
|
|
237
|
+
const trimmed = stdout.trim();
|
|
238
|
+
if (!trimmed) {
|
|
239
|
+
return null;
|
|
240
|
+
}
|
|
241
|
+
try {
|
|
242
|
+
return JSON.parse(trimmed);
|
|
243
|
+
}
|
|
244
|
+
catch {
|
|
245
|
+
return null;
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
function toKebabCase(value) {
|
|
249
|
+
return value.replace(/[A-Z]/g, (match) => `-${match.toLowerCase()}`);
|
|
250
|
+
}
|