@sciagent/cli 1.0.52 → 1.0.54

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
@@ -8,6 +8,7 @@
8
8
  const { spawn } = require('child_process');
9
9
  const path = require('path');
10
10
  const fs = require('fs');
11
+ const os = require('os');
11
12
 
12
13
  // 平台和架构映射
13
14
  const PLATFORM_MAP = {
@@ -47,6 +48,15 @@ function getBinaryPath() {
47
48
  // 尝试从node_modules中查找
48
49
  const binName = platform === 'win32' ? 'sciagent.exe' : 'sciagent';
49
50
 
51
+ // 方法0: 从 ~/.sciagent/bin/ 或 %LOCALAPPDATA%\sciagent\bin 查找(postinstall下载位置)
52
+ const homeBinDir = platform === 'win32'
53
+ ? path.join(process.env.LOCALAPPDATA || os.homedir(), 'sciagent', 'bin')
54
+ : path.join(os.homedir(), '.sciagent', 'bin');
55
+ const homeBinPath = path.join(homeBinDir, binName);
56
+ if (fs.existsSync(homeBinPath)) {
57
+ return homeBinPath;
58
+ }
59
+
50
60
  // 方法1: 从optionalDependencies安装的包中查找
51
61
  try {
52
62
  const packagePath = require.resolve(`${packageName}/bin/${binName}`);
@@ -69,12 +79,12 @@ function getBinaryPath() {
69
79
 
70
80
  // 未找到二进制文件
71
81
  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}`);
82
+ console.error(`Tried locations:`);
83
+ console.error(` ${homeBinPath}`);
84
+ console.error(` ${packageName}/bin/${binName} (npm package)`);
85
+ console.error(` ${localPath} (dev mode)`);
76
86
  console.error('');
77
- console.error('Or install all platform packages:');
87
+ console.error('Please reinstall:');
78
88
  console.error(' npm install -g @sciagent/cli');
79
89
  process.exit(1);
80
90
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sciagent/cli",
3
- "version": "1.0.52",
3
+ "version": "1.0.54",
4
4
  "description": "SciAgent CLI - AI Research Assistant",
5
5
  "main": "index.js",
6
6
  "files": [
@@ -15,11 +15,11 @@
15
15
  "postinstall": "node scripts/postinstall.js"
16
16
  },
17
17
  "optionalDependencies": {
18
- "@sciagent/cli-linux-x64": "1.0.51",
18
+ "@sciagent/cli-linux-x64": "1.0.54",
19
19
  "@sciagent/cli-linux-arm64": "1.0.39",
20
20
  "@sciagent/cli-darwin-x64": "1.0.39",
21
21
  "@sciagent/cli-darwin-arm64": "1.0.39",
22
- "@sciagent/cli-win32-x64": "1.0.52",
22
+ "@sciagent/cli-win32-x64": "1.0.54",
23
23
  "@sciagent/cli-win32-arm64": "1.0.39"
24
24
  },
25
25
  "keywords": [
@@ -27,7 +27,7 @@ const ARCH_MAP = {
27
27
  };
28
28
 
29
29
  // 当前版本号 - 每次发布时同步更新
30
- const CURRENT_VERSION = '1.0.52';
30
+ const CURRENT_VERSION = '1.0.54';
31
31
 
32
32
  // GitHub Releases 回退版本列表(当当前版本的 release 不存在时尝试)
33
33
  const GITHUB_FALLBACK_VERSIONS = ['1.0.50', '1.0.48', '1.0.46', '1.0.40', '1.0.38', '1.0.36'];
@@ -79,10 +79,38 @@ function getCodebuddyBinDir() {
79
79
  }
80
80
  }
81
81
 
82
+ function getHomeBinDir() {
83
+ return process.platform === 'win32'
84
+ ? path.join(process.env.LOCALAPPDATA || os.homedir(), 'sciagent', 'bin')
85
+ : path.join(os.homedir(), '.sciagent', 'bin');
86
+ }
87
+
82
88
  function checkBinaryInstalled(platform, arch) {
83
89
  const packageName = `@sciagent/cli-${platform}-${arch}`;
84
90
  const binName = platform === 'win32' ? 'sciagent.exe' : 'sciagent';
91
+ const homeBinDir = getHomeBinDir();
92
+ const homeBinPath = path.join(homeBinDir, binName);
93
+
94
+ // 检查 ~/.sciagent/bin/ 或 %LOCALAPPDATA%\sciagent\bin
95
+ if (fs.existsSync(homeBinPath)) {
96
+ const stats = fs.statSync(homeBinPath);
97
+ if (stats.size > 10 * 1024 * 1024) {
98
+ // 检查版本文件,版本不匹配则视为未安装(需要重新下载)
99
+ const versionFile = path.join(homeBinDir, '.version');
100
+ if (fs.existsSync(versionFile)) {
101
+ const installedVersion = fs.readFileSync(versionFile, 'utf8').trim();
102
+ if (installedVersion === CURRENT_VERSION) {
103
+ return { installed: true, path: homeBinPath };
104
+ } else {
105
+ console.log(` ℹ️ 已安装版本 ${installedVersion} != 目标版本 ${CURRENT_VERSION},需要更新`);
106
+ }
107
+ } else {
108
+ console.log(` ℹ️ 二进制版本未知,需要重新下载`);
109
+ }
110
+ }
111
+ }
85
112
 
113
+ // 检查 npm 包路径
86
114
  try {
87
115
  const packagePath = require.resolve(`${packageName}/bin/${binName}`);
88
116
  return { installed: true, path: packagePath };
@@ -272,42 +300,34 @@ async function installCodebuddySdk() {
272
300
  const platformKey = `${platform}-${arch}`;
273
301
  const platformTag = PYPI_PLATFORM_MAP[platformKey];
274
302
 
275
- if (!platformTag) {
276
- console.log(`⚠️ 不支持的平台: ${platformKey},跳过 CodeBuddy SDK 安装`);
277
- return false;
278
- }
279
-
280
303
  console.log('');
281
304
  console.log('📦 正在安装 CodeBuddy SDK...');
282
305
 
283
- try {
284
- // 获取版本信息和下载URL
285
- console.log(' 正在获取版本信息...');
286
- const sdkInfo = await getSdkDownloadInfo(platformTag);
287
- console.log(` 版本: ${sdkInfo.version}`);
288
- console.log(` 平台: ${platformTag}`);
289
- console.log(` 文件大小: ${(sdkInfo.size / (1024 * 1024)).toFixed(1)} MB`);
290
-
291
- // 创建临时目录
292
- const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'sciagent-sdk-'));
293
- const wheelFilename = `codebuddy_agent_sdk-${sdkInfo.version}-py3-none-${platformTag}.whl`;
294
- const wheelPath = path.join(tmpDir, wheelFilename);
295
-
296
- // 使用从JSON API获取的正确URL下载
297
- const binaryName = BINARY_NAMES[platform] || 'codebuddy-headless';
298
- const binDir = getCodebuddyBinDir();
299
- const targetPath = path.join(binDir, binaryName);
300
-
301
- console.log(' 正在下载...');
302
- await downloadFile(sdkInfo.url, wheelPath);
303
- console.log(' ✅ 下载成功');
304
-
305
- // 提取二进制文件
306
- console.log(' 正在提取二进制文件...');
307
- fs.mkdirSync(binDir, { recursive: true });
308
-
309
- // 使用 Python 解压 wheel 文件
310
- const extractScript = `
306
+ // 策略1: 从 PyPI 下载 wheel(Linux/macOS 有wheel,Windows 没有)
307
+ if (platformTag) {
308
+ try {
309
+ console.log(' 正在获取版本信息...');
310
+ const sdkInfo = await getSdkDownloadInfo(platformTag);
311
+ console.log(` 版本: ${sdkInfo.version}`);
312
+ console.log(` 平台: ${platformTag}`);
313
+ console.log(` 文件大小: ${(sdkInfo.size / (1024 * 1024)).toFixed(1)} MB`);
314
+
315
+ const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'sciagent-sdk-'));
316
+ const wheelFilename = `codebuddy_agent_sdk-${sdkInfo.version}-py3-none-${platformTag}.whl`;
317
+ const wheelPath = path.join(tmpDir, wheelFilename);
318
+
319
+ const binaryName = BINARY_NAMES[platform] || 'codebuddy-headless';
320
+ const binDir = getCodebuddyBinDir();
321
+ const targetPath = path.join(binDir, binaryName);
322
+
323
+ console.log(' 正在下载...');
324
+ await downloadFile(sdkInfo.url, wheelPath);
325
+ console.log(' ✅ 下载成功');
326
+
327
+ console.log(' 正在提取二进制文件...');
328
+ fs.mkdirSync(binDir, { recursive: true });
329
+
330
+ const extractScript = `
311
331
  import zipfile, sys, os
312
332
  wheel_path = sys.argv[1]
313
333
  target_dir = sys.argv[2]
@@ -327,49 +347,106 @@ with zipfile.ZipFile(wheel_path, 'r') as zf:
327
347
  print(f'Error: {binary_name} not found in wheel')
328
348
  sys.exit(1)
329
349
  `;
330
-
331
- const scriptPath = path.join(tmpDir, 'extract.py');
332
- fs.writeFileSync(scriptPath, extractScript);
333
-
334
- try {
335
- execSync(`python3 "${scriptPath}" "${wheelPath}" "${binDir}" "${binaryName}"`, {
336
- stdio: 'inherit',
337
- timeout: 120000
338
- });
350
+
351
+ const scriptPath = path.join(tmpDir, 'extract.py');
352
+ fs.writeFileSync(scriptPath, extractScript);
353
+
354
+ try {
355
+ execSync(`python3 "${scriptPath}" "${wheelPath}" "${binDir}" "${binaryName}"`, {
356
+ stdio: 'inherit',
357
+ timeout: 120000
358
+ });
359
+ } catch (e) {
360
+ execSync(`python "${scriptPath}" "${wheelPath}" "${binDir}" "${binaryName}"`, {
361
+ stdio: 'inherit',
362
+ timeout: 120000
363
+ });
364
+ }
365
+
366
+ if (fs.existsSync(targetPath)) {
367
+ const stats = fs.statSync(targetPath);
368
+ console.log(`✅ CodeBuddy SDK 安装成功!(PyPI wheel)`);
369
+ console.log(` 路径: ${targetPath}`);
370
+ console.log(` 大小: ${(stats.size / (1024 * 1024)).toFixed(1)} MB`);
371
+
372
+ try { fs.unlinkSync(wheelPath); fs.unlinkSync(scriptPath); fs.rmdirSync(tmpDir); } catch (e) {}
373
+ return true;
374
+ }
339
375
  } catch (e) {
340
- // 如果python3失败,尝试python
341
- execSync(`python "${scriptPath}" "${wheelPath}" "${binDir}" "${binaryName}"`, {
342
- stdio: 'inherit',
343
- timeout: 120000
344
- });
376
+ console.log(` ⚠️ PyPI 下载失败: ${e.message}`);
345
377
  }
378
+ }
379
+
380
+ // 策略2: 从 npm 安装 @tencent-ai/codebuddy-code(全平台支持,国内可访问)
381
+ console.log(' 尝试从 npm 安装 @tencent-ai/codebuddy-code...');
382
+ try {
383
+ execSync('npm install -g @tencent-ai/codebuddy-code', {
384
+ stdio: 'inherit',
385
+ timeout: 300000
386
+ });
346
387
 
347
- // 验证安装
348
- if (fs.existsSync(targetPath)) {
349
- const stats = fs.statSync(targetPath);
350
- const sizeMb = (stats.size / (1024 * 1024)).toFixed(1);
351
- console.log(`✅ CodeBuddy SDK 安装成功!`);
352
- console.log(` 路径: ${targetPath}`);
353
- console.log(` 大小: ${sizeMb} MB`);
388
+ // 查找 npm 安装的 codebuddy-headless.js
389
+ const npmRootResult = execSync('npm root -g', { encoding: 'utf8', timeout: 10000 }).trim();
390
+ const headlessJsPath = path.join(npmRootResult, '@tencent-ai', 'codebuddy-code', 'dist', 'codebuddy-headless.js');
391
+
392
+ if (fs.existsSync(headlessJsPath)) {
393
+ // 创建 wrapper 脚本,让 codebuddy-headless 可以被直接调用
394
+ const binDir = getCodebuddyBinDir();
395
+ fs.mkdirSync(binDir, { recursive: true });
396
+ const binaryName = BINARY_NAMES[platform] || 'codebuddy-headless';
397
+ const wrapperPath = path.join(binDir, binaryName);
354
398
 
355
- // 清理临时文件
356
- try {
357
- fs.unlinkSync(wheelPath);
358
- fs.unlinkSync(scriptPath);
359
- fs.rmdirSync(tmpDir);
360
- } catch (e) {}
399
+ if (platform === 'win32') {
400
+ // Windows: 创建 .cmd wrapper
401
+ const cmdPath = wrapperPath.replace(/\.(exe)?$/, '.cmd');
402
+ fs.writeFileSync(cmdPath, `@echo off\r\nnode "${headlessJsPath}" %*\r\n`);
403
+ // 也创建 .exe placeholder(实际用 .cmd)
404
+ fs.writeFileSync(wrapperPath, `#!/usr/bin/env node\r\nrequire("${headlessJsPath}");`);
405
+ } else {
406
+ fs.writeFileSync(wrapperPath, `#!/usr/bin/env node\nrequire("${headlessJsPath}");`);
407
+ fs.chmodSync(wrapperPath, 0o755);
408
+ }
361
409
 
410
+ console.log(`✅ CodeBuddy SDK 安装成功!(npm @tencent-ai/codebuddy-code)`);
411
+ console.log(` 路径: ${wrapperPath}`);
412
+ console.log(` headless.js: ${headlessJsPath}`);
362
413
  return true;
363
414
  } else {
364
- console.error('❌ 安装验证失败');
365
- return false;
415
+ console.log(` ⚠️ npm 安装成功但未找到 codebuddy-headless.js`);
366
416
  }
417
+ } catch (e) {
418
+ console.log(` ⚠️ npm 安装失败: ${e.message}`);
419
+ }
420
+
421
+ // 策略3: 从 releases 服务器下载
422
+ console.log(' 尝试从 Releases 服务器下载 CodeBuddy SDK...');
423
+ try {
424
+ const binDir = getCodebuddyBinDir();
425
+ fs.mkdirSync(binDir, { recursive: true });
426
+ const binaryName = BINARY_NAMES[platform] || 'codebuddy-headless';
427
+ const targetPath = path.join(binDir, binaryName);
428
+ const downloadUrl = `${RELEASE_SERVER_URL}/api/releases/download/codebuddy/${platform}/${arch}/latest`;
367
429
 
430
+ await downloadFile(downloadUrl, targetPath, 600000);
431
+
432
+ if (fs.existsSync(targetPath)) {
433
+ const stats = fs.statSync(targetPath);
434
+ if (stats.size > 10 * 1024 * 1024) {
435
+ if (platform !== 'win32') {
436
+ fs.chmodSync(targetPath, 0o755);
437
+ }
438
+ console.log(`✅ CodeBuddy SDK 安装成功!(Releases 服务器)`);
439
+ console.log(` 路径: ${targetPath}`);
440
+ return true;
441
+ }
442
+ }
368
443
  } catch (e) {
369
- console.error(`❌ CodeBuddy SDK 安装失败: ${e.message}`);
370
- console.error(' 你可以稍后运行 "sciagent install-sdk" 手动安装');
371
- return false;
444
+ console.log(` ⚠️ Releases 服务器下载失败: ${e.message}`);
372
445
  }
446
+
447
+ console.log('⚠️ CodeBuddy SDK 安装失败,CLI 仍可启动(AI 对话功能将在 SDK 安装后可用)');
448
+ console.log(' 手动安装: npm install -g @tencent-ai/codebuddy-code');
449
+ return false;
373
450
  }
374
451
 
375
452
  // GitHub Releases 配置
@@ -383,7 +460,7 @@ async function downloadFromGitHub(platform, arch, version) {
383
460
  console.log(`\n 📥 尝试从 GitHub Releases 下载...`);
384
461
 
385
462
  // 确定安装目录
386
- const installDir = path.join(os.homedir(), '.sciagent', 'bin');
463
+ const installDir = getHomeBinDir();
387
464
  fs.mkdirSync(installDir, { recursive: true });
388
465
  const targetPath = path.join(installDir, binName);
389
466
 
@@ -487,6 +564,8 @@ async function downloadFromGitHub(platform, arch, version) {
487
564
  if (platform !== 'win32') {
488
565
  fs.chmodSync(targetPath, 0o755);
489
566
  }
567
+ // 写入版本文件
568
+ fs.writeFileSync(path.join(installDir, '.version'), version);
490
569
  return true;
491
570
  }
492
571
  }
@@ -506,7 +585,7 @@ async function downloadFromServer(platform, arch, version) {
506
585
  console.log(`\n 📥 从 Releases 服务器下载: ${downloadUrl}`);
507
586
 
508
587
  // 确定安装目录
509
- const installDir = path.join(os.homedir(), '.sciagent', 'bin');
588
+ const installDir = getHomeBinDir();
510
589
  fs.mkdirSync(installDir, { recursive: true });
511
590
 
512
591
  const targetPath = path.join(installDir, binName);
@@ -525,6 +604,9 @@ async function downloadFromServer(platform, arch, version) {
525
604
  fs.chmodSync(targetPath, 0o755);
526
605
  }
527
606
 
607
+ // 写入版本文件
608
+ fs.writeFileSync(path.join(installDir, '.version'), version);
609
+
528
610
  return true;
529
611
  }
530
612
  }