@quonfig/cli 0.0.11 → 0.0.13

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 (106) hide show
  1. package/README.md +214 -30
  2. package/dist/codegen/json-schema-to-zod.js +7 -5
  3. package/dist/codegen/language-mappers/zod-base-mapper.d.ts +2 -2
  4. package/dist/codegen/language-mappers/zod-to-string-mapper.d.ts +2 -2
  5. package/dist/codegen/language-mappers/zod-to-string-mapper.js +6 -6
  6. package/dist/codegen/language-mappers/zod-to-typescript-mapper.d.ts +2 -2
  7. package/dist/codegen/language-mappers/zod-to-typescript-mapper.js +6 -6
  8. package/dist/codegen/language-mappers/zod-to-typescript-return-value-mapper.d.ts +2 -2
  9. package/dist/codegen/language-mappers/zod-to-typescript-return-value-mapper.js +5 -5
  10. package/dist/codegen/local-config-reader.js +0 -1
  11. package/dist/codegen/schema-extractor.js +5 -2
  12. package/dist/commands/info.js +4 -1
  13. package/dist/commands/init.js +12 -2
  14. package/dist/commands/interactive.d.ts +1 -0
  15. package/dist/commands/interactive.js +8 -0
  16. package/dist/commands/login.js +9 -3
  17. package/dist/commands/migrate/doctor.d.ts +12 -0
  18. package/dist/commands/migrate/doctor.js +63 -0
  19. package/dist/commands/migrate/my-code.d.ts +11 -0
  20. package/dist/commands/migrate/my-code.js +80 -0
  21. package/dist/commands/migrate/status.d.ts +10 -0
  22. package/dist/commands/migrate/status.js +99 -0
  23. package/dist/commands/migrate.d.ts +20 -0
  24. package/dist/commands/migrate.js +277 -0
  25. package/dist/commands/override.js +6 -3
  26. package/dist/commands/profile.d.ts +1 -1
  27. package/dist/commands/profile.js +1 -1
  28. package/dist/commands/pull.d.ts +2 -2
  29. package/dist/commands/pull.js +38 -41
  30. package/dist/commands/schema.d.ts +3 -3
  31. package/dist/commands/schema.js +37 -37
  32. package/dist/commands/sdk-key/create.js +12 -14
  33. package/dist/commands/sdk-key/revoke.d.ts +1 -1
  34. package/dist/commands/sdk-key/revoke.js +2 -4
  35. package/dist/commands/set-default.js +7 -5
  36. package/dist/commands/set-rollout.d.ts +1 -1
  37. package/dist/commands/set-rollout.js +16 -13
  38. package/dist/commands/sync.d.ts +3 -3
  39. package/dist/commands/sync.js +30 -26
  40. package/dist/commands/whoami.js +1 -5
  41. package/dist/commands/workspace/bootstrap.js +7 -7
  42. package/dist/commands/workspace/switch.js +2 -2
  43. package/dist/init/init-workspace.d.ts +2 -2
  44. package/dist/init/init-workspace.js +32 -18
  45. package/dist/init/samples.d.ts +1 -1
  46. package/dist/init/samples.js +2 -2
  47. package/dist/init/schema.js +24 -15
  48. package/dist/interactive-prompt.js +1 -10
  49. package/dist/migrate/doctor.d.ts +27 -0
  50. package/dist/migrate/doctor.js +222 -0
  51. package/dist/migrate/identifier-map.d.ts +14 -0
  52. package/dist/migrate/identifier-map.js +55 -0
  53. package/dist/migrate/import-state.d.ts +14 -0
  54. package/dist/migrate/import-state.js +60 -0
  55. package/dist/migrate/local-write.d.ts +26 -0
  56. package/dist/migrate/local-write.js +85 -0
  57. package/dist/migrate/migration-report.d.ts +42 -0
  58. package/dist/migrate/migration-report.js +85 -0
  59. package/dist/migrate/push-strategy.d.ts +34 -0
  60. package/dist/migrate/push-strategy.js +127 -0
  61. package/dist/migrate/push-to-cloud.d.ts +15 -0
  62. package/dist/migrate/push-to-cloud.js +31 -0
  63. package/dist/migrate/registry.d.ts +6 -0
  64. package/dist/migrate/registry.js +25 -0
  65. package/dist/migrate/source.d.ts +22 -0
  66. package/dist/migrate/source.js +12 -0
  67. package/dist/migrate/sources/flagsmith.d.ts +2 -0
  68. package/dist/migrate/sources/flagsmith.js +28 -0
  69. package/dist/migrate/sources/launch/api.d.ts +7 -0
  70. package/dist/migrate/sources/launch/api.js +75 -0
  71. package/dist/migrate/sources/launch/translate.d.ts +6 -0
  72. package/dist/migrate/sources/launch/translate.js +190 -0
  73. package/dist/migrate/sources/launch/types.d.ts +68 -0
  74. package/dist/migrate/sources/launch/types.js +1 -0
  75. package/dist/migrate/sources/launch.d.ts +3 -0
  76. package/dist/migrate/sources/launch.js +70 -0
  77. package/dist/migrate/sources/launchdarkly.d.ts +2 -0
  78. package/dist/migrate/sources/launchdarkly.js +18 -0
  79. package/dist/quonfig.d.ts +1 -1
  80. package/dist/quonfig.js +5 -9
  81. package/dist/ui/get-confirmation.d.ts +2 -1
  82. package/dist/ui/get-confirmation.js +9 -1
  83. package/dist/ui/get-value.d.ts +1 -1
  84. package/dist/ui/get-value.js +4 -3
  85. package/dist/util/config-value-dto.js +17 -1
  86. package/dist/util/encryption.js +4 -1
  87. package/dist/util/friction-log.d.ts +1 -1
  88. package/dist/util/friction-log.js +5 -1
  89. package/dist/util/get-client.js +51 -3
  90. package/dist/util/get-valid-token.d.ts +4 -0
  91. package/dist/util/get-valid-token.js +17 -2
  92. package/dist/util/git-ops.js +7 -7
  93. package/dist/util/gitea-api.d.ts +2 -2
  94. package/dist/util/gitea-api.js +5 -3
  95. package/dist/util/gitea-token-storage.d.ts +2 -2
  96. package/dist/util/gitea-token-storage.js +1 -1
  97. package/dist/util/is-interactive.d.ts +21 -1
  98. package/dist/util/is-interactive.js +21 -1
  99. package/dist/util/oauth-client.js +1 -1
  100. package/dist/util/token-storage.js +2 -2
  101. package/dist/verify/standalone.d.ts +0 -1
  102. package/dist/verify/standalone.js +22 -23
  103. package/dist/verify/validate.d.ts +8 -8
  104. package/dist/verify/validate.js +256 -245
  105. package/oclif.manifest.json +365 -3
  106. package/package.json +6 -6
package/README.md CHANGED
@@ -14,7 +14,7 @@ $ npm install -g @quonfig/cli
14
14
  $ qfg COMMAND
15
15
  running command...
16
16
  $ qfg (--version)
17
- @quonfig/cli/0.0.11 linux-x64 node-v24.4.1
17
+ @quonfig/cli/0.0.13 linux-x64 node-v24.4.1
18
18
  $ qfg --help [COMMAND]
19
19
  USAGE
20
20
  $ qfg COMMAND
@@ -40,6 +40,10 @@ USAGE
40
40
  * [`qfg login`](#qfg-login)
41
41
  * [`qfg logout`](#qfg-logout)
42
42
  * [`qfg mcp`](#qfg-mcp)
43
+ * [`qfg migrate`](#qfg-migrate)
44
+ * [`qfg migrate doctor`](#qfg-migrate-doctor)
45
+ * [`qfg migrate my-code`](#qfg-migrate-my-code)
46
+ * [`qfg migrate status`](#qfg-migrate-status)
43
47
  * [`qfg override [NAME]`](#qfg-override-name)
44
48
  * [`qfg pull`](#qfg-pull)
45
49
  * [`qfg schema NAME`](#qfg-schema-name)
@@ -84,7 +88,7 @@ EXAMPLES
84
88
  $ qfg config-schema --json-schema # full JSON Schema document (copy into your editor)
85
89
  ```
86
90
 
87
- _See code: [src/commands/config-schema.ts](https://github.com/quonfig/cli/blob/v0.0.11/src/commands/config-schema.ts)_
91
+ _See code: [src/commands/config-schema.ts](https://github.com/quonfig/cli/blob/v0.0.13/src/commands/config-schema.ts)_
88
92
 
89
93
  ## `qfg create NAME`
90
94
 
@@ -156,7 +160,7 @@ EXAMPLES
156
160
  $ qfg set-rollout my.new.flag --environment production --true-percent 20
157
161
  ```
158
162
 
159
- _See code: [src/commands/create.ts](https://github.com/quonfig/cli/blob/v0.0.11/src/commands/create.ts)_
163
+ _See code: [src/commands/create.ts](https://github.com/quonfig/cli/blob/v0.0.13/src/commands/create.ts)_
160
164
 
161
165
  ## `qfg flag info [NAME]`
162
166
 
@@ -356,7 +360,7 @@ EXAMPLES
356
360
  $ qfg generate --targets node-ts -o ./dist # combine with targets
357
361
  ```
358
362
 
359
- _See code: [src/commands/generate.ts](https://github.com/quonfig/cli/blob/v0.0.11/src/commands/generate.ts)_
363
+ _See code: [src/commands/generate.ts](https://github.com/quonfig/cli/blob/v0.0.13/src/commands/generate.ts)_
360
364
 
361
365
  ## `qfg generate-new-hex-key`
362
366
 
@@ -379,7 +383,7 @@ EXAMPLES
379
383
  $ qfg generate-new-hex-key
380
384
  ```
381
385
 
382
- _See code: [src/commands/generate-new-hex-key.ts](https://github.com/quonfig/cli/blob/v0.0.11/src/commands/generate-new-hex-key.ts)_
386
+ _See code: [src/commands/generate-new-hex-key.ts](https://github.com/quonfig/cli/blob/v0.0.13/src/commands/generate-new-hex-key.ts)_
383
387
 
384
388
  ## `qfg get [NAME]`
385
389
 
@@ -411,7 +415,7 @@ EXAMPLES
411
415
  $ qfg get my.config.name --environment=production
412
416
  ```
413
417
 
414
- _See code: [src/commands/get.ts](https://github.com/quonfig/cli/blob/v0.0.11/src/commands/get.ts)_
418
+ _See code: [src/commands/get.ts](https://github.com/quonfig/cli/blob/v0.0.13/src/commands/get.ts)_
415
419
 
416
420
  ## `qfg info [NAME]`
417
421
 
@@ -459,7 +463,7 @@ EXAMPLES
459
463
  $ qfg info my.config.name --exclude-evaluations # skip 24h stats
460
464
  ```
461
465
 
462
- _See code: [src/commands/info.ts](https://github.com/quonfig/cli/blob/v0.0.11/src/commands/info.ts)_
466
+ _See code: [src/commands/info.ts](https://github.com/quonfig/cli/blob/v0.0.13/src/commands/info.ts)_
463
467
 
464
468
  ## `qfg init [DIRECTORY]`
465
469
 
@@ -497,10 +501,12 @@ EXAMPLES
497
501
  $ qfg init --dry-run
498
502
  ```
499
503
 
500
- _See code: [src/commands/init.ts](https://github.com/quonfig/cli/blob/v0.0.11/src/commands/init.ts)_
504
+ _See code: [src/commands/init.ts](https://github.com/quonfig/cli/blob/v0.0.13/src/commands/init.ts)_
501
505
 
502
506
  ## `qfg interactive`
503
507
 
508
+ Launch an interactive menu to browse and manage your workspace.
509
+
504
510
  ```
505
511
  USAGE
506
512
  $ qfg interactive [--json] [--interactive] [--no-color] [--verbose]
@@ -511,11 +517,21 @@ GLOBAL FLAGS
511
517
  --no-color Do not colorize output
512
518
  --verbose Verbose output
513
519
 
520
+ DESCRIPTION
521
+ Launch an interactive menu to browse and manage your workspace.
522
+
523
+ Common shortcuts:
524
+ qfg set-default my.flag --environment production --value false # catch-all fallback
525
+ qfg set-rollout my.flag --environment production --true-percent 20 # % rollout
526
+
527
+ For arbitrary targeting rules (e.g. user.email, plan, segment, custom property),
528
+ run 'qfg config-schema' then 'qfg pull' and edit the JSON config directly.
529
+
514
530
  EXAMPLES
515
531
  $ qfg
516
532
  ```
517
533
 
518
- _See code: [src/commands/interactive.ts](https://github.com/quonfig/cli/blob/v0.0.11/src/commands/interactive.ts)_
534
+ _See code: [src/commands/interactive.ts](https://github.com/quonfig/cli/blob/v0.0.13/src/commands/interactive.ts)_
519
535
 
520
536
  ## `qfg list`
521
537
 
@@ -555,7 +571,7 @@ EXAMPLES
555
571
  $ qfg list --feature-flags
556
572
  ```
557
573
 
558
- _See code: [src/commands/list.ts](https://github.com/quonfig/cli/blob/v0.0.11/src/commands/list.ts)_
574
+ _See code: [src/commands/list.ts](https://github.com/quonfig/cli/blob/v0.0.13/src/commands/list.ts)_
559
575
 
560
576
  ## `qfg login`
561
577
 
@@ -580,7 +596,7 @@ EXAMPLES
580
596
  $ qfg login --profile myprofile
581
597
  ```
582
598
 
583
- _See code: [src/commands/login.ts](https://github.com/quonfig/cli/blob/v0.0.11/src/commands/login.ts)_
599
+ _See code: [src/commands/login.ts](https://github.com/quonfig/cli/blob/v0.0.13/src/commands/login.ts)_
584
600
 
585
601
  ## `qfg logout`
586
602
 
@@ -603,7 +619,7 @@ EXAMPLES
603
619
  $ qfg logout
604
620
  ```
605
621
 
606
- _See code: [src/commands/logout.ts](https://github.com/quonfig/cli/blob/v0.0.11/src/commands/logout.ts)_
622
+ _See code: [src/commands/logout.ts](https://github.com/quonfig/cli/blob/v0.0.13/src/commands/logout.ts)_
607
623
 
608
624
  ## `qfg mcp`
609
625
 
@@ -636,11 +652,166 @@ EXAMPLES
636
652
  $ qfg mcp --url http://local-app.quonfig-staging.com:3003/api/v1/mcp
637
653
  ```
638
654
 
639
- _See code: [src/commands/mcp.ts](https://github.com/quonfig/cli/blob/v0.0.11/src/commands/mcp.ts)_
655
+ _See code: [src/commands/mcp.ts](https://github.com/quonfig/cli/blob/v0.0.13/src/commands/mcp.ts)_
656
+
657
+ ## `qfg migrate`
658
+
659
+ Migrate flags and configs from a legacy feature-flag system into a Quonfig workspace.
660
+
661
+ ```
662
+ USAGE
663
+ $ qfg migrate --from launch|launchdarkly|flagsmith [--json] [--interactive] [--no-color] [--verbose]
664
+ [--api-key <value>] [--dir <value>] [--dry-run] [--push] [--recent <value>] [--reset] [--since <value>] [--staging]
665
+ [--workspace <value>]
666
+
667
+ FLAGS
668
+ --api-key=<value> API key for the legacy source (or set LAUNCH_API_KEY)
669
+ --dir=<value> Target local workspace directory. Defaults to cwd if it looks like a Quonfig workspace, otherwise
670
+ ./quonfig-config.
671
+ --dry-run Fetch and summarize changes without writing anything
672
+ --from=<option> (required) Legacy source to migrate from
673
+ <options: launch|launchdarkly|flagsmith>
674
+ --push After migrating to a local dir, also push to the given --workspace on Quonfig cloud
675
+ --recent=<value> Import only the last N changes (useful for tire-kicking)
676
+ --reset Ignore the delta cursor and re-import everything from scratch
677
+ --since=<value> Override the delta cursor (epoch milliseconds or ISO-8601 timestamp)
678
+ --staging Hit the staging API for the source (dev-only)
679
+ --workspace=<value> Quonfig cloud workspace slug to push to. Requires `qfg login` and is typically combined with
680
+ --push.
681
+
682
+ GLOBAL FLAGS
683
+ --[no-]interactive Force interactive mode
684
+ --json Format output as json.
685
+ --no-color Do not colorize output
686
+ --verbose Verbose output
687
+
688
+ DESCRIPTION
689
+ Migrate flags and configs from a legacy feature-flag system into a Quonfig workspace.
690
+
691
+ Currently supported sources:
692
+ launch — Reforge Launch (ported from launch-migrator)
693
+
694
+ See https://docs.quonfig.com/docs/migrating/from-launch for the step-by-step guide,
695
+ and https://docs.quonfig.com/docs/migrating/troubleshooting when something goes sideways.
696
+
697
+ EXAMPLES
698
+ $ qfg migrate --from launch --api-key $LAUNCH_API_KEY --dir ./quonfig-config
699
+
700
+ $ qfg migrate --from launch --api-key $LAUNCH_API_KEY --workspace acme-prod --push
701
+
702
+ $ qfg migrate --from launch --api-key $LAUNCH_API_KEY --dir ./quonfig-config --reset
703
+
704
+ $ qfg migrate --from launch --api-key $LAUNCH_API_KEY --dir ./quonfig-config --dry-run
705
+
706
+ $ qfg migrate --from launch --api-key $LAUNCH_API_KEY --dir ./quonfig-config --staging
707
+ ```
708
+
709
+ _See code: [src/commands/migrate.ts](https://github.com/quonfig/cli/blob/v0.0.13/src/commands/migrate.ts)_
710
+
711
+ ## `qfg migrate doctor`
712
+
713
+ Preflight health checks for `qfg migrate`. Verifies auth, workspace provisioning, working tree, and identifier collisions.
714
+
715
+ ```
716
+ USAGE
717
+ $ qfg migrate doctor [--json] [--interactive] [--no-color] [--verbose] [--api-key <value>] [--dir <value>] [--from
718
+ launch] [--language <value>]
719
+
720
+ FLAGS
721
+ --api-key=<value> Legacy SDK API key to validate against the source
722
+ --dir=<value> [default: .] Workspace directory to check (git clean / identifier map)
723
+ --from=<option> [default: launch] Legacy SDK to migrate from
724
+ <options: launch>
725
+ --language=<value> Customer SDK language — used to warn when datadir mode is unavailable (e.g. javascript-browser)
726
+
727
+ GLOBAL FLAGS
728
+ --[no-]interactive Force interactive mode
729
+ --json Format output as json.
730
+ --no-color Do not colorize output
731
+ --verbose Verbose output
732
+
733
+ DESCRIPTION
734
+ Preflight health checks for `qfg migrate`. Verifies auth, workspace provisioning, working tree, and identifier
735
+ collisions.
736
+
737
+ EXAMPLES
738
+ $ qfg migrate doctor
739
+
740
+ $ qfg migrate doctor --from launch --api-key $LAUNCH_API_KEY
741
+
742
+ $ qfg migrate doctor --dir ./my-workspace --language node
743
+
744
+ $ qfg migrate doctor --json
745
+ ```
746
+
747
+ _See code: [src/commands/migrate/doctor.ts](https://github.com/quonfig/cli/blob/v0.0.13/src/commands/migrate/doctor.ts)_
748
+
749
+ ## `qfg migrate my-code`
750
+
751
+ Migrate Launch SDK call sites in your codebase to Quonfig SDK call sites (invokes the qfg-migrate-code Claude skill)
752
+
753
+ ```
754
+ USAGE
755
+ $ qfg migrate my-code [--json] [--interactive] [--no-color] [--verbose] [--dry-run] [--from launch]
756
+
757
+ FLAGS
758
+ --dry-run Show what would be migrated without editing any files
759
+ --from=<option> [default: launch] Legacy SDK to migrate from
760
+ <options: launch>
761
+
762
+ GLOBAL FLAGS
763
+ --[no-]interactive Force interactive mode
764
+ --json Format output as json.
765
+ --no-color Do not colorize output
766
+ --verbose Verbose output
767
+
768
+ DESCRIPTION
769
+ Migrate Launch SDK call sites in your codebase to Quonfig SDK call sites (invokes the qfg-migrate-code Claude skill)
770
+
771
+ EXAMPLES
772
+ $ qfg migrate my-code
773
+
774
+ $ qfg migrate my-code --from launch
775
+
776
+ $ qfg migrate my-code --dry-run
777
+ ```
778
+
779
+ _See code: [src/commands/migrate/my-code.ts](https://github.com/quonfig/cli/blob/v0.0.13/src/commands/migrate/my-code.ts)_
780
+
781
+ ## `qfg migrate status`
782
+
783
+ Show the status of a workspace migrated with `qfg migrate`. Reads .qf/import-state.json and summarizes source, counts, and next steps.
784
+
785
+ ```
786
+ USAGE
787
+ $ qfg migrate status [--json] [--interactive] [--no-color] [--verbose] [--dir <value>]
788
+
789
+ FLAGS
790
+ --dir=<value> [default: .] Workspace directory to inspect
791
+
792
+ GLOBAL FLAGS
793
+ --[no-]interactive Force interactive mode
794
+ --json Format output as json.
795
+ --no-color Do not colorize output
796
+ --verbose Verbose output
797
+
798
+ DESCRIPTION
799
+ Show the status of a workspace migrated with `qfg migrate`. Reads .qf/import-state.json and summarizes source, counts,
800
+ and next steps.
801
+
802
+ EXAMPLES
803
+ $ qfg migrate status
804
+
805
+ $ qfg migrate status --dir ./my-workspace
806
+
807
+ $ qfg migrate status --json
808
+ ```
809
+
810
+ _See code: [src/commands/migrate/status.ts](https://github.com/quonfig/cli/blob/v0.0.13/src/commands/migrate/status.ts)_
640
811
 
641
812
  ## `qfg override [NAME]`
642
813
 
643
- Override the value of an item for your user/SDK key combo
814
+ Override the value of an item for your user/SDK key combo.
644
815
 
645
816
  ```
646
817
  USAGE
@@ -663,7 +834,12 @@ GLOBAL FLAGS
663
834
  --verbose Verbose output
664
835
 
665
836
  DESCRIPTION
666
- Override the value of an item for your user/SDK key combo
837
+ Override the value of an item for your user/SDK key combo.
838
+
839
+ To target users other than yourself, or to express rules like "user.email == X → value Y",
840
+ you cannot use override — see:
841
+ qfg config-schema # operator reference + worked multi-rule example
842
+ qfg pull # clone the workspace so you can edit JSON directly
667
843
 
668
844
  EXAMPLES
669
845
  $ qfg override # will prompt for name and value
@@ -675,7 +851,7 @@ EXAMPLES
675
851
  $ qfg override my.double.config --value=3.14159
676
852
  ```
677
853
 
678
- _See code: [src/commands/override.ts](https://github.com/quonfig/cli/blob/v0.0.11/src/commands/override.ts)_
854
+ _See code: [src/commands/override.ts](https://github.com/quonfig/cli/blob/v0.0.13/src/commands/override.ts)_
679
855
 
680
856
  ## `qfg pull`
681
857
 
@@ -719,7 +895,7 @@ EXAMPLES
719
895
  $ qfg pull # uses QUONFIG_DIR env var
720
896
  ```
721
897
 
722
- _See code: [src/commands/pull.ts](https://github.com/quonfig/cli/blob/v0.0.11/src/commands/pull.ts)_
898
+ _See code: [src/commands/pull.ts](https://github.com/quonfig/cli/blob/v0.0.13/src/commands/pull.ts)_
723
899
 
724
900
  ## `qfg schema NAME`
725
901
 
@@ -757,7 +933,7 @@ EXAMPLES
757
933
  $ qfg schema my-schema --set-json-schema=@schemas/my-schema.json --protected
758
934
  ```
759
935
 
760
- _See code: [src/commands/schema.ts](https://github.com/quonfig/cli/blob/v0.0.11/src/commands/schema.ts)_
936
+ _See code: [src/commands/schema.ts](https://github.com/quonfig/cli/blob/v0.0.13/src/commands/schema.ts)_
761
937
 
762
938
  ## `qfg sdk-key`
763
939
 
@@ -784,7 +960,7 @@ EXAMPLES
784
960
  $ qfg sdk-key revoke <key-id>
785
961
  ```
786
962
 
787
- _See code: [src/commands/sdk-key.ts](https://github.com/quonfig/cli/blob/v0.0.11/src/commands/sdk-key.ts)_
963
+ _See code: [src/commands/sdk-key.ts](https://github.com/quonfig/cli/blob/v0.0.13/src/commands/sdk-key.ts)_
788
964
 
789
965
  ## `qfg sdk-key create`
790
966
 
@@ -816,7 +992,7 @@ EXAMPLES
816
992
  $ qfg sdk-key create --environment staging --type browser
817
993
  ```
818
994
 
819
- _See code: [src/commands/sdk-key/create.ts](https://github.com/quonfig/cli/blob/v0.0.11/src/commands/sdk-key/create.ts)_
995
+ _See code: [src/commands/sdk-key/create.ts](https://github.com/quonfig/cli/blob/v0.0.13/src/commands/sdk-key/create.ts)_
820
996
 
821
997
  ## `qfg sdk-key list`
822
998
 
@@ -845,7 +1021,7 @@ EXAMPLES
845
1021
  $ qfg sdk-key list --environment production
846
1022
  ```
847
1023
 
848
- _See code: [src/commands/sdk-key/list.ts](https://github.com/quonfig/cli/blob/v0.0.11/src/commands/sdk-key/list.ts)_
1024
+ _See code: [src/commands/sdk-key/list.ts](https://github.com/quonfig/cli/blob/v0.0.13/src/commands/sdk-key/list.ts)_
849
1025
 
850
1026
  ## `qfg sdk-key revoke KEYID`
851
1027
 
@@ -872,7 +1048,7 @@ EXAMPLES
872
1048
  $ qfg sdk-key revoke a1b2c3d4-e5f6-7890-abcd-ef1234567890
873
1049
  ```
874
1050
 
875
- _See code: [src/commands/sdk-key/revoke.ts](https://github.com/quonfig/cli/blob/v0.0.11/src/commands/sdk-key/revoke.ts)_
1051
+ _See code: [src/commands/sdk-key/revoke.ts](https://github.com/quonfig/cli/blob/v0.0.13/src/commands/sdk-key/revoke.ts)_
876
1052
 
877
1053
  ## `qfg set-default [NAME]`
878
1054
 
@@ -937,9 +1113,13 @@ EXAMPLES
937
1113
  # For a percentage rollout, use set-rollout instead:
938
1114
 
939
1115
  $ qfg set-rollout my.flag.name --environment production --true-percent 20
1116
+
1117
+ # For per-user / per-property targeting (e.g. user.email == X), edit JSON directly:
1118
+
1119
+ $ qfg pull && qfg config-schema
940
1120
  ```
941
1121
 
942
- _See code: [src/commands/set-default.ts](https://github.com/quonfig/cli/blob/v0.0.11/src/commands/set-default.ts)_
1122
+ _See code: [src/commands/set-default.ts](https://github.com/quonfig/cli/blob/v0.0.13/src/commands/set-default.ts)_
943
1123
 
944
1124
  ## `qfg set-rollout [NAME]`
945
1125
 
@@ -1016,7 +1196,7 @@ EXAMPLES
1016
1196
  $ qfg set-rollout my.variant.flag --environment production --weights "a:33,b:33,c:34" --hash-by user.id
1017
1197
  ```
1018
1198
 
1019
- _See code: [src/commands/set-rollout.ts](https://github.com/quonfig/cli/blob/v0.0.11/src/commands/set-rollout.ts)_
1199
+ _See code: [src/commands/set-rollout.ts](https://github.com/quonfig/cli/blob/v0.0.13/src/commands/set-rollout.ts)_
1020
1200
 
1021
1201
  ## `qfg sync`
1022
1202
 
@@ -1048,7 +1228,7 @@ EXAMPLES
1048
1228
  $ qfg sync --watch --dir ./our-config --interval 30
1049
1229
  ```
1050
1230
 
1051
- _See code: [src/commands/sync.ts](https://github.com/quonfig/cli/blob/v0.0.11/src/commands/sync.ts)_
1231
+ _See code: [src/commands/sync.ts](https://github.com/quonfig/cli/blob/v0.0.13/src/commands/sync.ts)_
1052
1232
 
1053
1233
  ## `qfg toggle [NAME]`
1054
1234
 
@@ -1113,6 +1293,10 @@ EXAMPLES
1113
1293
  # For a percentage rollout, use set-rollout instead:
1114
1294
 
1115
1295
  $ qfg set-rollout my.flag.name --environment production --true-percent 20
1296
+
1297
+ # For per-user / per-property targeting (e.g. user.email == X), edit JSON directly:
1298
+
1299
+ $ qfg pull && qfg config-schema
1116
1300
  ```
1117
1301
 
1118
1302
  ## `qfg verify [PATH]`
@@ -1146,7 +1330,7 @@ EXAMPLES
1146
1330
  $ qfg verify --json
1147
1331
  ```
1148
1332
 
1149
- _See code: [src/commands/verify.ts](https://github.com/quonfig/cli/blob/v0.0.11/src/commands/verify.ts)_
1333
+ _See code: [src/commands/verify.ts](https://github.com/quonfig/cli/blob/v0.0.13/src/commands/verify.ts)_
1150
1334
 
1151
1335
  ## `qfg whoami`
1152
1336
 
@@ -1169,7 +1353,7 @@ EXAMPLES
1169
1353
  $ qfg whoami
1170
1354
  ```
1171
1355
 
1172
- _See code: [src/commands/whoami.ts](https://github.com/quonfig/cli/blob/v0.0.11/src/commands/whoami.ts)_
1356
+ _See code: [src/commands/whoami.ts](https://github.com/quonfig/cli/blob/v0.0.13/src/commands/whoami.ts)_
1173
1357
 
1174
1358
  ## `qfg workspace`
1175
1359
 
@@ -1192,7 +1376,7 @@ EXAMPLES
1192
1376
  $ qfg workspace
1193
1377
  ```
1194
1378
 
1195
- _See code: [src/commands/workspace.ts](https://github.com/quonfig/cli/blob/v0.0.11/src/commands/workspace.ts)_
1379
+ _See code: [src/commands/workspace.ts](https://github.com/quonfig/cli/blob/v0.0.13/src/commands/workspace.ts)_
1196
1380
 
1197
1381
  ## `qfg workspace bootstrap`
1198
1382
 
@@ -1225,7 +1409,7 @@ EXAMPLES
1225
1409
  $ qfg workspace bootstrap --dir ./our-config --skip-validate
1226
1410
  ```
1227
1411
 
1228
- _See code: [src/commands/workspace/bootstrap.ts](https://github.com/quonfig/cli/blob/v0.0.11/src/commands/workspace/bootstrap.ts)_
1412
+ _See code: [src/commands/workspace/bootstrap.ts](https://github.com/quonfig/cli/blob/v0.0.13/src/commands/workspace/bootstrap.ts)_
1229
1413
 
1230
1414
  ## `qfg workspace switch`
1231
1415
 
@@ -1248,7 +1432,7 @@ EXAMPLES
1248
1432
  $ qfg workspace switch
1249
1433
  ```
1250
1434
 
1251
- _See code: [src/commands/workspace/switch.ts](https://github.com/quonfig/cli/blob/v0.0.11/src/commands/workspace/switch.ts)_
1435
+ _See code: [src/commands/workspace/switch.ts](https://github.com/quonfig/cli/blob/v0.0.13/src/commands/workspace/switch.ts)_
1252
1436
  <!-- commandsstop -->
1253
1437
 
1254
1438
  ## Local Development
@@ -100,11 +100,11 @@ function schemaToZod(schema) {
100
100
  const items = schema.prefixItems.map((item) => schemaToZod(item));
101
101
  result = z.tuple(items);
102
102
  }
103
- else if (schema.items !== undefined) {
104
- result = z.array(schemaToZod(schema.items));
103
+ else if (schema.items === undefined) {
104
+ result = z.array(z.any());
105
105
  }
106
106
  else {
107
- result = z.array(z.any());
107
+ result = z.array(schemaToZod(schema.items));
108
108
  }
109
109
  break;
110
110
  }
@@ -121,12 +121,14 @@ function schemaToZod(schema) {
121
121
  default: {
122
122
  if (Array.isArray(schema.oneOf)) {
123
123
  const options = schema.oneOf.map((item) => schemaToZod(item));
124
- result = options.length === 1 ? options[0] : z.union(options);
124
+ result =
125
+ options.length === 1 ? options[0] : z.union(options);
125
126
  break;
126
127
  }
127
128
  if (Array.isArray(schema.anyOf)) {
128
129
  const options = schema.anyOf.map((item) => schemaToZod(item));
129
- result = options.length === 1 ? options[0] : z.union(options);
130
+ result =
131
+ options.length === 1 ? options[0] : z.union(options);
130
132
  break;
131
133
  }
132
134
  if (Array.isArray(schema.allOf) && schema.allOf.length === 1) {
@@ -20,12 +20,12 @@ export declare abstract class ZodBaseMapper {
20
20
  protected abstract function(args: string, returns: string): string;
21
21
  protected abstract functionArguments(value?: $ZodFunctionArgs): string;
22
22
  protected abstract functionReturns(value: $ZodFunctionOut): string;
23
- protected abstract null(): string;
24
23
  protected abstract literal(value: string | number | boolean | null): string;
24
+ protected abstract never(): string;
25
+ protected abstract null(): string;
25
26
  protected abstract number(isInteger: boolean): string;
26
27
  protected abstract object(properties: [string, z.ZodTypeAny][]): string;
27
28
  protected abstract optional(wrappedType: string): string;
28
- protected abstract never(): string;
29
29
  protected abstract record(keyType: string, valueType: string): string;
30
30
  protected abstract string(): string;
31
31
  protected abstract tuple(wrappedTypes: string[]): string;
@@ -9,12 +9,12 @@ export declare class ZodToStringMapper extends ZodBaseMapper {
9
9
  function(input: string, output: string): string;
10
10
  functionArguments(value?: $ZodFunctionArgs): string;
11
11
  functionReturns(value: $ZodFunctionOut): string;
12
- null(): string;
13
12
  literal(value: string | number | boolean | null): string;
13
+ never(): string;
14
+ null(): string;
14
15
  number(isInteger?: boolean): "z.number()" | "z.number().int()";
15
16
  object(properties: [string, z.ZodTypeAny][]): string;
16
17
  optional(wrappedType: string): string;
17
- never(): string;
18
18
  record(keyType: string, valueType: string): string;
19
19
  renderField(type: z.ZodTypeAny, key?: string): string;
20
20
  string(): string;
@@ -31,12 +31,15 @@ export class ZodToStringMapper extends ZodBaseMapper {
31
31
  const mapper = new ZodToStringMapper();
32
32
  return mapper.resolveType(value);
33
33
  }
34
- null() {
35
- return 'z.null()';
36
- }
37
34
  literal(value) {
38
35
  return `z.literal(${JSON.stringify(value)})`;
39
36
  }
37
+ never() {
38
+ return 'z.never()';
39
+ }
40
+ null() {
41
+ return 'z.null()';
42
+ }
40
43
  number(isInteger = false) {
41
44
  const base = 'z.number()';
42
45
  if (isInteger) {
@@ -56,9 +59,6 @@ export class ZodToStringMapper extends ZodBaseMapper {
56
59
  optional(wrappedType) {
57
60
  return `${wrappedType}.optional()`;
58
61
  }
59
- never() {
60
- return 'z.never()';
61
- }
62
62
  record(keyType, valueType) {
63
63
  return `z.record(${keyType}, ${valueType})`;
64
64
  }
@@ -18,12 +18,12 @@ export declare class ZodToTypescriptMapper extends ZodBaseMapper {
18
18
  function(args: string, returns: string): string;
19
19
  functionArguments(value?: z.ZodTuple): string;
20
20
  functionReturns(value: z.ZodTypeAny): string;
21
- null(): string;
22
21
  literal(value: string | number | boolean | null): string;
22
+ never(): string;
23
+ null(): string;
23
24
  number(): string;
24
25
  object(properties: [string, z.ZodTypeAny][]): string;
25
26
  optional(wrappedType: string): string;
26
- never(): string;
27
27
  record(keyType: string, valueType: string): string;
28
28
  renderField(type: ZodTypeSupported): string;
29
29
  string(): string;
@@ -41,12 +41,15 @@ export class ZodToTypescriptMapper extends ZodBaseMapper {
41
41
  const mapper = new ZodToTypescriptMapper();
42
42
  return mapper.resolveType(value);
43
43
  }
44
- null() {
45
- return 'null';
46
- }
47
44
  literal(value) {
48
45
  return JSON.stringify(value);
49
46
  }
47
+ never() {
48
+ return 'never';
49
+ }
50
+ null() {
51
+ return 'null';
52
+ }
50
53
  number() {
51
54
  return 'number';
52
55
  }
@@ -68,9 +71,6 @@ export class ZodToTypescriptMapper extends ZodBaseMapper {
68
71
  // Fallback to a union type w/undefined for inline optional definitions
69
72
  return this.union([wrappedType, 'undefined']);
70
73
  }
71
- never() {
72
- return 'never';
73
- }
74
74
  record(keyType, valueType) {
75
75
  return `Record<${keyType}, ${valueType}>`;
76
76
  }
@@ -17,12 +17,12 @@ export declare class ZodToTypescriptReturnValueMapper extends ZodBaseMapper {
17
17
  function(args: string, returns: string): string;
18
18
  functionArguments(value?: z.ZodTuple): string;
19
19
  functionReturns(): string;
20
- null(): string;
21
20
  literal(): string;
21
+ never(): string;
22
+ null(): string;
22
23
  number(): string;
23
24
  object(properties: [string, z.ZodTypeAny][]): string;
24
25
  optional(wrappedType: string): string;
25
- never(): string;
26
26
  record(): string;
27
27
  renderField(type: ZodTypeSupported): string;
28
28
  string(): string;
@@ -36,10 +36,13 @@ export class ZodToTypescriptReturnValueMapper extends ZodBaseMapper {
36
36
  functionReturns() {
37
37
  return `Mustache.render(raw${this.printPropertyPath()} ?? "", ${this.FUNCTION_ARGUMENTS_NAME})`;
38
38
  }
39
- null() {
39
+ literal() {
40
40
  return `raw${this.printPropertyPath()}`;
41
41
  }
42
- literal() {
42
+ never() {
43
+ return `raw${this.printPropertyPath()}`;
44
+ }
45
+ null() {
43
46
  return `raw${this.printPropertyPath()}`;
44
47
  }
45
48
  number() {
@@ -65,9 +68,6 @@ export class ZodToTypescriptReturnValueMapper extends ZodBaseMapper {
65
68
  // Fallback to a union type w/undefined for inline optional definitions
66
69
  return this.union([wrappedType, 'undefined']);
67
70
  }
68
- never() {
69
- return `raw${this.printPropertyPath()}`;
70
- }
71
71
  record() {
72
72
  // Explicitly not supporting navigation into record values, as the keys are not known at compile time
73
73
  return `raw${this.printPath(this.returnTypePropertyPath)}`;
@@ -18,7 +18,6 @@ function mapGitValue(gitValue) {
18
18
  case 'string_list': {
19
19
  return { value: { string: JSON.stringify(value) } };
20
20
  }
21
- case 'string':
22
21
  default: {
23
22
  return { value: { string: value } };
24
23
  }
@@ -216,8 +216,11 @@ export class SchemaExtractor {
216
216
  return;
217
217
  }
218
218
  const schemaFile = configFile.schemas?.find((schema) => {
219
- const schemaPath = schema.path.replace(/\\/g, '/');
220
- const derivedKey = schemaPath.split('/').at(-1)?.replace(/\.json$/, '');
219
+ const schemaPath = schema.path.replaceAll('\\', '/');
220
+ const derivedKey = schemaPath
221
+ .split('/')
222
+ .at(-1)
223
+ ?.replace(/\.json$/, '');
221
224
  return derivedKey === schemaKey;
222
225
  });
223
226
  if (schemaFile) {