@iamsamyiok/agents-chat 3.29.0 → 3.30.0
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/app/lib/agent.js +3 -1
- package/app/lib/kernel-setup.js +43 -0
- package/bin/agents-chat.js +6 -0
- package/package.json +5 -3
- package/scripts/build-exe.js +74 -0
- package/scripts/postinstall.js +10 -0
package/app/lib/agent.js
CHANGED
|
@@ -49,6 +49,8 @@ const KERNEL_DEFS = [
|
|
|
49
49
|
// Windows 下 npm 安装的 CLI 是 .cmd 垫片,Node 18.20+ 禁止直接 spawn,须走 shell
|
|
50
50
|
// 显式路径优先级:AGENTS_CHAT_<ID>_CMD(如 AGENTS_CHAT_OPENCODE_CMD)> PATH 查找
|
|
51
51
|
let detectCache = { ts: 0, map: null };
|
|
52
|
+
// 安装新内核后刷新缓存(否则同进程 10 秒内仍认为未安装)
|
|
53
|
+
function resetDetectCache() { detectCache = { ts: 0, map: null }; }
|
|
52
54
|
|
|
53
55
|
function findCli(def) {
|
|
54
56
|
const custom = process.env[`AGENTS_CHAT_${def.id.toUpperCase()}_CMD`];
|
|
@@ -484,4 +486,4 @@ function spawnMock(args, agent, env, onChunk, scope) {
|
|
|
484
486
|
return child;
|
|
485
487
|
}
|
|
486
488
|
|
|
487
|
-
module.exports = { runAgent, resolveRunner, detectKernels, KERNEL_DEFS, missingHint, describeTool, stopScope, stopAllChildren, resolveCwd, registerChild };
|
|
489
|
+
module.exports = { runAgent, resolveRunner, detectKernels, resetDetectCache, KERNEL_DEFS, missingHint, describeTool, stopScope, stopAllChildren, resolveCwd, registerChild };
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
// 内核自动安装:npm 包安装(postinstall)与 CLI 启动共用
|
|
2
|
+
// 策略:一个内核都没有时自动安装 opencode(默认推荐内核);任一内核已存在则跳过;
|
|
3
|
+
// 单文件 exe 形态无 npm,跳过;AGENTS_CHAT_AUTO_INSTALL=0 可关闭。
|
|
4
|
+
// 原则:任何失败只提示,绝不抛错(postinstall 失败会连带 npm install 整体失败)。
|
|
5
|
+
const { execSync } = require('child_process');
|
|
6
|
+
|
|
7
|
+
// 纯决策函数(单测覆盖):给定 detectKernels() 的 map,判断是否需要自动安装
|
|
8
|
+
function shouldAutoInstall(kernelMap, { standalone = false, disabled = false } = {}) {
|
|
9
|
+
if (standalone) return { need: false, reason: 'standalone' }; // exe 无 npm
|
|
10
|
+
if (disabled) return { need: false, reason: 'disabled' }; // 用户显式关闭
|
|
11
|
+
if (!kernelMap || typeof kernelMap !== 'object' || !Object.keys(kernelMap).length) return { need: false, reason: 'badmap' };
|
|
12
|
+
const anyOk = Object.values(kernelMap).some(k => k && k.ok);
|
|
13
|
+
if (anyOk) return { need: false, reason: 'has-kernel' };
|
|
14
|
+
return { need: true, reason: 'none' };
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
// 执行安装并返回结果;log/inject 可注入(postinstall 用 console,单测用收集器)
|
|
18
|
+
function ensureDefaultKernel({ log = console.log, standalone = !!process.versions.bun || process.env.AGENTS_CHAT_STANDALONE === '1' } = {}) {
|
|
19
|
+
const { detectKernels } = require('./agent');
|
|
20
|
+
const decision = shouldAutoInstall(detectKernels(), {
|
|
21
|
+
standalone,
|
|
22
|
+
disabled: process.env.AGENTS_CHAT_AUTO_INSTALL === '0'
|
|
23
|
+
});
|
|
24
|
+
if (!decision.need) {
|
|
25
|
+
if (decision.reason === 'standalone') log('ℹ 单文件版内置 npm 不可用:未检测到内核时请手动安装 opencode(npm install -g opencode-ai)');
|
|
26
|
+
return { installed: false, reason: decision.reason };
|
|
27
|
+
}
|
|
28
|
+
log('未检测到任何 AI 执行内核,正在自动安装 opencode(约 1-2 分钟,仅此一次)...');
|
|
29
|
+
try {
|
|
30
|
+
execSync('npm install -g opencode-ai', { stdio: 'inherit', timeout: 300000 });
|
|
31
|
+
// 刷新检测缓存,让随后的启动横幅直接看到新内核
|
|
32
|
+
try { require('./agent').resetDetectCache(); } catch { /* 旧版无此函数则忽略 */ }
|
|
33
|
+
log('✓ opencode 安装完成(PATH 由 npm 自动配置,重开终端生效)');
|
|
34
|
+
return { installed: true };
|
|
35
|
+
} catch (err) {
|
|
36
|
+
log('✗ 自动安装失败(通常是全局目录权限不足),请手动执行其中一条:');
|
|
37
|
+
log(' Windows: npm install -g opencode-ai');
|
|
38
|
+
log(' Linux/macOS: sudo npm install -g opencode-ai');
|
|
39
|
+
return { installed: false, reason: 'install-failed', error: err && err.message };
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
module.exports = { shouldAutoInstall, ensureDefaultKernel };
|
package/bin/agents-chat.js
CHANGED
|
@@ -70,6 +70,12 @@ function startServer() {
|
|
|
70
70
|
cleanupDeadProcess(check.pid);
|
|
71
71
|
}
|
|
72
72
|
|
|
73
|
+
// 兜底自动安装:postinstall 被跳过(yarn/pnpm/离线装包)时,首次 start 补装 opencode
|
|
74
|
+
try {
|
|
75
|
+
const { ensureDefaultKernel } = require('../app/lib/kernel-setup');
|
|
76
|
+
ensureDefaultKernel();
|
|
77
|
+
} catch { /* 任何失败不阻塞启动 */ }
|
|
78
|
+
|
|
73
79
|
console.log(`启动 Agents Chat 服务 (端口 ${PORT})...`);
|
|
74
80
|
|
|
75
81
|
const env = {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@iamsamyiok/agents-chat",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.30.0",
|
|
4
4
|
"description": "多智能体群聊工具 - 支持 OpenCode/Claude Code/Codex/pi 内核,微信风格聊天界面",
|
|
5
5
|
"main": "lib/start.js",
|
|
6
6
|
"bin": {
|
|
@@ -9,7 +9,8 @@
|
|
|
9
9
|
"files": [
|
|
10
10
|
"bin",
|
|
11
11
|
"lib",
|
|
12
|
-
"app"
|
|
12
|
+
"app",
|
|
13
|
+
"scripts"
|
|
13
14
|
],
|
|
14
15
|
"keywords": [
|
|
15
16
|
"ai",
|
|
@@ -35,6 +36,7 @@
|
|
|
35
36
|
"scripts": {
|
|
36
37
|
"start": "node app/server.js",
|
|
37
38
|
"test": "node --test \"test/*.test.js\"",
|
|
38
|
-
"build:exe": "node scripts/build-exe.js"
|
|
39
|
+
"build:exe": "node scripts/build-exe.js",
|
|
40
|
+
"postinstall": "node scripts/postinstall.js"
|
|
39
41
|
}
|
|
40
42
|
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* 单文件 exe 构建(bun compile)
|
|
4
|
+
*
|
|
5
|
+
* 用法:
|
|
6
|
+
* node scripts/build-exe.js # 全部平台(windows-x64 / linux-x64 / darwin-x64 / darwin-arm64)
|
|
7
|
+
* node scripts/build-exe.js windows-x64 # 只构建指定平台
|
|
8
|
+
*
|
|
9
|
+
* 产物: dist/agents-chat-<platform>[.exe](Windows 为 .exe)
|
|
10
|
+
* 原理: 先把 app/public/*.html 生成内嵌资源模块(app/lib/embedded-assets.js),
|
|
11
|
+
* 再由 bun build --compile 把 server.js + 内嵌资源打包成单可执行文件;
|
|
12
|
+
* 运行时 serveStatic 优先读内嵌资源,磁盘 public 目录仅开发模式使用。
|
|
13
|
+
*/
|
|
14
|
+
const { execSync } = require('child_process');
|
|
15
|
+
const fs = require('fs');
|
|
16
|
+
const path = require('path');
|
|
17
|
+
|
|
18
|
+
const ROOT = path.join(__dirname, '..');
|
|
19
|
+
const PUB = path.join(ROOT, 'app', 'public');
|
|
20
|
+
const EMBED = path.join(ROOT, 'app', 'lib', 'embedded-assets.js');
|
|
21
|
+
const DIST = path.join(ROOT, 'dist');
|
|
22
|
+
const PKG = require(path.join(ROOT, 'package.json'));
|
|
23
|
+
|
|
24
|
+
const ALL_TARGETS = ['windows-x64', 'linux-x64', 'darwin-x64', 'darwin-arm64'];
|
|
25
|
+
const targets = process.argv[2] ? [process.argv[2]] : ALL_TARGETS;
|
|
26
|
+
for (const t of targets) {
|
|
27
|
+
if (!ALL_TARGETS.includes(t)) {
|
|
28
|
+
console.error(`未知平台: ${t}(可选: ${ALL_TARGETS.join(' / ')})`);
|
|
29
|
+
process.exit(1);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// 1. 生成内嵌资源模块(HTML → JSON 字符串常量,杜绝转义问题)
|
|
34
|
+
const assets = {};
|
|
35
|
+
for (const f of fs.readdirSync(PUB)) {
|
|
36
|
+
if (f.endsWith('.html')) assets[f] = fs.readFileSync(path.join(PUB, f), 'utf8');
|
|
37
|
+
}
|
|
38
|
+
fs.writeFileSync(EMBED, [
|
|
39
|
+
'// 本文件由 scripts/build-exe.js 构建时自动生成,勿手工编辑、勿提交仓库',
|
|
40
|
+
`// 内嵌页面资源(构建于 ${new Date().toISOString()},v${PKG.version})`,
|
|
41
|
+
'module.exports = ' + JSON.stringify(assets, null, 2) + ';',
|
|
42
|
+
''
|
|
43
|
+
].join('\n'));
|
|
44
|
+
console.log(`已生成内嵌资源: ${Object.keys(assets).join('、')}`);
|
|
45
|
+
|
|
46
|
+
// 2. bun compile 各平台
|
|
47
|
+
fs.mkdirSync(DIST, { recursive: true });
|
|
48
|
+
let failed = [];
|
|
49
|
+
for (const t of targets) {
|
|
50
|
+
const out = path.join(DIST, t === 'windows-x64' ? `agents-chat-${t}.exe` : `agents-chat-${t}`);
|
|
51
|
+
console.log(`构建 ${t} -> ${path.relative(ROOT, out)} ...`);
|
|
52
|
+
// windows: 双击运行不弹命令行窗口(日志自动落到 exe 旁 .data/agents-chat.log)
|
|
53
|
+
// 注:--windows-title/icon 需在 Windows 本机构建,交叉编译只加 hide-console
|
|
54
|
+
const extra = t === 'windows-x64' ? ' --windows-hide-console' : '';
|
|
55
|
+
try {
|
|
56
|
+
execSync(`bun build --compile --minify --define "process.env.AGENTS_CHAT_STANDALONE=\\"1\\"" --target=bun-${t}${extra} app/server.js --outfile "${path.relative(ROOT, out)}"`, {
|
|
57
|
+
cwd: ROOT, stdio: 'inherit'
|
|
58
|
+
});
|
|
59
|
+
const mb = (fs.statSync(out).size / 1024 / 1024).toFixed(1);
|
|
60
|
+
console.log(` 完成: ${path.relative(ROOT, out)} (${mb} MB)`);
|
|
61
|
+
} catch (e) {
|
|
62
|
+
console.error(` ${t} 构建失败: ${e.message}`);
|
|
63
|
+
failed.push(t);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// 3. 清理中间产物(下次构建重新生成;源码运行不需要它)
|
|
68
|
+
try { fs.unlinkSync(EMBED); } catch { /* ignore */ }
|
|
69
|
+
|
|
70
|
+
if (failed.length) {
|
|
71
|
+
console.error(`失败平台: ${failed.join(', ')}`);
|
|
72
|
+
process.exit(1);
|
|
73
|
+
}
|
|
74
|
+
console.log('全部构建完成');
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// npm 安装钩子:全无 AI 内核时自动安装 opencode,小白开箱即用
|
|
3
|
+
// 铁律:任何失败只提示不抛错——postinstall 非零退出会连带 npm install 整体报错
|
|
4
|
+
try {
|
|
5
|
+
const { ensureDefaultKernel } = require('../app/lib/kernel-setup');
|
|
6
|
+
const r = ensureDefaultKernel();
|
|
7
|
+
if (r.reason === 'has-kernel') console.log('✓ 已检测到 AI 执行内核,跳过自动安装');
|
|
8
|
+
} catch (err) {
|
|
9
|
+
console.warn('内核自动安装检查跳过:', err && err.message);
|
|
10
|
+
}
|