@vincentbanana/bananacli 0.3.0 → 0.4.1

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.
@@ -1,6 +1,7 @@
1
1
  import { createServer } from 'node:http';
2
2
  import { randomBytes } from 'node:crypto';
3
3
  import { mkdir, readdir, readFile, stat, writeFile } from 'node:fs/promises';
4
+ import { existsSync } from 'node:fs';
4
5
  import { extname, join, resolve, dirname } from 'node:path';
5
6
  import { spawn } from 'node:child_process';
6
7
  import { fileURLToPath } from 'node:url';
@@ -41,13 +42,30 @@ const SKIP_DIRS = new Set([
41
42
  'node_modules', '.git', 'dist', 'build', 'out', '.next', '.nuxt', 'coverage', '__pycache__',
42
43
  '.venv', 'venv', 'target', '.cache', '.idea', '.gradle',
43
44
  ]);
44
- /** 静态资源目录:默认是 CLI 包自带的 ui/,GUI 包启动时可以传自己的目录进来。 */
45
- function defaultAssetsDir() {
46
- return join(dirname(fileURLToPath(import.meta.url)), '..', 'ui');
45
+ /**
46
+ * 静态资源目录。同一个包在两种形态下路径不同,所以按候选顺序找第一个真实存在的:
47
+ * - 源码运行:src/server/ -> src/ui
48
+ * - 编译产物:dist/server/ -> dist/ui(构建时由 scripts/copy-ui.mjs 复制)
49
+ * - 兜底:包根 ui/ 或环境变量指定的目录(GUI 独立包用这个)
50
+ */
51
+ export function resolveAssetsDir() {
52
+ const here = dirname(fileURLToPath(import.meta.url));
53
+ const candidates = [
54
+ process.env.BANANA_UI_DIR,
55
+ join(here, '..', 'ui'),
56
+ join(here, '..', '..', 'ui'),
57
+ join(here, '..', '..', 'src', 'ui'),
58
+ ].filter((item) => Boolean(item));
59
+ for (const candidate of candidates) {
60
+ if (existsSync(join(candidate, 'index.html')))
61
+ return candidate;
62
+ }
63
+ // 都找不到时返回默认位置,让 404 报错能指向一个具体路径
64
+ return join(here, '..', 'ui');
47
65
  }
48
66
  let activeAssetsDir = null;
49
67
  function assetRoot() {
50
- return activeAssetsDir ?? defaultAssetsDir();
68
+ return activeAssetsDir ?? resolveAssetsDir();
51
69
  }
52
70
  /** 启动只监听回环地址的本地 GUI 服务;token 保护所有接口。 */
53
71
  export async function startUiServer(options) {
@@ -55,8 +73,13 @@ export async function startUiServer(options) {
55
73
  const token = randomBytes(24).toString('hex');
56
74
  const host = options.host ?? '127.0.0.1';
57
75
  const prefix = `/t/${token}`;
58
- const assets = options.assetsDir ?? defaultAssetsDir();
76
+ const assets = options.assetsDir ?? resolveAssetsDir();
59
77
  activeAssetsDir = assets;
78
+ // 界面资源缺失时界面会是空白页,很容易被误判成「服务挂了」,这里说清原因
79
+ if (!existsSync(join(assets, 'index.html'))) {
80
+ process.stderr.write(`界面资源缺失(${assets}),页面会打不开。\n` +
81
+ '多半是内核版本太旧或安装不完整,重新安装即可:npm install -g @vincentbanana/bananacli\n');
82
+ }
60
83
  let turn = null;
61
84
  const provider = () => createProvider(config.current, config);
62
85
  const backups = (sessionId) => new BackupStore(join(bananaHome(), 'backups'), sessionId);