@levr-one/cli 0.12.8 → 0.12.9

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 (35) hide show
  1. package/dist/{addHandler-ybX54_3f.js → addHandler-CD1pda0z.js} +7 -7
  2. package/dist/{appendHandler-CKkl9ymw.js → appendHandler-BYOoCNXJ.js} +9 -9
  3. package/dist/{artifact-upload-Ba801tb6.js → artifact-upload-t6kL20b5.js} +2 -2
  4. package/dist/{attachHandler-CfNvVAV2.js → attachHandler-Ojk7mc2E.js} +9 -9
  5. package/dist/bindingsHandler-Dxx2LIci.js +2781 -0
  6. package/dist/change-scope-DBmyRWZV.js +379 -0
  7. package/dist/changedCoverageHandler-B8Zh5WIK.js +200 -0
  8. package/dist/cli.js +300 -15
  9. package/dist/{connect-yq3fGXkW.js → connect-A5VSJUv5.js} +3 -3
  10. package/dist/coverage-defaults-Ct3KNnGl.js +24 -0
  11. package/dist/{currentHandler-PaLZKLGF.js → currentHandler-DmffKHyZ.js} +1 -1
  12. package/dist/dependencyAuditHandler-CdpW-IvY.js +291 -0
  13. package/dist/dist-DU3htaZ_.js +325 -0
  14. package/dist/{find-workspace-4Us2vEb7.js → find-workspace-IWolSyrf.js} +1 -1
  15. package/dist/gate-op-BINrIT2l.js +278 -0
  16. package/dist/{importHandler-bYBWYC_0.js → importHandler-86cjc2Zs.js} +6 -6
  17. package/dist/inspect-CAxNgTwj.js +4 -0
  18. package/dist/{inspect-BbL7kDe-.js → inspect-CinRBSv6.js} +2 -277
  19. package/dist/{listHandler-Du_YGzre.js → listHandler-BoCzGUDK.js} +5 -5
  20. package/dist/{loginHandler-PbKmDAGo.js → loginHandler-CXmNViCo.js} +6 -6
  21. package/dist/{logoutHandler-DxnzGPYx.js → logoutHandler-DwTURB_A.js} +2 -2
  22. package/dist/{pushHandler-BulraEwP.js → pushHandler-BkCmzQz7.js} +9 -330
  23. package/dist/{resolve-token-DKEXT7SA.js → resolve-token-D1zteEfm.js} +2 -2
  24. package/dist/{resolve-workspace-D8y7twod.js → resolve-workspace-CJN1plpd.js} +2 -2
  25. package/dist/{runHandler-B-u-0eRk.js → runHandler-BLkPzImG.js} +8 -7
  26. package/dist/{sdk-client-BgzKzVIR.js → sdk-client-CSy2LOEh.js} +1 -1
  27. package/dist/{selectHandler-C0gs-Q70.js → selectHandler-Dp74pefc.js} +5 -5
  28. package/dist/{statusHandler-Dnnh80ZN.js → statusHandler-ByTUMdKK.js} +3 -3
  29. package/dist/{token-refresh-BpFuU4Ij.js → token-refresh-DEmYbJ8V.js} +1 -1
  30. package/package.json +1 -1
  31. package/dist/inspect-EGW-cgVD.js +0 -3
  32. /package/dist/{env-DjeRwmZ7.js → env-Cv-anxJA.js} +0 -0
  33. /package/dist/{refsHandler--ySvLjmX.js → refsHandler-BPlcdJvR.js} +0 -0
  34. /package/dist/{sleep-CGBHjsj5.js → sleep-DNLj0FMk.js} +0 -0
  35. /package/dist/{workspace-store-Bmw104Qa.js → workspace-store-BJyB_WEG.js} +0 -0
package/dist/cli.js CHANGED
@@ -1,6 +1,8 @@
1
1
  #!/usr/bin/env node
2
2
  import { COMPLETION_SHELLS } from "./completionHandler-O2G_WZLf.js";
3
- import { gatesInspectCommand } from "./inspect-BbL7kDe-.js";
3
+ import { COVERAGE_DEFAULT_EXCLUDES } from "./coverage-defaults-Ct3KNnGl.js";
4
+ import "./gate-op-BINrIT2l.js";
5
+ import { gatesInspectCommand } from "./inspect-CinRBSv6.js";
4
6
  import { buildApplication, buildCommand, buildRouteMap, proposeCompletions, run, text_en } from "@stricli/core";
5
7
  import chalk from "chalk";
6
8
  import { existsSync, readFileSync } from "node:fs";
@@ -224,7 +226,7 @@ Examples:
224
226
  aliases: { y: "yes" }
225
227
  },
226
228
  loader: async () => {
227
- const { mcpAddHandler } = await import("./addHandler-ybX54_3f.js");
229
+ const { mcpAddHandler } = await import("./addHandler-CD1pda0z.js");
228
230
  return mcpAddHandler;
229
231
  }
230
232
  });
@@ -273,7 +275,7 @@ Examples:
273
275
  aliases: { d: "device-code" }
274
276
  },
275
277
  loader: async () => {
276
- const { loginHandler } = await import("./loginHandler-PbKmDAGo.js");
278
+ const { loginHandler } = await import("./loginHandler-CXmNViCo.js");
277
279
  return loginHandler;
278
280
  }
279
281
  });
@@ -292,7 +294,7 @@ Examples:
292
294
  },
293
295
  parameters: {},
294
296
  loader: async () => {
295
- const { logoutHandler } = await import("./logoutHandler-DxnzGPYx.js");
297
+ const { logoutHandler } = await import("./logoutHandler-DwTURB_A.js");
296
298
  return logoutHandler;
297
299
  }
298
300
  });
@@ -312,7 +314,7 @@ Examples:
312
314
  },
313
315
  parameters: {},
314
316
  loader: async () => {
315
- const { statusHandler } = await import("./statusHandler-Dnnh80ZN.js");
317
+ const { statusHandler } = await import("./statusHandler-ByTUMdKK.js");
316
318
  return statusHandler;
317
319
  }
318
320
  });
@@ -441,7 +443,7 @@ levr attach --manifest or later uploads.`
441
443
  }
442
444
  },
443
445
  loader: async () => {
444
- const { pushHandler } = await import("./pushHandler-BulraEwP.js");
446
+ const { pushHandler } = await import("./pushHandler-BkCmzQz7.js");
445
447
  return pushHandler;
446
448
  }
447
449
  });
@@ -561,7 +563,7 @@ Examples:
561
563
  }
562
564
  },
563
565
  loader: async () => {
564
- const { importHandler } = await import("./importHandler-bYBWYC_0.js");
566
+ const { importHandler } = await import("./importHandler-86cjc2Zs.js");
565
567
  return importHandler;
566
568
  }
567
569
  });
@@ -582,7 +584,7 @@ Examples:
582
584
  },
583
585
  parameters: {},
584
586
  loader: async () => {
585
- const { listHandler } = await import("./listHandler-Du_YGzre.js");
587
+ const { listHandler } = await import("./listHandler-BoCzGUDK.js");
586
588
  return listHandler;
587
589
  }
588
590
  });
@@ -620,7 +622,7 @@ Examples:
620
622
  flags: {}
621
623
  },
622
624
  loader: async () => {
623
- const { selectHandler } = await import("./selectHandler-C0gs-Q70.js");
625
+ const { selectHandler } = await import("./selectHandler-Dp74pefc.js");
624
626
  return selectHandler;
625
627
  }
626
628
  });
@@ -637,11 +639,285 @@ Examples:
637
639
  },
638
640
  parameters: {},
639
641
  loader: async () => {
640
- const { currentHandler } = await import("./currentHandler-PaLZKLGF.js");
642
+ const { currentHandler } = await import("./currentHandler-DmffKHyZ.js");
641
643
  return currentHandler;
642
644
  }
643
645
  });
644
646
 
647
+ //#endregion
648
+ //#region src/commands/gates/bindings-export.ts
649
+ const gatesBindingsExportCommand = buildCommand({
650
+ docs: {
651
+ brief: "Export the workspace's gate configuration as JSON",
652
+ fullDescription: `Write the workspace's own gate bindings (every tier) and the gate
653
+ definitions people in the workspace authored, as one JSON file: the format
654
+ \`levr gates bindings import\` reads. Sorted, so exporting an unchanged
655
+ workspace twice gives the same bytes.
656
+
657
+ Owner or Admin only: the file holds every command the workspace's gates run.
658
+
659
+ Writes to stdout unless --out is given.
660
+
661
+ Exit code 0 on success, 1 when the server refuses (a Member gets 403) or the
662
+ request fails, 2 for a usage error.
663
+
664
+ Examples:
665
+ levr gates bindings export > gates.json
666
+ levr gates bindings export --out gates.json --workspace-id <uuid>`
667
+ },
668
+ parameters: {
669
+ flags: {
670
+ "workspace-id": {
671
+ kind: "parsed",
672
+ parse: String,
673
+ brief: "Workspace ID: needed with a login token and several workspaces; a personal access token is bound to its own",
674
+ placeholder: "uuid",
675
+ optional: true
676
+ },
677
+ out: {
678
+ kind: "parsed",
679
+ parse: String,
680
+ brief: "Write the file here instead of stdout",
681
+ placeholder: "file",
682
+ optional: true
683
+ }
684
+ },
685
+ aliases: {
686
+ w: "workspace-id",
687
+ o: "out"
688
+ }
689
+ },
690
+ loader: async () => {
691
+ const { gatesBindingsExportHandler } = await import("./bindingsHandler-Dxx2LIci.js");
692
+ return gatesBindingsExportHandler;
693
+ }
694
+ });
695
+
696
+ //#endregion
697
+ //#region src/commands/gates/bindings-import.ts
698
+ const gatesBindingsImportCommand = buildCommand({
699
+ docs: {
700
+ brief: "Import a gate configuration file into the workspace",
701
+ fullDescription: `Apply a gate configuration file (the format \`levr gates bindings export\`
702
+ writes) to the workspace. The file is parsed and checked here first, so a
703
+ malformed file is refused before anything is sent.
704
+
705
+ The import APPLIES unless --dry-run is given; --dry-run previews the plan and
706
+ writes nothing. One line per entry:
707
+ create not stored yet; created
708
+ exists stored exactly as the file says; nothing to do
709
+ differs stored differently; reported and NOT overwritten
710
+ update the disabled placeholder a workspace starts with; filled in
711
+ delete the entry says "delete": true; the stored binding is removed
712
+ absent the entry says "delete": true; nothing was stored
713
+ A binding the file does not mention is never touched: deletes are explicit.
714
+ Running the same import twice writes nothing the second time.
715
+
716
+ Owner or Admin only.
717
+
718
+ --repo-root checks that every file the lanes name (scripts, tests/<name>.rs
719
+ for --test <name>) exists in that checkout before sending.
720
+
721
+ Exit code 0 on success; 1 when the server refuses (403, 400), a lane file is
722
+ missing, a row differs, or the request fails; 2 for a usage error or a file
723
+ that does not parse.
724
+
725
+ Examples:
726
+ levr gates bindings import gates.json --dry-run
727
+ levr gates bindings import gates.json
728
+ levr gates bindings import scripts/gates/bindings/lansweeper-agv.json --repo-root ~/src/agv`
729
+ },
730
+ parameters: {
731
+ positional: {
732
+ kind: "tuple",
733
+ parameters: [{
734
+ parse: String,
735
+ brief: "The gate configuration JSON file",
736
+ placeholder: "file",
737
+ optional: false
738
+ }]
739
+ },
740
+ flags: {
741
+ "workspace-id": {
742
+ kind: "parsed",
743
+ parse: String,
744
+ brief: "Workspace ID: needed with a login token and several workspaces; a personal access token is bound to its own",
745
+ placeholder: "uuid",
746
+ optional: true
747
+ },
748
+ "repo-root": {
749
+ kind: "parsed",
750
+ parse: String,
751
+ brief: "Check every file the lanes name exists under this checkout",
752
+ placeholder: "path",
753
+ optional: true
754
+ },
755
+ "dry-run": {
756
+ kind: "boolean",
757
+ default: false,
758
+ brief: "Preview the plan; write nothing"
759
+ }
760
+ },
761
+ aliases: { w: "workspace-id" }
762
+ },
763
+ loader: async () => {
764
+ const { gatesBindingsImportHandler } = await import("./bindingsHandler-Dxx2LIci.js");
765
+ return gatesBindingsImportHandler;
766
+ }
767
+ });
768
+
769
+ //#endregion
770
+ //#region src/commands/gates/changed-coverage.ts
771
+ const gatesChangedCoverageCommand = buildCommand({
772
+ docs: {
773
+ brief: "Check line coverage over only the lines the change added",
774
+ fullDescription: `Read an lcov file and measure coverage over the lines this change added,
775
+ against the merge base. This is the command a changed_line_coverage gate runs.
776
+
777
+ The base is, first match wins: --base (empty or 'auto' counts as not given);
778
+ the CI provider's PR target branch (e.g. GITHUB_BASE_REF); origin/HEAD. The
779
+ working tree is compared with \`git merge-base HEAD <base>\`, so committed,
780
+ staged, unstaged and untracked files all count.
781
+
782
+ Only changed .ts, .tsx and .rs files are measured, and a line counts only
783
+ when the lcov file marks it executable. Every measured file must have an lcov
784
+ SF record: one without is reported and exits 2, never read as zero lines.
785
+
786
+ lcov SF paths are matched against repository paths: an absolute path is made
787
+ relative to the repository root, a relative one is resolved against
788
+ --lcov-root (e.g. apps/backender when the tests ran from that app).
789
+
790
+ Excluded by default (--exclude adds to this list):
791
+ ${COVERAGE_DEFAULT_EXCLUDES.join("\n ")}
792
+
793
+ Exit code 0 when coverage is at or above --min (default 80), or when fewer
794
+ than 20 changed lines are executable (reported as not enforced); 1 below
795
+ --min, printing every uncovered file:line; 2 for a usage error, no merge base,
796
+ no lcov file, a changed file with no lcov record, or a crash.
797
+
798
+ Examples:
799
+ levr gates changed-coverage --lcov apps/backender/coverage/lcov.info --lcov-root apps/backender
800
+ levr gates changed-coverage --lcov coverage/lcov.info --base origin/main --scope packages/cli --min 90`
801
+ },
802
+ parameters: { flags: {
803
+ lcov: {
804
+ kind: "parsed",
805
+ parse: String,
806
+ brief: "lcov file to read (e.g. coverage/lcov.info)",
807
+ placeholder: "file"
808
+ },
809
+ min: {
810
+ kind: "parsed",
811
+ parse: String,
812
+ brief: "Minimum percentage of changed executable lines covered",
813
+ placeholder: "percent",
814
+ default: "80"
815
+ },
816
+ base: {
817
+ kind: "parsed",
818
+ parse: String,
819
+ brief: "Base ref to diff against; empty or 'auto' means auto-detect",
820
+ placeholder: "ref",
821
+ default: ""
822
+ },
823
+ scope: {
824
+ kind: "parsed",
825
+ parse: String,
826
+ brief: "Only count changes under this path (repeatable)",
827
+ placeholder: "path",
828
+ variadic: true,
829
+ optional: true
830
+ },
831
+ exclude: {
832
+ kind: "parsed",
833
+ parse: String,
834
+ brief: "Also exclude changed files matching this glob (repeatable)",
835
+ placeholder: "glob",
836
+ variadic: true,
837
+ optional: true
838
+ },
839
+ "lcov-root": {
840
+ kind: "parsed",
841
+ parse: String,
842
+ brief: "Directory relative lcov SF paths are resolved against",
843
+ placeholder: "dir",
844
+ default: "."
845
+ }
846
+ } },
847
+ loader: async () => {
848
+ const { gatesChangedCoverageHandler } = await import("./changedCoverageHandler-B8Zh5WIK.js");
849
+ return gatesChangedCoverageHandler;
850
+ }
851
+ });
852
+
853
+ //#endregion
854
+ //#region src/commands/gates/dependency-audit.ts
855
+ const gatesDependencyAuditCommand = buildCommand({
856
+ docs: {
857
+ brief: "Audit only the dependencies the change added or upgraded",
858
+ fullDescription: `Find the packages this change added or upgraded, by diffing each changed
859
+ lockfile (yarn.lock, package-lock.json, pnpm-lock.yaml, Cargo.lock) at the
860
+ merge base against the working tree, then run trivy and keep the findings that
861
+ name one of those packages. This is the command a dependency_audit gate runs.
862
+ A vulnerable dependency the change did not touch does not fail it.
863
+
864
+ The base is, first match wins: --base (empty or 'auto' counts as not given);
865
+ the CI provider's PR target branch (e.g. GITHUB_BASE_REF); origin/HEAD.
866
+
867
+ trivy runs offline against the database it already has
868
+ (trivy fs --scanners vuln,license --skip-db-update --offline-scan --format json)
869
+ and never downloads one. Warm its cache outside the gate, for example in a
870
+ scheduled CI job or once on a dev machine:
871
+ trivy fs --download-db-only
872
+
873
+ Exit code 0 when no added or upgraded package has a finding at or above
874
+ --severity (default HIGH) or, with --allow-licenses, a license outside the
875
+ list; 1 when one does, naming package@version and the CVE or license; 2 for a
876
+ usage error, no merge base, trivy missing, an empty or missing database, or a
877
+ crash.
878
+
879
+ Examples:
880
+ levr gates dependency-audit
881
+ levr gates dependency-audit --base origin/main --severity CRITICAL
882
+ levr gates dependency-audit --allow-licenses MIT,Apache-2.0,BSD-3-Clause,ISC`
883
+ },
884
+ parameters: { flags: {
885
+ base: {
886
+ kind: "parsed",
887
+ parse: String,
888
+ brief: "Base ref to diff against; empty or 'auto' means auto-detect",
889
+ placeholder: "ref",
890
+ default: ""
891
+ },
892
+ scope: {
893
+ kind: "parsed",
894
+ parse: String,
895
+ brief: "Only count lockfiles under this path (repeatable)",
896
+ placeholder: "path",
897
+ variadic: true,
898
+ optional: true
899
+ },
900
+ severity: {
901
+ kind: "parsed",
902
+ parse: String,
903
+ brief: "Lowest severity that fails: UNKNOWN, LOW, MEDIUM, HIGH, CRITICAL",
904
+ placeholder: "level",
905
+ default: "HIGH"
906
+ },
907
+ "allow-licenses": {
908
+ kind: "parsed",
909
+ parse: String,
910
+ brief: "Comma-separated SPDX licenses allowed; omit to skip the license check",
911
+ placeholder: "list",
912
+ optional: true
913
+ }
914
+ } },
915
+ loader: async () => {
916
+ const { gatesDependencyAuditHandler } = await import("./dependencyAuditHandler-CdpW-IvY.js");
917
+ return gatesDependencyAuditHandler;
918
+ }
919
+ });
920
+
645
921
  //#endregion
646
922
  //#region src/commands/gates/refs.ts
647
923
  const gatesRefsCommand = buildCommand({
@@ -695,7 +971,7 @@ Examples:
695
971
  }
696
972
  } },
697
973
  loader: async () => {
698
- const { gatesRefsHandler } = await import("./refsHandler--ySvLjmX.js");
974
+ const { gatesRefsHandler } = await import("./refsHandler-BPlcdJvR.js");
699
975
  return gatesRefsHandler;
700
976
  }
701
977
  });
@@ -776,7 +1052,7 @@ Examples:
776
1052
  }
777
1053
  },
778
1054
  loader: async () => {
779
- const { gatesRunHandler } = await import("./runHandler-B-u-0eRk.js");
1055
+ const { gatesRunHandler } = await import("./runHandler-BLkPzImG.js");
780
1056
  return gatesRunHandler;
781
1057
  }
782
1058
  });
@@ -889,7 +1165,7 @@ Examples:
889
1165
  }
890
1166
  },
891
1167
  loader: async () => {
892
- const { attachHandler } = await import("./attachHandler-CfNvVAV2.js");
1168
+ const { attachHandler } = await import("./attachHandler-Ojk7mc2E.js");
893
1169
  return attachHandler;
894
1170
  }
895
1171
  });
@@ -965,14 +1241,14 @@ Examples:
965
1241
  }
966
1242
  },
967
1243
  loader: async () => {
968
- const { resultAppendHandler } = await import("./appendHandler-CKkl9ymw.js");
1244
+ const { resultAppendHandler } = await import("./appendHandler-BYOoCNXJ.js");
969
1245
  return resultAppendHandler;
970
1246
  }
971
1247
  });
972
1248
 
973
1249
  //#endregion
974
1250
  //#region package.json
975
- var version = "0.12.8";
1251
+ var version = "0.12.9";
976
1252
 
977
1253
  //#endregion
978
1254
  //#region src/app.ts
@@ -994,6 +1270,15 @@ const workspaceRoutes = buildRouteMap({
994
1270
  });
995
1271
  const gatesRoutes = buildRouteMap({
996
1272
  routes: {
1273
+ bindings: buildRouteMap({
1274
+ routes: {
1275
+ export: gatesBindingsExportCommand,
1276
+ import: gatesBindingsImportCommand
1277
+ },
1278
+ docs: { brief: "Export or import the workspace's gate configuration" }
1279
+ }),
1280
+ "changed-coverage": gatesChangedCoverageCommand,
1281
+ "dependency-audit": gatesDependencyAuditCommand,
997
1282
  inspect: gatesInspectCommand,
998
1283
  refs: gatesRefsCommand,
999
1284
  run: gatesRunCommand
@@ -1,6 +1,6 @@
1
- import { client, configureClient } from "./sdk-client-BgzKzVIR.js";
2
- import { resolveToken } from "./resolve-token-DKEXT7SA.js";
3
- import { resolveWorkspaceFor } from "./resolve-workspace-D8y7twod.js";
1
+ import { client, configureClient } from "./sdk-client-CSy2LOEh.js";
2
+ import { resolveToken } from "./resolve-token-D1zteEfm.js";
3
+ import { resolveWorkspaceFor } from "./resolve-workspace-CJN1plpd.js";
4
4
 
5
5
  //#region src/utils/connect.ts
6
6
  /**
@@ -0,0 +1,24 @@
1
+ //#region src/commands/gates/coverage-defaults.ts
2
+ /**
3
+ * Changed files `levr gates changed-coverage` never measures (ENG-7618 D4.2).
4
+ * A leaf module with no imports, so the command's `--help` text can print the
5
+ * list without loading the handler (commands stay lazily loaded).
6
+ * `--exclude` adds to it. Tests, declarations, generated code, fixtures,
7
+ * migrations, config files, Rust integration tests and build scripts.
8
+ */
9
+ const COVERAGE_DEFAULT_EXCLUDES = [
10
+ "*.test.ts",
11
+ "*.test.tsx",
12
+ "*.spec.ts",
13
+ "*.e2e-spec.ts",
14
+ "*.d.ts",
15
+ "**/src/gen/**",
16
+ "**/__fixtures__/**",
17
+ "**/migrations/**",
18
+ "*.config.ts",
19
+ "**/tests/**/*.rs",
20
+ "build.rs"
21
+ ];
22
+
23
+ //#endregion
24
+ export { COVERAGE_DEFAULT_EXCLUDES };
@@ -1,4 +1,4 @@
1
- import { loadWorkspace } from "./workspace-store-Bmw104Qa.js";
1
+ import { loadWorkspace } from "./workspace-store-BJyB_WEG.js";
2
2
 
3
3
  //#region src/commands/workspace/currentHandler.ts
4
4
  function currentHandler() {