@zshuangmu/agenthub 0.4.14 → 0.4.16
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/LICENSE +21 -21
- package/README.md +268 -268
- package/package.json +41 -41
- package/src/api-server.js +518 -244
- package/src/cli.js +714 -671
- package/src/commands/api.js +9 -9
- package/src/commands/doctor.js +335 -335
- package/src/commands/info.js +15 -15
- package/src/commands/install.js +56 -56
- package/src/commands/list.js +78 -78
- package/src/commands/pack.js +249 -156
- package/src/commands/publish-remote.js +9 -9
- package/src/commands/publish.js +7 -7
- package/src/commands/rollback.js +59 -59
- package/src/commands/search.js +14 -14
- package/src/commands/serve.js +9 -9
- package/src/commands/stats.js +105 -105
- package/src/commands/uninstall.js +76 -76
- package/src/commands/update.js +54 -54
- package/src/commands/verify.js +133 -133
- package/src/commands/versions.js +75 -75
- package/src/commands/web.js +9 -9
- package/src/index.js +18 -18
- package/src/lib/auth.js +301 -0
- package/src/lib/bundle-transfer.js +58 -58
- package/src/lib/colors.js +60 -60
- package/src/lib/database.js +450 -244
- package/src/lib/debug.js +135 -135
- package/src/lib/fs-utils.js +107 -50
- package/src/lib/html.js +2163 -1824
- package/src/lib/http.js +168 -168
- package/src/lib/install.js +60 -60
- package/src/lib/manifest.js +124 -124
- package/src/lib/openclaw-config.js +40 -40
- package/src/lib/permissions.js +105 -0
- package/src/lib/privacy-engine.js +220 -0
- package/src/lib/registry.js +130 -130
- package/src/lib/remote.js +11 -11
- package/src/lib/security-scanner.js +233 -233
- package/src/lib/signing.js +158 -0
- package/src/lib/version-manager.js +77 -77
- package/src/server.js +176 -176
- package/src/web-server.js +135 -135
package/src/lib/debug.js
CHANGED
|
@@ -1,135 +1,135 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Debug Logger
|
|
3
|
-
* 性能日志工具,用于调试和性能分析
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
let verboseMode = false;
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* 设置 verbose 模式
|
|
10
|
-
* @param {boolean} enabled - 是否启用
|
|
11
|
-
*/
|
|
12
|
-
export function setVerbose(enabled) {
|
|
13
|
-
verboseMode = enabled;
|
|
14
|
-
if (enabled) {
|
|
15
|
-
process.env.AGENTHUB_DEBUG = "true";
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* 获取是否处于 debug 模式
|
|
21
|
-
*/
|
|
22
|
-
export function isDebug() {
|
|
23
|
-
return verboseMode || process.env.AGENTHUB_DEBUG === "true" || process.env.AGENTHUB_DEBUG === "1";
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
const DEBUG = isDebug();
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
* 计时器存储
|
|
30
|
-
*/
|
|
31
|
-
const timers = new Map();
|
|
32
|
-
|
|
33
|
-
/**
|
|
34
|
-
* 开始计时
|
|
35
|
-
* @param {string} label - 计时标签
|
|
36
|
-
*/
|
|
37
|
-
export function time(label) {
|
|
38
|
-
if (!DEBUG) return;
|
|
39
|
-
timers.set(label, Date.now());
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
/**
|
|
43
|
-
* 结束计时并输出
|
|
44
|
-
* @param {string} label - 计时标签
|
|
45
|
-
* @returns {number|null} 耗时毫秒数
|
|
46
|
-
*/
|
|
47
|
-
export function timeEnd(label) {
|
|
48
|
-
if (!DEBUG) return null;
|
|
49
|
-
const start = timers.get(label);
|
|
50
|
-
if (!start) return null;
|
|
51
|
-
const elapsed = Date.now() - start;
|
|
52
|
-
timers.delete(label);
|
|
53
|
-
console.log(`[DEBUG] ${label}: ${elapsed}ms`);
|
|
54
|
-
return elapsed;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
/**
|
|
58
|
-
* 输出调试日志
|
|
59
|
-
* @param {string} message - 日志消息
|
|
60
|
-
* @param {...any} args - 额外参数
|
|
61
|
-
*/
|
|
62
|
-
export function debug(message, ...args) {
|
|
63
|
-
if (!DEBUG) return;
|
|
64
|
-
const timestamp = new Date().toISOString().split("T")[1].slice(0, 12);
|
|
65
|
-
console.log(`[DEBUG ${timestamp}] ${message}`, ...args);
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
/**
|
|
69
|
-
* 输出警告日志
|
|
70
|
-
* @param {string} message - 日志消息
|
|
71
|
-
* @param {...any} args - 额外参数
|
|
72
|
-
*/
|
|
73
|
-
export function warn(message, ...args) {
|
|
74
|
-
if (!DEBUG) return;
|
|
75
|
-
const timestamp = new Date().toISOString().split("T")[1].slice(0, 12);
|
|
76
|
-
console.warn(`[WARN ${timestamp}] ${message}`, ...args);
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
/**
|
|
80
|
-
* 输出错误日志
|
|
81
|
-
* @param {string} message - 日志消息
|
|
82
|
-
* @param {...any} args - 额外参数
|
|
83
|
-
*/
|
|
84
|
-
export function error(message, ...args) {
|
|
85
|
-
if (!DEBUG) return;
|
|
86
|
-
const timestamp = new Date().toISOString().split("T")[1].slice(0, 12);
|
|
87
|
-
console.error(`[ERROR ${timestamp}] ${message}`, ...args);
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
/**
|
|
91
|
-
* 性能追踪装饰器
|
|
92
|
-
* @param {string} label - 标签
|
|
93
|
-
* @param {Function} fn - 要执行的函数
|
|
94
|
-
* @returns {any} 函数执行结果
|
|
95
|
-
*/
|
|
96
|
-
export async function trace(label, fn) {
|
|
97
|
-
time(label);
|
|
98
|
-
try {
|
|
99
|
-
const result = await fn();
|
|
100
|
-
timeEnd(label);
|
|
101
|
-
return result;
|
|
102
|
-
} catch (err) {
|
|
103
|
-
timeEnd(label);
|
|
104
|
-
throw err;
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
/**
|
|
109
|
-
* 同步版本的性能追踪
|
|
110
|
-
* @param {string} label - 标签
|
|
111
|
-
* @param {Function} fn - 要执行的函数
|
|
112
|
-
* @returns {any} 函数执行结果
|
|
113
|
-
*/
|
|
114
|
-
export function traceSync(label, fn) {
|
|
115
|
-
time(label);
|
|
116
|
-
try {
|
|
117
|
-
const result = fn();
|
|
118
|
-
timeEnd(label);
|
|
119
|
-
return result;
|
|
120
|
-
} catch (err) {
|
|
121
|
-
timeEnd(label);
|
|
122
|
-
throw err;
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
export default {
|
|
127
|
-
DEBUG,
|
|
128
|
-
time,
|
|
129
|
-
timeEnd,
|
|
130
|
-
debug,
|
|
131
|
-
warn,
|
|
132
|
-
error,
|
|
133
|
-
trace,
|
|
134
|
-
traceSync,
|
|
135
|
-
};
|
|
1
|
+
/**
|
|
2
|
+
* Debug Logger
|
|
3
|
+
* 性能日志工具,用于调试和性能分析
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
let verboseMode = false;
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* 设置 verbose 模式
|
|
10
|
+
* @param {boolean} enabled - 是否启用
|
|
11
|
+
*/
|
|
12
|
+
export function setVerbose(enabled) {
|
|
13
|
+
verboseMode = enabled;
|
|
14
|
+
if (enabled) {
|
|
15
|
+
process.env.AGENTHUB_DEBUG = "true";
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* 获取是否处于 debug 模式
|
|
21
|
+
*/
|
|
22
|
+
export function isDebug() {
|
|
23
|
+
return verboseMode || process.env.AGENTHUB_DEBUG === "true" || process.env.AGENTHUB_DEBUG === "1";
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const DEBUG = isDebug();
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* 计时器存储
|
|
30
|
+
*/
|
|
31
|
+
const timers = new Map();
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* 开始计时
|
|
35
|
+
* @param {string} label - 计时标签
|
|
36
|
+
*/
|
|
37
|
+
export function time(label) {
|
|
38
|
+
if (!DEBUG) return;
|
|
39
|
+
timers.set(label, Date.now());
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* 结束计时并输出
|
|
44
|
+
* @param {string} label - 计时标签
|
|
45
|
+
* @returns {number|null} 耗时毫秒数
|
|
46
|
+
*/
|
|
47
|
+
export function timeEnd(label) {
|
|
48
|
+
if (!DEBUG) return null;
|
|
49
|
+
const start = timers.get(label);
|
|
50
|
+
if (!start) return null;
|
|
51
|
+
const elapsed = Date.now() - start;
|
|
52
|
+
timers.delete(label);
|
|
53
|
+
console.log(`[DEBUG] ${label}: ${elapsed}ms`);
|
|
54
|
+
return elapsed;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* 输出调试日志
|
|
59
|
+
* @param {string} message - 日志消息
|
|
60
|
+
* @param {...any} args - 额外参数
|
|
61
|
+
*/
|
|
62
|
+
export function debug(message, ...args) {
|
|
63
|
+
if (!DEBUG) return;
|
|
64
|
+
const timestamp = new Date().toISOString().split("T")[1].slice(0, 12);
|
|
65
|
+
console.log(`[DEBUG ${timestamp}] ${message}`, ...args);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* 输出警告日志
|
|
70
|
+
* @param {string} message - 日志消息
|
|
71
|
+
* @param {...any} args - 额外参数
|
|
72
|
+
*/
|
|
73
|
+
export function warn(message, ...args) {
|
|
74
|
+
if (!DEBUG) return;
|
|
75
|
+
const timestamp = new Date().toISOString().split("T")[1].slice(0, 12);
|
|
76
|
+
console.warn(`[WARN ${timestamp}] ${message}`, ...args);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* 输出错误日志
|
|
81
|
+
* @param {string} message - 日志消息
|
|
82
|
+
* @param {...any} args - 额外参数
|
|
83
|
+
*/
|
|
84
|
+
export function error(message, ...args) {
|
|
85
|
+
if (!DEBUG) return;
|
|
86
|
+
const timestamp = new Date().toISOString().split("T")[1].slice(0, 12);
|
|
87
|
+
console.error(`[ERROR ${timestamp}] ${message}`, ...args);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* 性能追踪装饰器
|
|
92
|
+
* @param {string} label - 标签
|
|
93
|
+
* @param {Function} fn - 要执行的函数
|
|
94
|
+
* @returns {any} 函数执行结果
|
|
95
|
+
*/
|
|
96
|
+
export async function trace(label, fn) {
|
|
97
|
+
time(label);
|
|
98
|
+
try {
|
|
99
|
+
const result = await fn();
|
|
100
|
+
timeEnd(label);
|
|
101
|
+
return result;
|
|
102
|
+
} catch (err) {
|
|
103
|
+
timeEnd(label);
|
|
104
|
+
throw err;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* 同步版本的性能追踪
|
|
110
|
+
* @param {string} label - 标签
|
|
111
|
+
* @param {Function} fn - 要执行的函数
|
|
112
|
+
* @returns {any} 函数执行结果
|
|
113
|
+
*/
|
|
114
|
+
export function traceSync(label, fn) {
|
|
115
|
+
time(label);
|
|
116
|
+
try {
|
|
117
|
+
const result = fn();
|
|
118
|
+
timeEnd(label);
|
|
119
|
+
return result;
|
|
120
|
+
} catch (err) {
|
|
121
|
+
timeEnd(label);
|
|
122
|
+
throw err;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
export default {
|
|
127
|
+
DEBUG,
|
|
128
|
+
time,
|
|
129
|
+
timeEnd,
|
|
130
|
+
debug,
|
|
131
|
+
warn,
|
|
132
|
+
error,
|
|
133
|
+
trace,
|
|
134
|
+
traceSync,
|
|
135
|
+
};
|
package/src/lib/fs-utils.js
CHANGED
|
@@ -1,50 +1,107 @@
|
|
|
1
|
-
import { cp, mkdir, readdir, readFile, rm, stat, writeFile } from "node:fs/promises";
|
|
2
|
-
import path from "node:path";
|
|
3
|
-
|
|
4
|
-
export async function ensureDir(dirPath) {
|
|
5
|
-
await mkdir(dirPath, { recursive: true });
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
export async function copyDir(source, destination) {
|
|
9
|
-
await ensureDir(path.dirname(destination));
|
|
10
|
-
await cp(source, destination, { recursive: true });
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
1
|
+
import { cp, mkdir, readdir, readFile, rm, stat, writeFile } from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
|
|
4
|
+
export async function ensureDir(dirPath) {
|
|
5
|
+
await mkdir(dirPath, { recursive: true });
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export async function copyDir(source, destination) {
|
|
9
|
+
await ensureDir(path.dirname(destination));
|
|
10
|
+
await cp(source, destination, { recursive: true });
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* 带过滤的目录复制
|
|
15
|
+
* @param {string} source - 源目录
|
|
16
|
+
* @param {string} destination - 目标目录
|
|
17
|
+
* @param {object} options - 过滤选项
|
|
18
|
+
* @param {string[]} [options.excludeDirs] - 排除的目录名/相对路径
|
|
19
|
+
* @param {string[]} [options.excludeFiles] - 排除的文件名
|
|
20
|
+
* @param {number} [options.maxFileSize] - 跳过超过此大小(字节)的文件
|
|
21
|
+
* @returns {Promise<{copied: string[], skipped: string[]}>} 复制报告
|
|
22
|
+
*/
|
|
23
|
+
export async function copyDirFiltered(source, destination, options = {}) {
|
|
24
|
+
const { excludeDirs = [], excludeFiles = [], maxFileSize = 50 * 1024 * 1024 } = options;
|
|
25
|
+
const report = { copied: [], skipped: [] };
|
|
26
|
+
|
|
27
|
+
async function walkAndCopy(srcDir, destDir, relativeBase = "") {
|
|
28
|
+
await ensureDir(destDir);
|
|
29
|
+
const entries = await readdir(srcDir, { withFileTypes: true });
|
|
30
|
+
|
|
31
|
+
for (const entry of entries) {
|
|
32
|
+
const srcPath = path.join(srcDir, entry.name);
|
|
33
|
+
const destPath = path.join(destDir, entry.name);
|
|
34
|
+
const relativePath = relativeBase ? `${relativeBase}/${entry.name}` : entry.name;
|
|
35
|
+
|
|
36
|
+
if (entry.isDirectory()) {
|
|
37
|
+
// 检查是否在排除目录列表中(匹配目录名或相对路径)
|
|
38
|
+
const shouldExclude = excludeDirs.some((pattern) => {
|
|
39
|
+
const normalized = pattern.replace(/\\/g, "/");
|
|
40
|
+
return entry.name === normalized || relativePath === normalized || relativePath.startsWith(`${normalized}/`);
|
|
41
|
+
});
|
|
42
|
+
if (shouldExclude) {
|
|
43
|
+
report.skipped.push(relativePath);
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
await walkAndCopy(srcPath, destPath, relativePath);
|
|
47
|
+
} else if (entry.isFile()) {
|
|
48
|
+
// 检查排除文件名
|
|
49
|
+
if (excludeFiles.includes(entry.name)) {
|
|
50
|
+
report.skipped.push(relativePath);
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
53
|
+
// 检查文件大小
|
|
54
|
+
const fileStat = await stat(srcPath);
|
|
55
|
+
if (fileStat.size > maxFileSize) {
|
|
56
|
+
report.skipped.push(relativePath);
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
await ensureDir(path.dirname(destPath));
|
|
60
|
+
await cp(srcPath, destPath);
|
|
61
|
+
report.copied.push(relativePath);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
await walkAndCopy(source, destination);
|
|
67
|
+
return report;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export async function readJson(filePath) {
|
|
71
|
+
return JSON.parse(await readFile(filePath, "utf8"));
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export async function writeJson(filePath, value) {
|
|
75
|
+
await ensureDir(path.dirname(filePath));
|
|
76
|
+
await writeFile(filePath, `${JSON.stringify(value, null, 2)}\n`, "utf8");
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export async function pathExists(targetPath) {
|
|
80
|
+
try {
|
|
81
|
+
await stat(targetPath);
|
|
82
|
+
return true;
|
|
83
|
+
} catch {
|
|
84
|
+
return false;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export async function removeDir(dirPath) {
|
|
89
|
+
await rm(dirPath, { recursive: true, force: true });
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export async function countFiles(dirPath) {
|
|
93
|
+
if (!(await pathExists(dirPath))) {
|
|
94
|
+
return 0;
|
|
95
|
+
}
|
|
96
|
+
const entries = await readdir(dirPath, { withFileTypes: true });
|
|
97
|
+
let total = 0;
|
|
98
|
+
for (const entry of entries) {
|
|
99
|
+
const fullPath = path.join(dirPath, entry.name);
|
|
100
|
+
if (entry.isDirectory()) {
|
|
101
|
+
total += await countFiles(fullPath);
|
|
102
|
+
} else {
|
|
103
|
+
total += 1;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
return total;
|
|
107
|
+
}
|