pqm-cli 1.0.0

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.
Files changed (43) hide show
  1. package/README.md +254 -0
  2. package/bin/pqm.js +6 -0
  3. package/package.json +31 -0
  4. package/src/ai/analyzer/collector.js +191 -0
  5. package/src/ai/analyzer/dependency.js +269 -0
  6. package/src/ai/analyzer/index.js +234 -0
  7. package/src/ai/analyzer/quality.js +241 -0
  8. package/src/ai/analyzer/security.js +302 -0
  9. package/src/ai/index.js +16 -0
  10. package/src/ai/providers/bailian.js +121 -0
  11. package/src/ai/providers/base.js +177 -0
  12. package/src/ai/providers/deepseek.js +100 -0
  13. package/src/ai/providers/index.js +100 -0
  14. package/src/ai/providers/openai.js +100 -0
  15. package/src/builders/base.js +35 -0
  16. package/src/builders/rollup.js +47 -0
  17. package/src/builders/vite.js +47 -0
  18. package/src/cli.js +41 -0
  19. package/src/commands/ai.js +317 -0
  20. package/src/commands/build.js +24 -0
  21. package/src/commands/commit.js +68 -0
  22. package/src/commands/config.js +113 -0
  23. package/src/commands/doctor.js +146 -0
  24. package/src/commands/init.js +61 -0
  25. package/src/commands/login.js +37 -0
  26. package/src/commands/publish.js +250 -0
  27. package/src/commands/release.js +107 -0
  28. package/src/commands/scan.js +239 -0
  29. package/src/commands/status.js +129 -0
  30. package/src/commands/watch.js +170 -0
  31. package/src/commands/webhook.js +240 -0
  32. package/src/config/detector.js +82 -0
  33. package/src/config/global.js +136 -0
  34. package/src/config/loader.js +49 -0
  35. package/src/core/builder.js +88 -0
  36. package/src/index.js +5 -0
  37. package/src/logs/build.js +47 -0
  38. package/src/logs/manager.js +60 -0
  39. package/src/report/formatter.js +282 -0
  40. package/src/utils/http.js +130 -0
  41. package/src/utils/logger.js +24 -0
  42. package/src/utils/prompt.js +132 -0
  43. package/src/utils/spinner.js +134 -0
package/README.md ADDED
@@ -0,0 +1,254 @@
1
+ # PQM CLI
2
+
3
+ Package Quality Monitor CLI - 文件监控、构建、发布一体化工具。
4
+
5
+ ## 安装
6
+
7
+ ```bash
8
+ cd pqm-cli
9
+ npm install
10
+ npm link
11
+ ```
12
+
13
+ ## 流程闭环
14
+
15
+ ```
16
+ ┌─────────────────────────────────────────────────────────────┐
17
+ │ PQM 完整工作流 │
18
+ ├─────────────────────────────────────────────────────────────┤
19
+ │ │
20
+ │ 开发阶段 发布阶段 │
21
+ │ ┌───────┐ ┌─────────┐ ┌─────────┐ │
22
+ │ │ watch │ ──────▶ │ commit │ ─────▶ │ release │ │
23
+ │ └───────┘ └─────────┘ └─────────┘ │
24
+ │ │ │ │ │
25
+ │ ▼ ▼ ▼ │
26
+ │ ┌───────┐ ┌─────────┐ ┌─────────┐ │
27
+ │ │ build │ │ status │ │ publish │ │
28
+ │ └───────┘ └─────────┘ └─────────┘ │
29
+ │ │ │
30
+ │ ▼ │
31
+ │ ┌─────────┐ │
32
+ │ │ webhook │ ◀── Git Tag │
33
+ │ └─────────┘ │
34
+ │ │ │
35
+ │ ▼ │
36
+ │ npm 发布 │
37
+ └─────────────────────────────────────────────────────────────┘
38
+ ```
39
+
40
+ ## 命令总览
41
+
42
+ ### 开发流程
43
+
44
+ ```bash
45
+ # 1. 初始化项目
46
+ pqm init
47
+
48
+ # 2. 启动文件监控(自动构建)
49
+ pqm watch
50
+
51
+ # 3. 查看项目状态
52
+ pqm status
53
+ ```
54
+
55
+ ### 提交发布
56
+
57
+ ```bash
58
+ # 4. 提交代码
59
+ pqm commit "feat: 新功能"
60
+
61
+ # 5. 创建发布版本
62
+ pqm release patch # 1.0.0 → 1.0.1
63
+ pqm release minor # 1.0.0 → 1.1.0
64
+ pqm release major # 1.0.0 → 2.0.0
65
+
66
+ # 6. 发布到 npm
67
+ pqm login # 登录 npm
68
+ pqm publish # 发布包
69
+ ```
70
+
71
+ ### Webhook 自动发布
72
+
73
+ ```bash
74
+ # 启动 webhook 服务器
75
+ pqm webhook start
76
+
77
+ # 在另一个终端测试
78
+ pqm webhook test
79
+ ```
80
+
81
+ ## 命令详情
82
+
83
+ ### `pqm watch`
84
+
85
+ 启动文件监控,自动触发构建。
86
+
87
+ ```bash
88
+ pqm watch # 监控 ./src
89
+ pqm watch -p ./lib # 监控 ./lib
90
+ pqm watch -t vite # 指定构建工具
91
+ pqm watch --webhook # 同时启动 webhook
92
+ ```
93
+
94
+ ### `pqm commit`
95
+
96
+ 提交并推送代码。
97
+
98
+ ```bash
99
+ pqm commit "feat: 添加新功能"
100
+ pqm commit "fix: 修复bug" -m "详细说明"
101
+ ```
102
+
103
+ ### `pqm release`
104
+
105
+ 创建版本发布。
106
+
107
+ ```bash
108
+ pqm release # 默认 patch
109
+ pqm release patch # 补丁版本 1.0.0 → 1.0.1
110
+ pqm release minor # 次要版本 1.0.0 → 1.1.0
111
+ pqm release major # 主要版本 1.0.0 → 2.0.0
112
+ ```
113
+
114
+ ### `pqm publish`
115
+
116
+ 发布到 npm。
117
+
118
+ ```bash
119
+ pqm publish # 交互式发布
120
+ pqm publish --access public # 公开包
121
+ pqm publish --skip-test # 跳过测试
122
+ pqm publish --skip-build # 跳过构建
123
+ ```
124
+
125
+ ### `pqm webhook`
126
+
127
+ 自动发布 webhook 服务器。
128
+
129
+ ```bash
130
+ # 设置 NPM_TOKEN 环境变量
131
+ export NPM_TOKEN=npm_xxxxx
132
+
133
+ # 启动服务器
134
+ pqm webhook start
135
+
136
+ # 指定端口
137
+ pqm webhook start -p 3200
138
+
139
+ # 启用签名验证
140
+ pqm webhook start -s your-secret
141
+
142
+ # 测试 webhook
143
+ pqm webhook test
144
+ ```
145
+
146
+ ### `pqm status`
147
+
148
+ 查看项目状态。
149
+
150
+ ```bash
151
+ pqm status
152
+ ```
153
+
154
+ 输出示例:
155
+ ```
156
+ 📦 包信息
157
+ ────────────────────────────────
158
+ 名称: my-package
159
+ 版本: v1.0.0
160
+
161
+ 🌿 Git 状态
162
+ ────────────────────────────────
163
+ 分支: main
164
+ 变更: 工作区干净
165
+
166
+ 📝 最近提交
167
+ ────────────────────────────────
168
+ abc1234 feat: 新功能
169
+ def5678 fix: 修复bug
170
+
171
+ 🔐 NPM 状态
172
+ ────────────────────────────────
173
+ 用户: your-username
174
+ ```
175
+
176
+ ### 其他命令
177
+
178
+ ```bash
179
+ pqm init # 初始化配置
180
+ pqm config list # 查看配置
181
+ pqm config set <k> <v> # 设置配置
182
+ pqm doctor # 环境诊断
183
+ pqm build # 手动构建
184
+ pqm build -t vite # 指定工具
185
+ pqm login # NPM 登录
186
+ ```
187
+
188
+ ## 配置文件 (.pqmrc)
189
+
190
+ ```json
191
+ {
192
+ "root": "./src",
193
+ "exclude": ["node_modules", "dist", ".git"],
194
+ "buildTool": "auto",
195
+ "buildMode": "incremental",
196
+ "buildOnStart": true,
197
+ "webhook": {
198
+ "enabled": false,
199
+ "port": 3200
200
+ },
201
+ "log": {
202
+ "level": "info",
203
+ "file": ".pqm/pqm.log"
204
+ }
205
+ }
206
+ ```
207
+
208
+ ## 典型工作流
209
+
210
+ ### 场景 1:日常开发
211
+
212
+ ```bash
213
+ # 1. 开始开发
214
+ pqm watch
215
+
216
+ # 2. 修改文件...(自动构建)
217
+
218
+ # 3. 提交
219
+ pqm commit "feat: 添加新功能"
220
+
221
+ # 4. 发布版本
222
+ pqm release patch
223
+ ```
224
+
225
+ ### 场景 2:CI/CD 自动发布
226
+
227
+ ```bash
228
+ # 服务器端运行
229
+ export NPM_TOKEN=npm_xxxxx
230
+ pqm webhook start -p 3000
231
+
232
+ # 配置 Git 平台 Webhook:
233
+ # URL: http://your-server:3000/webhook/npm-publish
234
+ # 触发: Tag push
235
+ ```
236
+
237
+ ### 场景 3:手动发布
238
+
239
+ ```bash
240
+ pqm status # 检查状态
241
+ pqm login # 登录
242
+ pqm release minor # 创建版本
243
+ pqm publish # 发布
244
+ ```
245
+
246
+ ## 依赖
247
+
248
+ - Node.js >= 18
249
+ - Git
250
+ - npm
251
+
252
+ ## License
253
+
254
+ MIT
package/bin/pqm.js ADDED
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env node
2
+ import { program } from 'commander';
3
+ import { registerCommands } from '../src/cli.js';
4
+
5
+ registerCommands(program);
6
+ program.parse();
package/package.json ADDED
@@ -0,0 +1,31 @@
1
+ {
2
+ "name": "pqm-cli",
3
+ "version": "1.0.0",
4
+ "type": "module",
5
+ "description": "Package Quality Monitor CLI - 文件监控、构建、发布一体化工具",
6
+ "bin": {
7
+ "pqm": "bin/pqm.js"
8
+ },
9
+ "files": [
10
+ "bin",
11
+ "src"
12
+ ],
13
+ "scripts": {
14
+ "test": "echo \"No tests yet\""
15
+ },
16
+ "dependencies": {
17
+ "commander": "^12.0.0",
18
+ "chalk": "^5.0.0",
19
+ "chokidar": "^5.0.0"
20
+ },
21
+ "engines": {
22
+ "node": ">=18.0.0"
23
+ },
24
+ "keywords": [
25
+ "cli",
26
+ "watch",
27
+ "build",
28
+ "monitor"
29
+ ],
30
+ "license": "MIT"
31
+ }
@@ -0,0 +1,191 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+ import { loadGlobalConfig } from '../../config/global.js';
4
+
5
+ /**
6
+ * Default exclude patterns
7
+ */
8
+ const DEFAULT_EXCLUDES = [
9
+ 'node_modules',
10
+ 'dist',
11
+ 'build',
12
+ '.git',
13
+ '.svn',
14
+ '.hg',
15
+ 'coverage',
16
+ '.nyc_output',
17
+ '**/*.min.js',
18
+ '**/*.min.css',
19
+ '**/*.map',
20
+ '**/*.lock',
21
+ 'package-lock.json',
22
+ 'yarn.lock',
23
+ 'pnpm-lock.yaml'
24
+ ];
25
+
26
+ /**
27
+ * Supported file extensions for analysis
28
+ */
29
+ const SUPPORTED_EXTENSIONS = [
30
+ '.js', '.jsx', '.ts', '.tsx',
31
+ '.vue', '.svelte',
32
+ '.py', '.rb', '.go',
33
+ '.java', '.kt', '.rs',
34
+ '.c', '.cpp', '.h', '.hpp',
35
+ '.php', '.cs',
36
+ '.swift', '.m', '.mm',
37
+ '.sh', '.bash',
38
+ '.sql',
39
+ '.html', '.css', '.scss', '.less'
40
+ ];
41
+
42
+ /**
43
+ * Check if path should be excluded
44
+ * @param {string} filePath - File path
45
+ * @param {Array<string>} excludes - Exclude patterns
46
+ * @returns {boolean} True if excluded
47
+ */
48
+ function isExcluded(filePath, excludes) {
49
+ const normalized = filePath.replace(/\\/g, '/');
50
+
51
+ for (const pattern of excludes) {
52
+ // Simple pattern matching
53
+ if (pattern.startsWith('**/*.')) {
54
+ const ext = pattern.slice(2);
55
+ if (normalized.endsWith(ext)) {
56
+ return true;
57
+ }
58
+ } else if (pattern.startsWith('**/')) {
59
+ const name = pattern.slice(3);
60
+ if (normalized.includes('/' + name + '/') || normalized.endsWith('/' + name)) {
61
+ return true;
62
+ }
63
+ } else {
64
+ // Simple directory/name match
65
+ if (normalized.includes('/' + pattern + '/') || normalized.endsWith('/' + pattern)) {
66
+ return true;
67
+ }
68
+ }
69
+ }
70
+
71
+ return false;
72
+ }
73
+
74
+ /**
75
+ * Check if file extension is supported
76
+ * @param {string} filePath - File path
77
+ * @returns {boolean} True if supported
78
+ */
79
+ function isSupportedFile(filePath) {
80
+ const ext = path.extname(filePath).toLowerCase();
81
+ return SUPPORTED_EXTENSIONS.includes(ext);
82
+ }
83
+
84
+ /**
85
+ * Collect files from a directory
86
+ * @param {string} dir - Directory path
87
+ * @param {Object} options - Options
88
+ * @returns {Promise<Array<Object>>} File list with content
89
+ */
90
+ export async function collectFiles(dir, options = {}) {
91
+ const config = loadGlobalConfig();
92
+ const exclude = options.exclude || config.scan?.exclude || DEFAULT_EXCLUDES;
93
+ const maxFileSize = options.maxFileSize || config.scan?.maxFileSize || 1048576;
94
+
95
+ const files = [];
96
+
97
+ async function walk(currentPath) {
98
+ try {
99
+ const entries = await fs.promises.readdir(currentPath, { withFileTypes: true });
100
+
101
+ for (const entry of entries) {
102
+ const fullPath = path.join(currentPath, entry.name);
103
+
104
+ if (isExcluded(fullPath, exclude)) {
105
+ continue;
106
+ }
107
+
108
+ if (entry.isDirectory()) {
109
+ await walk(fullPath);
110
+ } else if (entry.isFile() && isSupportedFile(fullPath)) {
111
+ try {
112
+ const stat = await fs.promises.stat(fullPath);
113
+
114
+ if (stat.size > maxFileSize) {
115
+ continue;
116
+ }
117
+
118
+ const content = await fs.promises.readFile(fullPath, 'utf-8');
119
+
120
+ // Skip empty files
121
+ if (content.trim().length === 0) {
122
+ continue;
123
+ }
124
+
125
+ files.push({
126
+ path: fullPath,
127
+ relativePath: path.relative(dir, fullPath),
128
+ content,
129
+ size: stat.size
130
+ });
131
+ } catch (error) {
132
+ // Skip files that can't be read
133
+ continue;
134
+ }
135
+ }
136
+ }
137
+ } catch (error) {
138
+ // Handle permission errors etc.
139
+ console.error(`Warning: Could not read directory ${currentPath}: ${error.message}`);
140
+ }
141
+ }
142
+
143
+ await walk(dir);
144
+
145
+ return files;
146
+ }
147
+
148
+ /**
149
+ * Collect a single file
150
+ * @param {string} filePath - File path
151
+ * @returns {Promise<Object|null>} File object or null
152
+ */
153
+ export async function collectSingleFile(filePath) {
154
+ if (!fs.existsSync(filePath)) {
155
+ return null;
156
+ }
157
+
158
+ const stat = await fs.promises.stat(filePath);
159
+
160
+ if (!stat.isFile()) {
161
+ return null;
162
+ }
163
+
164
+ const content = await fs.promises.readFile(filePath, 'utf-8');
165
+
166
+ return {
167
+ path: filePath,
168
+ relativePath: path.basename(filePath),
169
+ content,
170
+ size: stat.size
171
+ };
172
+ }
173
+
174
+ /**
175
+ * Get file count in directory
176
+ * @param {string} dir - Directory path
177
+ * @param {Object} options - Options
178
+ * @returns {Promise<number>} File count
179
+ */
180
+ export async function getFileCount(dir, options = {}) {
181
+ const files = await collectFiles(dir, options);
182
+ return files.length;
183
+ }
184
+
185
+ export default {
186
+ collectFiles,
187
+ collectSingleFile,
188
+ getFileCount,
189
+ DEFAULT_EXCLUDES,
190
+ SUPPORTED_EXTENSIONS
191
+ };