@sciagent/cli 1.0.33 → 1.0.36

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/bin/sciagent.js CHANGED
@@ -1,164 +1,164 @@
1
- #!/usr/bin/env node
2
-
3
- /**
4
- * SciAgent CLI 薄壳脚本
5
- * 自动识别平台并调用对应的预编译二进制文件
6
- */
7
-
8
- const { spawn } = require('child_process');
9
- const path = require('path');
10
- const fs = require('fs');
11
-
12
- // 平台和架构映射
13
- const PLATFORM_MAP = {
14
- linux: 'linux',
15
- darwin: 'darwin',
16
- win32: 'win32'
17
- };
18
-
19
- const ARCH_MAP = {
20
- x64: 'x64',
21
- arm64: 'arm64',
22
- amd64: 'x64'
23
- };
24
-
25
- /**
26
- * 获取当前平台的二进制文件路径
27
- */
28
- function getBinaryPath() {
29
- const platform = PLATFORM_MAP[process.platform];
30
- const arch = ARCH_MAP[process.arch];
31
-
32
- if (!platform) {
33
- console.error(`Error: Unsupported platform: ${process.platform}`);
34
- console.error('Supported platforms: linux, darwin, win32');
35
- process.exit(1);
36
- }
37
-
38
- if (!arch) {
39
- console.error(`Error: Unsupported architecture: ${process.arch}`);
40
- console.error('Supported architectures: x64, arm64');
41
- process.exit(1);
42
- }
43
-
44
- // 构建包名
45
- const packageName = `@sciagent/cli-${platform}-${arch}`;
46
-
47
- // 尝试从node_modules中查找
48
- const binName = platform === 'win32' ? 'sciagent.exe' : 'sciagent';
49
-
50
- // 方法1: 从optionalDependencies安装的包中查找
51
- try {
52
- const packagePath = require.resolve(`${packageName}/bin/${binName}`);
53
- return packagePath;
54
- } catch (e) {
55
- // 包未安装,继续尝试其他方法
56
- }
57
-
58
- // 方法2: 从本地packages目录查找(开发模式)
59
- const localPath = path.join(__dirname, '..', 'packages', `sciagent-${platform}-${arch}`, 'bin', binName);
60
- if (fs.existsSync(localPath)) {
61
- return localPath;
62
- }
63
-
64
- // 方法3: 从当前目录的bin查找
65
- const binPath = path.join(__dirname, '..', 'bin', platform, arch, binName);
66
- if (fs.existsSync(binPath)) {
67
- return binPath;
68
- }
69
-
70
- // 未找到二进制文件
71
- console.error(`Error: Could not find SciAgent binary for ${platform}-${arch}`);
72
- console.error(`Tried to find package: ${packageName}`);
73
- console.error('');
74
- console.error('Please install the platform-specific package:');
75
- console.error(` npm install ${packageName}`);
76
- console.error('');
77
- console.error('Or install all platform packages:');
78
- console.error(' npm install -g @sciagent/cli');
79
- process.exit(1);
80
- }
81
-
82
- /**
83
- * 主函数
84
- */
85
- function main() {
86
- const binaryPath = getBinaryPath();
87
-
88
- // 检查二进制文件是否存在
89
- if (!fs.existsSync(binaryPath)) {
90
- console.error(`Error: Binary not found at: ${binaryPath}`);
91
- console.error('The package may be corrupted. Please reinstall:');
92
- console.error(' npm install -g @sciagent/cli');
93
- process.exit(1);
94
- }
95
-
96
- // 检查可执行权限(非Windows)
97
- if (process.platform !== 'win32') {
98
- try {
99
- fs.accessSync(binaryPath, fs.constants.X_OK);
100
- } catch (e) {
101
- // 添加可执行权限
102
- fs.chmodSync(binaryPath, 0o755);
103
- }
104
- }
105
-
106
- // 获取命令行参数(跳过node和脚本路径)
107
- const args = process.argv.slice(2);
108
-
109
- // 启动子进程
110
- const child = spawn(binaryPath, args, {
111
- stdio: 'inherit', // 继承父进程的stdio
112
- windowsHide: false // Windows下不隐藏控制台
113
- });
114
-
115
- // 处理子进程退出
116
- child.on('exit', (code, signal) => {
117
- if (signal) {
118
- // 被信号终止
119
- process.kill(process.pid, signal);
120
- } else {
121
- // 正常退出,传递退出码
122
- process.exit(code || 0);
123
- }
124
- });
125
-
126
- // 处理子进程错误
127
- child.on('error', (err) => {
128
- if (err.code === 'ENOENT') {
129
- console.error(`Error: Could not execute binary: ${binaryPath}`);
130
- console.error('The binary may be corrupted or missing.');
131
- } else if (err.code === 'EACCES') {
132
- console.error(`Error: Permission denied: ${binaryPath}`);
133
- console.error('Please check file permissions.');
134
- } else {
135
- console.error(`Error: Failed to start SciAgent: ${err.message}`);
136
- }
137
- process.exit(1);
138
- });
139
-
140
- // 转发信号到子进程
141
- process.on('SIGINT', () => {
142
- child.kill('SIGINT');
143
- });
144
-
145
- process.on('SIGTERM', () => {
146
- child.kill('SIGTERM');
147
- });
148
-
149
- // Windows下处理CTRL+C
150
- if (process.platform === 'win32') {
151
- const readline = require('readline');
152
- const rl = readline.createInterface({
153
- input: process.stdin,
154
- output: process.stdout
155
- });
156
-
157
- rl.on('SIGINT', () => {
158
- child.kill('SIGINT');
159
- });
160
- }
161
- }
162
-
163
- // 运行主函数
164
- main();
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * SciAgent CLI 薄壳脚本
5
+ * 自动识别平台并调用对应的预编译二进制文件
6
+ */
7
+
8
+ const { spawn } = require('child_process');
9
+ const path = require('path');
10
+ const fs = require('fs');
11
+
12
+ // 平台和架构映射
13
+ const PLATFORM_MAP = {
14
+ linux: 'linux',
15
+ darwin: 'darwin',
16
+ win32: 'win32'
17
+ };
18
+
19
+ const ARCH_MAP = {
20
+ x64: 'x64',
21
+ arm64: 'arm64',
22
+ amd64: 'x64'
23
+ };
24
+
25
+ /**
26
+ * 获取当前平台的二进制文件路径
27
+ */
28
+ function getBinaryPath() {
29
+ const platform = PLATFORM_MAP[process.platform];
30
+ const arch = ARCH_MAP[process.arch];
31
+
32
+ if (!platform) {
33
+ console.error(`Error: Unsupported platform: ${process.platform}`);
34
+ console.error('Supported platforms: linux, darwin, win32');
35
+ process.exit(1);
36
+ }
37
+
38
+ if (!arch) {
39
+ console.error(`Error: Unsupported architecture: ${process.arch}`);
40
+ console.error('Supported architectures: x64, arm64');
41
+ process.exit(1);
42
+ }
43
+
44
+ // 构建包名
45
+ const packageName = `@sciagent/cli-${platform}-${arch}`;
46
+
47
+ // 尝试从node_modules中查找
48
+ const binName = platform === 'win32' ? 'sciagent.exe' : 'sciagent';
49
+
50
+ // 方法1: 从optionalDependencies安装的包中查找
51
+ try {
52
+ const packagePath = require.resolve(`${packageName}/bin/${binName}`);
53
+ return packagePath;
54
+ } catch (e) {
55
+ // 包未安装,继续尝试其他方法
56
+ }
57
+
58
+ // 方法2: 从本地packages目录查找(开发模式)
59
+ const localPath = path.join(__dirname, '..', 'packages', `sciagent-${platform}-${arch}`, 'bin', binName);
60
+ if (fs.existsSync(localPath)) {
61
+ return localPath;
62
+ }
63
+
64
+ // 方法3: 从当前目录的bin查找
65
+ const binPath = path.join(__dirname, '..', 'bin', platform, arch, binName);
66
+ if (fs.existsSync(binPath)) {
67
+ return binPath;
68
+ }
69
+
70
+ // 未找到二进制文件
71
+ console.error(`Error: Could not find SciAgent binary for ${platform}-${arch}`);
72
+ console.error(`Tried to find package: ${packageName}`);
73
+ console.error('');
74
+ console.error('Please install the platform-specific package:');
75
+ console.error(` npm install ${packageName}`);
76
+ console.error('');
77
+ console.error('Or install all platform packages:');
78
+ console.error(' npm install -g @sciagent/cli');
79
+ process.exit(1);
80
+ }
81
+
82
+ /**
83
+ * 主函数
84
+ */
85
+ function main() {
86
+ const binaryPath = getBinaryPath();
87
+
88
+ // 检查二进制文件是否存在
89
+ if (!fs.existsSync(binaryPath)) {
90
+ console.error(`Error: Binary not found at: ${binaryPath}`);
91
+ console.error('The package may be corrupted. Please reinstall:');
92
+ console.error(' npm install -g @sciagent/cli');
93
+ process.exit(1);
94
+ }
95
+
96
+ // 检查可执行权限(非Windows)
97
+ if (process.platform !== 'win32') {
98
+ try {
99
+ fs.accessSync(binaryPath, fs.constants.X_OK);
100
+ } catch (e) {
101
+ // 添加可执行权限
102
+ fs.chmodSync(binaryPath, 0o755);
103
+ }
104
+ }
105
+
106
+ // 获取命令行参数(跳过node和脚本路径)
107
+ const args = process.argv.slice(2);
108
+
109
+ // 启动子进程
110
+ const child = spawn(binaryPath, args, {
111
+ stdio: 'inherit', // 继承父进程的stdio
112
+ windowsHide: false // Windows下不隐藏控制台
113
+ });
114
+
115
+ // 处理子进程退出
116
+ child.on('exit', (code, signal) => {
117
+ if (signal) {
118
+ // 被信号终止
119
+ process.kill(process.pid, signal);
120
+ } else {
121
+ // 正常退出,传递退出码
122
+ process.exit(code || 0);
123
+ }
124
+ });
125
+
126
+ // 处理子进程错误
127
+ child.on('error', (err) => {
128
+ if (err.code === 'ENOENT') {
129
+ console.error(`Error: Could not execute binary: ${binaryPath}`);
130
+ console.error('The binary may be corrupted or missing.');
131
+ } else if (err.code === 'EACCES') {
132
+ console.error(`Error: Permission denied: ${binaryPath}`);
133
+ console.error('Please check file permissions.');
134
+ } else {
135
+ console.error(`Error: Failed to start SciAgent: ${err.message}`);
136
+ }
137
+ process.exit(1);
138
+ });
139
+
140
+ // 转发信号到子进程
141
+ process.on('SIGINT', () => {
142
+ child.kill('SIGINT');
143
+ });
144
+
145
+ process.on('SIGTERM', () => {
146
+ child.kill('SIGTERM');
147
+ });
148
+
149
+ // Windows下处理CTRL+C
150
+ if (process.platform === 'win32') {
151
+ const readline = require('readline');
152
+ const rl = readline.createInterface({
153
+ input: process.stdin,
154
+ output: process.stdout
155
+ });
156
+
157
+ rl.on('SIGINT', () => {
158
+ child.kill('SIGINT');
159
+ });
160
+ }
161
+ }
162
+
163
+ // 运行主函数
164
+ main();
package/package.json CHANGED
@@ -1,50 +1,50 @@
1
- {
2
- "name": "@sciagent/cli",
3
- "version": "1.0.33",
4
- "description": "SciAgent CLI - AI Research Assistant",
5
- "main": "index.js",
6
- "files": [
7
- "bin/",
8
- "scripts/",
9
- "index.js"
10
- ],
11
- "bin": {
12
- "sciagent": "bin/sciagent.js"
13
- },
14
- "scripts": {
15
- "postinstall": "node scripts/postinstall.js"
16
- },
17
- "optionalDependencies": {
18
- "@sciagent/cli-linux-x64": "1.0.33",
19
- "@sciagent/cli-linux-arm64": "1.0.33",
20
- "@sciagent/cli-darwin-x64": "1.0.33",
21
- "@sciagent/cli-darwin-arm64": "1.0.33",
22
- "@sciagent/cli-win32-x64": "1.0.33",
23
- "@sciagent/cli-win32-arm64": "1.0.33"
24
- },
25
- "keywords": [
26
- "ai",
27
- "research",
28
- "agent",
29
- "cli",
30
- "codebuddy"
31
- ],
32
- "author": "SciAgent Team",
33
- "license": "MIT",
34
- "repository": {
35
- "type": "git",
36
- "url": "https://gitee.com/garva/research-agent.git"
37
- },
38
- "engines": {
39
- "node": ">=16"
40
- },
41
- "os": [
42
- "linux",
43
- "darwin",
44
- "win32"
45
- ],
46
- "cpu": [
47
- "x64",
48
- "arm64"
49
- ]
50
- }
1
+ {
2
+ "name": "@sciagent/cli",
3
+ "version": "1.0.36",
4
+ "description": "SciAgent CLI - AI Research Assistant",
5
+ "main": "index.js",
6
+ "files": [
7
+ "bin/",
8
+ "scripts/",
9
+ "index.js"
10
+ ],
11
+ "bin": {
12
+ "sciagent": "bin/sciagent.js"
13
+ },
14
+ "scripts": {
15
+ "postinstall": "node scripts/postinstall.js"
16
+ },
17
+ "optionalDependencies": {
18
+ "@sciagent/cli-linux-x64": "1.0.36",
19
+ "@sciagent/cli-linux-arm64": "1.0.33",
20
+ "@sciagent/cli-darwin-x64": "1.0.33",
21
+ "@sciagent/cli-darwin-arm64": "1.0.33",
22
+ "@sciagent/cli-win32-x64": "1.0.36",
23
+ "@sciagent/cli-win32-arm64": "1.0.33"
24
+ },
25
+ "keywords": [
26
+ "ai",
27
+ "research",
28
+ "agent",
29
+ "cli",
30
+ "codebuddy"
31
+ ],
32
+ "author": "SciAgent Team",
33
+ "license": "MIT",
34
+ "repository": {
35
+ "type": "git",
36
+ "url": "https://gitee.com/garva/research-agent.git"
37
+ },
38
+ "engines": {
39
+ "node": ">=16"
40
+ },
41
+ "os": [
42
+ "linux",
43
+ "darwin",
44
+ "win32"
45
+ ],
46
+ "cpu": [
47
+ "x64",
48
+ "arm64"
49
+ ]
50
+ }
package/scripts/chmod.js CHANGED
@@ -1,29 +1,29 @@
1
- #!/usr/bin/env node
2
-
3
- /**
4
- * SciAgent CLI chmod 脚本
5
- * 在Linux/macOS上设置二进制文件的可执行权限
6
- */
7
-
8
- const fs = require('fs');
9
- const path = require('path');
10
-
11
- // 只在非Windows平台上运行
12
- if (process.platform === 'win32') {
13
- process.exit(0);
14
- }
15
-
16
- // 查找二进制文件
17
- const binDir = path.join(__dirname, '..', 'bin');
18
- const binaryName = 'sciagent';
19
- const binaryPath = path.join(binDir, binaryName);
20
-
21
- try {
22
- if (fs.existsSync(binaryPath)) {
23
- // 设置可执行权限 (755)
24
- fs.chmodSync(binaryPath, 0o755);
25
- console.log(`Set executable permission: ${binaryPath}`);
26
- }
27
- } catch (err) {
28
- console.warn(`Warning: Could not set executable permission: ${err.message}`);
29
- }
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * SciAgent CLI chmod 脚本
5
+ * 在Linux/macOS上设置二进制文件的可执行权限
6
+ */
7
+
8
+ const fs = require('fs');
9
+ const path = require('path');
10
+
11
+ // 只在非Windows平台上运行
12
+ if (process.platform === 'win32') {
13
+ process.exit(0);
14
+ }
15
+
16
+ // 查找二进制文件
17
+ const binDir = path.join(__dirname, '..', 'bin');
18
+ const binaryName = 'sciagent';
19
+ const binaryPath = path.join(binDir, binaryName);
20
+
21
+ try {
22
+ if (fs.existsSync(binaryPath)) {
23
+ // 设置可执行权限 (755)
24
+ fs.chmodSync(binaryPath, 0o755);
25
+ console.log(`Set executable permission: ${binaryPath}`);
26
+ }
27
+ } catch (err) {
28
+ console.warn(`Warning: Could not set executable permission: ${err.message}`);
29
+ }
@@ -1,149 +1,479 @@
1
- #!/usr/bin/env node
2
-
3
- /**
4
- * SciAgent CLI postinstall 脚本
5
- * 自动检测并安装平台特定的二进制包
6
- */
7
-
8
- const { execSync } = require('child_process');
9
- const path = require('path');
10
- const fs = require('fs');
11
-
12
- // 平台和架构映射
13
- const PLATFORM_MAP = {
14
- linux: 'linux',
15
- darwin: 'darwin',
16
- win32: 'win32'
17
- };
18
-
19
- const ARCH_MAP = {
20
- x64: 'x64',
21
- arm64: 'arm64',
22
- amd64: 'x64'
23
- };
24
-
25
- // 当前版本号 - 每次发布时同步更新
26
- const CURRENT_VERSION = '1.0.33';
27
-
28
- function checkBinaryInstalled(platform, arch) {
29
- const packageName = `@sciagent/cli-${platform}-${arch}`;
30
- const binName = platform === 'win32' ? 'sciagent.exe' : 'sciagent';
31
-
32
- try {
33
- const packagePath = require.resolve(`${packageName}/bin/${binName}`);
34
- return { installed: true, path: packagePath };
35
- } catch (e) {
36
- return { installed: false };
37
- }
38
- }
39
-
40
- function installBinaryPackage(platform, arch) {
41
- const packageName = `@sciagent/cli-${platform}-${arch}@${CURRENT_VERSION}`;
42
-
43
- console.log(`\n Installing platform binary: ${packageName}`);
44
- console.log(' This may take a moment (downloading ~180MB)...\n');
45
-
46
- try {
47
- // Determine npm global prefix for proper global install
48
- let npmCmd = 'npm';
49
- let installArgs = ['install', '-g', packageName];
50
-
51
- // Check if we're in a global install context
52
- const isGlobal = process.env.npm_config_global === 'true' ||
53
- process.env.npm_lifecycle_event === 'postinstall';
54
-
55
- if (isGlobal) {
56
- // Use npm install -g for global installs
57
- installArgs = ['install', '-g', packageName];
58
- } else {
59
- // Local install
60
- installArgs = ['install', packageName];
61
- }
62
-
63
- execSync(`${npmCmd} ${installArgs.join(' ')}`, {
64
- stdio: 'inherit',
65
- timeout: 300000 // 5 minutes timeout
66
- });
67
-
68
- return true;
69
- } catch (e) {
70
- console.error(`\n ❌ Failed to install ${packageName}`);
71
- console.error(` Error: ${e.message}\n`);
72
- return false;
73
- }
74
- }
75
-
76
- function main() {
77
- const platform = PLATFORM_MAP[process.platform];
78
- const arch = ARCH_MAP[process.arch];
79
-
80
- console.log('');
81
- console.log('╔══════════════════════════════════════════════════════════╗');
82
- console.log('║ SciAgent CLI - Post Install Setup ║');
83
- console.log('╚══════════════════════════════════════════════════════════╝');
84
- console.log('');
85
- console.log(` Platform: ${platform || process.platform}`);
86
- console.log(` Architecture: ${arch || process.arch}`);
87
- console.log(` Node.js: ${process.version}`);
88
- console.log('');
89
-
90
- // 检查平台支持
91
- if (!platform || !arch) {
92
- console.error('❌ Unsupported platform or architecture');
93
- console.error(` Platform: ${process.platform}`);
94
- console.error(` Architecture: ${process.arch}`);
95
- console.error('');
96
- console.error(' Supported platforms: linux, darwin, win32');
97
- console.error(' Supported architectures: x64, arm64');
98
- process.exit(1);
99
- }
100
-
101
- // 检查对应的二进制包是否已安装
102
- const packageName = `@sciagent/cli-${platform}-${arch}`;
103
- const result = checkBinaryInstalled(platform, arch);
104
-
105
- if (result.installed) {
106
- console.log(`✅ Platform binary already installed: ${packageName}`);
107
- console.log(` Path: ${result.path}`);
108
- } else {
109
- console.log(`⚠️ Platform binary not found: ${packageName}`);
110
-
111
- // 尝试自动安装
112
- const success = installBinaryPackage(platform, arch);
113
-
114
- if (!success) {
115
- console.error('');
116
- console.error('╔══════════════════════════════════════════════════════════╗');
117
- console.error('║ Manual Installation Required ║');
118
- console.error('╚══════════════════════════════════════════════════════════╝');
119
- console.error('');
120
- console.error(' Please run this command manually:');
121
- console.error(` npm install -g ${packageName}@${CURRENT_VERSION}`);
122
- console.error('');
123
- process.exit(1);
124
- }
125
-
126
- // Verify installation
127
- const verifyResult = checkBinaryInstalled(platform, arch);
128
- if (verifyResult.installed) {
129
- console.log(`\n✅ Platform binary installed successfully: ${packageName}`);
130
- } else {
131
- console.error(`\n❌ Installation verification failed. Please install manually:`);
132
- console.error(` npm install -g ${packageName}@${CURRENT_VERSION}`);
133
- process.exit(1);
134
- }
135
- }
136
-
137
- console.log('');
138
- console.log('Usage:');
139
- console.log(' sciagent # Start with default ports');
140
- console.log(' sciagent --port 8080 # Custom proxy port');
141
- console.log(' sciagent --no-browser # Don\'t open browser');
142
- console.log(' sciagent --help # Show help');
143
- console.log('');
144
- console.log('Documentation: https://gitee.com/garva/research-agent');
145
- console.log('');
146
- }
147
-
148
- // 运行主函数
149
- main();
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * SciAgent CLI postinstall 脚本
5
+ * 1. 自动检测并安装平台特定的二进制包
6
+ * 2. 自动下载 CodeBuddy SDK 二进制文件(使用国内镜像源)
7
+ */
8
+
9
+ const { execSync } = require('child_process');
10
+ const path = require('path');
11
+ const fs = require('fs');
12
+ const https = require('https');
13
+ const http = require('http');
14
+ const os = require('os');
15
+
16
+ // 平台和架构映射
17
+ const PLATFORM_MAP = {
18
+ linux: 'linux',
19
+ darwin: 'darwin',
20
+ win32: 'win32'
21
+ };
22
+
23
+ const ARCH_MAP = {
24
+ x64: 'x64',
25
+ arm64: 'arm64',
26
+ amd64: 'x64'
27
+ };
28
+
29
+ // 当前版本号 - 每次发布时同步更新
30
+ const CURRENT_VERSION = '1.0.36';
31
+
32
+ // PyPI 镜像源列表(国内优先)
33
+ const PYPI_MIRRORS = [
34
+ 'https://mirrors.cloud.tencent.com/pypi/simple', // 腾讯云
35
+ 'https://mirrors.aliyun.com/pypi/simple', // 阿里云
36
+ 'https://pypi.tuna.tsinghua.edu.cn/simple', // 清华
37
+ 'https://pypi.org/simple' // 官方(备用)
38
+ ];
39
+
40
+ // PyPI 下载URL的镜像(直接下载文件)
41
+ const PYPI_DOWNLOAD_MIRRORS = [
42
+ 'https://mirrors.cloud.tencent.com/pypi/packages', // 腾讯云
43
+ 'https://mirrors.aliyun.com/pypi/packages', // 阿里云
44
+ 'https://pypi.tuna.tsinghua.edu.cn/packages', // 清华
45
+ 'https://files.pythonhosted.org/packages' // 官方(备用)
46
+ ];
47
+
48
+ // PyPI wheel 平台标识映射
49
+ const PYPI_PLATFORM_MAP = {
50
+ 'win32-x64': 'win_amd64',
51
+ 'darwin-arm64': 'macosx_11_0_arm64',
52
+ 'darwin-x64': 'macosx_10_12_x86_64',
53
+ 'linux-x64': 'manylinux_2_17_x86_64',
54
+ 'linux-arm64': 'manylinux_2_17_aarch64'
55
+ };
56
+
57
+ // 二进制文件名
58
+ const BINARY_NAMES = {
59
+ win32: 'codebuddy-headless.exe',
60
+ darwin: 'codebuddy-headless',
61
+ linux: 'codebuddy-headless'
62
+ };
63
+
64
+ function getCodebuddyBinDir() {
65
+ const platform = process.platform;
66
+ if (platform === 'win32') {
67
+ const base = process.env.LOCALAPPDATA || os.homedir();
68
+ return path.join(base, 'sciagent', 'bin');
69
+ } else {
70
+ return path.join(os.homedir(), '.sciagent', 'bin');
71
+ }
72
+ }
73
+
74
+ function checkBinaryInstalled(platform, arch) {
75
+ const packageName = `@sciagent/cli-${platform}-${arch}`;
76
+ const binName = platform === 'win32' ? 'sciagent.exe' : 'sciagent';
77
+
78
+ try {
79
+ const packagePath = require.resolve(`${packageName}/bin/${binName}`);
80
+ return { installed: true, path: packagePath };
81
+ } catch (e) {
82
+ return { installed: false };
83
+ }
84
+ }
85
+
86
+ function checkCodebuddyBinaryInstalled() {
87
+ const binDir = getCodebuddyBinDir();
88
+ const binaryName = BINARY_NAMES[process.platform] || 'codebuddy-headless';
89
+ const binaryPath = path.join(binDir, binaryName);
90
+
91
+ if (fs.existsSync(binaryPath)) {
92
+ const stats = fs.statSync(binaryPath);
93
+ // 检查文件大小是否合理(至少10MB,防止损坏的文件)
94
+ if (stats.size > 10 * 1024 * 1024) {
95
+ return { installed: true, path: binaryPath, size: stats.size };
96
+ }
97
+ }
98
+ return { installed: false };
99
+ }
100
+
101
+ function downloadFile(url, destPath, timeout = 120000) {
102
+ return new Promise((resolve, reject) => {
103
+ const protocol = url.startsWith('https') ? https : http;
104
+ const file = fs.createWriteStream(destPath);
105
+ let completed = false;
106
+
107
+ const timer = setTimeout(() => {
108
+ if (!completed) {
109
+ file.close();
110
+ try { fs.unlinkSync(destPath); } catch (e) {}
111
+ reject(new Error('Download timeout'));
112
+ }
113
+ }, timeout);
114
+
115
+ const request = protocol.get(url, {
116
+ headers: { 'User-Agent': 'sciagent-cli/1.0' },
117
+ timeout: 30000
118
+ }, (response) => {
119
+ // Handle redirects
120
+ if (response.statusCode >= 300 && response.statusCode < 400 && response.headers.location) {
121
+ file.close();
122
+ try { fs.unlinkSync(destPath); } catch (e) {}
123
+ clearTimeout(timer);
124
+ downloadFile(response.headers.location, destPath, timeout).then(resolve).catch(reject);
125
+ return;
126
+ }
127
+
128
+ if (response.statusCode !== 200) {
129
+ file.close();
130
+ try { fs.unlinkSync(destPath); } catch (e) {}
131
+ clearTimeout(timer);
132
+ reject(new Error(`HTTP ${response.statusCode}`));
133
+ return;
134
+ }
135
+
136
+ const totalSize = parseInt(response.headers['content-length'], 10);
137
+ let downloadedSize = 0;
138
+
139
+ response.on('data', (chunk) => {
140
+ downloadedSize += chunk.length;
141
+ if (totalSize) {
142
+ const percent = Math.floor((downloadedSize / totalSize) * 100);
143
+ const mb = (downloadedSize / (1024 * 1024)).toFixed(1);
144
+ const totalMb = (totalSize / (1024 * 1024)).toFixed(1);
145
+ process.stdout.write(`\r 下载进度: ${percent}% (${mb}/${totalMb} MB)`);
146
+ }
147
+ });
148
+
149
+ response.pipe(file);
150
+
151
+ file.on('finish', () => {
152
+ completed = true;
153
+ clearTimeout(timer);
154
+ file.close();
155
+ console.log(); // New line after progress
156
+ resolve();
157
+ });
158
+
159
+ file.on('error', (err) => {
160
+ completed = true;
161
+ clearTimeout(timer);
162
+ file.close();
163
+ try { fs.unlinkSync(destPath); } catch (e) {}
164
+ reject(err);
165
+ });
166
+ });
167
+
168
+ request.on('error', (err) => {
169
+ completed = true;
170
+ clearTimeout(timer);
171
+ file.close();
172
+ try { fs.unlinkSync(destPath); } catch (e) {}
173
+ reject(err);
174
+ });
175
+
176
+ request.on('timeout', () => {
177
+ request.destroy();
178
+ });
179
+ });
180
+ }
181
+
182
+ async function getLatestSdkVersion() {
183
+ // 尝试从多个镜像获取版本信息
184
+ const mirrors = [
185
+ 'https://mirrors.cloud.tencent.com/pypi/pypi/codebuddy-agent-sdk/json',
186
+ 'https://mirrors.aliyun.com/pypi/pypi/codebuddy-agent-sdk/json',
187
+ 'https://pypi.tuna.tsinghua.edu.cn/pypi/codebuddy-agent-sdk/json',
188
+ 'https://pypi.org/pypi/codebuddy-agent-sdk/json'
189
+ ];
190
+
191
+ for (const url of mirrors) {
192
+ try {
193
+ const version = await new Promise((resolve, reject) => {
194
+ const protocol = url.startsWith('https') ? https : http;
195
+ protocol.get(url, {
196
+ headers: { 'User-Agent': 'sciagent-cli/1.0' },
197
+ timeout: 15000
198
+ }, (response) => {
199
+ // Handle redirects
200
+ if (response.statusCode >= 300 && response.statusCode < 400 && response.headers.location) {
201
+ protocol.get(response.headers.location, {
202
+ headers: { 'User-Agent': 'sciagent-cli/1.0' },
203
+ timeout: 15000
204
+ }, (res2) => {
205
+ let data = '';
206
+ res2.on('data', (chunk) => { data += chunk; });
207
+ res2.on('end', () => {
208
+ try {
209
+ const json = JSON.parse(data);
210
+ resolve(json.info.version);
211
+ } catch (e) {
212
+ reject(new Error('Parse error'));
213
+ }
214
+ });
215
+ }).on('error', reject);
216
+ return;
217
+ }
218
+
219
+ let data = '';
220
+ response.on('data', (chunk) => { data += chunk; });
221
+ response.on('end', () => {
222
+ try {
223
+ const json = JSON.parse(data);
224
+ resolve(json.info.version);
225
+ } catch (e) {
226
+ reject(new Error('Parse error'));
227
+ }
228
+ });
229
+ }).on('error', reject);
230
+ });
231
+
232
+ if (version) return version;
233
+ } catch (e) {
234
+ // 继续尝试下一个镜像
235
+ }
236
+ }
237
+
238
+ throw new Error('无法获取SDK版本信息,请检查网络连接');
239
+ }
240
+
241
+ async function installCodebuddySdk() {
242
+ const existing = checkCodebuddyBinaryInstalled();
243
+ if (existing.installed) {
244
+ console.log(`✅ CodeBuddy SDK 已安装: ${existing.path}`);
245
+ return true;
246
+ }
247
+
248
+ const platform = process.platform;
249
+ const arch = process.arch === 'arm64' ? 'arm64' : 'x64';
250
+ const platformKey = `${platform}-${arch}`;
251
+ const platformTag = PYPI_PLATFORM_MAP[platformKey];
252
+
253
+ if (!platformTag) {
254
+ console.log(`⚠️ 不支持的平台: ${platformKey},跳过 CodeBuddy SDK 安装`);
255
+ return false;
256
+ }
257
+
258
+ console.log('');
259
+ console.log('📦 正在安装 CodeBuddy SDK...');
260
+
261
+ try {
262
+ // 获取最新版本
263
+ console.log(' 正在获取版本信息...');
264
+ const version = await getLatestSdkVersion();
265
+ console.log(` 版本: ${version}`);
266
+ console.log(` 平台: ${platformTag}`);
267
+
268
+ // 构建 wheel 文件名
269
+ const wheelFilename = `codebuddy_agent_sdk-${version}-py3-none-${platformTag}.whl`;
270
+
271
+ // 创建临时目录
272
+ const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'sciagent-sdk-'));
273
+ const wheelPath = path.join(tmpDir, wheelFilename);
274
+
275
+ // 尝试从多个镜像下载
276
+ let downloaded = false;
277
+ const binaryName = BINARY_NAMES[platform] || 'codebuddy-headless';
278
+ const binDir = getCodebuddyBinDir();
279
+ const targetPath = path.join(binDir, binaryName);
280
+
281
+ for (const mirror of PYPI_DOWNLOAD_MIRRORS) {
282
+ const downloadUrl = `${mirror}/source/c/codebuddy-agent-sdk/${wheelFilename}`;
283
+
284
+ try {
285
+ console.log(` 尝试下载: ${mirror.split('/')[2]}...`);
286
+ await downloadFile(downloadUrl, wheelPath);
287
+ downloaded = true;
288
+ console.log(' ✅ 下载成功');
289
+ break;
290
+ } catch (e) {
291
+ console.log(` ❌ ${mirror.split('/')[2]}: ${e.message}`);
292
+ continue;
293
+ }
294
+ }
295
+
296
+ if (!downloaded) {
297
+ console.error('❌ 所有镜像源下载失败');
298
+ console.error(' 请检查网络连接,或稍后运行 "sciagent install-sdk" 手动安装');
299
+ return false;
300
+ }
301
+
302
+ // 提取二进制文件
303
+ console.log(' 正在提取二进制文件...');
304
+ fs.mkdirSync(binDir, { recursive: true });
305
+
306
+ // 使用 Python 解压 wheel 文件
307
+ const extractScript = `
308
+ import zipfile, sys, os
309
+ wheel_path = sys.argv[1]
310
+ target_dir = sys.argv[2]
311
+ binary_name = sys.argv[3]
312
+
313
+ with zipfile.ZipFile(wheel_path, 'r') as zf:
314
+ for name in zf.namelist():
315
+ if binary_name in name and '/bin/' in name:
316
+ with zf.open(name) as src:
317
+ target_path = os.path.join(target_dir, binary_name)
318
+ with open(target_path, 'wb') as dst:
319
+ dst.write(src.read())
320
+ if sys.platform != 'win32':
321
+ os.chmod(target_path, 0o755)
322
+ print(f'Extracted: {target_path}')
323
+ sys.exit(0)
324
+ print(f'Error: {binary_name} not found in wheel')
325
+ sys.exit(1)
326
+ `;
327
+
328
+ const scriptPath = path.join(tmpDir, 'extract.py');
329
+ fs.writeFileSync(scriptPath, extractScript);
330
+
331
+ try {
332
+ execSync(`python3 "${scriptPath}" "${wheelPath}" "${binDir}" "${binaryName}"`, {
333
+ stdio: 'inherit',
334
+ timeout: 120000
335
+ });
336
+ } catch (e) {
337
+ // 如果python3失败,尝试python
338
+ execSync(`python "${scriptPath}" "${wheelPath}" "${binDir}" "${binaryName}"`, {
339
+ stdio: 'inherit',
340
+ timeout: 120000
341
+ });
342
+ }
343
+
344
+ // 验证安装
345
+ if (fs.existsSync(targetPath)) {
346
+ const stats = fs.statSync(targetPath);
347
+ const sizeMb = (stats.size / (1024 * 1024)).toFixed(1);
348
+ console.log(`✅ CodeBuddy SDK 安装成功!`);
349
+ console.log(` 路径: ${targetPath}`);
350
+ console.log(` 大小: ${sizeMb} MB`);
351
+
352
+ // 清理临时文件
353
+ try {
354
+ fs.unlinkSync(wheelPath);
355
+ fs.unlinkSync(scriptPath);
356
+ fs.rmdirSync(tmpDir);
357
+ } catch (e) {}
358
+
359
+ return true;
360
+ } else {
361
+ console.error('❌ 安装验证失败');
362
+ return false;
363
+ }
364
+
365
+ } catch (e) {
366
+ console.error(`❌ CodeBuddy SDK 安装失败: ${e.message}`);
367
+ console.error(' 你可以稍后运行 "sciagent install-sdk" 手动安装');
368
+ return false;
369
+ }
370
+ }
371
+
372
+ function installBinaryPackage(platform, arch) {
373
+ const packageName = `@sciagent/cli-${platform}-${arch}@${CURRENT_VERSION}`;
374
+
375
+ console.log(`\n Installing platform binary: ${packageName}`);
376
+ console.log(' This may take a moment...\n');
377
+
378
+ try {
379
+ let npmCmd = 'npm';
380
+ let installArgs = ['install', '-g', packageName];
381
+
382
+ const isGlobal = process.env.npm_config_global === 'true' ||
383
+ process.env.npm_lifecycle_event === 'postinstall';
384
+
385
+ if (!isGlobal) {
386
+ installArgs = ['install', packageName];
387
+ }
388
+
389
+ execSync(`${npmCmd} ${installArgs.join(' ')}`, {
390
+ stdio: 'inherit',
391
+ timeout: 300000
392
+ });
393
+
394
+ return true;
395
+ } catch (e) {
396
+ console.error(`\n ❌ Failed to install ${packageName}`);
397
+ console.error(` Error: ${e.message}\n`);
398
+ return false;
399
+ }
400
+ }
401
+
402
+ async function main() {
403
+ const platform = PLATFORM_MAP[process.platform];
404
+ const arch = ARCH_MAP[process.arch];
405
+
406
+ console.log('');
407
+ console.log('╔══════════════════════════════════════════════════════════╗');
408
+ console.log('║ SciAgent CLI - Post Install Setup ║');
409
+ console.log('╚══════════════════════════════════════════════════════════╝');
410
+ console.log('');
411
+ console.log(` Platform: ${platform || process.platform}`);
412
+ console.log(` Architecture: ${arch || process.arch}`);
413
+ console.log(` Node.js: ${process.version}`);
414
+ console.log('');
415
+
416
+ if (!platform || !arch) {
417
+ console.error('❌ Unsupported platform or architecture');
418
+ console.error(` Platform: ${process.platform}`);
419
+ console.error(` Architecture: ${process.arch}`);
420
+ console.error('');
421
+ console.error(' Supported platforms: linux, darwin, win32');
422
+ console.error(' Supported architectures: x64, arm64');
423
+ process.exit(1);
424
+ }
425
+
426
+ // 检查 SciAgent CLI 二进制
427
+ const packageName = `@sciagent/cli-${platform}-${arch}`;
428
+ const result = checkBinaryInstalled(platform, arch);
429
+
430
+ if (result.installed) {
431
+ console.log(`✅ Platform binary already installed: ${packageName}`);
432
+ console.log(` Path: ${result.path}`);
433
+ } else {
434
+ console.log(`⚠️ Platform binary not found: ${packageName}`);
435
+
436
+ const success = installBinaryPackage(platform, arch);
437
+
438
+ if (!success) {
439
+ console.error('');
440
+ console.error('╔══════════════════════════════════════════════════════════╗');
441
+ console.error('║ Manual Installation Required ║');
442
+ console.error('╚══════════════════════════════════════════════════════════╝');
443
+ console.error('');
444
+ console.error(' Please run this command manually:');
445
+ console.error(` npm install -g ${packageName}@${CURRENT_VERSION}`);
446
+ console.error('');
447
+ process.exit(1);
448
+ }
449
+
450
+ const verifyResult = checkBinaryInstalled(platform, arch);
451
+ if (verifyResult.installed) {
452
+ console.log(`\n✅ Platform binary installed successfully: ${packageName}`);
453
+ } else {
454
+ console.error(`\n❌ Installation verification failed. Please install manually:`);
455
+ console.error(` npm install -g ${packageName}@${CURRENT_VERSION}`);
456
+ process.exit(1);
457
+ }
458
+ }
459
+
460
+ // 安装 CodeBuddy SDK(使用国内镜像)
461
+ await installCodebuddySdk();
462
+
463
+ console.log('');
464
+ console.log('Usage:');
465
+ console.log(' sciagent # Start with default ports');
466
+ console.log(' sciagent --port 8080 # Custom proxy port');
467
+ console.log(' sciagent --no-browser # Don\'t open browser');
468
+ console.log(' sciagent install-sdk # Install CodeBuddy SDK manually');
469
+ console.log(' sciagent --help # Show help');
470
+ console.log('');
471
+ console.log('Documentation: https://gitee.com/garva/research-agent');
472
+ console.log('');
473
+ }
474
+
475
+ // 运行主函数
476
+ main().catch(err => {
477
+ console.error('Post install error:', err.message);
478
+ process.exit(1);
479
+ });