bin-home 0.1.0 → 0.1.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.
package/README.md CHANGED
@@ -16,6 +16,41 @@ npm install -g bin-home
16
16
  bin-home <command> [--open]
17
17
  ```
18
18
 
19
+ ### Version & Update
20
+
21
+ ```bash
22
+ # 显示自身版本与线上版本
23
+ bin-home --version
24
+
25
+ # 显示指定命令对应包的版本信息
26
+ bin-home codex --version
27
+
28
+ # 进入更新流程(默认 latest)
29
+ bin-home --update
30
+ ```
31
+
32
+ 示例输出:
33
+
34
+ ```
35
+ 当前版本: 0.1.0
36
+ 线上版本: 0.1.0
37
+ 请输入要更新的版本 (默认 latest):
38
+ ```
39
+
40
+ 指定命令的更新示例:
41
+
42
+ ```bash
43
+ bin-home codex --update
44
+ ```
45
+
46
+ 示例输出:
47
+
48
+ ```
49
+ 当前版本: 0.72.0
50
+ 线上版本: 0.92.0-alpha.9,0.92.0-alpha.8,0.92.0-alpha.7,0.92.0-alpha.5,0.92.0-alpha.4,0.92.0-alpha.3
51
+ 请输入要更新的版本 (默认 latest):
52
+ ```
53
+
19
54
  ### Examples
20
55
 
21
56
  ```bash
package/bin/cli.js CHANGED
@@ -3,6 +3,12 @@ const path = require("path");
3
3
  const validateCommand = require("../lib/commandValidator");
4
4
  const findPackageForCommand = require("../lib/packageFinder");
5
5
  const displayPackageInfo = require("../lib/packageInfoFormatter");
6
+ const {
7
+ fetchOnlineVersions,
8
+ formatVersionOutput,
9
+ promptForVersion,
10
+ runGlobalUpdate
11
+ } = require("../lib/versionUpdate");
6
12
 
7
13
  const COMMAND_NOT_FOUND_EXIT_CODE = 1;
8
14
  const PACKAGE_NOT_FOUND_EXIT_CODE = 2;
@@ -13,14 +19,10 @@ function printHelp() {
13
19
  console.log("Options:");
14
20
  console.log(" --help, -h Show help");
15
21
  console.log(" --version, -v Show version");
22
+ console.log(" --update, -u Update to specified version");
16
23
  console.log(" --open, -o Open npm package page in browser");
17
24
  }
18
25
 
19
- function printVersion() {
20
- const packageJson = require(path.join(__dirname, "..", "package.json"));
21
- console.log(packageJson.version);
22
- }
23
-
24
26
  function parseArgs(argv) {
25
27
  const flags = new Set();
26
28
  let commandName = null;
@@ -37,15 +39,58 @@ function parseArgs(argv) {
37
39
  commandName,
38
40
  help: flags.has("--help") || flags.has("-h"),
39
41
  version: flags.has("--version") || flags.has("-v"),
42
+ update: flags.has("--update") || flags.has("-u"),
40
43
  open: flags.has("--open") || flags.has("-o")
41
44
  };
42
45
  }
43
46
 
47
+ async function resolvePackageInfo(commandName) {
48
+ if (!commandName) {
49
+ const packageJson = require(path.join(__dirname, "..", "package.json"));
50
+ return { packageName: packageJson.name, localVersion: packageJson.version };
51
+ }
52
+
53
+ const commandExists = await validateCommand(commandName);
54
+ if (!commandExists) {
55
+ const error = new Error(`Command '${commandName}' not found in system PATH`);
56
+ error.exitCode = COMMAND_NOT_FOUND_EXIT_CODE;
57
+ throw error;
58
+ }
59
+
60
+ const packageInfo = await findPackageForCommand(commandName);
61
+ if (!packageInfo) {
62
+ const error = new Error(
63
+ `No npm package found for command '${commandName}'. It may not be installed via npm.`
64
+ );
65
+ error.exitCode = PACKAGE_NOT_FOUND_EXIT_CODE;
66
+ throw error;
67
+ }
68
+
69
+ const packageName = packageInfo.packageJson.name || packageInfo.packageName;
70
+ return {
71
+ packageName,
72
+ localVersion: packageInfo.packageJson.version
73
+ };
74
+ }
75
+
76
+ async function showVersionInfo(commandName) {
77
+ const { packageName, localVersion } = await resolvePackageInfo(commandName);
78
+ const onlineVersions = await fetchOnlineVersions(packageName, { limit: 6 });
79
+ console.log(formatVersionOutput(localVersion, onlineVersions));
80
+ return packageName;
81
+ }
82
+
44
83
  async function run() {
45
- const { commandName, help, version, open } = parseArgs(process.argv.slice(2));
84
+ const { commandName, help, version, update, open } = parseArgs(
85
+ process.argv.slice(2)
86
+ );
46
87
 
47
- if (version) {
48
- printVersion();
88
+ if (version || update) {
89
+ const packageName = await showVersionInfo(commandName);
90
+ if (update) {
91
+ const targetVersion = await promptForVersion();
92
+ await runGlobalUpdate(packageName, targetVersion);
93
+ }
49
94
  return;
50
95
  }
51
96
 
@@ -0,0 +1,126 @@
1
+ const { exec } = require("child_process");
2
+ const readline = require("readline");
3
+
4
+ const NPM_VIEW_EXIT_CODE = 5;
5
+ const NPM_UPDATE_EXIT_CODE = 6;
6
+
7
+ function getNpmCommand() {
8
+ return process.platform === "win32" ? "npm.cmd" : "npm";
9
+ }
10
+
11
+ function normalizeVersions(raw) {
12
+ if (!raw) {
13
+ return [];
14
+ }
15
+
16
+ if (Array.isArray(raw)) {
17
+ return raw.filter(Boolean);
18
+ }
19
+
20
+ const text = String(raw).trim();
21
+ if (!text) {
22
+ return [];
23
+ }
24
+
25
+ try {
26
+ const parsed = JSON.parse(text);
27
+ if (Array.isArray(parsed)) {
28
+ return parsed.filter(Boolean);
29
+ }
30
+ } catch (error) {
31
+ // Fall through for non-JSON outputs.
32
+ }
33
+
34
+ return text
35
+ .replace(/[\[\]]/g, "")
36
+ .split(/[\s,]+/)
37
+ .filter(Boolean);
38
+ }
39
+
40
+ function sortNewestFirst(versions) {
41
+ if (!versions.length) {
42
+ return [];
43
+ }
44
+
45
+ const sorted = versions.slice();
46
+ sorted.reverse();
47
+ return sorted;
48
+ }
49
+
50
+ function execCommand(command, execFn, exitCode, errorMessage) {
51
+ return new Promise((resolve, reject) => {
52
+ execFn(
53
+ command,
54
+ { maxBuffer: 10 * 1024 * 1024, windowsHide: true },
55
+ (error, stdout) => {
56
+ if (error) {
57
+ const err = new Error(`${errorMessage}: ${error.message}`);
58
+ err.exitCode = exitCode;
59
+ return reject(err);
60
+ }
61
+ resolve(stdout);
62
+ }
63
+ );
64
+ });
65
+ }
66
+
67
+ async function fetchOnlineVersions(packageName, options = {}) {
68
+ if (options.versionsOverride) {
69
+ const versions = normalizeVersions(options.versionsOverride);
70
+ return sortNewestFirst(versions).slice(0, options.limit || 6);
71
+ }
72
+
73
+ if (process.env.BIN_HOME_TEST_VERSIONS) {
74
+ const versions = normalizeVersions(process.env.BIN_HOME_TEST_VERSIONS);
75
+ return sortNewestFirst(versions).slice(0, options.limit || 6);
76
+ }
77
+
78
+ const npmCommand = getNpmCommand();
79
+ const command = `${npmCommand} view ${packageName} versions --json`;
80
+ const stdout = await execCommand(
81
+ command,
82
+ options.execFn || exec,
83
+ NPM_VIEW_EXIT_CODE,
84
+ `Failed to fetch npm versions for ${packageName}`
85
+ );
86
+ const versions = normalizeVersions(stdout);
87
+ return sortNewestFirst(versions).slice(0, options.limit || 6);
88
+ }
89
+
90
+ function formatVersionOutput(localVersion, versions) {
91
+ const list = Array.isArray(versions) ? versions : [];
92
+ return `当前版本: ${localVersion}\n线上版本: ${list.join(",")}`;
93
+ }
94
+
95
+ function promptForVersion(options = {}) {
96
+ const input = options.input || process.stdin;
97
+ const output = options.output || process.stdout;
98
+ const defaultVersion = options.defaultVersion || "latest";
99
+
100
+ return new Promise((resolve) => {
101
+ const rl = readline.createInterface({ input, output });
102
+ rl.question(`请输入要更新的版本 (默认 ${defaultVersion}): `, (answer) => {
103
+ rl.close();
104
+ const trimmed = answer.trim();
105
+ resolve(trimmed || defaultVersion);
106
+ });
107
+ });
108
+ }
109
+
110
+ async function runGlobalUpdate(packageName, version, options = {}) {
111
+ const npmCommand = getNpmCommand();
112
+ const command = `${npmCommand} i -g ${packageName}@${version}`;
113
+ return execCommand(
114
+ command,
115
+ options.execFn || exec,
116
+ NPM_UPDATE_EXIT_CODE,
117
+ `Failed to update ${packageName}`
118
+ );
119
+ }
120
+
121
+ module.exports = {
122
+ fetchOnlineVersions,
123
+ formatVersionOutput,
124
+ promptForVersion,
125
+ runGlobalUpdate
126
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bin-home",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "Find which global npm package provides a CLI command",
5
5
  "author": "bin-home",
6
6
  "license": "MIT",