foliko 1.1.43 → 1.1.45
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/.claude/settings.local.json +7 -1
- package/cli/src/commands/daemon.js +40 -2
- package/cli/src/daemon.js +83 -0
- package/package.json +1 -1
- package/examples/daemon.js +0 -63
|
@@ -211,7 +211,13 @@
|
|
|
211
211
|
"Bash(node -c cli/src/commands/daemon.js 2>&1 && node -c cli/src/index.js 2>&1)",
|
|
212
212
|
"Bash(node -c examples/daemon.js 2>&1)",
|
|
213
213
|
"Bash(node -c cli/src/commands/daemon.js 2>&1)",
|
|
214
|
-
"Bash(node -c cli/src/index.js 2>&1)"
|
|
214
|
+
"Bash(node -c cli/src/index.js 2>&1)",
|
|
215
|
+
"Bash(node -c cli/src/daemon.js 2>&1 && node -c cli/src/commands/daemon.js 2>&1)",
|
|
216
|
+
"Bash(cd cli/src && node -e \"console.log\\(require.resolve\\('../src'\\)\\)\")",
|
|
217
|
+
"Bash(cd cli/src && node -e \"console.log\\(require.resolve\\('../../src'\\)\\)\")",
|
|
218
|
+
"Bash(node -e \"console.log\\(require.resolve\\('./src'\\)\\)\")",
|
|
219
|
+
"Bash(cd /d/Code/foliko/cli/src && node -e \"console.log\\(require.resolve\\('../../src'\\)\\)\")",
|
|
220
|
+
"Bash(node -c cli/src/daemon.js 2>&1)"
|
|
215
221
|
]
|
|
216
222
|
}
|
|
217
223
|
}
|
|
@@ -6,9 +6,10 @@
|
|
|
6
6
|
const fs = require('fs');
|
|
7
7
|
const path = require('path');
|
|
8
8
|
const { spawn } = require('child_process');
|
|
9
|
+
const dotenv = require('dotenv');
|
|
9
10
|
|
|
10
|
-
// Daemon
|
|
11
|
-
const DAEMON_SCRIPT = path.join(__dirname, '
|
|
11
|
+
// Daemon 脚本路径
|
|
12
|
+
const DAEMON_SCRIPT = path.join(__dirname, '../daemon.js');
|
|
12
13
|
|
|
13
14
|
/**
|
|
14
15
|
* 获取指定目录的 PID 文件路径
|
|
@@ -48,6 +49,33 @@ function isRunning(pid) {
|
|
|
48
49
|
}
|
|
49
50
|
}
|
|
50
51
|
|
|
52
|
+
/**
|
|
53
|
+
* 读取 .env 文件并解析为对象
|
|
54
|
+
*/
|
|
55
|
+
function parseEnvFile(envPath) {
|
|
56
|
+
if (!fs.existsSync(envPath)) {
|
|
57
|
+
return {};
|
|
58
|
+
}
|
|
59
|
+
const content = fs.readFileSync(envPath, 'utf8');
|
|
60
|
+
const env = {};
|
|
61
|
+
content.split('\n').forEach((line) => {
|
|
62
|
+
line = line.trim();
|
|
63
|
+
if (!line || line.startsWith('#')) return;
|
|
64
|
+
const eqIndex = line.indexOf('=');
|
|
65
|
+
if (eqIndex > 0) {
|
|
66
|
+
const key = line.substring(0, eqIndex).trim();
|
|
67
|
+
let value = line.substring(eqIndex + 1).trim();
|
|
68
|
+
// 去除引号
|
|
69
|
+
if ((value.startsWith('"') && value.endsWith('"')) ||
|
|
70
|
+
(value.startsWith("'") && value.endsWith("'"))) {
|
|
71
|
+
value = value.slice(1, -1);
|
|
72
|
+
}
|
|
73
|
+
env[key] = value;
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
return env;
|
|
77
|
+
}
|
|
78
|
+
|
|
51
79
|
/**
|
|
52
80
|
* 启动守护进程
|
|
53
81
|
*/
|
|
@@ -61,11 +89,21 @@ async function startDaemon(targetDir) {
|
|
|
61
89
|
return;
|
|
62
90
|
}
|
|
63
91
|
|
|
92
|
+
// 读取 .env 文件(从当前目录)
|
|
93
|
+
const envPath = path.join(process.cwd(), '.env');
|
|
94
|
+
const envVars = parseEnvFile(envPath);
|
|
95
|
+
|
|
96
|
+
// 合并环境变量
|
|
97
|
+
const childEnv = { ...process.env, ...envVars };
|
|
98
|
+
console.log(`已读取环境变量文件: ${envPath}`);
|
|
99
|
+
console.log(`QQ_APP_ID=${envVars.QQ_APP_ID ? '已设置' : '未设置'}`);
|
|
100
|
+
|
|
64
101
|
// 启动子进程
|
|
65
102
|
const child = spawn(process.execPath, [DAEMON_SCRIPT, '--cwd', targetDir], {
|
|
66
103
|
detached: true,
|
|
67
104
|
stdio: 'ignore',
|
|
68
105
|
cwd: targetDir,
|
|
106
|
+
env: childEnv, // 传递完整环境变量(包括 .env 中的变量)
|
|
69
107
|
});
|
|
70
108
|
|
|
71
109
|
// 写入启动日志
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Foliko 后台服务入口
|
|
3
|
+
* 使用 framework.bootstrap() 自动加载 .agent/ 目录配置
|
|
4
|
+
* 持续运行,不退出
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const fs = require('fs');
|
|
8
|
+
const path = require('path');
|
|
9
|
+
|
|
10
|
+
// 解析命令行参数 --cwd <path>
|
|
11
|
+
const cwdArg = process.argv.find((arg) => arg === '--cwd');
|
|
12
|
+
const daemonCwd = cwdArg ? process.argv[process.argv.indexOf(cwdArg) + 1] : process.cwd();
|
|
13
|
+
|
|
14
|
+
// 切换到工作目录
|
|
15
|
+
if (daemonCwd !== process.cwd()) {
|
|
16
|
+
process.chdir(daemonCwd);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// 日志文件
|
|
20
|
+
const LOG_FILE = path.join(process.cwd(), '.foliko.log');
|
|
21
|
+
|
|
22
|
+
// 覆盖 console.log,同时写日志和终端
|
|
23
|
+
const originalLog = console.log;
|
|
24
|
+
const originalError = console.error;
|
|
25
|
+
console.log = (...args) => {
|
|
26
|
+
const msg = `[${new Date().toISOString()}] ` + args.join(' ');
|
|
27
|
+
fs.appendFileSync(LOG_FILE, msg + '\n');
|
|
28
|
+
originalLog.apply(console, args);
|
|
29
|
+
};
|
|
30
|
+
console.error = (...args) => {
|
|
31
|
+
const msg = `[${new Date().toISOString()}] ERROR ` + args.join(' ');
|
|
32
|
+
fs.appendFileSync(LOG_FILE, msg + '\n');
|
|
33
|
+
originalError.apply(console, args);
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
// 覆盖 process.stdout.write,只写日志(捕获框架日志)
|
|
37
|
+
const originalStdoutWrite = process.stdout.write.bind(process.stdout);
|
|
38
|
+
process.stdout.write = (chunk) => {
|
|
39
|
+
fs.appendFileSync(LOG_FILE, chunk.toString());
|
|
40
|
+
return originalStdoutWrite(chunk);
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
// 覆盖 process.stderr.write
|
|
44
|
+
const originalStderrWrite = process.stderr.write.bind(process.stderr);
|
|
45
|
+
process.stderr.write = (chunk) => {
|
|
46
|
+
fs.appendFileSync(LOG_FILE, chunk.toString());
|
|
47
|
+
return originalStderrWrite(chunk);
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
// 环境变量已在 commands/daemon.js 中通过 spawn 传递
|
|
51
|
+
const { Framework } = require('../../src');
|
|
52
|
+
|
|
53
|
+
async function main() {
|
|
54
|
+
console.log('[Foliko] 启动后台服务...');
|
|
55
|
+
|
|
56
|
+
// 创建框架
|
|
57
|
+
const framework = new Framework({ debug: false });
|
|
58
|
+
|
|
59
|
+
// 使用 bootstrap 自动加载所有默认插件
|
|
60
|
+
await framework.bootstrap({
|
|
61
|
+
agentDir: './.agent',
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
console.log('[Foliko] 框架已就绪');
|
|
65
|
+
console.log('[Foliko] 已加载插件:', framework.pluginManager.getAll().map((p) => p.name));
|
|
66
|
+
console.log('[Foliko] 后台服务运行中 (PID: ' + process.pid + ')');
|
|
67
|
+
|
|
68
|
+
// 优雅退出
|
|
69
|
+
const shutdown = async () => {
|
|
70
|
+
console.log('[Foliko] 正在关闭...');
|
|
71
|
+
await framework.destroy();
|
|
72
|
+
console.log('[Foliko] 已关闭');
|
|
73
|
+
process.exit(0);
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
process.on('SIGINT', shutdown);
|
|
77
|
+
process.on('SIGTERM', shutdown);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
main().catch((err) => {
|
|
81
|
+
console.log('[Foliko] 启动失败:', err.message);
|
|
82
|
+
process.exit(1);
|
|
83
|
+
});
|
package/package.json
CHANGED
package/examples/daemon.js
DELETED
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Foliko 后台服务入口
|
|
3
|
-
* 使用 framework.bootstrap() 自动加载 .agent/ 目录配置
|
|
4
|
-
* 持续运行,不退出
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
// 解析命令行参数 --cwd <path>
|
|
8
|
-
const cwdArg = process.argv.find((arg) => arg === '--cwd');
|
|
9
|
-
const daemonCwd = cwdArg ? process.argv[process.argv.indexOf(cwdArg) + 1] : process.cwd();
|
|
10
|
-
|
|
11
|
-
// 切换到工作目录
|
|
12
|
-
if (daemonCwd !== process.cwd()) {
|
|
13
|
-
process.chdir(daemonCwd);
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
// 加载环境变量
|
|
17
|
-
require('dotenv').config({ path: path.join(process.cwd(), '.env') });
|
|
18
|
-
|
|
19
|
-
const { Framework } = require('../src');
|
|
20
|
-
const fs = require('fs');
|
|
21
|
-
const path = require('path');
|
|
22
|
-
|
|
23
|
-
// 重定向输出到日志文件
|
|
24
|
-
const LOG_FILE = path.join(process.cwd(), '.foliko.log');
|
|
25
|
-
const outFd = fs.openSync(LOG_FILE, 'a');
|
|
26
|
-
function log(...args) {
|
|
27
|
-
const msg = `[${new Date().toISOString()}] ` + args.join(' ') + '\n';
|
|
28
|
-
fs.writeSync(outFd, msg);
|
|
29
|
-
}
|
|
30
|
-
process.stdout.write = (chunk) => { log(chunk.toString()); return true; };
|
|
31
|
-
process.stderr.write = (chunk) => { log(chunk.toString()); return true; };
|
|
32
|
-
|
|
33
|
-
async function main() {
|
|
34
|
-
log('[Foliko] 启动后台服务...');
|
|
35
|
-
|
|
36
|
-
// 创建框架
|
|
37
|
-
const framework = new Framework({ debug: false });
|
|
38
|
-
|
|
39
|
-
// 使用 bootstrap 自动加载所有默认插件
|
|
40
|
-
await framework.bootstrap({
|
|
41
|
-
agentDir: './.agent',
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
log('[Foliko] 框架已就绪');
|
|
45
|
-
log('[Foliko] 已加载插件:', framework.pluginManager.getAll().map((p) => p.name));
|
|
46
|
-
log('[Foliko] 后台服务运行中 (PID: ' + process.pid + ')');
|
|
47
|
-
|
|
48
|
-
// 优雅退出
|
|
49
|
-
const shutdown = async () => {
|
|
50
|
-
log('[Foliko] 正在关闭...');
|
|
51
|
-
await framework.destroy();
|
|
52
|
-
log('[Foliko] 已关闭');
|
|
53
|
-
process.exit(0);
|
|
54
|
-
};
|
|
55
|
-
|
|
56
|
-
process.on('SIGINT', shutdown);
|
|
57
|
-
process.on('SIGTERM', shutdown);
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
main().catch((err) => {
|
|
61
|
-
log('[Foliko] 启动失败:', err.message);
|
|
62
|
-
process.exit(1);
|
|
63
|
-
});
|