@brierb/brier-cli 0.0.4 → 0.0.5

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/dist/config.js CHANGED
@@ -1,11 +1,23 @@
1
- import { hostname as getHostname, type as osType, arch, platform } from 'node:os';
1
+ import { hostname as getHostname, type as osType, arch, platform, homedir } from 'node:os';
2
2
  import { execSync } from 'node:child_process';
3
- import { homedir } from 'node:os';
3
+ import { accessSync, constants, readFileSync } from 'node:fs';
4
4
  import { join } from 'node:path';
5
+ import { fileURLToPath } from 'node:url';
5
6
  import { RUNTIME_REGISTRY } from './runtimes.js';
6
7
  export const BRIER_DIR = join(homedir(), '.brier');
7
8
  export const PID_FILE = join(BRIER_DIR, 'daemon.pid');
8
9
  export const LOG_FILE = join(BRIER_DIR, 'daemon.log');
10
+ /** CLI 自身版本(读取 dist 同级的 package.json)。 */
11
+ const readCliVersion = () => {
12
+ try {
13
+ const pkgPath = fileURLToPath(new URL('../package.json', import.meta.url));
14
+ const pkg = JSON.parse(readFileSync(pkgPath, 'utf8'));
15
+ return pkg.version ?? 'unknown';
16
+ }
17
+ catch {
18
+ return 'unknown';
19
+ }
20
+ };
9
21
  export const loadConfig = (options) => {
10
22
  const serverUrl = options.serverUrl ?? process.env.BRIER_SERVER_URL;
11
23
  const token = options.token ?? process.env.BRIER_TOKEN;
@@ -21,6 +33,7 @@ export const loadConfig = (options) => {
21
33
  hostname: getHostname(),
22
34
  os: `${osType()} ${platform()} ${arch()}`,
23
35
  runtimes: detectRuntimes(),
36
+ version: readCliVersion(),
24
37
  };
25
38
  };
26
39
  export const toWsUrl = (serverUrl) => {
@@ -29,16 +42,40 @@ export const toWsUrl = (serverUrl) => {
29
42
  .replace(/^http:\/\//, 'ws://')
30
43
  .replace(/\/$/, '') + '/tunnel');
31
44
  };
45
+ // macOS 自带磁盘分区工具 gpt(8) 位于 /usr/sbin/gpt,会与 OpenAI 的 gpt CLI 同名,
46
+ // macOS 自带磁盘分区工具 gpt(8) 位于 /usr/sbin/gpt,会与 OpenAI CLI 同名;
47
+ // 命中 /sbin、/usr/sbin 视为「未安装」,避免误报。
48
+ const SYSTEM_SBIN_RE = /^\/(usr\/)?sbin\//;
49
+ // shell 内建命令(如 continue、cd、type)会被 `command -v` 返回为无路径的裸名,
50
+ // 不是真实可执行文件,需排除。
51
+ const isRealExecutablePath = (hit) => Boolean(hit) && hit.includes('/') && !SYSTEM_SBIN_RE.test(hit);
52
+ const isExecutable = (file) => {
53
+ try {
54
+ accessSync(file, constants.X_OK);
55
+ return true;
56
+ }
57
+ catch {
58
+ return false;
59
+ }
60
+ };
61
+ const expandHome = (p) => (p.startsWith('~/') ? join(homedir(), p.slice(2)) : p);
32
62
  const detectRuntimes = () => {
33
63
  const runtimes = [];
34
- for (const { name, command } of RUNTIME_REGISTRY) {
64
+ for (const { name, command, fallbacks } of RUNTIME_REGISTRY) {
65
+ let found = false;
35
66
  try {
36
- execSync(`command -v ${command}`, { stdio: 'pipe' });
37
- runtimes.push(name);
67
+ const hit = execSync(`command -v ${command}`, { stdio: 'pipe' }).toString().trim();
68
+ found = isRealExecutablePath(hit);
38
69
  }
39
70
  catch {
40
- // not installed
71
+ // 不在 PATH
41
72
  }
73
+ if (!found) {
74
+ const candidates = fallbacks ?? [`~/.local/bin/${command}`];
75
+ found = candidates.some((p) => isExecutable(expandHome(p)));
76
+ }
77
+ if (found)
78
+ runtimes.push(name);
42
79
  }
43
80
  return runtimes;
44
81
  };
package/dist/index.js CHANGED
File without changes
package/dist/runtimes.js CHANGED
@@ -1,10 +1,16 @@
1
1
  export const RUNTIME_REGISTRY = [
2
- { name: 'Claude Code', command: 'claude' },
2
+ { name: 'Claude Code', command: 'claude', fallbacks: ['~/.claude/bin/claude'] },
3
3
  { name: 'Codex CLI', command: 'codex' },
4
- { name: 'GPT-4o CLI', command: 'gpt' },
4
+ { name: 'OpenAI CLI', command: 'openai' },
5
5
  { name: 'Gemini CLI', command: 'gemini' },
6
6
  { name: 'Cursor CLI', command: 'cursor' },
7
- { name: 'Node.js', command: 'node' },
8
- { name: 'Python', command: 'python3' },
7
+ {
8
+ name: 'OpenCode',
9
+ command: 'opencode',
10
+ fallbacks: ['~/.opencode/bin/opencode', '~/.local/bin/opencode'],
11
+ },
12
+ { name: 'Aider', command: 'aider', fallbacks: ['~/.local/bin/aider'] },
13
+ { name: 'Goose', command: 'goose', fallbacks: ['~/.local/bin/goose'] },
14
+ { name: 'Cody', command: 'cody', fallbacks: ['~/.local/bin/cody'] },
9
15
  ];
10
16
  export const RUNTIME_COMMANDS = Object.fromEntries(RUNTIME_REGISTRY.map((r) => [r.name, r.command]));
@@ -138,6 +138,7 @@ export const createTunnelClient = (config, taskExecutor) => {
138
138
  hostname: config.hostname,
139
139
  os: config.os,
140
140
  runtimes: config.runtimes,
141
+ version: config.version,
141
142
  });
142
143
  });
143
144
  ws.on('message', (data) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@brierb/brier-cli",
3
- "version": "0.0.4",
3
+ "version": "0.0.5",
4
4
  "description": "Brier 平台接入命令行工具:通过加密隧道将本机接入 Brier 远程编码池,接收并执行远程任务",
5
5
  "keywords": [
6
6
  "brier",
@@ -1,6 +1,8 @@
1
1
  export interface RuntimeEntry {
2
2
  name: string;
3
3
  command: string;
4
+ /** 命令不在 PATH 时的兜底可执行文件(~ 开头表示用户主目录),存在即视为已安装 */
5
+ fallbacks?: readonly string[];
4
6
  }
5
7
  export declare const RUNTIME_REGISTRY: readonly RuntimeEntry[];
6
8
  export declare const RUNTIME_COMMANDS: Record<string, string>;
package/types/types.d.ts CHANGED
@@ -7,6 +7,7 @@ export type ClientMessage = {
7
7
  hostname: string;
8
8
  os: string;
9
9
  runtimes: string[];
10
+ version?: string;
10
11
  } | {
11
12
  type: 'heartbeat';
12
13
  timestamp: number;
@@ -64,6 +65,8 @@ export interface DaemonConfig {
64
65
  hostname: string;
65
66
  os: string;
66
67
  runtimes: string[];
68
+ /** CLI 自身版本(package.json),Auth 时上报给服务端展示。 */
69
+ version: string;
67
70
  }
68
71
  export interface PidFileData {
69
72
  pid: number;