@visulima/vis 2.0.0 → 2.0.2

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 (220) hide show
  1. package/CHANGELOG.md +41 -0
  2. package/LICENSE.md +862 -170
  3. package/README.md +1 -1
  4. package/dist/bin.js +1 -1
  5. package/dist/binx.js +2 -2
  6. package/dist/config/index.d.ts +1817 -1811
  7. package/dist/generate/index.d.ts +39 -39
  8. package/dist/packem_chunks/CONFIG_FILES.js +5 -5
  9. package/dist/packem_chunks/bloom-status.js +1 -1
  10. package/dist/packem_chunks/bloom-sync.js +1 -1
  11. package/dist/packem_chunks/cache-attestation.js +1 -1
  12. package/dist/packem_chunks/catalog.js +69 -67
  13. package/dist/packem_chunks/cli-exec.js +1 -1
  14. package/dist/packem_chunks/cli-main.js +150 -145
  15. package/dist/packem_chunks/detect.js +3 -3
  16. package/dist/packem_chunks/detect2.js +4 -4
  17. package/dist/packem_chunks/dispatch.js +3 -3
  18. package/dist/packem_chunks/doctor-probe.js +1 -1
  19. package/dist/packem_chunks/extra-files.js +3 -3
  20. package/dist/packem_chunks/fix.js +9 -9
  21. package/dist/packem_chunks/handler.js +1 -1
  22. package/dist/packem_chunks/handler10.js +5 -5
  23. package/dist/packem_chunks/handler11.js +1 -1
  24. package/dist/packem_chunks/handler12.js +6 -6
  25. package/dist/packem_chunks/handler13.js +1 -1
  26. package/dist/packem_chunks/handler14.js +1 -1
  27. package/dist/packem_chunks/handler15.js +1 -1
  28. package/dist/packem_chunks/handler16.js +1 -1
  29. package/dist/packem_chunks/handler17.js +1 -1
  30. package/dist/packem_chunks/handler18.js +1 -1
  31. package/dist/packem_chunks/handler19.js +1 -1
  32. package/dist/packem_chunks/handler2.js +1 -1
  33. package/dist/packem_chunks/handler20.js +2 -2
  34. package/dist/packem_chunks/handler21.js +2 -2
  35. package/dist/packem_chunks/handler22.js +10 -10
  36. package/dist/packem_chunks/handler23.js +1 -1
  37. package/dist/packem_chunks/handler24.js +1 -1
  38. package/dist/packem_chunks/handler25.js +1 -1
  39. package/dist/packem_chunks/handler26.js +5 -5
  40. package/dist/packem_chunks/handler27.js +1 -1
  41. package/dist/packem_chunks/handler28.js +3 -3
  42. package/dist/packem_chunks/handler29.js +1 -1
  43. package/dist/packem_chunks/handler3.js +2 -3
  44. package/dist/packem_chunks/handler30.js +1 -1
  45. package/dist/packem_chunks/handler31.js +2 -2
  46. package/dist/packem_chunks/handler35.js +3 -3
  47. package/dist/packem_chunks/handler4.js +4 -4
  48. package/dist/packem_chunks/handler40.js +10 -10
  49. package/dist/packem_chunks/handler42.js +3 -3
  50. package/dist/packem_chunks/handler43.js +3 -3
  51. package/dist/packem_chunks/handler5.js +5 -5
  52. package/dist/packem_chunks/handler50.js +5 -5
  53. package/dist/packem_chunks/handler51.js +13 -13
  54. package/dist/packem_chunks/handler52.js +3 -3
  55. package/dist/packem_chunks/handler53.js +1 -1
  56. package/dist/packem_chunks/handler54.js +2 -2
  57. package/dist/packem_chunks/handler55.js +1 -1
  58. package/dist/packem_chunks/handler57.js +5 -5
  59. package/dist/packem_chunks/handler58.js +4 -4
  60. package/dist/packem_chunks/handler59.js +8 -8
  61. package/dist/packem_chunks/handler6.js +7 -7
  62. package/dist/packem_chunks/handler60.js +2 -2
  63. package/dist/packem_chunks/handler61.js +13 -13
  64. package/dist/packem_chunks/handler62.js +4 -4
  65. package/dist/packem_chunks/handler63.js +3 -3
  66. package/dist/packem_chunks/handler64.js +4 -4
  67. package/dist/packem_chunks/handler65.js +6 -6
  68. package/dist/packem_chunks/handler66.js +2 -2
  69. package/dist/packem_chunks/handler67.js +9 -9
  70. package/dist/packem_chunks/handler68.js +7 -7
  71. package/dist/packem_chunks/handler69.js +24 -24
  72. package/dist/packem_chunks/handler7.js +1 -1
  73. package/dist/packem_chunks/handler70.js +6 -6
  74. package/dist/packem_chunks/handler71.js +14 -14
  75. package/dist/packem_chunks/handler72.js +47 -47
  76. package/dist/packem_chunks/handler73.js +9 -9
  77. package/dist/packem_chunks/handler74.js +27 -27
  78. package/dist/packem_chunks/handler75.js +3 -3
  79. package/dist/packem_chunks/handler76.js +8 -8
  80. package/dist/packem_chunks/handler77.js +63 -64
  81. package/dist/packem_chunks/handler78.js +25 -25
  82. package/dist/packem_chunks/handler8.js +1 -1
  83. package/dist/packem_chunks/handler9.js +1 -1
  84. package/dist/packem_chunks/heal-accept.js +5 -5
  85. package/dist/packem_chunks/heal.js +8 -8
  86. package/dist/packem_chunks/help-command.js +46 -46
  87. package/dist/packem_chunks/index2.js +5 -5
  88. package/dist/packem_chunks/index3.js +3 -3
  89. package/dist/packem_chunks/index4.js +11 -11
  90. package/dist/packem_chunks/keys-refresh.js +1 -1
  91. package/dist/packem_chunks/lean.js +2 -2
  92. package/dist/packem_chunks/list.js +2 -2
  93. package/dist/packem_chunks/loader.js +4 -4
  94. package/dist/packem_chunks/orchestrator.js +14 -14
  95. package/dist/packem_chunks/pre-mode.js +2 -2
  96. package/dist/packem_chunks/prompts.js +3 -3
  97. package/dist/packem_chunks/prune.js +1 -1
  98. package/dist/packem_chunks/publish-guards.js +1 -1
  99. package/dist/packem_chunks/registry.js +17 -17
  100. package/dist/packem_chunks/resolveFormatter.js +5 -5
  101. package/dist/packem_chunks/shell-runner.js +1 -1
  102. package/dist/packem_chunks/snapshot.js +2 -2
  103. package/dist/packem_chunks/stage-publisher.js +1 -1
  104. package/dist/packem_chunks/staged-registry.js +2 -2
  105. package/dist/packem_chunks/state.js +3 -3
  106. package/dist/packem_chunks/status.js +1 -1
  107. package/dist/packem_chunks/sync.js +1 -1
  108. package/dist/packem_chunks/sync2.js +1 -1
  109. package/dist/packem_chunks/tar.js +3 -3
  110. package/dist/packem_chunks/tripwire.js +2 -2
  111. package/dist/packem_chunks/ts-loader.js +9 -9
  112. package/dist/packem_chunks/verify-lockfile.js +2 -2
  113. package/dist/packem_chunks/workspace.js +2 -2
  114. package/dist/packem_shared/advisories-CCBGdU8U.js +1 -0
  115. package/dist/packem_shared/affected-selection-Dj-ymxhw.js +1 -0
  116. package/dist/packem_shared/affected-shas-PwkVbPch.js +1 -0
  117. package/dist/packem_shared/ai-analysis-bGCAc1jR.js +68 -0
  118. package/dist/packem_shared/{ai-fix-CLfWbyqY.js → ai-fix-DV5-dHBY.js} +9 -9
  119. package/dist/packem_shared/{augment-BVuj3ee7.js → augment-24KX2nkI.js} +4 -4
  120. package/dist/packem_shared/bin-CtzhnYMp.js +1 -0
  121. package/dist/packem_shared/build-scripts-w4SNeR7D.js +1 -0
  122. package/dist/packem_shared/{command-runtime-DTbo12cP.js → command-runtime-BLFPUYAT.js} +1 -1
  123. package/dist/packem_shared/cyclonedx-C4KaVTn1.js +4 -0
  124. package/dist/packem_shared/{dependency-scan-DZcSlSFp.js → dependency-scan-D_ona0Qm.js} +1 -1
  125. package/dist/packem_shared/{docker-69ybb6g7.js → docker-DaVs-9wK.js} +40 -40
  126. package/dist/packem_shared/{en-C26W78--.js → en-D3CfXlO7.js} +13 -13
  127. package/dist/packem_shared/failure-log-CTneNcio.js +2 -0
  128. package/dist/packem_shared/giget-CAxjpwew.js +2 -0
  129. package/dist/packem_shared/glob-BUjyjdE8-C4M8e02u.js +1 -0
  130. package/dist/packem_shared/index-BWl4DbMp.js +1 -0
  131. package/dist/packem_shared/index-CTMU29dI.js +1 -0
  132. package/dist/packem_shared/index-uBVnF4ji.js +35 -0
  133. package/dist/packem_shared/index.server-CusjRLCh.js +2 -0
  134. package/dist/packem_shared/{interface.d-B7VK2rcH.d.ts → interface.d-CRqRz4jt.d.ts} +39 -39
  135. package/dist/packem_shared/{interface.d-Cezzifoh.d.ts → interface.d-CrHOtJc1.d.ts} +37 -37
  136. package/dist/packem_shared/lifecycle-B8A2T3gx.js +2 -0
  137. package/dist/packem_shared/lockfile-Bccery3L.js +1 -0
  138. package/dist/packem_shared/main-D_cam4hv.js +1 -0
  139. package/dist/packem_shared/manifests-BDkwiVbh.js +1 -0
  140. package/dist/packem_shared/{min-release-age-hK604veF.js → min-release-age-OaYpLwux.js} +2 -2
  141. package/dist/packem_shared/missing-package-json-BqS-OnKd.js +1 -0
  142. package/dist/packem_shared/{native-config-sync-DDKjAy0i.js → native-config-sync-Ds1FtcrM.js} +7 -7
  143. package/dist/packem_shared/osv-bloom-pKp7urSB.js +2 -0
  144. package/dist/packem_shared/package-version-C47v64aB.js +4 -0
  145. package/dist/packem_shared/packument-HBVbyf7x.js +1 -0
  146. package/dist/packem_shared/pm-runner-C6eTANt1.js +1 -0
  147. package/dist/packem_shared/project-name-filter-CJ3XX2TI.js +7 -0
  148. package/dist/packem_shared/prompt-BSAy8SMH.js +1 -0
  149. package/dist/packem_shared/{provenance-CRBV9cko.js → provenance-D4Cza8cp.js} +1 -1
  150. package/dist/packem_shared/{readJsonSync-DuMMeB3s-B9cGBVbJ.js → readJsonSync-DweZd5ZA-0eZh9sGm.js} +1 -1
  151. package/dist/packem_shared/registry-keys-C0ez2VND.js +1 -0
  152. package/dist/packem_shared/{resolve-explicit-BX6aMYl-.js → resolve-explicit-BbT764KS.js} +1 -1
  153. package/dist/packem_shared/{resolve-runtime-COyiEML3.js → resolve-runtime-D_vZovbB.js} +1 -1
  154. package/dist/packem_shared/run-file-DyPFFN9U.js +1 -0
  155. package/dist/packem_shared/{runtime-check-fzDkedMW.js → runtime-check-D4um-yQq.js} +1 -1
  156. package/dist/packem_shared/s1ngularity-St6dhKiq.js +1 -0
  157. package/dist/packem_shared/scan-progress-q-N2JtIp.js +2 -0
  158. package/dist/packem_shared/selectors-Ce_6UAoY.js +3 -0
  159. package/dist/packem_shared/signatures-Dyeyg1q9.js +2 -0
  160. package/dist/packem_shared/subtree-DSm0QEoE.js +2 -0
  161. package/dist/packem_shared/target-merge-Cfy7c__2.js +11 -0
  162. package/dist/packem_shared/target-options-7XcbqGDe.js +1 -0
  163. package/dist/packem_shared/toolchain-C_pNMBM6.js +5 -0
  164. package/dist/packem_shared/typosquats-xzcAGPiM.js +1 -0
  165. package/dist/packem_shared/{use-measured-height-DfNxp6nf.js → use-measured-height-CBjN0fle.js} +1 -1
  166. package/dist/packem_shared/verify-Dve9PQj3.js +1 -0
  167. package/dist/packem_shared/{vis-update-app-De8JjZm0.js → vis-update-app-DMAC2pPf.js} +1 -1
  168. package/dist/packem_shared/vis-user-error-xmha3L4n.js +30 -0
  169. package/dist/packem_shared/watch-BXOOX7lx.js +1 -0
  170. package/dist/packem_shared/watch-loop-Q7UpkVbr.js +11 -0
  171. package/dist/release/core/package-managers/index.d.ts +2 -2
  172. package/dist/release/core/version-actions/index.d.ts +10 -10
  173. package/dist/release/index.d.ts +60 -60
  174. package/dist/release/plugin-sdk.d.ts +80 -80
  175. package/dist/release/presets.d.ts +148 -148
  176. package/dist/release/types.d.ts +840 -840
  177. package/dist/runtime/preload.js +1 -1
  178. package/index.d.ts +204 -204
  179. package/index.js +52 -52
  180. package/package.json +16 -16
  181. package/schemas/project.schema.json +4 -1
  182. package/schemas/vis-config.schema.json +9 -3
  183. package/dist/packem_shared/advisories-B76fBVL-.js +0 -1
  184. package/dist/packem_shared/affected-shas-BOeR4vEc.js +0 -1
  185. package/dist/packem_shared/ai-analysis-D7HOdUwd.js +0 -68
  186. package/dist/packem_shared/bin-CkfFJCAM.js +0 -1
  187. package/dist/packem_shared/build-scripts-CfAqHBlq.js +0 -1
  188. package/dist/packem_shared/cyclonedx--L7NbMBH.js +0 -4
  189. package/dist/packem_shared/failure-log-BZQqxffZ.js +0 -2
  190. package/dist/packem_shared/giget-DVTFJlbR.js +0 -2
  191. package/dist/packem_shared/glob-DMbPwGSj-D2Hk3lFG.js +0 -1
  192. package/dist/packem_shared/index-2LCHaVNX.js +0 -35
  193. package/dist/packem_shared/index-B0EsgdzO.js +0 -1
  194. package/dist/packem_shared/index-Bhzio2RB.js +0 -1
  195. package/dist/packem_shared/index-Bq6YEpiq.js +0 -28
  196. package/dist/packem_shared/index.server-qvZ-cy29.js +0 -2
  197. package/dist/packem_shared/lifecycle-BcCMt9wn.js +0 -2
  198. package/dist/packem_shared/lockfile-Cwt0Nwr0.js +0 -1
  199. package/dist/packem_shared/main-B3juSU5z.js +0 -1
  200. package/dist/packem_shared/manifests-BshBdSb-.js +0 -1
  201. package/dist/packem_shared/missing-package-json-Cu0iWMT2.js +0 -1
  202. package/dist/packem_shared/osv-bloom-DMhXP184.js +0 -2
  203. package/dist/packem_shared/package-version-TsxLc6w2.js +0 -4
  204. package/dist/packem_shared/packument-CtVAoNo7.js +0 -1
  205. package/dist/packem_shared/pm-runner-CfyxALPK.js +0 -1
  206. package/dist/packem_shared/prompt-DjXHVgYU.js +0 -1
  207. package/dist/packem_shared/registry-keys-Ci2keQNi.js +0 -1
  208. package/dist/packem_shared/run-file-CTJfIZ0I.js +0 -1
  209. package/dist/packem_shared/s1ngularity-Cq1cCSpU.js +0 -1
  210. package/dist/packem_shared/scan-progress-DQ9qIGzr.js +0 -2
  211. package/dist/packem_shared/selectors-B9dOMIMq.js +0 -3
  212. package/dist/packem_shared/signatures-DvD1E8Xa.js +0 -2
  213. package/dist/packem_shared/subtree-C7bZuiSQ.js +0 -2
  214. package/dist/packem_shared/target-merge-Dg25Izl5.js +0 -11
  215. package/dist/packem_shared/target-options-aPqByoww.js +0 -1
  216. package/dist/packem_shared/toolchain-CiaW3bx4.js +0 -5
  217. package/dist/packem_shared/typosquats-CRnvlYPw.js +0 -1
  218. package/dist/packem_shared/verify-23b6IfSg.js +0 -1
  219. package/dist/packem_shared/watch-B3P2dwoG.js +0 -1
  220. package/dist/packem_shared/watch-loop-B3_O8hF-.js +0 -11
@@ -2,14 +2,14 @@ import { TargetConfiguration, TaskResult, Task, FingerprintContributor, Constrai
2
2
  export type { FingerprintContributor } from '@visulima/task-runner';
3
3
  import { VisReleaseConfig } from "../release/types.js";
4
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
- */
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
13
  interface SimilarDepFamily {
14
14
  /** Stable id; used in report output and config overrides. */
15
15
  id: string;
@@ -25,28 +25,28 @@ type FmtAdapterId = "biome" | "deno-fmt" | "dprint" | "oxfmt" | "prettier" | "ru
25
25
  /** Adapter IDs that can lint (adapter `kind` is `"lint"` or `"both"`). */
26
26
  type LintAdapterId = "biome" | "deno-lint" | "eslint" | "markdownlint" | "oxlint" | "ruff-check" | "shellcheck" | "stylelint";
27
27
  /**
28
- * Runtime adapter contract for the cross-runtime multi-tool (see
29
- * `rfc/design-runtime-multitool.md`). Phase 0 defines the identity +
30
- * detection metadata; Phase 1 extends adapters with the spawn-building
31
- * methods (`runFile` / `runScript` / `install` / `exec`) that route through
32
- * `pm-runner`. Deno is a planned third adapter — deliberately not a
33
- * `RuntimeId` yet (it carries permission + no-`node_modules` semantics that
34
- * the first cut omits).
35
- */
28
+ * Runtime adapter contract for the cross-runtime multi-tool (see
29
+ * `rfc/design-runtime-multitool.md`). Phase 0 defines the identity +
30
+ * detection metadata; Phase 1 extends adapters with the spawn-building
31
+ * methods (`runFile` / `runScript` / `install` / `exec`) that route through
32
+ * `pm-runner`. Deno is a planned third adapter — deliberately not a
33
+ * `RuntimeId` yet (it carries permission + no-`node_modules` semantics that
34
+ * the first cut omits).
35
+ */
36
36
  /** JS runtimes vis can target today. `"deno"` is deferred. */
37
37
  type RuntimeId = "bun" | "node";
38
38
  type VersionManagerName = "asdf" | "corepack" | "fnm" | "mise" | "none" | "nvm" | "proto" | "self-activate" | "volta";
39
39
  type RuntimeTool = "aube" | "bun" | "deno" | "go" | "node" | "npm" | "pnpm" | "python" | "ruby" | "rust" | "yarn";
40
40
  interface ToolchainConfig {
41
41
  /**
42
- * When a tool pin doesn't match the running version, try to fix it
43
- * automatically before `vis run` / `vis ci` proceed. Defaults to
44
- * `true` when {@link findInstalledManagers} reports at least one
45
- * installed manager, `false` otherwise.
46
- *
47
- * Set to `false` to keep the doctor-style warning behaviour and
48
- * make users run `vis toolchain install` themselves.
49
- */
42
+ * When a tool pin doesn't match the running version, try to fix it
43
+ * automatically before `vis run` / `vis ci` proceed. Defaults to
44
+ * `true` when {@link findInstalledManagers} reports at least one
45
+ * installed manager, `false` otherwise.
46
+ *
47
+ * Set to `false` to keep the doctor-style warning behaviour and
48
+ * make users run `vis toolchain install` themselves.
49
+ */
50
50
  readonly autoInstall?: boolean;
51
51
  /** Explicit manager override, useful in CI. */
52
52
  readonly preferredManager?: VersionManagerName;
@@ -54,90 +54,90 @@ interface ToolchainConfig {
54
54
  readonly tools?: Partial<Record<RuntimeTool, string>>;
55
55
  }
56
56
  /**
57
- * Custom task form — `{ title, task }` — analogous to lint-staged's
58
- * listr-style task objects. `task` receives the matched absolute paths
59
- * and returns a promise that resolves on success or rejects on failure.
60
- */
57
+ * Custom task form — `{ title, task }` — analogous to lint-staged's
58
+ * listr-style task objects. `task` receives the matched absolute paths
59
+ * and returns a promise that resolves on success or rejects on failure.
60
+ */
61
61
  interface CustomTask {
62
62
  readonly task: (files: string[]) => unknown;
63
63
  readonly title: string;
64
64
  }
65
65
  /**
66
- * Object form of a command task. Unlike a bare command string it carries
67
- * execution options:
68
- *
69
- * - `perPackage` runs the command once per workspace package that owns the
70
- * matched files, with `cwd` set to that package's directory and file paths
71
- * made relative to it. Use it for tools that resolve their config or
72
- * plugins from the nearest `package.json` — e.g. eslint with a
73
- * cwd-sensitive shareable config. Files that sit under no workspace
74
- * package fall back to a single run from the workspace root.
75
- * - `cwd` pins the command to a fixed directory (relative to the workspace
76
- * root, or absolute) and passes the matched files as absolute paths so
77
- * they resolve regardless of where the command runs. Ignored when
78
- * `perPackage` is set — that derives the cwd per package instead.
79
- *
80
- * A command task is distinguished from {@link CustomTask} by carrying a
81
- * `command` string and no `task` function.
82
- */
66
+ * Object form of a command task. Unlike a bare command string it carries
67
+ * execution options:
68
+ *
69
+ * - `perPackage` runs the command once per workspace package that owns the
70
+ * matched files, with `cwd` set to that package's directory and file paths
71
+ * made relative to it. Use it for tools that resolve their config or
72
+ * plugins from the nearest `package.json` — e.g. eslint with a
73
+ * cwd-sensitive shareable config. Files that sit under no workspace
74
+ * package fall back to a single run from the workspace root.
75
+ * - `cwd` pins the command to a fixed directory (relative to the workspace
76
+ * root, or absolute) and passes the matched files as absolute paths so
77
+ * they resolve regardless of where the command runs. Ignored when
78
+ * `perPackage` is set — that derives the cwd per package instead.
79
+ *
80
+ * A command task is distinguished from {@link CustomTask} by carrying a
81
+ * `command` string and no `task` function.
82
+ */
83
83
  interface CommandTask {
84
84
  readonly command: string;
85
85
  readonly cwd?: string;
86
86
  readonly perPackage?: boolean;
87
87
  }
88
88
  /**
89
- * A task value as authored by the user. Command strings are split into
90
- * argv and invoked with the matched file paths appended. `{ command, … }`
91
- * objects do the same with per-task execution options (cwd / perPackage).
92
- * Arrays run serially. Functions receive the matched paths and return
93
- * further task values (possibly async). `{ title, task }` objects run
94
- * `task` directly with no argv construction.
95
- */
89
+ * A task value as authored by the user. Command strings are split into
90
+ * argv and invoked with the matched file paths appended. `{ command, … }`
91
+ * objects do the same with per-task execution options (cwd / perPackage).
92
+ * Arrays run serially. Functions receive the matched paths and return
93
+ * further task values (possibly async). `{ title, task }` objects run
94
+ * `task` directly with no argv construction.
95
+ */
96
96
  type StagedTask = CommandTask | CustomTask | StagedTaskFunction | string | ReadonlyArray<CommandTask | CustomTask | StagedTaskFunction | string>;
97
97
  type StagedTaskFunction = (files: string[]) => Promise<StagedTaskResult> | StagedTaskResult;
98
98
  type StagedTaskResult = CommandTask | CustomTask | string | ReadonlyArray<CommandTask | CustomTask | string>;
99
99
  /**
100
- * Config object mapping glob patterns (basename or path-style) to tasks.
101
- * A top-level function form lets the user generate the entire config
102
- * from the staged file list.
103
- */
100
+ * Config object mapping glob patterns (basename or path-style) to tasks.
101
+ * A top-level function form lets the user generate the entire config
102
+ * from the staged file list.
103
+ */
104
104
  type StagedConfig = Readonly<Record<string, StagedTask>> | StagedConfigFunction;
105
105
  type StagedConfigFunction = (files: string[]) => Promise<Record<string, StagedTask>> | Record<string, StagedTask>;
106
106
  /**
107
- * Configuration block declared on a target to mark it as a long-lived
108
- * "service" — eligible to be started/stopped via `vis service` and
109
- * auto-attached when other tasks depend on it.
110
- *
111
- * Targets must also carry `preset: "server"` (or the equivalent
112
- * `persistent: true`) for the service-mode lifecycle to apply.
113
- */
107
+ * Configuration block declared on a target to mark it as a long-lived
108
+ * "service" — eligible to be started/stopped via `vis service` and
109
+ * auto-attached when other tasks depend on it.
110
+ *
111
+ * Targets must also carry `preset: "server"` (or the equivalent
112
+ * `persistent: true`) for the service-mode lifecycle to apply.
113
+ */
114
114
  interface ServiceConfig {
115
115
  /**
116
- * Env vars to expose to dependent tasks when this service is
117
- * registered. Merged into the dependent task's env after the task's
118
- * own envFile and before the task's explicit `env` overrides — the
119
- * dependent task wins on key collisions.
120
- *
121
- * Note: only this `env` map propagates to dependents. The service
122
- * target's own `envFile` is loaded into the **service process** at
123
- * start time but is *not* forwarded — dependents must declare any
124
- * shared values they need either here or in their own envFile. This
125
- * boundary is intentional: envFiles often contain operator-only
126
- * secrets (deploy keys, admin tokens) that should not leak into
127
- * downstream test commands.
128
- */
116
+ * Env vars to expose to dependent tasks when this service is
117
+ * registered. Merged into the dependent task's env after the task's
118
+ * own envFile and before the task's explicit `env` overrides — the
119
+ * dependent task wins on key collisions.
120
+ *
121
+ * Note: only this `env` map propagates to dependents. The service
122
+ * target's own `envFile` is loaded into the **service process** at
123
+ * start time but is *not* forwarded — dependents must declare any
124
+ * shared values they need either here or in their own envFile. This
125
+ * boundary is intentional: envFiles often contain operator-only
126
+ * secrets (deploy keys, admin tokens) that should not leak into
127
+ * downstream test commands.
128
+ */
129
129
  env?: Record<string, string>;
130
130
  /**
131
- * Grace period in milliseconds between SIGTERM and SIGKILL when the
132
- * service is stopped.
133
- * @default 5000
134
- */
131
+ * Grace period in milliseconds between SIGTERM and SIGKILL when the
132
+ * service is stopped.
133
+ * @default 5000
134
+ */
135
135
  killGracePeriodMs?: number;
136
136
  /**
137
- * Optional port the service listens on. Used as the default for
138
- * `readiness.tcp.port` when no explicit probe is configured, and
139
- * surfaced by `vis service list`.
140
- */
137
+ * Optional port the service listens on. Used as the default for
138
+ * `readiness.tcp.port` when no explicit probe is configured, and
139
+ * surfaced by `vis service list`.
140
+ */
141
141
  port?: number;
142
142
  /** Readiness probe configuration. v1 supports TCP only. */
143
143
  readiness?: {
@@ -149,9 +149,9 @@ interface ServiceConfig {
149
149
  };
150
150
  }
151
151
  /**
152
- * Persisted registry entry. One JSON file per running service in
153
- * `~/.vis-services/&lt;workspaceHash>/&lt;slug>.json`.
154
- */
152
+ * Persisted registry entry. One JSON file per running service in
153
+ * `~/.vis-services/&lt;workspaceHash>/&lt;slug>.json`.
154
+ */
155
155
  interface ServiceEntry {
156
156
  /** Resolved command actually spawned. Used for stale-PID detection. */
157
157
  command: string;
@@ -159,10 +159,10 @@ interface ServiceEntry {
159
159
  config: ServiceConfig;
160
160
  cwd: string;
161
161
  /**
162
- * Env vars to forward to dependents. Resolved at start time —
163
- * defaults to `config.env`, but a future `--env-from` flag could
164
- * extend this without touching the registry consumer.
165
- */
162
+ * Env vars to forward to dependents. Resolved at start time —
163
+ * defaults to `config.env`, but a future `--env-from` flag could
164
+ * extend this without touching the registry consumer.
165
+ */
166
166
  env: Record<string, string>;
167
167
  /** Target id, e.g. `apps/api:db`. */
168
168
  id: string;
@@ -170,28 +170,28 @@ interface ServiceEntry {
170
170
  logFile: string;
171
171
  pid: number;
172
172
  /**
173
- * Filesystem-safe slug of `id`. `apps/api:db` → `apps_api__db`.
174
- * Used as the entry's filename so registry reads can map slug → entry.
175
- */
173
+ * Filesystem-safe slug of `id`. `apps/api:db` → `apps_api__db`.
174
+ * Used as the entry's filename so registry reads can map slug → entry.
175
+ */
176
176
  slug: string;
177
177
  /** ISO 8601 timestamp of when the service was started. */
178
178
  startedAt: string;
179
179
  /**
180
- * vis version that started this service. Auto-attach refuses entries
181
- * from a mismatched version — protects against schema drift.
182
- */
180
+ * vis version that started this service. Auto-attach refuses entries
181
+ * from a mismatched version — protects against schema drift.
182
+ */
183
183
  visVersion: string;
184
184
  }
185
185
  /**
186
- * First-class task arguments: a declarative schema per target that lets a
187
- * task define its named/positional arguments, validate what the user passes
188
- * on the CLI, and render a per-task `--help`. The validated values are also
189
- * exposed to the command as `VIS_ARG_&lt;NAME>` environment variables so the
190
- * underlying script can read them without re-parsing argv.
191
- *
192
- * This module is intentionally pure (no IO) so it is trivially unit-testable;
193
- * the run handler wires it to the forwarded-args vector and the task env.
194
- */
186
+ * First-class task arguments: a declarative schema per target that lets a
187
+ * task define its named/positional arguments, validate what the user passes
188
+ * on the CLI, and render a per-task `--help`. The validated values are also
189
+ * exposed to the command as `VIS_ARG_&lt;NAME>` environment variables so the
190
+ * underlying script can read them without re-parsing argv.
191
+ *
192
+ * This module is intentionally pure (no IO) so it is trivially unit-testable;
193
+ * the run handler wires it to the forwarded-args vector and the task env.
194
+ */
195
195
  /** Value type a {@link TaskArgument} coerces to and validates against. */
196
196
  type TaskArgumentType = "boolean" | "enum" | "number" | "string";
197
197
  /** A coerced task-argument value. */
@@ -199,31 +199,31 @@ type TaskArgumentValue = boolean | number | string;
199
199
  /** A single declared argument for a task target. */
200
200
  interface TaskArgument {
201
201
  /**
202
- * Short single-character alias (e.g. `r` for `--reporter`, used as `-r`).
203
- * Must be exactly one character — enforced at run time by
204
- * {@link validateArgumentSchema}.
205
- */
202
+ * Short single-character alias (e.g. `r` for `--reporter`, used as `-r`).
203
+ * Must be exactly one character — enforced at run time by
204
+ * {@link validateArgumentSchema}.
205
+ */
206
206
  alias?: string;
207
207
  /**
208
- * Allowed values when {@link TaskArgument.type} is `"enum"`. Must be
209
- * non-empty (and is required) for `enum` — enforced at run time by
210
- * {@link validateArgumentSchema}.
211
- */
208
+ * Allowed values when {@link TaskArgument.type} is `"enum"`. Must be
209
+ * non-empty (and is required) for `enum` — enforced at run time by
210
+ * {@link validateArgumentSchema}.
211
+ */
212
212
  choices?: string[];
213
213
  /** Value applied when the argument is omitted. Skips the required check. */
214
214
  default?: TaskArgumentValue;
215
215
  /** One-line help text surfaced by per-task `--help`. */
216
216
  description?: string;
217
217
  /**
218
- * Canonical name, without the leading `--` (kebab-case by convention).
219
- * Must start with a letter and contain only letters, digits, `-`, `_` —
220
- * enforced at run time by {@link validateArgumentSchema}.
221
- */
218
+ * Canonical name, without the leading `--` (kebab-case by convention).
219
+ * Must start with a letter and contain only letters, digits, `-`, `_` —
220
+ * enforced at run time by {@link validateArgumentSchema}.
221
+ */
222
222
  name: string;
223
223
  /**
224
- * Consume the value from the next free positional argument instead of a
225
- * `--flag`. Positional args are filled in declaration order.
226
- */
224
+ * Consume the value from the next free positional argument instead of a
225
+ * `--flag`. Positional args are filled in declaration order.
226
+ */
227
227
  positional?: boolean;
228
228
  /** Fail the task when the argument is absent and has no `default`. */
229
229
  required?: boolean;
@@ -231,269 +231,269 @@ interface TaskArgument {
231
231
  type?: TaskArgumentType;
232
232
  }
233
233
  /**
234
- * Semantic classification for a target.
235
- * - `build`: Generates one or more artifacts; cached by default.
236
- * - `test`: Validation task (lint, typecheck, unit test). Default type.
237
- * - `run`: One-off or long-running process. Not cached by default.
238
- */
234
+ * Semantic classification for a target.
235
+ * - `build`: Generates one or more artifacts; cached by default.
236
+ * - `test`: Validation task (lint, typecheck, unit test). Default type.
237
+ * - `run`: One-off or long-running process. Not cached by default.
238
+ */
239
239
  type TargetType = "build" | "run" | "test";
240
240
  /**
241
- * Preset bundles of target options.
242
- * - `server`: Long-running local dev server — caching off, not in CI,
243
- * interactive, persistent.
244
- * - `utility`: Short-lived helper — caching off, not in CI.
245
- */
241
+ * Preset bundles of target options.
242
+ * - `server`: Long-running local dev server — caching off, not in CI,
243
+ * interactive, persistent.
244
+ * - `utility`: Short-lived helper — caching off, not in CI.
245
+ */
246
246
  type TargetPreset = "server" | "utility";
247
247
  /**
248
- * Controls whether a target runs in CI.
249
- * - `true` (default): Always run.
250
- * - `false`: Never run in CI (local-only).
251
- * - `"affected"`: Only when the project is affected by the current change set.
252
- * - `"always"`: Always run, even if unaffected.
253
- */
248
+ * Controls whether a target runs in CI.
249
+ * - `true` (default): Always run.
250
+ * - `false`: Never run in CI (local-only).
251
+ * - `"affected"`: Only when the project is affected by the current change set.
252
+ * - `"always"`: Always run, even if unaffected.
253
+ */
254
254
  type RunInCI = "affected" | "always" | boolean;
255
255
  /**
256
- * Controls how affected files are forwarded to a task.
257
- * - `false` (default): Do not forward.
258
- * - `"args"`: Append affected paths as additional command arguments.
259
- * - `"env"`: Expose them via `VIS_AFFECTED_FILES` environment variable.
260
- * - `"both"`: Both of the above.
261
- */
256
+ * Controls how affected files are forwarded to a task.
257
+ * - `false` (default): Do not forward.
258
+ * - `"args"`: Append affected paths as additional command arguments.
259
+ * - `"env"`: Expose them via `VIS_AFFECTED_FILES` environment variable.
260
+ * - `"both"`: Both of the above.
261
+ */
262
262
  type AffectedFilesMode = "args" | "both" | "env" | false;
263
263
  /**
264
- * Vis-specific target options that extend the task-runner's
265
- * base `TargetConfiguration`. These live under `target.options` and are
266
- * interpreted by vis before handing the task off to task-runner.
267
- *
268
- * Conditional execution (`when:`) and finally tasks (`always:`) live at
269
- * the target top level, not under `options` — they're handled by the
270
- * task-runner orchestrator. See `@visulima/task-runner`'s `WhenCondition`.
271
- */
264
+ * Vis-specific target options that extend the task-runner's
265
+ * base `TargetConfiguration`. These live under `target.options` and are
266
+ * interpreted by vis before handing the task off to task-runner.
267
+ *
268
+ * Conditional execution (`when:`) and finally tasks (`always:`) live at
269
+ * the target top level, not under `options` — they're handled by the
270
+ * task-runner orchestrator. See `@visulima/task-runner`'s `WhenCondition`.
271
+ */
272
272
  interface VisTargetOptions {
273
273
  /**
274
- * How to forward affected files to the task process.
275
- * Only used when invoked via `vis affected &lt;target>`.
276
- * @default false
277
- */
274
+ * How to forward affected files to the task process.
275
+ * Only used when invoked via `vis affected &lt;target>`.
276
+ * @default false
277
+ */
278
278
  affectedFiles?: AffectedFilesMode;
279
279
  /**
280
- * Load environment variables from dotenv file(s) before running.
281
- * - `string`: a single file path (relative to project root).
282
- * - `string[]`: multiple files — later entries override earlier ones,
283
- * so put more-specific files last (e.g. `[".env", ".env.local"]`).
284
- * - `true`: auto-cascade in the Next/Vite order:
285
- * `.env` → `.env.{NODE_ENV}` → `.env.local` → `.env.{NODE_ENV}.local`.
286
- * Skips `.env.local` when NODE_ENV is `test`, matching Next.js.
287
- */
280
+ * Load environment variables from dotenv file(s) before running.
281
+ * - `string`: a single file path (relative to project root).
282
+ * - `string[]`: multiple files — later entries override earlier ones,
283
+ * so put more-specific files last (e.g. `[".env", ".env.local"]`).
284
+ * - `true`: auto-cascade in the Next/Vite order:
285
+ * `.env` → `.env.{NODE_ENV}` → `.env.local` → `.env.{NODE_ENV}.local`.
286
+ * Skips `.env.local` when NODE_ENV is `test`, matching Next.js.
287
+ */
288
288
  envFile?: boolean | string | string[];
289
289
  /**
290
- * When true, the task is serialized with respect to parallel execution
291
- * and must be run on the main process (claims stdin). Used for commands
292
- * that read from the terminal.
293
- * @default false
294
- */
290
+ * When true, the task is serialized with respect to parallel execution
291
+ * and must be run on the main process (claims stdin). Used for commands
292
+ * that read from the terminal.
293
+ * @default false
294
+ */
295
295
  interactive?: boolean;
296
296
  /**
297
- * When true, the task is hidden from CLI listings and can only be invoked
298
- * as a dependency of another task.
299
- * @default false
300
- */
297
+ * When true, the task is hidden from CLI listings and can only be invoked
298
+ * as a dependency of another task.
299
+ * @default false
300
+ */
301
301
  internal?: boolean;
302
302
  /**
303
- * Milliseconds the timeout watchdog waits between sending SIGTERM
304
- * and SIGKILL when the `timeout` budget fires. Tasks that ignore
305
- * SIGTERM (e.g. test runners holding open child processes) get
306
- * force-killed after this grace window so a stuck task can't outlive
307
- * its budget.
308
- *
309
- * Set to `0` to skip escalation and rely on SIGTERM only.
310
- * @default 5000
311
- */
303
+ * Milliseconds the timeout watchdog waits between sending SIGTERM
304
+ * and SIGKILL when the `timeout` budget fires. Tasks that ignore
305
+ * SIGTERM (e.g. test runners holding open child processes) get
306
+ * force-killed after this grace window so a stuck task can't outlive
307
+ * its budget.
308
+ *
309
+ * Set to `0` to skip escalation and rely on SIGTERM only.
310
+ * @default 5000
311
+ */
312
312
  killGracePeriodMs?: number;
313
313
  /**
314
- * Serializes all tasks that share the same mutex name. Useful for tasks
315
- * that contend on a shared resource (e.g., a database migration).
316
- */
314
+ * Serializes all tasks that share the same mutex name. Useful for tasks
315
+ * that contend on a shared resource (e.g., a database migration).
316
+ */
317
317
  mutex?: string;
318
318
  /**
319
- * Per-target output verbosity. Overrides the global `--output-style`
320
- * flag for this specific target.
321
- *
322
- * - `"normal"` (default): print every task's terminal output
323
- * - `"quiet"`: only print output when the task fails. Successful
324
- * and cached tasks contribute their status line and timing, but
325
- * their captured stdout/stderr is suppressed.
326
- *
327
- * Useful when a routinely-noisy task (a linter or test runner with
328
- * verbose progress output) should stay quiet during green builds
329
- * but reveal everything when it fails.
330
- */
319
+ * Per-target output verbosity. Overrides the global `--output-style`
320
+ * flag for this specific target.
321
+ *
322
+ * - `"normal"` (default): print every task's terminal output
323
+ * - `"quiet"`: only print output when the task fails. Successful
324
+ * and cached tasks contribute their status line and timing, but
325
+ * their captured stdout/stderr is suppressed.
326
+ *
327
+ * Useful when a routinely-noisy task (a linter or test runner with
328
+ * verbose progress output) should stay quiet during green builds
329
+ * but reveal everything when it fails.
330
+ */
331
331
  outputStyle?: "normal" | "quiet";
332
332
  /**
333
- * When true, the task is a long-running / never-ending process.
334
- * Persistent tasks are scheduled last, execute after all cacheable
335
- * tasks complete, and are never cached.
336
- * @default false
337
- */
333
+ * When true, the task is a long-running / never-ending process.
334
+ * Persistent tasks are scheduled last, execute after all cacheable
335
+ * tasks complete, and are never cached.
336
+ * @default false
337
+ */
338
338
  persistent?: boolean;
339
339
  /**
340
- * A preset that pre-fills a common bundle of options.
341
- * User-provided fields always take precedence over the preset.
342
- */
340
+ * A preset that pre-fills a common bundle of options.
341
+ * User-provided fields always take precedence over the preset.
342
+ */
343
343
  preset?: TargetPreset;
344
344
  /**
345
- * Run the task through a pseudo-terminal so color-aware tools
346
- * (vitest, eslint, biome, …) render as if attached to a real TTY
347
- * instead of a pipe. Output is captured via task-runner's
348
- * `TerminalBuffer` so ANSI escapes are normalized into the final
349
- * rendered state before reaching the reporter.
350
- *
351
- * Forces cache to off — PTY output can include timing-dependent
352
- * frames (spinners) that aren't safe to replay from a cache.
353
- * @default false
354
- */
345
+ * Run the task through a pseudo-terminal so color-aware tools
346
+ * (vitest, eslint, biome, …) render as if attached to a real TTY
347
+ * instead of a pipe. Output is captured via task-runner's
348
+ * `TerminalBuffer` so ANSI escapes are normalized into the final
349
+ * rendered state before reaching the reporter.
350
+ *
351
+ * Forces cache to off — PTY output can include timing-dependent
352
+ * frames (spinners) that aren't safe to replay from a cache.
353
+ * @default false
354
+ */
355
355
  pty?: boolean;
356
356
  /**
357
- * Number of times to retry the task on failure. Uses an exponential
358
- * backoff by default (1s, 2s, 4s, ...).
359
- * @default 0
360
- */
357
+ * Number of times to retry the task on failure. Uses an exponential
358
+ * backoff by default (1s, 2s, 4s, ...).
359
+ * @default 0
360
+ */
361
361
  retryCount?: number;
362
362
  /**
363
- * Delay between retry attempts in milliseconds, or `"exponential"`
364
- * for 2^attempt * 1000 ms.
365
- * @default "exponential"
366
- */
363
+ * Delay between retry attempts in milliseconds, or `"exponential"`
364
+ * for 2^attempt * 1000 ms.
365
+ * @default "exponential"
366
+ */
367
367
  retryDelay?: number | "exponential";
368
368
  /**
369
- * When true, the command executes with the workspace root as CWD
370
- * instead of the project root.
371
- * @default false
372
- */
369
+ * When true, the command executes with the workspace root as CWD
370
+ * instead of the project root.
371
+ * @default false
372
+ */
373
373
  runFromWorkspaceRoot?: boolean;
374
374
  /**
375
- * Controls whether the task runs in CI environments.
376
- * @default true
377
- */
375
+ * Controls whether the task runs in CI environments.
376
+ * @default true
377
+ */
378
378
  runInCI?: RunInCI;
379
379
  /**
380
- * Capability tags that gate this task to runners advertising the
381
- * same tag. The CLI's `--runner-tags=gpu,slow` flag (or
382
- * `VIS_RUNNER_TAGS` env var) tells vis what the current runner
383
- * supports; tasks whose `runnerTags` share at least one tag with
384
- * the runner set are eligible. Untagged tasks (no `runnerTags` or
385
- * an empty array) are general-purpose and always run.
386
- *
387
- * Use this for special-purpose CI lanes — e.g. a GPU runner that
388
- * should only pick up visual-regression suites, or a nightly job
389
- * that runs `slow` integration tests. When neither flag nor env
390
- * is set, the filter is inactive and every task runs.
391
- */
380
+ * Capability tags that gate this task to runners advertising the
381
+ * same tag. The CLI's `--runner-tags=gpu,slow` flag (or
382
+ * `VIS_RUNNER_TAGS` env var) tells vis what the current runner
383
+ * supports; tasks whose `runnerTags` share at least one tag with
384
+ * the runner set are eligible. Untagged tasks (no `runnerTags` or
385
+ * an empty array) are general-purpose and always run.
386
+ *
387
+ * Use this for special-purpose CI lanes — e.g. a GPU runner that
388
+ * should only pick up visual-regression suites, or a nightly job
389
+ * that runs `slow` integration tests. When neither flag nor env
390
+ * is set, the filter is inactive and every task runs.
391
+ */
392
392
  runnerTags?: string[];
393
393
  /**
394
- * Marks this target as a long-lived service that can be started via
395
- * `vis service start &lt;id>` and auto-attached when other tasks declare
396
- * it in `dependsOn`. Implies persistent + non-cacheable behaviour
397
- * (set `preset: "server"` to inherit the rest of the bundle).
398
- *
399
- * The presence of this block — not `preset: "server"` alone — is
400
- * what makes a target eligible for the cross-invocation registry.
401
- * `preset: "server"` without `service` keeps today's in-run-only
402
- * behaviour.
403
- */
394
+ * Marks this target as a long-lived service that can be started via
395
+ * `vis service start &lt;id>` and auto-attached when other tasks declare
396
+ * it in `dependsOn`. Implies persistent + non-cacheable behaviour
397
+ * (set `preset: "server"` to inherit the rest of the bundle).
398
+ *
399
+ * The presence of this block — not `preset: "server"` alone — is
400
+ * what makes a target eligible for the cross-invocation registry.
401
+ * `preset: "server"` without `service` keeps today's in-run-only
402
+ * behaviour.
403
+ */
404
404
  service?: ServiceConfig;
405
405
  /**
406
- * Per-target shell override. When set, the command runs through this
407
- * shell instead of the platform default.
408
- */
406
+ * Per-target shell override. When set, the command runs through this
407
+ * shell instead of the platform default.
408
+ */
409
409
  shell?: string;
410
410
  /**
411
- * Arguments passed to the per-target shell/interpreter before the command
412
- * string. Defaults to `["-c"]` (POSIX shells, pwsh). Set this to run the
413
- * command under an interpreter that uses a different flag — e.g.
414
- * `shell: "node", shellArgs: ["-e"]` runs the command as inline JS
415
- * ("script mode"), or `shellArgs: ["-lc"]` for a login shell. Only applies
416
- * when `shell`/`unixShell`/`windowsShell` resolves to a custom shell.
417
- *
418
- * Must be non-empty when set — an empty array would drop the interpreter
419
- * flag entirely, so the runtime falls back to `-c` defensively.
420
- */
411
+ * Arguments passed to the per-target shell/interpreter before the command
412
+ * string. Defaults to `["-c"]` (POSIX shells, pwsh). Set this to run the
413
+ * command under an interpreter that uses a different flag — e.g.
414
+ * `shell: "node", shellArgs: ["-e"]` runs the command as inline JS
415
+ * ("script mode"), or `shellArgs: ["-lc"]` for a login shell. Only applies
416
+ * when `shell`/`unixShell`/`windowsShell` resolves to a custom shell.
417
+ *
418
+ * Must be non-empty when set — an empty array would drop the interpreter
419
+ * flag entirely, so the runtime falls back to `-c` defensively.
420
+ */
421
421
  shellArgs?: string[];
422
422
  /**
423
- * Override the workspace `strictEnv` setting for this target. When
424
- * truthy, the target fails if its command references an env var
425
- * that resolves to neither the task's effective env nor
426
- * `process.env`. When `false`, the target opts out of a workspace
427
- * `strictEnv: true` (e.g. for a one-off command that legitimately
428
- * tolerates an unset variable).
429
- * @see VisConfig.strictEnv
430
- */
423
+ * Override the workspace `strictEnv` setting for this target. When
424
+ * truthy, the target fails if its command references an env var
425
+ * that resolves to neither the task's effective env nor
426
+ * `process.env`. When `false`, the target opts out of a workspace
427
+ * `strictEnv: true` (e.g. for a one-off command that legitimately
428
+ * tolerates an unset variable).
429
+ * @see VisConfig.strictEnv
430
+ */
431
431
  strictEnv?: boolean;
432
432
  /**
433
- * Maximum wall-clock milliseconds a single task run is allowed to
434
- * take before being killed. `0` / `undefined` means no timeout.
435
- *
436
- * When the timeout fires the task is sent SIGTERM and, if it has
437
- * not exited within `killGracePeriodMs`, SIGKILL. The task exits
438
- * with a failure status carrying the `[timeout]` marker in
439
- * `terminalOutput`. Retries count per-attempt, not cumulatively.
440
- *
441
- * Use this to prevent runaway tasks from eating CI wall-clock time
442
- * up to the job-level cutoff.
443
- */
433
+ * Maximum wall-clock milliseconds a single task run is allowed to
434
+ * take before being killed. `0` / `undefined` means no timeout.
435
+ *
436
+ * When the timeout fires the task is sent SIGTERM and, if it has
437
+ * not exited within `killGracePeriodMs`, SIGKILL. The task exits
438
+ * with a failure status carrying the `[timeout]` marker in
439
+ * `terminalOutput`. Retries count per-attempt, not cumulatively.
440
+ *
441
+ * Use this to prevent runaway tasks from eating CI wall-clock time
442
+ * up to the job-level cutoff.
443
+ */
444
444
  timeout?: number;
445
445
  /**
446
- * Per-target unix shell override, used on Linux and macOS.
447
- * Takes precedence over `shell` on unix-like systems.
448
- */
446
+ * Per-target unix shell override, used on Linux and macOS.
447
+ * Takes precedence over `shell` on unix-like systems.
448
+ */
449
449
  unixShell?: string;
450
450
  /**
451
- * Per-target windows shell override, used on Windows.
452
- * Takes precedence over `shell` on Windows.
453
- */
451
+ * Per-target windows shell override, used on Windows.
452
+ * Takes precedence over `shell` on Windows.
453
+ */
454
454
  windowsShell?: string;
455
455
  }
456
456
  /**
457
- * An extended target configuration that adds the vis-specific options
458
- * on top of task-runner's `TargetConfiguration`.
459
- */
457
+ * An extended target configuration that adds the vis-specific options
458
+ * on top of task-runner's `TargetConfiguration`.
459
+ */
460
460
  interface VisTargetConfiguration extends Omit<TargetConfiguration, "options"> {
461
461
  /**
462
- * Alternate names that resolve to this target on the CLI. Useful
463
- * for shortening long canonical names (`test` ↔ `t`) or for
464
- * offering migration-friendly aliases when renaming targets.
465
- * Aliases must be globally unique within the workspace.
466
- */
462
+ * Alternate names that resolve to this target on the CLI. Useful
463
+ * for shortening long canonical names (`test` ↔ `t`) or for
464
+ * offering migration-friendly aliases when renaming targets.
465
+ * Aliases must be globally unique within the workspace.
466
+ */
467
467
  aliases?: string[];
468
468
  /**
469
- * Declarative argument schema for this target. Forwarded CLI args
470
- * (`vis run &lt;target> -- --flag value`) are validated against it, surfaced
471
- * by per-task `--help`, and exposed to the command as `VIS_ARG_&lt;NAME>`
472
- * environment variables.
473
- */
469
+ * Declarative argument schema for this target. Forwarded CLI args
470
+ * (`vis run &lt;target> -- --flag value`) are validated against it, surfaced
471
+ * by per-task `--help`, and exposed to the command as `VIS_ARG_&lt;NAME>`
472
+ * environment variables.
473
+ */
474
474
  arguments?: TaskArgument[];
475
475
  /**
476
- * One-line description surfaced by `vis list` and per-task `--help`.
477
- * Kept short — longer docs belong in project READMEs or
478
- * vis.config.ts comments.
479
- */
476
+ * One-line description surfaced by `vis list` and per-task `--help`.
477
+ * Kept short — longer docs belong in project READMEs or
478
+ * vis.config.ts comments.
479
+ */
480
480
  description?: string;
481
481
  /**
482
- * True when the target was synthesized by a Project Crystal-style
483
- * detector (see {@link ../inference}) rather than declared by a
484
- * package.json script, project.json, or vis.task.ts file. Surfaced
485
- * by `vis list --inferred` and used by tooling to distinguish
486
- * implicit defaults from explicit user intent.
487
- */
482
+ * True when the target was synthesized by a Project Crystal-style
483
+ * detector (see {@link ../inference}) rather than declared by a
484
+ * package.json script, project.json, or vis.task.ts file. Surfaced
485
+ * by `vis list --inferred` and used by tooling to distinguish
486
+ * implicit defaults from explicit user intent.
487
+ */
488
488
  inferred?: boolean;
489
489
  /** Vis-specific target options. */
490
490
  options?: VisTargetOptions;
491
491
  /** Preset applied before user-specified options. */
492
492
  preset?: TargetPreset;
493
493
  /**
494
- * Semantic task type. Affects caching defaults and CI filtering.
495
- * @default "test"
496
- */
494
+ * Semantic task type. Affects caching defaults and CI filtering.
495
+ * @default "test"
496
+ */
497
497
  type?: TargetType;
498
498
  }
499
499
  type HookCallback = (...arguments_: any) => Promise<void> | void;
@@ -504,20 +504,20 @@ type DeprecatedHook<T> = {
504
504
  };
505
505
  type ValueOf<C> = C extends Record<any, any> ? C[keyof C] : never;
506
506
  type Strings<T> = Exclude<keyof T, number | symbol>;
507
- type KnownKeys<T> = keyof { [K in keyof T as string extends K ? never : number extends K ? never : K]: never };
507
+ type KnownKeys<T> = keyof { [K in keyof T as string extends K ? never : number extends K ? never : K]: never; };
508
508
  type StripGeneric<T> = Pick<T, KnownKeys<T> extends keyof T ? KnownKeys<T> : never>;
509
509
  type OnlyGeneric<T> = Omit<T, KnownKeys<T> extends keyof T ? KnownKeys<T> : never>;
510
- type Namespaces<T> = ValueOf<{ [key in Strings<T>]: key extends `${infer Namespace}:${string}` ? Namespace : never }>;
511
- type BareHooks<T> = ValueOf<{ [key in Strings<T>]: key extends `${string}:${string}` ? never : key }>;
512
- type HooksInNamespace<T, Namespace extends string> = ValueOf<{ [key in Strings<T>]: key extends `${Namespace}:${infer HookName}` ? HookName : never }>;
513
- type WithoutNamespace<T, Namespace extends string> = { [key in HooksInNamespace<T, Namespace>]: `${Namespace}:${key}` extends keyof T ? T[`${Namespace}:${key}`] : never };
514
- type NestedHooks<T> = (Partial<StripGeneric<T>> | Partial<OnlyGeneric<T>>) & Partial<{ [key in Namespaces<StripGeneric<T>>]: NestedHooks<WithoutNamespace<T, key>> }> & Partial<{ [key in BareHooks<StripGeneric<T>>]: T[key] }>;
510
+ type Namespaces<T> = ValueOf<{ [key in Strings<T>]: key extends `${infer Namespace}:${string}` ? Namespace : never; }>;
511
+ type BareHooks<T> = ValueOf<{ [key in Strings<T>]: key extends `${string}:${string}` ? never : key; }>;
512
+ type HooksInNamespace<T, Namespace extends string> = ValueOf<{ [key in Strings<T>]: key extends `${Namespace}:${infer HookName}` ? HookName : never; }>;
513
+ type WithoutNamespace<T, Namespace extends string> = { [key in HooksInNamespace<T, Namespace>]: `${Namespace}:${key}` extends keyof T ? T[`${Namespace}:${key}`] : never; };
514
+ type NestedHooks<T> = (Partial<StripGeneric<T>> | Partial<OnlyGeneric<T>>) & Partial<{ [key in Namespaces<StripGeneric<T>>]: NestedHooks<WithoutNamespace<T, key>>; }> & Partial<{ [key in BareHooks<StripGeneric<T>>]: T[key]; }>;
515
515
  type InferCallback<HT, HN extends keyof HT> = HT[HN] extends HookCallback ? HT[HN] : never;
516
516
  type InferSpyEvent<HT extends Record<string, any>> = { [key in keyof HT]: {
517
517
  name: key;
518
518
  args: Parameters<HT[key]>;
519
519
  context: Record<string, any>;
520
- } }[keyof HT];
520
+ }; }[keyof HT];
521
521
  declare class Hookable<HooksT extends Record<string, any> = Record<string, HookCallback>, HookNameT extends HookKeys<HooksT> = HookKeys<HooksT>> {
522
522
  private _hooks;
523
523
  private _before?;
@@ -550,172 +550,171 @@ declare global {
550
550
  createTask?: CreateTask;
551
551
  }
552
552
  }
553
- /** @deprecated */
554
553
  /**
555
- * Typed hook surface exposed to vis plugins.
556
- *
557
- * Plugins subscribe via `hooks.hook(name, handler)` — handlers are
558
- * awaited sequentially in registration order. Returning a promise
559
- * delays the next hook firing until it resolves, so plugins can
560
- * safely perform async setup/teardown.
561
- *
562
- * Naming deliberately mirrors vite-task / webpack-style verbs:
563
- * before/after for boundaries, on&lt;Event> for passive observation.
564
- */
554
+ * Typed hook surface exposed to vis plugins.
555
+ *
556
+ * Plugins subscribe via `hooks.hook(name, handler)` — handlers are
557
+ * awaited sequentially in registration order. Returning a promise
558
+ * delays the next hook firing until it resolves, so plugins can
559
+ * safely perform async setup/teardown.
560
+ *
561
+ * Naming deliberately mirrors vite-task / webpack-style verbs:
562
+ * before/after for boundaries, on&lt;Event> for passive observation.
563
+ */
565
564
  interface VisHooks {
566
565
  /**
567
- * Fired after the entire task graph completes (including any
568
- * failures). `results` maps task ID → {@link TaskResult}.
569
- */
566
+ * Fired after the entire task graph completes (including any
567
+ * failures). `results` maps task ID → {@link TaskResult}.
568
+ */
570
569
  "run:after": (results: Map<string, TaskResult>) => Promise<void> | void;
571
570
  /**
572
- * Fired once before any task in the graph starts, after workspace
573
- * discovery and graph construction. Throwing aborts the run.
574
- */
571
+ * Fired once before any task in the graph starts, after workspace
572
+ * discovery and graph construction. Throwing aborts the run.
573
+ */
575
574
  "run:before": (context: {
576
575
  tasks: Task[];
577
576
  workspaceRoot: string;
578
577
  }) => Promise<void> | void;
579
578
  /**
580
- * Fired after `vis run` auto-attaches to one or more registered
581
- * services. `taskIds` lists the in-graph dependents that consumed
582
- * the service's `env` block; an empty array means the service was
583
- * registered but no kept task depended on it.
584
- */
579
+ * Fired after `vis run` auto-attaches to one or more registered
580
+ * services. `taskIds` lists the in-graph dependents that consumed
581
+ * the service's `env` block; an empty array means the service was
582
+ * registered but no kept task depended on it.
583
+ */
585
584
  "service:attach": (entry: ServiceEntry, taskIds: ReadonlyArray<string>) => Promise<void> | void;
586
585
  /**
587
- * Fired after a service is registered and its readiness probe
588
- * succeeds. Sourced from both `vis service start` (and `restart`'s
589
- * post-start phase) and any future programmatic call sites.
590
- */
586
+ * Fired after a service is registered and its readiness probe
587
+ * succeeds. Sourced from both `vis service start` (and `restart`'s
588
+ * post-start phase) and any future programmatic call sites.
589
+ */
591
590
  "service:start": (entry: ServiceEntry) => Promise<void> | void;
592
591
  /**
593
- * Fired after a registered service is stopped (SIGTERM/SIGKILL
594
- * acknowledged, registry entry deleted). Not fired when stop is
595
- * called against an unknown id — only when there was an alive
596
- * entry to terminate.
597
- */
592
+ * Fired after a registered service is stopped (SIGTERM/SIGKILL
593
+ * acknowledged, registry entry deleted). Not fired when stop is
594
+ * called against an unknown id — only when there was an alive
595
+ * entry to terminate.
596
+ */
598
597
  "service:stop": (entry: ServiceEntry) => Promise<void> | void;
599
598
  /**
600
- * Fired after a task completes (success, failure, or cache hit).
601
- * Receives the final {@link TaskResult}.
602
- */
599
+ * Fired after a task completes (success, failure, or cache hit).
600
+ * Receives the final {@link TaskResult}.
601
+ */
603
602
  "task:after": (task: Task, result: TaskResult) => Promise<void> | void;
604
603
  /**
605
- * Fired before each task begins execution — after scheduling, before
606
- * the executor runs the command. Throwing aborts that single task.
607
- */
604
+ * Fired before each task begins execution — after scheduling, before
605
+ * the executor runs the command. Throwing aborts that single task.
606
+ */
608
607
  "task:before": (task: Task) => Promise<void> | void;
609
608
  /** Fired when a task hit the local or remote cache. */
610
609
  "task:cacheHit": (task: Task, result: TaskResult) => Promise<void> | void;
611
610
  /**
612
- * Fired when auto-fingerprint cache diagnostics reports a miss,
613
- * carrying the human-readable reason string.
614
- */
611
+ * Fired when auto-fingerprint cache diagnostics reports a miss,
612
+ * carrying the human-readable reason string.
613
+ */
615
614
  "task:cacheMiss": (task: Task, reasons: string) => Promise<void> | void;
616
615
  /** Fired when a task exits non-zero. */
617
616
  "task:failure": (task: Task, result: TaskResult) => Promise<void> | void;
618
617
  /**
619
- * Fired during fingerprint construction, after built-in inputs are
620
- * gathered and before the hash is sealed. Plugins call
621
- * `contributor.contribute(key, value)` to mix arbitrary strings
622
- * into the task hash — the hasher namespaces and sorts contributions
623
- * deterministically so call order doesn't change the result.
624
- *
625
- * Throwing aborts hashing for the offending task and surfaces as a
626
- * task failure before any cache lookup runs. Use this to guarantee
627
- * a buggy plugin can't quietly poison cache state.
628
- */
618
+ * Fired during fingerprint construction, after built-in inputs are
619
+ * gathered and before the hash is sealed. Plugins call
620
+ * `contributor.contribute(key, value)` to mix arbitrary strings
621
+ * into the task hash — the hasher namespaces and sorts contributions
622
+ * deterministically so call order doesn't change the result.
623
+ *
624
+ * Throwing aborts hashing for the offending task and surfaces as a
625
+ * task failure before any cache lookup runs. Use this to guarantee
626
+ * a buggy plugin can't quietly poison cache state.
627
+ */
629
628
  "task:fingerprint": (task: Task, contributor: FingerprintContributor) => Promise<void> | void;
630
629
  /**
631
- * Fired right before a failed task is re-spawned by the retry
632
- * controller. `attempt` is 1-indexed and counts the retry that's
633
- * about to start (so the original failed run was attempt 0).
634
- * `prevExitCode` is the failing exit status that triggered the
635
- * retry (the full TaskResult isn't materialized at the retry
636
- * boundary — only the per-attempt close event is available).
637
- *
638
- * Throwing aborts the retry; the previous failure becomes the final
639
- * result.
640
- */
630
+ * Fired right before a failed task is re-spawned by the retry
631
+ * controller. `attempt` is 1-indexed and counts the retry that's
632
+ * about to start (so the original failed run was attempt 0).
633
+ * `prevExitCode` is the failing exit status that triggered the
634
+ * retry (the full TaskResult isn't materialized at the retry
635
+ * boundary — only the per-attempt close event is available).
636
+ *
637
+ * Throwing aborts the retry; the previous failure becomes the final
638
+ * result.
639
+ */
641
640
  "task:retry": (task: Task, attempt: number, prevExitCode: number) => Promise<void> | void;
642
641
  /**
643
- * Fired with a stderr chunk as a running task emits it. Plugins
644
- * that ship logs live (Slack, Datadog) should prefer this over
645
- * `task:after` so they don't wait for the full buffer.
646
- */
642
+ * Fired with a stderr chunk as a running task emits it. Plugins
643
+ * that ship logs live (Slack, Datadog) should prefer this over
644
+ * `task:after` so they don't wait for the full buffer.
645
+ */
647
646
  "task:stderr": (task: Task, chunk: string) => Promise<void> | void;
648
647
  /**
649
- * Fired with a stdout chunk as a running task emits it. See
650
- * `task:stderr` for semantics.
651
- */
648
+ * Fired with a stdout chunk as a running task emits it. See
649
+ * `task:stderr` for semantics.
650
+ */
652
651
  "task:stdout": (task: Task, chunk: string) => Promise<void> | void;
653
652
  }
654
653
  /**
655
- * Public plugin contract. Implementations register handlers by
656
- * returning a partial {@link VisHooks} map from `hooks`, or by
657
- * mutating the Hookable instance directly via `setup(hooks)` for
658
- * advanced cases (dynamic registration, removeHook, etc.).
659
- *
660
- * Plugins are loaded in the order they appear in `visConfig.plugins`.
661
- * Handler execution order within a hook follows registration order,
662
- * so earlier plugins see events first.
663
- */
654
+ * Public plugin contract. Implementations register handlers by
655
+ * returning a partial {@link VisHooks} map from `hooks`, or by
656
+ * mutating the Hookable instance directly via `setup(hooks)` for
657
+ * advanced cases (dynamic registration, removeHook, etc.).
658
+ *
659
+ * Plugins are loaded in the order they appear in `visConfig.plugins`.
660
+ * Handler execution order within a hook follows registration order,
661
+ * so earlier plugins see events first.
662
+ */
664
663
  interface VisPlugin {
665
664
  /**
666
- * Declarative handlers — the common shape. One entry per hook
667
- * name; pass a function or an array of functions (all run serially
668
- * in order).
669
- */
670
- hooks?: Partial<{ [K in keyof VisHooks]: VisHooks[K] | VisHooks[K][] }>;
665
+ * Declarative handlers — the common shape. One entry per hook
666
+ * name; pass a function or an array of functions (all run serially
667
+ * in order).
668
+ */
669
+ hooks?: Partial<{ [K in keyof VisHooks]: VisHooks[K] | VisHooks[K][]; }>;
671
670
  /** Plugin name — surfaced in debug logs. */
672
671
  name: string;
673
672
  /**
674
- * Imperative setup — receives the shared Hookable instance so the
675
- * plugin can register hooks conditionally, unregister later, or
676
- * use advanced APIs like `hookOnce`/`beforeEach`/`afterEach`.
677
- */
673
+ * Imperative setup — receives the shared Hookable instance so the
674
+ * plugin can register hooks conditionally, unregister later, or
675
+ * use advanced APIs like `hookOnce`/`beforeEach`/`afterEach`.
676
+ */
678
677
  setup?: (hooks: Hookable<VisHooks>) => Promise<void> | void;
679
678
  }
680
679
  /**
681
- * Per-adapter override applied by `vis lint` / `vis fmt`. Keyed by
682
- * adapter id under `lint.adapters` / `fmt.adapters`. Every field is
683
- * optional — set only what you need to change.
684
- */
680
+ * Per-adapter override applied by `vis lint` / `vis fmt`. Keyed by
681
+ * adapter id under `lint.adapters` / `fmt.adapters`. Every field is
682
+ * optional — set only what you need to change.
683
+ */
685
684
  interface LintFmtAdapterOverride {
686
685
  /**
687
- * Set to `false` to skip this adapter even when its config file or
688
- * package.json entry is detected. Defaults to `true` (run when
689
- * detected).
690
- */
686
+ * Set to `false` to skip this adapter even when its config file or
687
+ * package.json entry is detected. Defaults to `true` (run when
688
+ * detected).
689
+ */
691
690
  enabled?: boolean;
692
691
  /**
693
- * Extra arguments appended verbatim to every invocation of this
694
- * adapter. Useful for tool-specific flags vis doesn't expose
695
- * directly (e.g. `eslint --rulesdir`).
696
- */
692
+ * Extra arguments appended verbatim to every invocation of this
693
+ * adapter. Useful for tool-specific flags vis doesn't expose
694
+ * directly (e.g. `eslint --rulesdir`).
695
+ */
697
696
  extraArgs?: string[];
698
697
  }
699
698
  /**
700
- * The 8 Socket.dev-style supply-chain policies. Used in `security.policies`
701
- * and `security.acceptedRisks[*].policies`. Kept as a const tuple so callers
702
- * can import the runtime array (`POLICY_NAMES`) for iteration without
703
- * drifting from the union type.
704
- */
699
+ * The 8 Socket.dev-style supply-chain policies. Used in `security.policies`
700
+ * and `security.acceptedRisks[*].policies`. Kept as a const tuple so callers
701
+ * can import the runtime array (`POLICY_NAMES`) for iteration without
702
+ * drifting from the union type.
703
+ */
705
704
  declare const POLICY_NAMES: readonly ["firstSeen", "installScripts", "license", "malware", "publisherChange", "score", "unexpectedDeps", "vulnerability"];
706
705
  type PolicyName = (typeof POLICY_NAMES)[number];
707
706
  /**
708
- * Recognised input sources for the codeowners aggregator.
709
- *
710
- * - `project-json` — owners declared on each project's `project.json`.
711
- * Canonical source; takes precedence over the other two on path conflicts.
712
- * - `nested-codeowners` — `CODEOWNERS` files placed at arbitrary depth
713
- * in the workspace tree (excluding the generated root file).
714
- * - `package-json-maintainers` — fallback that reads each project's
715
- * `package.json#maintainers` and emits one entry per project root for
716
- * projects with no `project.json owners`. GitHub handles are extracted
717
- * from each maintainer's `url` (e.g. `https://github.com/&lt;handle&gt;`).
718
- */
707
+ * Recognised input sources for the codeowners aggregator.
708
+ *
709
+ * - `project-json` — owners declared on each project's `project.json`.
710
+ * Canonical source; takes precedence over the other two on path conflicts.
711
+ * - `nested-codeowners` — `CODEOWNERS` files placed at arbitrary depth
712
+ * in the workspace tree (excluding the generated root file).
713
+ * - `package-json-maintainers` — fallback that reads each project's
714
+ * `package.json#maintainers` and emits one entry per project root for
715
+ * projects with no `project.json owners`. GitHub handles are extracted
716
+ * from each maintainer's `url` (e.g. `https://github.com/&lt;handle&gt;`).
717
+ */
719
718
  type CodeownersSource = "nested-codeowners" | "package-json-maintainers" | "project-json";
720
719
  interface CodeownersConfig {
721
720
  /** Markers that bracket the generated block when `preserveBlock` is set. */
@@ -730,52 +729,52 @@ interface CodeownersConfig {
730
729
  /** Sort order for generated entries — mirrors moon's `orderBy`. */
731
730
  orderBy?: "file-source" | "project-id";
732
731
  /**
733
- * When set, the generated content is spliced between
734
- * {@link CodeownersConfig.blockMarker} markers in the existing file
735
- * (markers are appended if missing) instead of overwriting the file.
736
- */
732
+ * When set, the generated content is spliced between
733
+ * {@link CodeownersConfig.blockMarker} markers in the existing file
734
+ * (markers are appended if missing) instead of overwriting the file.
735
+ */
737
736
  preserveBlock?: boolean;
738
737
  /** Provider determines whether `channel` is emitted (GitHub supports it via comment). */
739
738
  provider?: "bitbucket" | "github" | "gitlab" | "other";
740
739
  /**
741
- * Header instruction shown to reviewers. Replaces the default
742
- * "Update each project's project.json `owners` field…" line. Useful
743
- * when the canonical regenerate path is a custom script.
744
- */
740
+ * Header instruction shown to reviewers. Replaces the default
741
+ * "Update each project's project.json `owners` field…" line. Useful
742
+ * when the canonical regenerate path is a custom script.
743
+ */
745
744
  regenerationCommand?: string;
746
745
  /** Enabled input sources. Defaults to `["project-json"]`. */
747
746
  sources?: CodeownersSource[];
748
747
  }
749
748
  /**
750
- * One user-declared customTypes entry. See `policy.customTypes.extraTypes`
751
- * for the full contract — this is just the row shape.
752
- */
749
+ * One user-declared customTypes entry. See `policy.customTypes.extraTypes`
750
+ * for the full contract — this is just the row shape.
751
+ */
753
752
  interface ExtraCustomType {
754
753
  /**
755
- * Required when `strategy === "string"`. The dep-cluster key the bare
756
- * version string at `path` should be associated with.
757
- */
754
+ * Required when `strategy === "string"`. The dep-cluster key the bare
755
+ * version string at `path` should be associated with.
756
+ */
758
757
  depName?: string;
759
758
  /**
760
- * Display name for this customType. Used as the cluster key prefix in
761
- * lint output and JSON. Must not collide with the built-in names.
762
- */
759
+ * Display name for this customType. Used as the cluster key prefix in
760
+ * lint output and JSON. Must not collide with the built-in names.
761
+ */
763
762
  name: string;
764
763
  /** Dot-separated walk into package.json (e.g. `pnpm.overrides`, `myTool.runtime`). */
765
764
  path: string;
766
765
  /**
767
- * How to interpret the JSON found at `path`.
768
- * - `name@version` — single string `pnpm@9.0.0` (with optional `+sha512.…` hash).
769
- * - `name~version` — single string `node~20.0.0`, mirrors syncpack's tilde form.
770
- * - `string` — bare version literal (requires `depName`).
771
- * - `versionsByName` — `{ name: version }` object such as `engines`.
772
- */
766
+ * How to interpret the JSON found at `path`.
767
+ * - `name@version` — single string `pnpm@9.0.0` (with optional `+sha512.…` hash).
768
+ * - `name~version` — single string `node~20.0.0`, mirrors syncpack's tilde form.
769
+ * - `string` — bare version literal (requires `depName`).
770
+ * - `versionsByName` — `{ name: version }` object such as `engines`.
771
+ */
773
772
  strategy: "name@version" | "name~version" | "string" | "versionsByName";
774
773
  }
775
774
  /**
776
- * Declared code-owner assignment for a path glob within a project.
777
- * Mirrors moon's `owners` shape so migrations can round-trip cleanly.
778
- */
775
+ * Declared code-owner assignment for a path glob within a project.
776
+ * Mirrors moon's `owners` shape so migrations can round-trip cleanly.
777
+ */
779
778
  interface OwnersEntry {
780
779
  /** Optional notification channel (e.g. Slack, Teams). */
781
780
  channel?: string;
@@ -785,38 +784,47 @@ interface OwnersEntry {
785
784
  path: string;
786
785
  }
787
786
  /**
788
- * Per-project TypeScript overlay loaded from `vis.task.ts`. Adds a
789
- * dynamic, type-safe layer for target overrides on top of `project.json`,
790
- * which stays the canonical home for static metadata (`tags`, `layer`,
791
- * `stack`, `language`, `owners`, `projectType`, `sourceRoot`,
792
- * `implicitDependencies`).
793
- *
794
- * `vis.task.ts` is opt-in. A package without one behaves identically to
795
- * before its introduction. Targets defined here merge over `project.json`'s
796
- * `targets` block — see `design-config-layering.md` for the full
797
- * precedence stack.
798
- */
787
+ * Per-project TypeScript overlay loaded from `vis.task.ts`. Adds a
788
+ * dynamic, type-safe layer for target overrides on top of `project.json`,
789
+ * which stays the canonical home for static metadata (`tags`, `layer`,
790
+ * `stack`, `language`, `owners`, `projectType`, `sourceRoot`,
791
+ * `implicitDependencies`).
792
+ *
793
+ * `vis.task.ts` is opt-in. A package without one behaves identically to
794
+ * before its introduction. Targets defined here merge over `project.json`'s
795
+ * `targets` block — see `design-config-layering.md` for the full
796
+ * precedence stack.
797
+ */
799
798
  interface VisTaskConfig {
800
799
  /** Per-target overrides — same shape as `project.json#targets`. */
801
800
  tasks?: Record<string, VisTargetConfiguration>;
802
801
  }
803
802
  /**
804
- * Per-project metadata surfaced by `project.json`. Extended beyond the
805
- * minimal `projectType` / `tags` / `sourceRoot` fields we historically
806
- * parsed to include targets, owners, and layer/stack classification.
807
- */
803
+ * Per-project metadata surfaced by `project.json`. Extended beyond the
804
+ * minimal `projectType` / `tags` / `sourceRoot` fields we historically
805
+ * parsed to include targets, owners, and layer/stack classification.
806
+ */
808
807
  interface ProjectJson {
809
808
  /** Implicit dependencies on other projects. */
810
809
  implicitDependencies?: string[];
811
810
  /** Primary language — informational and query-able. */
812
811
  language?: string;
813
- /** Project layer, used for constraint inheritance and query filtering. */
812
+ /**
813
+ * Architectural layer this project sits in. Purely declarative — set
814
+ * it here in `project.json` and nothing infers it, which is why the
815
+ * `Layer` column in `vis list` reads `—` until you do.
816
+ *
817
+ * Once set it becomes queryable (`--query "layer=library"`) and feeds
818
+ * `constraints`, where it is the natural way to express rules like
819
+ * "nothing in `library` may depend on an `application`".
820
+ * @example "library"
821
+ */
814
822
  layer?: "application" | "automation" | "configuration" | "library" | "scaffolding" | "tool";
815
823
  /**
816
- * Project name. When set, takes precedence over `package.json#name`
817
- * as the project's identity in the workspace graph and CLI filters.
818
- * Falls back to `package.json#name` when omitted.
819
- */
824
+ * Project name. When set, takes precedence over `package.json#name`
825
+ * as the project's identity in the workspace graph and CLI filters.
826
+ * Falls back to `package.json#name` when omitted.
827
+ */
820
828
  name?: string;
821
829
  /** Code owners for paths inside this project. */
822
830
  owners?: OwnersEntry[];
@@ -829,19 +837,19 @@ interface ProjectJson {
829
837
  title?: string;
830
838
  };
831
839
  /**
832
- * Project type — `library`, `application`, `service`, or `tool`.
833
- *
834
- * - `library` — reusable code consumed by other workspace projects.
835
- * - `application` — end-user-facing build target (web app, mobile app).
836
- * - `service` — long-running HTTP / worker process deployed independently.
837
- * - `tool` — CLI or developer tooling shipped as an executable.
838
- */
840
+ * Project type — `library`, `application`, `service`, or `tool`.
841
+ *
842
+ * - `library` — reusable code consumed by other workspace projects.
843
+ * - `application` — end-user-facing build target (web app, mobile app).
844
+ * - `service` — long-running HTTP / worker process deployed independently.
845
+ * - `tool` — CLI or developer tooling shipped as an executable.
846
+ */
839
847
  projectType?: "application" | "library" | "service" | "tool";
840
848
  /**
841
- * Marks the project as write-restricted. Consumed by
842
- * `vis sync codeowners --write-guard` to scope the generated
843
- * Write Guard workflow to this project's paths.
844
- */
849
+ * Marks the project as write-restricted. Consumed by
850
+ * `vis sync codeowners --write-guard` to scope the generated
851
+ * Write Guard workflow to this project's paths.
852
+ */
845
853
  restricted?: boolean;
846
854
  /** Source root, used for display and language inference. */
847
855
  sourceRoot?: string;
@@ -853,9 +861,9 @@ interface ProjectJson {
853
861
  targets?: Record<string, VisTargetConfiguration>;
854
862
  }
855
863
  /**
856
- * A predicate used by {@link VisConfig.scopedTasks}.
857
- * All listed constraints must match for the block to apply.
858
- */
864
+ * A predicate used by {@link VisConfig.scopedTasks}.
865
+ * All listed constraints must match for the block to apply.
866
+ */
859
867
  interface ScopedTasksMatch {
860
868
  /** Match on primary language. */
861
869
  language?: string | string[];
@@ -869,9 +877,9 @@ interface ScopedTasksMatch {
869
877
  tags?: string[];
870
878
  }
871
879
  /**
872
- * A single scoped-tasks block — a set of task defaults gated by an
873
- * optional match predicate.
874
- */
880
+ * A single scoped-tasks block — a set of task defaults gated by an
881
+ * optional match predicate.
882
+ */
875
883
  interface ScopedTasksBlock {
876
884
  /** Optional match predicate; if omitted, the block applies universally. */
877
885
  match?: ScopedTasksMatch;
@@ -889,422 +897,422 @@ interface VisConfig {
889
897
  provider?: string;
890
898
  };
891
899
  /**
892
- * Scope the task-runner cache directory by the current git branch.
893
- * When `true`, caches are stored under `&lt;cacheDir>/branches/&lt;slug>`
894
- * so `main` and feature branches stop thrashing each other —
895
- * generated artefacts (schemas, `.d.ts` snapshots) that legitimately
896
- * differ across branches no longer oscillate the cache contents.
897
- *
898
- * Falls back to the unscoped path on detached HEAD, non-git
899
- * workspaces, or when git isn't available.
900
- * @default false
901
- */
900
+ * Scope the task-runner cache directory by the current git branch.
901
+ * When `true`, caches are stored under `&lt;cacheDir>/branches/&lt;slug>`
902
+ * so `main` and feature branches stop thrashing each other —
903
+ * generated artefacts (schemas, `.d.ts` snapshots) that legitimately
904
+ * differ across branches no longer oscillate the cache contents.
905
+ *
906
+ * Falls back to the unscoped path on detached HEAD, non-git
907
+ * workspaces, or when git isn't available.
908
+ * @default false
909
+ */
902
910
  branchScopedCache?: boolean;
903
911
  /**
904
- * Code ownership configuration. Controls how `vis sync codeowners`
905
- * renders the generated CODEOWNERS file.
906
- */
912
+ * Code ownership configuration. Controls how `vis sync codeowners`
913
+ * renders the generated CODEOWNERS file.
914
+ */
907
915
  codeowners?: CodeownersConfig;
908
916
  /**
909
- * Project dependency constraints.
910
- * Enforced after building the project graph, before running tasks.
911
- */
917
+ * Project dependency constraints.
918
+ * Enforced after building the project graph, before running tasks.
919
+ */
912
920
  constraints?: ConstraintsConfig;
913
921
  /**
914
- * Configuration for the `vis create` scaffolding command.
915
- * Controls template downloads (via giget), default options, and
916
- * post-creation behavior.
917
- */
922
+ * Configuration for the `vis create` scaffolding command.
923
+ * Controls template downloads (via giget), default options, and
924
+ * post-creation behavior.
925
+ */
918
926
  create?: {
919
927
  /**
920
- * Authorization token for downloading private repository templates.
921
- * Passed as Bearer token to the git host API.
922
- * Can also be set via GIGET_AUTH, GITHUB_TOKEN, or GH_TOKEN environment variables.
923
- */
928
+ * Authorization token for downloading private repository templates.
929
+ * Passed as Bearer token to the git host API.
930
+ * Can also be set via GIGET_AUTH, GITHUB_TOKEN, or GH_TOKEN environment variables.
931
+ */
924
932
  auth?: string;
925
933
  /**
926
- * Default editor to configure after scaffolding.
927
- * When set, `vis create` automatically generates editor config files.
928
- * @example "vscode"
929
- */
934
+ * Default editor to configure after scaffolding.
935
+ * When set, `vis create` automatically generates editor config files.
936
+ * @example "vscode"
937
+ */
930
938
  defaultEditor?: "vscode";
931
939
  /**
932
- * Default package manager for new standalone projects.
933
- * When set, skips the PM selection prompt in interactive mode.
934
- */
940
+ * Default package manager for new standalone projects.
941
+ * When set, skips the PM selection prompt in interactive mode.
942
+ */
935
943
  defaultPm?: "bun" | "npm" | "pnpm" | "yarn";
936
944
  /**
937
- * Default giget provider for `owner/repo` shorthand inputs.
938
- * @default "github"
939
- */
945
+ * Default giget provider for `owner/repo` shorthand inputs.
946
+ * @default "github"
947
+ */
940
948
  defaultProvider?: "bitbucket" | "github" | "gitlab" | "sourcehut";
941
949
  /**
942
- * Initialize a git repository after scaffolding standalone projects.
943
- * @default false
944
- */
950
+ * Initialize a git repository after scaffolding standalone projects.
951
+ * @default false
952
+ */
945
953
  gitInit?: boolean;
946
954
  /**
947
- * Install dependencies automatically after scaffolding.
948
- * @default true
949
- */
955
+ * Install dependencies automatically after scaffolding.
956
+ * @default true
957
+ */
950
958
  install?: boolean;
951
959
  /**
952
- * Prefer locally cached templates over re-downloading.
953
- * Useful for offline development or slow connections.
954
- * @default false
955
- */
960
+ * Prefer locally cached templates over re-downloading.
961
+ * Useful for offline development or slow connections.
962
+ * @default false
963
+ */
956
964
  preferOffline?: boolean;
957
965
  /**
958
- * Custom template registry URL.
959
- * When set, giget checks this registry for template metadata
960
- * before falling back to direct provider resolution.
961
- * Set to `false` to disable registry lookup entirely.
962
- * @see https://github.com/unjs/giget#custom-registry
963
- */
966
+ * Custom template registry URL.
967
+ * When set, giget checks this registry for template metadata
968
+ * before falling back to direct provider resolution.
969
+ * Set to `false` to disable registry lookup entirely.
970
+ * @see https://github.com/unjs/giget#custom-registry
971
+ */
964
972
  registry?: false | string;
965
973
  /**
966
- * Named template aliases for quick access.
967
- * Maps short names to full giget source strings.
968
- * @example
969
- * ```
970
- * templates: {
971
- * "react": "github:vitejs/vite/packages/create-vite/template-react-ts",
972
- * "lib": "github:my-org/lib-template",
973
- * "internal": "gitlab:company/templates/node-service",
974
- * }
975
- * ```
976
- */
974
+ * Named template aliases for quick access.
975
+ * Maps short names to full giget source strings.
976
+ * @example
977
+ * ```
978
+ * templates: {
979
+ * "react": "github:vitejs/vite/packages/create-vite/template-react-ts",
980
+ * "lib": "github:my-org/lib-template",
981
+ * "internal": "gitlab:company/templates/node-service",
982
+ * }
983
+ * ```
984
+ */
977
985
  templates?: Record<string, string>;
978
986
  };
979
987
  /**
980
- * Default base branch used by `vis affected`, `vis ci`, and `vis run --affected`
981
- * when no explicit `--base` is passed and no CI smart-resolver fires.
982
- *
983
- * Resolved as `origin/&lt;defaultBase>` against the local clone; should be a
984
- * branch name (not a fully-qualified ref) such as `main`, `master`, or `trunk`.
985
- * Falls back to `main` when omitted.
986
- *
987
- * Migrated automatically from `nx.json#affected.defaultBase` /
988
- * `nx.json#defaultBase` by `vis migrate nx`.
989
- * @default "main"
990
- */
988
+ * Default base branch used by `vis affected`, `vis ci`, and `vis run --affected`
989
+ * when no explicit `--base` is passed and no CI smart-resolver fires.
990
+ *
991
+ * Resolved as `origin/&lt;defaultBase>` against the local clone; should be a
992
+ * branch name (not a fully-qualified ref) such as `main`, `master`, or `trunk`.
993
+ * Falls back to `main` when omitted.
994
+ *
995
+ * Migrated automatically from `nx.json#affected.defaultBase` /
996
+ * `nx.json#defaultBase` by `vis migrate nx`.
997
+ * @default "main"
998
+ */
991
999
  defaultBase?: string;
992
1000
  /**
993
- * Discover `.editorconfig` for indent / line-ending defaults during
994
- * file transformations (sort-package-json, migrate, hook, pm overrides,
995
- * workspace catalog rewrites). Per-command flags can still override.
996
- * @default true
997
- */
1001
+ * Discover `.editorconfig` for indent / line-ending defaults during
1002
+ * file transformations (sort-package-json, migrate, hook, pm overrides,
1003
+ * workspace catalog rewrites). Per-command flags can still override.
1004
+ * @default true
1005
+ */
998
1006
  editorconfig?: boolean;
999
1007
  /**
1000
- * Inherit configuration from one or more parent configs. Entries are
1001
- * resolved left-to-right (later wins) and the consumer's own values
1002
- * always override anything pulled in from `extends`.
1003
- *
1004
- * Each entry is either:
1005
- * - a relative path (`./shared.config.ts`, `../shared.config.ts`) —
1006
- * resolved against the file declaring `extends`;
1007
- * - an npm package name (`@acme/vis-preset`) — resolved via Node.js
1008
- * module resolution from the consumer file.
1009
- *
1010
- * Absolute paths are rejected — they break across machines and CI.
1011
- * Cycles raise `VisConfigCycleError` during load.
1012
- * @example
1013
- * ```
1014
- * extends: ["@acme/vis-preset", "./shared/security.config.ts"]
1015
- * ```
1016
- */
1008
+ * Inherit configuration from one or more parent configs. Entries are
1009
+ * resolved left-to-right (later wins) and the consumer's own values
1010
+ * always override anything pulled in from `extends`.
1011
+ *
1012
+ * Each entry is either:
1013
+ * - a relative path (`./shared.config.ts`, `../shared.config.ts`) —
1014
+ * resolved against the file declaring `extends`;
1015
+ * - an npm package name (`@acme/vis-preset`) — resolved via Node.js
1016
+ * module resolution from the consumer file.
1017
+ *
1018
+ * Absolute paths are rejected — they break across machines and CI.
1019
+ * Cycles raise `VisConfigCycleError` during load.
1020
+ * @example
1021
+ * ```
1022
+ * extends: ["@acme/vis-preset", "./shared/security.config.ts"]
1023
+ * ```
1024
+ */
1017
1025
  extends?: string | string[];
1018
1026
  /**
1019
- * Named file-group patterns, reusable from target `inputs` via the
1020
- * `@filegroup:&lt;name>` token. File groups are resolved relative to each
1021
- * project root at discovery time.
1022
- * @example
1023
- * ```
1024
- * fileGroups: {
1025
- * sources: ["src/**\/*.ts", "!src/**\/*.test.ts"],
1026
- * tests: ["**\/*.test.ts"],
1027
- * }
1028
- * ```
1029
- */
1027
+ * Named file-group patterns, reusable from target `inputs` via the
1028
+ * `@filegroup:&lt;name>` token. File groups are resolved relative to each
1029
+ * project root at discovery time.
1030
+ * @example
1031
+ * ```
1032
+ * fileGroups: {
1033
+ * sources: ["src/**\/*.ts", "!src/**\/*.test.ts"],
1034
+ * tests: ["**\/*.test.ts"],
1035
+ * }
1036
+ * ```
1037
+ */
1030
1038
  fileGroups?: Record<string, string[]>;
1031
1039
  /**
1032
- * Configuration for `vis fmt` — the formatter orchestrator.
1033
- *
1034
- * Tunes adapter detection precedence, per-extension routing, and
1035
- * per-adapter overrides. Flags on the CLI always win over config.
1036
- *
1037
- * The default fmt precedence is `oxfmt → biome → dprint → prettier
1038
- * → deno-fmt`. When multiple adapters claim the same extension,
1039
- * the first in this order owns it unless overridden here.
1040
- * @example
1041
- * ```
1042
- * fmt: {
1043
- * order: ["biome", "prettier"],
1044
- * extensionOverrides: { md: "dprint" },
1045
- * adapters: { "deno-fmt": { enabled: false } },
1046
- * }
1047
- * ```
1048
- */
1040
+ * Configuration for `vis fmt` — the formatter orchestrator.
1041
+ *
1042
+ * Tunes adapter detection precedence, per-extension routing, and
1043
+ * per-adapter overrides. Flags on the CLI always win over config.
1044
+ *
1045
+ * The default fmt precedence is `oxfmt → biome → dprint → prettier
1046
+ * → deno-fmt`. When multiple adapters claim the same extension,
1047
+ * the first in this order owns it unless overridden here.
1048
+ * @example
1049
+ * ```
1050
+ * fmt: {
1051
+ * order: ["biome", "prettier"],
1052
+ * extensionOverrides: { md: "dprint" },
1053
+ * adapters: { "deno-fmt": { enabled: false } },
1054
+ * }
1055
+ * ```
1056
+ */
1049
1057
  fmt?: {
1050
1058
  /**
1051
- * Per-adapter overrides. Keyed by `AdapterId`. Set
1052
- * `enabled: false` to skip an adapter even when detected, or
1053
- * `extraArgs` to append flags verbatim.
1054
- */
1059
+ * Per-adapter overrides. Keyed by `AdapterId`. Set
1060
+ * `enabled: false` to skip an adapter even when detected, or
1061
+ * `extraArgs` to append flags verbatim.
1062
+ */
1055
1063
  adapters?: Partial<Record<FmtAdapterId, LintFmtAdapterOverride>>;
1056
1064
  /**
1057
- * Pin a file extension (without the leading dot) to a specific
1058
- * adapter, overriding the registry's "first detected adapter
1059
- * wins" routing. Use to e.g. send `.md` to `dprint` even when
1060
- * both prettier and dprint are present.
1061
- */
1065
+ * Pin a file extension (without the leading dot) to a specific
1066
+ * adapter, overriding the registry's "first detected adapter
1067
+ * wins" routing. Use to e.g. send `.md` to `dprint` even when
1068
+ * both prettier and dprint are present.
1069
+ */
1062
1070
  extensionOverrides?: Record<string, FmtAdapterId>;
1063
1071
  /**
1064
- * Override the adapter precedence order. Adapters omitted from
1065
- * this list still run (appended at the end in registry order),
1066
- * but those listed earlier get priority for extension routing.
1067
- */
1072
+ * Override the adapter precedence order. Adapters omitted from
1073
+ * this list still run (appended at the end in registry order),
1074
+ * but those listed earlier get priority for extension routing.
1075
+ */
1068
1076
  order?: FmtAdapterId[];
1069
1077
  };
1070
1078
  /**
1071
- * Configuration for the `vis generate` in-repo scaffolding command.
1072
- * Points at additional template directories beyond the defaults
1073
- * (`.vis/templates/` and `.moon/templates/`).
1074
- */
1079
+ * Configuration for the `vis generate` in-repo scaffolding command.
1080
+ * Points at additional template directories beyond the defaults
1081
+ * (`.vis/templates/` and `.moon/templates/`).
1082
+ */
1075
1083
  generator?: {
1076
1084
  /**
1077
- * Authorization token forwarded to giget when fetching
1078
- * `git://`/`npm://` remote templates. Falls back to
1079
- * `GIGET_AUTH` / `GITHUB_TOKEN` / `GH_TOKEN` env vars.
1080
- */
1085
+ * Authorization token forwarded to giget when fetching
1086
+ * `git://`/`npm://` remote templates. Falls back to
1087
+ * `GIGET_AUTH` / `GITHUB_TOKEN` / `GH_TOKEN` env vars.
1088
+ */
1081
1089
  auth?: string;
1082
1090
  /**
1083
- * Prefer locally cached remote templates over re-downloading.
1084
- * Overridable per invocation via `--prefer-offline`.
1085
- * @default false
1086
- */
1091
+ * Prefer locally cached remote templates over re-downloading.
1092
+ * Overridable per invocation via `--prefer-offline`.
1093
+ * @default false
1094
+ */
1087
1095
  preferOffline?: boolean;
1088
1096
  /**
1089
- * Extra directories to scan for templates. Each directory is
1090
- * checked for both native templates (`&lt;name>.ts`) and
1091
- * moon-format directories (containing `template.yml`).
1092
- * @example
1093
- * ```
1094
- * generator: {
1095
- * templates: ["./tools/generators", "./packages/scaffolding/templates"],
1096
- * }
1097
- * ```
1098
- */
1097
+ * Extra directories to scan for templates. Each directory is
1098
+ * checked for both native templates (`&lt;name>.ts`) and
1099
+ * moon-format directories (containing `template.yml`).
1100
+ * @example
1101
+ * ```
1102
+ * generator: {
1103
+ * templates: ["./tools/generators", "./packages/scaffolding/templates"],
1104
+ * }
1105
+ * ```
1106
+ */
1099
1107
  templates?: string[];
1100
1108
  };
1101
1109
  /**
1102
- * Auto-create targets from detected config files (Project Crystal-style).
1103
- * On by default; set `false` to disable entirely, or use the object
1104
- * form to disable individual detectors.
1105
- *
1106
- * Inferred targets sit *below* explicit ones — the command from
1107
- * `package.json#scripts`, `project.json#targets`, or `vis.task.ts`
1108
- * always wins per-key, so opting in never changes what runs. As a
1109
- * caching aid, when a `package.json` script's command *is* a
1110
- * detector's command (optionally with extra flags, no shell
1111
- * chaining) and the script declares no `inputs`/`outputs`, the
1112
- * detector's `inputs`/`outputs` are adopted so the script target can
1113
- * cache precisely and restore its artifacts. Customised/compound
1114
- * scripts are left untouched.
1115
- *
1116
- * Built-in detectors and the targets they synthesize:
1117
- *
1118
- * - **App frameworks** — `nuxt` (build/dev/preview/generate),
1119
- * `next` (build/dev/start), `remix` (build/dev/start), `astro`
1120
- * (build/dev), `gatsby` (build/develop/serve), `docusaurus`
1121
- * (build/start/serve).
1122
- * - **Bundlers** — `vite` (build/dev/preview), `rolldown` (build),
1123
- * `tsdown` (build), `tsup` (build), `packem` (build), `rollup`
1124
- * (build), `webpack` (build).
1125
- * - **Docs sites** — `vitepress` (docs:build/docs:dev/docs:preview),
1126
- * `typedoc` (docs).
1127
- * - **Server frameworks** — `nest` (build/start/start:dev).
1128
- * - **Test runners** — `vitest` (test/test:watch), `jest`
1129
- * (test/test:watch), `bun` (test), `playwright` (test:e2e),
1130
- * `cypress` (test:e2e/cypress:open).
1131
- * - **Stories** — `storybook` (storybook/build-storybook).
1132
- * - **Type checking** — `typescript` (typecheck via `tsc --noEmit`).
1133
- * - **Lint / format** — `eslint` (lint), `prettier` (format /
1134
- * format:check), `biome` (lint, format), `oxlint` (lint),
1135
- * `oxfmt` (format / format:check), `stylelint` (lint:css),
1136
- * `knip` (knip).
1137
- * - **Runtimes** — `deno` (test/lint/fmt/check).
1138
- * - **Database tooling** — `prisma` (db:generate/db:migrate/
1139
- * db:push/db:studio), `drizzle` (db:generate/db:migrate/
1140
- * db:push/db:studio).
1141
- * - **Codegen / release** — `graphql-codegen` (codegen),
1142
- * `api-extractor` (api-extract), `changeset` (changeset:version /
1143
- * changeset:publish / changeset:status).
1144
- *
1145
- * Trigger: presence of any matching config file in the project root.
1146
- * Most detectors additionally match when their framework appears in
1147
- * `dependencies` / `devDependencies` / `peerDependencies` /
1148
- * `optionalDependencies` — covering convention-only setups (e.g.
1149
- * vitest with default config). Detectors that intentionally require
1150
- * a config file (because the package frequently appears transitively
1151
- * and a dep-only match would synthesize broken commands): `vite`,
1152
- * `rolldown`, `rollup`, `webpack`, `storybook`, `nest`, `remix`,
1153
- * `vitepress`, `bun`, `deno`, `changeset`.
1154
- *
1155
- * Conflict resolution: detectors are evaluated in registration order
1156
- * (see `BUILT_IN_DETECTORS`) and the first to claim a target name
1157
- * wins. Per-name priorities: `build` → nuxt > next > remix > astro
1158
- * > gatsby > docusaurus > vite > nest > rolldown > tsdown > tsup >
1159
- * packem > rollup > webpack; `test` → vitest > jest > bun > deno;
1160
- * `test:e2e` → playwright > cypress; `lint` → eslint > biome >
1161
- * oxlint > deno; `format` → prettier > biome > oxfmt; `db:*` →
1162
- * prisma > drizzle.
1163
- *
1164
- * Also accepts an object form (`{ vite: false, vitest: true }`) to
1165
- * opt individual detectors in or out by name. Detectors omitted from
1166
- * the object run at their default (enabled). Useful when one
1167
- * detector misfires for a given workspace without disabling the rest.
1168
- * @default true
1169
- */
1110
+ * Auto-create targets from detected config files (Project Crystal-style).
1111
+ * On by default; set `false` to disable entirely, or use the object
1112
+ * form to disable individual detectors.
1113
+ *
1114
+ * Inferred targets sit *below* explicit ones — the command from
1115
+ * `package.json#scripts`, `project.json#targets`, or `vis.task.ts`
1116
+ * always wins per-key, so opting in never changes what runs. As a
1117
+ * caching aid, when a `package.json` script's command *is* a
1118
+ * detector's command (optionally with extra flags, no shell
1119
+ * chaining) and the script declares no `inputs`/`outputs`, the
1120
+ * detector's `inputs`/`outputs` are adopted so the script target can
1121
+ * cache precisely and restore its artifacts. Customised/compound
1122
+ * scripts are left untouched.
1123
+ *
1124
+ * Built-in detectors and the targets they synthesize:
1125
+ *
1126
+ * - **App frameworks** — `nuxt` (build/dev/preview/generate),
1127
+ * `next` (build/dev/start), `remix` (build/dev/start), `astro`
1128
+ * (build/dev), `gatsby` (build/develop/serve), `docusaurus`
1129
+ * (build/start/serve).
1130
+ * - **Bundlers** — `vite` (build/dev/preview), `rolldown` (build),
1131
+ * `tsdown` (build), `tsup` (build), `packem` (build), `rollup`
1132
+ * (build), `webpack` (build).
1133
+ * - **Docs sites** — `vitepress` (docs:build/docs:dev/docs:preview),
1134
+ * `typedoc` (docs).
1135
+ * - **Server frameworks** — `nest` (build/start/start:dev).
1136
+ * - **Test runners** — `vitest` (test/test:watch), `jest`
1137
+ * (test/test:watch), `bun` (test), `playwright` (test:e2e),
1138
+ * `cypress` (test:e2e/cypress:open).
1139
+ * - **Stories** — `storybook` (storybook/build-storybook).
1140
+ * - **Type checking** — `typescript` (typecheck via `tsc --noEmit`).
1141
+ * - **Lint / format** — `eslint` (lint), `prettier` (format /
1142
+ * format:check), `biome` (lint, format), `oxlint` (lint),
1143
+ * `oxfmt` (format / format:check), `stylelint` (lint:css),
1144
+ * `knip` (knip).
1145
+ * - **Runtimes** — `deno` (test/lint/fmt/check).
1146
+ * - **Database tooling** — `prisma` (db:generate/db:migrate/
1147
+ * db:push/db:studio), `drizzle` (db:generate/db:migrate/
1148
+ * db:push/db:studio).
1149
+ * - **Codegen / release** — `graphql-codegen` (codegen),
1150
+ * `api-extractor` (api-extract), `changeset` (changeset:version /
1151
+ * changeset:publish / changeset:status).
1152
+ *
1153
+ * Trigger: presence of any matching config file in the project root.
1154
+ * Most detectors additionally match when their framework appears in
1155
+ * `dependencies` / `devDependencies` / `peerDependencies` /
1156
+ * `optionalDependencies` — covering convention-only setups (e.g.
1157
+ * vitest with default config). Detectors that intentionally require
1158
+ * a config file (because the package frequently appears transitively
1159
+ * and a dep-only match would synthesize broken commands): `vite`,
1160
+ * `rolldown`, `rollup`, `webpack`, `storybook`, `nest`, `remix`,
1161
+ * `vitepress`, `bun`, `deno`, `changeset`.
1162
+ *
1163
+ * Conflict resolution: detectors are evaluated in registration order
1164
+ * (see `BUILT_IN_DETECTORS`) and the first to claim a target name
1165
+ * wins. Per-name priorities: `build` → nuxt > next > remix > astro
1166
+ * > gatsby > docusaurus > vite > nest > rolldown > tsdown > tsup >
1167
+ * packem > rollup > webpack; `test` → vitest > jest > bun > deno;
1168
+ * `test:e2e` → playwright > cypress; `lint` → eslint > biome >
1169
+ * oxlint > deno; `format` → prettier > biome > oxfmt; `db:*` →
1170
+ * prisma > drizzle.
1171
+ *
1172
+ * Also accepts an object form (`{ vite: false, vitest: true }`) to
1173
+ * opt individual detectors in or out by name. Detectors omitted from
1174
+ * the object run at their default (enabled). Useful when one
1175
+ * detector misfires for a given workspace without disabling the rest.
1176
+ * @default true
1177
+ */
1170
1178
  inferTargets?: Record<string, boolean> | boolean;
1171
1179
  /**
1172
- * Installer backend selection for `vis install` / `vis add` /
1173
- * `vis remove` / `vis update` / `vis ci`.
1174
- *
1175
- * Lets users opt into [aube](https://github.com/endevco/aube) — a
1176
- * Rust-native package manager that reads/writes pnpm/npm/yarn/bun
1177
- * lockfiles in place — as the default installer, while keeping a
1178
- * single switch to fall back to the conventional PM detected from
1179
- * the lockfile.
1180
- *
1181
- * Resolution precedence (highest first):
1182
- * 1. CLI flag (`--installer &lt;name>` / `--no-aube`)
1183
- * 2. Env var `VIS_INSTALLER`
1184
- * 3. This config field
1185
- * 4. Auto-detect (the default)
1186
- *
1187
- * Aube must be installed separately — `vis` does not bundle it.
1188
- * Install via npm (`@endevco/aube`), `mise use -g aube`, or
1189
- * `brew install endevco/tap/aube`.
1190
- */
1180
+ * Installer backend selection for `vis install` / `vis add` /
1181
+ * `vis remove` / `vis update` / `vis ci`.
1182
+ *
1183
+ * Lets users opt into [aube](https://github.com/endevco/aube) — a
1184
+ * Rust-native package manager that reads/writes pnpm/npm/yarn/bun
1185
+ * lockfiles in place — as the default installer, while keeping a
1186
+ * single switch to fall back to the conventional PM detected from
1187
+ * the lockfile.
1188
+ *
1189
+ * Resolution precedence (highest first):
1190
+ * 1. CLI flag (`--installer &lt;name>` / `--no-aube`)
1191
+ * 2. Env var `VIS_INSTALLER`
1192
+ * 3. This config field
1193
+ * 4. Auto-detect (the default)
1194
+ *
1195
+ * Aube must be installed separately — `vis` does not bundle it.
1196
+ * Install via npm (`@endevco/aube`), `mise use -g aube`, or
1197
+ * `brew install endevco/tap/aube`.
1198
+ */
1191
1199
  install?: {
1192
1200
  /**
1193
- * Which package manager performs install/add/remove/etc.
1194
- * - `auto` (default): use `aube` when it is on PATH; otherwise
1195
- * fall back to the lockfile-detected PM.
1196
- * - explicit name: always use that PM. Errors when the named
1197
- * binary is missing rather than silently falling back.
1198
- * @default "auto"
1199
- */
1201
+ * Which package manager performs install/add/remove/etc.
1202
+ * - `auto` (default): use `aube` when it is on PATH; otherwise
1203
+ * fall back to the lockfile-detected PM.
1204
+ * - explicit name: always use that PM. Errors when the named
1205
+ * binary is missing rather than silently falling back.
1206
+ * @default "auto"
1207
+ */
1200
1208
  backend?: "aube" | "auto" | "bun" | "npm" | "pnpm" | "yarn";
1201
1209
  /**
1202
- * Whether to dispatch PM invocations through `corepack`.
1203
- * - `"auto"` (default): use corepack only when the workspace
1204
- * pins a PM via the `packageManager` field AND `corepack` is
1205
- * on PATH AND the PM is one corepack manages (pnpm/yarn/npm).
1206
- * - `true`: always prefix `corepack` when the binary is on PATH
1207
- * and the PM is corepack-managed (errors loudly otherwise).
1208
- * - `false`: never go through corepack — invoke the PM directly.
1209
- *
1210
- * Mirrors nypm's `corepack: true` flag. Bun, deno, and aube are
1211
- * never wrapped — corepack does not manage them.
1212
- * @default "auto"
1213
- */
1210
+ * Whether to dispatch PM invocations through `corepack`.
1211
+ * - `"auto"` (default): use corepack only when the workspace
1212
+ * pins a PM via the `packageManager` field AND `corepack` is
1213
+ * on PATH AND the PM is one corepack manages (pnpm/yarn/npm).
1214
+ * - `true`: always prefix `corepack` when the binary is on PATH
1215
+ * and the PM is corepack-managed (errors loudly otherwise).
1216
+ * - `false`: never go through corepack — invoke the PM directly.
1217
+ *
1218
+ * Mirrors nypm's `corepack: true` flag. Bun, deno, and aube are
1219
+ * never wrapped — corepack does not manage them.
1220
+ * @default "auto"
1221
+ */
1214
1222
  corepack?: "auto" | boolean;
1215
1223
  };
1216
1224
  /**
1217
- * Configuration for `vis lint` — the linter orchestrator.
1218
- *
1219
- * Tunes adapter detection precedence and per-adapter overrides.
1220
- * Flags on the CLI always win over config.
1221
- *
1222
- * The default lint precedence is `oxlint → biome → eslint →
1223
- * stylelint → deno-lint`. Override with `order` to e.g. let biome
1224
- * fire before oxlint when the workspace standardises on biome.
1225
- * @example
1226
- * ```
1227
- * lint: {
1228
- * order: ["biome", "eslint"],
1229
- * adapters: { "deno-lint": { enabled: false } },
1230
- * }
1231
- * ```
1232
- */
1225
+ * Configuration for `vis lint` — the linter orchestrator.
1226
+ *
1227
+ * Tunes adapter detection precedence and per-adapter overrides.
1228
+ * Flags on the CLI always win over config.
1229
+ *
1230
+ * The default lint precedence is `oxlint → biome → eslint →
1231
+ * stylelint → deno-lint`. Override with `order` to e.g. let biome
1232
+ * fire before oxlint when the workspace standardises on biome.
1233
+ * @example
1234
+ * ```
1235
+ * lint: {
1236
+ * order: ["biome", "eslint"],
1237
+ * adapters: { "deno-lint": { enabled: false } },
1238
+ * }
1239
+ * ```
1240
+ */
1233
1241
  lint?: {
1234
1242
  /**
1235
- * Per-adapter overrides. Keyed by `AdapterId`. Set
1236
- * `enabled: false` to skip an adapter even when detected, or
1237
- * `extraArgs` to append flags verbatim.
1238
- */
1243
+ * Per-adapter overrides. Keyed by `AdapterId`. Set
1244
+ * `enabled: false` to skip an adapter even when detected, or
1245
+ * `extraArgs` to append flags verbatim.
1246
+ */
1239
1247
  adapters?: Partial<Record<LintAdapterId, LintFmtAdapterOverride>>;
1240
1248
  /**
1241
- * Override the adapter precedence order. Adapters omitted from
1242
- * this list still run (appended at the end in registry order)
1243
- * unless explicitly disabled under `adapters[id].enabled`.
1244
- */
1249
+ * Override the adapter precedence order. Adapters omitted from
1250
+ * this list still run (appended at the end in registry order)
1251
+ * unless explicitly disabled under `adapters[id].enabled`.
1252
+ */
1245
1253
  order?: LintAdapterId[];
1246
1254
  };
1247
1255
  /**
1248
- * `vis-mcp` promotion notice shown after successful commands when an
1249
- * AI CLI (Claude Code, Cursor, Windsurf, Continue, Zed, Cline) is
1250
- * installed but `@visulima/vis-mcp` is not wired into its config.
1251
- *
1252
- * Shown at most once every 14 days; skipped in CI, non-TTY shells,
1253
- * during `--help`/`--version`/`ai`/`mcp` invocations, and when
1254
- * `VIS_NO_MCP_PROMOTE=1` is set. Set `enabled: false` to silence
1255
- * permanently for this workspace.
1256
- * @example
1257
- * ```
1258
- * mcpPromote: { enabled: false }
1259
- * ```
1260
- */
1256
+ * `vis-mcp` promotion notice shown after successful commands when an
1257
+ * AI CLI (Claude Code, Cursor, Windsurf, Continue, Zed, Cline) is
1258
+ * installed but `@visulima/vis-mcp` is not wired into its config.
1259
+ *
1260
+ * Shown at most once every 14 days; skipped in CI, non-TTY shells,
1261
+ * during `--help`/`--version`/`ai`/`mcp` invocations, and when
1262
+ * `VIS_NO_MCP_PROMOTE=1` is set. Set `enabled: false` to silence
1263
+ * permanently for this workspace.
1264
+ * @example
1265
+ * ```
1266
+ * mcpPromote: { enabled: false }
1267
+ * ```
1268
+ */
1261
1269
  mcpPromote?: {
1262
1270
  /**
1263
- * Show the vis-mcp promotion notice on successful command completion.
1264
- * @default true
1265
- */
1271
+ * Show the vis-mcp promotion notice on successful command completion.
1272
+ * @default true
1273
+ */
1266
1274
  enabled?: boolean;
1267
1275
  };
1268
1276
  /**
1269
- * Named input patterns inherited by every project target. Equivalent
1270
- * to task-runner's `namedInputs` but configurable from the vis config.
1271
- */
1277
+ * Named input patterns inherited by every project target. Equivalent
1278
+ * to task-runner's `namedInputs` but configurable from the vis config.
1279
+ */
1272
1280
  namedInputs?: NamedInputs;
1273
1281
  /** Package override mappings applied during migration (e.g., `{ "lodash": "lodash-es" }`) */
1274
1282
  overrides?: Record<string, string>;
1275
1283
  /**
1276
- * Plugins — each plugin registers typed hooks that fire at run /
1277
- * task / cache boundaries. See {@link VisPlugin} for the contract.
1278
- * Prefer plugins over per-target shell hooks when behaviour needs
1279
- * access to task metadata, results, or cache state.
1280
- */
1284
+ * Plugins — each plugin registers typed hooks that fire at run /
1285
+ * task / cache boundaries. See {@link VisPlugin} for the contract.
1286
+ * Prefer plugins over per-target shell hooks when behaviour needs
1287
+ * access to task metadata, results, or cache state.
1288
+ */
1281
1289
  plugins?: VisPlugin[];
1282
1290
  /**
1283
- * Workspace dep-policy lints exposed via `vis lint`. Each block opts in
1284
- * to a single rule; the command flags (`--workspace-protocol`,
1285
- * `--no-redefine-root`, `--banned-deps`) toggle them per-run.
1286
- */
1291
+ * Workspace dep-policy lints exposed via `vis lint`. Each block opts in
1292
+ * to a single rule; the command flags (`--workspace-protocol`,
1293
+ * `--no-redefine-root`, `--banned-deps`) toggle them per-run.
1294
+ */
1287
1295
  policy?: {
1288
1296
  /**
1289
- * Map of dep names or globs → reason (or `{ reason, replacement, packages?, paths? }`).
1290
- * Internal/workspace deps are never flagged here; the
1291
- * workspace-protocol lint owns those.
1292
- *
1293
- * Optional `packages` (globs over the declaring package's `name`) and
1294
- * `paths` (globs over the workspace-relative `packageDir`) narrow where
1295
- * the rule applies. With both set, either match is enough. Omit both
1296
- * to ban anywhere — the default.
1297
- * @example
1298
- * ```
1299
- * bannedDeps: {
1300
- * request: "deprecated; use undici",
1301
- * moment: { reason: "huge bundle, frozen upstream", replacement: "date-fns" },
1302
- * "@radix-ui/*": "we standardized on shadcn",
1303
- * react: { reason: "no react in shared libs", paths: ["packages/shared/*"] },
1304
- * "next": { reason: "apps only", packages: ["@app/*"] },
1305
- * }
1306
- * ```
1307
- */
1297
+ * Map of dep names or globs → reason (or `{ reason, replacement, packages?, paths? }`).
1298
+ * Internal/workspace deps are never flagged here; the
1299
+ * workspace-protocol lint owns those.
1300
+ *
1301
+ * Optional `packages` (globs over the declaring package's `name`) and
1302
+ * `paths` (globs over the workspace-relative `packageDir`) narrow where
1303
+ * the rule applies. With both set, either match is enough. Omit both
1304
+ * to ban anywhere — the default.
1305
+ * @example
1306
+ * ```
1307
+ * bannedDeps: {
1308
+ * request: "deprecated; use undici",
1309
+ * moment: { reason: "huge bundle, frozen upstream", replacement: "date-fns" },
1310
+ * "@radix-ui/*": "we standardized on shadcn",
1311
+ * react: { reason: "no react in shared libs", paths: ["packages/shared/*"] },
1312
+ * "next": { reason: "apps only", packages: ["@app/*"] },
1313
+ * }
1314
+ * ```
1315
+ */
1308
1316
  bannedDeps?: Record<string, string | {
1309
1317
  packages?: string[];
1310
1318
  paths?: string[];
@@ -1312,364 +1320,364 @@ interface VisConfig {
1312
1320
  replacement?: string;
1313
1321
  }>;
1314
1322
  /**
1315
- * Tweak the custom-types lint that flags drift in `engines.{node,pnpm,...}`,
1316
- * `packageManager`, `volta.{node,pnpm,yarn}`, and the proposed
1317
- * `devEngines.{runtime,packageManager}` array form.
1318
- *
1319
- * Each (customType × name) cluster is tracked independently —
1320
- * `engines.node` and `volta.node` don't cross-couple here. Use a
1321
- * versionGroup once that lands if you need to enforce they agree.
1322
- */
1323
+ * Tweak the custom-types lint that flags drift in `engines.{node,pnpm,...}`,
1324
+ * `packageManager`, `volta.{node,pnpm,yarn}`, and the proposed
1325
+ * `devEngines.{runtime,packageManager}` array form.
1326
+ *
1327
+ * Each (customType × name) cluster is tracked independently —
1328
+ * `engines.node` and `volta.node` don't cross-couple here. Use a
1329
+ * versionGroup once that lands if you need to enforce they agree.
1330
+ */
1323
1331
  customTypes?: {
1324
1332
  /**
1325
- * Three-state autofix opt-out. See `workspaceProtocol.autofix`
1326
- * for the contract — same semantics, applied to drift rewrites
1327
- * across engines / packageManager / volta / devEngines.
1328
- *
1329
- * Note: `--fix` strips any `+sha512.&lt;hash&gt;` suffix from
1330
- * `packageManager` on bump — content-integrity hashes are tied
1331
- * to a specific package, not a version, so users must regenerate
1332
- * via their PM (`pnpm install` re-pins; `corepack use pnpm@X` etc.).
1333
- * @default true
1334
- */
1333
+ * Three-state autofix opt-out. See `workspaceProtocol.autofix`
1334
+ * for the contract — same semantics, applied to drift rewrites
1335
+ * across engines / packageManager / volta / devEngines.
1336
+ *
1337
+ * Note: `--fix` strips any `+sha512.&lt;hash&gt;` suffix from
1338
+ * `packageManager` on bump — content-integrity hashes are tied
1339
+ * to a specific package, not a version, so users must regenerate
1340
+ * via their PM (`pnpm install` re-pins; `corepack use pnpm@X` etc.).
1341
+ * @default true
1342
+ */
1335
1343
  autofix?: "prompt" | boolean;
1336
1344
  /**
1337
- * User-defined custom-type pin locations. Each entry tells the
1338
- * customTypes lint to read additional version pins from a
1339
- * non-standard JSON path inside every workspace package.json,
1340
- * cluster them by `(name × depName)` like the built-in types,
1341
- * and rewrite them with `--fix`.
1342
- *
1343
- * The original built-ins (`engines`, `volta`, `packageManager`,
1344
- * `devEngines.runtime`, `devEngines.packageManager`) keep
1345
- * running unconditionally — these layer on top.
1346
- *
1347
- * Strategies:
1348
- * - `versionsByName`: the JSON at `path` is `{ [depName]: version }`
1349
- * (like `engines` or `pnpm.overrides`).
1350
- * - `name@version`: the JSON at `path` is a string of the form
1351
- * `name@version` (like `packageManager`). The leading `name@`
1352
- * is preserved; only the version segment is rewritten.
1353
- * - `string`: the JSON at `path` is a bare version string. The
1354
- * `depName` field is required and identifies the dep cluster.
1355
- *
1356
- * `name` must not collide with a built-in type name. `path` is
1357
- * a dot-separated walk into the package.json (e.g. `pnpm.overrides`).
1358
- * @example
1359
- * ```ts
1360
- * extraTypes: [
1361
- * { name: "pnpmOverridesLegacy", path: "pnpm.overrides", strategy: "versionsByName" },
1362
- * { name: "myToolPin", path: "myTool.runtime", strategy: "name@version" },
1363
- * { name: "minNode", path: "config.minNode", strategy: "string", depName: "node" },
1364
- * ]
1365
- * ```
1366
- */
1345
+ * User-defined custom-type pin locations. Each entry tells the
1346
+ * customTypes lint to read additional version pins from a
1347
+ * non-standard JSON path inside every workspace package.json,
1348
+ * cluster them by `(name × depName)` like the built-in types,
1349
+ * and rewrite them with `--fix`.
1350
+ *
1351
+ * The original built-ins (`engines`, `volta`, `packageManager`,
1352
+ * `devEngines.runtime`, `devEngines.packageManager`) keep
1353
+ * running unconditionally — these layer on top.
1354
+ *
1355
+ * Strategies:
1356
+ * - `versionsByName`: the JSON at `path` is `{ [depName]: version }`
1357
+ * (like `engines` or `pnpm.overrides`).
1358
+ * - `name@version`: the JSON at `path` is a string of the form
1359
+ * `name@version` (like `packageManager`). The leading `name@`
1360
+ * is preserved; only the version segment is rewritten.
1361
+ * - `string`: the JSON at `path` is a bare version string. The
1362
+ * `depName` field is required and identifies the dep cluster.
1363
+ *
1364
+ * `name` must not collide with a built-in type name. `path` is
1365
+ * a dot-separated walk into the package.json (e.g. `pnpm.overrides`).
1366
+ * @example
1367
+ * ```ts
1368
+ * extraTypes: [
1369
+ * { name: "pnpmOverridesLegacy", path: "pnpm.overrides", strategy: "versionsByName" },
1370
+ * { name: "myToolPin", path: "myTool.runtime", strategy: "name@version" },
1371
+ * { name: "minNode", path: "config.minNode", strategy: "string", depName: "node" },
1372
+ * ]
1373
+ * ```
1374
+ */
1367
1375
  extraTypes?: ExtraCustomType[];
1368
1376
  /**
1369
- * Dep names exempt from the drift check (exact match against the
1370
- * field name within the block — e.g. `node`, `pnpm`).
1371
- */
1377
+ * Dep names exempt from the drift check (exact match against the
1378
+ * field name within the block — e.g. `node`, `pnpm`).
1379
+ */
1372
1380
  ignore?: string[];
1373
1381
  /**
1374
- * Resolution strategy used when `--fix` runs.
1375
- * - `highest` (default): align every drifting instance to the
1376
- * highest declared version.
1377
- * - `lowest`: align to the lowest.
1378
- * @default "highest"
1379
- */
1382
+ * Resolution strategy used when `--fix` runs.
1383
+ * - `highest` (default): align every drifting instance to the
1384
+ * highest declared version.
1385
+ * - `lowest`: align to the lowest.
1386
+ * @default "highest"
1387
+ */
1380
1388
  resolve?: "highest" | "lowest";
1381
1389
  };
1382
1390
  /**
1383
- * Tweak the dead-workspace-patterns lint that flags entries in
1384
- * `pnpm-workspace.yaml#packages` / `package.json#workspaces` which
1385
- * resolve to zero on-disk directories.
1386
- */
1391
+ * Tweak the dead-workspace-patterns lint that flags entries in
1392
+ * `pnpm-workspace.yaml#packages` / `package.json#workspaces` which
1393
+ * resolve to zero on-disk directories.
1394
+ */
1387
1395
  deadWorkspacePatterns?: {
1388
1396
  /**
1389
- * Three-state autofix opt-out. See `workspaceProtocol.autofix`
1390
- * for the contract — applied here to dropping unmatched patterns
1391
- * from the workspace config file.
1392
- * @default true
1393
- */
1397
+ * Three-state autofix opt-out. See `workspaceProtocol.autofix`
1398
+ * for the contract — applied here to dropping unmatched patterns
1399
+ * from the workspace config file.
1400
+ * @default true
1401
+ */
1394
1402
  autofix?: "prompt" | boolean;
1395
1403
  };
1396
1404
  /**
1397
- * Tweak the empty-deps lint that flags empty `dependencies` /
1398
- * `devDependencies` / `peerDependencies` / `optionalDependencies`
1399
- * blocks across the workspace.
1400
- */
1405
+ * Tweak the empty-deps lint that flags empty `dependencies` /
1406
+ * `devDependencies` / `peerDependencies` / `optionalDependencies`
1407
+ * blocks across the workspace.
1408
+ */
1401
1409
  emptyDeps?: {
1402
1410
  /**
1403
- * Three-state autofix opt-out. See `workspaceProtocol.autofix`
1404
- * for the contract — applied here to removing the empty key.
1405
- * @default true
1406
- */
1411
+ * Three-state autofix opt-out. See `workspaceProtocol.autofix`
1412
+ * for the contract — applied here to removing the empty key.
1413
+ * @default true
1414
+ */
1407
1415
  autofix?: "prompt" | boolean;
1408
1416
  /**
1409
- * Block names exempt from the rule (e.g. `["peerDependencies"]`
1410
- * to keep the key around as a marker even when empty).
1411
- */
1417
+ * Block names exempt from the rule (e.g. `["peerDependencies"]`
1418
+ * to keep the key around as a marker even when empty).
1419
+ */
1412
1420
  ignoreBlocks?: ("dependencies" | "devDependencies" | "optionalDependencies" | "peerDependencies")[];
1413
1421
  };
1414
1422
  /**
1415
- * Tweak the redefine-root lint that flags non-root packages duplicating
1416
- * deps already pinned at the workspace root.
1417
- */
1423
+ * Tweak the redefine-root lint that flags non-root packages duplicating
1424
+ * deps already pinned at the workspace root.
1425
+ */
1418
1426
  redefineRoot?: {
1419
1427
  /** Dep names that are exempt from the redefine-root rule (exact match). */
1420
1428
  ignore?: string[];
1421
1429
  };
1422
1430
  /**
1423
- * Tweak the root-deps lint that flags runtime `dependencies` declared
1424
- * on the private workspace root (they should live in `devDependencies`).
1425
- */
1431
+ * Tweak the root-deps lint that flags runtime `dependencies` declared
1432
+ * on the private workspace root (they should live in `devDependencies`).
1433
+ */
1426
1434
  rootDeps?: {
1427
1435
  /**
1428
- * Three-state autofix opt-out. See `workspaceProtocol.autofix`
1429
- * for the contract — applied here to moving entries from
1430
- * `dependencies` to `devDependencies` on the root package.json.
1431
- * @default true
1432
- */
1436
+ * Three-state autofix opt-out. See `workspaceProtocol.autofix`
1437
+ * for the contract — applied here to moving entries from
1438
+ * `dependencies` to `devDependencies` on the root package.json.
1439
+ * @default true
1440
+ */
1433
1441
  autofix?: "prompt" | boolean;
1434
1442
  };
1435
1443
  /**
1436
- * Tweak the root-package-manager lint that flags a missing or
1437
- * malformed `packageManager` field on the workspace root.
1438
- */
1444
+ * Tweak the root-package-manager lint that flags a missing or
1445
+ * malformed `packageManager` field on the workspace root.
1446
+ */
1439
1447
  rootPackageManager?: {
1440
1448
  /**
1441
- * Three-state autofix opt-out. See `workspaceProtocol.autofix`
1442
- * for the contract. `--fix` only writes when `suggested` is set —
1443
- * a missing `packageManager` field has no canonical default.
1444
- * @default true
1445
- */
1449
+ * Three-state autofix opt-out. See `workspaceProtocol.autofix`
1450
+ * for the contract. `--fix` only writes when `suggested` is set —
1451
+ * a missing `packageManager` field has no canonical default.
1452
+ * @default true
1453
+ */
1446
1454
  autofix?: "prompt" | boolean;
1447
1455
  /**
1448
- * Canonical specifier (`name@version`) to write when `--fix` runs
1449
- * and the field is absent. Required to enable autofix —
1450
- * vis won't guess the workspace's preferred manager.
1451
- * @example "pnpm@10.32.1"
1452
- */
1456
+ * Canonical specifier (`name@version`) to write when `--fix` runs
1457
+ * and the field is absent. Required to enable autofix —
1458
+ * vis won't guess the workspace's preferred manager.
1459
+ * @example "pnpm@10.32.1"
1460
+ */
1453
1461
  suggested?: string;
1454
1462
  };
1455
1463
  /**
1456
- * Tweak the root-private lint that flags a workspace root package.json
1457
- * missing `"private": true`. Only fires when the root looks like a
1458
- * workspace (npm/yarn/bun `workspaces` field or `pnpm-workspace.yaml`).
1459
- */
1464
+ * Tweak the root-private lint that flags a workspace root package.json
1465
+ * missing `"private": true`. Only fires when the root looks like a
1466
+ * workspace (npm/yarn/bun `workspaces` field or `pnpm-workspace.yaml`).
1467
+ */
1460
1468
  rootPrivate?: {
1461
1469
  /**
1462
- * Three-state autofix opt-out. See `workspaceProtocol.autofix`
1463
- * for the contract — applied here to inserting `"private": true`.
1464
- * @default true
1465
- */
1470
+ * Three-state autofix opt-out. See `workspaceProtocol.autofix`
1471
+ * for the contract — applied here to inserting `"private": true`.
1472
+ * @default true
1473
+ */
1466
1474
  autofix?: "prompt" | boolean;
1467
1475
  };
1468
1476
  /**
1469
- * Tweak the similar-deps lint that flags drift across related dep
1470
- * families (e.g. `react` and `react-dom`, all of `@babel/*`).
1471
- *
1472
- * The lint is report-only — aligning a family requires picking a
1473
- * single canonical specifier across heterogeneous range syntaxes
1474
- * (`^`, `~`, exact), which is too lossy without user input.
1475
- */
1477
+ * Tweak the similar-deps lint that flags drift across related dep
1478
+ * families (e.g. `react` and `react-dom`, all of `@babel/*`).
1479
+ *
1480
+ * The lint is report-only — aligning a family requires picking a
1481
+ * single canonical specifier across heterogeneous range syntaxes
1482
+ * (`^`, `~`, exact), which is too lossy without user input.
1483
+ */
1476
1484
  similarDeps?: {
1477
1485
  /**
1478
- * Additional families merged with the built-ins. Same `id` wins
1479
- * → user override fully replaces the built-in entry.
1480
- * @example
1481
- * ```
1482
- * extraFamilies: [
1483
- * { id: "vue", label: "Vue", members: ["vue", "vue-router", "pinia"] },
1484
- * ]
1485
- * ```
1486
- */
1486
+ * Additional families merged with the built-ins. Same `id` wins
1487
+ * → user override fully replaces the built-in entry.
1488
+ * @example
1489
+ * ```
1490
+ * extraFamilies: [
1491
+ * { id: "vue", label: "Vue", members: ["vue", "vue-router", "pinia"] },
1492
+ * ]
1493
+ * ```
1494
+ */
1487
1495
  extraFamilies?: SimilarDepFamily[];
1488
1496
  /** Family ids to skip entirely (matches `SimilarDepFamily.id`). */
1489
1497
  ignoreFamilies?: string[];
1490
1498
  };
1491
1499
  /**
1492
- * Tweak the types-in-deps lint that flags `@types/*` declared in
1493
- * `dependencies` on a private package (they belong in
1494
- * `devDependencies` since the package never ships).
1495
- */
1500
+ * Tweak the types-in-deps lint that flags `@types/*` declared in
1501
+ * `dependencies` on a private package (they belong in
1502
+ * `devDependencies` since the package never ships).
1503
+ */
1496
1504
  typesInDeps?: {
1497
1505
  /**
1498
- * Three-state autofix opt-out. See `workspaceProtocol.autofix`
1499
- * for the contract — applied here to moving the entry to
1500
- * `devDependencies`. Existing dev pins are preserved on conflict.
1501
- * @default true
1502
- */
1506
+ * Three-state autofix opt-out. See `workspaceProtocol.autofix`
1507
+ * for the contract — applied here to moving the entry to
1508
+ * `devDependencies`. Existing dev pins are preserved on conflict.
1509
+ * @default true
1510
+ */
1503
1511
  autofix?: "prompt" | boolean;
1504
1512
  /** Dep names exempt from the rule (exact match, e.g. `@types/node`). */
1505
1513
  ignore?: string[];
1506
1514
  };
1507
1515
  /**
1508
- * Tweak the workspace-protocol lint that flags internal deps not
1509
- * using the `workspace:` protocol.
1510
- */
1516
+ * Tweak the workspace-protocol lint that flags internal deps not
1517
+ * using the `workspace:` protocol.
1518
+ */
1511
1519
  workspaceProtocol?: {
1512
1520
  /**
1513
- * Three-state autofix opt-out. Some workspaces want detection
1514
- * without rewrite (e.g. dual-licensed packages where `workspace:*`
1515
- * is unsafe).
1516
- * - `true` (default): `--fix` rewrites the specifier.
1517
- * - `false`: never rewrite — report the violation only.
1518
- * - `"prompt"`: ask before each rewrite. Falls back to report-only
1519
- * when stdin isn't a TTY (CI). Reserved; not yet implemented.
1520
- *
1521
- * Note: when `false` (or `"prompt"`), `--fix` still **fails CI** on
1522
- * detected violations — the rule is "report only", not "ignore".
1523
- * Drop the rule from the lint selection if you want a clean exit.
1524
- * @default true
1525
- * @example
1526
- * ```
1527
- * policy: {
1528
- * workspaceProtocol: { autofix: false },
1529
- * }
1530
- * ```
1531
- */
1521
+ * Three-state autofix opt-out. Some workspaces want detection
1522
+ * without rewrite (e.g. dual-licensed packages where `workspace:*`
1523
+ * is unsafe).
1524
+ * - `true` (default): `--fix` rewrites the specifier.
1525
+ * - `false`: never rewrite — report the violation only.
1526
+ * - `"prompt"`: ask before each rewrite. Falls back to report-only
1527
+ * when stdin isn't a TTY (CI). Reserved; not yet implemented.
1528
+ *
1529
+ * Note: when `false` (or `"prompt"`), `--fix` still **fails CI** on
1530
+ * detected violations — the rule is "report only", not "ignore".
1531
+ * Drop the rule from the lint selection if you want a clean exit.
1532
+ * @default true
1533
+ * @example
1534
+ * ```
1535
+ * policy: {
1536
+ * workspaceProtocol: { autofix: false },
1537
+ * }
1538
+ * ```
1539
+ */
1532
1540
  autofix?: "prompt" | boolean;
1533
1541
  };
1534
1542
  /**
1535
- * Tweak the workspace-versions lint that flags external deps declared
1536
- * at inconsistent versions across the workspace.
1537
- */
1543
+ * Tweak the workspace-versions lint that flags external deps declared
1544
+ * at inconsistent versions across the workspace.
1545
+ */
1538
1546
  workspaceVersions?: {
1539
1547
  /**
1540
- * Three-state autofix opt-out. See `workspaceProtocol.autofix`
1541
- * for the contract — same semantics, applied to drift rewrites.
1542
- *
1543
- * Also gates the `--propose-min` catalog suggestion writer:
1544
- * when `false` / `"prompt"`, `--fix --propose-min` reports the
1545
- * proposed catalog entries but does not write
1546
- * `pnpm-workspace.yaml`. Same "report only, still fails CI"
1547
- * note applies as on `workspaceProtocol.autofix`.
1548
- * @default true
1549
- */
1548
+ * Three-state autofix opt-out. See `workspaceProtocol.autofix`
1549
+ * for the contract — same semantics, applied to drift rewrites.
1550
+ *
1551
+ * Also gates the `--propose-min` catalog suggestion writer:
1552
+ * when `false` / `"prompt"`, `--fix --propose-min` reports the
1553
+ * proposed catalog entries but does not write
1554
+ * `pnpm-workspace.yaml`. Same "report only, still fails CI"
1555
+ * note applies as on `workspaceProtocol.autofix`.
1556
+ * @default true
1557
+ */
1550
1558
  autofix?: "prompt" | boolean;
1551
1559
  /** Dep names exempt from the version-drift check (exact match). */
1552
1560
  ignore?: string[];
1553
1561
  /**
1554
- * Resolution strategy used when `--fix` runs.
1555
- * - `highest` (default): rewrite every drifting instance to the
1556
- * highest sibling specifier.
1557
- * - `lowest`: rewrite to the lowest.
1558
- * - `catalog`: rewrite any dep already pinned in a workspace catalog
1559
- * to `catalog:` / `catalog:&lt;name>`. Catalog must exist; this lint
1560
- * does not create the catalog (see `vis lint --resolve catalog --propose`).
1561
- * @default "highest"
1562
- */
1562
+ * Resolution strategy used when `--fix` runs.
1563
+ * - `highest` (default): rewrite every drifting instance to the
1564
+ * highest sibling specifier.
1565
+ * - `lowest`: rewrite to the lowest.
1566
+ * - `catalog`: rewrite any dep already pinned in a workspace catalog
1567
+ * to `catalog:` / `catalog:&lt;name>`. Catalog must exist; this lint
1568
+ * does not create the catalog (see `vis lint --resolve catalog --propose`).
1569
+ * @default "highest"
1570
+ */
1563
1571
  resolve?: "catalog" | "highest" | "lowest";
1564
1572
  };
1565
1573
  };
1566
1574
  /**
1567
- * Pre-flight checks fired before `vis run` starts the orchestrator.
1568
- * Each check is opt-out (`false`) — defaults are sensible for the
1569
- * common monorepo case.
1570
- */
1575
+ * Pre-flight checks fired before `vis run` starts the orchestrator.
1576
+ * Each check is opt-out (`false`) — defaults are sensible for the
1577
+ * common monorepo case.
1578
+ */
1571
1579
  preflight?: {
1572
1580
  /**
1573
- * Detect "lockfile changed but `node_modules` is stale" before
1574
- * running tasks. Compares lockfile mtime against the
1575
- * package-manager-specific install marker
1576
- * (`node_modules/.modules.yaml` for pnpm, `.package-lock.json`
1577
- * for npm, etc.). Warns in TTY, hard-fails in CI.
1578
- * @default true
1579
- */
1581
+ * Detect "lockfile changed but `node_modules` is stale" before
1582
+ * running tasks. Compares lockfile mtime against the
1583
+ * package-manager-specific install marker
1584
+ * (`node_modules/.modules.yaml` for pnpm, `.package-lock.json`
1585
+ * for npm, etc.). Warns in TTY, hard-fails in CI.
1586
+ * @default true
1587
+ */
1580
1588
  lockfile?: boolean;
1581
1589
  };
1582
1590
  /**
1583
- * Configuration for the `vis release` subsystem. Controls change-file
1584
- * authoring, version computation, channel routing, publish behavior,
1585
- * and CI integration. See `packages/tooling/vis/rfc/design-release-manager.md`.
1586
- */
1591
+ * Configuration for the `vis release` subsystem. Controls change-file
1592
+ * authoring, version computation, channel routing, publish behavior,
1593
+ * and CI integration. See `packages/tooling/vis/rfc/design-release-manager.md`.
1594
+ */
1587
1595
  release?: VisReleaseConfig;
1588
1596
  /**
1589
- * Behavior of `vis run` when invoked tasks declare service dependencies
1590
- * that aren't running in the workspace registry. CLI `--services=&lt;mode>`
1591
- * overrides this block.
1592
- */
1597
+ * Behavior of `vis run` when invoked tasks declare service dependencies
1598
+ * that aren't running in the workspace registry. CLI `--services=&lt;mode>`
1599
+ * overrides this block.
1600
+ */
1593
1601
  run?: {
1594
1602
  /**
1595
- * Wrap each task's CI log block in collapsible groups so users
1596
- * can fold/unfold per-task output in the host CI's web UI.
1597
- * Failed tasks always render expanded so the failure is visible
1598
- * without an extra click.
1599
- *
1600
- * - `auto` (default): pick the format from the detected runner —
1601
- * `GITHUB_ACTIONS=true` → `github` (`::group::`),
1602
- * `GITLAB_CI=true` → `gitlab` (`section_start:` ANSI sequences),
1603
- * `BUILDKITE=true` → `buildkite` (`---` collapsed headers),
1604
- * `TF_BUILD=True` → `azure` (`##[group]`),
1605
- * no grouping otherwise.
1606
- * - `off`: never group (raw separators only — useful when
1607
- * piping through tools that mangle the directives).
1608
- * - `azure` / `buildkite` / `github` / `gitlab`: force the format
1609
- * regardless of detected environment (useful for self-hosted
1610
- * runners that don't set the standard env vars).
1611
- *
1612
- * CircleCI is intentionally not auto-detected: its 2.0+ format
1613
- * has no inline grouping directive — steps auto-group in the
1614
- * web UI without any markup from the runner.
1615
- */
1603
+ * Wrap each task's CI log block in collapsible groups so users
1604
+ * can fold/unfold per-task output in the host CI's web UI.
1605
+ * Failed tasks always render expanded so the failure is visible
1606
+ * without an extra click.
1607
+ *
1608
+ * - `auto` (default): pick the format from the detected runner —
1609
+ * `GITHUB_ACTIONS=true` → `github` (`::group::`),
1610
+ * `GITLAB_CI=true` → `gitlab` (`section_start:` ANSI sequences),
1611
+ * `BUILDKITE=true` → `buildkite` (`---` collapsed headers),
1612
+ * `TF_BUILD=True` → `azure` (`##[group]`),
1613
+ * no grouping otherwise.
1614
+ * - `off`: never group (raw separators only — useful when
1615
+ * piping through tools that mangle the directives).
1616
+ * - `azure` / `buildkite` / `github` / `gitlab`: force the format
1617
+ * regardless of detected environment (useful for self-hosted
1618
+ * runners that don't set the standard env vars).
1619
+ *
1620
+ * CircleCI is intentionally not auto-detected: its 2.0+ format
1621
+ * has no inline grouping directive — steps auto-group in the
1622
+ * web UI without any markup from the runner.
1623
+ */
1616
1624
  ciGrouping?: "auto" | "azure" | "buildkite" | "github" | "gitlab" | "off";
1617
1625
  /**
1618
- * Stay quiet when a run succeeds. When enabled:
1619
- * - non-interactive output suppresses successful and cached tasks
1620
- * and prints only failures (failed tasks always render in full —
1621
- * in CI as expanded log blocks), equivalent to
1622
- * `--output-style=quiet`; and
1623
- * - the interactive TUI auto-closes a few seconds after a clean run
1624
- * via a countdown dialog. A run with any failure stays open so the
1625
- * user can inspect it.
1626
- *
1627
- * The explicit `--output-style` CLI flag overrides the output side,
1628
- * a per-target `options.outputStyle` overrides both, and
1629
- * `tui.autoExit` overrides the auto-close countdown.
1630
- *
1631
- * Default: `false` — every task's output is echoed and the TUI waits
1632
- * for the user. Set to `true` to opt into quiet, auto-closing runs.
1633
- */
1626
+ * Stay quiet when a run succeeds. When enabled:
1627
+ * - non-interactive output suppresses successful and cached tasks
1628
+ * and prints only failures (failed tasks always render in full —
1629
+ * in CI as expanded log blocks), equivalent to
1630
+ * `--output-style=quiet`; and
1631
+ * - the interactive TUI auto-closes a few seconds after a clean run
1632
+ * via a countdown dialog. A run with any failure stays open so the
1633
+ * user can inspect it.
1634
+ *
1635
+ * The explicit `--output-style` CLI flag overrides the output side,
1636
+ * a per-target `options.outputStyle` overrides both, and
1637
+ * `tui.autoExit` overrides the auto-close countdown.
1638
+ *
1639
+ * Default: `false` — every task's output is echoed and the TUI waits
1640
+ * for the user. Set to `true` to opt into quiet, auto-closing runs.
1641
+ */
1634
1642
  quietOnSuccess?: boolean;
1635
1643
  /**
1636
- * One knob controlling auto-start of missing service deps.
1637
- * - `auto` (default in TTY): pick by task — `dev` → ephemeral,
1638
- * others → persistent.
1639
- * - `ephemeral`: services die with the run (no registry entry).
1640
- * - `persistent`: services persist across runs in the registry.
1641
- * - `off` (default in CI / non-TTY): print diagnostics and abort.
1642
- */
1644
+ * One knob controlling auto-start of missing service deps.
1645
+ * - `auto` (default in TTY): pick by task — `dev` → ephemeral,
1646
+ * others → persistent.
1647
+ * - `ephemeral`: services die with the run (no registry entry).
1648
+ * - `persistent`: services persist across runs in the registry.
1649
+ * - `off` (default in CI / non-TTY): print diagnostics and abort.
1650
+ */
1643
1651
  services?: "auto" | "ephemeral" | "off" | "persistent";
1644
1652
  };
1645
1653
  /**
1646
- * Target JS runtime for this workspace/project — `"node"` (default) or
1647
- * `"bun"`. Overridden by the `--runtime` flag and the `VIS_RUNTIME` env
1648
- * var; falls back to lockfile detection when unset. Part of the
1649
- * cross-runtime multi-tool (see `rfc/design-runtime-multitool.md`).
1650
- */
1654
+ * Target JS runtime for this workspace/project — `"node"` (default) or
1655
+ * `"bun"`. Overridden by the `--runtime` flag and the `VIS_RUNTIME` env
1656
+ * var; falls back to lockfile detection when unset. Part of the
1657
+ * cross-runtime multi-tool (see `rfc/design-runtime-multitool.md`).
1658
+ */
1651
1659
  runtime?: RuntimeId;
1652
1660
  /**
1653
- * Cascading scoped-task blocks. Each block may narrow its tasks to a
1654
- * subset of projects via `match`. Blocks are evaluated in order; later
1655
- * blocks override earlier ones when the same field is set.
1656
- *
1657
- * Match predicates are additive — if `match` is omitted, the block applies
1658
- * to every project.
1659
- * @example
1660
- * ```
1661
- * scopedTasks: [
1662
- * { match: { tags: ["frontend"] }, tasks: { build: { cache: true } } },
1663
- * { match: { projectType: "library" }, tasks: { lint: { cache: true } } },
1664
- * ]
1665
- * ```
1666
- */
1661
+ * Cascading scoped-task blocks. Each block may narrow its tasks to a
1662
+ * subset of projects via `match`. Blocks are evaluated in order; later
1663
+ * blocks override earlier ones when the same field is set.
1664
+ *
1665
+ * Match predicates are additive — if `match` is omitted, the block applies
1666
+ * to every project.
1667
+ * @example
1668
+ * ```
1669
+ * scopedTasks: [
1670
+ * { match: { tags: ["frontend"] }, tasks: { build: { cache: true } } },
1671
+ * { match: { projectType: "library" }, tasks: { lint: { cache: true } } },
1672
+ * ]
1673
+ * ```
1674
+ */
1667
1675
  scopedTasks?: ScopedTasksBlock[];
1668
1676
  /**
1669
- * Default options for `vis secrets`. CLI flags always take precedence;
1670
- * this block provides workspace-wide defaults so teams can commit config
1671
- * once and every invocation picks it up.
1672
- */
1677
+ * Default options for `vis secrets`. CLI flags always take precedence;
1678
+ * this block provides workspace-wide defaults so teams can commit config
1679
+ * once and every invocation picks it up.
1680
+ */
1673
1681
  secrets?: {
1674
1682
  /** Path to a baseline of previously-triaged findings (relative to workspace root). */
1675
1683
  baseline?: string;
@@ -1702,13 +1710,13 @@ interface VisConfig {
1702
1710
  /** Walker / filesystem traversal. */
1703
1711
  walk?: {
1704
1712
  /**
1705
- * Paths to additional `.gitignore`-syntax files (e.g. `.secretsignore`).
1706
- */
1713
+ * Paths to additional `.gitignore`-syntax files (e.g. `.secretsignore`).
1714
+ */
1707
1715
  excludeFromFiles?: string[];
1708
1716
  /**
1709
- * Gitignore-syntax patterns (supports negation, directory markers, leading `/`).
1710
- * Applied on top of `.gitignore`.
1711
- */
1717
+ * Gitignore-syntax patterns (supports negation, directory markers, leading `/`).
1718
+ * Applied on top of `.gitignore`.
1719
+ */
1712
1720
  excludePatterns?: string[];
1713
1721
  /** Respect `.gitignore`. Default: `true`. */
1714
1722
  gitignore?: boolean;
@@ -1719,182 +1727,182 @@ interface VisConfig {
1719
1727
  };
1720
1728
  };
1721
1729
  /**
1722
- * Supply chain security settings.
1723
- * These settings are inspired by pnpm's security features and are applied
1724
- * universally across all package managers (pnpm, npm, yarn, bun).
1725
- *
1726
- * For pnpm users: these map directly to pnpm-workspace.yaml settings.
1727
- * For npm/yarn/bun users: vis enforces these at the vis layer since
1728
- * those package managers lack native support.
1729
- */
1730
+ * Supply chain security settings.
1731
+ * These settings are inspired by pnpm's security features and are applied
1732
+ * universally across all package managers (pnpm, npm, yarn, bun).
1733
+ *
1734
+ * For pnpm users: these map directly to pnpm-workspace.yaml settings.
1735
+ * For npm/yarn/bun users: vis enforces these at the vis layer since
1736
+ * those package managers lack native support.
1737
+ */
1730
1738
  security?: {
1731
1739
  /**
1732
- * Packages whose policy findings have been reviewed and explicitly
1733
- * accepted. Matched against every policy unless `policies` narrows the
1734
- * scope. Replaces the legacy `security.socket.acceptedRisks` map.
1735
- *
1736
- * Key format: package name (`"lodash"`), name@version
1737
- * (`"lodash@4.17.21"`), or glob (`"@myorg/*"`). Unversioned keys match
1738
- * all versions of that package.
1739
- * @example
1740
- * ```
1741
- * acceptedRisks: {
1742
- * "some-risky-pkg": {
1743
- * reason: "Internal fork, low score expected",
1744
- * acceptedAt: "2026-03-15T10:00:00Z",
1745
- * acceptedScore: 0.25,
1746
- * policies: ["score"],
1747
- * expiresAt: "2026-12-31",
1748
- * },
1749
- * }
1750
- * ```
1751
- */
1740
+ * Packages whose policy findings have been reviewed and explicitly
1741
+ * accepted. Matched against every policy unless `policies` narrows the
1742
+ * scope. Replaces the legacy `security.socket.acceptedRisks` map.
1743
+ *
1744
+ * Key format: package name (`"lodash"`), name@version
1745
+ * (`"lodash@4.17.21"`), or glob (`"@myorg/*"`). Unversioned keys match
1746
+ * all versions of that package.
1747
+ * @example
1748
+ * ```
1749
+ * acceptedRisks: {
1750
+ * "some-risky-pkg": {
1751
+ * reason: "Internal fork, low score expected",
1752
+ * acceptedAt: "2026-03-15T10:00:00Z",
1753
+ * acceptedScore: 0.25,
1754
+ * policies: ["score"],
1755
+ * expiresAt: "2026-12-31",
1756
+ * },
1757
+ * }
1758
+ * ```
1759
+ */
1752
1760
  acceptedRisks?: Record<string, {
1753
1761
  /** ISO 8601 timestamp when the risk was accepted. */
1754
1762
  acceptedAt: string;
1755
1763
  /**
1756
- * The overall Socket.dev score at the time of acceptance,
1757
- * in the range `[0, 1]` (mirrors `policies.score.minimum`).
1758
- * Only relevant for the `score` policy; ignored elsewhere.
1759
- */
1764
+ * The overall Socket.dev score at the time of acceptance,
1765
+ * in the range `[0, 1]` (mirrors `policies.score.minimum`).
1766
+ * Only relevant for the `score` policy; ignored elsewhere.
1767
+ */
1760
1768
  acceptedScore?: number;
1761
1769
  /**
1762
- * ISO 8601 date (or datetime). After this point the acceptance
1763
- * stops applying and vis emits a warning. Leave undefined for
1764
- * non-expiring entries. Values that fail to parse as a Date
1765
- * are rejected by the loader rather than silently treated as
1766
- * "always expired".
1767
- */
1770
+ * ISO 8601 date (or datetime). After this point the acceptance
1771
+ * stops applying and vis emits a warning. Leave undefined for
1772
+ * non-expiring entries. Values that fail to parse as a Date
1773
+ * are rejected by the loader rather than silently treated as
1774
+ * "always expired".
1775
+ */
1768
1776
  expiresAt?: string;
1769
1777
  /**
1770
- * Which policies this acceptance covers. When undefined the
1771
- * acceptance applies to every policy finding on this package.
1772
- */
1778
+ * Which policies this acceptance covers. When undefined the
1779
+ * acceptance applies to every policy finding on this package.
1780
+ */
1773
1781
  policies?: PolicyName[];
1774
1782
  /** User-provided reason for accepting the risk. */
1775
1783
  reason: string;
1776
1784
  }>;
1777
1785
  /**
1778
- * Map of bin names (or `pkg#bin` qualifiers) blessed for shadowing.
1779
- * When two installed packages expose the same bin name, vis flags
1780
- * the collision in `vis security list` and the post-install drift
1781
- * report — set the bin (or `pkg#bin`) to `true` here to suppress
1782
- * the warning once you've reviewed the conflict.
1783
- *
1784
- * Port of LavaMoat allow-scripts' experimental `allowBins`.
1785
- * Bare names match any conflicting bin with that name; the
1786
- * `pkg#bin` form scopes the approval to a single package's bin.
1787
- * @example
1788
- * ```
1789
- * allowBins: {
1790
- * tsc: true, // bless any 'tsc' bin
1791
- * "typescript#tsc": true, // bless only typescript's 'tsc'
1792
- * }
1793
- * ```
1794
- */
1786
+ * Map of bin names (or `pkg#bin` qualifiers) blessed for shadowing.
1787
+ * When two installed packages expose the same bin name, vis flags
1788
+ * the collision in `vis security list` and the post-install drift
1789
+ * report — set the bin (or `pkg#bin`) to `true` here to suppress
1790
+ * the warning once you've reviewed the conflict.
1791
+ *
1792
+ * Port of LavaMoat allow-scripts' experimental `allowBins`.
1793
+ * Bare names match any conflicting bin with that name; the
1794
+ * `pkg#bin` form scopes the approval to a single package's bin.
1795
+ * @example
1796
+ * ```
1797
+ * allowBins: {
1798
+ * tsc: true, // bless any 'tsc' bin
1799
+ * "typescript#tsc": true, // bless only typescript's 'tsc'
1800
+ * }
1801
+ * ```
1802
+ */
1795
1803
  allowBins?: Record<string, boolean>;
1796
1804
  /**
1797
- * Offline OSV advisory + `vis audit` configuration.
1798
- *
1799
- * Controls `vis audit --offline` and `vis advisories sync` behavior:
1800
- * - `audit.advisories.source` is the OSV mirror to download from. It
1801
- * must be `https://` and resolve to a host in `allowedHosts` (or one
1802
- * of the built-in defaults).
1803
- * - `audit.offlineByDefault` flips the default of `--offline`.
1804
- *
1805
- * Vulnerability severity gating and reachability filtering live under
1806
- * `policies.vulnerability` (see below).
1807
- */
1805
+ * Offline OSV advisory + `vis audit` configuration.
1806
+ *
1807
+ * Controls `vis audit --offline` and `vis advisories sync` behavior:
1808
+ * - `audit.advisories.source` is the OSV mirror to download from. It
1809
+ * must be `https://` and resolve to a host in `allowedHosts` (or one
1810
+ * of the built-in defaults).
1811
+ * - `audit.offlineByDefault` flips the default of `--offline`.
1812
+ *
1813
+ * Vulnerability severity gating and reachability filtering live under
1814
+ * `policies.vulnerability` (see below).
1815
+ */
1808
1816
  audit?: {
1809
1817
  /**
1810
- * Offline advisory cache settings.
1811
- */
1818
+ * Offline advisory cache settings.
1819
+ */
1812
1820
  advisories?: {
1813
1821
  /**
1814
- * Extra hosts permitted as `audit.advisories.source`. The
1815
- * built-in allowlist is enforced even if this field is
1816
- * omitted; entries here add to it.
1817
- * @example ["mirror.corp.example.com"]
1818
- */
1822
+ * Extra hosts permitted as `audit.advisories.source`. The
1823
+ * built-in allowlist is enforced even if this field is
1824
+ * omitted; entries here add to it.
1825
+ * @example ["mirror.corp.example.com"]
1826
+ */
1819
1827
  allowedHosts?: string[];
1820
1828
  /**
1821
- * Bloom-filter prefilter for OSV `MAL-*` (malicious-package)
1822
- * advisories. Probes a ~380 KB filter fetched from
1823
- * `endevco/osv-bloom` and escalates hits to the existing
1824
- * advisory query path for `(name, version)` confirmation.
1825
- *
1826
- * Cost: ~380 KB on the wire, refreshed every 10 minutes
1827
- * upstream. False-positive rate is ~0.1%, so a typical
1828
- * 1000-package lockfile triggers zero or one extra
1829
- * round trip per audit.
1830
- *
1831
- * Independent of `audit.advisories.source` / `verify` —
1832
- * those control the full OSV ingest. The bloom is
1833
- * MAL-* only and aimed at cold-start preflight and
1834
- * ephemeral CI runners that haven't synced the full DB.
1835
- */
1829
+ * Bloom-filter prefilter for OSV `MAL-*` (malicious-package)
1830
+ * advisories. Probes a ~380 KB filter fetched from
1831
+ * `endevco/osv-bloom` and escalates hits to the existing
1832
+ * advisory query path for `(name, version)` confirmation.
1833
+ *
1834
+ * Cost: ~380 KB on the wire, refreshed every 10 minutes
1835
+ * upstream. False-positive rate is ~0.1%, so a typical
1836
+ * 1000-package lockfile triggers zero or one extra
1837
+ * round trip per audit.
1838
+ *
1839
+ * Independent of `audit.advisories.source` / `verify` —
1840
+ * those control the full OSV ingest. The bloom is
1841
+ * MAL-* only and aimed at cold-start preflight and
1842
+ * ephemeral CI runners that haven't synced the full DB.
1843
+ */
1836
1844
  bloom?: {
1837
1845
  /**
1838
- * Extra hosts permitted as `bloom.source`. The
1839
- * built-in allowlist (`endevco.github.io`) is enforced
1840
- * even if this field is omitted; entries here add to it.
1841
- */
1846
+ * Extra hosts permitted as `bloom.source`. The
1847
+ * built-in allowlist (`endevco.github.io`) is enforced
1848
+ * even if this field is omitted; entries here add to it.
1849
+ */
1842
1850
  allowedHosts?: string[];
1843
1851
  /**
1844
- * Prefilter mode:
1845
- * - `off`: never run the bloom check.
1846
- * - `on`: run when a local filter is cached; on
1847
- * fetch failure, fall back to the cached filter or
1848
- * skip the prefilter (audit continues against the
1849
- * non-bloom path).
1850
- * - `required`: hard-fail the audit when the bloom
1851
- * refresh fails or the local cache is missing.
1852
- * Use in hardened CI together with
1853
- * `audit.advisories.source`.
1854
- * @default "off"
1855
- */
1852
+ * Prefilter mode:
1853
+ * - `off`: never run the bloom check.
1854
+ * - `on`: run when a local filter is cached; on
1855
+ * fetch failure, fall back to the cached filter or
1856
+ * skip the prefilter (audit continues against the
1857
+ * non-bloom path).
1858
+ * - `required`: hard-fail the audit when the bloom
1859
+ * refresh fails or the local cache is missing.
1860
+ * Use in hardened CI together with
1861
+ * `audit.advisories.source`.
1862
+ * @default "off"
1863
+ */
1856
1864
  mode?: "off" | "on" | "required";
1857
1865
  /**
1858
- * Bloom mirror base URL (no trailing slash). Defaults
1859
- * to the public `endevco/osv-bloom` GH Pages site.
1860
- * Override only if you mirror the bloom artifacts
1861
- * internally; the hostname must appear in
1862
- * `allowedHosts`.
1863
- * @default "https://endevco.github.io/osv-bloom"
1864
- */
1866
+ * Bloom mirror base URL (no trailing slash). Defaults
1867
+ * to the public `endevco/osv-bloom` GH Pages site.
1868
+ * Override only if you mirror the bloom artifacts
1869
+ * internally; the hostname must appear in
1870
+ * `allowedHosts`.
1871
+ * @default "https://endevco.github.io/osv-bloom"
1872
+ */
1865
1873
  source?: string;
1866
1874
  };
1867
1875
  /**
1868
- * Number of hours after `lastSyncIso` before `vis audit`
1869
- * prints a "your advisory cache may be stale" notice.
1870
- * `vis audit` never auto-syncs — the user runs
1871
- * `vis advisories sync` themselves.
1872
- * @default 24
1873
- */
1876
+ * Number of hours after `lastSyncIso` before `vis audit`
1877
+ * prints a "your advisory cache may be stale" notice.
1878
+ * `vis audit` never auto-syncs — the user runs
1879
+ * `vis advisories sync` themselves.
1880
+ * @default 24
1881
+ */
1874
1882
  refreshIntervalHours?: number;
1875
1883
  /**
1876
- * OSV mirror base URL (no trailing slash). Defaults to the
1877
- * public Google Cloud Storage bucket. Override to point at a
1878
- * corporate mirror; the hostname must appear in `allowedHosts`
1879
- * (or one of the built-in defaults) and the scheme must be
1880
- * `https://`.
1881
- * @default "https://osv-vulnerabilities.storage.googleapis.com"
1882
- */
1884
+ * OSV mirror base URL (no trailing slash). Defaults to the
1885
+ * public Google Cloud Storage bucket. Override to point at a
1886
+ * corporate mirror; the hostname must appear in `allowedHosts`
1887
+ * (or one of the built-in defaults) and the scheme must be
1888
+ * `https://`.
1889
+ * @default "https://osv-vulnerabilities.storage.googleapis.com"
1890
+ */
1883
1891
  source?: string;
1884
1892
  /**
1885
- * Sigstore signature verification for the OSV dump.
1886
- * Requires the native binding to be built with the
1887
- * `verify-signatures` Cargo feature (default in the release
1888
- * build). Off by default — the upstream OSV bucket does not
1889
- * ship signatures today.
1890
- */
1893
+ * Sigstore signature verification for the OSV dump.
1894
+ * Requires the native binding to be built with the
1895
+ * `verify-signatures` Cargo feature (default in the release
1896
+ * build). Off by default — the upstream OSV bucket does not
1897
+ * ship signatures today.
1898
+ */
1891
1899
  verify?: {
1892
1900
  /**
1893
- * Enable signature verification. The sync flow downloads
1894
- * `&lt;eco>/all.zip.sig` next to the zip and aborts if it
1895
- * cannot verify against `expectedIssuer` / `expectedSubject`.
1896
- * @default false
1897
- */
1901
+ * Enable signature verification. The sync flow downloads
1902
+ * `&lt;eco>/all.zip.sig` next to the zip and aborts if it
1903
+ * cannot verify against `expectedIssuer` / `expectedSubject`.
1904
+ * @default false
1905
+ */
1898
1906
  enabled?: boolean;
1899
1907
  /** OIDC issuer that signed the bundle. */
1900
1908
  expectedIssuer?: string;
@@ -1903,111 +1911,111 @@ interface VisConfig {
1903
1911
  };
1904
1912
  };
1905
1913
  /**
1906
- * Gates for the auto-fix flow (`vis audit --fix` /
1907
- * `--fix-transitive`). The CLI prompts outside CI; inside CI
1908
- * the flags refuse to run unless `--yes` is set and, for
1909
- * transitives, `apply.transitive.enabled = true`.
1910
- */
1914
+ * Gates for the auto-fix flow (`vis audit --fix` /
1915
+ * `--fix-transitive`). The CLI prompts outside CI; inside CI
1916
+ * the flags refuse to run unless `--yes` is set and, for
1917
+ * transitives, `apply.transitive.enabled = true`.
1918
+ */
1911
1919
  apply?: {
1912
1920
  /**
1913
- * Gates for `vis audit --fix-transitive`. Two-lock: the
1914
- * CLI requires `--yes` AND this flag set to `true` before
1915
- * it will rewrite override entries in CI.
1916
- */
1921
+ * Gates for `vis audit --fix-transitive`. Two-lock: the
1922
+ * CLI requires `--yes` AND this flag set to `true` before
1923
+ * it will rewrite override entries in CI.
1924
+ */
1917
1925
  transitive?: {
1918
1926
  /**
1919
- * When true, allows `--fix-transitive` to run in CI
1920
- * environments. Defaults to false because rewriting
1921
- * overrides is a higher blast radius than bumping a
1922
- * direct dep.
1923
- * @default false
1924
- */
1927
+ * When true, allows `--fix-transitive` to run in CI
1928
+ * environments. Defaults to false because rewriting
1929
+ * overrides is a higher blast radius than bumping a
1930
+ * direct dep.
1931
+ * @default false
1932
+ */
1925
1933
  enabled?: boolean;
1926
1934
  };
1927
1935
  };
1928
1936
  /**
1929
- * Vulnerability scanner backend.
1930
- *
1931
- * - `auto` (default): delegate to `aube audit` when aube is the
1932
- * active installer (its scanner reads the same lockfile and
1933
- * produces equivalent severity ratings); otherwise run vis's
1934
- * own OSV/Socket scanner.
1935
- * - `aube`: always delegate to `aube audit`. Errors if `aube` is
1936
- * not on PATH.
1937
- * - `vis`: always use vis's built-in scanner — never delegate.
1938
- *
1939
- * Delegation avoids redundant work (aube already has a
1940
- * full-fidelity audit pass that respects its own exclusions
1941
- * via `aube-workspace.yaml::auditConfig`) and lets users get
1942
- * a single, consistent result regardless of which entry point
1943
- * they invoke.
1944
- * @default "auto"
1945
- */
1937
+ * Vulnerability scanner backend.
1938
+ *
1939
+ * - `auto` (default): delegate to `aube audit` when aube is the
1940
+ * active installer (its scanner reads the same lockfile and
1941
+ * produces equivalent severity ratings); otherwise run vis's
1942
+ * own OSV/Socket scanner.
1943
+ * - `aube`: always delegate to `aube audit`. Errors if `aube` is
1944
+ * not on PATH.
1945
+ * - `vis`: always use vis's built-in scanner — never delegate.
1946
+ *
1947
+ * Delegation avoids redundant work (aube already has a
1948
+ * full-fidelity audit pass that respects its own exclusions
1949
+ * via `aube-workspace.yaml::auditConfig`) and lets users get
1950
+ * a single, consistent result regardless of which entry point
1951
+ * they invoke.
1952
+ * @default "auto"
1953
+ */
1946
1954
  backend?: "aube" | "auto" | "vis";
1947
1955
  /**
1948
- * When true, `vis audit` skips network calls and queries the
1949
- * offline cache. Equivalent to the CLI `--offline` flag.
1950
- * @default false
1951
- */
1956
+ * When true, `vis audit` skips network calls and queries the
1957
+ * offline cache. Equivalent to the CLI `--offline` flag.
1958
+ * @default false
1959
+ */
1952
1960
  offlineByDefault?: boolean;
1953
1961
  };
1954
1962
  /**
1955
- * When true, prevents transitive dependencies from using exotic sources
1956
- * (git repositories, direct tarball URLs). Only direct dependencies may
1957
- * use such sources. Equivalent to pnpm's `blockExoticSubdeps`.
1958
- * @default false
1959
- */
1963
+ * When true, prevents transitive dependencies from using exotic sources
1964
+ * (git repositories, direct tarball URLs). Only direct dependencies may
1965
+ * use such sources. Equivalent to pnpm's `blockExoticSubdeps`.
1966
+ * @default false
1967
+ */
1960
1968
  blockExoticSubdeps?: boolean;
1961
1969
  /**
1962
- * deps.dev (Google Open Source Insights) data-source configuration.
1963
- * Public, unauthenticated; pulls Scorecard data + advisories from
1964
- * `api.deps.dev`. Complements or replaces Socket.dev. Heavily cached.
1965
- * @see https://docs.deps.dev/api/v3/
1966
- */
1970
+ * deps.dev (Google Open Source Insights) data-source configuration.
1971
+ * Public, unauthenticated; pulls Scorecard data + advisories from
1972
+ * `api.deps.dev`. Complements or replaces Socket.dev. Heavily cached.
1973
+ * @see https://docs.deps.dev/api/v3/
1974
+ */
1967
1975
  depsDev?: {
1968
1976
  /**
1969
- * Cache TTL for advisory entries (immutable once published). 7 days.
1970
- * @default 604800000
1971
- */
1977
+ * Cache TTL for advisory entries (immutable once published). 7 days.
1978
+ * @default 604800000
1979
+ */
1972
1980
  advisoryCacheTtlMs?: number;
1973
1981
  /**
1974
- * Enable deps.dev scanning on install/update/check/audit commands.
1975
- * @default false
1976
- */
1982
+ * Enable deps.dev scanning on install/update/check/audit commands.
1983
+ * @default false
1984
+ */
1977
1985
  enabled?: boolean;
1978
1986
  /**
1979
- * Cache TTL for OpenSSF Scorecard project data (refreshes weekly). 24 hours.
1980
- * @default 86400000
1981
- */
1987
+ * Cache TTL for OpenSSF Scorecard project data (refreshes weekly). 24 hours.
1988
+ * @default 86400000
1989
+ */
1982
1990
  projectCacheTtlMs?: number;
1983
1991
  /**
1984
- * Request timeout in milliseconds.
1985
- * @default 15000
1986
- */
1992
+ * Request timeout in milliseconds.
1993
+ * @default 15000
1994
+ */
1987
1995
  timeoutMs?: number;
1988
1996
  /**
1989
- * Cache TTL for npm version metadata (immutable). 7 days.
1990
- * @default 604800000
1991
- */
1997
+ * Cache TTL for npm version metadata (immutable). 7 days.
1998
+ * @default 604800000
1999
+ */
1992
2000
  versionCacheTtlMs?: number;
1993
2001
  };
1994
2002
  /**
1995
- * Package names exempted from the `blockExoticSubdeps` check.
1996
- * Bare names and a trailing `*` glob (`@scope/*`) are supported.
1997
- * Use for an internal package legitimately published as a git or
1998
- * tarball dependency.
1999
- * @example ["@myorg/legacy", "internal-*"]
2000
- */
2003
+ * Package names exempted from the `blockExoticSubdeps` check.
2004
+ * Bare names and a trailing `*` glob (`@scope/*`) are supported.
2005
+ * Use for an internal package legitimately published as a git or
2006
+ * tarball dependency.
2007
+ * @example ["@myorg/legacy", "internal-*"]
2008
+ */
2001
2009
  exoticSubdepsAllow?: string[];
2002
2010
  /**
2003
- * Pre-install marshall pipeline — packument-derived supply-chain
2004
- * gates (author, provenance, s1ngularity, new-bin, metadata,
2005
- * downloads, expired-domains, signatures, archived-repo) that run before
2006
- * `vis add` / `vis install &lt;pkg>` / `vis update &lt;pkg>` hand off to
2007
- * the underlying package manager. Every entry is optional; omit a
2008
- * key and the marshall runs with defaults. Set `enabled: false`
2009
- * on a specific marshall to skip it without touching env vars.
2010
- */
2011
+ * Pre-install marshall pipeline — packument-derived supply-chain
2012
+ * gates (author, provenance, s1ngularity, new-bin, metadata,
2013
+ * downloads, expired-domains, signatures, archived-repo) that run before
2014
+ * `vis add` / `vis install &lt;pkg>` / `vis update &lt;pkg>` hand off to
2015
+ * the underlying package manager. Every entry is optional; omit a
2016
+ * key and the marshall runs with defaults. Set `enabled: false`
2017
+ * on a specific marshall to skip it without touching env vars.
2018
+ */
2011
2019
  marshalls?: {
2012
2020
  /** Archived-repo marshall (GitHub repository status). */
2013
2021
  archivedRepo?: {
@@ -2020,11 +2028,13 @@ interface VisConfig {
2020
2028
  };
2021
2029
  /** Author / publisher heuristics. */
2022
2030
  author?: {
2023
- allowlist?: string[]; /** Days since the publisher's last release before flagging as error. */
2031
+ allowlist?: string[];
2032
+ /** Days since the publisher's last release before flagging as error. */
2024
2033
  dormantErrorDays?: number;
2025
2034
  /** Days since the publisher's last release before flagging as warning. */
2026
2035
  dormantWarnDays?: number;
2027
- enabled?: boolean; /** Window for the "new publisher on an established package" check. */
2036
+ enabled?: boolean;
2037
+ /** Window for the "new publisher on an established package" check. */
2028
2038
  newPublisherWindowDays?: number;
2029
2039
  /** Days since the resolved version was published — error threshold. */
2030
2040
  recentVersionErrorDays?: number;
@@ -2039,7 +2049,8 @@ interface VisConfig {
2039
2049
  /** Monthly download-count floor. */
2040
2050
  downloads?: {
2041
2051
  allowlist?: string[];
2042
- enabled?: boolean; /** Below this monthly count → error (default: 20). */
2052
+ enabled?: boolean;
2053
+ /** Below this monthly count → error (default: 20). */
2043
2054
  errorThreshold?: number;
2044
2055
  /** Below this monthly count → warning (default: 1000). */
2045
2056
  warnThreshold?: number;
@@ -2048,14 +2059,17 @@ interface VisConfig {
2048
2059
  expiredDomains?: {
2049
2060
  /** Domains exempted from the check (legacy / internal). */
2050
2061
  allowDomains?: string[];
2051
- allowlist?: string[]; /** DNS resolvers to query (default: system). */
2062
+ allowlist?: string[];
2063
+ /** DNS resolvers to query (default: system). */
2052
2064
  dnsServers?: string[];
2053
- enabled?: boolean; /** Per-domain DNS timeout (default: 5000). */
2065
+ enabled?: boolean;
2066
+ /** Per-domain DNS timeout (default: 5000). */
2054
2067
  timeoutMs?: number;
2055
2068
  };
2056
2069
  /** README / license / repository presence checks. */
2057
2070
  metadata?: {
2058
- allowlist?: string[]; /** Subset of checks to run. Default: all three. */
2071
+ allowlist?: string[];
2072
+ /** Subset of checks to run. Default: all three. */
2059
2073
  checks?: ("license" | "readme" | "repo")[];
2060
2074
  enabled?: boolean;
2061
2075
  };
@@ -2067,7 +2081,8 @@ interface VisConfig {
2067
2081
  /** Whole-package age heuristics (newly created / unmaintained). */
2068
2082
  packageAge?: {
2069
2083
  allowlist?: string[];
2070
- enabled?: boolean; /** Package created fewer than this many days ago → error. Default 22. */
2084
+ enabled?: boolean;
2085
+ /** Package created fewer than this many days ago → error. Default 22. */
2071
2086
  newPackageDays?: number;
2072
2087
  /** No publish within this many days → warning. Default 365. */
2073
2088
  unmaintainedDays?: number;
@@ -2078,22 +2093,23 @@ interface VisConfig {
2078
2093
  enabled?: boolean;
2079
2094
  };
2080
2095
  /**
2081
- * Composite "compromised-publish shape" detector — flags a single
2082
- * version that simultaneously introduced/changed an install hook
2083
- * AND dropped the provenance attestation a prior stable version
2084
- * carried (the August 2025 s1ngularity / Nx fingerprint).
2085
- */
2096
+ * Composite "compromised-publish shape" detector — flags a single
2097
+ * version that simultaneously introduced/changed an install hook
2098
+ * AND dropped the provenance attestation a prior stable version
2099
+ * carried (the August 2025 s1ngularity / Nx fingerprint).
2100
+ */
2086
2101
  s1ngularity?: {
2087
2102
  allowlist?: string[];
2088
2103
  enabled?: boolean;
2089
2104
  };
2090
2105
  /**
2091
- * ECDSA P-256 verification against npm's signing keys. Disabled
2092
- * by default because npm coverage still has gaps that produce
2093
- * noisy warnings on legitimate packages.
2094
- */
2106
+ * ECDSA P-256 verification against npm's signing keys. Disabled
2107
+ * by default because npm coverage still has gaps that produce
2108
+ * noisy warnings on legitimate packages.
2109
+ */
2095
2110
  signatures?: {
2096
- allowlist?: string[]; /** Default: marshall is *off*. Set true to enable. */
2111
+ allowlist?: string[];
2112
+ /** Default: marshall is *off*. Set true to enable. */
2097
2113
  enabled?: boolean;
2098
2114
  /** Override the keys endpoint (default: npm registry). */
2099
2115
  keysUrl?: string;
@@ -2102,313 +2118,313 @@ interface VisConfig {
2102
2118
  };
2103
2119
  };
2104
2120
  /**
2105
- * When true, `security.policies.installScripts.allow` keys are matched
2106
- * as `name@version`. A version bump on an approved package drops it from
2107
- * the allowlist until the new version is explicitly re-approved (port
2108
- * of LavaMoat allow-scripts' version-aware policy matcher).
2109
- *
2110
- * After a version bump, run `vis approve-builds` or `vis security list`
2111
- * — both surface a "Version drift" block with the suggested new key
2112
- * (`old-key → new-key`) so you can update `vis.config.ts` by hand.
2113
- * @default false
2114
- */
2121
+ * When true, `security.policies.installScripts.allow` keys are matched
2122
+ * as `name@version`. A version bump on an approved package drops it from
2123
+ * the allowlist until the new version is explicitly re-approved (port
2124
+ * of LavaMoat allow-scripts' version-aware policy matcher).
2125
+ *
2126
+ * After a version bump, run `vis approve-builds` or `vis security list`
2127
+ * — both surface a "Version drift" block with the suggested new key
2128
+ * (`old-key → new-key`) so you can update `vis.config.ts` by hand.
2129
+ * @default false
2130
+ */
2115
2131
  pinVersions?: boolean;
2116
2132
  /**
2117
- * Supply-chain policy gates. Each sub-block enables one policy and
2118
- * configures its behavior. When a sub-block is omitted the policy is
2119
- * inactive. `acceptedRisks` (above) silences specific packages without
2120
- * disabling a policy globally.
2121
- *
2122
- * The 8 policies are inspired by Socket.dev's classification:
2123
- * - `malware` — Socket-flagged malicious packages
2124
- * - `firstSeen` — packages published less than N minutes ago
2125
- * - `unexpectedDeps` — packages outside an allow-list / baseline
2126
- * - `publisherChange` — maintainer set changed between installs
2127
- * - `installScripts` — preinstall/install/postinstall scripts
2128
- * - `score` — Socket overall score below threshold
2129
- * - `vulnerability` — OSV vulnerability findings
2130
- * - `license` — SPDX allow / deny lists
2131
- */
2133
+ * Supply-chain policy gates. Each sub-block enables one policy and
2134
+ * configures its behavior. When a sub-block is omitted the policy is
2135
+ * inactive. `acceptedRisks` (above) silences specific packages without
2136
+ * disabling a policy globally.
2137
+ *
2138
+ * The 8 policies are inspired by Socket.dev's classification:
2139
+ * - `malware` — Socket-flagged malicious packages
2140
+ * - `firstSeen` — packages published less than N minutes ago
2141
+ * - `unexpectedDeps` — packages outside an allow-list / baseline
2142
+ * - `publisherChange` — maintainer set changed between installs
2143
+ * - `installScripts` — preinstall/install/postinstall scripts
2144
+ * - `score` — Socket overall score below threshold
2145
+ * - `vulnerability` — OSV vulnerability findings
2146
+ * - `license` — SPDX allow / deny lists
2147
+ */
2132
2148
  policies?: {
2133
2149
  /**
2134
- * Minimum number of minutes that must pass after a version is
2135
- * published before vis will allow installation. Migrated from
2136
- * the legacy `security.minimumReleaseAge` field. Equivalent to
2137
- * pnpm's `minimumReleaseAge`.
2138
- * @default 0
2139
- * @example { minutes: 1440, exclude: ["@myorg/*"] } // 24 hours
2140
- */
2150
+ * Minimum number of minutes that must pass after a version is
2151
+ * published before vis will allow installation. Migrated from
2152
+ * the legacy `security.minimumReleaseAge` field. Equivalent to
2153
+ * pnpm's `minimumReleaseAge`.
2154
+ * @default 0
2155
+ * @example { minutes: 1440, exclude: ["@myorg/*"] } // 24 hours
2156
+ */
2141
2157
  firstSeen?: {
2142
2158
  /**
2143
- * Package names/patterns excluded from the firstSeen check.
2144
- * Equivalent to pnpm's `minimumReleaseAgeExclude`.
2145
- * @example ["webpack", "react", "@myorg/*"]
2146
- */
2159
+ * Package names/patterns excluded from the firstSeen check.
2160
+ * Equivalent to pnpm's `minimumReleaseAgeExclude`.
2161
+ * @example ["webpack", "react", "@myorg/*"]
2162
+ */
2147
2163
  exclude?: string[];
2148
2164
  /** Minutes after publish before install is allowed. */
2149
2165
  minutes?: number;
2150
2166
  };
2151
2167
  /**
2152
- * Build-script (pre/install/postinstall/prepare) controls.
2153
- * Migrated from the legacy `security.allowBuilds` /
2154
- * `security.strictDepBuilds` fields.
2155
- * @example { allow: { esbuild: true }, strict: true }
2156
- */
2168
+ * Build-script (pre/install/postinstall/prepare) controls.
2169
+ * Migrated from the legacy `security.allowBuilds` /
2170
+ * `security.strictDepBuilds` fields.
2171
+ * @example { allow: { esbuild: true }, strict: true }
2172
+ */
2157
2173
  installScripts?: {
2158
2174
  /**
2159
- * Map of package names/patterns to allow (true) or deny
2160
- * (false) build scripts. Packages not listed are denied
2161
- * by default. Equivalent to pnpm's `allowBuilds`.
2162
- */
2175
+ * Map of package names/patterns to allow (true) or deny
2176
+ * (false) build scripts. Packages not listed are denied
2177
+ * by default. Equivalent to pnpm's `allowBuilds`.
2178
+ */
2163
2179
  allow?: Record<string, boolean>;
2164
2180
  /**
2165
- * When true, installation will fail (exit non-zero) if any
2166
- * dependencies have unreviewed build scripts. Equivalent to
2167
- * pnpm's `strictDepBuilds`.
2168
- * @default false
2169
- */
2181
+ * When true, installation will fail (exit non-zero) if any
2182
+ * dependencies have unreviewed build scripts. Equivalent to
2183
+ * pnpm's `strictDepBuilds`.
2184
+ * @default false
2185
+ */
2170
2186
  strict?: boolean;
2171
2187
  };
2172
2188
  /**
2173
- * SPDX license allow / deny lists. Deny wins on any sub-license
2174
- * match in SPDX expressions (`(MIT OR GPL-3.0)` against
2175
- * `deny: ["GPL-3.0"]` is blocked). Packages with no declared
2176
- * license are flagged when `allow` is set.
2177
- * @example
2178
- * ```
2179
- * license: {
2180
- * allow: ["MIT", "Apache-2.0", "BSD-3-Clause"],
2181
- * deny: ["GPL-3.0", "AGPL-3.0"],
2182
- * }
2183
- * ```
2184
- */
2189
+ * SPDX license allow / deny lists. Deny wins on any sub-license
2190
+ * match in SPDX expressions (`(MIT OR GPL-3.0)` against
2191
+ * `deny: ["GPL-3.0"]` is blocked). Packages with no declared
2192
+ * license are flagged when `allow` is set.
2193
+ * @example
2194
+ * ```
2195
+ * license: {
2196
+ * allow: ["MIT", "Apache-2.0", "BSD-3-Clause"],
2197
+ * deny: ["GPL-3.0", "AGPL-3.0"],
2198
+ * }
2199
+ * ```
2200
+ */
2185
2201
  license?: {
2186
2202
  /**
2187
- * SPDX identifiers that are explicitly permitted. When set,
2188
- * any package whose declared license is not on this list is
2189
- * blocked.
2190
- */
2203
+ * SPDX identifiers that are explicitly permitted. When set,
2204
+ * any package whose declared license is not on this list is
2205
+ * blocked.
2206
+ */
2191
2207
  allow?: string[];
2192
2208
  /**
2193
- * SPDX identifiers that are explicitly forbidden. Always
2194
- * wins over `allow` when both reference the same identifier.
2195
- */
2209
+ * SPDX identifiers that are explicitly forbidden. Always
2210
+ * wins over `allow` when both reference the same identifier.
2211
+ */
2196
2212
  deny?: string[];
2197
2213
  };
2198
2214
  /**
2199
- * Behavior when the Socket.dev feed flags a package as malicious
2200
- * (`alerts[].type === "Malware"`).
2201
- *
2202
- * The default is cross-field: `{ mode: "block" }` whenever
2203
- * `security.socket.enabled !== false` (the engine cannot evaluate
2204
- * malware without Socket data), and `"off"` otherwise. Consumers
2205
- * resolve this default at evaluation time.
2206
- */
2215
+ * Behavior when the Socket.dev feed flags a package as malicious
2216
+ * (`alerts[].type === "Malware"`).
2217
+ *
2218
+ * The default is cross-field: `{ mode: "block" }` whenever
2219
+ * `security.socket.enabled !== false` (the engine cannot evaluate
2220
+ * malware without Socket data), and `"off"` otherwise. Consumers
2221
+ * resolve this default at evaluation time.
2222
+ */
2207
2223
  malware?: {
2208
2224
  /**
2209
- * - `"block"` — emit a block decision.
2210
- * - `"warn"` — surface as a warning; do not gate exit code.
2211
- * - `"off"` — disable the policy entirely.
2212
- */
2225
+ * - `"block"` — emit a block decision.
2226
+ * - `"warn"` — surface as a warning; do not gate exit code.
2227
+ * - `"off"` — disable the policy entirely.
2228
+ */
2213
2229
  mode?: "block" | "off" | "warn";
2214
2230
  };
2215
2231
  /**
2216
- * Trust-level checking for package publishing. Migrated from the
2217
- * legacy `security.trustPolicy*` fields. Equivalent to pnpm's
2218
- * `trustPolicy`.
2219
- * @example { mode: "no-downgrade", ignoreAfter: 43200 } // 30 days
2220
- */
2232
+ * Trust-level checking for package publishing. Migrated from the
2233
+ * legacy `security.trustPolicy*` fields. Equivalent to pnpm's
2234
+ * `trustPolicy`.
2235
+ * @example { mode: "no-downgrade", ignoreAfter: 43200 } // 30 days
2236
+ */
2221
2237
  publisherChange?: {
2222
2238
  /**
2223
- * Package selectors excluded from the check.
2224
- * Equivalent to pnpm's `trustPolicyExclude`.
2225
- * @example ["chokidar@4.0.3"]
2226
- */
2239
+ * Package selectors excluded from the check.
2240
+ * Equivalent to pnpm's `trustPolicyExclude`.
2241
+ * @example ["chokidar@4.0.3"]
2242
+ */
2227
2243
  exclude?: string[];
2228
2244
  /**
2229
- * Ignore packages published more than N minutes ago. Useful
2230
- * for older packages that pre-date provenance support.
2231
- * Equivalent to pnpm's `trustPolicyIgnoreAfter`.
2232
- */
2245
+ * Ignore packages published more than N minutes ago. Useful
2246
+ * for older packages that pre-date provenance support.
2247
+ * Equivalent to pnpm's `trustPolicyIgnoreAfter`.
2248
+ */
2233
2249
  ignoreAfter?: number;
2234
2250
  /**
2235
- * - `"off"` — no trust checking (default).
2236
- * - `"no-downgrade"` — block when a package's trust level
2237
- * has decreased compared to previous releases (e.g., was
2238
- * published by trusted publisher, now only has provenance).
2239
- */
2251
+ * - `"off"` — no trust checking (default).
2252
+ * - `"no-downgrade"` — block when a package's trust level
2253
+ * has decreased compared to previous releases (e.g., was
2254
+ * published by trusted publisher, now only has provenance).
2255
+ */
2240
2256
  mode?: "no-downgrade" | "off";
2241
2257
  };
2242
2258
  /**
2243
- * Socket.dev overall-score threshold. Packages scoring below
2244
- * `minimum` trigger a block decision (or interactive prompt
2245
- * during `vis add`). Migrated from the legacy
2246
- * `security.socket.minimumScore` field.
2247
- * @example { minimum: 0.4 }
2248
- */
2259
+ * Socket.dev overall-score threshold. Packages scoring below
2260
+ * `minimum` trigger a block decision (or interactive prompt
2261
+ * during `vis add`). Migrated from the legacy
2262
+ * `security.socket.minimumScore` field.
2263
+ * @example { minimum: 0.4 }
2264
+ */
2249
2265
  score?: {
2250
2266
  /**
2251
- * Minimum overall Socket.dev score (0–1). Set to 0 to
2252
- * disable the gate while keeping Socket data fetched.
2253
- *
2254
- * Consulted by `vis add`, `audit`, `doctor`, `check`, and
2255
- * `update`; resolved once in `buildSocketOptions`, then
2256
- * threaded through every consumer. Falls back to
2257
- * `DEFAULT_LOW_SCORE_THRESHOLD` (`0.4`) when unset.
2258
- */
2267
+ * Minimum overall Socket.dev score (0–1). Set to 0 to
2268
+ * disable the gate while keeping Socket data fetched.
2269
+ *
2270
+ * Consulted by `vis add`, `audit`, `doctor`, `check`, and
2271
+ * `update`; resolved once in `buildSocketOptions`, then
2272
+ * threaded through every consumer. Falls back to
2273
+ * `DEFAULT_LOW_SCORE_THRESHOLD` (`0.4`) when unset.
2274
+ */
2259
2275
  minimum?: number;
2260
2276
  };
2261
2277
  /**
2262
- * Net-new transitive dependency detection. Either provide a
2263
- * static allow-list, a baseline lockfile path (recommended), or
2264
- * both — the intersection is enforced.
2265
- * @example { baselineLockfile: "./security/lockfile.baseline.yaml" }
2266
- */
2278
+ * Net-new transitive dependency detection. Either provide a
2279
+ * static allow-list, a baseline lockfile path (recommended), or
2280
+ * both — the intersection is enforced.
2281
+ * @example { baselineLockfile: "./security/lockfile.baseline.yaml" }
2282
+ */
2267
2283
  unexpectedDeps?: {
2268
2284
  /**
2269
- * Allow-list of dependency names that may appear in the
2270
- * resolved package set. Glob patterns are supported.
2271
- * @example ["lodash", "axios", "@myorg/*"]
2272
- */
2285
+ * Allow-list of dependency names that may appear in the
2286
+ * resolved package set. Glob patterns are supported.
2287
+ * @example ["lodash", "axios", "@myorg/*"]
2288
+ */
2273
2289
  allow?: string[];
2274
2290
  /**
2275
- * Path (absolute or relative to the workspace root) to a
2276
- * baseline lockfile snapshot. The policy diffs the current
2277
- * lockfile against this baseline and flags any package that
2278
- * didn't exist before.
2279
- * @example "./security/lockfile.baseline.yaml"
2280
- */
2291
+ * Path (absolute or relative to the workspace root) to a
2292
+ * baseline lockfile snapshot. The policy diffs the current
2293
+ * lockfile against this baseline and flags any package that
2294
+ * didn't exist before.
2295
+ * @example "./security/lockfile.baseline.yaml"
2296
+ */
2281
2297
  baselineLockfile?: string;
2282
2298
  };
2283
2299
  /**
2284
- * OSV vulnerability gating. Migrated from the legacy
2285
- * `security.audit.failOn` + `security.audit.usage` fields.
2286
- */
2300
+ * OSV vulnerability gating. Migrated from the legacy
2301
+ * `security.audit.failOn` + `security.audit.usage` fields.
2302
+ */
2287
2303
  vulnerability?: {
2288
2304
  /**
2289
- * Severity threshold that makes `vis audit` exit non-zero.
2290
- * Equivalent to the CLI `--fail-on` flag.
2291
- * @example "high"
2292
- */
2305
+ * Severity threshold that makes `vis audit` exit non-zero.
2306
+ * Equivalent to the CLI `--fail-on` flag.
2307
+ * @example "high"
2308
+ */
2293
2309
  failOn?: "critical" | "high" | "low" | "medium";
2294
2310
  /**
2295
- * Reachability filter — only report vulnerabilities in
2296
- * packages the workspace statically imports.
2297
- */
2311
+ * Reachability filter — only report vulnerabilities in
2312
+ * packages the workspace statically imports.
2313
+ */
2298
2314
  usage?: {
2299
2315
  /**
2300
- * Packages to always treat as reachable even if no
2301
- * static import is found.
2302
- * @example ["esbuild", "webpack-cli"]
2303
- */
2316
+ * Packages to always treat as reachable even if no
2317
+ * static import is found.
2318
+ * @example ["esbuild", "webpack-cli"]
2319
+ */
2304
2320
  alwaysAssumeUsed?: string[];
2305
2321
  /**
2306
- * Enable the reachability filter by default. Equivalent
2307
- * to `--usage` on the CLI; `--no-usage` disables.
2308
- * @default false
2309
- */
2322
+ * Enable the reachability filter by default. Equivalent
2323
+ * to `--usage` on the CLI; `--no-usage` disables.
2324
+ * @default false
2325
+ */
2310
2326
  enabled?: boolean;
2311
2327
  };
2312
2328
  };
2313
2329
  };
2314
2330
  /**
2315
- * Which provider wins merge conflicts when multiple are enabled (e.g.
2316
- * both Socket.dev and deps.dev return data for the same package). The
2317
- * primary provider's `score` is kept; alerts from secondaries are
2318
- * appended and deduped by `key`. Defaults to whichever provider is
2319
- * enabled first in this order: socket → deps-dev → snyk.
2320
- */
2331
+ * Which provider wins merge conflicts when multiple are enabled (e.g.
2332
+ * both Socket.dev and deps.dev return data for the same package). The
2333
+ * primary provider's `score` is kept; alerts from secondaries are
2334
+ * appended and deduped by `key`. Defaults to whichever provider is
2335
+ * enabled first in this order: socket → deps-dev → snyk.
2336
+ */
2321
2337
  primaryProvider?: "deps-dev" | "snyk" | "socket";
2322
2338
  /**
2323
- * Snyk data-source configuration. Snyk only contributes vulnerability
2324
- * data (no maintenance / quality / supply-chain / license signal);
2325
- * those axes stay neutral. Requires both an org id and an API token —
2326
- * if either is missing the provider is skipped.
2327
- * @see https://docs.snyk.io/snyk-api/using-specific-snyk-apis/issues-list-issues-for-a-package
2328
- */
2339
+ * Snyk data-source configuration. Snyk only contributes vulnerability
2340
+ * data (no maintenance / quality / supply-chain / license signal);
2341
+ * those axes stay neutral. Requires both an org id and an API token —
2342
+ * if either is missing the provider is skipped.
2343
+ * @see https://docs.snyk.io/snyk-api/using-specific-snyk-apis/issues-list-issues-for-a-package
2344
+ */
2329
2345
  snyk?: {
2330
2346
  /**
2331
- * Snyk API token. Set via VIS_SNYK_TOKEN environment variable or
2332
- * here.
2333
- */
2347
+ * Snyk API token. Set via VIS_SNYK_TOKEN environment variable or
2348
+ * here.
2349
+ */
2334
2350
  apiToken?: string;
2335
2351
  /**
2336
- * Snyk REST API version date sent as the `version` query param.
2337
- * @default "2024-10-15"
2338
- */
2352
+ * Snyk REST API version date sent as the `version` query param.
2353
+ * @default "2024-10-15"
2354
+ */
2339
2355
  apiVersion?: string;
2340
2356
  /**
2341
- * Cache TTL in milliseconds for Snyk issue lookups. 6 hours.
2342
- * @default 21600000
2343
- */
2357
+ * Cache TTL in milliseconds for Snyk issue lookups. 6 hours.
2358
+ * @default 21600000
2359
+ */
2344
2360
  cacheTtlMs?: number;
2345
2361
  /**
2346
- * Enable Snyk security scanning on install/update/check/audit
2347
- * commands.
2348
- * @default false
2349
- */
2362
+ * Enable Snyk security scanning on install/update/check/audit
2363
+ * commands.
2364
+ * @default false
2365
+ */
2350
2366
  enabled?: boolean;
2351
2367
  /**
2352
- * Snyk organization id (the REST endpoint is org-scoped). Set via
2353
- * VIS_SNYK_ORG environment variable or here.
2354
- */
2368
+ * Snyk organization id (the REST endpoint is org-scoped). Set via
2369
+ * VIS_SNYK_ORG environment variable or here.
2370
+ */
2355
2371
  orgId?: string;
2356
2372
  /**
2357
- * Request timeout in milliseconds for the Snyk API. 15 seconds.
2358
- * @default 15000
2359
- */
2373
+ * Request timeout in milliseconds for the Snyk API. 15 seconds.
2374
+ * @default 15000
2375
+ */
2360
2376
  timeoutMs?: number;
2361
2377
  };
2362
2378
  /**
2363
- * Socket.dev data-source configuration. Connection knobs only — score
2364
- * thresholds and accepted-risk overrides moved to `policies.score` and
2365
- * `security.acceptedRisks` respectively.
2366
- * @see https://socket.dev
2367
- */
2379
+ * Socket.dev data-source configuration. Connection knobs only — score
2380
+ * thresholds and accepted-risk overrides moved to `policies.score` and
2381
+ * `security.acceptedRisks` respectively.
2382
+ * @see https://socket.dev
2383
+ */
2368
2384
  socket?: {
2369
2385
  /**
2370
- * Custom Socket.dev API token. Falls back to the public API token.
2371
- * Set via VIS_SOCKET_TOKEN environment variable or here.
2372
- */
2386
+ * Custom Socket.dev API token. Falls back to the public API token.
2387
+ * Set via VIS_SOCKET_TOKEN environment variable or here.
2388
+ */
2373
2389
  apiToken?: string;
2374
2390
  /**
2375
- * Cache TTL in milliseconds for Socket.dev reports. 1 hour.
2376
- * @default 3600000
2377
- */
2391
+ * Cache TTL in milliseconds for Socket.dev reports. 1 hour.
2392
+ * @default 3600000
2393
+ */
2378
2394
  cacheTtlMs?: number;
2379
2395
  /**
2380
- * Enable Socket.dev security scanning on install/update/check commands.
2381
- * @default false
2382
- */
2396
+ * Enable Socket.dev security scanning on install/update/check commands.
2397
+ * @default false
2398
+ */
2383
2399
  enabled?: boolean;
2384
2400
  /**
2385
- * Request timeout in milliseconds for the Socket.dev API. 15 seconds.
2386
- * @default 15000
2387
- */
2401
+ * Request timeout in milliseconds for the Socket.dev API. 15 seconds.
2402
+ * @default 15000
2403
+ */
2388
2404
  timeoutMs?: number;
2389
2405
  };
2390
2406
  /**
2391
- * Package names to skip during typosquat detection.
2392
- * Use this for internal packages or known-safe names that happen to
2393
- * look similar to popular packages.
2394
- * @example ["my-internal-axois", "@myorg/recat"]
2395
- */
2407
+ * Package names to skip during typosquat detection.
2408
+ * Use this for internal packages or known-safe names that happen to
2409
+ * look similar to popular packages.
2410
+ * @example ["my-internal-axois", "@myorg/recat"]
2411
+ */
2396
2412
  typosquatAllowlist?: string[];
2397
2413
  };
2398
2414
  /**
2399
- * Share the cache between sibling git worktrees. When the workspace is a
2400
- * linked worktree (created with `git worktree add`), the cache root is
2401
- * relocated from `&lt;linkedRoot>/node_modules/.cache/vis` to the *main*
2402
- * worktree's `node_modules/.cache/vis`. Multiple parallel agents working in
2403
- * sibling worktrees then share a single cache instead of rebuilding the
2404
- * same hash N times.
2405
- *
2406
- * Single-checkout repos (where `.git` is a directory) are unaffected.
2407
- *
2408
- * Set to `false` to opt out — useful when worktrees deliberately need
2409
- * independent caches, e.g. for hermetic experiments.
2410
- * @default true
2411
- */
2415
+ * Share the cache between sibling git worktrees. When the workspace is a
2416
+ * linked worktree (created with `git worktree add`), the cache root is
2417
+ * relocated from `&lt;linkedRoot>/node_modules/.cache/vis` to the *main*
2418
+ * worktree's `node_modules/.cache/vis`. Multiple parallel agents working in
2419
+ * sibling worktrees then share a single cache instead of rebuilding the
2420
+ * same hash N times.
2421
+ *
2422
+ * Single-checkout repos (where `.git` is a directory) are unaffected.
2423
+ *
2424
+ * Set to `false` to opt out — useful when worktrees deliberately need
2425
+ * independent caches, e.g. for hermetic experiments.
2426
+ * @default true
2427
+ */
2412
2428
  sharedWorktreeCache?: boolean;
2413
2429
  /** sort-package-json command defaults */
2414
2430
  sortPackageJson?: {
@@ -2424,55 +2440,55 @@ interface VisConfig {
2424
2440
  sortScripts?: boolean;
2425
2441
  };
2426
2442
  /**
2427
- * Sponsorship notice shown after successful commands.
2428
- *
2429
- * vis prints a one-line "consider sponsoring visulima" notice at most
2430
- * once every 14 days (skipped in CI, non-TTY, and when
2431
- * `VIS_NO_SPONSOR=1` is set). Set `enabled: false` to silence it
2432
- * permanently for this workspace.
2433
- * @example
2434
- * ```
2435
- * sponsor: { enabled: false }
2436
- * ```
2437
- */
2443
+ * Sponsorship notice shown after successful commands.
2444
+ *
2445
+ * vis prints a one-line "consider sponsoring visulima" notice at most
2446
+ * once every 14 days (skipped in CI, non-TTY, and when
2447
+ * `VIS_NO_SPONSOR=1` is set). Set `enabled: false` to silence it
2448
+ * permanently for this workspace.
2449
+ * @example
2450
+ * ```
2451
+ * sponsor: { enabled: false }
2452
+ * ```
2453
+ */
2438
2454
  sponsor?: {
2439
2455
  /**
2440
- * Show the sponsor notice on successful command completion.
2441
- * @default true
2442
- */
2456
+ * Show the sponsor notice on successful command completion.
2457
+ * @default true
2458
+ */
2443
2459
  enabled?: boolean;
2444
2460
  };
2445
2461
  /**
2446
- * Staged file patterns and commands (replaces lint-staged).
2447
- *
2448
- * Accepts all lint-staged config forms:
2449
- * - `string` or `string[]` commands
2450
- * - Sync/async functions returning `string | string[]`
2451
- * - `{ title, task }` objects for named side-effect tasks
2452
- * - `{ command, perPackage }` to run a command once per owning workspace package (cwd = that package dir), and `{ command, cwd }` to pin a command to a fixed directory
2453
- * - Mixed arrays of strings and functions
2454
- * - A top-level generate-task function
2455
- */
2462
+ * Staged file patterns and commands (replaces lint-staged).
2463
+ *
2464
+ * Accepts all lint-staged config forms:
2465
+ * - `string` or `string[]` commands
2466
+ * - Sync/async functions returning `string | string[]`
2467
+ * - `{ title, task }` objects for named side-effect tasks
2468
+ * - `{ command, perPackage }` to run a command once per owning workspace package (cwd = that package dir), and `{ command, cwd }` to pin a command to a fixed directory
2469
+ * - Mixed arrays of strings and functions
2470
+ * - A top-level generate-task function
2471
+ */
2456
2472
  staged?: StagedConfig;
2457
2473
  /**
2458
- * When `true`, every task command is scanned for `${VAR}` / `$VAR`
2459
- * references before spawn. If a referenced var is unset in the
2460
- * task's effective env (envFile + service env + per-task `env` +
2461
- * `process.env`), the task fails with an actionable error
2462
- * naming the missing variable, instead of letting the shell
2463
- * silently substitute an empty string.
2464
- *
2465
- * Override per run with `--strict-env` / `--no-strict-env`.
2466
- * Override per target with `options.strictEnv`.
2467
- * @default false
2468
- */
2474
+ * When `true`, every task command is scanned for `${VAR}` / `$VAR`
2475
+ * references before spawn. If a referenced var is unset in the
2476
+ * task's effective env (envFile + service env + per-task `env` +
2477
+ * `process.env`), the task fails with an actionable error
2478
+ * naming the missing variable, instead of letting the shell
2479
+ * silently substitute an empty string.
2480
+ *
2481
+ * Override per run with `--strict-env` / `--no-strict-env`.
2482
+ * Override per target with `options.strictEnv`.
2483
+ * @default false
2484
+ */
2469
2485
  strictEnv?: boolean;
2470
2486
  /**
2471
- * Named bundles of target dependencies, referenceable from any task's
2472
- * `dependsOn`. `dependsOn: [{ group: "lint" }]` expands to every entry
2473
- * in the named group; nested groups are resolved recursively and a
2474
- * cycle raises during discovery.
2475
- */
2487
+ * Named bundles of target dependencies, referenceable from any task's
2488
+ * `dependsOn`. `dependsOn: [{ group: "lint" }]` expands to every entry
2489
+ * in the named group; nested groups are resolved recursively and a
2490
+ * cycle raises during discovery.
2491
+ */
2476
2492
  taskGroups?: Record<string, (string | {
2477
2493
  dependencies?: boolean;
2478
2494
  projects?: string | string[];
@@ -2481,130 +2497,130 @@ interface VisConfig {
2481
2497
  group: string;
2482
2498
  })[]>;
2483
2499
  /**
2484
- * Task runner options forwarded verbatim to `defaultTaskRunner`.
2485
- *
2486
- * Includes `remoteCache` (HTTP or REAPI gRPC backend), `cacheDirectory`,
2487
- * `parallel`, `globalEnv`, `globalInputs`, etc.
2488
- * See `TaskRunnerOptions` for the full surface.
2489
- */
2500
+ * Task runner options forwarded verbatim to `defaultTaskRunner`.
2501
+ *
2502
+ * Includes `remoteCache` (HTTP or REAPI gRPC backend), `cacheDirectory`,
2503
+ * `parallel`, `globalEnv`, `globalInputs`, etc.
2504
+ * See `TaskRunnerOptions` for the full surface.
2505
+ */
2490
2506
  taskRunner?: Partial<TaskRunnerOptions>;
2491
2507
  /**
2492
- * Workspace-wide task defaults keyed by target name. Applied universally
2493
- * to every project that exposes a matching target. Use `scopedTasks` when
2494
- * defaults should only apply to a subset of projects.
2495
- */
2508
+ * Workspace-wide task defaults keyed by target name. Applied universally
2509
+ * to every project that exposes a matching target. Use `scopedTasks` when
2510
+ * defaults should only apply to a subset of projects.
2511
+ */
2496
2512
  tasks?: Record<string, Partial<VisTargetConfiguration>>;
2497
2513
  /**
2498
- * Toolchain (Node / pnpm / python / rust / ...) management. vis
2499
- * delegates to whichever version manager (proto, mise, fnm, volta,
2500
- * asdf, nvm, corepack) the developer already has — it does not ship
2501
- * its own.
2502
- *
2503
- * Re-exported from `./toolchain` so the public config type stays
2504
- * in lockstep with the resolver implementation. `self-activate` is
2505
- * narrowed out of `preferredManager` here — it's auto-resolved for
2506
- * pnpm/yarn `packageManager` pins and isn't meaningful as an
2507
- * override.
2508
- */
2514
+ * Toolchain (Node / pnpm / python / rust / ...) management. vis
2515
+ * delegates to whichever version manager (proto, mise, fnm, volta,
2516
+ * asdf, nvm, corepack) the developer already has — it does not ship
2517
+ * its own.
2518
+ *
2519
+ * Re-exported from `./toolchain` so the public config type stays
2520
+ * in lockstep with the resolver implementation. `self-activate` is
2521
+ * narrowed out of `preferredManager` here — it's auto-resolved for
2522
+ * pnpm/yarn `packageManager` pins and isn't meaningful as an
2523
+ * override.
2524
+ */
2509
2525
  toolchain?: Omit<ToolchainConfig, "preferredManager"> & {
2510
2526
  readonly preferredManager?: Exclude<VersionManagerName, "self-activate">;
2511
2527
  };
2512
2528
  /** Terminal UI configuration */
2513
2529
  tui?: {
2514
2530
  /**
2515
- * Auto-exit the TUI after tasks complete.
2516
- * - `false`: Stay open until the user presses `q` (default)
2517
- * - `true`: Show quit dialog with 3-second countdown after completion
2518
- * - `number`: Show quit dialog with custom countdown in seconds
2519
- */
2531
+ * Auto-exit the TUI after tasks complete.
2532
+ * - `false`: Stay open until the user presses `q` (default)
2533
+ * - `true`: Show quit dialog with 3-second countdown after completion
2534
+ * - `number`: Show quit dialog with custom countdown in seconds
2535
+ */
2520
2536
  autoExit?: boolean | number;
2521
2537
  };
2522
2538
  /** Update command defaults */
2523
2539
  update?: {
2524
2540
  /**
2525
- * Dependency fields to scan for outdated packages.
2526
- * Beyond the standard fields, supports:
2527
- * - `"overrides"` (npm)
2528
- * - `"resolutions"` (yarn)
2529
- * - `"pnpm.overrides"`
2530
- * @default ["dependencies", "devDependencies", "optionalDependencies", "peerDependencies"]
2531
- */
2541
+ * Dependency fields to scan for outdated packages.
2542
+ * Beyond the standard fields, supports:
2543
+ * - `"overrides"` (npm)
2544
+ * - `"resolutions"` (yarn)
2545
+ * - `"pnpm.overrides"`
2546
+ * @default ["dependencies", "devDependencies", "optionalDependencies", "peerDependencies"]
2547
+ */
2532
2548
  depFields?: string[];
2533
2549
  exclude?: string[];
2534
2550
  format?: "json" | "minimal" | "table";
2535
2551
  /**
2536
- * Package names or glob patterns to permanently ignore during updates.
2537
- * Ignored packages are skipped and listed in the output so you know
2538
- * they were not checked.
2539
- * @example ["eslint", "@types/*"]
2540
- */
2552
+ * Package names or glob patterns to permanently ignore during updates.
2553
+ * Ignored packages are skipped and listed in the output so you know
2554
+ * they were not checked.
2555
+ * @example ["eslint", "@types/*"]
2556
+ */
2541
2557
  ignore?: string[];
2542
2558
  include?: string[];
2543
2559
  /**
2544
- * Include packages with pinned/exact versions (no `^` or `~` prefix).
2545
- * By default, pinned versions are skipped during update checks.
2546
- * @default false
2547
- */
2560
+ * Include packages with pinned/exact versions (no `^` or `~` prefix).
2561
+ * By default, pinned versions are skipped during update checks.
2562
+ * @default false
2563
+ */
2548
2564
  includeLocked?: boolean;
2549
2565
  install?: boolean;
2550
2566
  /**
2551
- * Maximum number of concurrent registry requests during outdated checks.
2552
- * Higher values speed up large workspaces but risk hitting registry rate
2553
- * limits or self-hosted Verdaccio caps.
2554
- * @default 8
2555
- */
2567
+ * Maximum number of concurrent registry requests during outdated checks.
2568
+ * Higher values speed up large workspaces but risk hitting registry rate
2569
+ * limits or self-hosted Verdaccio caps.
2570
+ * @default 8
2571
+ */
2556
2572
  maxConcurrentRequests?: number;
2557
2573
  /**
2558
- * Minimum number of minutes since a version was published before
2559
- * vis will consider it for updates. This mirrors pnpm's
2560
- * `minimumReleaseAge` — a single setting that applies to both
2561
- * install and update.
2562
- *
2563
- * Not set by default. If your package manager config
2564
- * (`pnpm-workspace.yaml`) has `minimumReleaseAge`, vis will
2565
- * read it from there as a fallback.
2566
- * @example 1440 // 24 hours
2567
- */
2574
+ * Minimum number of minutes since a version was published before
2575
+ * vis will consider it for updates. This mirrors pnpm's
2576
+ * `minimumReleaseAge` — a single setting that applies to both
2577
+ * install and update.
2578
+ *
2579
+ * Not set by default. If your package manager config
2580
+ * (`pnpm-workspace.yaml`) has `minimumReleaseAge`, vis will
2581
+ * read it from there as a fallback.
2582
+ * @example 1440 // 24 hours
2583
+ */
2568
2584
  minimumReleaseAge?: number;
2569
2585
  /**
2570
- * Package names/patterns excluded from the minimumReleaseAge check.
2571
- * @example ["webpack", "@myorg/*"]
2572
- */
2586
+ * Package names/patterns excluded from the minimumReleaseAge check.
2587
+ * @example ["webpack", "@myorg/*"]
2588
+ */
2573
2589
  minimumReleaseAgeExclude?: string[];
2574
2590
  /**
2575
- * Per-package or per-pattern update target overrides.
2576
- * Keys are exact package names, glob patterns, or regex patterns
2577
- * wrapped in `/` (e.g., `/^@vue/`).
2578
- * Values are `"latest"`, `"minor"`, or `"patch"`.
2579
- * @example { "typescript": "minor", "/^@vue/": "patch" }
2580
- */
2591
+ * Per-package or per-pattern update target overrides.
2592
+ * Keys are exact package names, glob patterns, or regex patterns
2593
+ * wrapped in `/` (e.g., `/^@vue/`).
2594
+ * Values are `"latest"`, `"minor"`, or `"patch"`.
2595
+ * @example { "typescript": "minor", "/^@vue/": "patch" }
2596
+ */
2581
2597
  packageMode?: Record<string, "latest" | "minor" | "patch">;
2582
2598
  prerelease?: boolean;
2583
2599
  /**
2584
- * Which release channels to consider when picking the target version.
2585
- * - `"stable"` (default) — only ship stable releases (no prereleases).
2586
- * - `"same"` — match the prerelease channel of the *current* range:
2587
- * if you're on `react@19.0.0-rc.1`, only `rc.*` candidates qualify;
2588
- * if you're on a stable, only stable candidates. Prevents
2589
- * accidentally promoting a prerelease pin to a stable major bump.
2590
- * - `"any"` — equivalent to `--prerelease`. Any channel is fair game.
2591
- *
2592
- * `--release-channel` on the CLI overrides this. If `prerelease: true`
2593
- * is set without `releaseChannel`, vis treats it as `"any"`.
2594
- * @default "stable"
2595
- */
2600
+ * Which release channels to consider when picking the target version.
2601
+ * - `"stable"` (default) — only ship stable releases (no prereleases).
2602
+ * - `"same"` — match the prerelease channel of the *current* range:
2603
+ * if you're on `react@19.0.0-rc.1`, only `rc.*` candidates qualify;
2604
+ * if you're on a stable, only stable candidates. Prevents
2605
+ * accidentally promoting a prerelease pin to a stable major bump.
2606
+ * - `"any"` — equivalent to `--prerelease`. Any channel is fair game.
2607
+ *
2608
+ * `--release-channel` on the CLI overrides this. If `prerelease: true`
2609
+ * is set without `releaseChannel`, vis treats it as `"any"`.
2610
+ * @default "stable"
2611
+ */
2596
2612
  releaseChannel?: "any" | "same" | "stable";
2597
2613
  security?: boolean;
2598
2614
  target?: "latest" | "minor" | "patch";
2599
2615
  };
2600
2616
  /**
2601
- * Minimum vis CLI version required by this workspace. When the
2602
- * running vis binary is older than this constraint, vis exits with
2603
- * an actionable error before executing any command.
2604
- *
2605
- * Accepts a semver range string (e.g. `">=1.0.0"`, `"^1.2.0"`).
2606
- * @example ">=1.0.0"
2607
- */
2617
+ * Minimum vis CLI version required by this workspace. When the
2618
+ * running vis binary is older than this constraint, vis exits with
2619
+ * an actionable error before executing any command.
2620
+ *
2621
+ * Accepts a semver range string (e.g. `">=1.0.0"`, `"^1.2.0"`).
2622
+ * @example ">=1.0.0"
2623
+ */
2608
2624
  versionConstraint?: string;
2609
2625
  }
2610
2626
  /**
@@ -2830,7 +2846,7 @@ declare enum SpanStatusCode {
2830
2846
  /**
2831
2847
  * The operation contains an error.
2832
2848
  */
2833
- ERROR = 2,
2849
+ ERROR = 2
2834
2850
  }
2835
2851
  /**
2836
2852
  * A pointer from the current {@link Span} to another span in the same trace or
@@ -3009,7 +3025,7 @@ declare enum SpanKind {
3009
3025
  * broker. Unlike client and server, there is no direct critical path latency
3010
3026
  * relationship between producer and consumer spans.
3011
3027
  */
3012
- CONSUMER = 4,
3028
+ CONSUMER = 4
3013
3029
  }
3014
3030
  /**
3015
3031
  * Options needed for span creation
@@ -3102,175 +3118,165 @@ interface Tracer {
3102
3118
  }
3103
3119
  interface OtelPluginOptions {
3104
3120
  /**
3105
- * Rename incoming `project:target` IDs before they become OTel
3106
- * span names. Defaults to passing the id through unchanged.
3107
- */
3121
+ * Rename incoming `project:target` IDs before they become OTel
3122
+ * span names. Defaults to passing the id through unchanged.
3123
+ */
3108
3124
  renameSpan?: (task: Task) => string;
3109
3125
  /** Tracer used to emit spans. Pass the one from `@opentelemetry/api`'s `trace.getTracer("vis")`. */
3110
3126
  tracer: Tracer;
3111
3127
  }
3112
3128
  /**
3113
- * Reference plugin that maps vis hook lifecycle events to OTel spans.
3114
- *
3115
- * Emits:
3116
- * - one **root span** named `vis.run` spanning `run:before` → `run:after`
3117
- * - one **child span** per task spanning `task:before` → `task:after`
3118
- * with attributes `vis.task.id`, `vis.task.project`, `vis.task.target`,
3119
- * `vis.task.cache_status`, `vis.task.exit_code`
3120
- * - `task:failure` sets span status to ERROR and records the exit code
3121
- *
3122
- * Streaming stdout/stderr events are intentionally **not** emitted as
3123
- * span events — high-frequency chunks would blow up OTel backends. Use
3124
- * a log exporter if you need stream-level visibility.
3125
- * @example
3126
- * ```ts
3127
- * import { trace } from "@opentelemetry/api";
3128
- * import { defineConfig } from "@visulima/vis/config";
3129
- * import { otelPlugin } from "@visulima/vis/plugins/otel";
3130
- *
3131
- * const tracer = trace.getTracer("vis", "1.0.0");
3132
- *
3133
- * export default defineConfig({
3134
- * plugins: [otelPlugin({ tracer })],
3135
- * });
3136
- * ```
3137
- */
3129
+ * Reference plugin that maps vis hook lifecycle events to OTel spans.
3130
+ *
3131
+ * Emits:
3132
+ * - one **root span** named `vis.run` spanning `run:before` → `run:after`
3133
+ * - one **child span** per task spanning `task:before` → `task:after`
3134
+ * with attributes `vis.task.id`, `vis.task.project`, `vis.task.target`,
3135
+ * `vis.task.cache_status`, `vis.task.exit_code`
3136
+ * - `task:failure` sets span status to ERROR and records the exit code
3137
+ *
3138
+ * Streaming stdout/stderr events are intentionally **not** emitted as
3139
+ * span events — high-frequency chunks would blow up OTel backends. Use
3140
+ * a log exporter if you need stream-level visibility.
3141
+ * @example
3142
+ * ```ts
3143
+ * import { trace } from "@opentelemetry/api";
3144
+ * import { defineConfig } from "@visulima/vis/config";
3145
+ * import { otelPlugin } from "@visulima/vis/plugins/otel";
3146
+ *
3147
+ * const tracer = trace.getTracer("vis", "1.0.0");
3148
+ *
3149
+ * export default defineConfig({
3150
+ * plugins: [otelPlugin({ tracer })],
3151
+ * });
3152
+ * ```
3153
+ */
3138
3154
  declare const otelPlugin: (options: OtelPluginOptions) => VisPlugin;
3139
3155
  /**
3140
- * Type-safe helper for defining a vis plugin. Pure identity — exists
3141
- * only so plugin authors get inference from the `VisPlugin` contract
3142
- * without needing a `satisfies` annotation.
3143
- *
3144
- * Lives in its own module so plugins can import it without going
3145
- * through `config.ts`, which re-exports plugins like `otelPlugin` and
3146
- * would otherwise form an import cycle.
3147
- */
3156
+ * Type-safe helper for defining a vis plugin. Pure identity — exists
3157
+ * only so plugin authors get inference from the `VisPlugin` contract
3158
+ * without needing a `satisfies` annotation.
3159
+ *
3160
+ * Lives in its own module so plugins can import it without going
3161
+ * through `config.ts`, which re-exports plugins like `otelPlugin` and
3162
+ * would otherwise form an import cycle.
3163
+ */
3148
3164
  declare const definePlugin: (plugin: VisPlugin) => VisPlugin;
3149
3165
  /** Supported config file names, checked in priority order. */
3150
3166
  declare const CONFIG_FILES: string[];
3151
3167
  /** Per-package overlay file names, checked in priority order. */
3152
3168
  declare const TASK_CONFIG_FILES: string[];
3153
3169
  /**
3154
- * Default `security.policies.firstSeen.minutes` applied by `vis init`.
3155
- * 2 days — long enough to filter out most rage-published malware while
3156
- * staying short enough that genuine fixes still land in a working week.
3157
- *
3158
- * Note: this is NOT merged into `SECURITY_DEFAULTS` — leaving it undefined
3159
- * preserves the "no opinion" semantics that downstream drift checks rely
3160
- * on. `vis init` writes the value explicitly into the generated config.
3161
- */
3162
-
3163
- /**
3164
- * Secure-by-default security settings based on npm supply chain best practices.
3165
- *
3166
- * Applied automatically when using `defineConfig()` or `loadVisConfig()`.
3167
- * Users can override any value — their settings always take precedence.
3168
- * @see https://github.com/lirantal/awesome-npm-security-best-practices
3169
- */
3170
+ * Secure-by-default security settings based on npm supply chain best practices.
3171
+ *
3172
+ * Applied automatically when using `defineConfig()` or `loadVisConfig()`.
3173
+ * Users can override any value — their settings always take precedence.
3174
+ * @see https://github.com/lirantal/awesome-npm-security-best-practices
3175
+ */
3170
3176
  declare const SECURITY_DEFAULTS: NonNullable<VisConfig["security"]>;
3171
3177
  /**
3172
- * Apply secure defaults to a raw config object.
3173
- * Merges `SECURITY_DEFAULTS` into `config.security`, preserving all user overrides.
3174
- */
3178
+ * Apply secure defaults to a raw config object.
3179
+ * Merges `SECURITY_DEFAULTS` into `config.security`, preserving all user overrides.
3180
+ */
3175
3181
  declare const applyDefaults: (config: VisConfig) => VisConfig;
3176
3182
  /**
3177
- * Find the vis config file in a directory.
3178
- *
3179
- * Reads the directory listing once and intersects it with the known
3180
- * config filenames rather than `stat`-ing each candidate — one syscall
3181
- * instead of up to six. Priority order is preserved via
3182
- * `CONFIG_FILES` so `.ts` still wins over `.mjs` when both exist.
3183
- * @param directory The directory to search in.
3184
- * @returns The absolute path to the config file, or `undefined` if not found.
3185
- */
3183
+ * Find the vis config file in a directory.
3184
+ *
3185
+ * Reads the directory listing once and intersects it with the known
3186
+ * config filenames rather than `stat`-ing each candidate — one syscall
3187
+ * instead of up to six. Priority order is preserved via
3188
+ * `CONFIG_FILES` so `.ts` still wins over `.mjs` when both exist.
3189
+ * @param directory The directory to search in.
3190
+ * @returns The absolute path to the config file, or `undefined` if not found.
3191
+ */
3186
3192
  declare const findVisConfigFile: (directory: string) => string | undefined;
3187
3193
  /**
3188
- * Find the per-package `vis.task.ts` overlay in a project directory.
3189
- * Same single-readdir lookup pattern as {@link findVisConfigFile}.
3190
- */
3194
+ * Find the per-package `vis.task.ts` overlay in a project directory.
3195
+ * Same single-readdir lookup pattern as {@link findVisConfigFile}.
3196
+ */
3191
3197
  declare const findVisTaskConfigFile: (projectDirectory: string) => string | undefined;
3192
3198
  /**
3193
- * Load the vis configuration from a `vis.config.ts` (or `.js`, `.mjs`, `.cjs`, `.mts`, `.cts`) file.
3194
- *
3195
- * Resolves the entire `extends` chain, post-order, and folds it into a
3196
- * single merged config (extends first, root last — child wins). The
3197
- * cache key covers every file in the chain, so editing any extended
3198
- * file invalidates the cache.
3199
- *
3200
- * Falls back to secure defaults if no config file is found.
3201
- * @param workspaceRoot The workspace root directory to search for the config file.
3202
- * @param options Optional loader options.
3203
- * @param options.explicitConfigPath Overrides discovery — used by the
3204
- * global `--config` flag so users can point at any file regardless of
3205
- * cwd. The path must exist; otherwise an error is thrown so the
3206
- * config-loader plugin can surface it to the user.
3207
- * @returns The loaded and resolved configuration with secure defaults applied.
3208
- */
3199
+ * Load the vis configuration from a `vis.config.ts` (or `.js`, `.mjs`, `.cjs`, `.mts`, `.cts`) file.
3200
+ *
3201
+ * Resolves the entire `extends` chain, post-order, and folds it into a
3202
+ * single merged config (extends first, root last — child wins). The
3203
+ * cache key covers every file in the chain, so editing any extended
3204
+ * file invalidates the cache.
3205
+ *
3206
+ * Falls back to secure defaults if no config file is found.
3207
+ * @param workspaceRoot The workspace root directory to search for the config file.
3208
+ * @param options Optional loader options.
3209
+ * @param options.explicitConfigPath Overrides discovery — used by the
3210
+ * global `--config` flag so users can point at any file regardless of
3211
+ * cwd. The path must exist; otherwise an error is thrown so the
3212
+ * config-loader plugin can surface it to the user.
3213
+ * @returns The loaded and resolved configuration with secure defaults applied.
3214
+ */
3209
3215
  declare const loadVisConfig: (workspaceRoot: string, options?: {
3210
3216
  explicitConfigPath?: string;
3211
3217
  }) => Promise<VisConfig>;
3212
3218
  /**
3213
- * Load the per-package `vis.task.ts` overlay for a project, if any.
3214
- *
3215
- * Returns `undefined` when no overlay file exists. Otherwise compiles
3216
- * the file via the oxc TS loader and caches the result under
3217
- * `node_modules/.cache/vis/task-configs/&lt;project>.json`, keyed by the
3218
- * file's content hash. Editing one project's overlay does not invalidate
3219
- * the root config cache.
3220
- *
3221
- * Errors thrown by the file are wrapped in `VisConfigLoadError` so the
3222
- * source path is reported instead of an opaque workspace.ts failure.
3223
- * @param workspaceRoot Absolute workspace root path (cache scope).
3224
- * @param projectDirectory Absolute path of the project to probe.
3225
- * @param projectName Project identifier — used to scope the cache file.
3226
- */
3219
+ * Load the per-package `vis.task.ts` overlay for a project, if any.
3220
+ *
3221
+ * Returns `undefined` when no overlay file exists. Otherwise compiles
3222
+ * the file via the oxc TS loader and caches the result under
3223
+ * `node_modules/.cache/vis/task-configs/&lt;project>.json`, keyed by the
3224
+ * file's content hash. Editing one project's overlay does not invalidate
3225
+ * the root config cache.
3226
+ *
3227
+ * Errors thrown by the file are wrapped in `VisConfigLoadError` so the
3228
+ * source path is reported instead of an opaque workspace.ts failure.
3229
+ * @param workspaceRoot Absolute workspace root path (cache scope).
3230
+ * @param projectDirectory Absolute path of the project to probe.
3231
+ * @param projectName Project identifier — used to scope the cache file.
3232
+ */
3227
3233
  declare const loadVisTaskConfig: (workspaceRoot: string, projectDirectory: string, projectName: string) => Promise<VisTaskConfig | undefined>;
3228
3234
  /**
3229
- * Type-safe helper for defining a per-package `vis.task.ts` overlay.
3230
- * Pure identity — exists only so users get type inference and
3231
- * autocomplete from the `VisTaskConfig` shape.
3232
- * @example
3233
- * ```typescript
3234
- * // packages/api/crud/vis.task.ts
3235
- * import { defineTaskConfig } from "@visulima/vis/config";
3236
- *
3237
- * export default defineTaskConfig({
3238
- * targets: {
3239
- * build: {
3240
- * inputs: ["@inherit", "src/proto/**\/*.proto"],
3241
- * outputs: ["dist/**\/*"],
3242
- * },
3243
- * },
3244
- * });
3245
- * ```
3246
- */
3235
+ * Type-safe helper for defining a per-package `vis.task.ts` overlay.
3236
+ * Pure identity — exists only so users get type inference and
3237
+ * autocomplete from the `VisTaskConfig` shape.
3238
+ * @example
3239
+ * ```typescript
3240
+ * // packages/api/crud/vis.task.ts
3241
+ * import { defineTaskConfig } from "@visulima/vis/config";
3242
+ *
3243
+ * export default defineTaskConfig({
3244
+ * targets: {
3245
+ * build: {
3246
+ * inputs: ["@inherit", "src/proto/**\/*.proto"],
3247
+ * outputs: ["dist/**\/*"],
3248
+ * },
3249
+ * },
3250
+ * });
3251
+ * ```
3252
+ */
3247
3253
  declare const defineTaskConfig: (config: VisTaskConfig) => VisTaskConfig;
3248
3254
  /**
3249
- * Type-safe helper for defining vis configuration.
3250
- *
3251
- * Pure typed-identity — returns its argument unchanged. The point is purely
3252
- * editor autocomplete and structural type-checking on the literal you pass
3253
- * in. Secure defaults are applied by `loadVisConfig` at load time, not here,
3254
- * so wrapping vs. using `satisfies VisConfig` produces the exact same
3255
- * runtime behavior. To see the active defaults, run `vis check --security-config`.
3256
- * @example
3257
- * ```typescript
3258
- * // vis.config.ts — minimal config, fully secured by defaults
3259
- * import { defineConfig } from "@visulima/vis/config";
3260
- *
3261
- * export default defineConfig({
3262
- * security: {
3263
- * policies: {
3264
- * installScripts: {
3265
- * allow: {
3266
- * esbuild: true,
3267
- * "@prisma/client": true,
3268
- * },
3269
- * },
3270
- * },
3271
- * },
3272
- * });
3273
- * ```
3274
- */
3255
+ * Type-safe helper for defining vis configuration.
3256
+ *
3257
+ * Pure typed-identity — returns its argument unchanged. The point is purely
3258
+ * editor autocomplete and structural type-checking on the literal you pass
3259
+ * in. Secure defaults are applied by `loadVisConfig` at load time, not here,
3260
+ * so wrapping vs. using `satisfies VisConfig` produces the exact same
3261
+ * runtime behavior. To see the active defaults, run `vis check --security-config`.
3262
+ * @example
3263
+ * ```typescript
3264
+ * // vis.config.ts — minimal config, fully secured by defaults
3265
+ * import { defineConfig } from "@visulima/vis/config";
3266
+ *
3267
+ * export default defineConfig({
3268
+ * security: {
3269
+ * policies: {
3270
+ * installScripts: {
3271
+ * allow: {
3272
+ * esbuild: true,
3273
+ * "@prisma/client": true,
3274
+ * },
3275
+ * },
3276
+ * },
3277
+ * },
3278
+ * });
3279
+ * ```
3280
+ */
3275
3281
  declare const defineConfig: (config: VisConfig) => VisConfig;
3276
3282
  export { CONFIG_FILES, type OtelPluginOptions, SECURITY_DEFAULTS, TASK_CONFIG_FILES, type VisConfig, type VisHooks, type VisPlugin, type VisTaskConfig, applyDefaults, defineConfig, definePlugin, defineTaskConfig, findVisConfigFile, findVisTaskConfigFile, loadVisConfig, loadVisTaskConfig, otelPlugin };