@lkangd/cc-env 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 (111) hide show
  1. package/.claude/settings.json +6 -0
  2. package/.claude/settings.local.json +3 -0
  3. package/.nvmrc +1 -0
  4. package/dist/cli.js +266 -0
  5. package/dist/commands/debug.js +17 -0
  6. package/dist/commands/init.js +64 -0
  7. package/dist/commands/preset/create.js +61 -0
  8. package/dist/commands/preset/delete.js +25 -0
  9. package/dist/commands/preset/edit.js +15 -0
  10. package/dist/commands/preset/list.js +16 -0
  11. package/dist/commands/preset/show.js +16 -0
  12. package/dist/commands/restore.js +65 -0
  13. package/dist/commands/run.js +80 -0
  14. package/dist/core/errors.js +11 -0
  15. package/dist/core/find-claude.js +64 -0
  16. package/dist/core/format.js +23 -0
  17. package/dist/core/fs.js +12 -0
  18. package/dist/core/gitignore.js +23 -0
  19. package/dist/core/lock.js +25 -0
  20. package/dist/core/logger.js +8 -0
  21. package/dist/core/mask.js +13 -0
  22. package/dist/core/paths.js +32 -0
  23. package/dist/core/process-env.js +4 -0
  24. package/dist/core/schema.js +38 -0
  25. package/dist/core/spawn.js +26 -0
  26. package/dist/flows/init-flow.js +35 -0
  27. package/dist/flows/preset-create-flow.js +80 -0
  28. package/dist/flows/restore-flow.js +75 -0
  29. package/dist/ink/init-app.js +54 -0
  30. package/dist/ink/preset-create-app.js +271 -0
  31. package/dist/ink/preset-delete-app.js +47 -0
  32. package/dist/ink/preset-list-app.js +27 -0
  33. package/dist/ink/preset-show-app.js +27 -0
  34. package/dist/ink/restore-app.js +102 -0
  35. package/dist/ink/run-preset-select-app.js +31 -0
  36. package/dist/ink/summary.js +28 -0
  37. package/dist/services/claude-settings-env-service.js +55 -0
  38. package/dist/services/config-service.js +26 -0
  39. package/dist/services/history-service.js +39 -0
  40. package/dist/services/preset-service.js +61 -0
  41. package/dist/services/project-env-service.js +90 -0
  42. package/dist/services/project-state-service.js +26 -0
  43. package/dist/services/runtime-env-service.js +13 -0
  44. package/dist/services/settings-env-service.js +36 -0
  45. package/dist/services/shell-env-service.js +77 -0
  46. package/docs/product-specs/index.draft.md +106 -0
  47. package/docs/product-specs/index.md +911 -0
  48. package/docs/product-specs/optional.md +42 -0
  49. package/docs/references/claude-code-env.md +224 -0
  50. package/docs/superpowers/plans/2026-04-24-cc-env-init-shell-migration.md +1331 -0
  51. package/docs/superpowers/plans/2026-04-24-cc-env.md +1666 -0
  52. package/docs/superpowers/plans/2026-04-26-preset-create-interactive-refactor.md +1432 -0
  53. package/docs/superpowers/specs/2026-04-24-cc-env-design.md +438 -0
  54. package/docs/superpowers/specs/2026-04-24-cc-env-init-shell-migration-design.md +181 -0
  55. package/docs/superpowers/specs/2026-04-26-preset-create-interactive-refactor-design.md +78 -0
  56. package/package.json +55 -0
  57. package/src/cli.ts +337 -0
  58. package/src/commands/init.ts +139 -0
  59. package/src/commands/preset/create.ts +96 -0
  60. package/src/commands/preset/delete.ts +62 -0
  61. package/src/commands/preset/show.ts +51 -0
  62. package/src/commands/restore.ts +150 -0
  63. package/src/commands/run.ts +158 -0
  64. package/src/core/errors.ts +13 -0
  65. package/src/core/find-claude.ts +70 -0
  66. package/src/core/format.ts +29 -0
  67. package/src/core/fs.ts +18 -0
  68. package/src/core/gitignore.ts +26 -0
  69. package/src/core/logger.ts +11 -0
  70. package/src/core/mask.ts +17 -0
  71. package/src/core/paths.ts +41 -0
  72. package/src/core/process-env.ts +11 -0
  73. package/src/core/schema.ts +55 -0
  74. package/src/core/spawn.ts +36 -0
  75. package/src/flows/init-flow.ts +61 -0
  76. package/src/flows/preset-create-flow.ts +129 -0
  77. package/src/flows/restore-flow.ts +144 -0
  78. package/src/ink/init-app.tsx +110 -0
  79. package/src/ink/preset-create-app.tsx +451 -0
  80. package/src/ink/preset-delete-app.tsx +114 -0
  81. package/src/ink/preset-show-app.tsx +76 -0
  82. package/src/ink/restore-app.tsx +230 -0
  83. package/src/ink/run-preset-select-app.tsx +83 -0
  84. package/src/ink/summary.tsx +91 -0
  85. package/src/services/claude-settings-env-service.ts +72 -0
  86. package/src/services/history-service.ts +48 -0
  87. package/src/services/preset-service.ts +72 -0
  88. package/src/services/project-env-service.ts +128 -0
  89. package/src/services/project-state-service.ts +31 -0
  90. package/src/services/settings-env-service.ts +40 -0
  91. package/src/services/shell-env-service.ts +112 -0
  92. package/src/types.d.ts +19 -0
  93. package/tests/cli/help.test.ts +133 -0
  94. package/tests/cli/init.test.ts +76 -0
  95. package/tests/cli/restore.test.ts +172 -0
  96. package/tests/commands/create.test.ts +263 -0
  97. package/tests/commands/output.test.ts +119 -0
  98. package/tests/commands/run.test.ts +218 -0
  99. package/tests/core/gitignore.test.ts +98 -0
  100. package/tests/core/paths.test.ts +24 -0
  101. package/tests/core/schema-mask.test.ts +182 -0
  102. package/tests/core/spawn.test.ts +47 -0
  103. package/tests/flows/init-flow.test.ts +40 -0
  104. package/tests/flows/preset-create-flow.test.ts +225 -0
  105. package/tests/flows/restore-flow.test.ts +157 -0
  106. package/tests/integration/init-restore.test.ts +406 -0
  107. package/tests/services/claude-shell.test.ts +183 -0
  108. package/tests/services/storage.test.ts +143 -0
  109. package/tsconfig.build.json +9 -0
  110. package/tsconfig.json +22 -0
  111. package/vitest.config.ts +8 -0
@@ -0,0 +1,911 @@
1
+ # cc-env CLI 规范(Final Draft)
2
+
3
+ Version: **1.0**
4
+ Status: **Ready for Implementation**
5
+
6
+ ---
7
+
8
+ # 1. 项目目标(Objective)
9
+
10
+ 构建一个基于 Node.js 的 CLI 工具:
11
+
12
+ ```bash
13
+ cc-env
14
+ ```
15
+
16
+ 用于在运行时为 **Claude Code CLI** 注入一组预定义环境变量,从而支持:
17
+
18
+ - 多模型提供商切换(OpenAI / Azure / Anthropic / 自建)
19
+ - 不修改 `~/.claude/settings.json`
20
+ - 支持项目级配置
21
+ - 支持历史记录与回滚
22
+ - 支持安全管理 secrets
23
+ - 支持 deterministic runtime behavior
24
+
25
+ ---
26
+
27
+ # 2. 核心设计原则(Design Principles)
28
+
29
+ ## 2.1 Runtime 注入优先
30
+
31
+ 永远:
32
+
33
+ ```text
34
+ 不修改 shell 环境
35
+ 只在子进程中注入 env
36
+ ```
37
+
38
+ ---
39
+
40
+ ## 2.2 幂等(Idempotent)
41
+
42
+ 任何命令:
43
+
44
+ ```text
45
+ 重复执行不会破坏状态
46
+ ```
47
+
48
+ ---
49
+
50
+ ## 2.3 可回滚(Reversible)
51
+
52
+ 所有 destructive 操作必须:
53
+
54
+ ```text
55
+ 可恢复
56
+ ```
57
+
58
+ ---
59
+
60
+ ## 2.4 Deterministic Behavior
61
+
62
+ 相同输入:
63
+
64
+ ```text
65
+ 必须产生相同 env
66
+ ```
67
+
68
+ ---
69
+
70
+ # 3. 非目标(Non-Goals)
71
+
72
+ 本工具不会:
73
+
74
+ ```text
75
+ 不实现 sandbox
76
+ 不 hook Claude CLI
77
+ 不管理 token 生命周期
78
+ 不实现权限隔离
79
+ ```
80
+
81
+ ---
82
+
83
+ # 4. 配置存放目录结构(File System Layout)
84
+
85
+ 默认:
86
+
87
+ ```text
88
+ ~/.cc-env/
89
+ ```
90
+
91
+ 结构:
92
+
93
+ ```text
94
+ ~/.cc-env/
95
+
96
+ config.json
97
+
98
+ presets/
99
+ openai.json
100
+ azure.json
101
+ anthropic.json
102
+
103
+ history/
104
+ 2026-04-24T10-00-00.json
105
+
106
+ logs/
107
+ cc-env.log
108
+ ```
109
+
110
+ ---
111
+
112
+ # 5. 数据结构(Schemas)
113
+
114
+ 必须使用:
115
+
116
+ ```text
117
+ zod validation
118
+ ```
119
+
120
+ ---
121
+
122
+ ## 5.1 preset schema
123
+
124
+ ```json
125
+ {
126
+ "name": "openai",
127
+ "createdAt": "2026-04-24T10:00:00Z",
128
+ "updatedAt": "2026-04-24T10:00:00Z",
129
+ "env": {
130
+ "ANTHROPIC_BASE_URL": "https://api.openai.com",
131
+ "ANTHROPIC_AUTH_TOKEN": "sk-xxx"
132
+ }
133
+ }
134
+ ```
135
+
136
+ ---
137
+
138
+ 规则:
139
+
140
+ ```text
141
+ env 必须是 flat object
142
+ value 必须是 string
143
+ key 必须匹配:
144
+
145
+ ^[A-Z0-9_]+$
146
+ ```
147
+
148
+ ---
149
+
150
+ ## 5.2 history schema
151
+
152
+ ```json
153
+ {
154
+ "timestamp": "2026-04-24T10:00:00Z",
155
+ "action": "init",
156
+ "movedKeys": ["ANTHROPIC_BASE_URL"],
157
+ "backup": {
158
+ "ANTHROPIC_BASE_URL": "https://api.anthropic.com"
159
+ }
160
+ }
161
+ ```
162
+
163
+ ---
164
+
165
+ # 6. 环境变量优先级(Critical)
166
+
167
+ 优先级必须固定:
168
+
169
+ ```text
170
+ 1. project env
171
+ 2. preset
172
+ 3. process env
173
+ 4. ~/.claude/settings.json
174
+ ```
175
+
176
+ ---
177
+
178
+ ## 6.1 project env
179
+
180
+ 路径:
181
+
182
+ ```text
183
+ ./.cc-env/env.json
184
+ ./.cc-env/env.yaml
185
+ ```
186
+
187
+ ---
188
+
189
+ ## 示例
190
+
191
+ ```bash
192
+ .cc-env/env.json
193
+ ```
194
+
195
+ ```json
196
+ {
197
+ "ANTHROPIC_BASE_URL": "https://dev-api"
198
+ }
199
+ ```
200
+
201
+ ---
202
+
203
+ # 7. CLI 命令设计
204
+
205
+ ---
206
+
207
+ # 7.1 启动命令
208
+
209
+ ## 语法
210
+
211
+ ```bash
212
+ cc-env --preset=<name> <command>
213
+ ```
214
+
215
+ ---
216
+
217
+ ## 示例
218
+
219
+ ```bash
220
+ cc-env --preset=openai claude
221
+ ```
222
+
223
+ ---
224
+
225
+ ## 行为
226
+
227
+ cc-env:
228
+
229
+ ```text
230
+ load preset
231
+ merge env
232
+ spawn child process
233
+ inject env
234
+ ```
235
+
236
+ ---
237
+
238
+ ## Node.js 实现规范
239
+
240
+ 必须:
241
+
242
+ ```js
243
+ spawn(command, args, {
244
+ stdio: 'inherit',
245
+ env: mergedEnv
246
+ })
247
+ ```
248
+
249
+ ---
250
+
251
+ 不能:
252
+
253
+ ```js
254
+ exec()
255
+ ```
256
+
257
+ ---
258
+
259
+ ## 错误
260
+
261
+ ```text
262
+ Preset not found: openai
263
+ ```
264
+
265
+ exit code:
266
+
267
+ ```text
268
+ 1
269
+ ```
270
+
271
+ ---
272
+
273
+ # 7.2 init
274
+
275
+ ## 命令
276
+
277
+ ```bash
278
+ cc-env --init
279
+ ```
280
+
281
+ ---
282
+
283
+ ## 目标
284
+
285
+ 迁移:
286
+
287
+ ```text
288
+ ~/.claude/settings.json
289
+ ```
290
+
291
+ 中的:
292
+
293
+ ```json
294
+ env
295
+ ```
296
+
297
+ 到:
298
+
299
+ ```text
300
+ ~/.cc-env/history
301
+ ```
302
+
303
+ ---
304
+
305
+ ## React Ink UI
306
+
307
+ ```text
308
+ Move env from settings.json
309
+
310
+ [✓] ANTHROPIC_AUTH_TOKEN
311
+ sk-1234********
312
+
313
+ [✓] ANTHROPIC_BASE_URL
314
+ https://api.openai.com
315
+
316
+ [ ] CUSTOM_VAR
317
+ custom
318
+
319
+ Confirm move?
320
+
321
+ (Y/N)
322
+ ```
323
+
324
+ ---
325
+
326
+ ## 行为
327
+
328
+ ```text
329
+ backup env
330
+ remove env from settings.json
331
+ write history
332
+ ```
333
+
334
+ ---
335
+
336
+ ## 幂等
337
+
338
+ 如果:
339
+
340
+ ```text
341
+ env 不存在
342
+ ```
343
+
344
+ 输出:
345
+
346
+ ```text
347
+ No env field found
348
+ ```
349
+
350
+ ---
351
+
352
+ # 7.3 restore
353
+
354
+ ## 命令
355
+
356
+ ```bash
357
+ cc-env restore
358
+ ```
359
+
360
+ ---
361
+
362
+ ## React Ink UI
363
+
364
+ ```text
365
+ Restore record
366
+
367
+ 2026-04-24 10:00
368
+
369
+ ANTHROPIC_BASE_URL
370
+ https://api.openai.com
371
+
372
+ Confirm restore?
373
+
374
+ (Y/N)
375
+ ```
376
+
377
+ ---
378
+
379
+ ## 冲突处理
380
+
381
+ ```text
382
+ Key already exists
383
+
384
+ Overwrite?
385
+
386
+ (Y/N)
387
+ ```
388
+
389
+ ---
390
+
391
+ # 7.4 preset create
392
+
393
+ ---
394
+
395
+ ## 命令
396
+
397
+ ```bash
398
+ cc-env preset create
399
+ ```
400
+
401
+ ---
402
+
403
+ ## 支持方式
404
+
405
+ ---
406
+
407
+ ### 方式 1 — 交互
408
+
409
+ ```bash
410
+ cc-env preset create
411
+ ```
412
+
413
+ React Ink:
414
+
415
+ ```text
416
+ Select variables:
417
+
418
+ [✓] ANTHROPIC_AUTH_TOKEN
419
+ [✓] ANTHROPIC_BASE_URL
420
+ [ ] CUSTOM_VAR
421
+ ```
422
+
423
+ ---
424
+
425
+ ### 方式 2 — 文件导入
426
+
427
+ ```bash
428
+ cc-env preset create --file env.yaml
429
+ ```
430
+
431
+ ---
432
+
433
+ 支持:
434
+
435
+ ```yaml
436
+ ANTHROPIC_BASE_URL: https://api.openai.com
437
+ ```
438
+
439
+ ---
440
+
441
+ ### 方式 3 — inline
442
+
443
+ ```bash
444
+ cc-env preset create \
445
+ ANTHROPIC_BASE_URL=https://api.openai.com \
446
+ ANTHROPIC_AUTH_TOKEN=xxx
447
+ ```
448
+
449
+ ---
450
+
451
+ ## 限制
452
+
453
+ 必须:
454
+
455
+ ```text
456
+ flat object only
457
+ ```
458
+
459
+ ---
460
+
461
+ # 7.5 preset list
462
+
463
+ ## 命令
464
+
465
+ ```bash
466
+ cc-env preset list
467
+ ```
468
+
469
+ ---
470
+
471
+ 输出:
472
+
473
+ ```text
474
+ NAME UPDATED VARS
475
+ openai 2026-04-24 6
476
+ azure 2026-04-23 5
477
+ ```
478
+
479
+ ---
480
+
481
+ # 7.6 preset show
482
+
483
+ ## 命令
484
+
485
+ ```bash
486
+ cc-env preset show openai
487
+ ```
488
+
489
+ ---
490
+
491
+ 输出:
492
+
493
+ ```text
494
+ Preset: openai
495
+
496
+ ANTHROPIC_BASE_URL
497
+ https://api.openai.com
498
+
499
+ ANTHROPIC_AUTH_TOKEN
500
+ sk-1234********
501
+ ```
502
+
503
+ ---
504
+
505
+ ## 安全规则
506
+
507
+ 必须 mask:
508
+
509
+ ```text
510
+ *_TOKEN
511
+ *_KEY
512
+ *_SECRET
513
+ ```
514
+
515
+ ---
516
+
517
+ # 7.7 preset delete
518
+
519
+ ```bash
520
+ cc-env preset delete openai
521
+ ```
522
+
523
+ ---
524
+
525
+ 必须:
526
+
527
+ ```text
528
+ Confirm delete?
529
+
530
+ (Y/N)
531
+ ```
532
+
533
+ ---
534
+
535
+ # 7.8 preset edit
536
+
537
+ ```bash
538
+ cc-env preset edit openai
539
+ ```
540
+
541
+ ---
542
+
543
+ 默认:
544
+
545
+ ```text
546
+ use $EDITOR
547
+ ```
548
+
549
+ ---
550
+
551
+ # 7.9 debug(强烈建议)
552
+
553
+ ## 命令
554
+
555
+ ```bash
556
+ cc-env debug
557
+ ```
558
+
559
+ ---
560
+
561
+ 输出:
562
+
563
+ ```text
564
+ Active env:
565
+
566
+ Source: preset=openai
567
+
568
+ ANTHROPIC_BASE_URL
569
+ https://api.openai.com
570
+
571
+ ANTHROPIC_AUTH_TOKEN
572
+ sk-1234********
573
+ ```
574
+
575
+ ---
576
+
577
+ # 8. React Ink 使用范围(明确)
578
+
579
+ 必须:
580
+
581
+ ```text
582
+ 只用于复杂交互
583
+ ```
584
+
585
+ ---
586
+
587
+ 使用:
588
+
589
+ ```text
590
+ preset create
591
+ init
592
+ restore
593
+ interactive select
594
+ ```
595
+
596
+ ---
597
+
598
+ 不使用:
599
+
600
+ ```text
601
+ preset list
602
+ preset show
603
+ debug
604
+ ```
605
+
606
+ ---
607
+
608
+ 原因:
609
+
610
+ ```text
611
+ 保持 CLI 简洁
612
+ 避免性能开销
613
+ ```
614
+
615
+ ---
616
+
617
+ # 9. 环境变量合并逻辑(Deterministic)
618
+
619
+ 必须按顺序:
620
+
621
+ ```text
622
+ settings.json env
623
+ → process.env
624
+ → preset
625
+ → project env
626
+ ```
627
+
628
+ ---
629
+
630
+ 示例:
631
+
632
+ ```text
633
+ settings.json:
634
+
635
+ BASE_URL=a
636
+
637
+ process.env:
638
+
639
+ BASE_URL=b
640
+
641
+ preset:
642
+
643
+ BASE_URL=c
644
+
645
+ project:
646
+
647
+ BASE_URL=d
648
+ ```
649
+
650
+ ---
651
+
652
+ 最终:
653
+
654
+ ```text
655
+ BASE_URL=d
656
+ ```
657
+
658
+ ---
659
+
660
+ # 10. 技术栈(Final)
661
+
662
+ ---
663
+
664
+ ## Runtime
665
+
666
+ ```text
667
+ Node.js >= 20
668
+ TypeScript
669
+ ```
670
+
671
+ ---
672
+
673
+ ## CLI
674
+
675
+ ```text
676
+ commander
677
+ ```
678
+
679
+ ---
680
+
681
+ ## UI
682
+
683
+ ```text
684
+ react ink
685
+ @inkjs/ui
686
+ ```
687
+
688
+ ---
689
+
690
+ ## validation
691
+
692
+ ```text
693
+ zod
694
+ ```
695
+
696
+ ---
697
+
698
+ ## file utils
699
+
700
+ ```text
701
+ fs-extra
702
+ ```
703
+
704
+ ---
705
+
706
+ ## YAML
707
+
708
+ ```text
709
+ yaml
710
+ ```
711
+
712
+ ---
713
+
714
+ ## spawn
715
+
716
+ ```text
717
+ cross-spawn
718
+ ```
719
+
720
+ ---
721
+
722
+ ## concurrency
723
+
724
+ ```text
725
+ proper-lockfile
726
+ ```
727
+
728
+ ---
729
+
730
+ ## logging
731
+
732
+ ```text
733
+ pino
734
+ ```
735
+
736
+ ---
737
+
738
+ # 11. 安全要求(Mandatory)
739
+
740
+ ---
741
+
742
+ ## 禁止打印:
743
+
744
+ ```text
745
+ TOKEN
746
+ SECRET
747
+ KEY
748
+ PASSWORD
749
+ ```
750
+
751
+ ---
752
+
753
+ ## 必须:
754
+
755
+ ```text
756
+ mask sensitive values
757
+ ```
758
+
759
+ ---
760
+
761
+ 示例:
762
+
763
+ ```text
764
+ sk-123456********
765
+ ```
766
+
767
+ ---
768
+
769
+ # 12. 并发控制(Mandatory)
770
+
771
+ 所有写操作必须:
772
+
773
+ ```text
774
+ file lock
775
+ ```
776
+
777
+ ---
778
+
779
+ 否则:
780
+
781
+ ```text
782
+ history corruption
783
+ ```
784
+
785
+ ---
786
+
787
+ 推荐:
788
+
789
+ ```text
790
+ proper-lockfile
791
+ ```
792
+
793
+ ---
794
+
795
+ # 13. Shell 兼容性(Mandatory)
796
+
797
+ 必须支持:
798
+
799
+ ```text
800
+ bash
801
+ zsh
802
+ fish
803
+ ```
804
+
805
+ ---
806
+
807
+ 不能:
808
+
809
+ ```text
810
+ 依赖 shell 行为
811
+ ```
812
+
813
+ ---
814
+
815
+ # 14. 可测试性(Mandatory)
816
+
817
+ ---
818
+
819
+ ## dry run
820
+
821
+ ```bash
822
+ cc-env --dry-run
823
+ ```
824
+
825
+ ---
826
+
827
+ 输出:
828
+
829
+ ```text
830
+ Would run:
831
+
832
+ ANTHROPIC_BASE_URL=https://api.openai.com
833
+
834
+ claude
835
+ ```
836
+
837
+ ---
838
+
839
+ 不执行:
840
+
841
+ ```text
842
+ spawn
843
+ write file
844
+ ```
845
+
846
+ ---
847
+
848
+ # 15. Logging 规范
849
+
850
+ ---
851
+
852
+ 日志:
853
+
854
+ ```text
855
+ ~/.cc-env/logs/cc-env.log
856
+ ```
857
+
858
+ ---
859
+
860
+ 必须记录:
861
+
862
+ ```text
863
+ timestamp
864
+ command
865
+ result
866
+ error
867
+ ```
868
+
869
+ ---
870
+
871
+ 不能记录:
872
+
873
+ ```text
874
+ token
875
+ secret
876
+ key
877
+ ```
878
+
879
+ ---
880
+
881
+ # 16. 错误处理规范
882
+
883
+ ---
884
+
885
+ 所有错误必须:
886
+
887
+ ```text
888
+ human readable
889
+ no stack trace
890
+ exit code
891
+ ```
892
+
893
+ ---
894
+
895
+ 示例:
896
+
897
+ ```text
898
+ Preset not found: openai
899
+ ```
900
+
901
+ exit:
902
+
903
+ ```text
904
+ 1
905
+ ```
906
+
907
+ ---
908
+
909
+ # 17. 引用
910
+
911
+ ### [claude code 官方支持 env](../references/claude-code-env.md)