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
package/dist/src/admin/cli.js
CHANGED
|
@@ -1,43 +1,43 @@
|
|
|
1
|
-
import { getOpenClawRoot, getProjectRoot } from './lib/paths.js';
|
|
2
|
-
import { getMethod } from './methods/index.js';
|
|
3
|
-
import { failure, JsonRpcException, JSON_RPC_ERRORS, parseRequest, serialize, success } from './jsonrpc.js';
|
|
4
|
-
async function main() {
|
|
5
|
-
const raw = await readStdin();
|
|
6
|
-
const request = parseRequest(raw);
|
|
7
|
-
const context = {
|
|
8
|
-
projectRoot: getProjectRoot(),
|
|
9
|
-
openclawRoot: getOpenClawRoot()
|
|
10
|
-
};
|
|
11
|
-
try {
|
|
12
|
-
const handler = getMethod(request.method);
|
|
13
|
-
const result = await handler(request.params, context);
|
|
14
|
-
process.stdout.write(serialize(success(normalizeId(request.id), result)));
|
|
15
|
-
}
|
|
16
|
-
catch (error) {
|
|
17
|
-
process.stdout.write(serialize(toErrorResponse(normalizeId(request.id), error)));
|
|
18
|
-
process.exitCode = 1;
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
async function readStdin() {
|
|
22
|
-
const chunks = [];
|
|
23
|
-
for await (const chunk of process.stdin) {
|
|
24
|
-
chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
|
|
25
|
-
}
|
|
26
|
-
const raw = Buffer.concat(chunks).toString('utf8').trim();
|
|
27
|
-
if (!raw) {
|
|
28
|
-
throw new JsonRpcException(JSON_RPC_ERRORS.invalidRequest, 'Request body is empty');
|
|
29
|
-
}
|
|
30
|
-
return raw;
|
|
31
|
-
}
|
|
32
|
-
function normalizeId(value) {
|
|
33
|
-
return value ?? null;
|
|
34
|
-
}
|
|
35
|
-
function toErrorResponse(id, error) {
|
|
36
|
-
if (error instanceof JsonRpcException) {
|
|
37
|
-
return failure(id, error.code, error.message, error.data);
|
|
38
|
-
}
|
|
39
|
-
return failure(id, JSON_RPC_ERRORS.internalError, 'Internal error', {
|
|
40
|
-
detail: error instanceof Error ? error.message : String(error)
|
|
41
|
-
});
|
|
42
|
-
}
|
|
43
|
-
await main();
|
|
1
|
+
import { getOpenClawRoot, getProjectRoot } from './lib/paths.js';
|
|
2
|
+
import { getMethod } from './methods/index.js';
|
|
3
|
+
import { failure, JsonRpcException, JSON_RPC_ERRORS, parseRequest, serialize, success } from './jsonrpc.js';
|
|
4
|
+
async function main() {
|
|
5
|
+
const raw = await readStdin();
|
|
6
|
+
const request = parseRequest(raw);
|
|
7
|
+
const context = {
|
|
8
|
+
projectRoot: getProjectRoot(),
|
|
9
|
+
openclawRoot: getOpenClawRoot()
|
|
10
|
+
};
|
|
11
|
+
try {
|
|
12
|
+
const handler = getMethod(request.method);
|
|
13
|
+
const result = await handler(request.params, context);
|
|
14
|
+
process.stdout.write(serialize(success(normalizeId(request.id), result)));
|
|
15
|
+
}
|
|
16
|
+
catch (error) {
|
|
17
|
+
process.stdout.write(serialize(toErrorResponse(normalizeId(request.id), error)));
|
|
18
|
+
process.exitCode = 1;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
async function readStdin() {
|
|
22
|
+
const chunks = [];
|
|
23
|
+
for await (const chunk of process.stdin) {
|
|
24
|
+
chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
|
|
25
|
+
}
|
|
26
|
+
const raw = Buffer.concat(chunks).toString('utf8').trim();
|
|
27
|
+
if (!raw) {
|
|
28
|
+
throw new JsonRpcException(JSON_RPC_ERRORS.invalidRequest, 'Request body is empty');
|
|
29
|
+
}
|
|
30
|
+
return raw;
|
|
31
|
+
}
|
|
32
|
+
function normalizeId(value) {
|
|
33
|
+
return value ?? null;
|
|
34
|
+
}
|
|
35
|
+
function toErrorResponse(id, error) {
|
|
36
|
+
if (error instanceof JsonRpcException) {
|
|
37
|
+
return failure(id, error.code, error.message, error.data);
|
|
38
|
+
}
|
|
39
|
+
return failure(id, JSON_RPC_ERRORS.internalError, 'Internal error', {
|
|
40
|
+
detail: error instanceof Error ? error.message : String(error)
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
await main();
|
|
@@ -1,60 +1,60 @@
|
|
|
1
|
-
export const JSON_RPC_VERSION = '2.0';
|
|
2
|
-
export const JSON_RPC_ERRORS = {
|
|
3
|
-
parseError: -32700,
|
|
4
|
-
invalidRequest: -32600,
|
|
5
|
-
methodNotFound: -32601,
|
|
6
|
-
invalidParams: -32602,
|
|
7
|
-
internalError: -32603
|
|
8
|
-
};
|
|
9
|
-
export class JsonRpcException extends Error {
|
|
10
|
-
constructor(code, message, data) {
|
|
11
|
-
super(message);
|
|
12
|
-
this.code = code;
|
|
13
|
-
this.data = data;
|
|
14
|
-
}
|
|
15
|
-
}
|
|
16
|
-
export function parseRequest(raw) {
|
|
17
|
-
let parsed;
|
|
18
|
-
try {
|
|
19
|
-
parsed = JSON.parse(raw);
|
|
20
|
-
}
|
|
21
|
-
catch (error) {
|
|
22
|
-
throw new JsonRpcException(JSON_RPC_ERRORS.parseError, 'Parse error', {
|
|
23
|
-
detail: error instanceof Error ? error.message : String(error)
|
|
24
|
-
});
|
|
25
|
-
}
|
|
26
|
-
if (!isRequest(parsed)) {
|
|
27
|
-
throw new JsonRpcException(JSON_RPC_ERRORS.invalidRequest, 'Invalid Request');
|
|
28
|
-
}
|
|
29
|
-
return parsed;
|
|
30
|
-
}
|
|
31
|
-
export function success(id, result) {
|
|
32
|
-
return {
|
|
33
|
-
jsonrpc: JSON_RPC_VERSION,
|
|
34
|
-
id,
|
|
35
|
-
result: result
|
|
36
|
-
};
|
|
37
|
-
}
|
|
38
|
-
export function failure(id, code, message, data) {
|
|
39
|
-
return {
|
|
40
|
-
jsonrpc: JSON_RPC_VERSION,
|
|
41
|
-
id,
|
|
42
|
-
error: {
|
|
43
|
-
code,
|
|
44
|
-
message,
|
|
45
|
-
...(data === undefined ? {} : { data: data })
|
|
46
|
-
}
|
|
47
|
-
};
|
|
48
|
-
}
|
|
49
|
-
export function serialize(response) {
|
|
50
|
-
return `${JSON.stringify(response, null, 2)}\n`;
|
|
51
|
-
}
|
|
52
|
-
function isRequest(value) {
|
|
53
|
-
if (!value || typeof value !== 'object') {
|
|
54
|
-
return false;
|
|
55
|
-
}
|
|
56
|
-
const candidate = value;
|
|
57
|
-
return (candidate.jsonrpc === JSON_RPC_VERSION &&
|
|
58
|
-
typeof candidate.method === 'string' &&
|
|
59
|
-
candidate.method.length > 0);
|
|
60
|
-
}
|
|
1
|
+
export const JSON_RPC_VERSION = '2.0';
|
|
2
|
+
export const JSON_RPC_ERRORS = {
|
|
3
|
+
parseError: -32700,
|
|
4
|
+
invalidRequest: -32600,
|
|
5
|
+
methodNotFound: -32601,
|
|
6
|
+
invalidParams: -32602,
|
|
7
|
+
internalError: -32603
|
|
8
|
+
};
|
|
9
|
+
export class JsonRpcException extends Error {
|
|
10
|
+
constructor(code, message, data) {
|
|
11
|
+
super(message);
|
|
12
|
+
this.code = code;
|
|
13
|
+
this.data = data;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
export function parseRequest(raw) {
|
|
17
|
+
let parsed;
|
|
18
|
+
try {
|
|
19
|
+
parsed = JSON.parse(raw);
|
|
20
|
+
}
|
|
21
|
+
catch (error) {
|
|
22
|
+
throw new JsonRpcException(JSON_RPC_ERRORS.parseError, 'Parse error', {
|
|
23
|
+
detail: error instanceof Error ? error.message : String(error)
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
if (!isRequest(parsed)) {
|
|
27
|
+
throw new JsonRpcException(JSON_RPC_ERRORS.invalidRequest, 'Invalid Request');
|
|
28
|
+
}
|
|
29
|
+
return parsed;
|
|
30
|
+
}
|
|
31
|
+
export function success(id, result) {
|
|
32
|
+
return {
|
|
33
|
+
jsonrpc: JSON_RPC_VERSION,
|
|
34
|
+
id,
|
|
35
|
+
result: result
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
export function failure(id, code, message, data) {
|
|
39
|
+
return {
|
|
40
|
+
jsonrpc: JSON_RPC_VERSION,
|
|
41
|
+
id,
|
|
42
|
+
error: {
|
|
43
|
+
code,
|
|
44
|
+
message,
|
|
45
|
+
...(data === undefined ? {} : { data: data })
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
export function serialize(response) {
|
|
50
|
+
return `${JSON.stringify(response, null, 2)}\n`;
|
|
51
|
+
}
|
|
52
|
+
function isRequest(value) {
|
|
53
|
+
if (!value || typeof value !== 'object') {
|
|
54
|
+
return false;
|
|
55
|
+
}
|
|
56
|
+
const candidate = value;
|
|
57
|
+
return (candidate.jsonrpc === JSON_RPC_VERSION &&
|
|
58
|
+
typeof candidate.method === 'string' &&
|
|
59
|
+
candidate.method.length > 0);
|
|
60
|
+
}
|
package/dist/src/admin/lib/fs.js
CHANGED
|
@@ -1,30 +1,30 @@
|
|
|
1
|
-
import fs from 'node:fs/promises';
|
|
2
|
-
import path from 'node:path';
|
|
3
|
-
export async function readJsonFile(filePath) {
|
|
4
|
-
const raw = await fs.readFile(filePath, 'utf8');
|
|
5
|
-
return JSON.parse(raw);
|
|
6
|
-
}
|
|
7
|
-
export async function writeJsonFile(filePath, data) {
|
|
8
|
-
const json = JSON.stringify(data, null, 2);
|
|
9
|
-
await fs.writeFile(filePath, json, 'utf8');
|
|
10
|
-
}
|
|
11
|
-
export async function pathExists(targetPath) {
|
|
12
|
-
try {
|
|
13
|
-
await fs.access(targetPath);
|
|
14
|
-
return true;
|
|
15
|
-
}
|
|
16
|
-
catch {
|
|
17
|
-
return false;
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
export async function ensureDir(targetDir) {
|
|
21
|
-
await fs.mkdir(targetDir, { recursive: true });
|
|
22
|
-
}
|
|
23
|
-
export async function copyIfExists(sourcePath, destPath) {
|
|
24
|
-
if (!(await pathExists(sourcePath))) {
|
|
25
|
-
return false;
|
|
26
|
-
}
|
|
27
|
-
await ensureDir(path.dirname(destPath));
|
|
28
|
-
await fs.copyFile(sourcePath, destPath);
|
|
29
|
-
return true;
|
|
30
|
-
}
|
|
1
|
+
import fs from 'node:fs/promises';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
export async function readJsonFile(filePath) {
|
|
4
|
+
const raw = await fs.readFile(filePath, 'utf8');
|
|
5
|
+
return JSON.parse(raw);
|
|
6
|
+
}
|
|
7
|
+
export async function writeJsonFile(filePath, data) {
|
|
8
|
+
const json = JSON.stringify(data, null, 2);
|
|
9
|
+
await fs.writeFile(filePath, json, 'utf8');
|
|
10
|
+
}
|
|
11
|
+
export async function pathExists(targetPath) {
|
|
12
|
+
try {
|
|
13
|
+
await fs.access(targetPath);
|
|
14
|
+
return true;
|
|
15
|
+
}
|
|
16
|
+
catch {
|
|
17
|
+
return false;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
export async function ensureDir(targetDir) {
|
|
21
|
+
await fs.mkdir(targetDir, { recursive: true });
|
|
22
|
+
}
|
|
23
|
+
export async function copyIfExists(sourcePath, destPath) {
|
|
24
|
+
if (!(await pathExists(sourcePath))) {
|
|
25
|
+
return false;
|
|
26
|
+
}
|
|
27
|
+
await ensureDir(path.dirname(destPath));
|
|
28
|
+
await fs.copyFile(sourcePath, destPath);
|
|
29
|
+
return true;
|
|
30
|
+
}
|
|
@@ -1,80 +1,80 @@
|
|
|
1
|
-
import fs from 'node:fs';
|
|
2
|
-
import path from 'node:path';
|
|
3
|
-
import { fileURLToPath } from 'node:url';
|
|
4
|
-
import { JsonRpcException, JSON_RPC_ERRORS } from '../jsonrpc.js';
|
|
5
|
-
const __filename = fileURLToPath(import.meta.url);
|
|
6
|
-
const __dirname = path.dirname(__filename);
|
|
7
|
-
export function getProjectRoot() {
|
|
8
|
-
let root = path.resolve(__dirname, '..', '..', '..');
|
|
9
|
-
if (path.basename(root) === 'dist') {
|
|
10
|
-
root = path.dirname(root);
|
|
11
|
-
}
|
|
12
|
-
console.log('[paths] __dirname:', __dirname);
|
|
13
|
-
console.log('[paths] getProjectRoot:', root);
|
|
14
|
-
return root;
|
|
15
|
-
}
|
|
16
|
-
export function getOpenClawRoot() {
|
|
17
|
-
if (process.env.OPENCLAW_HOME) {
|
|
18
|
-
console.log('[paths] getOpenClawRoot from env:', process.env.OPENCLAW_HOME);
|
|
19
|
-
return path.resolve(process.env.OPENCLAW_HOME);
|
|
20
|
-
}
|
|
21
|
-
const projectRoot = getProjectRoot();
|
|
22
|
-
const configuredRoot = findNearestOpenClawConfigRoot(projectRoot);
|
|
23
|
-
if (configuredRoot) {
|
|
24
|
-
console.log('[paths] getOpenClawRoot from discovered openclaw.json:', configuredRoot);
|
|
25
|
-
return configuredRoot;
|
|
26
|
-
}
|
|
27
|
-
const openclawDir = findAncestorNamed(projectRoot, '.openclaw');
|
|
28
|
-
if (openclawDir) {
|
|
29
|
-
console.log('[paths] getOpenClawRoot from .openclaw ancestor:', openclawDir);
|
|
30
|
-
return openclawDir;
|
|
31
|
-
}
|
|
32
|
-
const parentDir = path.dirname(projectRoot);
|
|
33
|
-
const parentName = path.basename(parentDir);
|
|
34
|
-
console.log('[paths] projectRoot:', projectRoot);
|
|
35
|
-
console.log('[paths] parentDir:', parentDir);
|
|
36
|
-
console.log('[paths] parentName:', parentName);
|
|
37
|
-
if (parentName === 'extensions') {
|
|
38
|
-
const openclawRoot = path.dirname(parentDir);
|
|
39
|
-
console.log('[paths] getOpenClawRoot (extensions):', openclawRoot);
|
|
40
|
-
return openclawRoot;
|
|
41
|
-
}
|
|
42
|
-
const fallbackRoot = path.resolve(projectRoot, '..');
|
|
43
|
-
console.log('[paths] getOpenClawRoot (fallback):', fallbackRoot);
|
|
44
|
-
return fallbackRoot;
|
|
45
|
-
}
|
|
46
|
-
function findNearestOpenClawConfigRoot(startDir) {
|
|
47
|
-
for (const dir of walkAncestors(startDir)) {
|
|
48
|
-
if (fs.existsSync(path.join(dir, 'openclaw.json'))) {
|
|
49
|
-
return dir;
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
return null;
|
|
53
|
-
}
|
|
54
|
-
function findAncestorNamed(startDir, name) {
|
|
55
|
-
for (const dir of walkAncestors(startDir)) {
|
|
56
|
-
if (path.basename(dir) === name) {
|
|
57
|
-
return dir;
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
return null;
|
|
61
|
-
}
|
|
62
|
-
function* walkAncestors(startDir) {
|
|
63
|
-
let current = path.resolve(startDir);
|
|
64
|
-
while (true) {
|
|
65
|
-
yield current;
|
|
66
|
-
const parent = path.dirname(current);
|
|
67
|
-
if (parent === current) {
|
|
68
|
-
return;
|
|
69
|
-
}
|
|
70
|
-
current = parent;
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
export function ensureInside(parentDir, targetPath) {
|
|
74
|
-
const parent = path.resolve(parentDir);
|
|
75
|
-
const target = path.resolve(targetPath);
|
|
76
|
-
if (target !== parent && !target.startsWith(`${parent}${path.sep}`)) {
|
|
77
|
-
throw new JsonRpcException(JSON_RPC_ERRORS.invalidParams, 'Path escapes allowed directory', { parent, target });
|
|
78
|
-
}
|
|
79
|
-
return target;
|
|
80
|
-
}
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { fileURLToPath } from 'node:url';
|
|
4
|
+
import { JsonRpcException, JSON_RPC_ERRORS } from '../jsonrpc.js';
|
|
5
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
6
|
+
const __dirname = path.dirname(__filename);
|
|
7
|
+
export function getProjectRoot() {
|
|
8
|
+
let root = path.resolve(__dirname, '..', '..', '..');
|
|
9
|
+
if (path.basename(root) === 'dist') {
|
|
10
|
+
root = path.dirname(root);
|
|
11
|
+
}
|
|
12
|
+
console.log('[paths] __dirname:', __dirname);
|
|
13
|
+
console.log('[paths] getProjectRoot:', root);
|
|
14
|
+
return root;
|
|
15
|
+
}
|
|
16
|
+
export function getOpenClawRoot() {
|
|
17
|
+
if (process.env.OPENCLAW_HOME) {
|
|
18
|
+
console.log('[paths] getOpenClawRoot from env:', process.env.OPENCLAW_HOME);
|
|
19
|
+
return path.resolve(process.env.OPENCLAW_HOME);
|
|
20
|
+
}
|
|
21
|
+
const projectRoot = getProjectRoot();
|
|
22
|
+
const configuredRoot = findNearestOpenClawConfigRoot(projectRoot);
|
|
23
|
+
if (configuredRoot) {
|
|
24
|
+
console.log('[paths] getOpenClawRoot from discovered openclaw.json:', configuredRoot);
|
|
25
|
+
return configuredRoot;
|
|
26
|
+
}
|
|
27
|
+
const openclawDir = findAncestorNamed(projectRoot, '.openclaw');
|
|
28
|
+
if (openclawDir) {
|
|
29
|
+
console.log('[paths] getOpenClawRoot from .openclaw ancestor:', openclawDir);
|
|
30
|
+
return openclawDir;
|
|
31
|
+
}
|
|
32
|
+
const parentDir = path.dirname(projectRoot);
|
|
33
|
+
const parentName = path.basename(parentDir);
|
|
34
|
+
console.log('[paths] projectRoot:', projectRoot);
|
|
35
|
+
console.log('[paths] parentDir:', parentDir);
|
|
36
|
+
console.log('[paths] parentName:', parentName);
|
|
37
|
+
if (parentName === 'extensions') {
|
|
38
|
+
const openclawRoot = path.dirname(parentDir);
|
|
39
|
+
console.log('[paths] getOpenClawRoot (extensions):', openclawRoot);
|
|
40
|
+
return openclawRoot;
|
|
41
|
+
}
|
|
42
|
+
const fallbackRoot = path.resolve(projectRoot, '..');
|
|
43
|
+
console.log('[paths] getOpenClawRoot (fallback):', fallbackRoot);
|
|
44
|
+
return fallbackRoot;
|
|
45
|
+
}
|
|
46
|
+
function findNearestOpenClawConfigRoot(startDir) {
|
|
47
|
+
for (const dir of walkAncestors(startDir)) {
|
|
48
|
+
if (fs.existsSync(path.join(dir, 'openclaw.json'))) {
|
|
49
|
+
return dir;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return null;
|
|
53
|
+
}
|
|
54
|
+
function findAncestorNamed(startDir, name) {
|
|
55
|
+
for (const dir of walkAncestors(startDir)) {
|
|
56
|
+
if (path.basename(dir) === name) {
|
|
57
|
+
return dir;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
return null;
|
|
61
|
+
}
|
|
62
|
+
function* walkAncestors(startDir) {
|
|
63
|
+
let current = path.resolve(startDir);
|
|
64
|
+
while (true) {
|
|
65
|
+
yield current;
|
|
66
|
+
const parent = path.dirname(current);
|
|
67
|
+
if (parent === current) {
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
current = parent;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
export function ensureInside(parentDir, targetPath) {
|
|
74
|
+
const parent = path.resolve(parentDir);
|
|
75
|
+
const target = path.resolve(targetPath);
|
|
76
|
+
if (target !== parent && !target.startsWith(`${parent}${path.sep}`)) {
|
|
77
|
+
throw new JsonRpcException(JSON_RPC_ERRORS.invalidParams, 'Path escapes allowed directory', { parent, target });
|
|
78
|
+
}
|
|
79
|
+
return target;
|
|
80
|
+
}
|
|
@@ -1,60 +1,60 @@
|
|
|
1
|
-
import path from 'node:path';
|
|
2
|
-
import { readJsonFile } from '../lib/fs.js';
|
|
3
|
-
export const getAgents = async (_params, context) => {
|
|
4
|
-
const configPath = path.join(context.openclawRoot, 'openclaw.json');
|
|
5
|
-
const config = await readJsonFile(configPath);
|
|
6
|
-
return {
|
|
7
|
-
sourceConfigFile: configPath,
|
|
8
|
-
defaultAgentConfig: config.agents?.defaults ?? {},
|
|
9
|
-
namedAgents: config.agents?.list ?? [],
|
|
10
|
-
activeToolProfile: config.tools?.profile ?? null
|
|
11
|
-
};
|
|
12
|
-
};
|
|
13
|
-
export const getConfig = async (params, context) => {
|
|
14
|
-
const configPath = path.join(context.openclawRoot, 'openclaw.json');
|
|
15
|
-
const config = await readJsonFile(configPath);
|
|
16
|
-
const objectParams = isObject(params) ? params : {};
|
|
17
|
-
const section = typeof objectParams.section === 'string' ? objectParams.section : null;
|
|
18
|
-
if (!section) {
|
|
19
|
-
return {
|
|
20
|
-
sourceConfigFile: configPath,
|
|
21
|
-
config: redactSecrets(config)
|
|
22
|
-
};
|
|
23
|
-
}
|
|
24
|
-
const value = config[section];
|
|
25
|
-
return {
|
|
26
|
-
sourceConfigFile: configPath,
|
|
27
|
-
section,
|
|
28
|
-
sectionValue: value === undefined ? null : redactSecrets(value)
|
|
29
|
-
};
|
|
30
|
-
};
|
|
31
|
-
function isObject(value) {
|
|
32
|
-
return Boolean(value) && typeof value === 'object' && !Array.isArray(value);
|
|
33
|
-
}
|
|
34
|
-
function redactSecrets(value) {
|
|
35
|
-
if (Array.isArray(value)) {
|
|
36
|
-
return value.map(redactSecrets);
|
|
37
|
-
}
|
|
38
|
-
if (!value || typeof value !== 'object') {
|
|
39
|
-
return value;
|
|
40
|
-
}
|
|
41
|
-
const result = {};
|
|
42
|
-
for (const [key, nestedValue] of Object.entries(value)) {
|
|
43
|
-
if (isSecretKey(key) && typeof nestedValue === 'string') {
|
|
44
|
-
result[key] = redactString(nestedValue);
|
|
45
|
-
continue;
|
|
46
|
-
}
|
|
47
|
-
result[key] = redactSecrets(nestedValue);
|
|
48
|
-
}
|
|
49
|
-
return result;
|
|
50
|
-
}
|
|
51
|
-
function isSecretKey(key) {
|
|
52
|
-
const normalized = key.toLowerCase();
|
|
53
|
-
return normalized.includes('apikey') || normalized.includes('token') || normalized.includes('secret');
|
|
54
|
-
}
|
|
55
|
-
function redactString(value) {
|
|
56
|
-
if (value.length <= 8) {
|
|
57
|
-
return '********';
|
|
58
|
-
}
|
|
59
|
-
return `${value.slice(0, 4)}***${value.slice(-4)}`;
|
|
60
|
-
}
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { readJsonFile } from '../lib/fs.js';
|
|
3
|
+
export const getAgents = async (_params, context) => {
|
|
4
|
+
const configPath = path.join(context.openclawRoot, 'openclaw.json');
|
|
5
|
+
const config = await readJsonFile(configPath);
|
|
6
|
+
return {
|
|
7
|
+
sourceConfigFile: configPath,
|
|
8
|
+
defaultAgentConfig: config.agents?.defaults ?? {},
|
|
9
|
+
namedAgents: config.agents?.list ?? [],
|
|
10
|
+
activeToolProfile: config.tools?.profile ?? null
|
|
11
|
+
};
|
|
12
|
+
};
|
|
13
|
+
export const getConfig = async (params, context) => {
|
|
14
|
+
const configPath = path.join(context.openclawRoot, 'openclaw.json');
|
|
15
|
+
const config = await readJsonFile(configPath);
|
|
16
|
+
const objectParams = isObject(params) ? params : {};
|
|
17
|
+
const section = typeof objectParams.section === 'string' ? objectParams.section : null;
|
|
18
|
+
if (!section) {
|
|
19
|
+
return {
|
|
20
|
+
sourceConfigFile: configPath,
|
|
21
|
+
config: redactSecrets(config)
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
const value = config[section];
|
|
25
|
+
return {
|
|
26
|
+
sourceConfigFile: configPath,
|
|
27
|
+
section,
|
|
28
|
+
sectionValue: value === undefined ? null : redactSecrets(value)
|
|
29
|
+
};
|
|
30
|
+
};
|
|
31
|
+
function isObject(value) {
|
|
32
|
+
return Boolean(value) && typeof value === 'object' && !Array.isArray(value);
|
|
33
|
+
}
|
|
34
|
+
function redactSecrets(value) {
|
|
35
|
+
if (Array.isArray(value)) {
|
|
36
|
+
return value.map(redactSecrets);
|
|
37
|
+
}
|
|
38
|
+
if (!value || typeof value !== 'object') {
|
|
39
|
+
return value;
|
|
40
|
+
}
|
|
41
|
+
const result = {};
|
|
42
|
+
for (const [key, nestedValue] of Object.entries(value)) {
|
|
43
|
+
if (isSecretKey(key) && typeof nestedValue === 'string') {
|
|
44
|
+
result[key] = redactString(nestedValue);
|
|
45
|
+
continue;
|
|
46
|
+
}
|
|
47
|
+
result[key] = redactSecrets(nestedValue);
|
|
48
|
+
}
|
|
49
|
+
return result;
|
|
50
|
+
}
|
|
51
|
+
function isSecretKey(key) {
|
|
52
|
+
const normalized = key.toLowerCase();
|
|
53
|
+
return normalized.includes('apikey') || normalized.includes('token') || normalized.includes('secret');
|
|
54
|
+
}
|
|
55
|
+
function redactString(value) {
|
|
56
|
+
if (value.length <= 8) {
|
|
57
|
+
return '********';
|
|
58
|
+
}
|
|
59
|
+
return `${value.slice(0, 4)}***${value.slice(-4)}`;
|
|
60
|
+
}
|