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,191 +1,210 @@
|
|
|
1
|
-
import { afterEach, describe, test } from 'node:test';
|
|
2
|
-
import assert from 'node:assert/strict';
|
|
3
|
-
import fs from 'node:fs/promises';
|
|
4
|
-
import os from 'node:os';
|
|
5
|
-
import path from 'node:path';
|
|
6
|
-
import { ensureArtifactUploaded, listArtifacts, markArtifactUploaded, refreshArtifacts } from './artifacts.js';
|
|
7
|
-
const tempDirs = [];
|
|
8
|
-
const originalFetch = globalThis.fetch;
|
|
9
|
-
afterEach(async () => {
|
|
10
|
-
globalThis.fetch = originalFetch;
|
|
11
|
-
while (tempDirs.length > 0) {
|
|
12
|
-
const dir = tempDirs.pop();
|
|
13
|
-
if (dir) {
|
|
14
|
-
await fs.rm(dir, { recursive: true, force: true });
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
});
|
|
18
|
-
describe('artifacts workspace scope', () => {
|
|
19
|
-
test('only indexes allowed artifact types inside workspace', async () => {
|
|
20
|
-
const context = await createMethodContext();
|
|
21
|
-
const workspaceRoot = path.join(context.openclawRoot, 'workspace');
|
|
22
|
-
await fs.writeFile(path.join(workspaceRoot, 'SOUL.md'), '# root noise\n', 'utf8');
|
|
23
|
-
await fs.mkdir(path.join(workspaceRoot, 'exports'), { recursive: true });
|
|
24
|
-
await fs.mkdir(path.join(workspaceRoot, 'logs'), { recursive: true });
|
|
25
|
-
await fs.mkdir(path.join(workspaceRoot, 'nested', 'media'), { recursive: true });
|
|
26
|
-
await fs.writeFile(path.join(workspaceRoot, 'exports', 'preview.png'), 'png-data', 'utf8');
|
|
27
|
-
await fs.writeFile(path.join(workspaceRoot, 'exports', 'report.pdf'), 'pdf-data', 'utf8');
|
|
28
|
-
await fs.writeFile(path.join(workspaceRoot, 'nested', 'media', 'archive.zip'), 'zip-data', 'utf8');
|
|
29
|
-
await fs.writeFile(path.join(workspaceRoot, 'nested', 'media', 'video.mp4'), 'mp4-data', 'utf8');
|
|
30
|
-
await fs.writeFile(path.join(workspaceRoot, 'exports', 'spec.docx'), 'docx-data', 'utf8');
|
|
31
|
-
await fs.writeFile(path.join(workspaceRoot, 'exports', 'ignored.md'), '# markdown noise\n', 'utf8');
|
|
32
|
-
await fs.writeFile(path.join(workspaceRoot, 'exports', 'ignored.json'), '{"noise":true}\n', 'utf8');
|
|
33
|
-
await fs.writeFile(path.join(workspaceRoot, 'logs', 'ignored.pdf'), 'log pdf noise', 'utf8');
|
|
34
|
-
await fs.writeFile(path.join(workspaceRoot, 'artifacts.json'), '[]', 'utf8');
|
|
35
|
-
const result = await refreshArtifacts({}, context);
|
|
36
|
-
assert.equal(result.scope, 'workspace');
|
|
37
|
-
assert.equal(result.count, 5);
|
|
38
|
-
assert.deepEqual(result.items.map((item) => item.relativePath), [
|
|
39
|
-
'nested/media/archive.zip',
|
|
40
|
-
'exports/preview.png',
|
|
41
|
-
'exports/report.pdf',
|
|
42
|
-
'exports/spec.docx',
|
|
43
|
-
'nested/media/video.mp4'
|
|
44
|
-
]);
|
|
45
|
-
assert.equal(result.workspaceRoot, workspaceRoot);
|
|
46
|
-
assert.equal(result.manifestPath, path.join(workspaceRoot, 'artifacts.json'));
|
|
47
|
-
});
|
|
48
|
-
test('
|
|
49
|
-
const context = await createMethodContext();
|
|
50
|
-
const workspaceRoot = path.join(context.openclawRoot, 'workspace');
|
|
51
|
-
await fs.mkdir(path.join(workspaceRoot, '
|
|
52
|
-
await fs.writeFile(path.join(workspaceRoot, '
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
const
|
|
56
|
-
assert.equal(
|
|
57
|
-
assert.
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
await
|
|
69
|
-
const
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
const
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
assert.equal(
|
|
137
|
-
assert.equal(
|
|
138
|
-
assert.equal(
|
|
139
|
-
assert.equal(
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
1
|
+
import { afterEach, describe, test } from 'node:test';
|
|
2
|
+
import assert from 'node:assert/strict';
|
|
3
|
+
import fs from 'node:fs/promises';
|
|
4
|
+
import os from 'node:os';
|
|
5
|
+
import path from 'node:path';
|
|
6
|
+
import { ensureArtifactUploaded, listArtifacts, markArtifactUploaded, refreshArtifacts } from './artifacts.js';
|
|
7
|
+
const tempDirs = [];
|
|
8
|
+
const originalFetch = globalThis.fetch;
|
|
9
|
+
afterEach(async () => {
|
|
10
|
+
globalThis.fetch = originalFetch;
|
|
11
|
+
while (tempDirs.length > 0) {
|
|
12
|
+
const dir = tempDirs.pop();
|
|
13
|
+
if (dir) {
|
|
14
|
+
await fs.rm(dir, { recursive: true, force: true });
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
});
|
|
18
|
+
describe('artifacts workspace scope', () => {
|
|
19
|
+
test('only indexes allowed artifact types inside workspace', async () => {
|
|
20
|
+
const context = await createMethodContext();
|
|
21
|
+
const workspaceRoot = path.join(context.openclawRoot, 'workspace');
|
|
22
|
+
await fs.writeFile(path.join(workspaceRoot, 'SOUL.md'), '# root noise\n', 'utf8');
|
|
23
|
+
await fs.mkdir(path.join(workspaceRoot, 'exports'), { recursive: true });
|
|
24
|
+
await fs.mkdir(path.join(workspaceRoot, 'logs'), { recursive: true });
|
|
25
|
+
await fs.mkdir(path.join(workspaceRoot, 'nested', 'media'), { recursive: true });
|
|
26
|
+
await fs.writeFile(path.join(workspaceRoot, 'exports', 'preview.png'), 'png-data', 'utf8');
|
|
27
|
+
await fs.writeFile(path.join(workspaceRoot, 'exports', 'report.pdf'), 'pdf-data', 'utf8');
|
|
28
|
+
await fs.writeFile(path.join(workspaceRoot, 'nested', 'media', 'archive.zip'), 'zip-data', 'utf8');
|
|
29
|
+
await fs.writeFile(path.join(workspaceRoot, 'nested', 'media', 'video.mp4'), 'mp4-data', 'utf8');
|
|
30
|
+
await fs.writeFile(path.join(workspaceRoot, 'exports', 'spec.docx'), 'docx-data', 'utf8');
|
|
31
|
+
await fs.writeFile(path.join(workspaceRoot, 'exports', 'ignored.md'), '# markdown noise\n', 'utf8');
|
|
32
|
+
await fs.writeFile(path.join(workspaceRoot, 'exports', 'ignored.json'), '{"noise":true}\n', 'utf8');
|
|
33
|
+
await fs.writeFile(path.join(workspaceRoot, 'logs', 'ignored.pdf'), 'log pdf noise', 'utf8');
|
|
34
|
+
await fs.writeFile(path.join(workspaceRoot, 'artifacts.json'), '[]', 'utf8');
|
|
35
|
+
const result = await refreshArtifacts({}, context);
|
|
36
|
+
assert.equal(result.scope, 'workspace');
|
|
37
|
+
assert.equal(result.count, 5);
|
|
38
|
+
assert.deepEqual(result.items.map((item) => item.relativePath), [
|
|
39
|
+
'nested/media/archive.zip',
|
|
40
|
+
'exports/preview.png',
|
|
41
|
+
'exports/report.pdf',
|
|
42
|
+
'exports/spec.docx',
|
|
43
|
+
'nested/media/video.mp4'
|
|
44
|
+
]);
|
|
45
|
+
assert.equal(result.workspaceRoot, workspaceRoot);
|
|
46
|
+
assert.equal(result.manifestPath, path.join(workspaceRoot, 'artifacts.json'));
|
|
47
|
+
});
|
|
48
|
+
test('indexes only markdown files added after the initial baseline', async () => {
|
|
49
|
+
const context = await createMethodContext();
|
|
50
|
+
const workspaceRoot = path.join(context.openclawRoot, 'workspace');
|
|
51
|
+
await fs.mkdir(path.join(workspaceRoot, 'docs'), { recursive: true });
|
|
52
|
+
await fs.writeFile(path.join(workspaceRoot, 'docs', 'existing.md'), '# existing\n', 'utf8');
|
|
53
|
+
await fs.writeFile(path.join(workspaceRoot, 'MEMORY.md'), '# memory\n', 'utf8');
|
|
54
|
+
await fs.writeFile(path.join(workspaceRoot, 'SoUL.md'), '# soul\n', 'utf8');
|
|
55
|
+
const baseline = await refreshArtifacts({}, context);
|
|
56
|
+
assert.equal(baseline.count, 0);
|
|
57
|
+
assert.deepEqual(baseline.items, []);
|
|
58
|
+
await fs.writeFile(path.join(workspaceRoot, 'docs', 'existing.md'), '# changed\n', 'utf8');
|
|
59
|
+
await fs.writeFile(path.join(workspaceRoot, 'MEMORY.md'), '# changed memory\n', 'utf8');
|
|
60
|
+
await fs.writeFile(path.join(workspaceRoot, 'docs', 'generated.md'), '# generated\n', 'utf8');
|
|
61
|
+
const refreshed = await refreshArtifacts({}, context);
|
|
62
|
+
assert.equal(refreshed.count, 1);
|
|
63
|
+
assert.deepEqual(refreshed.items.map((item) => item.relativePath), ['docs/generated.md']);
|
|
64
|
+
assert.equal(refreshed.items[0]?.category, 'document');
|
|
65
|
+
assert.equal(refreshed.items[0]?.mimeType, 'text/markdown');
|
|
66
|
+
});
|
|
67
|
+
test('list reads workspace manifest without taskId', async () => {
|
|
68
|
+
const context = await createMethodContext();
|
|
69
|
+
const workspaceRoot = path.join(context.openclawRoot, 'workspace');
|
|
70
|
+
await fs.mkdir(path.join(workspaceRoot, 'exports'), { recursive: true });
|
|
71
|
+
await fs.writeFile(path.join(workspaceRoot, 'exports', 'me.pdf'), 'pdf-data', 'utf8');
|
|
72
|
+
const refreshed = await refreshArtifacts({}, context);
|
|
73
|
+
assert.equal(refreshed.count, 1);
|
|
74
|
+
const listed = await listArtifacts({ refresh: false }, context);
|
|
75
|
+
assert.equal(listed.scope, 'workspace');
|
|
76
|
+
assert.equal(listed.count, 1);
|
|
77
|
+
assert.deepEqual(listed.items.map((item) => item.relativePath), ['exports/me.pdf']);
|
|
78
|
+
assert.equal(listed.manifestPath, path.join(workspaceRoot, 'artifacts.json'));
|
|
79
|
+
assert.equal(listed.workspaceRoot, workspaceRoot);
|
|
80
|
+
});
|
|
81
|
+
test('ensureUploaded uploads local artifact and updates manifest', async () => {
|
|
82
|
+
const context = await createMethodContext();
|
|
83
|
+
const workspaceRoot = path.join(context.openclawRoot, 'workspace');
|
|
84
|
+
const artifactPath = path.join(workspaceRoot, 'exports', 'me.pdf');
|
|
85
|
+
await writeApiCoreBotConfig(context.openclawRoot, 'https://api.example.com');
|
|
86
|
+
await fs.mkdir(path.dirname(artifactPath), { recursive: true });
|
|
87
|
+
await fs.writeFile(artifactPath, 'pdf-data', 'utf8');
|
|
88
|
+
const refreshed = await refreshArtifacts({}, context);
|
|
89
|
+
const artifactId = refreshed.items[0]?.id;
|
|
90
|
+
assert.ok(artifactId);
|
|
91
|
+
const calls = [];
|
|
92
|
+
globalThis.fetch = (async (input, init) => {
|
|
93
|
+
const url = typeof input === 'string'
|
|
94
|
+
? input
|
|
95
|
+
: input instanceof URL
|
|
96
|
+
? input.toString()
|
|
97
|
+
: input.url;
|
|
98
|
+
const method = init?.method ?? (input instanceof Request ? input.method : 'GET');
|
|
99
|
+
calls.push({ url, method });
|
|
100
|
+
if (url === 'https://api.example.com/api-core-bot/front/s3/get-presigned-post') {
|
|
101
|
+
assert.equal(init?.body !== undefined, true);
|
|
102
|
+
const parsedBody = JSON.parse(String(init?.body));
|
|
103
|
+
assert.equal(parsedBody.dir, 'artifacts/');
|
|
104
|
+
assert.equal(parsedBody.filename, 'me.pdf');
|
|
105
|
+
assert.equal(parsedBody.file_name, undefined);
|
|
106
|
+
return new Response(JSON.stringify({
|
|
107
|
+
code: 0,
|
|
108
|
+
message: '',
|
|
109
|
+
success: true,
|
|
110
|
+
data: {
|
|
111
|
+
url: 'https://upload.example.com',
|
|
112
|
+
fields: {
|
|
113
|
+
key: 'artifacts/me.pdf',
|
|
114
|
+
policy: 'policy-token'
|
|
115
|
+
},
|
|
116
|
+
file_key: 'artifacts/me.pdf',
|
|
117
|
+
file_url: 'https://cdn.example.com/artifacts/me.pdf'
|
|
118
|
+
}
|
|
119
|
+
}), {
|
|
120
|
+
status: 200,
|
|
121
|
+
headers: { 'Content-Type': 'application/json' }
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
if (url === 'https://upload.example.com') {
|
|
125
|
+
assert.ok(init?.body instanceof FormData);
|
|
126
|
+
return new Response(null, { status: 204 });
|
|
127
|
+
}
|
|
128
|
+
throw new Error(`Unexpected fetch call: ${url}`);
|
|
129
|
+
});
|
|
130
|
+
const ensured = await ensureArtifactUploaded({
|
|
131
|
+
artifactId,
|
|
132
|
+
presignedPostBody: {
|
|
133
|
+
dir: 'artifacts/'
|
|
134
|
+
}
|
|
135
|
+
}, context);
|
|
136
|
+
assert.equal(ensured.ok, true);
|
|
137
|
+
assert.equal(ensured.uploaded, true);
|
|
138
|
+
assert.equal(ensured.downloadUrl, 'https://cdn.example.com/artifacts/me.pdf');
|
|
139
|
+
assert.equal(ensured.objectKey, 'artifacts/me.pdf');
|
|
140
|
+
assert.equal(ensured.item.storageStatus, 'uploaded');
|
|
141
|
+
assert.equal(ensured.item.fileUrl, 'https://cdn.example.com/artifacts/me.pdf');
|
|
142
|
+
assert.equal(ensured.item.objectKey, 'artifacts/me.pdf');
|
|
143
|
+
assert.deepEqual(calls, [
|
|
144
|
+
{
|
|
145
|
+
url: 'https://api.example.com/api-core-bot/front/s3/get-presigned-post',
|
|
146
|
+
method: 'POST'
|
|
147
|
+
},
|
|
148
|
+
{
|
|
149
|
+
url: 'https://upload.example.com',
|
|
150
|
+
method: 'POST'
|
|
151
|
+
}
|
|
152
|
+
]);
|
|
153
|
+
const listed = await listArtifacts({ refresh: false }, context);
|
|
154
|
+
assert.equal(listed.items.length, 1);
|
|
155
|
+
assert.equal(listed.items[0]?.relativePath, 'exports/me.pdf');
|
|
156
|
+
assert.equal(listed.items[0]?.storageStatus, 'uploaded');
|
|
157
|
+
assert.equal(listed.items[0]?.fileUrl, 'https://cdn.example.com/artifacts/me.pdf');
|
|
158
|
+
assert.equal(listed.items[0]?.objectKey, 'artifacts/me.pdf');
|
|
159
|
+
});
|
|
160
|
+
test('ensureUploaded reuses existing uploaded artifact without fetching', async () => {
|
|
161
|
+
const context = await createMethodContext();
|
|
162
|
+
const workspaceRoot = path.join(context.openclawRoot, 'workspace');
|
|
163
|
+
const artifactPath = path.join(workspaceRoot, 'exports', 'me.pdf');
|
|
164
|
+
await fs.mkdir(path.dirname(artifactPath), { recursive: true });
|
|
165
|
+
await fs.writeFile(artifactPath, 'pdf-data', 'utf8');
|
|
166
|
+
const refreshed = await refreshArtifacts({}, context);
|
|
167
|
+
const artifactId = refreshed.items[0]?.id;
|
|
168
|
+
assert.ok(artifactId);
|
|
169
|
+
await markArtifactUploaded({
|
|
170
|
+
artifactId,
|
|
171
|
+
objectKey: 'artifacts/me.pdf',
|
|
172
|
+
fileUrl: 'https://cdn.example.com/artifacts/me.pdf'
|
|
173
|
+
}, context);
|
|
174
|
+
globalThis.fetch = (async () => {
|
|
175
|
+
throw new Error('fetch should not be called for existing uploaded artifact');
|
|
176
|
+
});
|
|
177
|
+
const ensured = await ensureArtifactUploaded({ artifactId }, context);
|
|
178
|
+
assert.equal(ensured.ok, true);
|
|
179
|
+
assert.equal(ensured.uploaded, false);
|
|
180
|
+
assert.equal(ensured.downloadUrl, 'https://cdn.example.com/artifacts/me.pdf');
|
|
181
|
+
assert.equal(ensured.item.storageStatus, 'uploaded');
|
|
182
|
+
assert.equal(ensured.item.fileUrl, 'https://cdn.example.com/artifacts/me.pdf');
|
|
183
|
+
});
|
|
184
|
+
});
|
|
185
|
+
async function createMethodContext() {
|
|
186
|
+
const rootDir = await fs.mkdtemp(path.join(os.tmpdir(), 'artifacts-task-scope-'));
|
|
187
|
+
tempDirs.push(rootDir);
|
|
188
|
+
const openclawRoot = path.join(rootDir, '.openclaw');
|
|
189
|
+
const workspaceRoot = path.join(openclawRoot, 'workspace');
|
|
190
|
+
await fs.mkdir(workspaceRoot, { recursive: true });
|
|
191
|
+
return {
|
|
192
|
+
projectRoot: rootDir,
|
|
193
|
+
openclawRoot
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
async function writeApiCoreBotConfig(openclawRoot, baseUrl) {
|
|
197
|
+
await fs.writeFile(path.join(openclawRoot, 'openclaw.json'), JSON.stringify({
|
|
198
|
+
plugins: {
|
|
199
|
+
entries: {
|
|
200
|
+
'rol-websocket-channel': {
|
|
201
|
+
config: {
|
|
202
|
+
apiCoreBot: {
|
|
203
|
+
baseUrl
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
}, null, 2), 'utf8');
|
|
210
|
+
}
|