@visulima/vis 6.0.1 → 6.1.1

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 (185) hide show
  1. package/CHANGELOG.md +54 -0
  2. package/dist/bin.js +1 -1
  3. package/dist/binx.js +1 -1
  4. package/dist/config/index.d.ts +1226 -1216
  5. package/dist/packem_chunks/bloom-sync.js +1 -1
  6. package/dist/packem_chunks/cargo-lock.js +5 -0
  7. package/dist/packem_chunks/cargo-plan.js +3 -3
  8. package/dist/packem_chunks/catalog-detector.js +1 -1
  9. package/dist/packem_chunks/catalog.js +1 -94
  10. package/dist/packem_chunks/catalog2.js +11 -0
  11. package/dist/packem_chunks/cli-exec.js +1 -1
  12. package/dist/packem_chunks/cli-main.js +156 -174
  13. package/dist/packem_chunks/context.js +8 -0
  14. package/dist/packem_chunks/fix.js +1 -1
  15. package/dist/packem_chunks/handler10.js +1 -1
  16. package/dist/packem_chunks/handler12.js +4 -4
  17. package/dist/packem_chunks/handler13.js +1 -1
  18. package/dist/packem_chunks/handler14.js +1 -1
  19. package/dist/packem_chunks/handler15.js +1 -1
  20. package/dist/packem_chunks/handler19.js +5 -5
  21. package/dist/packem_chunks/handler2.js +1 -1
  22. package/dist/packem_chunks/handler20.js +1 -1
  23. package/dist/packem_chunks/handler21.js +1 -1
  24. package/dist/packem_chunks/handler23.js +1 -1
  25. package/dist/packem_chunks/handler24.js +1 -1
  26. package/dist/packem_chunks/handler25.js +1 -1
  27. package/dist/packem_chunks/handler26.js +4 -4
  28. package/dist/packem_chunks/handler28.js +1 -1
  29. package/dist/packem_chunks/handler3.js +1 -1
  30. package/dist/packem_chunks/handler31.js +1 -1
  31. package/dist/packem_chunks/handler32.js +1 -1
  32. package/dist/packem_chunks/handler33.js +1 -1
  33. package/dist/packem_chunks/handler34.js +3 -3
  34. package/dist/packem_chunks/handler35.js +1 -1
  35. package/dist/packem_chunks/handler36.js +1 -1
  36. package/dist/packem_chunks/handler38.js +2 -2
  37. package/dist/packem_chunks/handler39.js +5 -5
  38. package/dist/packem_chunks/handler4.js +4 -4
  39. package/dist/packem_chunks/handler40.js +1 -1
  40. package/dist/packem_chunks/handler41.js +1 -1
  41. package/dist/packem_chunks/handler42.js +1 -1
  42. package/dist/packem_chunks/handler43.js +1 -1
  43. package/dist/packem_chunks/handler44.js +1 -1
  44. package/dist/packem_chunks/handler45.js +1 -1
  45. package/dist/packem_chunks/handler46.js +1 -1
  46. package/dist/packem_chunks/handler47.js +1 -1
  47. package/dist/packem_chunks/handler48.js +1 -1
  48. package/dist/packem_chunks/handler49.js +1 -1
  49. package/dist/packem_chunks/handler5.js +4 -4
  50. package/dist/packem_chunks/handler50.js +5 -5
  51. package/dist/packem_chunks/handler52.js +1 -1
  52. package/dist/packem_chunks/handler54.js +2 -2
  53. package/dist/packem_chunks/handler55.js +1 -1
  54. package/dist/packem_chunks/handler56.js +3 -3
  55. package/dist/packem_chunks/handler57.js +4 -4
  56. package/dist/packem_chunks/handler58.js +4 -4
  57. package/dist/packem_chunks/handler59.js +2 -2
  58. package/dist/packem_chunks/handler6.js +7 -7
  59. package/dist/packem_chunks/handler60.js +1 -1
  60. package/dist/packem_chunks/handler61.js +3 -3
  61. package/dist/packem_chunks/handler62.js +1 -1
  62. package/dist/packem_chunks/handler63.js +3 -3
  63. package/dist/packem_chunks/handler64.js +3 -3
  64. package/dist/packem_chunks/handler65.js +4 -4
  65. package/dist/packem_chunks/handler66.js +2 -2
  66. package/dist/packem_chunks/handler67.js +5 -5
  67. package/dist/packem_chunks/handler68.js +12 -25
  68. package/dist/packem_chunks/handler69.js +25 -22
  69. package/dist/packem_chunks/handler7.js +1 -1
  70. package/dist/packem_chunks/handler70.js +22 -10
  71. package/dist/packem_chunks/handler71.js +10 -153
  72. package/dist/packem_chunks/handler72.js +133 -23
  73. package/dist/packem_chunks/handler73.js +23 -323
  74. package/dist/packem_chunks/handler74.js +274 -659
  75. package/dist/packem_chunks/handler75.js +708 -48
  76. package/dist/packem_chunks/handler76.js +48 -27
  77. package/dist/packem_chunks/handler77.js +27 -3
  78. package/dist/packem_chunks/handler78.js +3 -191
  79. package/dist/packem_chunks/handler79.js +191 -0
  80. package/dist/packem_chunks/handler8.js +1 -1
  81. package/dist/packem_chunks/heal.js +2 -2
  82. package/dist/packem_chunks/help-command.js +1 -1
  83. package/dist/packem_chunks/index2.js +3 -58
  84. package/dist/packem_chunks/index3.js +40 -3
  85. package/dist/packem_chunks/index6.js +135 -7
  86. package/dist/packem_chunks/index7.js +7 -135
  87. package/dist/packem_chunks/keys-refresh.js +1 -1
  88. package/dist/packem_chunks/list.js +2 -2
  89. package/dist/packem_chunks/prune.js +1 -1
  90. package/dist/packem_chunks/python-plan.js +3 -3
  91. package/dist/packem_chunks/python-projects.js +1 -1
  92. package/dist/packem_chunks/python.js +1 -0
  93. package/dist/packem_chunks/run.js +1 -1
  94. package/dist/packem_chunks/snapshot.js +2 -2
  95. package/dist/packem_chunks/state.js +2 -2
  96. package/dist/packem_chunks/status.js +1 -1
  97. package/dist/packem_chunks/sync.js +1 -1
  98. package/dist/packem_chunks/verify-lockfile.js +1 -1
  99. package/dist/packem_chunks/version-resolver.js +1 -1
  100. package/dist/packem_chunks/workspace.js +2 -2
  101. package/dist/packem_shared/ReleaseClient-CWD9BC5w.js +1 -0
  102. package/dist/packem_shared/advisories-BodWQ5DQ.js +1 -0
  103. package/dist/packem_shared/{affected-selection-CrW7fWEd.js → affected-selection-QaMUnFqe.js} +1 -1
  104. package/dist/packem_shared/{ai-analysis-pldoS_N4.js → ai-analysis-D7jlbJky.js} +3 -3
  105. package/dist/packem_shared/ai-cache-iSIyY3So.js +1 -0
  106. package/dist/packem_shared/{ai-fix-D9MxigBQ.js → ai-fix-CgCyO65Q.js} +6 -6
  107. package/dist/packem_shared/apply-DoeQAAGm.js +6 -0
  108. package/dist/packem_shared/apply-release-plan-BalHtK-g.js +15 -0
  109. package/dist/packem_shared/{bin-D3TtXgz6.js → bin-LyW9KY0i.js} +1 -1
  110. package/dist/packem_shared/clean-package-json-rutwkKl-.js +1 -0
  111. package/dist/packem_shared/createAdapter-DMK4bBET.js +1 -0
  112. package/dist/packem_shared/createVersionActions-DXo4z8VN.js +1 -0
  113. package/dist/packem_shared/dependency-scan-DFnt1mni.js +1 -0
  114. package/dist/packem_shared/detect-CbMRSXkM.js +1 -0
  115. package/dist/packem_shared/{ecosystem-gate-ByxWtzPE.js → ecosystem-gate-Bdz-gK_Y.js} +1 -1
  116. package/dist/packem_shared/env-BSXG3QKH.js +4 -0
  117. package/dist/packem_shared/env-consistency-B4rU4MQb.js +1 -0
  118. package/dist/packem_shared/failure-log-DIsKBKaI.js +2 -0
  119. package/dist/packem_shared/formatBytes-_HvjOy8a-iHCer6uX.js +1 -0
  120. package/dist/packem_shared/glob-Cyk1H9ZL-DRlUeuow.js +1 -0
  121. package/dist/packem_shared/{index-BKbMnn8K.js → index-B1ZsG3oa.js} +1 -1
  122. package/dist/packem_shared/index-CgNfNk12.js +1 -0
  123. package/dist/packem_shared/lifecycle-CQjeMPY0.js +2 -0
  124. package/dist/packem_shared/missing-package-json-dtwl6w-S.js +1 -0
  125. package/dist/packem_shared/multi-eco-lockfiles-CyIfYw4u.js +1 -0
  126. package/dist/packem_shared/npmrc-CHsOyMvA.js +2 -0
  127. package/dist/packem_shared/osv-C53WUoSW.js +1 -0
  128. package/dist/packem_shared/{package-version-QFmE9anh.js → package-version-DqYSd_ia.js} +1 -1
  129. package/dist/packem_shared/packument-CbTmbHU4.js +1 -0
  130. package/dist/packem_shared/{project-name-filter-DIqpdsvP.js → project-name-filter-mwTJC1IK.js} +1 -1
  131. package/dist/packem_shared/{provenance-L1M2FPy_.js → provenance-SX1MxPUZ.js} +1 -1
  132. package/dist/packem_shared/publish-Dc0XGH3K.js +34 -0
  133. package/dist/packem_shared/registry-CkoaWkjP.js +81 -0
  134. package/dist/packem_shared/registry-keys-z038Ecb4.js +1 -0
  135. package/dist/packem_shared/removeSync-g1D5kONg-LbjATA8v.js +1 -0
  136. package/dist/packem_shared/renderToString-DR0zDUjh-C7p-L6AO.js +3 -0
  137. package/dist/packem_shared/{resolve-explicit-CQa37JSq.js → resolve-explicit-D9kdTNvl.js} +1 -1
  138. package/dist/packem_shared/{run-D-uVGHQ4.js → run-DLvd3RIZ.js} +1 -1
  139. package/dist/packem_shared/run-summary-utils-CMeURYtS.js +1 -0
  140. package/dist/packem_shared/runtime-check-D3cRDuoi.js +1 -0
  141. package/dist/packem_shared/s1ngularity-BuU9Cxpy.js +1 -0
  142. package/dist/packem_shared/scaffold-files-Bje3_Ixv.js +28 -0
  143. package/dist/packem_shared/scan-progress-D8ojNcKt.js +2 -0
  144. package/dist/packem_shared/{signatures-DIqFUOfs.js → signatures-CeL0bOEo.js} +1 -1
  145. package/dist/packem_shared/spinner-Bqjpz3i4.js +1 -0
  146. package/dist/packem_shared/table-DDAJalPF.js +1 -0
  147. package/dist/packem_shared/tabs-CC0GJLww.js +1 -0
  148. package/dist/packem_shared/{task-env-DzR4RkOj.js → task-env-C2lmxvzA.js} +1 -1
  149. package/dist/packem_shared/toolchain-CP79HNVy.js +5 -0
  150. package/dist/packem_shared/typosquats-BFKus_aM.js +1 -0
  151. package/dist/packem_shared/use-measured-height-_nYuZ-Au.js +1 -0
  152. package/dist/packem_shared/vis-update-app-Ba5ce8Jd.js +1 -0
  153. package/dist/packem_shared/{vis-user-error-S0Fesz5y.js → vis-user-error-D_ekz9rF.js} +1 -1
  154. package/dist/packem_shared/watch-loop-DWr41vHM.js +11 -0
  155. package/dist/packem_shared/xxh3-BLHlvhgT.js +1 -0
  156. package/dist/release/core/package-managers/index.js +1 -1
  157. package/dist/release/core/version-actions/index.js +1 -1
  158. package/dist/release/index.js +1 -1
  159. package/index.js +26 -26
  160. package/package.json +9 -9
  161. package/dist/packem_chunks/orchestrator.js +0 -46
  162. package/dist/packem_shared/ReleaseClient-DAvbxCdo.js +0 -1
  163. package/dist/packem_shared/createAdapter-F7GidOzU.js +0 -1
  164. package/dist/packem_shared/createVersionActions-ByaJ1Nbv.js +0 -1
  165. package/dist/packem_shared/dependency-scan-B8jroa1D.js +0 -1
  166. package/dist/packem_shared/env-consistency-Dt_uDbSP.js +0 -1
  167. package/dist/packem_shared/failure-log-BP-gCUb5.js +0 -2
  168. package/dist/packem_shared/formatBytes-_HvjOy8a-B_qQr4Hw.js +0 -4
  169. package/dist/packem_shared/glob-Cyk1H9ZL-Dxlf9Swz.js +0 -1
  170. package/dist/packem_shared/index-DGdD4w-b.js +0 -1
  171. package/dist/packem_shared/lifecycle-DvmDIRbb.js +0 -2
  172. package/dist/packem_shared/missing-package-json-Cu5YVAot.js +0 -1
  173. package/dist/packem_shared/multi-eco-lockfiles-B2X3yhyo.js +0 -1
  174. package/dist/packem_shared/packument-zb18Jnlw.js +0 -1
  175. package/dist/packem_shared/registry-keys-DxdqMzyp.js +0 -1
  176. package/dist/packem_shared/runtime-check-1U8HrQd9.js +0 -1
  177. package/dist/packem_shared/s1ngularity-CO5GkkqX.js +0 -1
  178. package/dist/packem_shared/scan-progress-RwCRxJdX.js +0 -2
  179. package/dist/packem_shared/spinner-BJjbNl1F.js +0 -1
  180. package/dist/packem_shared/tabs--uxJGL8N.js +0 -1
  181. package/dist/packem_shared/toolchain-Bz70UIcp.js +0 -5
  182. package/dist/packem_shared/typosquats-D4DEHhFy.js +0 -1
  183. package/dist/packem_shared/use-measured-height-DUZyyias.js +0 -1
  184. package/dist/packem_shared/vis-update-app-9b2kSk9f.js +0 -1
  185. package/dist/packem_shared/watch-loop-BEnGuMBn.js +0 -11
@@ -1,25 +1,6 @@
1
1
  import { TargetConfiguration, ChildEnvOptions, TaskResult, Task, FingerprintContributor, ConstraintsConfig, NamedInputs, TaskRunnerOptions } from '@visulima/task-runner';
2
2
  export type { FingerprintContributor } from '@visulima/task-runner';
3
3
  import { VisReleaseConfig } from "../release/types.js";
4
- /**
5
- * One family of upstream-coupled packages.
6
- *
7
- * `members` is an exact-match list. `prefixes` accept any dep whose
8
- * name starts with the prefix — useful for monorepos that ship many
9
- * subpackages under one scope (e.g. `@babel/`, `@storybook/`,
10
- * `@nx/`). A family can use either or both; a dep matching either
11
- * list belongs to the family.
12
- */
13
- interface SimilarDepFamily {
14
- /** Stable id; used in report output and config overrides. */
15
- id: string;
16
- /** Pretty label for the report. Defaults to `id` when omitted. */
17
- label?: string;
18
- /** Dep names that belong to this family verbatim. */
19
- members?: string[];
20
- /** Dep-name prefixes (literal, no glob). Match if `depName.startsWith(prefix)`. */
21
- prefixes?: string[];
22
- }
23
4
  /** Adapter IDs that can format (adapter `kind` is `"fmt"` or `"both"`). */
24
5
  type FmtAdapterId = "biome" | "dprint" | "oxfmt" | "prettier" | "ruff-fmt";
25
6
  /** Adapter IDs that can lint (adapter `kind` is `"lint"` or `"both"`). */
@@ -693,33 +674,6 @@ interface VisPlugin {
693
674
  */
694
675
  setup?: (hooks: Hookable<VisHooks>) => Promise<void> | void;
695
676
  }
696
- /**
697
- * Per-adapter override applied by `vis lint` / `vis fmt`. Keyed by
698
- * adapter id under `lint.adapters` / `fmt.adapters`. Every field is
699
- * optional — set only what you need to change.
700
- */
701
- interface LintFmtAdapterOverride {
702
- /**
703
- * Set to `false` to skip this adapter even when its config file or
704
- * package.json entry is detected. Defaults to `true` (run when
705
- * detected).
706
- */
707
- enabled?: boolean;
708
- /**
709
- * Extra arguments appended verbatim to every invocation of this
710
- * adapter. Useful for tool-specific flags vis doesn't expose
711
- * directly (e.g. `eslint --rulesdir`).
712
- */
713
- extraArgs?: string[];
714
- }
715
- /**
716
- * The 8 Socket.dev-style supply-chain policies. Used in `security.policies`
717
- * and `security.acceptedRisks[*].policies`. Kept as a const tuple so callers
718
- * can import the runtime array (`POLICY_NAMES`) for iteration without
719
- * drifting from the union type.
720
- */
721
- declare const POLICY_NAMES: readonly ["firstSeen", "installScripts", "license", "malware", "publisherChange", "score", "unexpectedDeps", "vulnerability"];
722
- type PolicyName = (typeof POLICY_NAMES)[number];
723
677
  /**
724
678
  * Recognised input sources for the codeowners aggregator.
725
679
  *
@@ -762,6 +716,56 @@ interface CodeownersConfig {
762
716
  /** Enabled input sources. Defaults to `["project-json"]`. */
763
717
  sources?: CodeownersSource[];
764
718
  }
719
+ /**
720
+ * Declared code-owner assignment for a path glob within a project.
721
+ * Mirrors moon's `owners` shape so migrations can round-trip cleanly.
722
+ */
723
+ interface OwnersEntry {
724
+ /** Optional notification channel (e.g. Slack, Teams). */
725
+ channel?: string;
726
+ /** Owner handles (e.g. `@visulima/core-team`). */
727
+ owners: string[];
728
+ /** File/glob pattern relative to the project root. */
729
+ path: string;
730
+ }
731
+ /**
732
+ * Per-adapter override applied by `vis lint` / `vis fmt`. Keyed by
733
+ * adapter id under `lint.adapters` / `fmt.adapters`. Every field is
734
+ * optional — set only what you need to change.
735
+ */
736
+ interface LintFmtAdapterOverride {
737
+ /**
738
+ * Set to `false` to skip this adapter even when its config file or
739
+ * package.json entry is detected. Defaults to `true` (run when
740
+ * detected).
741
+ */
742
+ enabled?: boolean;
743
+ /**
744
+ * Extra arguments appended verbatim to every invocation of this
745
+ * adapter. Useful for tool-specific flags vis doesn't expose
746
+ * directly (e.g. `eslint --rulesdir`).
747
+ */
748
+ extraArgs?: string[];
749
+ }
750
+ /**
751
+ * One family of upstream-coupled packages.
752
+ *
753
+ * `members` is an exact-match list. `prefixes` accept any dep whose
754
+ * name starts with the prefix — useful for monorepos that ship many
755
+ * subpackages under one scope (e.g. `@babel/`, `@storybook/`,
756
+ * `@nx/`). A family can use either or both; a dep matching either
757
+ * list belongs to the family.
758
+ */
759
+ interface SimilarDepFamily {
760
+ /** Stable id; used in report output and config overrides. */
761
+ id: string;
762
+ /** Pretty label for the report. Defaults to `id` when omitted. */
763
+ label?: string;
764
+ /** Dep names that belong to this family verbatim. */
765
+ members?: string[];
766
+ /** Dep-name prefixes (literal, no glob). Match if `depName.startsWith(prefix)`. */
767
+ prefixes?: string[];
768
+ }
765
769
  /**
766
770
  * One user-declared customTypes entry. See `policy.customTypes.extraTypes`
767
771
  * for the full contract — this is just the row shape.
@@ -788,18 +792,6 @@ interface ExtraCustomType {
788
792
  */
789
793
  strategy: "name@version" | "name~version" | "string" | "versionsByName";
790
794
  }
791
- /**
792
- * Declared code-owner assignment for a path glob within a project.
793
- * Mirrors moon's `owners` shape so migrations can round-trip cleanly.
794
- */
795
- interface OwnersEntry {
796
- /** Optional notification channel (e.g. Slack, Teams). */
797
- channel?: string;
798
- /** Owner handles (e.g. `@visulima/core-team`). */
799
- owners: string[];
800
- /** File/glob pattern relative to the project root. */
801
- path: string;
802
- }
803
795
  /**
804
796
  * Per-project TypeScript overlay loaded from `vis.task.ts`. Adds a
805
797
  * dynamic, type-safe layer for target overrides on top of `project.json`,
@@ -877,22 +869,6 @@ interface ProjectJson {
877
869
  /** Vis-style target definitions (merged on top of package.json scripts). */
878
870
  targets?: Record<string, VisTargetConfiguration>;
879
871
  }
880
- /**
881
- * A predicate used by {@link VisConfig.scopedTasks}.
882
- * All listed constraints must match for the block to apply.
883
- */
884
- interface ScopedTasksMatch {
885
- /** Match on primary language. */
886
- language?: string | string[];
887
- /** Match on project layer. */
888
- layer?: ProjectJson["layer"] | ProjectJson["layer"][];
889
- /** Match on project type. */
890
- projectType?: "application" | "library" | "service" | "tool";
891
- /** Match on project stack. */
892
- stack?: ProjectJson["stack"] | ProjectJson["stack"][];
893
- /** Match projects tagged with any of these tags. */
894
- tags?: string[];
895
- }
896
872
  /**
897
873
  * A single scoped-tasks block — a set of task defaults gated by an
898
874
  * optional match predicate.
@@ -903,104 +879,1167 @@ interface ScopedTasksBlock {
903
879
  /** Task default configurations, keyed by target name. */
904
880
  tasks: Record<string, Partial<VisTargetConfiguration>>;
905
881
  }
906
- interface VisConfig {
882
+ /**
883
+ * The 8 Socket.dev-style supply-chain policies. Used in `security.policies`
884
+ * and `security.acceptedRisks[*].policies`. Kept as a const tuple so callers
885
+ * can import the runtime array (`POLICY_NAMES`) for iteration without
886
+ * drifting from the union type.
887
+ */
888
+ declare const POLICY_NAMES: readonly ["firstSeen", "installScripts", "license", "malware", "publisherChange", "score", "unexpectedDeps", "vulnerability"];
889
+ type PolicyName = (typeof POLICY_NAMES)[number];
890
+ interface VisPolicyConfig {
907
891
  /**
908
- * Workspace-relative glob patterns for changed files outside every
909
- * project that `vis affected`, `vis run --affected`, `vis ci` and
910
- * `vis ci ignore` should not count as a change.
911
- *
912
- * By default a changed file that belongs to no project (a root
913
- * `tsconfig.json`, `package.json`, …) is a global change and marks every
914
- * project affected. A changed file matching one of these patterns is
915
- * skipped instead. The patterns are only checked for files that belong
916
- * to NO project: a file inside a project root is never filtered, so a
917
- * broad pattern like `*.md` cannot hide a real package change.
918
- *
919
- * Patterns use `path.matchesGlob` syntax, where `*` does not cross `/`:
920
- * `*.md` matches `README.md` but not `docs/guide.md`.
892
+ * Map of dep names or globs → reason (or `{ reason, replacement, packages?, paths? }`).
893
+ * Internal/workspace deps are never flagged here; the
894
+ * workspace-protocol lint owns those.
921
895
  *
922
- * Do NOT list paths whose changes really do affect projects, such as
923
- * bundler-inlined shared source or the root `tsconfig.json`: an edit
924
- * there would then run nothing.
925
- * @example ["api-snapshots/**", "plans/**", "*.md"]
896
+ * Optional `packages` (globs over the declaring package's `name`) and
897
+ * `paths` (globs over the workspace-relative `packageDir`) narrow where
898
+ * the rule applies. With both set, either match is enough. Omit both
899
+ * to ban anywhere — the default.
900
+ * @example
901
+ * ```
902
+ * bannedDeps: {
903
+ * request: "deprecated; use undici",
904
+ * moment: { reason: "huge bundle, frozen upstream", replacement: "date-fns" },
905
+ * "@radix-ui/*": "we standardized on shadcn",
906
+ * react: { reason: "no react in shared libs", paths: ["packages/shared/*"] },
907
+ * "next": { reason: "apps only", packages: ["@app/*"] },
908
+ * }
909
+ * ```
926
910
  */
927
- affectedIgnore?: string[];
928
- /** AI analysis configuration */
929
- ai?: {
930
- /** Cache TTL in milliseconds. Overrides default (1h / 30min for security). */
931
- cacheTtl?: number;
932
- /** Override default provider priority. Higher number = preferred. */
933
- priority?: Record<string, number>;
934
- /** Use a specific provider instead of auto-detecting (e.g., `"claude"`, `"gemini"`). */
935
- provider?: string;
936
- };
911
+ bannedDeps?: Record<string, string | {
912
+ packages?: string[];
913
+ paths?: string[];
914
+ reason: string;
915
+ replacement?: string;
916
+ }>;
937
917
  /**
938
- * Scope the task-runner cache directory by the current git branch.
939
- * When `true`, caches are stored under `&lt;cacheDir>/branches/&lt;slug>`
940
- * so `main` and feature branches stop thrashing each other —
941
- * generated artefacts (schemas, `.d.ts` snapshots) that legitimately
942
- * differ across branches no longer oscillate the cache contents.
918
+ * Tweak the custom-types lint that flags drift in `engines.{node,pnpm,...}`,
919
+ * `packageManager`, `volta.{node,pnpm,yarn}`, and the proposed
920
+ * `devEngines.{runtime,packageManager}` array form.
943
921
  *
944
- * Falls back to the unscoped path on detached HEAD, non-git
945
- * workspaces, or when git isn't available.
946
- * @default false
922
+ * Each (customType × name) cluster is tracked independently —
923
+ * `engines.node` and `volta.node` don't cross-couple here. Use a
924
+ * versionGroup once that lands if you need to enforce they agree.
947
925
  */
948
- branchScopedCache?: boolean;
926
+ customTypes?: {
927
+ /**
928
+ * Three-state autofix opt-out. See `workspaceProtocol.autofix`
929
+ * for the contract — same semantics, applied to drift rewrites
930
+ * across engines / packageManager / volta / devEngines.
931
+ *
932
+ * Note: `--fix` strips any `+sha512.&lt;hash&gt;` suffix from
933
+ * `packageManager` on bump — content-integrity hashes are tied
934
+ * to a specific package, not a version, so users must regenerate
935
+ * via their PM (`pnpm install` re-pins; `corepack use pnpm@X` etc.).
936
+ * @default true
937
+ */
938
+ autofix?: "prompt" | boolean;
939
+ /**
940
+ * User-defined custom-type pin locations. Each entry tells the
941
+ * customTypes lint to read additional version pins from a
942
+ * non-standard JSON path inside every workspace package.json,
943
+ * cluster them by `(name × depName)` like the built-in types,
944
+ * and rewrite them with `--fix`.
945
+ *
946
+ * The original built-ins (`engines`, `volta`, `packageManager`,
947
+ * `devEngines.runtime`, `devEngines.packageManager`) keep
948
+ * running unconditionally — these layer on top.
949
+ *
950
+ * Strategies:
951
+ * - `versionsByName`: the JSON at `path` is `{ [depName]: version }`
952
+ * (like `engines` or `pnpm.overrides`).
953
+ * - `name@version`: the JSON at `path` is a string of the form
954
+ * `name@version` (like `packageManager`). The leading `name@`
955
+ * is preserved; only the version segment is rewritten.
956
+ * - `string`: the JSON at `path` is a bare version string. The
957
+ * `depName` field is required and identifies the dep cluster.
958
+ *
959
+ * `name` must not collide with a built-in type name. `path` is
960
+ * a dot-separated walk into the package.json (e.g. `pnpm.overrides`).
961
+ * @example
962
+ * ```ts
963
+ * extraTypes: [
964
+ * { name: "pnpmOverridesLegacy", path: "pnpm.overrides", strategy: "versionsByName" },
965
+ * { name: "myToolPin", path: "myTool.runtime", strategy: "name@version" },
966
+ * { name: "minNode", path: "config.minNode", strategy: "string", depName: "node" },
967
+ * ]
968
+ * ```
969
+ */
970
+ extraTypes?: ExtraCustomType[];
971
+ /**
972
+ * Dep names exempt from the drift check (exact match against the
973
+ * field name within the block — e.g. `node`, `pnpm`).
974
+ */
975
+ ignore?: string[];
976
+ /**
977
+ * Resolution strategy used when `--fix` runs.
978
+ * - `highest` (default): align every drifting instance to the
979
+ * highest declared version.
980
+ * - `lowest`: align to the lowest.
981
+ * @default "highest"
982
+ */
983
+ resolve?: "highest" | "lowest";
984
+ };
949
985
  /**
950
- * Code ownership configuration. Controls how `vis sync codeowners`
951
- * renders the generated CODEOWNERS file.
986
+ * Tweak the dead-workspace-patterns lint that flags entries in
987
+ * `pnpm-workspace.yaml#packages` / `package.json#workspaces` which
988
+ * resolve to zero on-disk directories.
952
989
  */
953
- codeowners?: CodeownersConfig;
990
+ deadWorkspacePatterns?: {
991
+ /**
992
+ * Three-state autofix opt-out. See `workspaceProtocol.autofix`
993
+ * for the contract — applied here to dropping unmatched patterns
994
+ * from the workspace config file.
995
+ * @default true
996
+ */
997
+ autofix?: "prompt" | boolean;
998
+ };
954
999
  /**
955
- * Composer packages as task projects. Off by default: a `composer.json` in a
956
- * subdirectory gets validate and, when its scripts define them, test and lint targets.
1000
+ * Tweak the empty-deps lint that flags empty `dependencies` /
1001
+ * `devDependencies` / `peerDependencies` / `optionalDependencies`
1002
+ * blocks across the workspace.
957
1003
  */
958
- composer?: {
959
- discover?: boolean;
1004
+ emptyDeps?: {
1005
+ /**
1006
+ * Three-state autofix opt-out. See `workspaceProtocol.autofix`
1007
+ * for the contract — applied here to removing the empty key.
1008
+ * @default true
1009
+ */
1010
+ autofix?: "prompt" | boolean;
1011
+ /**
1012
+ * Block names exempt from the rule (e.g. `["peerDependencies"]`
1013
+ * to keep the key around as a marker even when empty).
1014
+ */
1015
+ ignoreBlocks?: ("dependencies" | "devDependencies" | "optionalDependencies" | "peerDependencies")[];
960
1016
  };
961
1017
  /**
962
- * Project dependency constraints.
963
- * Enforced after building the project graph, before running tasks.
1018
+ * Tweak the redefine-root lint that flags non-root packages duplicating
1019
+ * deps already pinned at the workspace root.
964
1020
  */
965
- constraints?: ConstraintsConfig;
1021
+ redefineRoot?: {
1022
+ /** Dep names that are exempt from the redefine-root rule (exact match). */
1023
+ ignore?: string[];
1024
+ };
966
1025
  /**
967
- * Configuration for the `vis create` scaffolding command.
968
- * Controls template downloads (via giget), default options, and
969
- * post-creation behavior.
1026
+ * Tweak the root-deps lint that flags runtime `dependencies` declared
1027
+ * on the private workspace root (they should live in `devDependencies`).
970
1028
  */
971
- create?: {
1029
+ rootDeps?: {
972
1030
  /**
973
- * Authorization token for downloading private repository templates.
974
- * Passed as Bearer token to the git host API.
975
- * Can also be set via GIGET_AUTH, GITHUB_TOKEN, or GH_TOKEN environment variables.
1031
+ * Three-state autofix opt-out. See `workspaceProtocol.autofix`
1032
+ * for the contract — applied here to moving entries from
1033
+ * `dependencies` to `devDependencies` on the root package.json.
1034
+ * @default true
976
1035
  */
977
- auth?: string;
1036
+ autofix?: "prompt" | boolean;
1037
+ };
1038
+ /**
1039
+ * Tweak the root-package-manager lint that flags a missing or
1040
+ * malformed `packageManager` field on the workspace root.
1041
+ */
1042
+ rootPackageManager?: {
978
1043
  /**
979
- * Default editor to configure after scaffolding.
980
- * When set, `vis create` automatically generates editor config files.
981
- * @example "vscode"
1044
+ * Three-state autofix opt-out. See `workspaceProtocol.autofix`
1045
+ * for the contract. `--fix` only writes when `suggested` is set —
1046
+ * a missing `packageManager` field has no canonical default.
1047
+ * @default true
982
1048
  */
983
- defaultEditor?: "vscode";
1049
+ autofix?: "prompt" | boolean;
984
1050
  /**
985
- * Default package manager for new standalone projects.
986
- * When set, skips the PM selection prompt in interactive mode.
1051
+ * Canonical specifier (`name@version`) to write when `--fix` runs
1052
+ * and the field is absent. Required to enable autofix —
1053
+ * vis won't guess the workspace's preferred manager.
1054
+ * @example "pnpm@10.32.1"
987
1055
  */
988
- defaultPm?: "bun" | "npm" | "pnpm" | "yarn";
1056
+ suggested?: string;
1057
+ };
1058
+ /**
1059
+ * Tweak the root-private lint that flags a workspace root package.json
1060
+ * missing `"private": true`. Only fires when the root looks like a
1061
+ * workspace (npm/yarn/bun `workspaces` field or `pnpm-workspace.yaml`).
1062
+ */
1063
+ rootPrivate?: {
989
1064
  /**
990
- * Default giget provider for `owner/repo` shorthand inputs.
991
- * @default "github"
1065
+ * Three-state autofix opt-out. See `workspaceProtocol.autofix`
1066
+ * for the contract — applied here to inserting `"private": true`.
1067
+ * @default true
992
1068
  */
993
- defaultProvider?: "bitbucket" | "github" | "gitlab" | "sourcehut";
1069
+ autofix?: "prompt" | boolean;
1070
+ };
1071
+ /**
1072
+ * Tweak the similar-deps lint that flags drift across related dep
1073
+ * families (e.g. `react` and `react-dom`, all of `@babel/*`).
1074
+ *
1075
+ * The lint is report-only — aligning a family requires picking a
1076
+ * single canonical specifier across heterogeneous range syntaxes
1077
+ * (`^`, `~`, exact), which is too lossy without user input.
1078
+ */
1079
+ similarDeps?: {
994
1080
  /**
995
- * Template used by a bare `vis create`. Accepts any template input, including an
996
- * organization scope (`@acme` opens the `@acme/create` manifest picker, `@acme:app`
997
- * selects one entry directly). In a terminal the usual prompts still run, minus the template step.
998
- * @example "@acme"
1081
+ * Additional families merged with the built-ins. Same `id` wins
1082
+ * → user override fully replaces the built-in entry.
1083
+ * @example
1084
+ * ```
1085
+ * extraFamilies: [
1086
+ * { id: "vue", label: "Vue", members: ["vue", "vue-router", "pinia"] },
1087
+ * ]
1088
+ * ```
999
1089
  */
1000
- defaultTemplate?: string;
1090
+ extraFamilies?: SimilarDepFamily[];
1091
+ /** Family ids to skip entirely (matches `SimilarDepFamily.id`). */
1092
+ ignoreFamilies?: string[];
1093
+ };
1094
+ /**
1095
+ * Tweak the types-in-deps lint that flags `@types/*` declared in
1096
+ * `dependencies` on a private package (they belong in
1097
+ * `devDependencies` since the package never ships).
1098
+ */
1099
+ typesInDeps?: {
1001
1100
  /**
1002
- * Initialize a git repository after scaffolding standalone projects.
1003
- * @default false
1101
+ * Three-state autofix opt-out. See `workspaceProtocol.autofix`
1102
+ * for the contract — applied here to moving the entry to
1103
+ * `devDependencies`. Existing dev pins are preserved on conflict.
1104
+ * @default true
1105
+ */
1106
+ autofix?: "prompt" | boolean;
1107
+ /** Dep names exempt from the rule (exact match, e.g. `@types/node`). */
1108
+ ignore?: string[];
1109
+ };
1110
+ /**
1111
+ * Tweak the workspace-protocol lint that flags internal deps not
1112
+ * using the `workspace:` protocol.
1113
+ */
1114
+ workspaceProtocol?: {
1115
+ /**
1116
+ * Three-state autofix opt-out. Some workspaces want detection
1117
+ * without rewrite (e.g. dual-licensed packages where `workspace:*`
1118
+ * is unsafe).
1119
+ * - `true` (default): `--fix` rewrites the specifier.
1120
+ * - `false`: never rewrite — report the violation only.
1121
+ * - `"prompt"`: ask before each rewrite. Falls back to report-only
1122
+ * when stdin isn't a TTY (CI). Reserved; not yet implemented.
1123
+ *
1124
+ * Note: when `false` (or `"prompt"`), `--fix` still **fails CI** on
1125
+ * detected violations — the rule is "report only", not "ignore".
1126
+ * Drop the rule from the lint selection if you want a clean exit.
1127
+ * @default true
1128
+ * @example
1129
+ * ```
1130
+ * policy: {
1131
+ * workspaceProtocol: { autofix: false },
1132
+ * }
1133
+ * ```
1134
+ */
1135
+ autofix?: "prompt" | boolean;
1136
+ };
1137
+ /**
1138
+ * Tweak the workspace-versions lint that flags external deps declared
1139
+ * at inconsistent versions across the workspace.
1140
+ */
1141
+ workspaceVersions?: {
1142
+ /**
1143
+ * Three-state autofix opt-out. See `workspaceProtocol.autofix`
1144
+ * for the contract — same semantics, applied to drift rewrites.
1145
+ *
1146
+ * Also gates the `--propose-min` catalog suggestion writer:
1147
+ * when `false` / `"prompt"`, `--fix --propose-min` reports the
1148
+ * proposed catalog entries but does not write
1149
+ * `pnpm-workspace.yaml`. Same "report only, still fails CI"
1150
+ * note applies as on `workspaceProtocol.autofix`.
1151
+ * @default true
1152
+ */
1153
+ autofix?: "prompt" | boolean;
1154
+ /** Dep names exempt from the version-drift check (exact match). */
1155
+ ignore?: string[];
1156
+ /**
1157
+ * Resolution strategy used when `--fix` runs.
1158
+ * - `highest` (default): rewrite every drifting instance to the
1159
+ * highest sibling specifier.
1160
+ * - `lowest`: rewrite to the lowest.
1161
+ * - `catalog`: rewrite any dep already pinned in a workspace catalog
1162
+ * to `catalog:` / `catalog:&lt;name>`. Catalog must exist; this lint
1163
+ * does not create the catalog (see `vis lint --resolve catalog --propose`).
1164
+ * @default "highest"
1165
+ */
1166
+ resolve?: "catalog" | "highest" | "lowest";
1167
+ };
1168
+ }
1169
+ interface VisSecurityConfig {
1170
+ /**
1171
+ * Packages whose policy findings have been reviewed and explicitly
1172
+ * accepted. Matched against every policy unless `policies` narrows the
1173
+ * scope. Replaces the legacy `security.socket.acceptedRisks` map.
1174
+ *
1175
+ * Key format: package name (`"lodash"`), name@version
1176
+ * (`"lodash@4.17.21"`), or glob (`"@myorg/*"`). Unversioned keys match
1177
+ * all versions of that package.
1178
+ * @example
1179
+ * ```
1180
+ * acceptedRisks: {
1181
+ * "some-risky-pkg": {
1182
+ * reason: "Internal fork, low score expected",
1183
+ * acceptedAt: "2026-03-15T10:00:00Z",
1184
+ * acceptedScore: 0.25,
1185
+ * policies: ["score"],
1186
+ * expiresAt: "2026-12-31",
1187
+ * },
1188
+ * }
1189
+ * ```
1190
+ */
1191
+ acceptedRisks?: Record<string, {
1192
+ /** ISO 8601 timestamp when the risk was accepted. */
1193
+ acceptedAt: string;
1194
+ /**
1195
+ * The overall Socket.dev score at the time of acceptance,
1196
+ * in the range `[0, 1]` (mirrors `policies.score.minimum`).
1197
+ * Only relevant for the `score` policy; ignored elsewhere.
1198
+ */
1199
+ acceptedScore?: number;
1200
+ /**
1201
+ * ISO 8601 date (or datetime). After this point the acceptance
1202
+ * stops applying and vis emits a warning. Leave undefined for
1203
+ * non-expiring entries. Values that fail to parse as a Date
1204
+ * are rejected by the loader rather than silently treated as
1205
+ * "always expired".
1206
+ */
1207
+ expiresAt?: string;
1208
+ /**
1209
+ * Which policies this acceptance covers. When undefined the
1210
+ * acceptance applies to every policy finding on this package.
1211
+ */
1212
+ policies?: PolicyName[];
1213
+ /** User-provided reason for accepting the risk. */
1214
+ reason: string;
1215
+ }>;
1216
+ /**
1217
+ * Map of bin names (or `pkg#bin` qualifiers) blessed for shadowing.
1218
+ * When two installed packages expose the same bin name, vis flags
1219
+ * the collision in `vis security list` and the post-install drift
1220
+ * report — set the bin (or `pkg#bin`) to `true` here to suppress
1221
+ * the warning once you've reviewed the conflict.
1222
+ *
1223
+ * Port of LavaMoat allow-scripts' experimental `allowBins`.
1224
+ * Bare names match any conflicting bin with that name; the
1225
+ * `pkg#bin` form scopes the approval to a single package's bin.
1226
+ * @example
1227
+ * ```
1228
+ * allowBins: {
1229
+ * tsc: true, // bless any 'tsc' bin
1230
+ * "typescript#tsc": true, // bless only typescript's 'tsc'
1231
+ * }
1232
+ * ```
1233
+ */
1234
+ allowBins?: Record<string, boolean>;
1235
+ /**
1236
+ * Offline OSV advisory + `vis audit` configuration.
1237
+ *
1238
+ * Controls `vis audit --offline` and `vis advisories sync` behavior:
1239
+ * - `audit.advisories.source` is the OSV mirror to download from. It
1240
+ * must be `https://` and resolve to a host in `allowedHosts` (or one
1241
+ * of the built-in defaults).
1242
+ * - `audit.offlineByDefault` flips the default of `--offline`.
1243
+ *
1244
+ * Vulnerability severity gating and reachability filtering live under
1245
+ * `policies.vulnerability` (see below).
1246
+ */
1247
+ audit?: {
1248
+ /**
1249
+ * Offline advisory cache settings.
1250
+ */
1251
+ advisories?: {
1252
+ /**
1253
+ * Extra hosts permitted as `audit.advisories.source`. The
1254
+ * built-in allowlist is enforced even if this field is
1255
+ * omitted; entries here add to it.
1256
+ * @example ["mirror.corp.example.com"]
1257
+ */
1258
+ allowedHosts?: string[];
1259
+ /**
1260
+ * Bloom-filter prefilter for OSV `MAL-*` (malicious-package)
1261
+ * advisories. Probes a ~380 KB filter fetched from
1262
+ * `endevco/osv-bloom` and escalates hits to the existing
1263
+ * advisory query path for `(name, version)` confirmation.
1264
+ *
1265
+ * Cost: ~380 KB on the wire, refreshed every 10 minutes
1266
+ * upstream. False-positive rate is ~0.1%, so a typical
1267
+ * 1000-package lockfile triggers zero or one extra
1268
+ * round trip per audit.
1269
+ *
1270
+ * Independent of `audit.advisories.source` / `verify` —
1271
+ * those control the full OSV ingest. The bloom is
1272
+ * MAL-* only and aimed at cold-start preflight and
1273
+ * ephemeral CI runners that haven't synced the full DB.
1274
+ */
1275
+ bloom?: {
1276
+ /**
1277
+ * Extra hosts permitted as `bloom.source`. The
1278
+ * built-in allowlist (`endevco.github.io`) is enforced
1279
+ * even if this field is omitted; entries here add to it.
1280
+ */
1281
+ allowedHosts?: string[];
1282
+ /**
1283
+ * Prefilter mode:
1284
+ * - `off`: never run the bloom check.
1285
+ * - `on`: run when a local filter is cached; on
1286
+ * fetch failure, fall back to the cached filter or
1287
+ * skip the prefilter (audit continues against the
1288
+ * non-bloom path).
1289
+ * - `required`: hard-fail the audit when the bloom
1290
+ * refresh fails or the local cache is missing.
1291
+ * Use in hardened CI together with
1292
+ * `audit.advisories.source`.
1293
+ * @default "off"
1294
+ */
1295
+ mode?: "off" | "on" | "required";
1296
+ /**
1297
+ * Bloom mirror base URL (no trailing slash). Defaults
1298
+ * to the public `endevco/osv-bloom` GH Pages site.
1299
+ * Override only if you mirror the bloom artifacts
1300
+ * internally; the hostname must appear in
1301
+ * `allowedHosts`.
1302
+ * @default "https://endevco.github.io/osv-bloom"
1303
+ */
1304
+ source?: string;
1305
+ };
1306
+ /**
1307
+ * Number of hours after `lastSyncIso` before `vis audit`
1308
+ * prints a "your advisory cache may be stale" notice.
1309
+ * `vis audit` never auto-syncs — the user runs
1310
+ * `vis advisories sync` themselves.
1311
+ * @default 24
1312
+ */
1313
+ refreshIntervalHours?: number;
1314
+ /**
1315
+ * OSV mirror base URL (no trailing slash). Defaults to the
1316
+ * public Google Cloud Storage bucket. Override to point at a
1317
+ * corporate mirror; the hostname must appear in `allowedHosts`
1318
+ * (or one of the built-in defaults) and the scheme must be
1319
+ * `https://`.
1320
+ * @default "https://osv-vulnerabilities.storage.googleapis.com"
1321
+ */
1322
+ source?: string;
1323
+ /**
1324
+ * Sigstore signature verification for the OSV dump.
1325
+ * Requires the native binding to be built with the
1326
+ * `verify-signatures` Cargo feature (default in the release
1327
+ * build). Off by default — the upstream OSV bucket does not
1328
+ * ship signatures today.
1329
+ */
1330
+ verify?: {
1331
+ /**
1332
+ * Enable signature verification. The sync flow downloads
1333
+ * `&lt;eco>/all.zip.sig` next to the zip and aborts if it
1334
+ * cannot verify against `expectedIssuer` / `expectedSubject`.
1335
+ * @default false
1336
+ */
1337
+ enabled?: boolean;
1338
+ /** OIDC issuer that signed the bundle. */
1339
+ expectedIssuer?: string;
1340
+ /** OIDC subject (workload identity) that signed the bundle. */
1341
+ expectedSubject?: string;
1342
+ };
1343
+ };
1344
+ /**
1345
+ * Gates for the auto-fix flow (`vis audit --fix` /
1346
+ * `--fix-transitive`). The CLI prompts outside CI; inside CI
1347
+ * the flags refuse to run unless `--yes` is set and, for
1348
+ * transitives, `apply.transitive.enabled = true`.
1349
+ */
1350
+ apply?: {
1351
+ /**
1352
+ * Gates for `vis audit --fix-transitive`. Two-lock: the
1353
+ * CLI requires `--yes` AND this flag set to `true` before
1354
+ * it will rewrite override entries in CI.
1355
+ */
1356
+ transitive?: {
1357
+ /**
1358
+ * When true, allows `--fix-transitive` to run in CI
1359
+ * environments. Defaults to false because rewriting
1360
+ * overrides is a higher blast radius than bumping a
1361
+ * direct dep.
1362
+ * @default false
1363
+ */
1364
+ enabled?: boolean;
1365
+ };
1366
+ };
1367
+ /**
1368
+ * Vulnerability scanner backend.
1369
+ *
1370
+ * - `auto` (default): delegate to `aube audit` when aube is the
1371
+ * active installer (its scanner reads the same lockfile and
1372
+ * produces equivalent severity ratings); otherwise run vis's
1373
+ * own OSV/Socket scanner.
1374
+ * - `aube`: always delegate to `aube audit`. Errors if `aube` is
1375
+ * not on PATH.
1376
+ * - `vis`: always use vis's built-in scanner — never delegate.
1377
+ *
1378
+ * Delegation avoids redundant work (aube already has a
1379
+ * full-fidelity audit pass that respects its own exclusions
1380
+ * via `aube-workspace.yaml::auditConfig`) and lets users get
1381
+ * a single, consistent result regardless of which entry point
1382
+ * they invoke.
1383
+ * @default "auto"
1384
+ */
1385
+ backend?: "aube" | "auto" | "vis";
1386
+ /**
1387
+ * When true, `vis audit` skips network calls and queries the
1388
+ * offline cache. Equivalent to the CLI `--offline` flag.
1389
+ * @default false
1390
+ */
1391
+ offlineByDefault?: boolean;
1392
+ };
1393
+ /**
1394
+ * When true, prevents transitive dependencies from using exotic sources
1395
+ * (git repositories, direct tarball URLs). Only direct dependencies may
1396
+ * use such sources. Equivalent to pnpm's `blockExoticSubdeps`.
1397
+ * @default false
1398
+ */
1399
+ blockExoticSubdeps?: boolean;
1400
+ /**
1401
+ * deps.dev (Google Open Source Insights) data-source configuration.
1402
+ * Public, unauthenticated; pulls Scorecard data + advisories from
1403
+ * `api.deps.dev`. Complements or replaces Socket.dev. Heavily cached.
1404
+ * @see https://docs.deps.dev/api/v3/
1405
+ */
1406
+ depsDev?: {
1407
+ /**
1408
+ * Cache TTL for advisory entries (immutable once published). 7 days.
1409
+ * @default 604800000
1410
+ */
1411
+ advisoryCacheTtlMs?: number;
1412
+ /**
1413
+ * Enable deps.dev scanning on install/update/check/audit commands.
1414
+ * @default false
1415
+ */
1416
+ enabled?: boolean;
1417
+ /**
1418
+ * Cache TTL for OpenSSF Scorecard project data (refreshes weekly). 24 hours.
1419
+ * @default 86400000
1420
+ */
1421
+ projectCacheTtlMs?: number;
1422
+ /**
1423
+ * Request timeout in milliseconds.
1424
+ * @default 15000
1425
+ */
1426
+ timeoutMs?: number;
1427
+ /**
1428
+ * Cache TTL for npm version metadata (immutable). 7 days.
1429
+ * @default 604800000
1430
+ */
1431
+ versionCacheTtlMs?: number;
1432
+ };
1433
+ /**
1434
+ * Package names exempted from the `blockExoticSubdeps` check.
1435
+ * Bare names and a trailing `*` glob (`@scope/*`) are supported.
1436
+ * Use for an internal package legitimately published as a git or
1437
+ * tarball dependency.
1438
+ * @example ["@myorg/legacy", "internal-*"]
1439
+ */
1440
+ exoticSubdepsAllow?: string[];
1441
+ /**
1442
+ * Pre-install marshall pipeline — packument-derived supply-chain
1443
+ * gates (author, provenance, s1ngularity, new-bin, metadata,
1444
+ * downloads, expired-domains, signatures, archived-repo) that run before
1445
+ * `vis add` / `vis install &lt;pkg>` / `vis update &lt;pkg>` hand off to
1446
+ * the underlying package manager. Every entry is optional; omit a
1447
+ * key and the marshall runs with defaults. Set `enabled: false`
1448
+ * on a specific marshall to skip it without touching env vars.
1449
+ */
1450
+ marshalls?: {
1451
+ /** Archived-repo marshall (GitHub repository status). */
1452
+ archivedRepo?: {
1453
+ /** Package names to skip. */
1454
+ allowlist?: string[];
1455
+ /** Default: marshall is on. Set false to disable. */
1456
+ enabled?: boolean;
1457
+ /** GitHub PAT for the API call (5k/hr vs 60/hr). */
1458
+ githubToken?: string;
1459
+ };
1460
+ /** Author / publisher heuristics. */
1461
+ author?: {
1462
+ allowlist?: string[];
1463
+ /** Days since the publisher's last release before flagging as error. */
1464
+ dormantErrorDays?: number;
1465
+ /** Days since the publisher's last release before flagging as warning. */
1466
+ dormantWarnDays?: number;
1467
+ enabled?: boolean;
1468
+ /** Window for the "new publisher on an established package" check. */
1469
+ newPublisherWindowDays?: number;
1470
+ /** Days since the resolved version was published — error threshold. */
1471
+ recentVersionErrorDays?: number;
1472
+ /** Days since the resolved version was published — warning threshold. */
1473
+ recentVersionWarnDays?: number;
1474
+ };
1475
+ /** npm `deprecated`-flag check on the resolved version. */
1476
+ deprecation?: {
1477
+ allowlist?: string[];
1478
+ enabled?: boolean;
1479
+ };
1480
+ /** Monthly download-count floor. */
1481
+ downloads?: {
1482
+ allowlist?: string[];
1483
+ enabled?: boolean;
1484
+ /** Below this monthly count → error (default: 20). */
1485
+ errorThreshold?: number;
1486
+ /** Below this monthly count → warning (default: 1000). */
1487
+ warnThreshold?: number;
1488
+ };
1489
+ /** Maintainer-email-domain NS lookup. */
1490
+ expiredDomains?: {
1491
+ /** Domains exempted from the check (legacy / internal). */
1492
+ allowDomains?: string[];
1493
+ allowlist?: string[];
1494
+ /** DNS resolvers to query (default: system). */
1495
+ dnsServers?: string[];
1496
+ enabled?: boolean;
1497
+ /** Per-domain DNS timeout (default: 5000). */
1498
+ timeoutMs?: number;
1499
+ };
1500
+ /** README / license / repository presence checks. */
1501
+ metadata?: {
1502
+ allowlist?: string[];
1503
+ /** Subset of checks to run. Default: all three. */
1504
+ checks?: ("license" | "readme" | "repo")[];
1505
+ enabled?: boolean;
1506
+ };
1507
+ /** New CLI-bin script introduced in this version. */
1508
+ newBin?: {
1509
+ allowlist?: string[];
1510
+ enabled?: boolean;
1511
+ };
1512
+ /** Whole-package age heuristics (newly created / unmaintained). */
1513
+ packageAge?: {
1514
+ allowlist?: string[];
1515
+ enabled?: boolean;
1516
+ /** Package created fewer than this many days ago → error. Default 22. */
1517
+ newPackageDays?: number;
1518
+ /** No publish within this many days → warning. Default 365. */
1519
+ unmaintainedDays?: number;
1520
+ };
1521
+ /** Provenance regression check. */
1522
+ provenance?: {
1523
+ allowlist?: string[];
1524
+ enabled?: boolean;
1525
+ };
1526
+ /**
1527
+ * Composite "compromised-publish shape" detector — flags a single
1528
+ * version that simultaneously introduced/changed an install hook
1529
+ * AND dropped the provenance attestation a prior stable version
1530
+ * carried (the August 2025 s1ngularity / Nx fingerprint).
1531
+ */
1532
+ s1ngularity?: {
1533
+ allowlist?: string[];
1534
+ enabled?: boolean;
1535
+ };
1536
+ /**
1537
+ * ECDSA P-256 verification against npm's signing keys. Disabled
1538
+ * by default because npm coverage still has gaps that produce
1539
+ * noisy warnings on legitimate packages.
1540
+ */
1541
+ signatures?: {
1542
+ allowlist?: string[];
1543
+ /** Default: marshall is *off*. Set true to enable. */
1544
+ enabled?: boolean;
1545
+ /** Override the keys endpoint (default: npm registry). */
1546
+ keysUrl?: string;
1547
+ /** How to treat an expired-but-known key. Default: "warning". */
1548
+ treatExpiredAs?: "error" | "warning";
1549
+ };
1550
+ };
1551
+ /**
1552
+ * When true, `security.policies.installScripts.allow` keys are matched
1553
+ * as `name@version`. A version bump on an approved package drops it from
1554
+ * the allowlist until the new version is explicitly re-approved (port
1555
+ * of LavaMoat allow-scripts' version-aware policy matcher).
1556
+ *
1557
+ * After a version bump, run `vis approve-builds` or `vis security list`
1558
+ * — both surface a "Version drift" block with the suggested new key
1559
+ * (`old-key → new-key`) so you can update `vis.config.ts` by hand.
1560
+ * @default false
1561
+ */
1562
+ pinVersions?: boolean;
1563
+ /**
1564
+ * Supply-chain policy gates. Each sub-block enables one policy and
1565
+ * configures its behavior. When a sub-block is omitted the policy is
1566
+ * inactive. `acceptedRisks` (above) silences specific packages without
1567
+ * disabling a policy globally.
1568
+ *
1569
+ * The 8 policies are inspired by Socket.dev's classification:
1570
+ * - `malware` — Socket-flagged malicious packages
1571
+ * - `firstSeen` — packages published less than N minutes ago
1572
+ * - `unexpectedDeps` — packages outside an allow-list / baseline
1573
+ * - `publisherChange` — maintainer set changed between installs
1574
+ * - `installScripts` — preinstall/install/postinstall scripts
1575
+ * - `score` — Socket overall score below threshold
1576
+ * - `vulnerability` — OSV vulnerability findings
1577
+ * - `license` — SPDX allow / deny lists
1578
+ */
1579
+ policies?: {
1580
+ /**
1581
+ * Minimum number of minutes that must pass after a version is
1582
+ * published before vis will allow installation. Migrated from
1583
+ * the legacy `security.minimumReleaseAge` field. Equivalent to
1584
+ * pnpm's `minimumReleaseAge`.
1585
+ * @default 0
1586
+ * @example { minutes: 1440, exclude: ["@myorg/*"] } // 24 hours
1587
+ */
1588
+ firstSeen?: {
1589
+ /**
1590
+ * Package names/patterns excluded from the firstSeen check.
1591
+ * Equivalent to pnpm's `minimumReleaseAgeExclude`.
1592
+ * @example ["webpack", "react", "@myorg/*"]
1593
+ */
1594
+ exclude?: string[];
1595
+ /** Minutes after publish before install is allowed. */
1596
+ minutes?: number;
1597
+ };
1598
+ /**
1599
+ * Build-script (pre/install/postinstall/prepare) controls.
1600
+ * Migrated from the legacy `security.allowBuilds` /
1601
+ * `security.strictDepBuilds` fields.
1602
+ * @example { allow: { esbuild: true }, strict: true }
1603
+ */
1604
+ installScripts?: {
1605
+ /**
1606
+ * Map of package names/patterns to allow (true) or deny
1607
+ * (false) build scripts. Packages not listed are denied
1608
+ * by default. Equivalent to pnpm's `allowBuilds`.
1609
+ */
1610
+ allow?: Record<string, boolean>;
1611
+ /**
1612
+ * When true, installation will fail (exit non-zero) if any
1613
+ * dependencies have unreviewed build scripts. Equivalent to
1614
+ * pnpm's `strictDepBuilds`.
1615
+ * @default false
1616
+ */
1617
+ strict?: boolean;
1618
+ };
1619
+ /**
1620
+ * SPDX license allow / deny lists. Deny wins on any sub-license
1621
+ * match in SPDX expressions (`(MIT OR GPL-3.0)` against
1622
+ * `deny: ["GPL-3.0"]` is blocked). Packages with no declared
1623
+ * license are flagged when `allow` is set.
1624
+ * @example
1625
+ * ```
1626
+ * license: {
1627
+ * allow: ["MIT", "Apache-2.0", "BSD-3-Clause"],
1628
+ * deny: ["GPL-3.0", "AGPL-3.0"],
1629
+ * }
1630
+ * ```
1631
+ */
1632
+ license?: {
1633
+ /**
1634
+ * SPDX identifiers that are explicitly permitted. When set,
1635
+ * any package whose declared license is not on this list is
1636
+ * blocked.
1637
+ */
1638
+ allow?: string[];
1639
+ /**
1640
+ * SPDX identifiers that are explicitly forbidden. Always
1641
+ * wins over `allow` when both reference the same identifier.
1642
+ */
1643
+ deny?: string[];
1644
+ };
1645
+ /**
1646
+ * Behavior when the Socket.dev feed flags a package as malicious
1647
+ * (`alerts[].type === "Malware"`).
1648
+ *
1649
+ * The default is cross-field: `{ mode: "block" }` whenever
1650
+ * `security.socket.enabled !== false` (the engine cannot evaluate
1651
+ * malware without Socket data), and `"off"` otherwise. Consumers
1652
+ * resolve this default at evaluation time.
1653
+ */
1654
+ malware?: {
1655
+ /**
1656
+ * - `"block"` — emit a block decision.
1657
+ * - `"warn"` — surface as a warning; do not gate exit code.
1658
+ * - `"off"` — disable the policy entirely.
1659
+ */
1660
+ mode?: "block" | "off" | "warn";
1661
+ };
1662
+ /**
1663
+ * Trust-level checking for package publishing. Migrated from the
1664
+ * legacy `security.trustPolicy*` fields. Equivalent to pnpm's
1665
+ * `trustPolicy`.
1666
+ * @example { mode: "no-downgrade", ignoreAfter: 43200 } // 30 days
1667
+ */
1668
+ publisherChange?: {
1669
+ /**
1670
+ * Package selectors excluded from the check.
1671
+ * Equivalent to pnpm's `trustPolicyExclude`.
1672
+ * @example ["chokidar@4.0.3"]
1673
+ */
1674
+ exclude?: string[];
1675
+ /**
1676
+ * Ignore packages published more than N minutes ago. Useful
1677
+ * for older packages that pre-date provenance support.
1678
+ * Equivalent to pnpm's `trustPolicyIgnoreAfter`.
1679
+ */
1680
+ ignoreAfter?: number;
1681
+ /**
1682
+ * - `"off"` — no trust checking (default).
1683
+ * - `"no-downgrade"` — block when a package's trust level
1684
+ * has decreased compared to previous releases (e.g., was
1685
+ * published by trusted publisher, now only has provenance).
1686
+ */
1687
+ mode?: "no-downgrade" | "off";
1688
+ };
1689
+ /**
1690
+ * Socket.dev overall-score threshold. Packages scoring below
1691
+ * `minimum` trigger a block decision (or interactive prompt
1692
+ * during `vis add`). Migrated from the legacy
1693
+ * `security.socket.minimumScore` field.
1694
+ * @example { minimum: 0.4 }
1695
+ */
1696
+ score?: {
1697
+ /**
1698
+ * Minimum overall Socket.dev score (0–1). Set to 0 to
1699
+ * disable the gate while keeping Socket data fetched.
1700
+ *
1701
+ * Consulted by `vis add`, `audit`, `doctor`, `check`, and
1702
+ * `update`; resolved once in `buildSocketOptions`, then
1703
+ * threaded through every consumer. Falls back to
1704
+ * `DEFAULT_LOW_SCORE_THRESHOLD` (`0.4`) when unset.
1705
+ */
1706
+ minimum?: number;
1707
+ };
1708
+ /**
1709
+ * Net-new transitive dependency detection. Either provide a
1710
+ * static allow-list, a baseline lockfile path (recommended), or
1711
+ * both — the intersection is enforced.
1712
+ * @example { baselineLockfile: "./security/lockfile.baseline.yaml" }
1713
+ */
1714
+ unexpectedDeps?: {
1715
+ /**
1716
+ * Allow-list of dependency names that may appear in the
1717
+ * resolved package set. Glob patterns are supported.
1718
+ * @example ["lodash", "axios", "@myorg/*"]
1719
+ */
1720
+ allow?: string[];
1721
+ /**
1722
+ * Path (absolute or relative to the workspace root) to a
1723
+ * baseline lockfile snapshot. The policy diffs the current
1724
+ * lockfile against this baseline and flags any package that
1725
+ * didn't exist before.
1726
+ * @example "./security/lockfile.baseline.yaml"
1727
+ */
1728
+ baselineLockfile?: string;
1729
+ };
1730
+ /**
1731
+ * OSV vulnerability gating. Migrated from the legacy
1732
+ * `security.audit.failOn` + `security.audit.usage` fields.
1733
+ */
1734
+ vulnerability?: {
1735
+ /**
1736
+ * Severity threshold that makes `vis audit` exit non-zero.
1737
+ * Equivalent to the CLI `--fail-on` flag.
1738
+ * @example "high"
1739
+ */
1740
+ failOn?: "critical" | "high" | "low" | "medium";
1741
+ /**
1742
+ * Reachability filter — only report vulnerabilities in
1743
+ * packages the workspace statically imports.
1744
+ */
1745
+ usage?: {
1746
+ /**
1747
+ * Packages to always treat as reachable even if no
1748
+ * static import is found.
1749
+ * @example ["esbuild", "webpack-cli"]
1750
+ */
1751
+ alwaysAssumeUsed?: string[];
1752
+ /**
1753
+ * Enable the reachability filter by default. Equivalent
1754
+ * to `--usage` on the CLI; `--no-usage` disables.
1755
+ * @default false
1756
+ */
1757
+ enabled?: boolean;
1758
+ };
1759
+ };
1760
+ };
1761
+ /**
1762
+ * Which provider wins merge conflicts when multiple are enabled (e.g.
1763
+ * both Socket.dev and deps.dev return data for the same package). The
1764
+ * primary provider's `score` is kept; alerts from secondaries are
1765
+ * appended and deduped by `key`. Defaults to whichever provider is
1766
+ * enabled first in this order: socket → deps-dev → snyk.
1767
+ */
1768
+ primaryProvider?: "deps-dev" | "snyk" | "socket";
1769
+ /**
1770
+ * Snyk data-source configuration. Snyk only contributes vulnerability
1771
+ * data (no maintenance / quality / supply-chain / license signal);
1772
+ * those axes stay neutral. Requires both an org id and an API token —
1773
+ * if either is missing the provider is skipped.
1774
+ * @see https://docs.snyk.io/snyk-api/using-specific-snyk-apis/issues-list-issues-for-a-package
1775
+ */
1776
+ snyk?: {
1777
+ /**
1778
+ * Snyk API token. Set via VIS_SNYK_TOKEN environment variable or
1779
+ * here.
1780
+ */
1781
+ apiToken?: string;
1782
+ /**
1783
+ * Snyk REST API version date sent as the `version` query param.
1784
+ * @default "2024-10-15"
1785
+ */
1786
+ apiVersion?: string;
1787
+ /**
1788
+ * Cache TTL in milliseconds for Snyk issue lookups. 6 hours.
1789
+ * @default 21600000
1790
+ */
1791
+ cacheTtlMs?: number;
1792
+ /**
1793
+ * Enable Snyk security scanning on install/update/check/audit
1794
+ * commands.
1795
+ * @default false
1796
+ */
1797
+ enabled?: boolean;
1798
+ /**
1799
+ * Snyk organization id (the REST endpoint is org-scoped). Set via
1800
+ * VIS_SNYK_ORG environment variable or here.
1801
+ */
1802
+ orgId?: string;
1803
+ /**
1804
+ * Request timeout in milliseconds for the Snyk API. 15 seconds.
1805
+ * @default 15000
1806
+ */
1807
+ timeoutMs?: number;
1808
+ };
1809
+ /**
1810
+ * Socket.dev data-source configuration. Connection knobs only — score
1811
+ * thresholds and accepted-risk overrides moved to `policies.score` and
1812
+ * `security.acceptedRisks` respectively.
1813
+ * @see https://socket.dev
1814
+ */
1815
+ socket?: {
1816
+ /**
1817
+ * Custom Socket.dev API token. Falls back to the public API token.
1818
+ * Set via VIS_SOCKET_TOKEN environment variable or here.
1819
+ */
1820
+ apiToken?: string;
1821
+ /**
1822
+ * Cache TTL in milliseconds for Socket.dev reports. 1 hour.
1823
+ * @default 3600000
1824
+ */
1825
+ cacheTtlMs?: number;
1826
+ /**
1827
+ * Enable Socket.dev security scanning on install/update/check commands.
1828
+ * @default false
1829
+ */
1830
+ enabled?: boolean;
1831
+ /**
1832
+ * Request timeout in milliseconds for the Socket.dev API. 15 seconds.
1833
+ * @default 15000
1834
+ */
1835
+ timeoutMs?: number;
1836
+ };
1837
+ /**
1838
+ * Package names to skip during typosquat detection.
1839
+ * Use this for internal packages or known-safe names that happen to
1840
+ * look similar to popular packages.
1841
+ * @example ["my-internal-axois", "@myorg/recat"]
1842
+ */
1843
+ typosquatAllowlist?: string[];
1844
+ }
1845
+ interface VisUpdateConfig {
1846
+ /**
1847
+ * Dependency fields to scan for outdated packages.
1848
+ * Beyond the standard fields, supports:
1849
+ * - `"overrides"` (npm)
1850
+ * - `"resolutions"` (yarn)
1851
+ * - `"pnpm.overrides"`
1852
+ * @default ["dependencies", "devDependencies", "optionalDependencies", "peerDependencies"]
1853
+ */
1854
+ depFields?: string[];
1855
+ exclude?: string[];
1856
+ format?: "json" | "minimal" | "table";
1857
+ /**
1858
+ * Package names or glob patterns to permanently ignore during updates.
1859
+ * Ignored packages are skipped and listed in the output so you know
1860
+ * they were not checked.
1861
+ * @example ["eslint", "@types/*"]
1862
+ */
1863
+ ignore?: string[];
1864
+ include?: string[];
1865
+ /**
1866
+ * Include packages with pinned/exact versions (no `^` or `~` prefix).
1867
+ * By default, pinned versions are skipped during update checks.
1868
+ * @default false
1869
+ */
1870
+ includeLocked?: boolean;
1871
+ install?: boolean;
1872
+ /**
1873
+ * Maximum number of concurrent registry requests during outdated checks.
1874
+ * Higher values speed up large workspaces but risk hitting registry rate
1875
+ * limits or self-hosted Verdaccio caps.
1876
+ * @default 8
1877
+ */
1878
+ maxConcurrentRequests?: number;
1879
+ /**
1880
+ * Minimum number of minutes since a version was published before
1881
+ * vis will consider it for updates. This mirrors pnpm's
1882
+ * `minimumReleaseAge` — a single setting that applies to both
1883
+ * install and update.
1884
+ *
1885
+ * Not set by default. If your package manager config
1886
+ * (`pnpm-workspace.yaml`) has `minimumReleaseAge`, vis will
1887
+ * read it from there as a fallback.
1888
+ * @example 1440 // 24 hours
1889
+ */
1890
+ minimumReleaseAge?: number;
1891
+ /**
1892
+ * Package names/patterns excluded from the minimumReleaseAge check.
1893
+ * @example ["webpack", "@myorg/*"]
1894
+ */
1895
+ minimumReleaseAgeExclude?: string[];
1896
+ /**
1897
+ * Per-package or per-pattern update target overrides.
1898
+ * Keys are exact package names, glob patterns, or regex patterns
1899
+ * wrapped in `/` (e.g., `/^@vue/`).
1900
+ * Values are `"latest"`, `"minor"`, or `"patch"`.
1901
+ * @example { "typescript": "minor", "/^@vue/": "patch" }
1902
+ */
1903
+ packageMode?: Record<string, "latest" | "minor" | "patch">;
1904
+ prerelease?: boolean;
1905
+ /**
1906
+ * Which release channels to consider when picking the target version.
1907
+ * - `"stable"` (default) — only ship stable releases (no prereleases).
1908
+ * - `"same"` — match the prerelease channel of the *current* range:
1909
+ * if you're on `react@19.0.0-rc.1`, only `rc.*` candidates qualify;
1910
+ * if you're on a stable, only stable candidates. Prevents
1911
+ * accidentally promoting a prerelease pin to a stable major bump.
1912
+ * - `"any"` — equivalent to `--prerelease`. Any channel is fair game.
1913
+ *
1914
+ * `--release-channel` on the CLI overrides this. If `prerelease: true`
1915
+ * is set without `releaseChannel`, vis treats it as `"any"`.
1916
+ * @default "stable"
1917
+ */
1918
+ releaseChannel?: "any" | "same" | "stable";
1919
+ security?: boolean;
1920
+ target?: "latest" | "minor" | "patch";
1921
+ }
1922
+ /**
1923
+ * Same shape as `T`. Wrapping a section type in it makes the schema
1924
+ * generator emit the section as a nested object, as it does for an inline
1925
+ * type literal, instead of a `$ref` to a named definition. This keeps the
1926
+ * published JSON schema unchanged when a section moves to its own module.
1927
+ */
1928
+ type Inline<T> = { [K in keyof T]: T[K]; };
1929
+ /**
1930
+ * A predicate used by {@link VisConfig.scopedTasks}.
1931
+ * All listed constraints must match for the block to apply.
1932
+ */
1933
+ interface ScopedTasksMatch {
1934
+ /** Match on primary language. */
1935
+ language?: string | string[];
1936
+ /** Match on project layer. */
1937
+ layer?: ProjectJson["layer"] | ProjectJson["layer"][];
1938
+ /** Match on project type. */
1939
+ projectType?: "application" | "library" | "service" | "tool";
1940
+ /** Match on project stack. */
1941
+ stack?: ProjectJson["stack"] | ProjectJson["stack"][];
1942
+ /** Match projects tagged with any of these tags. */
1943
+ tags?: string[];
1944
+ }
1945
+ interface VisConfig {
1946
+ /**
1947
+ * Workspace-relative glob patterns for changed files outside every
1948
+ * project that `vis affected`, `vis run --affected`, `vis ci` and
1949
+ * `vis ci ignore` should not count as a change.
1950
+ *
1951
+ * By default a changed file that belongs to no project (a root
1952
+ * `tsconfig.json`, `package.json`, …) is a global change and marks every
1953
+ * project affected. A changed file matching one of these patterns is
1954
+ * skipped instead. The patterns are only checked for files that belong
1955
+ * to NO project: a file inside a project root is never filtered, so a
1956
+ * broad pattern like `*.md` cannot hide a real package change.
1957
+ *
1958
+ * Patterns use `path.matchesGlob` syntax, where `*` does not cross `/`:
1959
+ * `*.md` matches `README.md` but not `docs/guide.md`.
1960
+ *
1961
+ * Do NOT list paths whose changes really do affect projects, such as
1962
+ * bundler-inlined shared source or the root `tsconfig.json`: an edit
1963
+ * there would then run nothing.
1964
+ * @example ["api-snapshots/**", "plans/**", "*.md"]
1965
+ */
1966
+ affectedIgnore?: string[];
1967
+ /** AI analysis configuration */
1968
+ ai?: {
1969
+ /** Cache TTL in milliseconds. Overrides default (1h / 30min for security). */
1970
+ cacheTtl?: number;
1971
+ /** Override default provider priority. Higher number = preferred. */
1972
+ priority?: Record<string, number>;
1973
+ /** Use a specific provider instead of auto-detecting (e.g., `"claude"`, `"gemini"`). */
1974
+ provider?: string;
1975
+ };
1976
+ /**
1977
+ * Scope the task-runner cache directory by the current git branch.
1978
+ * When `true`, caches are stored under `&lt;cacheDir>/branches/&lt;slug>`
1979
+ * so `main` and feature branches stop thrashing each other —
1980
+ * generated artefacts (schemas, `.d.ts` snapshots) that legitimately
1981
+ * differ across branches no longer oscillate the cache contents.
1982
+ *
1983
+ * Falls back to the unscoped path on detached HEAD, non-git
1984
+ * workspaces, or when git isn't available.
1985
+ * @default false
1986
+ */
1987
+ branchScopedCache?: boolean;
1988
+ /**
1989
+ * Code ownership configuration. Controls how `vis sync codeowners`
1990
+ * renders the generated CODEOWNERS file.
1991
+ */
1992
+ codeowners?: CodeownersConfig;
1993
+ /**
1994
+ * Composer packages as task projects. Off by default: a `composer.json` in a
1995
+ * subdirectory gets validate and, when its scripts define them, test and lint targets.
1996
+ */
1997
+ composer?: {
1998
+ discover?: boolean;
1999
+ };
2000
+ /**
2001
+ * Project dependency constraints.
2002
+ * Enforced after building the project graph, before running tasks.
2003
+ */
2004
+ constraints?: ConstraintsConfig;
2005
+ /**
2006
+ * Configuration for the `vis create` scaffolding command.
2007
+ * Controls template downloads (via giget), default options, and
2008
+ * post-creation behavior.
2009
+ */
2010
+ create?: {
2011
+ /**
2012
+ * Authorization token for downloading private repository templates.
2013
+ * Passed as Bearer token to the git host API.
2014
+ * Can also be set via GIGET_AUTH, GITHUB_TOKEN, or GH_TOKEN environment variables.
2015
+ */
2016
+ auth?: string;
2017
+ /**
2018
+ * Default editor to configure after scaffolding.
2019
+ * When set, `vis create` automatically generates editor config files.
2020
+ * @example "vscode"
2021
+ */
2022
+ defaultEditor?: "vscode";
2023
+ /**
2024
+ * Default package manager for new standalone projects.
2025
+ * When set, skips the PM selection prompt in interactive mode.
2026
+ */
2027
+ defaultPm?: "bun" | "npm" | "pnpm" | "yarn";
2028
+ /**
2029
+ * Default giget provider for `owner/repo` shorthand inputs.
2030
+ * @default "github"
2031
+ */
2032
+ defaultProvider?: "bitbucket" | "github" | "gitlab" | "sourcehut";
2033
+ /**
2034
+ * Template used by a bare `vis create`. Accepts any template input, including an
2035
+ * organization scope (`@acme` opens the `@acme/create` manifest picker, `@acme:app`
2036
+ * selects one entry directly). In a terminal the usual prompts still run, minus the template step.
2037
+ * @example "@acme"
2038
+ */
2039
+ defaultTemplate?: string;
2040
+ /**
2041
+ * Initialize a git repository after scaffolding standalone projects.
2042
+ * @default false
1004
2043
  */
1005
2044
  gitInit?: boolean;
1006
2045
  /**
@@ -1376,326 +2415,48 @@ interface VisConfig {
1376
2415
  *
1377
2416
  * Shown at most once every 14 days; skipped in CI, non-TTY shells,
1378
2417
  * during `--help`/`--version`/`ai`/`mcp` invocations, and when
1379
- * `VIS_NO_MCP_PROMOTE=1` is set. Set `enabled: false` to silence
1380
- * permanently for this workspace.
1381
- * @example
1382
- * ```
1383
- * mcpPromote: { enabled: false }
1384
- * ```
1385
- */
1386
- mcpPromote?: {
1387
- /**
1388
- * Show the vis-mcp promotion notice on successful command completion.
1389
- * @default true
1390
- */
1391
- enabled?: boolean;
1392
- };
1393
- /**
1394
- * Named input patterns inherited by every project target. Equivalent
1395
- * to task-runner's `namedInputs` but configurable from the vis config.
1396
- */
1397
- namedInputs?: NamedInputs;
1398
- /**
1399
- * NuGet projects as task projects. Off by default: each directory with one `*.csproj` or
1400
- * `*.fsproj` (outside `bin`, `obj` and `node_modules`) gets build, test and format:check
1401
- * targets when this is set. POSIX only: the inferred commands are not verified on Windows.
1402
- */
1403
- nuget?: {
1404
- discover?: boolean;
1405
- };
1406
- /** Package override mappings applied during migration (e.g., `{ "lodash": "lodash-es" }`) */
1407
- overrides?: Record<string, string>;
1408
- /**
1409
- * Plugins — each plugin registers typed hooks that fire at run /
1410
- * task / cache boundaries. See {@link VisPlugin} for the contract.
1411
- * Prefer plugins over per-target shell hooks when behaviour needs
1412
- * access to task metadata, results, or cache state.
1413
- */
1414
- plugins?: VisPlugin[];
1415
- /**
1416
- * Workspace dep-policy lints exposed via `vis lint`. Each block opts in
1417
- * to a single rule; the command flags (`--workspace-protocol`,
1418
- * `--no-redefine-root`, `--banned-deps`) toggle them per-run.
1419
- */
1420
- policy?: {
1421
- /**
1422
- * Map of dep names or globs → reason (or `{ reason, replacement, packages?, paths? }`).
1423
- * Internal/workspace deps are never flagged here; the
1424
- * workspace-protocol lint owns those.
1425
- *
1426
- * Optional `packages` (globs over the declaring package's `name`) and
1427
- * `paths` (globs over the workspace-relative `packageDir`) narrow where
1428
- * the rule applies. With both set, either match is enough. Omit both
1429
- * to ban anywhere — the default.
1430
- * @example
1431
- * ```
1432
- * bannedDeps: {
1433
- * request: "deprecated; use undici",
1434
- * moment: { reason: "huge bundle, frozen upstream", replacement: "date-fns" },
1435
- * "@radix-ui/*": "we standardized on shadcn",
1436
- * react: { reason: "no react in shared libs", paths: ["packages/shared/*"] },
1437
- * "next": { reason: "apps only", packages: ["@app/*"] },
1438
- * }
1439
- * ```
1440
- */
1441
- bannedDeps?: Record<string, string | {
1442
- packages?: string[];
1443
- paths?: string[];
1444
- reason: string;
1445
- replacement?: string;
1446
- }>;
1447
- /**
1448
- * Tweak the custom-types lint that flags drift in `engines.{node,pnpm,...}`,
1449
- * `packageManager`, `volta.{node,pnpm,yarn}`, and the proposed
1450
- * `devEngines.{runtime,packageManager}` array form.
1451
- *
1452
- * Each (customType × name) cluster is tracked independently —
1453
- * `engines.node` and `volta.node` don't cross-couple here. Use a
1454
- * versionGroup once that lands if you need to enforce they agree.
1455
- */
1456
- customTypes?: {
1457
- /**
1458
- * Three-state autofix opt-out. See `workspaceProtocol.autofix`
1459
- * for the contract — same semantics, applied to drift rewrites
1460
- * across engines / packageManager / volta / devEngines.
1461
- *
1462
- * Note: `--fix` strips any `+sha512.&lt;hash&gt;` suffix from
1463
- * `packageManager` on bump — content-integrity hashes are tied
1464
- * to a specific package, not a version, so users must regenerate
1465
- * via their PM (`pnpm install` re-pins; `corepack use pnpm@X` etc.).
1466
- * @default true
1467
- */
1468
- autofix?: "prompt" | boolean;
1469
- /**
1470
- * User-defined custom-type pin locations. Each entry tells the
1471
- * customTypes lint to read additional version pins from a
1472
- * non-standard JSON path inside every workspace package.json,
1473
- * cluster them by `(name × depName)` like the built-in types,
1474
- * and rewrite them with `--fix`.
1475
- *
1476
- * The original built-ins (`engines`, `volta`, `packageManager`,
1477
- * `devEngines.runtime`, `devEngines.packageManager`) keep
1478
- * running unconditionally — these layer on top.
1479
- *
1480
- * Strategies:
1481
- * - `versionsByName`: the JSON at `path` is `{ [depName]: version }`
1482
- * (like `engines` or `pnpm.overrides`).
1483
- * - `name@version`: the JSON at `path` is a string of the form
1484
- * `name@version` (like `packageManager`). The leading `name@`
1485
- * is preserved; only the version segment is rewritten.
1486
- * - `string`: the JSON at `path` is a bare version string. The
1487
- * `depName` field is required and identifies the dep cluster.
1488
- *
1489
- * `name` must not collide with a built-in type name. `path` is
1490
- * a dot-separated walk into the package.json (e.g. `pnpm.overrides`).
1491
- * @example
1492
- * ```ts
1493
- * extraTypes: [
1494
- * { name: "pnpmOverridesLegacy", path: "pnpm.overrides", strategy: "versionsByName" },
1495
- * { name: "myToolPin", path: "myTool.runtime", strategy: "name@version" },
1496
- * { name: "minNode", path: "config.minNode", strategy: "string", depName: "node" },
1497
- * ]
1498
- * ```
1499
- */
1500
- extraTypes?: ExtraCustomType[];
1501
- /**
1502
- * Dep names exempt from the drift check (exact match against the
1503
- * field name within the block — e.g. `node`, `pnpm`).
1504
- */
1505
- ignore?: string[];
1506
- /**
1507
- * Resolution strategy used when `--fix` runs.
1508
- * - `highest` (default): align every drifting instance to the
1509
- * highest declared version.
1510
- * - `lowest`: align to the lowest.
1511
- * @default "highest"
1512
- */
1513
- resolve?: "highest" | "lowest";
1514
- };
1515
- /**
1516
- * Tweak the dead-workspace-patterns lint that flags entries in
1517
- * `pnpm-workspace.yaml#packages` / `package.json#workspaces` which
1518
- * resolve to zero on-disk directories.
1519
- */
1520
- deadWorkspacePatterns?: {
1521
- /**
1522
- * Three-state autofix opt-out. See `workspaceProtocol.autofix`
1523
- * for the contract — applied here to dropping unmatched patterns
1524
- * from the workspace config file.
1525
- * @default true
1526
- */
1527
- autofix?: "prompt" | boolean;
1528
- };
1529
- /**
1530
- * Tweak the empty-deps lint that flags empty `dependencies` /
1531
- * `devDependencies` / `peerDependencies` / `optionalDependencies`
1532
- * blocks across the workspace.
1533
- */
1534
- emptyDeps?: {
1535
- /**
1536
- * Three-state autofix opt-out. See `workspaceProtocol.autofix`
1537
- * for the contract — applied here to removing the empty key.
1538
- * @default true
1539
- */
1540
- autofix?: "prompt" | boolean;
1541
- /**
1542
- * Block names exempt from the rule (e.g. `["peerDependencies"]`
1543
- * to keep the key around as a marker even when empty).
1544
- */
1545
- ignoreBlocks?: ("dependencies" | "devDependencies" | "optionalDependencies" | "peerDependencies")[];
1546
- };
1547
- /**
1548
- * Tweak the redefine-root lint that flags non-root packages duplicating
1549
- * deps already pinned at the workspace root.
1550
- */
1551
- redefineRoot?: {
1552
- /** Dep names that are exempt from the redefine-root rule (exact match). */
1553
- ignore?: string[];
1554
- };
1555
- /**
1556
- * Tweak the root-deps lint that flags runtime `dependencies` declared
1557
- * on the private workspace root (they should live in `devDependencies`).
1558
- */
1559
- rootDeps?: {
1560
- /**
1561
- * Three-state autofix opt-out. See `workspaceProtocol.autofix`
1562
- * for the contract — applied here to moving entries from
1563
- * `dependencies` to `devDependencies` on the root package.json.
1564
- * @default true
1565
- */
1566
- autofix?: "prompt" | boolean;
1567
- };
1568
- /**
1569
- * Tweak the root-package-manager lint that flags a missing or
1570
- * malformed `packageManager` field on the workspace root.
1571
- */
1572
- rootPackageManager?: {
1573
- /**
1574
- * Three-state autofix opt-out. See `workspaceProtocol.autofix`
1575
- * for the contract. `--fix` only writes when `suggested` is set —
1576
- * a missing `packageManager` field has no canonical default.
1577
- * @default true
1578
- */
1579
- autofix?: "prompt" | boolean;
1580
- /**
1581
- * Canonical specifier (`name@version`) to write when `--fix` runs
1582
- * and the field is absent. Required to enable autofix —
1583
- * vis won't guess the workspace's preferred manager.
1584
- * @example "pnpm@10.32.1"
1585
- */
1586
- suggested?: string;
1587
- };
1588
- /**
1589
- * Tweak the root-private lint that flags a workspace root package.json
1590
- * missing `"private": true`. Only fires when the root looks like a
1591
- * workspace (npm/yarn/bun `workspaces` field or `pnpm-workspace.yaml`).
1592
- */
1593
- rootPrivate?: {
1594
- /**
1595
- * Three-state autofix opt-out. See `workspaceProtocol.autofix`
1596
- * for the contract — applied here to inserting `"private": true`.
1597
- * @default true
1598
- */
1599
- autofix?: "prompt" | boolean;
1600
- };
1601
- /**
1602
- * Tweak the similar-deps lint that flags drift across related dep
1603
- * families (e.g. `react` and `react-dom`, all of `@babel/*`).
1604
- *
1605
- * The lint is report-only — aligning a family requires picking a
1606
- * single canonical specifier across heterogeneous range syntaxes
1607
- * (`^`, `~`, exact), which is too lossy without user input.
1608
- */
1609
- similarDeps?: {
1610
- /**
1611
- * Additional families merged with the built-ins. Same `id` wins
1612
- * → user override fully replaces the built-in entry.
1613
- * @example
1614
- * ```
1615
- * extraFamilies: [
1616
- * { id: "vue", label: "Vue", members: ["vue", "vue-router", "pinia"] },
1617
- * ]
1618
- * ```
1619
- */
1620
- extraFamilies?: SimilarDepFamily[];
1621
- /** Family ids to skip entirely (matches `SimilarDepFamily.id`). */
1622
- ignoreFamilies?: string[];
1623
- };
1624
- /**
1625
- * Tweak the types-in-deps lint that flags `@types/*` declared in
1626
- * `dependencies` on a private package (they belong in
1627
- * `devDependencies` since the package never ships).
1628
- */
1629
- typesInDeps?: {
1630
- /**
1631
- * Three-state autofix opt-out. See `workspaceProtocol.autofix`
1632
- * for the contract — applied here to moving the entry to
1633
- * `devDependencies`. Existing dev pins are preserved on conflict.
1634
- * @default true
1635
- */
1636
- autofix?: "prompt" | boolean;
1637
- /** Dep names exempt from the rule (exact match, e.g. `@types/node`). */
1638
- ignore?: string[];
1639
- };
1640
- /**
1641
- * Tweak the workspace-protocol lint that flags internal deps not
1642
- * using the `workspace:` protocol.
1643
- */
1644
- workspaceProtocol?: {
1645
- /**
1646
- * Three-state autofix opt-out. Some workspaces want detection
1647
- * without rewrite (e.g. dual-licensed packages where `workspace:*`
1648
- * is unsafe).
1649
- * - `true` (default): `--fix` rewrites the specifier.
1650
- * - `false`: never rewrite — report the violation only.
1651
- * - `"prompt"`: ask before each rewrite. Falls back to report-only
1652
- * when stdin isn't a TTY (CI). Reserved; not yet implemented.
1653
- *
1654
- * Note: when `false` (or `"prompt"`), `--fix` still **fails CI** on
1655
- * detected violations — the rule is "report only", not "ignore".
1656
- * Drop the rule from the lint selection if you want a clean exit.
1657
- * @default true
1658
- * @example
1659
- * ```
1660
- * policy: {
1661
- * workspaceProtocol: { autofix: false },
1662
- * }
1663
- * ```
1664
- */
1665
- autofix?: "prompt" | boolean;
1666
- };
2418
+ * `VIS_NO_MCP_PROMOTE=1` is set. Set `enabled: false` to silence
2419
+ * permanently for this workspace.
2420
+ * @example
2421
+ * ```
2422
+ * mcpPromote: { enabled: false }
2423
+ * ```
2424
+ */
2425
+ mcpPromote?: {
1667
2426
  /**
1668
- * Tweak the workspace-versions lint that flags external deps declared
1669
- * at inconsistent versions across the workspace.
2427
+ * Show the vis-mcp promotion notice on successful command completion.
2428
+ * @default true
1670
2429
  */
1671
- workspaceVersions?: {
1672
- /**
1673
- * Three-state autofix opt-out. See `workspaceProtocol.autofix`
1674
- * for the contract — same semantics, applied to drift rewrites.
1675
- *
1676
- * Also gates the `--propose-min` catalog suggestion writer:
1677
- * when `false` / `"prompt"`, `--fix --propose-min` reports the
1678
- * proposed catalog entries but does not write
1679
- * `pnpm-workspace.yaml`. Same "report only, still fails CI"
1680
- * note applies as on `workspaceProtocol.autofix`.
1681
- * @default true
1682
- */
1683
- autofix?: "prompt" | boolean;
1684
- /** Dep names exempt from the version-drift check (exact match). */
1685
- ignore?: string[];
1686
- /**
1687
- * Resolution strategy used when `--fix` runs.
1688
- * - `highest` (default): rewrite every drifting instance to the
1689
- * highest sibling specifier.
1690
- * - `lowest`: rewrite to the lowest.
1691
- * - `catalog`: rewrite any dep already pinned in a workspace catalog
1692
- * to `catalog:` / `catalog:&lt;name>`. Catalog must exist; this lint
1693
- * does not create the catalog (see `vis lint --resolve catalog --propose`).
1694
- * @default "highest"
1695
- */
1696
- resolve?: "catalog" | "highest" | "lowest";
1697
- };
2430
+ enabled?: boolean;
2431
+ };
2432
+ /**
2433
+ * Named input patterns inherited by every project target. Equivalent
2434
+ * to task-runner's `namedInputs` but configurable from the vis config.
2435
+ */
2436
+ namedInputs?: NamedInputs;
2437
+ /**
2438
+ * NuGet projects as task projects. Off by default: each directory with one `*.csproj` or
2439
+ * `*.fsproj` (outside `bin`, `obj` and `node_modules`) gets build, test and format:check
2440
+ * targets when this is set. POSIX only: the inferred commands are not verified on Windows.
2441
+ */
2442
+ nuget?: {
2443
+ discover?: boolean;
1698
2444
  };
2445
+ /** Package override mappings applied during migration (e.g., `{ "lodash": "lodash-es" }`) */
2446
+ overrides?: Record<string, string>;
2447
+ /**
2448
+ * Plugins — each plugin registers typed hooks that fire at run /
2449
+ * task / cache boundaries. See {@link VisPlugin} for the contract.
2450
+ * Prefer plugins over per-target shell hooks when behaviour needs
2451
+ * access to task metadata, results, or cache state.
2452
+ */
2453
+ plugins?: VisPlugin[];
2454
+ /**
2455
+ * Workspace dep-policy lints exposed via `vis lint`. Each block opts in
2456
+ * to a single rule; the command flags (`--workspace-protocol`,
2457
+ * `--no-redefine-root`, `--banned-deps`) toggle them per-run.
2458
+ */
2459
+ policy?: Inline<VisPolicyConfig>;
1699
2460
  /**
1700
2461
  * Pre-flight checks fired before `vis run` starts the orchestrator.
1701
2462
  * Each check is opt-out (`false`) — defaults are sensible for the
@@ -1880,682 +2641,7 @@ interface VisConfig {
1880
2641
  * For npm/yarn/bun users: vis enforces these at the vis layer since
1881
2642
  * those package managers lack native support.
1882
2643
  */
1883
- security?: {
1884
- /**
1885
- * Packages whose policy findings have been reviewed and explicitly
1886
- * accepted. Matched against every policy unless `policies` narrows the
1887
- * scope. Replaces the legacy `security.socket.acceptedRisks` map.
1888
- *
1889
- * Key format: package name (`"lodash"`), name@version
1890
- * (`"lodash@4.17.21"`), or glob (`"@myorg/*"`). Unversioned keys match
1891
- * all versions of that package.
1892
- * @example
1893
- * ```
1894
- * acceptedRisks: {
1895
- * "some-risky-pkg": {
1896
- * reason: "Internal fork, low score expected",
1897
- * acceptedAt: "2026-03-15T10:00:00Z",
1898
- * acceptedScore: 0.25,
1899
- * policies: ["score"],
1900
- * expiresAt: "2026-12-31",
1901
- * },
1902
- * }
1903
- * ```
1904
- */
1905
- acceptedRisks?: Record<string, {
1906
- /** ISO 8601 timestamp when the risk was accepted. */
1907
- acceptedAt: string;
1908
- /**
1909
- * The overall Socket.dev score at the time of acceptance,
1910
- * in the range `[0, 1]` (mirrors `policies.score.minimum`).
1911
- * Only relevant for the `score` policy; ignored elsewhere.
1912
- */
1913
- acceptedScore?: number;
1914
- /**
1915
- * ISO 8601 date (or datetime). After this point the acceptance
1916
- * stops applying and vis emits a warning. Leave undefined for
1917
- * non-expiring entries. Values that fail to parse as a Date
1918
- * are rejected by the loader rather than silently treated as
1919
- * "always expired".
1920
- */
1921
- expiresAt?: string;
1922
- /**
1923
- * Which policies this acceptance covers. When undefined the
1924
- * acceptance applies to every policy finding on this package.
1925
- */
1926
- policies?: PolicyName[];
1927
- /** User-provided reason for accepting the risk. */
1928
- reason: string;
1929
- }>;
1930
- /**
1931
- * Map of bin names (or `pkg#bin` qualifiers) blessed for shadowing.
1932
- * When two installed packages expose the same bin name, vis flags
1933
- * the collision in `vis security list` and the post-install drift
1934
- * report — set the bin (or `pkg#bin`) to `true` here to suppress
1935
- * the warning once you've reviewed the conflict.
1936
- *
1937
- * Port of LavaMoat allow-scripts' experimental `allowBins`.
1938
- * Bare names match any conflicting bin with that name; the
1939
- * `pkg#bin` form scopes the approval to a single package's bin.
1940
- * @example
1941
- * ```
1942
- * allowBins: {
1943
- * tsc: true, // bless any 'tsc' bin
1944
- * "typescript#tsc": true, // bless only typescript's 'tsc'
1945
- * }
1946
- * ```
1947
- */
1948
- allowBins?: Record<string, boolean>;
1949
- /**
1950
- * Offline OSV advisory + `vis audit` configuration.
1951
- *
1952
- * Controls `vis audit --offline` and `vis advisories sync` behavior:
1953
- * - `audit.advisories.source` is the OSV mirror to download from. It
1954
- * must be `https://` and resolve to a host in `allowedHosts` (or one
1955
- * of the built-in defaults).
1956
- * - `audit.offlineByDefault` flips the default of `--offline`.
1957
- *
1958
- * Vulnerability severity gating and reachability filtering live under
1959
- * `policies.vulnerability` (see below).
1960
- */
1961
- audit?: {
1962
- /**
1963
- * Offline advisory cache settings.
1964
- */
1965
- advisories?: {
1966
- /**
1967
- * Extra hosts permitted as `audit.advisories.source`. The
1968
- * built-in allowlist is enforced even if this field is
1969
- * omitted; entries here add to it.
1970
- * @example ["mirror.corp.example.com"]
1971
- */
1972
- allowedHosts?: string[];
1973
- /**
1974
- * Bloom-filter prefilter for OSV `MAL-*` (malicious-package)
1975
- * advisories. Probes a ~380 KB filter fetched from
1976
- * `endevco/osv-bloom` and escalates hits to the existing
1977
- * advisory query path for `(name, version)` confirmation.
1978
- *
1979
- * Cost: ~380 KB on the wire, refreshed every 10 minutes
1980
- * upstream. False-positive rate is ~0.1%, so a typical
1981
- * 1000-package lockfile triggers zero or one extra
1982
- * round trip per audit.
1983
- *
1984
- * Independent of `audit.advisories.source` / `verify` —
1985
- * those control the full OSV ingest. The bloom is
1986
- * MAL-* only and aimed at cold-start preflight and
1987
- * ephemeral CI runners that haven't synced the full DB.
1988
- */
1989
- bloom?: {
1990
- /**
1991
- * Extra hosts permitted as `bloom.source`. The
1992
- * built-in allowlist (`endevco.github.io`) is enforced
1993
- * even if this field is omitted; entries here add to it.
1994
- */
1995
- allowedHosts?: string[];
1996
- /**
1997
- * Prefilter mode:
1998
- * - `off`: never run the bloom check.
1999
- * - `on`: run when a local filter is cached; on
2000
- * fetch failure, fall back to the cached filter or
2001
- * skip the prefilter (audit continues against the
2002
- * non-bloom path).
2003
- * - `required`: hard-fail the audit when the bloom
2004
- * refresh fails or the local cache is missing.
2005
- * Use in hardened CI together with
2006
- * `audit.advisories.source`.
2007
- * @default "off"
2008
- */
2009
- mode?: "off" | "on" | "required";
2010
- /**
2011
- * Bloom mirror base URL (no trailing slash). Defaults
2012
- * to the public `endevco/osv-bloom` GH Pages site.
2013
- * Override only if you mirror the bloom artifacts
2014
- * internally; the hostname must appear in
2015
- * `allowedHosts`.
2016
- * @default "https://endevco.github.io/osv-bloom"
2017
- */
2018
- source?: string;
2019
- };
2020
- /**
2021
- * Number of hours after `lastSyncIso` before `vis audit`
2022
- * prints a "your advisory cache may be stale" notice.
2023
- * `vis audit` never auto-syncs — the user runs
2024
- * `vis advisories sync` themselves.
2025
- * @default 24
2026
- */
2027
- refreshIntervalHours?: number;
2028
- /**
2029
- * OSV mirror base URL (no trailing slash). Defaults to the
2030
- * public Google Cloud Storage bucket. Override to point at a
2031
- * corporate mirror; the hostname must appear in `allowedHosts`
2032
- * (or one of the built-in defaults) and the scheme must be
2033
- * `https://`.
2034
- * @default "https://osv-vulnerabilities.storage.googleapis.com"
2035
- */
2036
- source?: string;
2037
- /**
2038
- * Sigstore signature verification for the OSV dump.
2039
- * Requires the native binding to be built with the
2040
- * `verify-signatures` Cargo feature (default in the release
2041
- * build). Off by default — the upstream OSV bucket does not
2042
- * ship signatures today.
2043
- */
2044
- verify?: {
2045
- /**
2046
- * Enable signature verification. The sync flow downloads
2047
- * `&lt;eco>/all.zip.sig` next to the zip and aborts if it
2048
- * cannot verify against `expectedIssuer` / `expectedSubject`.
2049
- * @default false
2050
- */
2051
- enabled?: boolean;
2052
- /** OIDC issuer that signed the bundle. */
2053
- expectedIssuer?: string;
2054
- /** OIDC subject (workload identity) that signed the bundle. */
2055
- expectedSubject?: string;
2056
- };
2057
- };
2058
- /**
2059
- * Gates for the auto-fix flow (`vis audit --fix` /
2060
- * `--fix-transitive`). The CLI prompts outside CI; inside CI
2061
- * the flags refuse to run unless `--yes` is set and, for
2062
- * transitives, `apply.transitive.enabled = true`.
2063
- */
2064
- apply?: {
2065
- /**
2066
- * Gates for `vis audit --fix-transitive`. Two-lock: the
2067
- * CLI requires `--yes` AND this flag set to `true` before
2068
- * it will rewrite override entries in CI.
2069
- */
2070
- transitive?: {
2071
- /**
2072
- * When true, allows `--fix-transitive` to run in CI
2073
- * environments. Defaults to false because rewriting
2074
- * overrides is a higher blast radius than bumping a
2075
- * direct dep.
2076
- * @default false
2077
- */
2078
- enabled?: boolean;
2079
- };
2080
- };
2081
- /**
2082
- * Vulnerability scanner backend.
2083
- *
2084
- * - `auto` (default): delegate to `aube audit` when aube is the
2085
- * active installer (its scanner reads the same lockfile and
2086
- * produces equivalent severity ratings); otherwise run vis's
2087
- * own OSV/Socket scanner.
2088
- * - `aube`: always delegate to `aube audit`. Errors if `aube` is
2089
- * not on PATH.
2090
- * - `vis`: always use vis's built-in scanner — never delegate.
2091
- *
2092
- * Delegation avoids redundant work (aube already has a
2093
- * full-fidelity audit pass that respects its own exclusions
2094
- * via `aube-workspace.yaml::auditConfig`) and lets users get
2095
- * a single, consistent result regardless of which entry point
2096
- * they invoke.
2097
- * @default "auto"
2098
- */
2099
- backend?: "aube" | "auto" | "vis";
2100
- /**
2101
- * When true, `vis audit` skips network calls and queries the
2102
- * offline cache. Equivalent to the CLI `--offline` flag.
2103
- * @default false
2104
- */
2105
- offlineByDefault?: boolean;
2106
- };
2107
- /**
2108
- * When true, prevents transitive dependencies from using exotic sources
2109
- * (git repositories, direct tarball URLs). Only direct dependencies may
2110
- * use such sources. Equivalent to pnpm's `blockExoticSubdeps`.
2111
- * @default false
2112
- */
2113
- blockExoticSubdeps?: boolean;
2114
- /**
2115
- * deps.dev (Google Open Source Insights) data-source configuration.
2116
- * Public, unauthenticated; pulls Scorecard data + advisories from
2117
- * `api.deps.dev`. Complements or replaces Socket.dev. Heavily cached.
2118
- * @see https://docs.deps.dev/api/v3/
2119
- */
2120
- depsDev?: {
2121
- /**
2122
- * Cache TTL for advisory entries (immutable once published). 7 days.
2123
- * @default 604800000
2124
- */
2125
- advisoryCacheTtlMs?: number;
2126
- /**
2127
- * Enable deps.dev scanning on install/update/check/audit commands.
2128
- * @default false
2129
- */
2130
- enabled?: boolean;
2131
- /**
2132
- * Cache TTL for OpenSSF Scorecard project data (refreshes weekly). 24 hours.
2133
- * @default 86400000
2134
- */
2135
- projectCacheTtlMs?: number;
2136
- /**
2137
- * Request timeout in milliseconds.
2138
- * @default 15000
2139
- */
2140
- timeoutMs?: number;
2141
- /**
2142
- * Cache TTL for npm version metadata (immutable). 7 days.
2143
- * @default 604800000
2144
- */
2145
- versionCacheTtlMs?: number;
2146
- };
2147
- /**
2148
- * Package names exempted from the `blockExoticSubdeps` check.
2149
- * Bare names and a trailing `*` glob (`@scope/*`) are supported.
2150
- * Use for an internal package legitimately published as a git or
2151
- * tarball dependency.
2152
- * @example ["@myorg/legacy", "internal-*"]
2153
- */
2154
- exoticSubdepsAllow?: string[];
2155
- /**
2156
- * Pre-install marshall pipeline — packument-derived supply-chain
2157
- * gates (author, provenance, s1ngularity, new-bin, metadata,
2158
- * downloads, expired-domains, signatures, archived-repo) that run before
2159
- * `vis add` / `vis install &lt;pkg>` / `vis update &lt;pkg>` hand off to
2160
- * the underlying package manager. Every entry is optional; omit a
2161
- * key and the marshall runs with defaults. Set `enabled: false`
2162
- * on a specific marshall to skip it without touching env vars.
2163
- */
2164
- marshalls?: {
2165
- /** Archived-repo marshall (GitHub repository status). */
2166
- archivedRepo?: {
2167
- /** Package names to skip. */
2168
- allowlist?: string[];
2169
- /** Default: marshall is on. Set false to disable. */
2170
- enabled?: boolean;
2171
- /** GitHub PAT for the API call (5k/hr vs 60/hr). */
2172
- githubToken?: string;
2173
- };
2174
- /** Author / publisher heuristics. */
2175
- author?: {
2176
- allowlist?: string[];
2177
- /** Days since the publisher's last release before flagging as error. */
2178
- dormantErrorDays?: number;
2179
- /** Days since the publisher's last release before flagging as warning. */
2180
- dormantWarnDays?: number;
2181
- enabled?: boolean;
2182
- /** Window for the "new publisher on an established package" check. */
2183
- newPublisherWindowDays?: number;
2184
- /** Days since the resolved version was published — error threshold. */
2185
- recentVersionErrorDays?: number;
2186
- /** Days since the resolved version was published — warning threshold. */
2187
- recentVersionWarnDays?: number;
2188
- };
2189
- /** npm `deprecated`-flag check on the resolved version. */
2190
- deprecation?: {
2191
- allowlist?: string[];
2192
- enabled?: boolean;
2193
- };
2194
- /** Monthly download-count floor. */
2195
- downloads?: {
2196
- allowlist?: string[];
2197
- enabled?: boolean;
2198
- /** Below this monthly count → error (default: 20). */
2199
- errorThreshold?: number;
2200
- /** Below this monthly count → warning (default: 1000). */
2201
- warnThreshold?: number;
2202
- };
2203
- /** Maintainer-email-domain NS lookup. */
2204
- expiredDomains?: {
2205
- /** Domains exempted from the check (legacy / internal). */
2206
- allowDomains?: string[];
2207
- allowlist?: string[];
2208
- /** DNS resolvers to query (default: system). */
2209
- dnsServers?: string[];
2210
- enabled?: boolean;
2211
- /** Per-domain DNS timeout (default: 5000). */
2212
- timeoutMs?: number;
2213
- };
2214
- /** README / license / repository presence checks. */
2215
- metadata?: {
2216
- allowlist?: string[];
2217
- /** Subset of checks to run. Default: all three. */
2218
- checks?: ("license" | "readme" | "repo")[];
2219
- enabled?: boolean;
2220
- };
2221
- /** New CLI-bin script introduced in this version. */
2222
- newBin?: {
2223
- allowlist?: string[];
2224
- enabled?: boolean;
2225
- };
2226
- /** Whole-package age heuristics (newly created / unmaintained). */
2227
- packageAge?: {
2228
- allowlist?: string[];
2229
- enabled?: boolean;
2230
- /** Package created fewer than this many days ago → error. Default 22. */
2231
- newPackageDays?: number;
2232
- /** No publish within this many days → warning. Default 365. */
2233
- unmaintainedDays?: number;
2234
- };
2235
- /** Provenance regression check. */
2236
- provenance?: {
2237
- allowlist?: string[];
2238
- enabled?: boolean;
2239
- };
2240
- /**
2241
- * Composite "compromised-publish shape" detector — flags a single
2242
- * version that simultaneously introduced/changed an install hook
2243
- * AND dropped the provenance attestation a prior stable version
2244
- * carried (the August 2025 s1ngularity / Nx fingerprint).
2245
- */
2246
- s1ngularity?: {
2247
- allowlist?: string[];
2248
- enabled?: boolean;
2249
- };
2250
- /**
2251
- * ECDSA P-256 verification against npm's signing keys. Disabled
2252
- * by default because npm coverage still has gaps that produce
2253
- * noisy warnings on legitimate packages.
2254
- */
2255
- signatures?: {
2256
- allowlist?: string[];
2257
- /** Default: marshall is *off*. Set true to enable. */
2258
- enabled?: boolean;
2259
- /** Override the keys endpoint (default: npm registry). */
2260
- keysUrl?: string;
2261
- /** How to treat an expired-but-known key. Default: "warning". */
2262
- treatExpiredAs?: "error" | "warning";
2263
- };
2264
- };
2265
- /**
2266
- * When true, `security.policies.installScripts.allow` keys are matched
2267
- * as `name@version`. A version bump on an approved package drops it from
2268
- * the allowlist until the new version is explicitly re-approved (port
2269
- * of LavaMoat allow-scripts' version-aware policy matcher).
2270
- *
2271
- * After a version bump, run `vis approve-builds` or `vis security list`
2272
- * — both surface a "Version drift" block with the suggested new key
2273
- * (`old-key → new-key`) so you can update `vis.config.ts` by hand.
2274
- * @default false
2275
- */
2276
- pinVersions?: boolean;
2277
- /**
2278
- * Supply-chain policy gates. Each sub-block enables one policy and
2279
- * configures its behavior. When a sub-block is omitted the policy is
2280
- * inactive. `acceptedRisks` (above) silences specific packages without
2281
- * disabling a policy globally.
2282
- *
2283
- * The 8 policies are inspired by Socket.dev's classification:
2284
- * - `malware` — Socket-flagged malicious packages
2285
- * - `firstSeen` — packages published less than N minutes ago
2286
- * - `unexpectedDeps` — packages outside an allow-list / baseline
2287
- * - `publisherChange` — maintainer set changed between installs
2288
- * - `installScripts` — preinstall/install/postinstall scripts
2289
- * - `score` — Socket overall score below threshold
2290
- * - `vulnerability` — OSV vulnerability findings
2291
- * - `license` — SPDX allow / deny lists
2292
- */
2293
- policies?: {
2294
- /**
2295
- * Minimum number of minutes that must pass after a version is
2296
- * published before vis will allow installation. Migrated from
2297
- * the legacy `security.minimumReleaseAge` field. Equivalent to
2298
- * pnpm's `minimumReleaseAge`.
2299
- * @default 0
2300
- * @example { minutes: 1440, exclude: ["@myorg/*"] } // 24 hours
2301
- */
2302
- firstSeen?: {
2303
- /**
2304
- * Package names/patterns excluded from the firstSeen check.
2305
- * Equivalent to pnpm's `minimumReleaseAgeExclude`.
2306
- * @example ["webpack", "react", "@myorg/*"]
2307
- */
2308
- exclude?: string[];
2309
- /** Minutes after publish before install is allowed. */
2310
- minutes?: number;
2311
- };
2312
- /**
2313
- * Build-script (pre/install/postinstall/prepare) controls.
2314
- * Migrated from the legacy `security.allowBuilds` /
2315
- * `security.strictDepBuilds` fields.
2316
- * @example { allow: { esbuild: true }, strict: true }
2317
- */
2318
- installScripts?: {
2319
- /**
2320
- * Map of package names/patterns to allow (true) or deny
2321
- * (false) build scripts. Packages not listed are denied
2322
- * by default. Equivalent to pnpm's `allowBuilds`.
2323
- */
2324
- allow?: Record<string, boolean>;
2325
- /**
2326
- * When true, installation will fail (exit non-zero) if any
2327
- * dependencies have unreviewed build scripts. Equivalent to
2328
- * pnpm's `strictDepBuilds`.
2329
- * @default false
2330
- */
2331
- strict?: boolean;
2332
- };
2333
- /**
2334
- * SPDX license allow / deny lists. Deny wins on any sub-license
2335
- * match in SPDX expressions (`(MIT OR GPL-3.0)` against
2336
- * `deny: ["GPL-3.0"]` is blocked). Packages with no declared
2337
- * license are flagged when `allow` is set.
2338
- * @example
2339
- * ```
2340
- * license: {
2341
- * allow: ["MIT", "Apache-2.0", "BSD-3-Clause"],
2342
- * deny: ["GPL-3.0", "AGPL-3.0"],
2343
- * }
2344
- * ```
2345
- */
2346
- license?: {
2347
- /**
2348
- * SPDX identifiers that are explicitly permitted. When set,
2349
- * any package whose declared license is not on this list is
2350
- * blocked.
2351
- */
2352
- allow?: string[];
2353
- /**
2354
- * SPDX identifiers that are explicitly forbidden. Always
2355
- * wins over `allow` when both reference the same identifier.
2356
- */
2357
- deny?: string[];
2358
- };
2359
- /**
2360
- * Behavior when the Socket.dev feed flags a package as malicious
2361
- * (`alerts[].type === "Malware"`).
2362
- *
2363
- * The default is cross-field: `{ mode: "block" }` whenever
2364
- * `security.socket.enabled !== false` (the engine cannot evaluate
2365
- * malware without Socket data), and `"off"` otherwise. Consumers
2366
- * resolve this default at evaluation time.
2367
- */
2368
- malware?: {
2369
- /**
2370
- * - `"block"` — emit a block decision.
2371
- * - `"warn"` — surface as a warning; do not gate exit code.
2372
- * - `"off"` — disable the policy entirely.
2373
- */
2374
- mode?: "block" | "off" | "warn";
2375
- };
2376
- /**
2377
- * Trust-level checking for package publishing. Migrated from the
2378
- * legacy `security.trustPolicy*` fields. Equivalent to pnpm's
2379
- * `trustPolicy`.
2380
- * @example { mode: "no-downgrade", ignoreAfter: 43200 } // 30 days
2381
- */
2382
- publisherChange?: {
2383
- /**
2384
- * Package selectors excluded from the check.
2385
- * Equivalent to pnpm's `trustPolicyExclude`.
2386
- * @example ["chokidar@4.0.3"]
2387
- */
2388
- exclude?: string[];
2389
- /**
2390
- * Ignore packages published more than N minutes ago. Useful
2391
- * for older packages that pre-date provenance support.
2392
- * Equivalent to pnpm's `trustPolicyIgnoreAfter`.
2393
- */
2394
- ignoreAfter?: number;
2395
- /**
2396
- * - `"off"` — no trust checking (default).
2397
- * - `"no-downgrade"` — block when a package's trust level
2398
- * has decreased compared to previous releases (e.g., was
2399
- * published by trusted publisher, now only has provenance).
2400
- */
2401
- mode?: "no-downgrade" | "off";
2402
- };
2403
- /**
2404
- * Socket.dev overall-score threshold. Packages scoring below
2405
- * `minimum` trigger a block decision (or interactive prompt
2406
- * during `vis add`). Migrated from the legacy
2407
- * `security.socket.minimumScore` field.
2408
- * @example { minimum: 0.4 }
2409
- */
2410
- score?: {
2411
- /**
2412
- * Minimum overall Socket.dev score (0–1). Set to 0 to
2413
- * disable the gate while keeping Socket data fetched.
2414
- *
2415
- * Consulted by `vis add`, `audit`, `doctor`, `check`, and
2416
- * `update`; resolved once in `buildSocketOptions`, then
2417
- * threaded through every consumer. Falls back to
2418
- * `DEFAULT_LOW_SCORE_THRESHOLD` (`0.4`) when unset.
2419
- */
2420
- minimum?: number;
2421
- };
2422
- /**
2423
- * Net-new transitive dependency detection. Either provide a
2424
- * static allow-list, a baseline lockfile path (recommended), or
2425
- * both — the intersection is enforced.
2426
- * @example { baselineLockfile: "./security/lockfile.baseline.yaml" }
2427
- */
2428
- unexpectedDeps?: {
2429
- /**
2430
- * Allow-list of dependency names that may appear in the
2431
- * resolved package set. Glob patterns are supported.
2432
- * @example ["lodash", "axios", "@myorg/*"]
2433
- */
2434
- allow?: string[];
2435
- /**
2436
- * Path (absolute or relative to the workspace root) to a
2437
- * baseline lockfile snapshot. The policy diffs the current
2438
- * lockfile against this baseline and flags any package that
2439
- * didn't exist before.
2440
- * @example "./security/lockfile.baseline.yaml"
2441
- */
2442
- baselineLockfile?: string;
2443
- };
2444
- /**
2445
- * OSV vulnerability gating. Migrated from the legacy
2446
- * `security.audit.failOn` + `security.audit.usage` fields.
2447
- */
2448
- vulnerability?: {
2449
- /**
2450
- * Severity threshold that makes `vis audit` exit non-zero.
2451
- * Equivalent to the CLI `--fail-on` flag.
2452
- * @example "high"
2453
- */
2454
- failOn?: "critical" | "high" | "low" | "medium";
2455
- /**
2456
- * Reachability filter — only report vulnerabilities in
2457
- * packages the workspace statically imports.
2458
- */
2459
- usage?: {
2460
- /**
2461
- * Packages to always treat as reachable even if no
2462
- * static import is found.
2463
- * @example ["esbuild", "webpack-cli"]
2464
- */
2465
- alwaysAssumeUsed?: string[];
2466
- /**
2467
- * Enable the reachability filter by default. Equivalent
2468
- * to `--usage` on the CLI; `--no-usage` disables.
2469
- * @default false
2470
- */
2471
- enabled?: boolean;
2472
- };
2473
- };
2474
- };
2475
- /**
2476
- * Which provider wins merge conflicts when multiple are enabled (e.g.
2477
- * both Socket.dev and deps.dev return data for the same package). The
2478
- * primary provider's `score` is kept; alerts from secondaries are
2479
- * appended and deduped by `key`. Defaults to whichever provider is
2480
- * enabled first in this order: socket → deps-dev → snyk.
2481
- */
2482
- primaryProvider?: "deps-dev" | "snyk" | "socket";
2483
- /**
2484
- * Snyk data-source configuration. Snyk only contributes vulnerability
2485
- * data (no maintenance / quality / supply-chain / license signal);
2486
- * those axes stay neutral. Requires both an org id and an API token —
2487
- * if either is missing the provider is skipped.
2488
- * @see https://docs.snyk.io/snyk-api/using-specific-snyk-apis/issues-list-issues-for-a-package
2489
- */
2490
- snyk?: {
2491
- /**
2492
- * Snyk API token. Set via VIS_SNYK_TOKEN environment variable or
2493
- * here.
2494
- */
2495
- apiToken?: string;
2496
- /**
2497
- * Snyk REST API version date sent as the `version` query param.
2498
- * @default "2024-10-15"
2499
- */
2500
- apiVersion?: string;
2501
- /**
2502
- * Cache TTL in milliseconds for Snyk issue lookups. 6 hours.
2503
- * @default 21600000
2504
- */
2505
- cacheTtlMs?: number;
2506
- /**
2507
- * Enable Snyk security scanning on install/update/check/audit
2508
- * commands.
2509
- * @default false
2510
- */
2511
- enabled?: boolean;
2512
- /**
2513
- * Snyk organization id (the REST endpoint is org-scoped). Set via
2514
- * VIS_SNYK_ORG environment variable or here.
2515
- */
2516
- orgId?: string;
2517
- /**
2518
- * Request timeout in milliseconds for the Snyk API. 15 seconds.
2519
- * @default 15000
2520
- */
2521
- timeoutMs?: number;
2522
- };
2523
- /**
2524
- * Socket.dev data-source configuration. Connection knobs only — score
2525
- * thresholds and accepted-risk overrides moved to `policies.score` and
2526
- * `security.acceptedRisks` respectively.
2527
- * @see https://socket.dev
2528
- */
2529
- socket?: {
2530
- /**
2531
- * Custom Socket.dev API token. Falls back to the public API token.
2532
- * Set via VIS_SOCKET_TOKEN environment variable or here.
2533
- */
2534
- apiToken?: string;
2535
- /**
2536
- * Cache TTL in milliseconds for Socket.dev reports. 1 hour.
2537
- * @default 3600000
2538
- */
2539
- cacheTtlMs?: number;
2540
- /**
2541
- * Enable Socket.dev security scanning on install/update/check commands.
2542
- * @default false
2543
- */
2544
- enabled?: boolean;
2545
- /**
2546
- * Request timeout in milliseconds for the Socket.dev API. 15 seconds.
2547
- * @default 15000
2548
- */
2549
- timeoutMs?: number;
2550
- };
2551
- /**
2552
- * Package names to skip during typosquat detection.
2553
- * Use this for internal packages or known-safe names that happen to
2554
- * look similar to popular packages.
2555
- * @example ["my-internal-axois", "@myorg/recat"]
2556
- */
2557
- typosquatAllowlist?: string[];
2558
- };
2644
+ security?: Inline<VisSecurityConfig>;
2559
2645
  /**
2560
2646
  * Share the cache between sibling git worktrees. When the workspace is a
2561
2647
  * linked worktree (created with `git worktree add`), the cache root is
@@ -2688,83 +2774,7 @@ interface VisConfig {
2688
2774
  autoExit?: boolean | number;
2689
2775
  };
2690
2776
  /** Update command defaults */
2691
- update?: {
2692
- /**
2693
- * Dependency fields to scan for outdated packages.
2694
- * Beyond the standard fields, supports:
2695
- * - `"overrides"` (npm)
2696
- * - `"resolutions"` (yarn)
2697
- * - `"pnpm.overrides"`
2698
- * @default ["dependencies", "devDependencies", "optionalDependencies", "peerDependencies"]
2699
- */
2700
- depFields?: string[];
2701
- exclude?: string[];
2702
- format?: "json" | "minimal" | "table";
2703
- /**
2704
- * Package names or glob patterns to permanently ignore during updates.
2705
- * Ignored packages are skipped and listed in the output so you know
2706
- * they were not checked.
2707
- * @example ["eslint", "@types/*"]
2708
- */
2709
- ignore?: string[];
2710
- include?: string[];
2711
- /**
2712
- * Include packages with pinned/exact versions (no `^` or `~` prefix).
2713
- * By default, pinned versions are skipped during update checks.
2714
- * @default false
2715
- */
2716
- includeLocked?: boolean;
2717
- install?: boolean;
2718
- /**
2719
- * Maximum number of concurrent registry requests during outdated checks.
2720
- * Higher values speed up large workspaces but risk hitting registry rate
2721
- * limits or self-hosted Verdaccio caps.
2722
- * @default 8
2723
- */
2724
- maxConcurrentRequests?: number;
2725
- /**
2726
- * Minimum number of minutes since a version was published before
2727
- * vis will consider it for updates. This mirrors pnpm's
2728
- * `minimumReleaseAge` — a single setting that applies to both
2729
- * install and update.
2730
- *
2731
- * Not set by default. If your package manager config
2732
- * (`pnpm-workspace.yaml`) has `minimumReleaseAge`, vis will
2733
- * read it from there as a fallback.
2734
- * @example 1440 // 24 hours
2735
- */
2736
- minimumReleaseAge?: number;
2737
- /**
2738
- * Package names/patterns excluded from the minimumReleaseAge check.
2739
- * @example ["webpack", "@myorg/*"]
2740
- */
2741
- minimumReleaseAgeExclude?: string[];
2742
- /**
2743
- * Per-package or per-pattern update target overrides.
2744
- * Keys are exact package names, glob patterns, or regex patterns
2745
- * wrapped in `/` (e.g., `/^@vue/`).
2746
- * Values are `"latest"`, `"minor"`, or `"patch"`.
2747
- * @example { "typescript": "minor", "/^@vue/": "patch" }
2748
- */
2749
- packageMode?: Record<string, "latest" | "minor" | "patch">;
2750
- prerelease?: boolean;
2751
- /**
2752
- * Which release channels to consider when picking the target version.
2753
- * - `"stable"` (default) — only ship stable releases (no prereleases).
2754
- * - `"same"` — match the prerelease channel of the *current* range:
2755
- * if you're on `react@19.0.0-rc.1`, only `rc.*` candidates qualify;
2756
- * if you're on a stable, only stable candidates. Prevents
2757
- * accidentally promoting a prerelease pin to a stable major bump.
2758
- * - `"any"` — equivalent to `--prerelease`. Any channel is fair game.
2759
- *
2760
- * `--release-channel` on the CLI overrides this. If `prerelease: true`
2761
- * is set without `releaseChannel`, vis treats it as `"any"`.
2762
- * @default "stable"
2763
- */
2764
- releaseChannel?: "any" | "same" | "stable";
2765
- security?: boolean;
2766
- target?: "latest" | "minor" | "patch";
2767
- };
2777
+ update?: Inline<VisUpdateConfig>;
2768
2778
  /**
2769
2779
  * Minimum vis CLI version required by this workspace. When the
2770
2780
  * running vis binary is older than this constraint, vis exits with