@zqw-cli/qenv 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.
package/README.md ADDED
@@ -0,0 +1,867 @@
1
+ <p align="center">
2
+ <h1 align="center">qenv</h1>
3
+ <p align="center">
4
+ 跨平台环境变量管理 CLI 工具<br/>
5
+ <strong>一套命令,三端一致 — Windows · macOS · Linux</strong>
6
+ </p>
7
+ <p align="center">
8
+ <a href="https://www.npmjs.com/package/@zqw-cli/qenv"><img src="https://img.shields.io/npm/v/@zqw-cli/qenv.svg?style=flat-square" alt="npm version" /></a>
9
+ <a href="https://nodejs.org"><img src="https://img.shields.io/node/v/@zqw-cli/qenv.svg?style=flat-square" alt="node version" /></a>
10
+ <a href="LICENSE"><img src="https://img.shields.io/badge/License-MIT-blue.svg?style=flat-square" alt="license" /></a>
11
+ </p>
12
+ </p>
13
+
14
+ ---
15
+
16
+ ## 为什么选 qenv?
17
+
18
+ 在不同操作系统上管理环境变量是件令人头疼的事:Windows 用 `setx`,macOS/Linux 要编辑 `.bashrc` 或 `.zshrc`,项目里还有 `.env` 文件需要维护……
19
+
20
+ **qenv 将这一切统一为一行命令。**
21
+
22
+ ```bash
23
+ # 不管你在什么平台,设置环境变量永远是这一行
24
+ qenv set NODE_ENV production
25
+ ```
26
+
27
+ ### 核心亮点
28
+
29
+ | 特性 | 说明 |
30
+ |------|------|
31
+ | 🌍 **跨平台统一** | 同一命令在 Windows / macOS / Linux 上行为一致 |
32
+ | 📋 **Manifest 追踪** | 记录每一个由 qenv 管理过的变量,支持 `list`、`diff`、`clean` |
33
+ | 🐚 **Shell 集成** | 通过 `qenv init` 安装 wrapper,支持 `--local` 在当前终端立即生效 |
34
+ | 📁 **`.env` 文件支持** | 用 `--file` 读写项目级 `.env` 文件,无需额外工具 |
35
+ | 📦 **批量导入导出** | `qenv import` / `qenv export` 快速迁移环境配置 |
36
+ | 🎨 **友好的终端输出** | 彩色图标、表格对齐、敏感值自动脱敏 |
37
+
38
+ ---
39
+
40
+ ## 目录
41
+
42
+ - [安装](#安装)
43
+ - [快速上手](#快速上手)
44
+ - [命令参考](#命令参考)
45
+ - [qenv set](#qenv-set)
46
+ - [qenv get](#qenv-get)
47
+ - [qenv remove](#qenv-remove)
48
+ - [qenv list](#qenv-list)
49
+ - [qenv import](#qenv-import)
50
+ - [qenv export](#qenv-export)
51
+ - [qenv diff](#qenv-diff)
52
+ - [qenv clean](#qenv-clean)
53
+ - [qenv init](#qenv-init)
54
+ - [全局选项](#全局选项)
55
+ - [Shell 集成详解](#shell-集成详解)
56
+ - [工作原理](#工作原理)
57
+ - [平台驱动层](#平台驱动层)
58
+ - [Manifest 机制](#manifest-机制)
59
+ - [Scope 说明](#scope-说明)
60
+ - [常见用法示例](#常见用法示例)
61
+ - [注意事项与限制](#注意事项与限制)
62
+ - [开发指南](#开发指南)
63
+ - [项目结构](#项目结构)
64
+ - [License](#license)
65
+
66
+ ---
67
+
68
+ ## 安装
69
+
70
+ **要求:** Node.js >= 16
71
+
72
+ ```bash
73
+ npm install -g @zqw-cli/qenv
74
+ ```
75
+
76
+ 安装后即可在任意终端中使用 `qenv` 命令:
77
+
78
+ ```bash
79
+ qenv --version
80
+ # 1.0.0
81
+ ```
82
+
83
+ ---
84
+
85
+ ## 快速上手
86
+
87
+ ### 1. 设置环境变量
88
+
89
+ ```bash
90
+ # 设置用户级系统环境变量(永久生效,重启终端后可用)
91
+ qenv set NODE_ENV production
92
+
93
+ # 设置后覆盖已有的变量
94
+ qenv set NODE_ENV development --overwrite
95
+ ```
96
+
97
+ ### 2. 读取环境变量
98
+
99
+ ```bash
100
+ qenv get NODE_ENV
101
+ # NODE_ENV=production
102
+
103
+ # 只输出纯值(适合在脚本中使用)
104
+ qenv get NODE_ENV --raw
105
+ # production
106
+ ```
107
+
108
+ ### 3. 使用 .env 文件
109
+
110
+ ```bash
111
+ # 写入项目 .env 文件
112
+ qenv set DATABASE_URL postgres://localhost/mydb --file
113
+
114
+ # 写入指定的 .env 文件
115
+ qenv set API_KEY sk-xxx --file .env.local
116
+
117
+ # 查看 .env 文件中的所有变量
118
+ qenv list --file .env.local
119
+ ```
120
+
121
+ ### 4. 批量操作
122
+
123
+ ```bash
124
+ # 从 .env 文件批量导入到系统变量
125
+ qenv import .env.prod
126
+
127
+ # 先预览再导入
128
+ qenv import .env.prod --dry-run
129
+
130
+ # 导出所有 qenv 管理的变量到文件
131
+ qenv export .env.backup
132
+ ```
133
+
134
+ ### 5. 查看与维护
135
+
136
+ ```bash
137
+ # 列出所有由 qenv 管理的变量
138
+ qenv list
139
+
140
+ # 对比 manifest 记录与系统实际值
141
+ qenv diff
142
+
143
+ # 清理已失效的记录
144
+ qenv clean
145
+ ```
146
+
147
+ ---
148
+
149
+ ## 命令参考
150
+
151
+ > 💡 每个命令都支持 `--help` 查看详细用法,例如 `qenv set --help`。
152
+
153
+ ### qenv set
154
+
155
+ 设置环境变量。
156
+
157
+ ```
158
+ 用法: qenv set <name> <value> [options]
159
+ ```
160
+
161
+ | 选项 | 说明 |
162
+ |------|------|
163
+ | `--local` | 仅在当前 Shell 会话中生效(需先运行 `qenv init`) |
164
+ | `--system` | 设置系统级变量(需管理员/sudo 权限) |
165
+ | `--file [path]` | 写入 `.env` 文件,默认路径为 `./.env` |
166
+ | `--json` | 将 value 作为 JSON 解析并校验 |
167
+ | `--overwrite` | 如果变量已存在,强制覆盖 |
168
+
169
+ **示例:**
170
+
171
+ ```bash
172
+ # 基础用法:设置用户级系统变量(永久)
173
+ qenv set NODE_ENV production
174
+
175
+ # 仅当前终端会话生效(需 qenv init)
176
+ qenv set API_KEY sk-xxx --local
177
+
178
+ # 写入项目 .env 文件
179
+ qenv set PORT 3000 --file
180
+
181
+ # 写入指定 .env 文件
182
+ qenv set PORT 3000 --file .env.local
183
+
184
+ # JSON 值校验
185
+ qenv set CONFIG '{"debug":true}' --json
186
+
187
+ # 覆盖已有变量
188
+ qenv set NODE_ENV development --overwrite
189
+ ```
190
+
191
+ **行为说明:**
192
+ - 默认会检查变量是否已存在,若已存在则提示使用 `--overwrite`
193
+ - 不带 `--file` 或 `--local` 时,变量写入当前用户的系统环境(永久生效)
194
+ - 写入的变量会自动记录到 manifest 中,可通过 `qenv list` 查看
195
+
196
+ ---
197
+
198
+ ### qenv get
199
+
200
+ 获取环境变量的值。
201
+
202
+ ```
203
+ 用法: qenv get <name> [options]
204
+ ```
205
+
206
+ | 选项 | 说明 |
207
+ |------|------|
208
+ | `--source` | 显示变量来源(qenv 管理 / 系统原有 / 文件) |
209
+ | `--file [path]` | 从 `.env` 文件读取,默认路径为 `./.env` |
210
+ | `--json` | 以 JSON 格式输出 `{ name, value, source }` |
211
+ | `--raw` | 仅输出纯值,不带任何前缀(适合 `$()` 嵌入脚本使用) |
212
+
213
+ **示例:**
214
+
215
+ ```bash
216
+ # 读取系统变量
217
+ qenv get NODE_ENV
218
+ # NODE_ENV=production
219
+
220
+ # 查看变量来源
221
+ qenv get NODE_ENV --source
222
+ # NODE_ENV=production
223
+ # ℹ Source: qenv (system)
224
+
225
+ # 从 .env 文件读取
226
+ qenv get DATABASE_URL --file .env.prod
227
+
228
+ # 纯值输出(适合脚本嵌入)
229
+ echo "当前环境: $(qenv get NODE_ENV --raw)"
230
+
231
+ # JSON 格式
232
+ qenv get PORT --json
233
+ # {"name":"PORT","value":"3000","source":"qenv (system)"}
234
+ ```
235
+
236
+ **行为说明:**
237
+ - `--raw` 模式下,如果变量不存在,进程退出码为 `1`,stdout 无输出
238
+ - 不加 `--raw` 时,变量不存在会输出 `⚠ Variable "XXX" not found`
239
+
240
+ ---
241
+
242
+ ### qenv remove
243
+
244
+ 删除环境变量。别名:`qenv rm`。
245
+
246
+ ```
247
+ 用法: qenv remove <name> [options]
248
+ ```
249
+
250
+ | 选项 | 说明 |
251
+ |------|------|
252
+ | `--system` | 删除系统级变量(需管理员/sudo 权限) |
253
+ | `--local` | 从当前 Shell 会话中移除(需 `qenv init`) |
254
+ | `--file [path]` | 从 `.env` 文件中删除 |
255
+ | `--force` | 跳过确认提示,直接删除 |
256
+ | `--all` | 配合 `--file` 使用,清空文件中所有变量 |
257
+
258
+ **示例:**
259
+
260
+ ```bash
261
+ # 删除用户级系统变量(会有确认提示)
262
+ qenv remove NODE_ENV
263
+
264
+ # 跳过确认直接删除
265
+ qenv remove NODE_ENV --force
266
+
267
+ # 从 .env 文件删除
268
+ qenv remove DATABASE_URL --file .env.prod
269
+
270
+ # 清空 .env 文件中所有变量
271
+ qenv remove --all --file
272
+
273
+ # 从当前会话移除(需 qenv init)
274
+ qenv remove API_KEY --local
275
+ ```
276
+
277
+ **行为说明:**
278
+ - 默认删除前会弹出确认提示 `(y/N)`,使用 `--force` 跳过
279
+ - 删除成功后同时从 manifest 中清除记录
280
+
281
+ ---
282
+
283
+ ### qenv list
284
+
285
+ 列出环境变量。别名:`qenv ls`。
286
+
287
+ ```
288
+ 用法: qenv list [options]
289
+ ```
290
+
291
+ | 选项 | 说明 |
292
+ |------|------|
293
+ | `--all` | 列出系统中所有环境变量(等同 `printenv`) |
294
+ | `--file [path]` | 列出 `.env` 文件中的变量 |
295
+ | `--json` | 以 JSON 格式输出 |
296
+ | `--verify` | 检验 manifest 记录与系统实际值是否一致 |
297
+ | `--stale` | 仅显示已失效的 manifest 记录 |
298
+
299
+ **示例:**
300
+
301
+ ```bash
302
+ # 列出 qenv 管理的变量(默认)
303
+ qenv list
304
+
305
+ # 输出示例:
306
+ # NAME VALUE SCOPE UPDATED
307
+ # ─────────────────────────────────────────────────────
308
+ # NODE_ENV pro***ion system 2 days ago
309
+ # API_KEY sk-***xxx system 1 hour ago
310
+ # DATABASE_URL (not found) ⚠ system 5 days ago
311
+ #
312
+ # ⚠ 1 stale entry found. Run `qenv clean` to remove.
313
+
314
+ # 列出所有系统变量
315
+ qenv list --all
316
+
317
+ # 列出 .env 文件变量
318
+ qenv list --file .env.prod
319
+
320
+ # 仅查看失效记录
321
+ qenv list --stale
322
+
323
+ # JSON 输出
324
+ qenv list --json
325
+ ```
326
+
327
+ **输出说明:**
328
+ - `VALUE` 列会自动脱敏显示(保留前 3 位和后 3 位,中间用 `***` 替代)
329
+ - `UPDATED` 列显示上次更新的相对时间(如 `2 days ago`、`just now`)
330
+ - 系统中已不存在的变量会显示 `(not found) ⚠` 标记
331
+ - `--all` 模式展示完整值,不做脱敏处理
332
+
333
+ ---
334
+
335
+ ### qenv import
336
+
337
+ 从 `.env` 文件批量导入环境变量。
338
+
339
+ ```
340
+ 用法: qenv import <file> [options]
341
+ ```
342
+
343
+ | 选项 | 说明 |
344
+ |------|------|
345
+ | `--local` | 导入到当前 Shell 会话(需 `qenv init`) |
346
+ | `--dry-run` | 预览将要导入的变量,不实际执行 |
347
+ | `--overwrite` | 覆盖已存在的变量 |
348
+
349
+ **示例:**
350
+
351
+ ```bash
352
+ # 将 .env 文件中的变量导入为系统环境变量
353
+ qenv import .env
354
+
355
+ # 先预览,确认后再操作
356
+ qenv import .env.prod --dry-run
357
+ # ℹ Preview of import from .env.prod:
358
+ # + NODE_ENV=production
359
+ # + API_KEY=sk-xxx
360
+ # + PORT=3000
361
+ #
362
+ # Total: 3 variables
363
+
364
+ # 覆盖已存在的变量
365
+ qenv import .env --overwrite
366
+
367
+ # 导入到当前会话(需 qenv init)
368
+ qenv import .env.dev --local
369
+ ```
370
+
371
+ **行为说明:**
372
+ - 默认不覆盖已存在的变量,逐条跳过并提示
373
+ - `.env` 文件格式支持:`KEY=VALUE`、带引号 `KEY="VALUE"`、注释 `# ...`
374
+
375
+ ---
376
+
377
+ ### qenv export
378
+
379
+ 将环境变量导出为 `.env` 格式。
380
+
381
+ ```
382
+ 用法: qenv export [file] [options]
383
+ ```
384
+
385
+ | 选项 | 说明 |
386
+ |------|------|
387
+ | `--all` | 导出系统中所有环境变量 |
388
+ | `--filter <prefix>` | 仅导出匹配指定前缀的变量 |
389
+
390
+ **示例:**
391
+
392
+ ```bash
393
+ # 导出 qenv 管理的变量到 stdout
394
+ qenv export
395
+
396
+ # 导出到文件
397
+ qenv export .env.backup
398
+
399
+ # 导出所有系统变量
400
+ qenv export env-full.txt --all
401
+
402
+ # 仅导出特定前缀的变量
403
+ qenv export --filter REACT_APP_
404
+ qenv export .env.react --filter REACT_APP_
405
+ ```
406
+
407
+ **行为说明:**
408
+ - 不指定文件时输出到 stdout,可配合管道使用:`qenv export | grep NODE`
409
+ - 默认只导出 manifest 中跟踪的变量,`--all` 则导出系统全部
410
+
411
+ ---
412
+
413
+ ### qenv diff
414
+
415
+ 对比 manifest 记录与系统中的实际值。
416
+
417
+ ```
418
+ 用法: qenv diff [options]
419
+ ```
420
+
421
+ | 选项 | 说明 |
422
+ |------|------|
423
+ | `--json` | 以 JSON 格式输出对比结果 |
424
+
425
+ **示例:**
426
+
427
+ ```bash
428
+ qenv diff
429
+ # 输出示例:
430
+ # NAME SCOPE STATUS
431
+ # ─────────────────────────────────────────
432
+ # NODE_ENV system ✔ in sync
433
+ # API_KEY system ✔ in sync
434
+ # OLD_VAR system ✖ missing
435
+ #
436
+ # ⚠ 1 variable missing from system. Run `qenv clean` to remove stale entries.
437
+
438
+ qenv diff --json
439
+ ```
440
+
441
+ **状态说明:**
442
+
443
+ | 状态 | 含义 |
444
+ |------|------|
445
+ | `✔ in sync` | manifest 记录的变量在系统中存在 |
446
+ | `✖ missing` | manifest 中记录了但系统中已不存在 |
447
+
448
+ ---
449
+
450
+ ### qenv clean
451
+
452
+ 清理 manifest 中的失效记录。
453
+
454
+ ```
455
+ 用法: qenv clean [options]
456
+ ```
457
+
458
+ | 选项 | 说明 |
459
+ |------|------|
460
+ | `--force` | 跳过确认提示,直接清理 |
461
+
462
+ **示例:**
463
+
464
+ ```bash
465
+ # 交互式清理(有确认提示)
466
+ qenv clean
467
+ # ℹ Found 2 stale entries:
468
+ # ⚠ OLD_VAR_1
469
+ # ⚠ OLD_VAR_2
470
+ #
471
+ # Remove these stale entries from manifest? (y/N)
472
+
473
+ # 跳过确认直接清理
474
+ qenv clean --force
475
+ ```
476
+
477
+ ---
478
+
479
+ ### qenv init
480
+
481
+ 安装 Shell 集成(wrapper function),以支持 `--local` 模式。
482
+
483
+ ```
484
+ 用法: qenv init [options]
485
+ ```
486
+
487
+ | 选项 | 说明 |
488
+ |------|------|
489
+ | `--shell <type>` | 指定 Shell 类型:`bash` / `zsh` / `fish` / `pwsh` |
490
+ | `--print` | 仅打印 wrapper 代码,不自动安装 |
491
+ | `--uninstall` | 从配置文件中移除 wrapper |
492
+
493
+ **示例:**
494
+
495
+ ```bash
496
+ # 自动检测当前 Shell 并安装
497
+ qenv init
498
+
499
+ # 指定 Shell 类型
500
+ qenv init --shell zsh
501
+
502
+ # 只查看代码,不安装
503
+ qenv init --print
504
+
505
+ # 卸载 Shell 集成
506
+ qenv init --uninstall
507
+ ```
508
+
509
+ > 详见 [Shell 集成详解](#shell-集成详解)。
510
+
511
+ ---
512
+
513
+ ## 全局选项
514
+
515
+ 以下选项可与任意命令组合使用:
516
+
517
+ | 选项 | 说明 |
518
+ |------|------|
519
+ | `-V, --version` | 输出版本号 |
520
+ | `-h, --help` | 显示帮助信息 |
521
+ | `--no-color` | 禁用终端彩色输出 |
522
+ | `--silent` | 禁止所有 stdout 输出(仅保留 stderr 错误信息) |
523
+ | `--verbose` | 输出调试信息(驱动层调用详情) |
524
+
525
+ ```bash
526
+ # 无色输出(适合重定向到文件)
527
+ qenv list --no-color > vars.txt
528
+
529
+ # 静默模式(CI 中使用)
530
+ qenv set CI true --silent
531
+
532
+ # 调试模式
533
+ qenv set NODE_ENV test --verbose
534
+ ```
535
+
536
+ ---
537
+
538
+ ## Shell 集成详解
539
+
540
+ ### 为什么需要 Shell 集成?
541
+
542
+ `qenv set NAME value` 默认将变量写入**系统环境**(永久但需重启终端),如果你希望变量在**当前终端窗口立即可用**,需要使用 `--local` 模式。
543
+
544
+ 然而,一个子进程(qenv CLI)无法直接修改父进程(你的终端)的环境变量。为了解决这个限制,qenv 使用了 **shell wrapper + eval** 机制:
545
+
546
+ 1. `qenv init` 在你的 Shell 配置文件中安装一个 wrapper function
547
+ 2. 调用 `qenv set NAME value --local` 时,wrapper 实际执行的是 `qenv --shell-eval set NAME value --local`
548
+ 3. qenv 在 `--shell-eval` 模式下只向 stdout 输出一行 shell 表达式(如 `export NAME="value"`)
549
+ 4. wrapper 用 `eval` 执行这行表达式,从而修改当前 Shell 会话的环境
550
+
551
+ ### 各 Shell 的 wrapper 代码
552
+
553
+ **Bash / Zsh**(写入 `~/.bashrc` 或 `~/.zshrc`):
554
+
555
+ ```bash
556
+ # qenv shell integration
557
+ qenv() { eval "$(command qenv --shell-eval "$@")"; }
558
+ # end qenv
559
+ ```
560
+
561
+ **Fish**(写入 `~/.config/fish/config.fish`):
562
+
563
+ ```fish
564
+ # qenv shell integration
565
+ function qenv
566
+ eval (command qenv --shell-eval $argv)
567
+ end
568
+ # end qenv
569
+ ```
570
+
571
+ **PowerShell**(写入 `$PROFILE`):
572
+
573
+ ```powershell
574
+ # qenv shell integration
575
+ function qenv { $result = & qenv.cmd --shell-eval @args; if ($result) { Invoke-Expression $result } }
576
+ # end qenv
577
+ ```
578
+
579
+ ### 手动安装
580
+
581
+ 如果不想自动修改配置文件,可以用 `--print` 查看代码后手动添加:
582
+
583
+ ```bash
584
+ qenv init --print
585
+ ```
586
+
587
+ ---
588
+
589
+ ## 工作原理
590
+
591
+ ### 平台驱动层
592
+
593
+ qenv 根据 `process.platform` 自动选择合适的驱动:
594
+
595
+ | 平台 | 用户级操作 | 系统级操作 (`--system`) |
596
+ |------|-----------|----------------------|
597
+ | **Windows** | `setx NAME "value"`(写入 `HKCU\Environment`) | `reg add HKLM\...\Environment`(需管理员) |
598
+ | **macOS** | 追加 `export NAME="value" # qenv:managed` 到 `~/.zshrc` | 写入 `/etc/environment`(需 sudo) |
599
+ | **Linux** | 追加 `export NAME="value" # qenv:managed` 到 `~/.bashrc` | 写入 `/etc/environment`(需 sudo) |
600
+ | **.env 文件** | 直接读写指定的 `.env` 文件 | — |
601
+
602
+ **Unix 驱动细节:**
603
+ - 使用注释标记 `# qenv:managed` 管理 Shell 配置文件中的行
604
+ - 更新变量时通过正则精准替换已标记的行,不会产生重复条目
605
+ - 自动检测当前 Shell 类型,选择正确的配置文件
606
+
607
+ **Windows 驱动细节:**
608
+ - 用户级变量使用 `setx` 命令,系统级使用 `reg add` 操作注册表
609
+ - 设置变量后自动广播 `WM_SETTINGCHANGE` 消息,通知其他进程刷新环境
610
+ - 自动校验值长度,超过 `setx` 的 1024 字符限制时提前报错
611
+
612
+ ### Manifest 机制
613
+
614
+ qenv 使用 [conf](https://github.com/sindresorhus/conf) 库将 manifest 持久化到用户配置目录:
615
+
616
+ | 平台 | 路径 |
617
+ |------|------|
618
+ | **macOS / Linux** | `~/.config/qenv/config.json` |
619
+ | **Windows** | `%APPDATA%\qenv\config.json` |
620
+
621
+ **数据结构示例:**
622
+
623
+ ```json
624
+ {
625
+ "version": 1,
626
+ "vars": {
627
+ "NODE_ENV": {
628
+ "scope": "system",
629
+ "filePath": null,
630
+ "setAt": "2026-03-16T10:00:00Z",
631
+ "updatedAt": "2026-03-16T12:00:00Z",
632
+ "setBy": "qenv@1.0.0"
633
+ },
634
+ "DATABASE_URL": {
635
+ "scope": "file",
636
+ "filePath": "D:\\projects\\myapp\\.env",
637
+ "setAt": "2026-03-16T09:00:00Z",
638
+ "updatedAt": "2026-03-16T09:00:00Z",
639
+ "setBy": "qenv@1.0.0"
640
+ }
641
+ }
642
+ }
643
+ ```
644
+
645
+ **字段说明:**
646
+
647
+ | 字段 | 说明 |
648
+ |------|------|
649
+ | `scope` | `system`(用户级永久)/ `system-wide`(系统级)/ `file`(.env 文件) |
650
+ | `filePath` | 仅 `scope=file` 时有值,记录 `.env` 文件的绝对路径 |
651
+ | `setAt` | 首次设置时间(ISO 8601 格式) |
652
+ | `updatedAt` | 最近一次更新时间 |
653
+ | `setBy` | 写入时的 qenv 版本号 |
654
+
655
+ > ⚠️ **重要边界:** manifest 仅记录"qenv 操作过哪些变量",不独占管理权。如果用户或其他工具直接修改了同一变量,qenv 不会阻止,但 `qenv diff` 可以发现变量已被删除(`missing`)。
656
+
657
+ ### Scope 说明
658
+
659
+ | Scope | 触发方式 | 生效范围 | 持久性 |
660
+ |-------|---------|---------|--------|
661
+ | `system`(默认) | `qenv set NAME value` | 新终端窗口 | ✅ 永久 |
662
+ | `system-wide` | `qenv set NAME value --system` | 所有用户的新终端 | ✅ 永久 |
663
+ | `session` | `qenv set NAME value --local` | 仅当前终端窗口 | ❌ 关闭即失效 |
664
+ | `file` | `qenv set NAME value --file` | 取决于应用是否读取 | ✅ 文件存在即有效 |
665
+
666
+ ---
667
+
668
+ ## 常见用法示例
669
+
670
+ ### CI/CD 中批量设置环境变量
671
+
672
+ ```bash
673
+ # 从密钥管理中导出 .env 文件,然后导入到系统
674
+ qenv import .env.ci --overwrite --silent
675
+ ```
676
+
677
+ ### 在脚本中获取值
678
+
679
+ ```bash
680
+ # Bash / Zsh
681
+ DB_HOST=$(qenv get DB_HOST --raw)
682
+ echo "连接到数据库: $DB_HOST"
683
+ ```
684
+
685
+ ```powershell
686
+ # PowerShell
687
+ $dbHost = qenv get DB_HOST --raw
688
+ Write-Host "连接到数据库: $dbHost"
689
+ ```
690
+
691
+ ### 在不同 .env 文件间切换
692
+
693
+ ```bash
694
+ # 查看各环境配置
695
+ qenv list --file .env.dev
696
+ qenv list --file .env.staging
697
+ qenv list --file .env.prod
698
+
699
+ # 导入开发环境配置到当前会话
700
+ qenv import .env.dev --local
701
+ ```
702
+
703
+ ### 导出特定前缀的变量
704
+
705
+ ```bash
706
+ # 只导出 React 应用相关变量
707
+ qenv export .env.react --filter REACT_APP_
708
+
709
+ # 只导出 AWS 相关变量到 stdout
710
+ qenv export --filter AWS_
711
+ ```
712
+
713
+ ### 项目初始化模板
714
+
715
+ ```bash
716
+ # 为新同事快速搭建开发环境
717
+ qenv import .env.example --overwrite
718
+ qenv list --verify
719
+ ```
720
+
721
+ ### 定期维护 manifest
722
+
723
+ ```bash
724
+ # 检查是否有过期的记录
725
+ qenv diff
726
+
727
+ # 自动清理所有失效记录
728
+ qenv clean --force
729
+ ```
730
+
731
+ ---
732
+
733
+ ## 注意事项与限制
734
+
735
+ ### Windows 平台
736
+
737
+ | 限制 | 说明 |
738
+ |------|------|
739
+ | `setx` 字符上限 | 值不能超过 **1024 个字符**,超出时 qenv 会提前报错 |
740
+ | 需重启终端 | 通过 `setx` 设置的变量需要打开**新终端窗口**才能生效 |
741
+ | 管理员权限 | `--system` 模式需要以**管理员身份**运行终端 |
742
+
743
+ > 💡 **提示:** 使用 `--local` 模式可以避免重启终端的问题,变量立即在当前窗口生效。
744
+
745
+ ### macOS / Linux 平台
746
+
747
+ | 限制 | 说明 |
748
+ |------|------|
749
+ | 需 source 配置 | 修改 `.bashrc` / `.zshrc` 后需 `source` 或重启终端才能生效 |
750
+ | sudo 权限 | `--system` 操作 `/etc/environment` 需要 sudo |
751
+ | Shell 兼容 | 已内置支持 Bash、Zsh、Fish;其他 Shell 可用 `qenv init --print` 手动适配 |
752
+
753
+ ### 通用限制
754
+
755
+ | 限制 | 说明 |
756
+ |------|------|
757
+ | 变量名规则 | 必须匹配 `/^[A-Za-z_][A-Za-z0-9_]*$/`(字母或下划线开头) |
758
+ | 不存储值 | manifest 仅记录元信息,不缓存变量的实际值 |
759
+ | 非独占管理 | 其他工具可修改同一变量,qenv 不阻止但 `diff` 可检测差异 |
760
+
761
+ ---
762
+
763
+ ## 开发指南
764
+
765
+ ### 环境准备
766
+
767
+ ```bash
768
+ git clone https://github.com/user/qenv.git
769
+ cd qenv
770
+ npm install
771
+ ```
772
+
773
+ > 📦 npm 包名为 `@zqw-cli/qenv`,CLI 命令名仍为 `qenv`。
774
+
775
+ ### 常用命令
776
+
777
+ | 命令 | 说明 |
778
+ |------|------|
779
+ | `npm run build` | 使用 tsup 构建,输出到 `dist/` |
780
+ | `npm run dev` | 开发模式(watch,文件变更自动重新构建) |
781
+ | `npm test` | 运行 Vitest 单元测试 |
782
+ | `npm link` | 本地全局链接,方便开发调试 |
783
+
784
+ ### 本地调试
785
+
786
+ ```bash
787
+ # 构建
788
+ npm run build
789
+
790
+ # 直接运行
791
+ node dist/index.js --help
792
+
793
+ # 或全局链接后使用
794
+ npm link
795
+ qenv --help
796
+ ```
797
+
798
+ ### 技术栈
799
+
800
+ | 工具 | 用途 |
801
+ |------|------|
802
+ | [TypeScript](https://www.typescriptlang.org/) | 类型安全的开发语言 |
803
+ | [tsup](https://github.com/egoist/tsup) | 零配置打包,输出 CJS + DTS,自动加 `#!/usr/bin/env node` |
804
+ | [Commander.js](https://github.com/tj/commander.js) | CLI 框架,链式 API,自动 `--help` 生成 |
805
+ | [chalk](https://github.com/chalk/chalk) | 终端彩色输出 |
806
+ | [conf](https://github.com/sindresorhus/conf) | 跨平台 JSON 持久化存储(manifest) |
807
+ | [ora](https://github.com/sindresorhus/ora) | 终端 spinner 加载动画 |
808
+ | [Vitest](https://vitest.dev/) | 快速单元测试框架 |
809
+
810
+ ### 发布到 npm
811
+
812
+ ```bash
813
+ # prepublishOnly 会自动执行 build + test
814
+ npm publish
815
+ ```
816
+
817
+ ---
818
+
819
+ ## 项目结构
820
+
821
+ ```
822
+ qenv/
823
+ ├── src/
824
+ │ ├── index.ts # CLI 入口:注册全部命令 + 全局选项 + --shell-eval 处理
825
+ │ ├── commands/
826
+ │ │ ├── set.ts # qenv set — 设置环境变量
827
+ │ │ ├── get.ts # qenv get — 读取环境变量
828
+ │ │ ├── remove.ts # qenv remove (rm) — 删除环境变量
829
+ │ │ ├── list.ts # qenv list (ls) — 列出变量 + 失效标记
830
+ │ │ ├── diff.ts # qenv diff + qenv clean — 对比 & 清理 manifest
831
+ │ │ ├── init.ts # qenv init — 安装/卸载 Shell 集成
832
+ │ │ └── import.ts # qenv import + qenv export — 批量导入导出
833
+ │ ├── drivers/
834
+ │ │ ├── types.ts # EnvDriver 接口定义(get/set/remove/list)
835
+ │ │ ├── index.ts # 驱动选择器(根据 process.platform)
836
+ │ │ ├── windows.ts # Windows 驱动(setx / reg add / reg query)
837
+ │ │ ├── unix.ts # Unix 驱动(读写 .bashrc / .zshrc / config.fish)
838
+ │ │ └── dotenv.ts # .env 文件驱动(解析、写入、保留注释)
839
+ │ ├── shell/
840
+ │ │ ├── detect.ts # Shell 类型自动检测(bash/zsh/fish/pwsh/cmd)
841
+ │ │ └── eval.ts # --shell-eval 输出 eval 表达式
842
+ │ ├── manifest/
843
+ │ │ └── index.ts # Manifest 管理器(基于 conf 库的单例)
844
+ │ └── utils/
845
+ │ ├── logger.ts # 统一日志输出(success/warn/error/info/table)
846
+ │ ├── validator.ts # 变量名校验 + .env 解析 + 序列化
847
+ │ └── platform.ts # 平台判断 + 权限检测 + Home 目录
848
+ ├── tests/
849
+ │ ├── validator.test.ts # 校验器 & .env 解析测试(15 cases)
850
+ │ ├── dotenv.test.ts # .env 驱动集成测试(8 cases)
851
+ │ ├── platform.test.ts # 平台工具测试(2 cases)
852
+ │ ├── shell.test.ts # Shell 检测测试(2 cases)
853
+ │ └── manifest.test.ts # Manifest 结构测试(2 cases)
854
+ ├── dist/ # 构建输出(.gitignore)
855
+ ├── tsup.config.ts # tsup 构建配置
856
+ ├── tsconfig.json # TypeScript 编译配置
857
+ ├── vitest.config.ts # Vitest 测试配置
858
+ ├── package.json # 包描述 & 脚本
859
+ ├── .gitignore
860
+ └── README.md # 本文档
861
+ ```
862
+
863
+ ---
864
+
865
+ ## License
866
+
867
+ [MIT](LICENSE) © 2026