@mindbase/node-tools 1.1.0 → 1.3.7

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 ADDED
@@ -0,0 +1,170 @@
1
+ # @mindbase/node-tools
2
+
3
+ Node.js 开发工具集合,提供清理、Git 日志查看、包发布三个命令。
4
+
5
+ ## 安装
6
+
7
+ ```bash
8
+ npm install -g @mindbase/node-tools
9
+ ```
10
+
11
+ ---
12
+
13
+ ## 命令概览
14
+
15
+ | 命令 | 功能 |
16
+ |------|------|
17
+ | `nodeclear` | 清理 node_modules 和锁文件 |
18
+ | `gitlog` | 交互式 Git 日志查看 |
19
+ | `npmpublish` | 通用包发布工具 |
20
+
21
+ ---
22
+
23
+ ## nodeclear - 清理工具
24
+
25
+ 交互式清理 node_modules 和锁文件的 CLI 工具。
26
+
27
+ ### 基本用法
28
+
29
+ ```bash
30
+ # 清理当前目录
31
+ nodeclear
32
+
33
+ # 清理指定目录
34
+ nodeclear ../my-project
35
+ ```
36
+
37
+ ### 配置管理
38
+
39
+ ```bash
40
+ # 显示当前配置
41
+ nodeclear config --show
42
+
43
+ # 重置为默认配置
44
+ nodeclear config --reset
45
+
46
+ # 编辑配置文件
47
+ nodeclear editConfig
48
+ ```
49
+
50
+ ### 配置项
51
+
52
+ 配置文件位于 `~/.nodeclear.config.json`,支持配置:
53
+
54
+ - 扫描目标(node_modules、锁文件等)
55
+ - 排除目录
56
+ - 是否显示隐藏目录
57
+
58
+ ---
59
+
60
+ ## gitlog - Git 日志查看
61
+
62
+ 交互式 Git 日志查看工具,支持多仓库、多条件筛选。
63
+
64
+ ### 基本用法
65
+
66
+ ```bash
67
+ # 扫描当前目录及子目录的 Git 仓库
68
+ gitlog
69
+
70
+ # 扫描指定目录
71
+ gitlog ~/projects
72
+ ```
73
+
74
+ ### 功能特性
75
+
76
+ - 自动扫描当前目录及子目录的 Git 仓库
77
+ - 支持多选仓库
78
+ - 按作者筛选
79
+ - 按日期范围筛选
80
+ - 表格化展示日志
81
+
82
+ ---
83
+
84
+ ## npmpublish - 发布工具
85
+
86
+ 通用发布工具,支持单项目和工作空间(npm workspace/monorepo)。
87
+
88
+ ### 基本用法
89
+
90
+ ```bash
91
+ # 发布当前项目
92
+ npmpublish
93
+
94
+ # 发布指定项目
95
+ npmpublish ../my-package
96
+
97
+ # 模拟运行(不实际发布)
98
+ npmpublish --dry-run
99
+
100
+ # 指定标签
101
+ npmpublish --tag beta
102
+
103
+ # 跳过构建步骤
104
+ npmpublish --skip-build
105
+
106
+ # 自动确认(非交互模式)
107
+ npmpublish --yes
108
+
109
+ # 多源并行发布
110
+ npmpublish --parallel
111
+ ```
112
+
113
+ ### 全局配置管理
114
+
115
+ ```bash
116
+ # 显示全局配置
117
+ npmpublish config --show
118
+
119
+ # 编辑全局配置
120
+ npmpublish config --edit
121
+
122
+ # 添加注册源
123
+ npmpublish config --add-registry
124
+
125
+ # 删除注册源
126
+ npmpublish config --remove-registry <id>
127
+
128
+ # 添加 token
129
+ npmpublish config --add-token
130
+
131
+ # 删除 token
132
+ npmpublish config --remove-token <id>
133
+
134
+ # 验证 token 有效性
135
+ npmpublish config --validate-token <id>
136
+
137
+ # 重置配置
138
+ npmpublish config --reset
139
+ ```
140
+
141
+ ### 项目配置管理
142
+
143
+ ```bash
144
+ # 显示项目配置
145
+ npmpublish project --show
146
+
147
+ # 编辑项目配置
148
+ npmpublish project --edit
149
+
150
+ # 初始化项目配置
151
+ npmpublish project --init
152
+ ```
153
+
154
+ ### 配置文件
155
+
156
+ - **全局配置**: `~/.node-tools-publish.json` - 存储注册源和 token
157
+ - **项目配置**: `./.node-tools-publish.json` - 存储项目默认配置
158
+
159
+ > 注意: 请将 `.node-tools-publish.json` 添加到 `.gitignore`
160
+
161
+ ---
162
+
163
+ ## 系统要求
164
+
165
+ - Node.js >= 16.0.0
166
+ - Git(gitlog 命令需要)
167
+
168
+ ## License
169
+
170
+ MIT
package/bin/clear.js CHANGED
@@ -2,8 +2,7 @@
2
2
  const { Command } = require("commander");
3
3
  const { resolve } = require("path");
4
4
  const { scan } = require("../src/clear/scanner.js");
5
- const { clean } = require("../src/clear/cleaner.js");
6
- const { selectItems, confirmDelete, showResult } = require("../src/clear/ui.js");
5
+ const { runCleanFlow } = require("../src/clear/ui.js");
7
6
  const { getConfig, resetConfig, showConfig, editConfig } = require("../src/clear/config.js");
8
7
 
9
8
  const program = new Command();
@@ -18,8 +17,6 @@ program
18
17
  .argument("[path]", "要清理的目录路径", ".")
19
18
  .action(async (path) => {
20
19
  const targetPath = resolve(path);
21
- console.log(`扫描目录: ${targetPath}\n`);
22
-
23
20
  const config = getConfig();
24
21
  const items = scan(targetPath, config);
25
22
 
@@ -28,22 +25,16 @@ program
28
25
  return;
29
26
  }
30
27
 
31
- // 显示多选界面
32
- const selected = await selectItems(items);
28
+ // 全程备用屏幕执行
29
+ const stats = await runCleanFlow(targetPath, items);
33
30
 
34
- if (selected.length === 0) {
35
- console.log("未选择任何内容");
36
- return;
31
+ // 主终端只输出最终摘要
32
+ if (stats) {
33
+ console.log(
34
+ `✓ 清理完成: 成功 ${stats.success} 项` +
35
+ (stats.failed > 0 ? `, 失败 ${stats.failed} 项` : '')
36
+ );
37
37
  }
38
-
39
- // 确认删除
40
- const confirmed = await confirmDelete(selected);
41
- if (!confirmed) return;
42
-
43
- // 执行删除
44
- console.log("\n执行删除中...");
45
- const stats = clean(selected);
46
- await showResult(stats);
47
38
  });
48
39
 
49
40
  // config 子命令
package/bin/publish.js ADDED
@@ -0,0 +1,236 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Publish 命令 CLI 入口
4
+ * 通用发布工具,支持单项目和工作空间模式
5
+ */
6
+
7
+ const { Command } = require('commander');
8
+ const { resolve } = require('path');
9
+ const { runPublishFlow } = require('../src/publish/ui.js');
10
+ const { GlobalConfig } = require('../src/publish/registry/global-config.js');
11
+ const { ProjectConfig } = require('../src/publish/registry/project-config.js');
12
+ const { RegistryManager } = require('../src/publish/registry/registry-manager.js');
13
+ const chalk = require('chalk');
14
+ const prompts = require('prompts');
15
+
16
+ const program = new Command();
17
+
18
+ program
19
+ .name('node-tools-publish')
20
+ .description('通用发布工具,支持单项目和工作空间(npm workspace/monorepo)')
21
+ .version('1.0.0');
22
+
23
+ // 默认命令 - 执行发布
24
+ program
25
+ .argument('[path]', '要发布的目录路径', '.')
26
+ .option('--dry-run', '模拟运行,不实际发布')
27
+ .option('--yes', '自动确认所有提示(非交互模式)')
28
+ .action(async (path, options) => {
29
+ const targetPath = resolve(path);
30
+
31
+ try {
32
+ await runPublishFlow(targetPath, options);
33
+ } catch (error) {
34
+ console.error(chalk.red(`\n错误: ${error.message}`));
35
+ if (error.stack) {
36
+ console.error(chalk.gray(error.stack));
37
+ }
38
+ process.exit(1);
39
+ }
40
+ });
41
+
42
+ // config 子命令 - 全局配置管理
43
+ program
44
+ .command('config')
45
+ .description('全局配置管理(源和 token)')
46
+ .option('--show', '显示全局配置')
47
+ .option('--edit', '编辑全局配置')
48
+ .option('--add-registry', '添加注册源')
49
+ .option('--remove-registry <id>', '删除注册源')
50
+ .option('--add-token', '添加 token')
51
+ .option('--remove-token <id>', '删除 token')
52
+ .option('--validate-token <id>', '验证 token 有效性')
53
+ .option('--reset', '重置为默认配置')
54
+ .action(async (options) => {
55
+ const globalConfig = new GlobalConfig();
56
+
57
+ try {
58
+ if (options.show) {
59
+ globalConfig.showConfig();
60
+ } else if (options.edit) {
61
+ globalConfig.editConfig();
62
+ } else if (options.addRegistry) {
63
+ // 添加注册源
64
+ const questions = [
65
+ {
66
+ type: 'text',
67
+ name: 'id',
68
+ message: '注册源 ID',
69
+ validate: value => value ? true : 'ID 不能为空'
70
+ },
71
+ {
72
+ type: 'text',
73
+ name: 'name',
74
+ message: '注册源名称',
75
+ validate: value => value ? true : '名称不能为空'
76
+ },
77
+ {
78
+ type: 'select',
79
+ name: 'type',
80
+ message: '注册源类型',
81
+ choices: [
82
+ { title: 'npm(npm 兼容源)', value: 'npm' },
83
+ { title: 'codeup(Codeup 内部源)', value: 'codeup' }
84
+ ]
85
+ },
86
+ {
87
+ type: 'text',
88
+ name: 'url',
89
+ message: '注册源 URL',
90
+ validate: value => value ? true : 'URL 不能为空'
91
+ }
92
+ ];
93
+
94
+ const { id, name, type, url } = await prompts(questions);
95
+ globalConfig.addRegistry(id, name, type, url);
96
+ console.log(chalk.green(`\n✓ 添加注册源成功: ${name}`));
97
+ } else if (options.removeRegistry) {
98
+ globalConfig.removeRegistry(options.removeRegistry);
99
+ console.log(chalk.green(`\n✓ 删除注册源: ${options.removeRegistry}`));
100
+ } else if (options.addToken) {
101
+ // 添加 token
102
+ const registries = globalConfig.getRegistries();
103
+ if (registries.length === 0) {
104
+ console.log(chalk.red('\n错误: 请先添加注册源'));
105
+ return;
106
+ }
107
+
108
+ const questions = [
109
+ {
110
+ type: 'select',
111
+ name: 'registryId',
112
+ message: '选择注册源',
113
+ choices: registries.map(r => ({
114
+ title: `${r.name} (${r.id})`,
115
+ value: r.id
116
+ }))
117
+ },
118
+ {
119
+ type: 'text',
120
+ name: 'name',
121
+ message: 'Token 名称',
122
+ validate: value => value ? true : '名称不能为空'
123
+ },
124
+ {
125
+ type: 'password',
126
+ name: 'token',
127
+ message: 'Token 值',
128
+ validate: value => value ? true : 'Token 不能为空'
129
+ }
130
+ ];
131
+
132
+ const { registryId, name, token } = await prompts(questions);
133
+ const tokenId = await globalConfig.addToken(registryId, name, token);
134
+ console.log(chalk.green(`\n✓ 添加 token 成功: ${name} (${tokenId})`));
135
+ } else if (options.removeToken) {
136
+ await globalConfig.removeToken(options.removeToken);
137
+ console.log(chalk.green(`\n✓ 删除 token: ${options.removeToken}`));
138
+ } else if (options.validateToken) {
139
+ const registryManager = await RegistryManager.create(process.cwd());
140
+ const result = await registryManager.validateToken(
141
+ options.validateToken.split(':')[0],
142
+ options.validateToken
143
+ );
144
+ if (result.valid) {
145
+ console.log(chalk.green('\n✓ Token 有效'));
146
+ if (result.username) {
147
+ console.log(` 用户: ${result.username}`);
148
+ }
149
+ } else {
150
+ console.log(chalk.red('\n✗ Token 无效'));
151
+ console.log(` 错误: ${result.error}`);
152
+ }
153
+ } else if (options.reset) {
154
+ globalConfig.resetConfig();
155
+ console.log(chalk.green('\n✓ 配置已重置为默认值'));
156
+ } else {
157
+ globalConfig.showConfig();
158
+ }
159
+ } catch (error) {
160
+ console.error(chalk.red(`\n错误: ${error.message}`));
161
+ process.exit(1);
162
+ }
163
+ });
164
+
165
+ // project 子命令 - 项目配置管理
166
+ program
167
+ .command('project')
168
+ .description('项目配置管理(默认值)')
169
+ .option('--show', '显示项目配置')
170
+ .option('--edit', '编辑项目配置')
171
+ .option('--init', '初始化项目配置')
172
+ .action(async (options) => {
173
+ const projectPath = process.cwd();
174
+ const projectConfig = new ProjectConfig(projectPath);
175
+
176
+ try {
177
+ if (options.show) {
178
+ projectConfig.showConfig();
179
+ } else if (options.edit) {
180
+ projectConfig.editConfig();
181
+ } else if (options.init) {
182
+ // 初始化项目配置
183
+ const registryManager = await RegistryManager.create(projectPath);
184
+ const registries = registryManager.globalConfig.getRegistries();
185
+
186
+ if (registries.length === 0) {
187
+ console.log(chalk.red('\n错误: 请先使用 "node-tools-publish config --add-registry" 添加注册源'));
188
+ return;
189
+ }
190
+
191
+ const questions = [
192
+ {
193
+ type: 'select',
194
+ name: 'registryId',
195
+ message: '选择默认注册源',
196
+ choices: registries.map(r => ({
197
+ title: `${r.name} (${r.id})`,
198
+ value: r.id
199
+ }))
200
+ }
201
+ ];
202
+
203
+ const { registryId } = await prompts(questions);
204
+
205
+ // 选择该源的 token
206
+ const tokens = registryManager.globalConfig.getTokensByRegistry(registryId);
207
+ if (tokens.length === 0) {
208
+ console.log(chalk.red('\n错误: 该注册源没有配置 token'));
209
+ console.log(chalk.yellow('请使用 "node-tools-publish config --add-token" 添加 token'));
210
+ return;
211
+ }
212
+
213
+ const { tokenId } = await prompts({
214
+ type: 'select',
215
+ name: 'tokenId',
216
+ message: '选择默认 token',
217
+ choices: tokens.map(t => ({
218
+ title: `${t.name} (${t.id})`,
219
+ value: t.id
220
+ }))
221
+ });
222
+
223
+ await projectConfig.initConfig(registryId, tokenId);
224
+ console.log(chalk.green('\n✓ 项目配置已初始化'));
225
+ console.log(chalk.gray(` 配置文件: ${projectConfig.configPath}`));
226
+ console.log(chalk.yellow(' 注意: 请将 .node-tools-publish.json 添加到 .gitignore'));
227
+ } else {
228
+ projectConfig.showConfig();
229
+ }
230
+ } catch (error) {
231
+ console.error(chalk.red(`\n错误: ${error.message}`));
232
+ process.exit(1);
233
+ }
234
+ });
235
+
236
+ program.parse();
package/package.json CHANGED
@@ -1,11 +1,12 @@
1
1
  {
2
2
  "name": "@mindbase/node-tools",
3
- "version": "1.1.0",
4
- "description": "Node.js 开发工具集合:清理 node_modules、查看 Git 日志",
3
+ "version": "1.3.7",
4
+ "description": "Node.js 开发工具集合:清理 node_modules、查看 Git 日志、发布包",
5
5
  "main": "src/index.js",
6
6
  "bin": {
7
7
  "nodeclear": "./bin/clear.js",
8
- "gitlog": "./bin/git-log.js"
8
+ "gitlog": "./bin/git-log.js",
9
+ "npmpublish": "./bin/publish.js"
9
10
  },
10
11
  "files": [
11
12
  "bin",
@@ -27,7 +28,10 @@
27
28
  "cli-table3": "^0.6.3",
28
29
  "commander": "^11.0.0",
29
30
  "editor": "^1.0.0",
31
+ "execa": "^9.6.1",
32
+ "glob": "^13.0.2",
30
33
  "prompts": "^2.4.2",
34
+ "semver": "^7.7.4",
31
35
  "treeify": "^1.1.0"
32
36
  },
33
37
  "engines": {
@@ -39,4 +43,4 @@
39
43
  "publishConfig": {
40
44
  "access": "public"
41
45
  }
42
- }
46
+ }