@visulima/vis 1.0.0-alpha.11 → 1.0.0-alpha.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (116) hide show
  1. package/CHANGELOG.md +101 -0
  2. package/LICENSE.md +559 -186
  3. package/README.md +18 -0
  4. package/dist/bin.js +1 -9
  5. package/dist/config/index.d.ts +477 -556
  6. package/dist/config/index.js +1 -2
  7. package/dist/generate/index.js +1 -3
  8. package/dist/packem_chunks/applyDefaults.js +2 -336
  9. package/dist/packem_chunks/bin.js +234 -9552
  10. package/dist/packem_chunks/doctor-probe.js +2 -112
  11. package/dist/packem_chunks/fix.js +11 -234
  12. package/dist/packem_chunks/handler.js +1 -99
  13. package/dist/packem_chunks/handler10.js +2 -53
  14. package/dist/packem_chunks/handler11.js +1 -32
  15. package/dist/packem_chunks/handler12.js +5 -100
  16. package/dist/packem_chunks/handler13.js +1 -25
  17. package/dist/packem_chunks/handler14.js +18 -916
  18. package/dist/packem_chunks/handler15.js +15 -201
  19. package/dist/packem_chunks/handler16.js +1 -124
  20. package/dist/packem_chunks/handler17.js +1 -13
  21. package/dist/packem_chunks/handler18.js +1 -106
  22. package/dist/packem_chunks/handler19.js +1 -19
  23. package/dist/packem_chunks/handler2.js +2 -75
  24. package/dist/packem_chunks/handler20.js +5 -29
  25. package/dist/packem_chunks/handler21.js +1 -222
  26. package/dist/packem_chunks/handler22.js +1 -237
  27. package/dist/packem_chunks/handler23.js +5 -101
  28. package/dist/packem_chunks/handler24.js +1 -110
  29. package/dist/packem_chunks/handler25.js +3 -402
  30. package/dist/packem_chunks/handler26.js +1 -13
  31. package/dist/packem_chunks/handler27.js +1 -63
  32. package/dist/packem_chunks/handler28.js +7 -34
  33. package/dist/packem_chunks/handler29.js +21 -456
  34. package/dist/packem_chunks/handler3.js +4 -95
  35. package/dist/packem_chunks/handler30.js +3 -170
  36. package/dist/packem_chunks/handler31.js +1 -530
  37. package/dist/packem_chunks/handler32.js +2 -214
  38. package/dist/packem_chunks/handler33.js +25 -119
  39. package/dist/packem_chunks/handler34.js +2 -630
  40. package/dist/packem_chunks/handler35.js +3 -283
  41. package/dist/packem_chunks/handler36.js +22 -542
  42. package/dist/packem_chunks/handler37.js +410 -744
  43. package/dist/packem_chunks/handler38.js +22 -989
  44. package/dist/packem_chunks/handler39.js +22 -574
  45. package/dist/packem_chunks/handler4.js +2 -90
  46. package/dist/packem_chunks/handler40.js +22 -1685
  47. package/dist/packem_chunks/handler41.js +6 -1088
  48. package/dist/packem_chunks/handler42.js +5 -797
  49. package/dist/packem_chunks/handler43.js +10 -2658
  50. package/dist/packem_chunks/handler44.js +51 -3784
  51. package/dist/packem_chunks/handler45.js +25 -2574
  52. package/dist/packem_chunks/handler46.js +3 -3769
  53. package/dist/packem_chunks/handler47.js +21 -1485
  54. package/dist/packem_chunks/handler48.js +42 -0
  55. package/dist/packem_chunks/handler5.js +8 -174
  56. package/dist/packem_chunks/handler6.js +1 -95
  57. package/dist/packem_chunks/handler7.js +1 -115
  58. package/dist/packem_chunks/handler8.js +1 -12
  59. package/dist/packem_chunks/handler9.js +1 -29
  60. package/dist/packem_chunks/heal-accept.js +10 -522
  61. package/dist/packem_chunks/heal.js +14 -673
  62. package/dist/packem_chunks/index.js +7 -873
  63. package/dist/packem_chunks/loader.js +1 -23
  64. package/dist/packem_chunks/tar.js +3 -0
  65. package/dist/packem_shared/ai-analysis-hm8d2W7z.js +67 -0
  66. package/dist/packem_shared/ai-cache-DoiF80AR.js +1 -0
  67. package/dist/packem_shared/ai-fix-nn4zOE95.js +43 -0
  68. package/dist/packem_shared/cache-directory-CwHlJhgx.js +1 -0
  69. package/dist/packem_shared/dependency-scan-COr5n63B.js +2 -0
  70. package/dist/packem_shared/docker-D6OGr5_S.js +2 -0
  71. package/dist/packem_shared/failure-log-iUVLf6ts.js +2 -0
  72. package/dist/packem_shared/flakiness-D9wf0t56.js +1 -0
  73. package/dist/packem_shared/giget-CcEy_Elm.js +2 -0
  74. package/dist/packem_shared/index-DH-5hsrC.js +1 -0
  75. package/dist/packem_shared/otel-DxDUPJJH.js +6 -0
  76. package/dist/packem_shared/otelPlugin-CQq6poq8.js +1 -0
  77. package/dist/packem_shared/registry-CkubDdiY.js +2 -0
  78. package/dist/packem_shared/run-summary-utils-BfBvjzhY.js +1 -0
  79. package/dist/packem_shared/runtime-check-BXZ43CBW.js +1 -0
  80. package/dist/packem_shared/selectors-BylODRiM.js +3 -0
  81. package/dist/packem_shared/symbols-CQmER5MT.js +1 -0
  82. package/dist/packem_shared/toolchain-BgBOUHII.js +5 -0
  83. package/dist/packem_shared/typosquats-CcZl99B1.js +1 -0
  84. package/dist/packem_shared/use-measured-height-DjYgUOKk.js +1 -0
  85. package/dist/packem_shared/utils-DrNg0XTR.js +1 -0
  86. package/dist/packem_shared/verify-Baj5mFJ7.js +1 -0
  87. package/dist/packem_shared/vis-update-app-D1jl0UZZ.js +1 -0
  88. package/dist/packem_shared/xxh3-DrAUNq4n.js +1 -0
  89. package/index.js +556 -727
  90. package/package.json +19 -29
  91. package/schemas/project.schema.json +739 -297
  92. package/schemas/vis-config.schema.json +3365 -384
  93. package/templates/buildkite-ci/template.yml +20 -20
  94. package/dist/packem_shared/VisUpdateApp-D-Yz_wvg.js +0 -1316
  95. package/dist/packem_shared/_commonjsHelpers-BqLXS_qQ.js +0 -5
  96. package/dist/packem_shared/ai-analysis-CHeB1joD.js +0 -367
  97. package/dist/packem_shared/ai-cache-Be_jexe4.js +0 -142
  98. package/dist/packem_shared/ai-fix-B9iQVcD2.js +0 -379
  99. package/dist/packem_shared/cache-directory-2qvs4goY.js +0 -98
  100. package/dist/packem_shared/catalog-BJTtyi-O.js +0 -1371
  101. package/dist/packem_shared/dependency-scan-A0KSklpG.js +0 -188
  102. package/dist/packem_shared/docker-2iZzc280.js +0 -181
  103. package/dist/packem_shared/failure-log-Cz3Z4SKL.js +0 -100
  104. package/dist/packem_shared/flakiness-goTxXuCX.js +0 -180
  105. package/dist/packem_shared/otel-DCvqCTz_.js +0 -158
  106. package/dist/packem_shared/otelPlugin-DFaLDvJf.js +0 -3
  107. package/dist/packem_shared/registry-CbqXI0rc.js +0 -272
  108. package/dist/packem_shared/run-summary-utils-PVMl4aIh.js +0 -130
  109. package/dist/packem_shared/runtime-check-Cobi3p6l.js +0 -127
  110. package/dist/packem_shared/selectors-SM69TfqC.js +0 -194
  111. package/dist/packem_shared/symbols-Ta7g2nU-.js +0 -14
  112. package/dist/packem_shared/toolchain-BdZd9eBi.js +0 -975
  113. package/dist/packem_shared/typosquats-C-bCh3PX.js +0 -1210
  114. package/dist/packem_shared/use-measured-height-CNP0vT4M.js +0 -20
  115. package/dist/packem_shared/utils-CthVdBPS.js +0 -40
  116. package/dist/packem_shared/xxh3-Ck8mXNg1.js +0 -239
@@ -4,498 +4,3479 @@
4
4
  "title": "vis.config.ts",
5
5
  "description": "Workspace configuration for @visulima/vis. Used by defineConfig() in vis.config.ts. This schema is for non-TypeScript editors; TypeScript users get autocomplete from defineConfig() types.",
6
6
  "type": "object",
7
- "additionalProperties": false,
8
7
  "properties": {
9
8
  "ai": {
10
9
  "type": "object",
11
- "description": "AI analysis configuration.",
12
- "additionalProperties": false,
13
10
  "properties": {
14
- "cacheTtl": { "type": "number", "description": "Cache TTL in milliseconds." },
11
+ "cacheTtl": {
12
+ "type": "number",
13
+ "description": "Cache TTL in milliseconds. Overrides default (1h / 30min for security)."
14
+ },
15
15
  "priority": {
16
16
  "type": "object",
17
- "description": "Override default provider priority. Higher number = preferred.",
18
- "additionalProperties": { "type": "number" }
19
- },
20
- "provider": { "type": "string", "description": "Use a specific provider (e.g. \"claude\", \"gemini\")." }
21
- }
22
- },
23
- "codeowners": {
24
- "type": "object",
25
- "description": "Controls vis sync codeowners output.",
26
- "additionalProperties": false,
27
- "properties": {
28
- "orderBy": {
29
- "type": "string",
30
- "enum": ["file-source", "project-id"],
31
- "default": "file-source"
17
+ "additionalProperties": {
18
+ "type": "number"
19
+ },
20
+ "description": "Override default provider priority. Higher number = preferred."
32
21
  },
33
22
  "provider": {
34
23
  "type": "string",
35
- "enum": ["github", "gitlab", "bitbucket", "other"],
36
- "default": "github"
37
- },
38
- "globalPaths": {
39
- "type": "object",
40
- "description": "Workspace-level paths and their owners (e.g. \"/.github/**\": [\"@org/platform\"]).",
41
- "additionalProperties": {
42
- "type": "array",
43
- "items": { "type": "string" }
44
- }
24
+ "description": "Use a specific provider instead of auto-detecting (e.g., `\"claude\"`, `\"gemini\"`)."
45
25
  }
46
- }
26
+ },
27
+ "additionalProperties": false,
28
+ "description": "AI analysis configuration"
29
+ },
30
+ "branchScopedCache": {
31
+ "type": "boolean",
32
+ "description": "Scope the task-runner cache directory by the current git branch. When `true`, caches are stored under `<cacheDir>/branches/<slug>` so `main` and feature branches stop thrashing each other — generated artefacts (schemas, `.d.ts` snapshots) that legitimately differ across branches no longer oscillate the cache contents.\n\nFalls back to the unscoped path on detached HEAD, non-git workspaces, or when git isn't available.",
33
+ "default": false
34
+ },
35
+ "codeowners": {
36
+ "$ref": "#/$defs/CodeownersConfig",
37
+ "description": "Code ownership configuration. Controls how `vis sync codeowners` renders the generated CODEOWNERS file."
47
38
  },
48
39
  "constraints": {
49
40
  "type": "object",
50
- "description": "Project dependency constraints enforced before running tasks.",
51
- "additionalProperties": false,
52
41
  "properties": {
42
+ "dependencyKindRules": {
43
+ "type": "object",
44
+ "properties": {
45
+ "noDevDependencyOnProductionDep": {
46
+ "type": "boolean",
47
+ "description": "When true, a \"library\" project must not have workspace-internal devDependencies on other libraries that are also in its production dependencies. Prevents publishing libraries that silently rely on dev-only workspace packages.",
48
+ "default": false
49
+ },
50
+ "noProductionDependencyOnApplication": {
51
+ "type": "boolean",
52
+ "description": "When true, production `dependencies` must not point to \"application\" type projects. devDependencies on applications are allowed (e.g., for testing).",
53
+ "default": false
54
+ }
55
+ },
56
+ "additionalProperties": false,
57
+ "description": "Rules based on the dependency kind (static vs devDependency vs peerDependency)"
58
+ },
53
59
  "enforceLayerRelationships": {
54
60
  "type": "boolean",
55
- "description": "Projects can only depend on the same or lower layer: configuration < library < scaffolding < tool < automation < application.",
61
+ "description": "When true, projects can only depend on projects at the same or lower layer in the hierarchy:\n\n configuration < library < scaffolding < tool < automation < application\n\nProjects without an explicit `layer` are unconstrained.",
56
62
  "default": false
57
63
  },
58
64
  "tagRelationships": {
59
65
  "type": "object",
60
- "description": "Tag-based rules. Key = source tag, value = allowed dependency tags.",
61
66
  "additionalProperties": {
62
67
  "type": "array",
63
- "items": { "type": "string" }
64
- }
68
+ "items": {
69
+ "type": "string"
70
+ }
71
+ },
72
+ "description": "Tag-based dependency rules"
65
73
  },
66
74
  "typeBoundaries": {
67
75
  "type": "object",
68
- "additionalProperties": false,
69
76
  "properties": {
70
- "enforceApplicationBoundary": {
71
- "type": "boolean",
72
- "description": "No project may depend on an application.",
73
- "default": true
74
- },
75
77
  "allowedDependencyTypes": {
76
78
  "type": "object",
77
- "description": "Maps project types to allowed dependency types.",
78
79
  "additionalProperties": {
79
80
  "type": "array",
80
- "items": { "type": "string" }
81
- }
81
+ "items": {
82
+ "type": "string"
83
+ }
84
+ },
85
+ "description": "Custom rules mapping project types to allowed dependency types. Example: `{ \"application\": [\"library\"] }` means applications can only depend on libraries."
86
+ },
87
+ "enforceApplicationBoundary": {
88
+ "type": "boolean",
89
+ "description": "When true, no project may depend on an \"application\" type project. Applications are typically deployment targets, not libraries.",
90
+ "default": true
82
91
  }
83
- }
84
- },
85
- "dependencyKindRules": {
86
- "type": "object",
92
+ },
87
93
  "additionalProperties": false,
88
- "properties": {
89
- "noDevDependencyOnProductionDep": { "type": "boolean", "default": false },
90
- "noProductionDependencyOnApplication": { "type": "boolean", "default": false }
91
- }
94
+ "description": "Project-type-based dependency rules"
92
95
  }
93
- }
96
+ },
97
+ "additionalProperties": false,
98
+ "description": "Project dependency constraints. Enforced after building the project graph, before running tasks."
94
99
  },
95
- "install": {
100
+ "create": {
96
101
  "type": "object",
97
- "description": "Installer backend selection. Lets `vis install` (and friends) use aube — a fast Rust-native PM that reads/writes pnpm/npm/yarn/bun lockfiles in place — or pin a specific conventional PM. Aube must be installed separately; vis does not bundle it.",
98
- "additionalProperties": false,
99
102
  "properties": {
100
- "backend": {
103
+ "auth": {
104
+ "type": "string",
105
+ "description": "Authorization token for downloading private repository templates. Passed as Bearer token to the git host API. Can also be set via GIGET_AUTH, GITHUB_TOKEN, or GH_TOKEN environment variables."
106
+ },
107
+ "defaultEditor": {
101
108
  "type": "string",
102
- "enum": ["auto", "aube", "pnpm", "npm", "yarn", "bun"],
103
- "default": "auto",
104
- "description": "Which PM runs install/add/remove. `auto` uses aube when it is on PATH and falls back to the lockfile-detected PM. Explicit names error if the binary is missing. CLI flag `--installer` and env var `VIS_INSTALLER` override this."
109
+ "const": "vscode",
110
+ "description": "Default editor to configure after scaffolding. When set, `vis create` automatically generates editor config files.",
111
+ "examples": [
112
+ "vscode"
113
+ ]
114
+ },
115
+ "defaultPm": {
116
+ "type": "string",
117
+ "enum": [
118
+ "bun",
119
+ "npm",
120
+ "pnpm",
121
+ "yarn"
122
+ ],
123
+ "description": "Default package manager for new standalone projects. When set, skips the PM selection prompt in interactive mode."
124
+ },
125
+ "defaultProvider": {
126
+ "type": "string",
127
+ "enum": [
128
+ "bitbucket",
129
+ "github",
130
+ "gitlab",
131
+ "sourcehut"
132
+ ],
133
+ "description": "Default giget provider for `owner/repo` shorthand inputs.",
134
+ "default": "github"
135
+ },
136
+ "gitInit": {
137
+ "type": "boolean",
138
+ "description": "Initialize a git repository after scaffolding standalone projects.",
139
+ "default": false
140
+ },
141
+ "install": {
142
+ "type": "boolean",
143
+ "description": "Install dependencies automatically after scaffolding.",
144
+ "default": true
145
+ },
146
+ "preferOffline": {
147
+ "type": "boolean",
148
+ "description": "Prefer locally cached templates over re-downloading. Useful for offline development or slow connections.",
149
+ "default": false
150
+ },
151
+ "registry": {
152
+ "anyOf": [
153
+ {
154
+ "type": "string"
155
+ },
156
+ {
157
+ "type": "boolean",
158
+ "const": false
159
+ }
160
+ ],
161
+ "description": "Custom template registry URL. When set, giget checks this registry for template metadata before falling back to direct provider resolution. Set to `false` to disable registry lookup entirely."
162
+ },
163
+ "templates": {
164
+ "type": "object",
165
+ "additionalProperties": {
166
+ "type": "string"
167
+ },
168
+ "description": "Named template aliases for quick access. Maps short names to full giget source strings."
105
169
  }
106
- }
170
+ },
171
+ "additionalProperties": false,
172
+ "description": "Configuration for the `vis create` scaffolding command. Controls template downloads (via giget), default options, and post-creation behavior."
107
173
  },
108
- "inferTargets": {
109
- "default": false,
110
- "oneOf": [
111
- { "type": "boolean" },
174
+ "editorconfig": {
175
+ "type": "boolean",
176
+ "description": "Discover `.editorconfig` for indent / line-ending defaults during file transformations (sort-package-json, migrate, hook, pm overrides, workspace catalog rewrites). Per-command flags can still override.",
177
+ "default": true
178
+ },
179
+ "extends": {
180
+ "anyOf": [
112
181
  {
113
- "type": "object",
114
- "description": "Per-detector opt-out map. Keys must be one of the 36 built-in detector names; set a key to `false` to disable that detector. Detectors omitted from the object stay enabled. Unknown keys log a warning at config-load time.",
115
- "additionalProperties": { "type": "boolean" },
116
- "propertyNames": {
117
- "enum": [
118
- "nuxt",
119
- "next",
120
- "remix",
121
- "astro",
122
- "gatsby",
123
- "docusaurus",
124
- "vite",
125
- "vitepress",
126
- "nest",
127
- "rolldown",
128
- "tsdown",
129
- "tsup",
130
- "packem",
131
- "rollup",
132
- "webpack",
133
- "vitest",
134
- "jest",
135
- "bun",
136
- "playwright",
137
- "cypress",
138
- "storybook",
139
- "typescript",
140
- "typedoc",
141
- "eslint",
142
- "prettier",
143
- "biome",
144
- "oxlint",
145
- "oxfmt",
146
- "stylelint",
147
- "knip",
148
- "deno",
149
- "prisma",
150
- "drizzle",
151
- "graphql-codegen",
152
- "api-extractor",
153
- "changeset"
154
- ]
182
+ "type": "string"
183
+ },
184
+ {
185
+ "type": "array",
186
+ "items": {
187
+ "type": "string"
155
188
  }
156
189
  }
157
190
  ],
158
- "description": "Project Crystal-style inference. Synthesizes default targets (`build`, `test`, `dev`, `lint`, `format`, `typecheck`, `docs`, `db:*`, …) for each project by sniffing config files and `package.json` dependencies. Ships with 36 detectors covering app frameworks (nuxt, next, remix, astro, gatsby, docusaurus), bundlers (vite, rolldown, tsdown, tsup, packem, rollup, webpack), test runners (vitest, jest, bun, deno, playwright, cypress), lint/format tools (eslint, prettier, biome, oxlint, oxfmt, stylelint, knip), docs (typedoc, vitepress), DB tooling (prisma, drizzle), and release plumbing (graphql-codegen, api-extractor, changeset). Inferred targets are the lowest-priority layer package.json scripts, project.json, and vis.task.ts always win on a per-target-name basis. Boolean `true` enables every detector; the object form opts individual detectors in or out by name. See `vis list --inferred` to inspect what each project resolves to."
191
+ "description": "Inherit configuration from one or more parent configs. Entries are resolved left-to-right (later wins) and the consumer's own values always override anything pulled in from `extends`.\n\nEach entry is either:\n- a relative path (`./shared.config.ts`, `../shared.config.ts`) — resolved against the file declaring `extends`;\n- an npm package name (`@acme/vis-preset`) — resolved via Node.js module resolution from the consumer file.\n\nAbsolute paths are rejected they break across machines and CI. Cycles raise `VisConfigCycleError` during load."
159
192
  },
160
- "create": {
193
+ "fileGroups": {
161
194
  "type": "object",
162
- "description": "Configuration for vis create scaffolding command.",
163
- "additionalProperties": false,
164
- "properties": {
165
- "auth": { "type": "string", "description": "Authorization token for private templates." },
166
- "defaultEditor": { "type": "string", "enum": ["vscode"] },
167
- "defaultPm": { "type": "string", "enum": ["pnpm", "npm", "yarn", "bun"] },
168
- "defaultProvider": { "type": "string", "enum": ["github", "gitlab", "bitbucket", "sourcehut"], "default": "github" },
169
- "gitInit": { "type": "boolean", "default": false },
170
- "install": { "type": "boolean", "default": true },
171
- "preferOffline": { "type": "boolean", "default": false },
172
- "registry": {
173
- "oneOf": [{ "type": "string" }, { "type": "boolean", "const": false }]
174
- },
175
- "templates": {
176
- "type": "object",
177
- "description": "Named template aliases mapping short names to giget source strings.",
178
- "additionalProperties": { "type": "string" }
195
+ "additionalProperties": {
196
+ "type": "array",
197
+ "items": {
198
+ "type": "string"
179
199
  }
180
- }
181
- },
182
- "overrides": {
183
- "type": "object",
184
- "description": "Package override mappings applied during migration.",
185
- "additionalProperties": { "type": "string" }
200
+ },
201
+ "description": "Named file-group patterns, reusable from target `inputs` via the `@filegroup:&lt;name>` token. File groups are resolved relative to each project root at discovery time."
186
202
  },
187
- "preflight": {
203
+ "generator": {
188
204
  "type": "object",
189
- "description": "Preflight checks gating `vis run` / `vis ci`. Each check can be opted out individually; the CLI flag `--no-preflight` disables them all.",
190
- "additionalProperties": false,
191
205
  "properties": {
192
- "lockfile": {
206
+ "auth": {
207
+ "type": "string",
208
+ "description": "Authorization token forwarded to giget when fetching `git://`/`npm://` remote templates. Falls back to `GIGET_AUTH` / `GITHUB_TOKEN` / `GH_TOKEN` env vars."
209
+ },
210
+ "preferOffline": {
193
211
  "type": "boolean",
194
- "default": true,
195
- "description": "Detect lockfile drift by comparing the lockfile mtime against the package manager's install marker (e.g. `node_modules/.modules.yaml` for pnpm). When the lockfile is newer than the marker, the run fails with the right reinstall command for CI vs TTY."
212
+ "description": "Prefer locally cached remote templates over re-downloading. Overridable per invocation via `--prefer-offline`.",
213
+ "default": false
214
+ },
215
+ "templates": {
216
+ "type": "array",
217
+ "items": {
218
+ "type": "string"
219
+ },
220
+ "description": "Extra directories to scan for templates. Each directory is checked for both native templates (`&lt;name>.ts`) and moon-format directories (containing `template.yml`)."
196
221
  }
197
- }
198
- },
199
- "security": {
200
- "type": "object",
201
- "description": "Supply-chain security settings.",
222
+ },
202
223
  "additionalProperties": false,
203
- "properties": {
204
- "allowBuilds": {
205
- "type": "object",
206
- "description": "Allow (true) or deny (false) build scripts per package.",
207
- "additionalProperties": { "type": "boolean" }
208
- },
209
- "blockExoticSubdeps": { "type": "boolean", "default": false },
210
- "minimumReleaseAge": { "type": "number", "description": "Minutes since publish before allowing install.", "default": 0 },
211
- "minimumReleaseAgeExclude": { "type": "array", "items": { "type": "string" } },
212
- "socket": {
224
+ "description": "Configuration for the `vis generate` in-repo scaffolding command. Points at additional template directories beyond the defaults (`.vis/templates/` and `.moon/templates/`)."
225
+ },
226
+ "inferTargets": {
227
+ "anyOf": [
228
+ {
213
229
  "type": "object",
214
- "additionalProperties": false,
215
- "properties": {
216
- "acceptedRisks": {
217
- "type": "object",
218
- "additionalProperties": {
219
- "type": "object",
220
- "required": ["reason", "acceptedAt", "acceptedScore"],
221
- "properties": {
222
- "reason": { "type": "string" },
223
- "acceptedAt": { "type": "string", "format": "date-time" },
224
- "acceptedScore": { "type": "number" }
225
- }
226
- }
227
- },
228
- "apiToken": { "type": "string" },
229
- "cacheTtlMs": { "type": "number", "default": 3600000 },
230
- "enabled": { "type": "boolean", "default": false },
231
- "minimumScore": { "type": "number", "default": 0.4 },
232
- "timeoutMs": { "type": "number", "default": 15000 }
230
+ "additionalProperties": {
231
+ "type": "boolean"
233
232
  }
234
233
  },
235
- "strictDepBuilds": { "type": "boolean", "default": false },
236
- "trustPolicy": { "type": "string", "enum": ["off", "no-downgrade"], "default": "off" },
237
- "trustPolicyExclude": { "type": "array", "items": { "type": "string" } },
238
- "trustPolicyIgnoreAfter": { "type": "number" },
239
- "typosquatAllowlist": { "type": "array", "items": { "type": "string" } }
240
- }
241
- },
242
- "sortPackageJson": {
243
- "type": "object",
244
- "additionalProperties": false,
245
- "properties": {
246
- "sortScripts": { "type": "boolean", "default": false }
247
- }
234
+ {
235
+ "type": "boolean"
236
+ }
237
+ ],
238
+ "description": "Auto-create targets from detected config files (Project Crystal-style). Inferred targets sit *below* explicit ones — anything in `package.json#scripts`, `project.json#targets`, or `vis.task.ts` wins per-key, so opting in never overrides existing setups.\n\nBuilt-in detectors and the targets they synthesize:\n\n- **App frameworks** — `nuxt` (build/dev/preview/generate), `next` (build/dev/start), `remix` (build/dev/start), `astro` (build/dev), `gatsby` (build/develop/serve), `docusaurus` (build/start/serve).\n- **Bundlers** — `vite` (build/dev/preview), `rolldown` (build), `tsdown` (build), `tsup` (build), `packem` (build), `rollup` (build), `webpack` (build).\n- **Docs sites** — `vitepress` (docs:build/docs:dev/docs:preview), `typedoc` (docs).\n- **Server frameworks** — `nest` (build/start/start:dev).\n- **Test runners** — `vitest` (test/test:watch), `jest` (test/test:watch), `bun` (test), `playwright` (test:e2e), `cypress` (test:e2e/cypress:open).\n- **Stories** — `storybook` (storybook/build-storybook).\n- **Type checking** — `typescript` (typecheck via `tsc --noEmit`).\n- **Lint / format** — `eslint` (lint), `prettier` (format / format:check), `biome` (lint, format), `oxlint` (lint), `oxfmt` (format / format:check), `stylelint` (lint:css), `knip` (knip).\n- **Runtimes** — `deno` (test/lint/fmt/check).\n- **Database tooling** — `prisma` (db:generate/db:migrate/ db:push/db:studio), `drizzle` (db:generate/db:migrate/ db:push/db:studio).\n- **Codegen / release** — `graphql-codegen` (codegen), `api-extractor` (api-extract), `changeset` (changeset:version / changeset:publish / changeset:status).\n\nTrigger: presence of any matching config file in the project root. Most detectors additionally match when their framework appears in `dependencies` / `devDependencies` / `peerDependencies` / `optionalDependencies` — covering convention-only setups (e.g. vitest with default config). Detectors that intentionally require a config file (because the package frequently appears transitively and a dep-only match would synthesize broken commands): `vite`, `rolldown`, `rollup`, `webpack`, `storybook`, `nest`, `remix`, `vitepress`, `bun`, `deno`, `changeset`.\n\nConflict resolution: detectors are evaluated in registration order (see `BUILT_IN_DETECTORS`) and the first to claim a target name wins. Per-name priorities: `build` → nuxt > next > remix > astro > gatsby > docusaurus > vite > nest > rolldown > tsdown > tsup > packem > rollup > webpack; `test` → vitest > jest > bun > deno; `test:e2e` → playwright > cypress; `lint` → eslint > biome > oxlint > deno; `format` → prettier > biome > oxfmt; `db:*` → prisma > drizzle.\n\nAlso accepts an object form (`{ vite: false, vitest: true }`) to opt individual detectors in or out by name. Detectors omitted from the object run at their default (enabled). Useful when one detector misfires for a given workspace without disabling the rest.",
239
+ "default": false
248
240
  },
249
- "toolchain": {
241
+ "install": {
250
242
  "type": "object",
251
- "description": "Toolchain (Node / pnpm / python / ...) management. Delegates to proto / mise / fnm / volta / asdf / nvm / corepack.",
252
- "additionalProperties": false,
253
243
  "properties": {
254
- "autoInstall": {
255
- "type": "boolean",
256
- "description": "Run the right manager install on engines.node mismatch before vis run / vis ci proceed. Default: true when a manager is detected on PATH."
257
- },
258
- "preferredManager": {
244
+ "backend": {
259
245
  "type": "string",
260
- "enum": ["proto", "mise", "fnm", "volta", "asdf", "nvm", "corepack", "none"],
261
- "description": "Explicit manager override, bypasses auto-detection. Note: self-activate is resolved automatically for pnpm/yarn + packageManager pins and is not a valid override."
246
+ "enum": [
247
+ "aube",
248
+ "auto",
249
+ "bun",
250
+ "npm",
251
+ "pnpm",
252
+ "yarn"
253
+ ],
254
+ "description": "Which package manager performs install/add/remove/etc.\n- `auto` (default): use `aube` when it is on PATH; otherwise fall back to the lockfile-detected PM.\n- explicit name: always use that PM. Errors when the named binary is missing rather than silently falling back.",
255
+ "default": "auto"
262
256
  },
263
- "tools": {
264
- "type": "object",
265
- "description": "Override engines/packageManager-derived pins.",
266
- "additionalProperties": false,
267
- "properties": {
268
- "bun": { "type": "string" },
269
- "deno": { "type": "string" },
270
- "go": { "type": "string" },
271
- "node": { "type": "string" },
272
- "npm": { "type": "string" },
273
- "pnpm": { "type": "string" },
274
- "python": { "type": "string" },
275
- "ruby": { "type": "string" },
276
- "rust": { "type": "string" },
277
- "yarn": { "type": "string" }
278
- }
279
- }
280
- }
281
- },
282
- "staged": {
283
- "description": "Staged file patterns and commands (replaces lint-staged). Accepts string, string[], {title, task}, or mixed arrays. Function-form tasks are supported at runtime but are not JSON-schema-representable.",
284
- "type": "object",
285
- "additionalProperties": {
286
- "oneOf": [
287
- { "type": "string" },
288
- { "type": "array", "items": { "oneOf": [{ "type": "string" }, { "type": "object" }] } },
289
- {
290
- "type": "object",
291
- "required": ["title"],
292
- "properties": {
293
- "title": { "type": "string" }
257
+ "corepack": {
258
+ "anyOf": [
259
+ {
260
+ "type": "string",
261
+ "const": "auto"
262
+ },
263
+ {
264
+ "type": "boolean"
294
265
  }
295
- }
296
- ]
297
- }
298
- },
299
- "targetDefaults": {
300
- "type": "object",
301
- "description": "Default target configurations applied to all projects with a matching target.",
302
- "additionalProperties": { "$ref": "project.schema.json#/$defs/targetConfiguration" }
303
- },
304
- "fileGroups": {
305
- "type": "object",
306
- "description": "Named file-group patterns, reusable via @filegroup:<name> in target inputs. Strings may be bare globs or URI form (file://, glob://, env://, func://, dep://).",
307
- "additionalProperties": {
308
- "type": "array",
309
- "items": { "$ref": "project.schema.json#/$defs/inputString" }
310
- }
266
+ ],
267
+ "description": "Whether to dispatch PM invocations through `corepack`.\n- `\"auto\"` (default): use corepack only when the workspace pins a PM via the `packageManager` field AND `corepack` is on PATH AND the PM is one corepack manages (pnpm/yarn/npm).\n- `true`: always prefix `corepack` when the binary is on PATH and the PM is corepack-managed (errors loudly otherwise).\n- `false`: never go through corepack — invoke the PM directly.\n\nMirrors nypm's `corepack: true` flag. Bun, deno, and aube are never wrapped — corepack does not manage them.",
268
+ "default": "auto"
269
+ }
270
+ },
271
+ "additionalProperties": false,
272
+ "description": "Installer backend selection for `vis install` / `vis add` / `vis remove` / `vis update` / `vis ci`.\n\nLets users opt into [aube](https://github.com/endevco/aube) — a Rust-native package manager that reads/writes pnpm/npm/yarn/bun lockfiles in place — as the default installer, while keeping a single switch to fall back to the conventional PM detected from the lockfile.\n\nResolution precedence (highest first): 1. CLI flag (`--installer &lt;name>` / `--no-aube`) 2. Env var `VIS_INSTALLER` 3. This config field 4. Auto-detect (the default)\n\nAube must be installed separately — `vis` does not bundle it. Install via npm (`@endevco/aube`), `mise use -g aube`, or `brew install endevco/tap/aube`."
311
273
  },
312
274
  "namedInputs": {
313
275
  "type": "object",
314
- "description": "Named input patterns inherited by every project target.",
315
276
  "additionalProperties": {
316
277
  "type": "array",
317
278
  "items": {
318
- "oneOf": [
319
- { "$ref": "project.schema.json#/$defs/inputString" },
320
- { "$ref": "project.schema.json#/$defs/fileSetInput" },
321
- { "$ref": "project.schema.json#/$defs/environmentInput" },
322
- { "$ref": "project.schema.json#/$defs/runtimeInput" },
323
- { "$ref": "project.schema.json#/$defs/externalDependencyInput" }
279
+ "anyOf": [
280
+ {
281
+ "type": "string"
282
+ },
283
+ {
284
+ "anyOf": [
285
+ {
286
+ "type": "object",
287
+ "properties": {
288
+ "fileset": {
289
+ "anyOf": [
290
+ {
291
+ "type": "object",
292
+ "properties": {
293
+ "base": {
294
+ "type": "string",
295
+ "enum": [
296
+ "package",
297
+ "workspace"
298
+ ],
299
+ "description": "Anchor for the pattern."
300
+ },
301
+ "pattern": {
302
+ "type": "string",
303
+ "description": "Glob pattern (may start with `!` for negation)."
304
+ }
305
+ },
306
+ "required": [
307
+ "base",
308
+ "pattern"
309
+ ],
310
+ "additionalProperties": false,
311
+ "description": "Object form of a fileset pattern, for anchoring to the workspace root."
312
+ },
313
+ {
314
+ "type": "string"
315
+ }
316
+ ]
317
+ }
318
+ },
319
+ "required": [
320
+ "fileset"
321
+ ],
322
+ "additionalProperties": false,
323
+ "description": "An input based on file patterns.\n\n`fileset` may be a bare glob string (package-root relative) or an object form `{ pattern, base }` to anchor explicitly to the workspace root. Negation (`!` prefix) works in both forms."
324
+ },
325
+ {
326
+ "type": "object",
327
+ "properties": {
328
+ "runtime": {
329
+ "type": "string"
330
+ }
331
+ },
332
+ "required": [
333
+ "runtime"
334
+ ],
335
+ "additionalProperties": false,
336
+ "description": "An input based on a runtime command."
337
+ },
338
+ {
339
+ "type": "object",
340
+ "properties": {
341
+ "env": {
342
+ "type": "string"
343
+ }
344
+ },
345
+ "required": [
346
+ "env"
347
+ ],
348
+ "additionalProperties": false,
349
+ "description": "An input based on environment variables."
350
+ },
351
+ {
352
+ "type": "object",
353
+ "properties": {
354
+ "externalDependencies": {
355
+ "type": "array",
356
+ "items": {
357
+ "type": "string"
358
+ }
359
+ }
360
+ },
361
+ "required": [
362
+ "externalDependencies"
363
+ ],
364
+ "additionalProperties": false,
365
+ "description": "An input based on external dependency versions."
366
+ }
367
+ ],
368
+ "description": "Defines an input for cache invalidation."
369
+ }
324
370
  ]
325
371
  }
326
- }
372
+ },
373
+ "description": "Named input patterns inherited by every project target. Equivalent to task-runner's `namedInputs` but configurable from the vis config."
327
374
  },
328
- "taskDefaults": {
375
+ "overrides": {
376
+ "type": "object",
377
+ "additionalProperties": {
378
+ "type": "string"
379
+ },
380
+ "description": "Package override mappings applied during migration (e.g., `{ \"lodash\": \"lodash-es\" }`)"
381
+ },
382
+ "plugins": {
329
383
  "type": "array",
330
- "description": "Cascading task-default blocks scoped by project metadata.",
331
384
  "items": {
332
- "type": "object",
333
- "required": ["targets"],
334
- "additionalProperties": false,
335
- "properties": {
336
- "scope": {
337
- "type": "object",
338
- "description": "Scope predicate — all fields must match for the block to apply.",
339
- "additionalProperties": false,
340
- "properties": {
341
- "tags": { "type": "array", "items": { "type": "string" } },
342
- "projectType": { "type": "string", "enum": ["library", "application"] },
343
- "layer": {
344
- "oneOf": [
345
- { "type": "string", "enum": ["configuration", "library", "scaffolding", "tool", "automation", "application"] },
346
- {
385
+ "$ref": "#/$defs/VisPlugin"
386
+ },
387
+ "description": "Plugins — each plugin registers typed hooks that fire at run / task / cache boundaries. See {@link VisPlugin } for the contract. Prefer plugins over per-target shell hooks when behaviour needs access to task metadata, results, or cache state."
388
+ },
389
+ "policy": {
390
+ "type": "object",
391
+ "properties": {
392
+ "bannedDeps": {
393
+ "type": "object",
394
+ "additionalProperties": {
395
+ "anyOf": [
396
+ {
397
+ "type": "string"
398
+ },
399
+ {
400
+ "type": "object",
401
+ "properties": {
402
+ "packages": {
347
403
  "type": "array",
348
- "items": { "type": "string", "enum": ["configuration", "library", "scaffolding", "tool", "automation", "application"] }
404
+ "items": {
405
+ "type": "string"
406
+ }
407
+ },
408
+ "paths": {
409
+ "type": "array",
410
+ "items": {
411
+ "type": "string"
412
+ }
413
+ },
414
+ "reason": {
415
+ "type": "string"
416
+ },
417
+ "replacement": {
418
+ "type": "string"
349
419
  }
350
- ]
420
+ },
421
+ "required": [
422
+ "reason"
423
+ ],
424
+ "additionalProperties": false
425
+ }
426
+ ]
427
+ },
428
+ "description": "Map of dep names or globs → reason (or `{ reason, replacement, packages?, paths? }`). Internal/workspace deps are never flagged here; the workspace-protocol lint owns those.\n\nOptional `packages` (globs over the declaring package's `name`) and `paths` (globs over the workspace-relative `packageDir`) narrow where the rule applies. With both set, either match is enough. Omit both to ban anywhere — the default."
429
+ },
430
+ "customTypes": {
431
+ "type": "object",
432
+ "properties": {
433
+ "autofix": {
434
+ "anyOf": [
435
+ {
436
+ "type": "string",
437
+ "const": "prompt"
438
+ },
439
+ {
440
+ "type": "boolean"
441
+ }
442
+ ],
443
+ "description": "Three-state autofix opt-out. See `workspaceProtocol.autofix` for the contract — same semantics, applied to drift rewrites across engines / packageManager / volta / devEngines.\n\nNote: `--fix` strips any `+sha512.&lt;hash&gt;` suffix from `packageManager` on bump — content-integrity hashes are tied to a specific package, not a version, so users must regenerate via their PM (`pnpm install` re-pins; `corepack use pnpm@X` etc.).",
444
+ "default": true
445
+ },
446
+ "extraTypes": {
447
+ "type": "array",
448
+ "items": {
449
+ "$ref": "#/$defs/ExtraCustomType"
351
450
  },
352
- "stack": {
353
- "oneOf": [
354
- { "type": "string", "enum": ["backend", "frontend", "data", "infrastructure", "systems"] },
355
- { "type": "array", "items": { "type": "string", "enum": ["backend", "frontend", "data", "infrastructure", "systems"] } }
356
- ]
451
+ "description": "User-defined custom-type pin locations. Each entry tells the customTypes lint to read additional version pins from a non-standard JSON path inside every workspace package.json, cluster them by `(name × depName)` like the built-in types, and rewrite them with `--fix`.\n\nThe original built-ins (`engines`, `volta`, `packageManager`, `devEngines.runtime`, `devEngines.packageManager`) keep running unconditionally — these layer on top.\n\nStrategies:\n- `versionsByName`: the JSON at `path` is `{ [depName]: version }` (like `engines` or `pnpm.overrides`).\n- `name@version`: the JSON at `path` is a string of the form `name@version` (like `packageManager`). The leading `name@` is preserved; only the version segment is rewritten.\n- `string`: the JSON at `path` is a bare version string. The `depName` field is required and identifies the dep cluster.\n\n`name` must not collide with a built-in type name. `path` is a dot-separated walk into the package.json (e.g. `pnpm.overrides`)."
452
+ },
453
+ "ignore": {
454
+ "type": "array",
455
+ "items": {
456
+ "type": "string"
357
457
  },
358
- "language": {
359
- "oneOf": [{ "type": "string" }, { "type": "array", "items": { "type": "string" } }]
360
- }
458
+ "description": "Dep names exempt from the drift check (exact match against the field name within the block — e.g. `node`, `pnpm`)."
459
+ },
460
+ "resolve": {
461
+ "type": "string",
462
+ "enum": [
463
+ "highest",
464
+ "lowest"
465
+ ],
466
+ "description": "Resolution strategy used when `--fix` runs.\n- `highest` (default): align every drifting instance to the highest declared version.\n- `lowest`: align to the lowest.",
467
+ "default": "highest"
361
468
  }
362
469
  },
363
- "targets": {
364
- "type": "object",
365
- "additionalProperties": { "$ref": "project.schema.json#/$defs/targetConfiguration" }
366
- }
367
- }
368
- }
369
- },
370
- "taskRunnerOptions": {
371
- "type": "object",
372
- "description": "Task runner engine options.",
373
- "additionalProperties": false,
374
- "properties": {
375
- "parallel": { "oneOf": [{ "type": "number" }, { "type": "boolean" }], "default": 3 },
376
- "smartLockfileHashing": { "type": "boolean", "default": false },
377
- "frameworkInference": { "type": "boolean", "default": false },
378
- "autoFingerprint": { "type": "boolean", "default": false },
379
- "cacheDiagnostics": { "type": "boolean", "default": false },
380
- "cacheDirectory": { "type": "string" },
381
- "dryRun": { "type": "boolean", "default": false },
382
- "summarize": { "type": "boolean", "default": false },
383
- "skipNxCache": { "type": "boolean" },
384
- "globalInputs": { "type": "array", "items": { "type": "string" } },
385
- "globalEnv": { "type": "array", "items": { "type": "string" } },
386
- "maxCacheAge": { "type": "number" },
387
- "maxCacheSize": { "type": "string" },
388
- "remoteCache": {
470
+ "additionalProperties": false,
471
+ "description": "Tweak the custom-types lint that flags drift in `engines.{node,pnpm,...}`, `packageManager`, `volta.{node,pnpm,yarn}`, and the proposed `devEngines.{runtime,packageManager}` array form.\n\nEach (customType × name) cluster is tracked independently — `engines.node` and `volta.node` don't cross-couple here. Use a versionGroup once that lands if you need to enforce they agree."
472
+ },
473
+ "redefineRoot": {
389
474
  "type": "object",
390
- "required": ["url"],
475
+ "properties": {
476
+ "ignore": {
477
+ "type": "array",
478
+ "items": {
479
+ "type": "string"
480
+ },
481
+ "description": "Dep names that are exempt from the redefine-root rule (exact match)."
482
+ }
483
+ },
391
484
  "additionalProperties": false,
485
+ "description": "Tweak the redefine-root lint that flags non-root packages duplicating deps already pinned at the workspace root."
486
+ },
487
+ "workspaceProtocol": {
488
+ "type": "object",
392
489
  "properties": {
393
- "url": {
394
- "type": "string",
395
- "description": "Cache server URL. HTTP: 'https://cache.example.com'. REAPI: 'grpcs://host:port' (TLS) or 'grpc://host:port' (cleartext)."
396
- },
397
- "backend": {
398
- "type": "string",
399
- "enum": ["http", "reapi"],
400
- "default": "http",
401
- "description": "Wire-protocol selector. 'http' is Turborepo-compatible; 'reapi' speaks the Bazel Remote Execution API over gRPC (bazel-remote, BuildBuddy, BuildBarn, EngFlow)."
490
+ "autofix": {
491
+ "anyOf": [
492
+ {
493
+ "type": "string",
494
+ "const": "prompt"
495
+ },
496
+ {
497
+ "type": "boolean"
498
+ }
499
+ ],
500
+ "description": "Three-state autofix opt-out. Some workspaces want detection without rewrite (e.g. dual-licensed packages where `workspace:*` is unsafe).\n- `true` (default): `--fix` rewrites the specifier.\n- `false`: never rewrite — report the violation only.\n- `\"prompt\"`: ask before each rewrite. Falls back to report-only when stdin isn't a TTY (CI). Reserved; not yet implemented.\n\nNote: when `false` (or `\"prompt\"`), `--fix` still **fails CI** on detected violations — the rule is \"report only\", not \"ignore\". Drop the rule from the lint selection if you want a clean exit.",
501
+ "default": true
502
+ }
503
+ },
504
+ "additionalProperties": false,
505
+ "description": "Tweak the workspace-protocol lint that flags internal deps not using the `workspace:` protocol."
506
+ },
507
+ "workspaceVersions": {
508
+ "type": "object",
509
+ "properties": {
510
+ "autofix": {
511
+ "anyOf": [
512
+ {
513
+ "type": "string",
514
+ "const": "prompt"
515
+ },
516
+ {
517
+ "type": "boolean"
518
+ }
519
+ ],
520
+ "description": "Three-state autofix opt-out. See `workspaceProtocol.autofix` for the contract — same semantics, applied to drift rewrites.\n\nAlso gates the `--propose-min` catalog suggestion writer: when `false` / `\"prompt\"`, `--fix --propose-min` reports the proposed catalog entries but does not write `pnpm-workspace.yaml`. Same \"report only, still fails CI\" note applies as on `workspaceProtocol.autofix`.",
521
+ "default": true
402
522
  },
403
- "mode": {
404
- "type": "string",
405
- "enum": ["read", "readwrite", "write"],
406
- "default": "readwrite",
407
- "description": "Cache mode. 'read' pulls only, 'write' pushes only, 'readwrite' does both."
523
+ "ignore": {
524
+ "type": "array",
525
+ "items": {
526
+ "type": "string"
527
+ },
528
+ "description": "Dep names exempt from the version-drift check (exact match)."
408
529
  },
409
- "token": {
530
+ "resolve": {
410
531
  "type": "string",
411
- "description": "HTTP backend bearer token sent as 'Authorization: Bearer …'. For REAPI, use 'bearerToken' instead."
532
+ "enum": [
533
+ "catalog",
534
+ "highest",
535
+ "lowest"
536
+ ],
537
+ "description": "Resolution strategy used when `--fix` runs.\n- `highest` (default): rewrite every drifting instance to the highest sibling specifier.\n- `lowest`: rewrite to the lowest.\n- `catalog`: rewrite any dep already pinned in a workspace catalog to `catalog:` / `catalog:&lt;name>`. Catalog must exist; this lint does not create the catalog (see `vis lint --resolve catalog --propose`).",
538
+ "default": "highest"
539
+ }
540
+ },
541
+ "additionalProperties": false,
542
+ "description": "Tweak the workspace-versions lint that flags external deps declared at inconsistent versions across the workspace."
543
+ }
544
+ },
545
+ "additionalProperties": false,
546
+ "description": "Workspace dep-policy lints exposed via `vis lint`. Each block opts in to a single rule; the command flags (`--workspace-protocol`, `--no-redefine-root`, `--banned-deps`) toggle them per-run."
547
+ },
548
+ "preflight": {
549
+ "type": "object",
550
+ "properties": {
551
+ "lockfile": {
552
+ "type": "boolean",
553
+ "description": "Detect \"lockfile changed but `node_modules` is stale\" before running tasks. Compares lockfile mtime against the package-manager-specific install marker (`node_modules/.modules.yaml` for pnpm, `.package-lock.json` for npm, etc.). Warns in TTY, hard-fails in CI.",
554
+ "default": true
555
+ }
556
+ },
557
+ "additionalProperties": false,
558
+ "description": "Pre-flight checks fired before `vis run` starts the orchestrator. Each check is opt-out (`false`) — defaults are sensible for the common monorepo case."
559
+ },
560
+ "secrets": {
561
+ "type": "object",
562
+ "properties": {
563
+ "baseline": {
564
+ "type": "string",
565
+ "description": "Path to a baseline of previously-triaged findings (relative to workspace root)."
566
+ },
567
+ "config": {
568
+ "type": "object",
569
+ "properties": {
570
+ "extendBundled": {
571
+ "type": "boolean",
572
+ "description": "Layer the user's rules on top of the bundled ruleset. Default: `true`."
573
+ },
574
+ "inline": {
575
+ "type": "object",
576
+ "properties": {
577
+ "allowlist": {},
578
+ "allowlists": {
579
+ "type": "array",
580
+ "items": {}
581
+ },
582
+ "description": {
583
+ "type": "string"
584
+ },
585
+ "rules": {
586
+ "type": "array",
587
+ "items": {}
588
+ },
589
+ "title": {
590
+ "type": "string"
591
+ }
592
+ },
593
+ "additionalProperties": false,
594
+ "description": "Inline rule overrides. Wins over `path` when both are set."
595
+ },
596
+ "path": {
597
+ "type": "string",
598
+ "description": "Path to a JSON config (gitleaks-compatible)."
599
+ },
600
+ "presets": {
601
+ "type": "array",
602
+ "items": {
603
+ "type": "string"
604
+ },
605
+ "description": "Bundled presets layered on top of the default ruleset (e.g. `\"weak-passwords\"`)."
606
+ }
607
+ },
608
+ "additionalProperties": false,
609
+ "description": "Where the ruleset comes from. Omit for the bundled gitleaks default."
610
+ },
611
+ "redact": {
612
+ "type": "boolean",
613
+ "description": "Redact secret values in findings."
614
+ },
615
+ "rules": {
616
+ "type": "object",
617
+ "properties": {
618
+ "exclude": {
619
+ "type": "array",
620
+ "items": {
621
+ "type": "string"
622
+ },
623
+ "description": "Drop findings whose ruleId matches."
624
+ },
625
+ "include": {
626
+ "type": "array",
627
+ "items": {
628
+ "type": "string"
629
+ },
630
+ "description": "Only report findings whose ruleId matches."
631
+ }
632
+ },
633
+ "additionalProperties": false,
634
+ "description": "Rule-id filters applied after scanning."
635
+ },
636
+ "walk": {
637
+ "type": "object",
638
+ "properties": {
639
+ "excludeFromFiles": {
640
+ "type": "array",
641
+ "items": {
642
+ "type": "string"
643
+ },
644
+ "description": "Paths to additional `.gitignore`-syntax files (e.g. `.secretsignore`)."
645
+ },
646
+ "excludePatterns": {
647
+ "type": "array",
648
+ "items": {
649
+ "type": "string"
650
+ },
651
+ "description": "Gitignore-syntax patterns (supports negation, directory markers, leading `/`). Applied on top of `.gitignore`."
652
+ },
653
+ "gitignore": {
654
+ "type": "boolean",
655
+ "description": "Respect `.gitignore`. Default: `true`."
656
+ },
657
+ "includeHidden": {
658
+ "type": "boolean",
659
+ "description": "Include hidden (dotfile) entries. Default: `false`."
660
+ },
661
+ "maxFileSize": {
662
+ "type": "number",
663
+ "description": "Max file size in bytes. Default 10 MiB."
664
+ }
665
+ },
666
+ "additionalProperties": false,
667
+ "description": "Walker / filesystem traversal."
668
+ }
669
+ },
670
+ "additionalProperties": false,
671
+ "description": "Default options for `vis secrets`. CLI flags always take precedence; this block provides workspace-wide defaults so teams can commit config once and every invocation picks it up."
672
+ },
673
+ "security": {
674
+ "type": "object",
675
+ "properties": {
676
+ "allowBuilds": {
677
+ "type": "object",
678
+ "additionalProperties": {
679
+ "type": "boolean"
680
+ },
681
+ "description": "Map of package names/patterns to allow (true) or deny (false) build scripts. Packages not listed are denied by default. Equivalent to pnpm's `allowBuilds` setting."
682
+ },
683
+ "blockExoticSubdeps": {
684
+ "type": "boolean",
685
+ "description": "When true, prevents transitive dependencies from using exotic sources (git repositories, direct tarball URLs). Only direct dependencies may use such sources. Equivalent to pnpm's `blockExoticSubdeps`.",
686
+ "default": false
687
+ },
688
+ "minimumReleaseAge": {
689
+ "type": "number",
690
+ "description": "Minimum number of minutes that must pass after a version is published before vis will allow installation. Reduces risk of installing compromised packages that are typically discovered within hours. Equivalent to pnpm's `minimumReleaseAge`.",
691
+ "examples": [
692
+ 1440
693
+ ],
694
+ "default": 0
695
+ },
696
+ "minimumReleaseAgeExclude": {
697
+ "type": "array",
698
+ "items": {
699
+ "type": "string"
700
+ },
701
+ "description": "Package names/patterns excluded from minimumReleaseAge check. Equivalent to pnpm's `minimumReleaseAgeExclude`.",
702
+ "examples": [
703
+ [
704
+ "webpack",
705
+ "react",
706
+ "@myorg/*"
707
+ ]
708
+ ]
709
+ },
710
+ "socket": {
711
+ "type": "object",
712
+ "properties": {
713
+ "acceptedRisks": {
714
+ "type": "object",
715
+ "additionalProperties": {
716
+ "type": "object",
717
+ "properties": {
718
+ "acceptedAt": {
719
+ "type": "string",
720
+ "description": "ISO 8601 timestamp when the risk was accepted."
721
+ },
722
+ "acceptedScore": {
723
+ "type": "number",
724
+ "description": "The overall Socket.dev score at the time of acceptance."
725
+ },
726
+ "reason": {
727
+ "type": "string",
728
+ "description": "User-provided reason for accepting the risk."
729
+ }
730
+ },
731
+ "required": [
732
+ "acceptedAt",
733
+ "acceptedScore",
734
+ "reason"
735
+ ],
736
+ "additionalProperties": false
737
+ },
738
+ "description": "Packages whose low Socket.dev scores or alerts have been reviewed and explicitly accepted. These packages skip the confirmation prompt during `vis add` and show as \"acknowledged\" in `vis audit`.\n\nKey format: package name (`\"lodash\"`), name@version (`\"lodash@4.17.21\"`), or glob (`\"@myorg/*\"`). Unversioned keys match all versions of that package."
739
+ },
740
+ "apiToken": {
741
+ "type": "string",
742
+ "description": "Custom Socket.dev API token. Falls back to the public API token. Set via VIS_SOCKET_TOKEN environment variable or here."
743
+ },
744
+ "cacheTtlMs": {
745
+ "type": "number",
746
+ "description": "Cache TTL in milliseconds for Socket.dev reports.",
747
+ "default": "3_600_000 (1 hour)"
748
+ },
749
+ "enabled": {
750
+ "type": "boolean",
751
+ "description": "Enable Socket.dev security scanning on install/update/check commands.",
752
+ "default": false
753
+ },
754
+ "minimumScore": {
755
+ "type": "number",
756
+ "description": "Minimum overall Socket.dev score (0–1) for a package to be accepted without a confirmation prompt during `vis add`. Packages scoring below this threshold trigger an interactive prompt asking the user to confirm. Set to 0 to disable.",
757
+ "default": 0.4
758
+ },
759
+ "timeoutMs": {
760
+ "type": "number",
761
+ "description": "Request timeout in milliseconds for the Socket.dev API.",
762
+ "default": "15_000 (15 seconds)"
763
+ }
764
+ },
765
+ "additionalProperties": false,
766
+ "description": "Socket.dev security intelligence configuration. When enabled, vis fetches package security scores, alerts, and report data from the Socket.dev API during install, update, and check commands."
767
+ },
768
+ "strictDepBuilds": {
769
+ "type": "boolean",
770
+ "description": "When true, installation will fail (exit non-zero) if any dependencies have unreviewed build scripts. Equivalent to pnpm's `strictDepBuilds`.",
771
+ "default": false
772
+ },
773
+ "trustPolicy": {
774
+ "type": "string",
775
+ "enum": [
776
+ "no-downgrade",
777
+ "off"
778
+ ],
779
+ "description": "Trust level checking for package publishing.\n- \"off\": No trust checking (default)\n- \"no-downgrade\": Fail if a package's trust level has decreased compared to previous releases (e.g., was published by trusted publisher, now only has provenance). Equivalent to pnpm's `trustPolicy`.",
780
+ "default": "off"
781
+ },
782
+ "trustPolicyExclude": {
783
+ "type": "array",
784
+ "items": {
785
+ "type": "string"
786
+ },
787
+ "description": "Package selectors excluded from trust policy checks. Equivalent to pnpm's `trustPolicyExclude`.",
788
+ "examples": [
789
+ [
790
+ "chokidar@4.0.3",
791
+ "@babel/core@7.28.5"
792
+ ]
793
+ ]
794
+ },
795
+ "trustPolicyIgnoreAfter": {
796
+ "type": "number",
797
+ "description": "Ignore the trust policy check for packages published more than the specified number of minutes ago. Useful for older packages that pre-date provenance support. Equivalent to pnpm's `trustPolicyIgnoreAfter` (10.27+).",
798
+ "examples": [
799
+ 43200
800
+ ]
801
+ },
802
+ "typosquatAllowlist": {
803
+ "type": "array",
804
+ "items": {
805
+ "type": "string"
806
+ },
807
+ "description": "Package names to skip during typosquat detection. Use this for internal packages or known-safe names that happen to look similar to popular packages.",
808
+ "examples": [
809
+ [
810
+ "my-internal-axois",
811
+ "@myorg/recat"
812
+ ]
813
+ ]
814
+ }
815
+ },
816
+ "additionalProperties": false,
817
+ "description": "Supply chain security settings. These settings are inspired by pnpm's security features and are applied universally across all package managers (pnpm, npm, yarn, bun).\n\nFor pnpm users: these map directly to pnpm-workspace.yaml settings. For npm/yarn/bun users: vis enforces these at the vis layer since those package managers lack native support."
818
+ },
819
+ "sharedWorktreeCache": {
820
+ "type": "boolean",
821
+ "description": "Share the cache between sibling git worktrees. When the workspace is a linked worktree (created with `git worktree add`), the cache root is relocated from `&lt;linkedRoot>/.task-runner-cache` to the *main* worktree's `.task-runner-cache`. Multiple parallel agents working in sibling worktrees then share a single cache instead of rebuilding the same hash N times.\n\nSingle-checkout repos (where `.git` is a directory) are unaffected.\n\nSet to `false` to opt out — useful when worktrees deliberately need independent caches, e.g. for hermetic experiments.",
822
+ "default": true
823
+ },
824
+ "sortPackageJson": {
825
+ "type": "object",
826
+ "properties": {
827
+ "editorconfig": {
828
+ "type": "boolean",
829
+ "description": "Discover `.editorconfig` for indent / line-ending defaults (default: true)."
830
+ },
831
+ "formatBugs": {
832
+ "type": "boolean",
833
+ "description": "Collapse `bugs: { url }` to the bare string form when `url` is the only field (default: true)."
834
+ },
835
+ "formatRepository": {
836
+ "type": "boolean",
837
+ "description": "Collapse `repository: { type, url }` to the GitHub `owner/repo` shorthand (default: true)."
838
+ },
839
+ "sortExports": {
840
+ "type": "boolean",
841
+ "description": "Sort `exports` condition keys in canonical order (default: true)."
842
+ },
843
+ "sortScripts": {
844
+ "type": "boolean",
845
+ "description": "Alphabetize script commands (default: false)"
846
+ }
847
+ },
848
+ "additionalProperties": false,
849
+ "description": "sort-package-json command defaults"
850
+ },
851
+ "staged": {
852
+ "$ref": "#/$defs/StagedConfig",
853
+ "description": "Staged file patterns and commands (replaces lint-staged).\n\nAccepts all lint-staged config forms:\n- `string` or `string[]` commands\n- Sync/async functions returning `string | string[]`\n- `{ title, task }` objects for named side-effect tasks\n- Mixed arrays of strings and functions\n- A top-level generate-task function"
854
+ },
855
+ "strictEnv": {
856
+ "type": "boolean",
857
+ "description": "When `true`, every task command is scanned for `${VAR}` / `$VAR` references before spawn. If a referenced var is unset in the task's effective env (envFile + service env + per-task `env` + `process.env`), the task fails with an actionable error naming the missing variable, instead of letting the shell silently substitute an empty string.\n\nOverride per run with `--strict-env` / `--no-strict-env`. Override per target with `options.strictEnv`.",
858
+ "default": false
859
+ },
860
+ "targetDefaults": {
861
+ "type": "object",
862
+ "additionalProperties": {
863
+ "type": "object",
864
+ "properties": {
865
+ "aliases": {
866
+ "type": "array",
867
+ "items": {
868
+ "type": "string"
869
+ },
870
+ "description": "Alternate names that resolve to this target on the CLI. Useful for shortening long canonical names (`test` ↔ `t`) or for offering migration-friendly aliases when renaming targets. Aliases must be globally unique within the workspace."
871
+ },
872
+ "description": {
873
+ "type": "string",
874
+ "description": "One-line description surfaced by `vis list` and (in future) per-task `--help`. Kept short — longer docs belong in project READMEs or vis.config.ts comments."
875
+ },
876
+ "inferred": {
877
+ "type": "boolean",
878
+ "description": "True when the target was synthesized by a Project Crystal-style detector (see {@link ../inference } ) rather than declared by a package.json script, project.json, or vis.task.ts file. Surfaced by `vis list --inferred` and used by tooling to distinguish implicit defaults from explicit user intent."
879
+ },
880
+ "options": {
881
+ "$ref": "#/$defs/VisTargetOptions",
882
+ "description": "Vis-specific target options."
883
+ },
884
+ "preset": {
885
+ "$ref": "#/$defs/TargetPreset",
886
+ "description": "Preset applied before user-specified options."
887
+ },
888
+ "type": {
889
+ "$ref": "#/$defs/TargetType",
890
+ "description": "Semantic task type. Affects caching defaults and CI filtering.",
891
+ "default": "test"
892
+ },
893
+ "always": {
894
+ "type": "boolean",
895
+ "description": "When `true`, this target runs after the main task graph completes — even if upstream tasks failed. Useful for cleanup, teardown, notifications, or anything that should fire regardless of build outcome. Always-tasks are not part of the normal dependency graph and never block other tasks."
896
+ },
897
+ "cache": {
898
+ "type": "boolean",
899
+ "description": "Whether this target is cacheable"
900
+ },
901
+ "cacheOnWarning": {
902
+ "type": "boolean",
903
+ "description": "When `false`, exit-0 runs whose terminal output matched any {@link TargetConfiguration.warningPattern } are not seeded into the cache. Defaults to `true` — warnings are surfaced on the result (`hadWarnings: true`) but caching still happens, matching the \"succeeded with warnings is incremental\" behaviour rush, lage and wireit users have repeatedly asked for."
904
+ },
905
+ "cacheRestore": {
906
+ "type": "object",
907
+ "properties": {
908
+ "preserveMtime": {
909
+ "type": "boolean",
910
+ "description": "Restore each file's modification time from the captured tar header (second precision). When `false`, restored files take the current wall-clock time, matching the legacy behaviour."
911
+ },
912
+ "preservePerms": {
913
+ "type": "boolean",
914
+ "description": "Restore each file's POSIX mode bits (rwx triplets, low 12 bits). When `false`, restored files take the process umask. Only meaningful on POSIX hosts; Windows ignores tar mode."
915
+ }
916
+ },
917
+ "additionalProperties": false,
918
+ "description": "Fine-grained controls over how cached outputs are rehydrated. See {@link CacheRestoreOptions } . Both fields default to `true` (faithful restore); flip individually when downstream tooling needs the legacy \"now\"-stamped behaviour."
919
+ },
920
+ "command": {
921
+ "type": "string",
922
+ "description": "The command to run (alternative to executor)"
923
+ },
924
+ "configurations": {
925
+ "type": "object",
926
+ "additionalProperties": {
927
+ "type": "object",
928
+ "additionalProperties": {}
929
+ },
930
+ "description": "Named configurations (e.g., \"production\", \"development\")"
931
+ },
932
+ "dependsOn": {
933
+ "type": "array",
934
+ "items": {
935
+ "anyOf": [
936
+ {
937
+ "type": "string"
938
+ },
939
+ {
940
+ "type": "object",
941
+ "properties": {
942
+ "dependencies": {
943
+ "type": "boolean",
944
+ "description": "Whether this is a dependency on the same project"
945
+ },
946
+ "params": {
947
+ "type": "string",
948
+ "enum": [
949
+ "forward",
950
+ "ignore"
951
+ ],
952
+ "description": "Params to pass through"
953
+ },
954
+ "projects": {
955
+ "anyOf": [
956
+ {
957
+ "type": "string"
958
+ },
959
+ {
960
+ "type": "array",
961
+ "items": {
962
+ "type": "string"
963
+ }
964
+ }
965
+ ],
966
+ "description": "The project name (if different from the current project)"
967
+ },
968
+ "target": {
969
+ "type": "string",
970
+ "description": "The target name"
971
+ }
972
+ },
973
+ "required": [
974
+ "target"
975
+ ],
976
+ "additionalProperties": false,
977
+ "description": "Defines a dependency on another target."
978
+ }
979
+ ]
980
+ },
981
+ "description": "Other targets this target depends on"
982
+ },
983
+ "executor": {
984
+ "type": "string",
985
+ "description": "The executor/command to run"
986
+ },
987
+ "inputs": {
988
+ "type": "array",
989
+ "items": {
990
+ "anyOf": [
991
+ {
992
+ "type": "string"
993
+ },
994
+ {
995
+ "anyOf": [
996
+ {
997
+ "type": "object",
998
+ "properties": {
999
+ "fileset": {
1000
+ "anyOf": [
1001
+ {
1002
+ "type": "object",
1003
+ "properties": {
1004
+ "base": {
1005
+ "type": "string",
1006
+ "enum": [
1007
+ "package",
1008
+ "workspace"
1009
+ ],
1010
+ "description": "Anchor for the pattern."
1011
+ },
1012
+ "pattern": {
1013
+ "type": "string",
1014
+ "description": "Glob pattern (may start with `!` for negation)."
1015
+ }
1016
+ },
1017
+ "required": [
1018
+ "base",
1019
+ "pattern"
1020
+ ],
1021
+ "additionalProperties": false,
1022
+ "description": "Object form of a fileset pattern, for anchoring to the workspace root."
1023
+ },
1024
+ {
1025
+ "type": "string"
1026
+ }
1027
+ ]
1028
+ }
1029
+ },
1030
+ "required": [
1031
+ "fileset"
1032
+ ],
1033
+ "additionalProperties": false,
1034
+ "description": "An input based on file patterns.\n\n`fileset` may be a bare glob string (package-root relative) or an object form `{ pattern, base }` to anchor explicitly to the workspace root. Negation (`!` prefix) works in both forms."
1035
+ },
1036
+ {
1037
+ "type": "object",
1038
+ "properties": {
1039
+ "runtime": {
1040
+ "type": "string"
1041
+ }
1042
+ },
1043
+ "required": [
1044
+ "runtime"
1045
+ ],
1046
+ "additionalProperties": false,
1047
+ "description": "An input based on a runtime command."
1048
+ },
1049
+ {
1050
+ "type": "object",
1051
+ "properties": {
1052
+ "env": {
1053
+ "type": "string"
1054
+ }
1055
+ },
1056
+ "required": [
1057
+ "env"
1058
+ ],
1059
+ "additionalProperties": false,
1060
+ "description": "An input based on environment variables."
1061
+ },
1062
+ {
1063
+ "type": "object",
1064
+ "properties": {
1065
+ "externalDependencies": {
1066
+ "type": "array",
1067
+ "items": {
1068
+ "type": "string"
1069
+ }
1070
+ }
1071
+ },
1072
+ "required": [
1073
+ "externalDependencies"
1074
+ ],
1075
+ "additionalProperties": false,
1076
+ "description": "An input based on external dependency versions."
1077
+ }
1078
+ ],
1079
+ "description": "Defines an input for cache invalidation."
1080
+ }
1081
+ ]
1082
+ },
1083
+ "description": "Input patterns for cache invalidation"
1084
+ },
1085
+ "outputs": {
1086
+ "type": "array",
1087
+ "items": {
1088
+ "type": "string"
1089
+ },
1090
+ "description": "Output patterns produced by this target"
1091
+ },
1092
+ "parallelism": {
1093
+ "type": "boolean",
1094
+ "description": "Whether this target supports parallel execution"
1095
+ },
1096
+ "warningPattern": {
1097
+ "anyOf": [
1098
+ {
1099
+ "type": "string"
1100
+ },
1101
+ {
1102
+ "type": "array",
1103
+ "items": {
1104
+ "type": "string"
1105
+ }
1106
+ }
1107
+ ],
1108
+ "description": "Regex source string(s) that mark a successful task as having emitted warnings. The orchestrator scans the task's combined terminal output after a 0-exit and, on first match, sets `hadWarnings` on the result. Combine with `cacheOnWarning: false` to skip caching for warning-tainted runs. Both bare strings and arrays are accepted; arrays are tested in order.\n\n ```ts warningPattern: [\"\\\\bwarning\\\\b\", \"TS\\\\d{4}\"] ```"
1109
+ },
1110
+ "when": {
1111
+ "type": "object",
1112
+ "properties": {
1113
+ "branch": {
1114
+ "anyOf": [
1115
+ {
1116
+ "type": "string"
1117
+ },
1118
+ {
1119
+ "type": "array",
1120
+ "items": {
1121
+ "type": "string"
1122
+ }
1123
+ }
1124
+ ],
1125
+ "description": "Match against the current git branch (HEAD)."
1126
+ },
1127
+ "ci": {
1128
+ "type": "boolean",
1129
+ "description": "Run only when invoked inside CI when `true`, only outside CI when `false`. Detects CI via the `CI` env var (the convention GitHub Actions, GitLab, CircleCI, Jenkins, etc. all share)."
1130
+ },
1131
+ "env": {
1132
+ "anyOf": [
1133
+ {
1134
+ "anyOf": [
1135
+ {
1136
+ "type": "string"
1137
+ },
1138
+ {
1139
+ "type": "object",
1140
+ "properties": {
1141
+ "equals": {
1142
+ "type": "string",
1143
+ "description": "Match this exact value. Mutually exclusive with `exists`."
1144
+ },
1145
+ "exists": {
1146
+ "type": "boolean",
1147
+ "description": "Assert the variable is set & non-empty (`true`) or unset/empty (`false`)."
1148
+ },
1149
+ "name": {
1150
+ "type": "string",
1151
+ "description": "Variable name."
1152
+ }
1153
+ },
1154
+ "required": [
1155
+ "name"
1156
+ ],
1157
+ "additionalProperties": false
1158
+ }
1159
+ ],
1160
+ "description": "An environment-variable match. The string form is shorthand for `{ name, exists: true }` (set + non-empty). The object form supports either presence assertions or exact-value matching."
1161
+ },
1162
+ {
1163
+ "type": "array",
1164
+ "items": {
1165
+ "anyOf": [
1166
+ {
1167
+ "type": "string"
1168
+ },
1169
+ {
1170
+ "type": "object",
1171
+ "properties": {
1172
+ "equals": {
1173
+ "type": "string",
1174
+ "description": "Match this exact value. Mutually exclusive with `exists`."
1175
+ },
1176
+ "exists": {
1177
+ "type": "boolean",
1178
+ "description": "Assert the variable is set & non-empty (`true`) or unset/empty (`false`)."
1179
+ },
1180
+ "name": {
1181
+ "type": "string",
1182
+ "description": "Variable name."
1183
+ }
1184
+ },
1185
+ "required": [
1186
+ "name"
1187
+ ],
1188
+ "additionalProperties": false
1189
+ }
1190
+ ],
1191
+ "description": "An environment-variable match. The string form is shorthand for `{ name, exists: true }` (set + non-empty). The object form supports either presence assertions or exact-value matching."
1192
+ }
1193
+ }
1194
+ ],
1195
+ "description": "Match against environment variables. A bare string asserts the variable is set and non-empty; the object form lets you match an exact value or just assert presence/absence."
1196
+ },
1197
+ "not": {
1198
+ "type": "object",
1199
+ "properties": {
1200
+ "branch": {
1201
+ "anyOf": [
1202
+ {
1203
+ "type": "string"
1204
+ },
1205
+ {
1206
+ "type": "array",
1207
+ "items": {
1208
+ "type": "string"
1209
+ }
1210
+ }
1211
+ ]
1212
+ },
1213
+ "ci": {
1214
+ "type": "boolean"
1215
+ },
1216
+ "env": {
1217
+ "anyOf": [
1218
+ {
1219
+ "anyOf": [
1220
+ {
1221
+ "type": "string"
1222
+ },
1223
+ {
1224
+ "type": "object",
1225
+ "properties": {
1226
+ "equals": {
1227
+ "type": "string",
1228
+ "description": "Match this exact value. Mutually exclusive with `exists`."
1229
+ },
1230
+ "exists": {
1231
+ "type": "boolean",
1232
+ "description": "Assert the variable is set & non-empty (`true`) or unset/empty (`false`)."
1233
+ },
1234
+ "name": {
1235
+ "type": "string",
1236
+ "description": "Variable name."
1237
+ }
1238
+ },
1239
+ "required": [
1240
+ "name"
1241
+ ],
1242
+ "additionalProperties": false
1243
+ }
1244
+ ],
1245
+ "description": "An environment-variable match. The string form is shorthand for `{ name, exists: true }` (set + non-empty). The object form supports either presence assertions or exact-value matching."
1246
+ },
1247
+ {
1248
+ "type": "array",
1249
+ "items": {
1250
+ "anyOf": [
1251
+ {
1252
+ "type": "string"
1253
+ },
1254
+ {
1255
+ "type": "object",
1256
+ "properties": {
1257
+ "equals": {
1258
+ "type": "string",
1259
+ "description": "Match this exact value. Mutually exclusive with `exists`."
1260
+ },
1261
+ "exists": {
1262
+ "type": "boolean",
1263
+ "description": "Assert the variable is set & non-empty (`true`) or unset/empty (`false`)."
1264
+ },
1265
+ "name": {
1266
+ "type": "string",
1267
+ "description": "Variable name."
1268
+ }
1269
+ },
1270
+ "required": [
1271
+ "name"
1272
+ ],
1273
+ "additionalProperties": false
1274
+ }
1275
+ ],
1276
+ "description": "An environment-variable match. The string form is shorthand for `{ name, exists: true }` (set + non-empty). The object form supports either presence assertions or exact-value matching."
1277
+ }
1278
+ }
1279
+ ]
1280
+ },
1281
+ "os": {
1282
+ "anyOf": [
1283
+ {
1284
+ "type": "string",
1285
+ "enum": [
1286
+ "aix",
1287
+ "darwin",
1288
+ "freebsd",
1289
+ "linux",
1290
+ "openbsd",
1291
+ "sunos",
1292
+ "windows",
1293
+ "win32"
1294
+ ],
1295
+ "description": "Aliased platform list — `\"windows\"` is sugar for Node's `\"win32\"`."
1296
+ },
1297
+ {
1298
+ "type": "array",
1299
+ "items": {
1300
+ "type": "string",
1301
+ "enum": [
1302
+ "aix",
1303
+ "darwin",
1304
+ "freebsd",
1305
+ "linux",
1306
+ "openbsd",
1307
+ "sunos",
1308
+ "windows",
1309
+ "win32"
1310
+ ],
1311
+ "description": "Aliased platform list — `\"windows\"` is sugar for Node's `\"win32\"`."
1312
+ }
1313
+ }
1314
+ ]
1315
+ }
1316
+ },
1317
+ "additionalProperties": false,
1318
+ "description": "Negative mirrors. A task runs only when *all* `not.*` clauses fail."
1319
+ },
1320
+ "os": {
1321
+ "anyOf": [
1322
+ {
1323
+ "type": "string",
1324
+ "enum": [
1325
+ "aix",
1326
+ "darwin",
1327
+ "freebsd",
1328
+ "linux",
1329
+ "openbsd",
1330
+ "sunos",
1331
+ "windows",
1332
+ "win32"
1333
+ ],
1334
+ "description": "Aliased platform list — `\"windows\"` is sugar for Node's `\"win32\"`."
1335
+ },
1336
+ {
1337
+ "type": "array",
1338
+ "items": {
1339
+ "type": "string",
1340
+ "enum": [
1341
+ "aix",
1342
+ "darwin",
1343
+ "freebsd",
1344
+ "linux",
1345
+ "openbsd",
1346
+ "sunos",
1347
+ "windows",
1348
+ "win32"
1349
+ ],
1350
+ "description": "Aliased platform list — `\"windows\"` is sugar for Node's `\"win32\"`."
1351
+ }
1352
+ }
1353
+ ],
1354
+ "description": "Match `process.platform` (`\"linux\" | \"darwin\" | \"win32\" | \"freebsd\" | \"openbsd\" | \"sunos\" | \"aix\"`). Pass `\"windows\"` as an alias for `\"win32\"` — easier to remember and matches what people type."
1355
+ }
1356
+ },
1357
+ "additionalProperties": false,
1358
+ "description": "Predicate that gates execution. When the condition evaluates to `false` for the current environment, the task is skipped (marked `\"skipped\"`, not failed). Combine with `os`, `env`, `branch`, and `ci` clauses for granular control:\n\n ```ts when: { os: \"linux\", ci: true, env: \"DEPLOY_TOKEN\" } ```"
1359
+ }
1360
+ },
1361
+ "additionalProperties": false
1362
+ },
1363
+ "description": "Target default configurations"
1364
+ },
1365
+ "taskDefaults": {
1366
+ "type": "array",
1367
+ "items": {
1368
+ "$ref": "#/$defs/TaskDefaultsBlock"
1369
+ },
1370
+ "description": "Cascading task-default blocks. Each block may scope its targets to a subset of projects via `scope`. Blocks are evaluated in order; later blocks override earlier ones when the same field is set.\n\nScope matching is additive — if `scope` is omitted, the block applies to every project."
1371
+ },
1372
+ "taskGroups": {
1373
+ "type": "object",
1374
+ "additionalProperties": {
1375
+ "type": "array",
1376
+ "items": {
1377
+ "anyOf": [
1378
+ {
1379
+ "type": "string"
1380
+ },
1381
+ {
1382
+ "type": "object",
1383
+ "properties": {
1384
+ "dependencies": {
1385
+ "type": "boolean"
1386
+ },
1387
+ "projects": {
1388
+ "anyOf": [
1389
+ {
1390
+ "type": "string"
1391
+ },
1392
+ {
1393
+ "type": "array",
1394
+ "items": {
1395
+ "type": "string"
1396
+ }
1397
+ }
1398
+ ]
1399
+ },
1400
+ "target": {
1401
+ "type": "string"
1402
+ }
1403
+ },
1404
+ "required": [
1405
+ "target"
1406
+ ],
1407
+ "additionalProperties": false
1408
+ },
1409
+ {
1410
+ "type": "object",
1411
+ "properties": {
1412
+ "group": {
1413
+ "type": "string"
1414
+ }
1415
+ },
1416
+ "required": [
1417
+ "group"
1418
+ ],
1419
+ "additionalProperties": false
1420
+ }
1421
+ ]
1422
+ }
1423
+ },
1424
+ "description": "Named bundles of target dependencies, referenceable from any task's `dependsOn`. `dependsOn: [{ group: \"lint\" }]` expands to every entry in the named group; nested groups are resolved recursively and a cycle raises during discovery."
1425
+ },
1426
+ "taskRunnerOptions": {
1427
+ "type": "object",
1428
+ "properties": {
1429
+ "autoEnvVars": {
1430
+ "type": "boolean",
1431
+ "description": "Scan each task's resolved command text for `$VAR`/`${VAR}` references and automatically fingerprint those env vars. Catches tasks like `curl ${VERCEL_URL}/api` where the user forgot to declare the reference in `envVars`/`globalEnv`.",
1432
+ "default": false
1433
+ },
1434
+ "autoFingerprint": {
1435
+ "type": "boolean",
1436
+ "description": "Enable auto-fingerprinting mode (Vite Task-style). When enabled, the task runner automatically tracks which files a task accesses during execution and uses that for cache invalidation instead of requiring manual input configuration.\n\nFalls back to explicit inputs (Nx-style) when file tracking is not supported on the current platform.",
1437
+ "default": false
1438
+ },
1439
+ "cacheDiagnostics": {
1440
+ "type": "boolean",
1441
+ "description": "Whether to show cache miss diagnostics (why a cache miss occurred).",
1442
+ "default": false
1443
+ },
1444
+ "cacheDirectory": {
1445
+ "type": "string",
1446
+ "description": "Directory for storing cache"
1447
+ },
1448
+ "dryRun": {
1449
+ "type": "boolean",
1450
+ "description": "Dry-run mode: compute hashes and check cache but don't execute tasks. Useful for debugging cache hits/misses.",
1451
+ "default": false
1452
+ },
1453
+ "envVars": {
1454
+ "type": "array",
1455
+ "items": {
1456
+ "type": "string"
1457
+ },
1458
+ "description": "Custom environment variables to include in hash"
1459
+ },
1460
+ "fingerprintEnvPatterns": {
1461
+ "type": "array",
1462
+ "items": {
1463
+ "type": "string"
1464
+ },
1465
+ "description": "Environment variable patterns to include in auto-fingerprint. Supports wildcard patterns like \"VITE_*\". Only used when autoFingerprint is enabled."
1466
+ },
1467
+ "frameworkInference": {
1468
+ "type": "boolean",
1469
+ "description": "Enable framework environment variable inference. When true, automatically detects common frontend frameworks and includes their public env var prefixes in the task hash:\n- Next.js: NEXT_PUBLIC_*\n- Vite: VITE_*\n- Create React App: REACT_APP_*\n- Gatsby: GATSBY_*\n- Nuxt: NUXT_PUBLIC_*\n- Expo: EXPO_PUBLIC_*\n\nMatches Turborepo's framework inference behavior.",
1470
+ "default": false
1471
+ },
1472
+ "globalEnv": {
1473
+ "type": "array",
1474
+ "items": {
1475
+ "type": "string"
1476
+ },
1477
+ "description": "Global environment variables that invalidate ALL task hashes. Matches Turborepo's `globalEnv`."
1478
+ },
1479
+ "globalInputs": {
1480
+ "type": "array",
1481
+ "items": {
1482
+ "type": "string"
1483
+ },
1484
+ "description": "Global input files that invalidate ALL task hashes when changed. These are workspace-root-relative paths.\n\nDefault: [\"package-lock.json\", \"pnpm-lock.yaml\", \"yarn.lock\", \"tsconfig.base.json\", \".env\"]\n\nWhen any global input changes, every task's hash changes, forcing a full rebuild. This matches Turborepo's `globalDependencies`."
1485
+ },
1486
+ "incrementalFileHashing": {
1487
+ "type": "boolean",
1488
+ "description": "When `true`, file hashes are cached in a persistent mtime+size indexed snapshot under `node_modules/.cache/task-runner/`. On subsequent runs, unchanged files skip content re-reads — cuts cold-cache fingerprint time dramatically on large workspaces.\n\nChanged or new files still get full content hashing. Safe to leave on by default; overhead when nothing matches is a single `stat` call per file.",
1489
+ "default": false
1490
+ },
1491
+ "maxCacheAge": {
1492
+ "type": "number",
1493
+ "description": "Maximum age of cache entries in milliseconds"
1494
+ },
1495
+ "maxCacheSize": {
1496
+ "type": "string",
1497
+ "description": "Maximum cache size (e.g., \"1GB\")"
1498
+ },
1499
+ "namedInputs": {
1500
+ "type": "object",
1501
+ "additionalProperties": {
1502
+ "type": "array",
1503
+ "items": {
1504
+ "anyOf": [
1505
+ {
1506
+ "type": "string"
1507
+ },
1508
+ {
1509
+ "anyOf": [
1510
+ {
1511
+ "type": "object",
1512
+ "properties": {
1513
+ "fileset": {
1514
+ "anyOf": [
1515
+ {
1516
+ "type": "object",
1517
+ "properties": {
1518
+ "base": {
1519
+ "type": "string",
1520
+ "enum": [
1521
+ "package",
1522
+ "workspace"
1523
+ ],
1524
+ "description": "Anchor for the pattern."
1525
+ },
1526
+ "pattern": {
1527
+ "type": "string",
1528
+ "description": "Glob pattern (may start with `!` for negation)."
1529
+ }
1530
+ },
1531
+ "required": [
1532
+ "base",
1533
+ "pattern"
1534
+ ],
1535
+ "additionalProperties": false,
1536
+ "description": "Object form of a fileset pattern, for anchoring to the workspace root."
1537
+ },
1538
+ {
1539
+ "type": "string"
1540
+ }
1541
+ ]
1542
+ }
1543
+ },
1544
+ "required": [
1545
+ "fileset"
1546
+ ],
1547
+ "additionalProperties": false,
1548
+ "description": "An input based on file patterns.\n\n`fileset` may be a bare glob string (package-root relative) or an object form `{ pattern, base }` to anchor explicitly to the workspace root. Negation (`!` prefix) works in both forms."
1549
+ },
1550
+ {
1551
+ "type": "object",
1552
+ "properties": {
1553
+ "runtime": {
1554
+ "type": "string"
1555
+ }
1556
+ },
1557
+ "required": [
1558
+ "runtime"
1559
+ ],
1560
+ "additionalProperties": false,
1561
+ "description": "An input based on a runtime command."
1562
+ },
1563
+ {
1564
+ "type": "object",
1565
+ "properties": {
1566
+ "env": {
1567
+ "type": "string"
1568
+ }
1569
+ },
1570
+ "required": [
1571
+ "env"
1572
+ ],
1573
+ "additionalProperties": false,
1574
+ "description": "An input based on environment variables."
1575
+ },
1576
+ {
1577
+ "type": "object",
1578
+ "properties": {
1579
+ "externalDependencies": {
1580
+ "type": "array",
1581
+ "items": {
1582
+ "type": "string"
1583
+ }
1584
+ }
1585
+ },
1586
+ "required": [
1587
+ "externalDependencies"
1588
+ ],
1589
+ "additionalProperties": false,
1590
+ "description": "An input based on external dependency versions."
1591
+ }
1592
+ ],
1593
+ "description": "Defines an input for cache invalidation."
1594
+ }
1595
+ ]
1596
+ }
1597
+ },
1598
+ "description": "Named inputs for cache invalidation"
1599
+ },
1600
+ "namespaceByGlobalEnv": {
1601
+ "type": "boolean",
1602
+ "description": "When `true`, the cache directory is partitioned by a hash of the resolved `globalEnv` values. Changing a globalEnv var moves cache writes into a new namespace; rolling it back reuses the old namespace and its hits. Without this option, any globalEnv change silently busts every cached entry.\n\nKeep disabled when globalEnv is stable across runs — the extra path depth offers no value, and misconfigured namespaces can hide stale hits.",
1603
+ "default": false
1604
+ },
1605
+ "parallel": {
1606
+ "type": [
1607
+ "number",
1608
+ "boolean"
1609
+ ],
1610
+ "description": "Maximum number of parallel tasks"
1611
+ },
1612
+ "remoteCache": {
1613
+ "type": "object",
1614
+ "properties": {
1615
+ "allowInsecureBearer": {
1616
+ "type": "boolean",
1617
+ "description": "Opt out of the REAPI safety check that refuses to send a bearer token over cleartext gRPC. Required only when the connection terminates inside a trusted boundary (loopback dev cache, mesh mTLS sidecar that strips/re-encrypts on the next hop). Default `false` — production callers should reach for `grpcs://` first.\n\nREAPI-only."
1618
+ },
1619
+ "backend": {
1620
+ "type": "string",
1621
+ "enum": [
1622
+ "http",
1623
+ "reapi"
1624
+ ],
1625
+ "description": "Wire-protocol selector. `\"http\"` is the Turborepo-compatible single-tarball cache; `\"reapi\"` switches to the Bazel Remote Execution API gRPC client, unlocking `bazel-remote`, BuildBuddy, BuildBarn, EngFlow as drop-in backends.",
1626
+ "default": "http"
1627
+ },
1628
+ "bearerToken": {
1629
+ "type": "string",
1630
+ "description": "Bearer token sent in REAPI's `authorization: Bearer {token}` gRPC metadata header. REAPI-only — HTTP backend uses `token`."
1631
+ },
1632
+ "compression": {
1633
+ "type": "string",
1634
+ "enum": [
1635
+ "brotli",
1636
+ "gzip"
1637
+ ],
1638
+ "description": "HTTP-only: tarball compression on the wire.",
1639
+ "default": "gzip"
1640
+ },
1641
+ "instanceName": {
1642
+ "type": "string",
1643
+ "description": "REAPI-only `instance_name` for multi-tenant servers (a single gRPC endpoint can host multiple logical caches keyed on the `instance_name` prefix)."
1644
+ },
1645
+ "localCasRoot": {
1646
+ "type": "string",
1647
+ "description": "Local CAS root used by the per-blob {@link RemoteCacheBackend } methods. The HTTP wire format is still single-tarball; on retrieve the bridge extracts blobs into this root so a follow-up `fetchBlob` is just a local read."
1648
+ },
1649
+ "mode": {
1650
+ "type": "string",
1651
+ "enum": [
1652
+ "read",
1653
+ "readwrite",
1654
+ "write"
1655
+ ],
1656
+ "description": "Canonical cache mode flag.\n\n- `\"read\"`: Pull cache hits, never push. Sensible default for local dev so a developer doesn't poison the shared cache while their workspace is dirty.\n- `\"write\"`: Push results, never read. Useful for refill / warm-up jobs that should always re-execute and re-upload.\n- `\"readwrite\"`: Both. Default for CI.",
1657
+ "default": "readwrite"
1658
+ },
1659
+ "signing": {
1660
+ "type": "object",
1661
+ "properties": {
1662
+ "secret": {
1663
+ "type": "string",
1664
+ "description": "Shared secret. Must be at least 16 characters."
1665
+ },
1666
+ "verifyOnDownload": {
1667
+ "type": "boolean",
1668
+ "description": "Reject downloads whose signature doesn't match or is missing. Set to `true` once every upload on your server is signed.",
1669
+ "default": false
1670
+ }
1671
+ },
1672
+ "required": [
1673
+ "secret"
1674
+ ],
1675
+ "additionalProperties": false,
1676
+ "description": "HTTP-only: HMAC-SHA256 signing for upload integrity."
1677
+ },
1678
+ "teamId": {
1679
+ "type": "string",
1680
+ "description": "Team / namespace for cache isolation."
1681
+ },
1682
+ "timeout": {
1683
+ "type": "number",
1684
+ "description": "Per-call request timeout in milliseconds.",
1685
+ "default": 30000
1686
+ },
1687
+ "token": {
1688
+ "type": "string",
1689
+ "description": "HTTP authentication token sent as `Authorization: Bearer …`. For REAPI, use `bearerToken` instead — same wire mechanic, but a separate field so REAPI's cleartext-bearer guard can distinguish \"user explicitly opted into a gRPC token\" from \"user set HTTP auth and accidentally selected the REAPI backend\"."
1690
+ },
1691
+ "url": {
1692
+ "type": "string",
1693
+ "description": "Cache server URL.\n\n- HTTP: `https://cache.example.com`\n- REAPI: `grpcs://host:port` (TLS, recommended) or `grpc://host:port` (cleartext — bearer tokens are refused unless `allowInsecureBearer`)."
1694
+ }
1695
+ },
1696
+ "required": [
1697
+ "url"
1698
+ ],
1699
+ "additionalProperties": false,
1700
+ "description": "Remote cache configuration. When configured, the task runner checks the remote cache after a local miss and uploads results after execution. See {@link RemoteCacheOptions } for the full HTTP and REAPI surface."
1701
+ },
1702
+ "skipNxCache": {
1703
+ "type": "boolean",
1704
+ "description": "Whether to skip cache reads"
1705
+ },
1706
+ "smartLockfileHashing": {
1707
+ "type": "boolean",
1708
+ "description": "Enable smart lockfile hashing. Instead of hashing the entire lockfile (which busts ALL caches), only hash the resolved versions of each package's actual dependencies. This matches Turborepo's smart lockfile hashing behavior.",
1709
+ "default": false
1710
+ },
1711
+ "summarize": {
1712
+ "type": "boolean",
1713
+ "description": "Generate a detailed JSON run summary after execution. When true, writes a summary file to `.task-runner/runs/` containing all task inputs, outputs, hashes, timings, and cache status.\n\nUseful for debugging cache misses and comparing runs. Matches Turborepo's `--summarize` flag.",
1714
+ "default": false
1715
+ },
1716
+ "targetDefaults": {
1717
+ "type": "object",
1718
+ "additionalProperties": {
1719
+ "type": "object",
1720
+ "properties": {
1721
+ "always": {
1722
+ "type": "boolean",
1723
+ "description": "When `true`, this target runs after the main task graph completes — even if upstream tasks failed. Useful for cleanup, teardown, notifications, or anything that should fire regardless of build outcome. Always-tasks are not part of the normal dependency graph and never block other tasks."
1724
+ },
1725
+ "cache": {
1726
+ "type": "boolean",
1727
+ "description": "Whether this target is cacheable"
1728
+ },
1729
+ "cacheOnWarning": {
1730
+ "type": "boolean",
1731
+ "description": "When `false`, exit-0 runs whose terminal output matched any {@link TargetConfiguration.warningPattern } are not seeded into the cache. Defaults to `true` — warnings are surfaced on the result (`hadWarnings: true`) but caching still happens, matching the \"succeeded with warnings is incremental\" behaviour rush, lage and wireit users have repeatedly asked for."
1732
+ },
1733
+ "cacheRestore": {
1734
+ "type": "object",
1735
+ "properties": {
1736
+ "preserveMtime": {
1737
+ "type": "boolean",
1738
+ "description": "Restore each file's modification time from the captured tar header (second precision). When `false`, restored files take the current wall-clock time, matching the legacy behaviour."
1739
+ },
1740
+ "preservePerms": {
1741
+ "type": "boolean",
1742
+ "description": "Restore each file's POSIX mode bits (rwx triplets, low 12 bits). When `false`, restored files take the process umask. Only meaningful on POSIX hosts; Windows ignores tar mode."
1743
+ }
1744
+ },
1745
+ "additionalProperties": false,
1746
+ "description": "Fine-grained controls over how cached outputs are rehydrated. See {@link CacheRestoreOptions } . Both fields default to `true` (faithful restore); flip individually when downstream tooling needs the legacy \"now\"-stamped behaviour."
1747
+ },
1748
+ "command": {
1749
+ "type": "string",
1750
+ "description": "The command to run (alternative to executor)"
1751
+ },
1752
+ "configurations": {
1753
+ "type": "object",
1754
+ "additionalProperties": {
1755
+ "type": "object",
1756
+ "additionalProperties": {}
1757
+ },
1758
+ "description": "Named configurations (e.g., \"production\", \"development\")"
1759
+ },
1760
+ "dependsOn": {
1761
+ "type": "array",
1762
+ "items": {
1763
+ "anyOf": [
1764
+ {
1765
+ "type": "string"
1766
+ },
1767
+ {
1768
+ "type": "object",
1769
+ "properties": {
1770
+ "dependencies": {
1771
+ "type": "boolean",
1772
+ "description": "Whether this is a dependency on the same project"
1773
+ },
1774
+ "params": {
1775
+ "type": "string",
1776
+ "enum": [
1777
+ "forward",
1778
+ "ignore"
1779
+ ],
1780
+ "description": "Params to pass through"
1781
+ },
1782
+ "projects": {
1783
+ "anyOf": [
1784
+ {
1785
+ "type": "string"
1786
+ },
1787
+ {
1788
+ "type": "array",
1789
+ "items": {
1790
+ "type": "string"
1791
+ }
1792
+ }
1793
+ ],
1794
+ "description": "The project name (if different from the current project)"
1795
+ },
1796
+ "target": {
1797
+ "type": "string",
1798
+ "description": "The target name"
1799
+ }
1800
+ },
1801
+ "required": [
1802
+ "target"
1803
+ ],
1804
+ "additionalProperties": false,
1805
+ "description": "Defines a dependency on another target."
1806
+ }
1807
+ ]
1808
+ },
1809
+ "description": "Other targets this target depends on"
1810
+ },
1811
+ "executor": {
1812
+ "type": "string",
1813
+ "description": "The executor/command to run"
1814
+ },
1815
+ "inputs": {
1816
+ "type": "array",
1817
+ "items": {
1818
+ "anyOf": [
1819
+ {
1820
+ "type": "string"
1821
+ },
1822
+ {
1823
+ "anyOf": [
1824
+ {
1825
+ "type": "object",
1826
+ "properties": {
1827
+ "fileset": {
1828
+ "anyOf": [
1829
+ {
1830
+ "type": "object",
1831
+ "properties": {
1832
+ "base": {
1833
+ "type": "string",
1834
+ "enum": [
1835
+ "package",
1836
+ "workspace"
1837
+ ],
1838
+ "description": "Anchor for the pattern."
1839
+ },
1840
+ "pattern": {
1841
+ "type": "string",
1842
+ "description": "Glob pattern (may start with `!` for negation)."
1843
+ }
1844
+ },
1845
+ "required": [
1846
+ "base",
1847
+ "pattern"
1848
+ ],
1849
+ "additionalProperties": false,
1850
+ "description": "Object form of a fileset pattern, for anchoring to the workspace root."
1851
+ },
1852
+ {
1853
+ "type": "string"
1854
+ }
1855
+ ]
1856
+ }
1857
+ },
1858
+ "required": [
1859
+ "fileset"
1860
+ ],
1861
+ "additionalProperties": false,
1862
+ "description": "An input based on file patterns.\n\n`fileset` may be a bare glob string (package-root relative) or an object form `{ pattern, base }` to anchor explicitly to the workspace root. Negation (`!` prefix) works in both forms."
1863
+ },
1864
+ {
1865
+ "type": "object",
1866
+ "properties": {
1867
+ "runtime": {
1868
+ "type": "string"
1869
+ }
1870
+ },
1871
+ "required": [
1872
+ "runtime"
1873
+ ],
1874
+ "additionalProperties": false,
1875
+ "description": "An input based on a runtime command."
1876
+ },
1877
+ {
1878
+ "type": "object",
1879
+ "properties": {
1880
+ "env": {
1881
+ "type": "string"
1882
+ }
1883
+ },
1884
+ "required": [
1885
+ "env"
1886
+ ],
1887
+ "additionalProperties": false,
1888
+ "description": "An input based on environment variables."
1889
+ },
1890
+ {
1891
+ "type": "object",
1892
+ "properties": {
1893
+ "externalDependencies": {
1894
+ "type": "array",
1895
+ "items": {
1896
+ "type": "string"
1897
+ }
1898
+ }
1899
+ },
1900
+ "required": [
1901
+ "externalDependencies"
1902
+ ],
1903
+ "additionalProperties": false,
1904
+ "description": "An input based on external dependency versions."
1905
+ }
1906
+ ],
1907
+ "description": "Defines an input for cache invalidation."
1908
+ }
1909
+ ]
1910
+ },
1911
+ "description": "Input patterns for cache invalidation"
1912
+ },
1913
+ "options": {
1914
+ "type": "object",
1915
+ "additionalProperties": {},
1916
+ "description": "Options passed to the executor"
1917
+ },
1918
+ "outputs": {
1919
+ "type": "array",
1920
+ "items": {
1921
+ "type": "string"
1922
+ },
1923
+ "description": "Output patterns produced by this target"
1924
+ },
1925
+ "parallelism": {
1926
+ "type": "boolean",
1927
+ "description": "Whether this target supports parallel execution"
1928
+ },
1929
+ "warningPattern": {
1930
+ "anyOf": [
1931
+ {
1932
+ "type": "string"
1933
+ },
1934
+ {
1935
+ "type": "array",
1936
+ "items": {
1937
+ "type": "string"
1938
+ }
1939
+ }
1940
+ ],
1941
+ "description": "Regex source string(s) that mark a successful task as having emitted warnings. The orchestrator scans the task's combined terminal output after a 0-exit and, on first match, sets `hadWarnings` on the result. Combine with `cacheOnWarning: false` to skip caching for warning-tainted runs. Both bare strings and arrays are accepted; arrays are tested in order.\n\n ```ts warningPattern: [\"\\\\bwarning\\\\b\", \"TS\\\\d{4}\"] ```"
1942
+ },
1943
+ "when": {
1944
+ "type": "object",
1945
+ "properties": {
1946
+ "branch": {
1947
+ "anyOf": [
1948
+ {
1949
+ "type": "string"
1950
+ },
1951
+ {
1952
+ "type": "array",
1953
+ "items": {
1954
+ "type": "string"
1955
+ }
1956
+ }
1957
+ ],
1958
+ "description": "Match against the current git branch (HEAD)."
1959
+ },
1960
+ "ci": {
1961
+ "type": "boolean",
1962
+ "description": "Run only when invoked inside CI when `true`, only outside CI when `false`. Detects CI via the `CI` env var (the convention GitHub Actions, GitLab, CircleCI, Jenkins, etc. all share)."
1963
+ },
1964
+ "env": {
1965
+ "anyOf": [
1966
+ {
1967
+ "anyOf": [
1968
+ {
1969
+ "type": "string"
1970
+ },
1971
+ {
1972
+ "type": "object",
1973
+ "properties": {
1974
+ "equals": {
1975
+ "type": "string",
1976
+ "description": "Match this exact value. Mutually exclusive with `exists`."
1977
+ },
1978
+ "exists": {
1979
+ "type": "boolean",
1980
+ "description": "Assert the variable is set & non-empty (`true`) or unset/empty (`false`)."
1981
+ },
1982
+ "name": {
1983
+ "type": "string",
1984
+ "description": "Variable name."
1985
+ }
1986
+ },
1987
+ "required": [
1988
+ "name"
1989
+ ],
1990
+ "additionalProperties": false
1991
+ }
1992
+ ],
1993
+ "description": "An environment-variable match. The string form is shorthand for `{ name, exists: true }` (set + non-empty). The object form supports either presence assertions or exact-value matching."
1994
+ },
1995
+ {
1996
+ "type": "array",
1997
+ "items": {
1998
+ "anyOf": [
1999
+ {
2000
+ "type": "string"
2001
+ },
2002
+ {
2003
+ "type": "object",
2004
+ "properties": {
2005
+ "equals": {
2006
+ "type": "string",
2007
+ "description": "Match this exact value. Mutually exclusive with `exists`."
2008
+ },
2009
+ "exists": {
2010
+ "type": "boolean",
2011
+ "description": "Assert the variable is set & non-empty (`true`) or unset/empty (`false`)."
2012
+ },
2013
+ "name": {
2014
+ "type": "string",
2015
+ "description": "Variable name."
2016
+ }
2017
+ },
2018
+ "required": [
2019
+ "name"
2020
+ ],
2021
+ "additionalProperties": false
2022
+ }
2023
+ ],
2024
+ "description": "An environment-variable match. The string form is shorthand for `{ name, exists: true }` (set + non-empty). The object form supports either presence assertions or exact-value matching."
2025
+ }
2026
+ }
2027
+ ],
2028
+ "description": "Match against environment variables. A bare string asserts the variable is set and non-empty; the object form lets you match an exact value or just assert presence/absence."
2029
+ },
2030
+ "not": {
2031
+ "type": "object",
2032
+ "properties": {
2033
+ "branch": {
2034
+ "anyOf": [
2035
+ {
2036
+ "type": "string"
2037
+ },
2038
+ {
2039
+ "type": "array",
2040
+ "items": {
2041
+ "type": "string"
2042
+ }
2043
+ }
2044
+ ]
2045
+ },
2046
+ "ci": {
2047
+ "type": "boolean"
2048
+ },
2049
+ "env": {
2050
+ "anyOf": [
2051
+ {
2052
+ "anyOf": [
2053
+ {
2054
+ "type": "string"
2055
+ },
2056
+ {
2057
+ "type": "object",
2058
+ "properties": {
2059
+ "equals": {
2060
+ "type": "string",
2061
+ "description": "Match this exact value. Mutually exclusive with `exists`."
2062
+ },
2063
+ "exists": {
2064
+ "type": "boolean",
2065
+ "description": "Assert the variable is set & non-empty (`true`) or unset/empty (`false`)."
2066
+ },
2067
+ "name": {
2068
+ "type": "string",
2069
+ "description": "Variable name."
2070
+ }
2071
+ },
2072
+ "required": [
2073
+ "name"
2074
+ ],
2075
+ "additionalProperties": false
2076
+ }
2077
+ ],
2078
+ "description": "An environment-variable match. The string form is shorthand for `{ name, exists: true }` (set + non-empty). The object form supports either presence assertions or exact-value matching."
2079
+ },
2080
+ {
2081
+ "type": "array",
2082
+ "items": {
2083
+ "anyOf": [
2084
+ {
2085
+ "type": "string"
2086
+ },
2087
+ {
2088
+ "type": "object",
2089
+ "properties": {
2090
+ "equals": {
2091
+ "type": "string",
2092
+ "description": "Match this exact value. Mutually exclusive with `exists`."
2093
+ },
2094
+ "exists": {
2095
+ "type": "boolean",
2096
+ "description": "Assert the variable is set & non-empty (`true`) or unset/empty (`false`)."
2097
+ },
2098
+ "name": {
2099
+ "type": "string",
2100
+ "description": "Variable name."
2101
+ }
2102
+ },
2103
+ "required": [
2104
+ "name"
2105
+ ],
2106
+ "additionalProperties": false
2107
+ }
2108
+ ],
2109
+ "description": "An environment-variable match. The string form is shorthand for `{ name, exists: true }` (set + non-empty). The object form supports either presence assertions or exact-value matching."
2110
+ }
2111
+ }
2112
+ ]
2113
+ },
2114
+ "os": {
2115
+ "anyOf": [
2116
+ {
2117
+ "type": "string",
2118
+ "enum": [
2119
+ "aix",
2120
+ "darwin",
2121
+ "freebsd",
2122
+ "linux",
2123
+ "openbsd",
2124
+ "sunos",
2125
+ "windows",
2126
+ "win32"
2127
+ ],
2128
+ "description": "Aliased platform list — `\"windows\"` is sugar for Node's `\"win32\"`."
2129
+ },
2130
+ {
2131
+ "type": "array",
2132
+ "items": {
2133
+ "type": "string",
2134
+ "enum": [
2135
+ "aix",
2136
+ "darwin",
2137
+ "freebsd",
2138
+ "linux",
2139
+ "openbsd",
2140
+ "sunos",
2141
+ "windows",
2142
+ "win32"
2143
+ ],
2144
+ "description": "Aliased platform list — `\"windows\"` is sugar for Node's `\"win32\"`."
2145
+ }
2146
+ }
2147
+ ]
2148
+ }
2149
+ },
2150
+ "additionalProperties": false,
2151
+ "description": "Negative mirrors. A task runs only when *all* `not.*` clauses fail."
2152
+ },
2153
+ "os": {
2154
+ "anyOf": [
2155
+ {
2156
+ "type": "string",
2157
+ "enum": [
2158
+ "aix",
2159
+ "darwin",
2160
+ "freebsd",
2161
+ "linux",
2162
+ "openbsd",
2163
+ "sunos",
2164
+ "windows",
2165
+ "win32"
2166
+ ],
2167
+ "description": "Aliased platform list — `\"windows\"` is sugar for Node's `\"win32\"`."
2168
+ },
2169
+ {
2170
+ "type": "array",
2171
+ "items": {
2172
+ "type": "string",
2173
+ "enum": [
2174
+ "aix",
2175
+ "darwin",
2176
+ "freebsd",
2177
+ "linux",
2178
+ "openbsd",
2179
+ "sunos",
2180
+ "windows",
2181
+ "win32"
2182
+ ],
2183
+ "description": "Aliased platform list — `\"windows\"` is sugar for Node's `\"win32\"`."
2184
+ }
2185
+ }
2186
+ ],
2187
+ "description": "Match `process.platform` (`\"linux\" | \"darwin\" | \"win32\" | \"freebsd\" | \"openbsd\" | \"sunos\" | \"aix\"`). Pass `\"windows\"` as an alias for `\"win32\"` — easier to remember and matches what people type."
2188
+ }
2189
+ },
2190
+ "additionalProperties": false,
2191
+ "description": "Predicate that gates execution. When the condition evaluates to `false` for the current environment, the task is skipped (marked `\"skipped\"`, not failed). Combine with `os`, `env`, `branch`, and `ci` clauses for granular control:\n\n ```ts when: { os: \"linux\", ci: true, env: \"DEPLOY_TOKEN\" } ```"
2192
+ }
2193
+ },
2194
+ "additionalProperties": false
2195
+ },
2196
+ "description": "Target-specific default configurations"
2197
+ },
2198
+ "untrackedEnvVars": {
2199
+ "type": "array",
2200
+ "items": {
2201
+ "type": "string"
2202
+ },
2203
+ "description": "Environment variables that should be passed to tasks but NOT included in the cache fingerprint. Useful for CI-specific vars. Only used when autoFingerprint is enabled."
2204
+ }
2205
+ },
2206
+ "additionalProperties": false,
2207
+ "description": "Task runner options forwarded verbatim to `defaultTaskRunner`.\n\nIncludes `remoteCache` (HTTP or REAPI gRPC backend), `cacheDirectory`, `parallel`, `globalEnv`, `globalInputs`, `targetDefaults`, etc. See `TaskRunnerOptions` for the full surface."
2208
+ },
2209
+ "toolchain": {
2210
+ "type": "object",
2211
+ "additionalProperties": false,
2212
+ "properties": {
2213
+ "preferredManager": {
2214
+ "type": "string",
2215
+ "enum": [
2216
+ "asdf",
2217
+ "corepack",
2218
+ "fnm",
2219
+ "mise",
2220
+ "none",
2221
+ "nvm",
2222
+ "proto",
2223
+ "volta"
2224
+ ]
2225
+ },
2226
+ "autoInstall": {
2227
+ "type": "boolean",
2228
+ "description": "When a tool pin doesn't match the running version, try to fix it automatically before `vis run` / `vis ci` proceed. Defaults to `true` when {@link findInstalledManagers } reports at least one installed manager, `false` otherwise.\n\nSet to `false` to keep the doctor-style warning behaviour and make users run `vis toolchain install` themselves."
2229
+ },
2230
+ "tools": {
2231
+ "type": "object",
2232
+ "properties": {
2233
+ "bun": {
2234
+ "type": "string"
2235
+ },
2236
+ "deno": {
2237
+ "type": "string"
2238
+ },
2239
+ "go": {
2240
+ "type": "string"
2241
+ },
2242
+ "node": {
2243
+ "type": "string"
2244
+ },
2245
+ "npm": {
2246
+ "type": "string"
2247
+ },
2248
+ "pnpm": {
2249
+ "type": "string"
2250
+ },
2251
+ "python": {
2252
+ "type": "string"
2253
+ },
2254
+ "ruby": {
2255
+ "type": "string"
2256
+ },
2257
+ "rust": {
2258
+ "type": "string"
2259
+ },
2260
+ "yarn": {
2261
+ "type": "string"
2262
+ }
2263
+ },
2264
+ "additionalProperties": false,
2265
+ "description": "Overrides for engines/packageManager-derived pins."
2266
+ }
2267
+ },
2268
+ "description": "Toolchain (Node / pnpm / python / rust / ...) management. vis delegates to whichever version manager (proto, mise, fnm, volta, asdf, nvm, corepack) the developer already has — it does not ship its own.\n\nRe-exported from `./toolchain` so the public config type stays in lockstep with the resolver implementation. `self-activate` is narrowed out of `preferredManager` here — it's auto-resolved for pnpm/yarn `packageManager` pins and isn't meaningful as an override."
2269
+ },
2270
+ "tui": {
2271
+ "type": "object",
2272
+ "properties": {
2273
+ "autoExit": {
2274
+ "type": [
2275
+ "boolean",
2276
+ "number"
2277
+ ],
2278
+ "description": "Auto-exit the TUI after tasks complete.\n- `false`: Stay open until the user presses `q` (default)\n- `true`: Show quit dialog with 3-second countdown after completion\n- `number`: Show quit dialog with custom countdown in seconds"
2279
+ }
2280
+ },
2281
+ "additionalProperties": false,
2282
+ "description": "Terminal UI configuration"
2283
+ },
2284
+ "update": {
2285
+ "type": "object",
2286
+ "properties": {
2287
+ "depFields": {
2288
+ "type": "array",
2289
+ "items": {
2290
+ "type": "string"
2291
+ },
2292
+ "description": "Dependency fields to scan for outdated packages. Beyond the standard fields, supports:\n- `\"overrides\"` (npm)\n- `\"resolutions\"` (yarn)\n- `\"pnpm.overrides\"`",
2293
+ "default": [
2294
+ "dependencies",
2295
+ "devDependencies",
2296
+ "optionalDependencies",
2297
+ "peerDependencies"
2298
+ ]
2299
+ },
2300
+ "exclude": {
2301
+ "type": "array",
2302
+ "items": {
2303
+ "type": "string"
2304
+ }
2305
+ },
2306
+ "format": {
2307
+ "type": "string",
2308
+ "enum": [
2309
+ "json",
2310
+ "minimal",
2311
+ "table"
2312
+ ]
2313
+ },
2314
+ "ignore": {
2315
+ "type": "array",
2316
+ "items": {
2317
+ "type": "string"
2318
+ },
2319
+ "description": "Package names or glob patterns to permanently ignore during updates. Ignored packages are skipped and listed in the output so you know they were not checked.",
2320
+ "examples": [
2321
+ [
2322
+ "eslint",
2323
+ "@types/*"
2324
+ ]
2325
+ ]
2326
+ },
2327
+ "include": {
2328
+ "type": "array",
2329
+ "items": {
2330
+ "type": "string"
2331
+ }
2332
+ },
2333
+ "includeLocked": {
2334
+ "type": "boolean",
2335
+ "description": "Include packages with pinned/exact versions (no `^` or `~` prefix). By default, pinned versions are skipped during update checks.",
2336
+ "default": false
2337
+ },
2338
+ "install": {
2339
+ "type": "boolean"
2340
+ },
2341
+ "maxConcurrentRequests": {
2342
+ "type": "number",
2343
+ "description": "Maximum number of concurrent registry requests during outdated checks. Higher values speed up large workspaces but risk hitting registry rate limits or self-hosted Verdaccio caps.",
2344
+ "default": 8
2345
+ },
2346
+ "minimumReleaseAge": {
2347
+ "type": "number",
2348
+ "description": "Minimum number of minutes since a version was published before vis will consider it for updates. This mirrors pnpm's `minimumReleaseAge` — a single setting that applies to both install and update.\n\nNot set by default. If your package manager config (`pnpm-workspace.yaml`) has `minimumReleaseAge`, vis will read it from there as a fallback.",
2349
+ "examples": [
2350
+ 1440
2351
+ ]
2352
+ },
2353
+ "minimumReleaseAgeExclude": {
2354
+ "type": "array",
2355
+ "items": {
2356
+ "type": "string"
2357
+ },
2358
+ "description": "Package names/patterns excluded from the minimumReleaseAge check.",
2359
+ "examples": [
2360
+ [
2361
+ "webpack",
2362
+ "@myorg/*"
2363
+ ]
2364
+ ]
2365
+ },
2366
+ "packageMode": {
2367
+ "type": "object",
2368
+ "additionalProperties": {
2369
+ "type": "string",
2370
+ "enum": [
2371
+ "latest",
2372
+ "minor",
2373
+ "patch"
2374
+ ]
2375
+ },
2376
+ "description": "Per-package or per-pattern update target overrides. Keys are exact package names, glob patterns, or regex patterns wrapped in `/` (e.g., `/^@vue/`). Values are `\"latest\"`, `\"minor\"`, or `\"patch\"`.",
2377
+ "examples": [
2378
+ {
2379
+ "typescript": "minor",
2380
+ "/^@vue/": "patch"
2381
+ }
2382
+ ]
2383
+ },
2384
+ "prerelease": {
2385
+ "type": "boolean"
2386
+ },
2387
+ "releaseChannel": {
2388
+ "type": "string",
2389
+ "enum": [
2390
+ "any",
2391
+ "same",
2392
+ "stable"
2393
+ ],
2394
+ "description": "Which release channels to consider when picking the target version.\n- `\"stable\"` (default) — only ship stable releases (no prereleases).\n- `\"same\"` — match the prerelease channel of the *current* range: if you're on `react@19.0.0-rc.1`, only `rc.*` candidates qualify; if you're on a stable, only stable candidates. Prevents accidentally promoting a prerelease pin to a stable major bump.\n- `\"any\"` — equivalent to `--prerelease`. Any channel is fair game.\n\n`--release-channel` on the CLI overrides this. If `prerelease: true` is set without `releaseChannel`, vis treats it as `\"any\"`.",
2395
+ "default": "stable"
2396
+ },
2397
+ "security": {
2398
+ "type": "boolean"
2399
+ },
2400
+ "target": {
2401
+ "type": "string",
2402
+ "enum": [
2403
+ "latest",
2404
+ "minor",
2405
+ "patch"
2406
+ ]
2407
+ }
2408
+ },
2409
+ "additionalProperties": false,
2410
+ "description": "Update command defaults"
2411
+ },
2412
+ "versionConstraint": {
2413
+ "type": "string",
2414
+ "description": "Minimum vis CLI version required by this workspace. When the running vis binary is older than this constraint, vis exits with an actionable error before executing any command.\n\nAccepts a semver range string (e.g. `\">=1.0.0\"`, `\"^1.2.0\"`).",
2415
+ "examples": [
2416
+ ">=1.0.0"
2417
+ ]
2418
+ }
2419
+ },
2420
+ "additionalProperties": false,
2421
+ "$defs": {
2422
+ "CodeownersConfig": {
2423
+ "type": "object",
2424
+ "properties": {
2425
+ "globalPaths": {
2426
+ "type": "object",
2427
+ "additionalProperties": {
2428
+ "type": "array",
2429
+ "items": {
2430
+ "type": "string"
2431
+ }
2432
+ },
2433
+ "description": "Workspace-level paths that apply outside any project (e.g., `.github/**`)."
2434
+ },
2435
+ "orderBy": {
2436
+ "type": "string",
2437
+ "enum": [
2438
+ "file-source",
2439
+ "project-id"
2440
+ ],
2441
+ "description": "Sort order for generated entries — mirrors moon's `orderBy`."
2442
+ },
2443
+ "provider": {
2444
+ "type": "string",
2445
+ "enum": [
2446
+ "bitbucket",
2447
+ "github",
2448
+ "gitlab",
2449
+ "other"
2450
+ ],
2451
+ "description": "Provider determines whether `channel` is emitted (GitHub supports it via comment)."
2452
+ }
2453
+ },
2454
+ "additionalProperties": false
2455
+ },
2456
+ "VisPlugin": {
2457
+ "type": "object",
2458
+ "properties": {
2459
+ "hooks": {
2460
+ "type": "object",
2461
+ "properties": {
2462
+ "run:after": {
2463
+ "type": "array",
2464
+ "items": {
2465
+ "not": {},
2466
+ "description": "Fired after the entire task graph completes (including any failures). `results` maps task ID → {@link TaskResult } ."
2467
+ }
412
2468
  },
413
- "teamId": { "type": "string", "description": "Team / namespace for cache isolation." },
414
- "timeout": { "type": "number", "default": 30000, "description": "Per-call request timeout in milliseconds." },
415
- "compression": {
416
- "type": "string",
417
- "enum": ["gzip", "brotli"],
418
- "default": "gzip",
419
- "description": "HTTP-only: tarball compression on the wire."
2469
+ "run:before": {
2470
+ "type": "array",
2471
+ "items": {
2472
+ "not": {},
2473
+ "description": "Fired once before any task in the graph starts, after workspace discovery and graph construction. Throwing aborts the run."
2474
+ }
420
2475
  },
421
- "signing": {
422
- "type": "object",
423
- "additionalProperties": false,
424
- "required": ["secret"],
425
- "description": "HTTP-only HMAC-SHA256 signing for upload integrity.",
426
- "properties": {
427
- "secret": { "type": "string", "minLength": 16, "description": "Shared secret. Must be at least 16 characters." },
428
- "verifyOnDownload": { "type": "boolean", "default": false, "description": "Reject downloads whose signature doesn't match." }
2476
+ "task:after": {
2477
+ "type": "array",
2478
+ "items": {
2479
+ "not": {},
2480
+ "description": "Fired after a task completes (success, failure, or cache hit). Receives the final {@link TaskResult } ."
429
2481
  }
430
2482
  },
431
- "localCasRoot": {
432
- "type": "string",
433
- "description": "Local CAS root used by per-blob backend methods. The HTTP bridge extracts retrieved tarballs into this root so follow-up fetchBlob calls hit local disk."
2483
+ "task:before": {
2484
+ "type": "array",
2485
+ "items": {
2486
+ "not": {},
2487
+ "description": "Fired before each task begins execution — after scheduling, before the executor runs the command. Throwing aborts that single task."
2488
+ }
434
2489
  },
435
- "bearerToken": {
436
- "type": "string",
437
- "description": "REAPI-only: bearer token sent in gRPC 'authorization: Bearer …' metadata."
2490
+ "task:cacheHit": {
2491
+ "type": "array",
2492
+ "items": {
2493
+ "not": {},
2494
+ "description": "Fired when a task hit the local or remote cache."
2495
+ }
438
2496
  },
439
- "instanceName": {
440
- "type": "string",
441
- "description": "REAPI-only: 'instance_name' for multi-tenant servers (single gRPC endpoint hosting multiple logical caches)."
2497
+ "task:cacheMiss": {
2498
+ "type": "array",
2499
+ "items": {
2500
+ "not": {},
2501
+ "description": "Fired when auto-fingerprint cache diagnostics reports a miss, carrying the human-readable reason string."
2502
+ }
442
2503
  },
443
- "allowInsecureBearer": {
444
- "type": "boolean",
445
- "default": false,
446
- "description": "REAPI-only: opt out of the safety check that refuses bearer tokens over cleartext gRPC. Only set when the connection terminates inside a trusted boundary (loopback, mTLS sidecar)."
2504
+ "task:failure": {
2505
+ "type": "array",
2506
+ "items": {
2507
+ "not": {},
2508
+ "description": "Fired when a task exits non-zero."
2509
+ }
447
2510
  },
448
- "read": {
449
- "type": "boolean",
450
- "deprecated": true,
451
- "description": "Deprecated. Use 'mode' instead. Setting both still works but emits a one-time warning."
2511
+ "task:stderr": {
2512
+ "type": "array",
2513
+ "items": {
2514
+ "not": {},
2515
+ "description": "Fired with a stderr chunk as a running task emits it. Plugins that ship logs live (Slack, Datadog) should prefer this over `task:after` so they don't wait for the full buffer."
2516
+ }
452
2517
  },
453
- "write": {
454
- "type": "boolean",
455
- "deprecated": true,
456
- "description": "Deprecated. Use 'mode' instead. Setting both still works but emits a one-time warning."
2518
+ "task:stdout": {
2519
+ "type": "array",
2520
+ "items": {
2521
+ "not": {},
2522
+ "description": "Fired with a stdout chunk as a running task emits it. See `task:stderr` for semantics."
2523
+ }
457
2524
  }
458
- }
2525
+ },
2526
+ "additionalProperties": false,
2527
+ "description": "Declarative handlers — the common shape. One entry per hook name; pass a function or an array of functions (all run serially in order)."
2528
+ },
2529
+ "name": {
2530
+ "type": "string",
2531
+ "description": "Plugin name — surfaced in debug logs."
459
2532
  }
460
- }
2533
+ },
2534
+ "required": [
2535
+ "name"
2536
+ ],
2537
+ "additionalProperties": false,
2538
+ "description": "Public plugin contract. Implementations register handlers by returning a partial {@link VisHooks } map from `hooks`, or by mutating the Hookable instance directly via `setup(hooks)` for advanced cases (dynamic registration, removeHook, etc.).\n\nPlugins are loaded in the order they appear in `visConfig.plugins`. Handler execution order within a hook follows registration order, so earlier plugins see events first."
461
2539
  },
462
- "tui": {
2540
+ "ExtraCustomType": {
463
2541
  "type": "object",
2542
+ "properties": {
2543
+ "depName": {
2544
+ "type": "string",
2545
+ "description": "Required when `strategy === \"string\"`. The dep-cluster key the bare version string at `path` should be associated with."
2546
+ },
2547
+ "name": {
2548
+ "type": "string",
2549
+ "description": "Display name for this customType. Used as the cluster key prefix in lint output and JSON. Must not collide with the built-in names."
2550
+ },
2551
+ "path": {
2552
+ "type": "string",
2553
+ "description": "Dot-separated walk into package.json (e.g. `pnpm.overrides`, `myTool.runtime`)."
2554
+ },
2555
+ "strategy": {
2556
+ "type": "string",
2557
+ "enum": [
2558
+ "name@version",
2559
+ "name~version",
2560
+ "string",
2561
+ "versionsByName"
2562
+ ],
2563
+ "description": "How to interpret the JSON found at `path`.\n- `name@version` — single string `pnpm@9.0.0` (with optional `+sha512.…` hash).\n- `name~version` — single string `node~20.0.0`, mirrors syncpack's tilde form.\n- `string` — bare version literal (requires `depName`).\n- `versionsByName` — `{ name: version }` object such as `engines`."
2564
+ }
2565
+ },
2566
+ "required": [
2567
+ "name",
2568
+ "path",
2569
+ "strategy"
2570
+ ],
464
2571
  "additionalProperties": false,
2572
+ "description": "One user-declared customTypes entry. See `policy.customTypes.extraTypes` for the full contract — this is just the row shape."
2573
+ },
2574
+ "StagedConfig": {
2575
+ "type": "object",
2576
+ "additionalProperties": {
2577
+ "$ref": "#/$defs/StagedTask"
2578
+ },
2579
+ "description": "Config object mapping glob patterns (basename or path-style) to tasks. A top-level function form lets the user generate the entire config from the staged file list."
2580
+ },
2581
+ "StagedTask": {
2582
+ "anyOf": [
2583
+ {
2584
+ "type": "array",
2585
+ "items": {
2586
+ "type": "string"
2587
+ }
2588
+ },
2589
+ {
2590
+ "type": "string"
2591
+ },
2592
+ {
2593
+ "type": "array",
2594
+ "items": {
2595
+ "type": "string"
2596
+ }
2597
+ }
2598
+ ],
2599
+ "description": "A task value as authored by the user. Command strings are split into argv and invoked with the matched file paths appended. Arrays run serially. Functions receive the matched paths and return further task values (possibly async). `{ title, task }` objects run `task` directly with no argv construction."
2600
+ },
2601
+ "VisTargetOptions": {
2602
+ "type": "object",
465
2603
  "properties": {
466
- "autoExit": {
467
- "oneOf": [{ "type": "boolean" }, { "type": "number" }],
468
- "description": "Auto-exit TUI after completion. false=stay open, true=3s countdown, number=custom seconds.",
2604
+ "affectedFiles": {
2605
+ "$ref": "#/$defs/AffectedFilesMode",
2606
+ "description": "How to forward affected files to the task process. Only used when invoked via `vis affected &lt;target>`.",
2607
+ "default": false
2608
+ },
2609
+ "envFile": {
2610
+ "anyOf": [
2611
+ {
2612
+ "type": "boolean"
2613
+ },
2614
+ {
2615
+ "type": "string"
2616
+ },
2617
+ {
2618
+ "type": "array",
2619
+ "items": {
2620
+ "type": "string"
2621
+ }
2622
+ }
2623
+ ],
2624
+ "description": "Load environment variables from dotenv file(s) before running.\n- `string`: a single file path (relative to project root).\n- `string[]`: multiple files — later entries override earlier ones, so put more-specific files last (e.g. `[\".env\", \".env.local\"]`).\n- `true`: auto-cascade in the Next/Vite order: `.env` → `.env.{NODE_ENV}` → `.env.local` → `.env.{NODE_ENV}.local`. Skips `.env.local` when NODE_ENV is `test`, matching Next.js."
2625
+ },
2626
+ "interactive": {
2627
+ "type": "boolean",
2628
+ "description": "When true, the task is serialized with respect to parallel execution and must be run on the main process (claims stdin). Used for commands that read from the terminal.",
2629
+ "default": false
2630
+ },
2631
+ "internal": {
2632
+ "type": "boolean",
2633
+ "description": "When true, the task is hidden from CLI listings and can only be invoked as a dependency of another task.",
2634
+ "default": false
2635
+ },
2636
+ "killGracePeriodMs": {
2637
+ "type": "number",
2638
+ "description": "Milliseconds the timeout watchdog waits between sending SIGTERM and SIGKILL when the `timeout` budget fires. Tasks that ignore SIGTERM (e.g. test runners holding open child processes) get force-killed after this grace window so a stuck task can't outlive its budget.\n\nSet to `0` to skip escalation and rely on SIGTERM only.",
2639
+ "default": 5000
2640
+ },
2641
+ "mutex": {
2642
+ "type": "string",
2643
+ "description": "Serializes all tasks that share the same mutex name. Useful for tasks that contend on a shared resource (e.g., a database migration)."
2644
+ },
2645
+ "outputStyle": {
2646
+ "type": "string",
2647
+ "enum": [
2648
+ "normal",
2649
+ "quiet"
2650
+ ],
2651
+ "description": "Per-target output verbosity. Overrides the global `--output-style` flag for this specific target.\n\n- `\"normal\"` (default): print every task's terminal output\n- `\"quiet\"`: only print output when the task fails. Successful and cached tasks contribute their status line and timing, but their captured stdout/stderr is suppressed.\n\nUseful when a routinely-noisy task (a linter or test runner with verbose progress output) should stay quiet during green builds but reveal everything when it fails."
2652
+ },
2653
+ "persistent": {
2654
+ "type": "boolean",
2655
+ "description": "When true, the task is a long-running / never-ending process. Persistent tasks are scheduled last, execute after all cacheable tasks complete, and are never cached.",
2656
+ "default": false
2657
+ },
2658
+ "preset": {
2659
+ "$ref": "#/$defs/TargetPreset",
2660
+ "description": "A preset that pre-fills a common bundle of options. User-provided fields always take precedence over the preset."
2661
+ },
2662
+ "pty": {
2663
+ "type": "boolean",
2664
+ "description": "Run the task through a pseudo-terminal so color-aware tools (vitest, eslint, biome, …) render as if attached to a real TTY instead of a pipe. Output is captured via task-runner's `TerminalBuffer` so ANSI escapes are normalized into the final rendered state before reaching the reporter.\n\nForces cache to off — PTY output can include timing-dependent frames (spinners) that aren't safe to replay from a cache.",
2665
+ "default": false
2666
+ },
2667
+ "retryCount": {
2668
+ "type": "number",
2669
+ "description": "Number of times to retry the task on failure. Uses an exponential backoff by default (1s, 2s, 4s, ...).",
2670
+ "default": 0
2671
+ },
2672
+ "retryDelay": {
2673
+ "anyOf": [
2674
+ {
2675
+ "type": "number"
2676
+ },
2677
+ {
2678
+ "type": "string",
2679
+ "const": "exponential"
2680
+ }
2681
+ ],
2682
+ "description": "Delay between retry attempts in milliseconds, or `\"exponential\"` for 2^attempt * 1000 ms.",
2683
+ "default": "exponential"
2684
+ },
2685
+ "runFromWorkspaceRoot": {
2686
+ "type": "boolean",
2687
+ "description": "When true, the command executes with the workspace root as CWD instead of the project root.",
469
2688
  "default": false
2689
+ },
2690
+ "runInCI": {
2691
+ "$ref": "#/$defs/RunInCI",
2692
+ "description": "Controls whether the task runs in CI environments.",
2693
+ "default": true
2694
+ },
2695
+ "runnerTags": {
2696
+ "type": "array",
2697
+ "items": {
2698
+ "type": "string"
2699
+ },
2700
+ "description": "Capability tags that gate this task to runners advertising the same tag. The CLI's `--runner-tags=gpu,slow` flag (or `VIS_RUNNER_TAGS` env var) tells vis what the current runner supports; tasks whose `runnerTags` share at least one tag with the runner set are eligible. Untagged tasks (no `runnerTags` or an empty array) are general-purpose and always run.\n\nUse this for special-purpose CI lanes — e.g. a GPU runner that should only pick up visual-regression suites, or a nightly job that runs `slow` integration tests. When neither flag nor env is set, the filter is inactive and every task runs."
2701
+ },
2702
+ "service": {
2703
+ "$ref": "#/$defs/ServiceConfig",
2704
+ "description": "Marks this target as a long-lived service that can be started via `vis service start &lt;id>` and auto-attached when other tasks declare it in `dependsOn`. Implies persistent + non-cacheable behaviour (set `preset: \"server\"` to inherit the rest of the bundle).\n\nThe presence of this block — not `preset: \"server\"` alone — is what makes a target eligible for the cross-invocation registry. `preset: \"server\"` without `service` keeps today's in-run-only behaviour."
2705
+ },
2706
+ "shell": {
2707
+ "type": "string",
2708
+ "description": "Per-target shell override. When set, the command runs through this shell instead of the platform default."
2709
+ },
2710
+ "strictEnv": {
2711
+ "type": "boolean",
2712
+ "description": "Override the workspace `strictEnv` setting for this target. When truthy, the target fails if its command references an env var that resolves to neither the task's effective env nor `process.env`. When `false`, the target opts out of a workspace `strictEnv: true` (e.g. for a one-off command that legitimately tolerates an unset variable)."
2713
+ },
2714
+ "timeout": {
2715
+ "type": "number",
2716
+ "description": "Maximum wall-clock milliseconds a single task run is allowed to take before being killed. `0` / `undefined` means no timeout.\n\nWhen the timeout fires the task is sent SIGTERM and, if it has not exited within `killGracePeriodMs`, SIGKILL. The task exits with a failure status carrying the `[timeout]` marker in `terminalOutput`. Retries count per-attempt, not cumulatively.\n\nUse this to prevent runaway tasks from eating CI wall-clock time up to the job-level cutoff."
2717
+ },
2718
+ "unixShell": {
2719
+ "type": "string",
2720
+ "description": "Per-target unix shell override, used on Linux and macOS. Takes precedence over `shell` on unix-like systems."
2721
+ },
2722
+ "windowsShell": {
2723
+ "type": "string",
2724
+ "description": "Per-target windows shell override, used on Windows. Takes precedence over `shell` on Windows."
470
2725
  }
471
- }
2726
+ },
2727
+ "additionalProperties": false,
2728
+ "description": "Vis-specific target options that extend the task-runner's base `TargetConfiguration`. These live under `target.options` and are interpreted by vis before handing the task off to task-runner.\n\nConditional execution (`when:`) and finally tasks (`always:`) live at the target top level, not under `options` — they're handled by the task-runner orchestrator. See `@visulima/task-runner`'s `WhenCondition`."
472
2729
  },
473
- "update": {
2730
+ "AffectedFilesMode": {
2731
+ "type": [
2732
+ "string",
2733
+ "boolean"
2734
+ ],
2735
+ "enum": [
2736
+ "args",
2737
+ "both",
2738
+ "env",
2739
+ false
2740
+ ],
2741
+ "description": "Controls how affected files are forwarded to a task.\n- `false` (default): Do not forward.\n- `\"args\"`: Append affected paths as additional command arguments.\n- `\"env\"`: Expose them via `VIS_AFFECTED_FILES` environment variable.\n- `\"both\"`: Both of the above."
2742
+ },
2743
+ "TargetPreset": {
2744
+ "type": "string",
2745
+ "enum": [
2746
+ "server",
2747
+ "utility"
2748
+ ],
2749
+ "description": "Preset bundles of target options.\n- `server`: Long-running local dev server — caching off, not in CI, interactive, persistent.\n- `utility`: Short-lived helper — caching off, not in CI."
2750
+ },
2751
+ "RunInCI": {
2752
+ "anyOf": [
2753
+ {
2754
+ "type": "string",
2755
+ "const": "affected"
2756
+ },
2757
+ {
2758
+ "type": "string",
2759
+ "const": "always"
2760
+ },
2761
+ {
2762
+ "type": "boolean"
2763
+ }
2764
+ ],
2765
+ "description": "Controls whether a target runs in CI.\n- `true` (default): Always run.\n- `false`: Never run in CI (local-only).\n- `\"affected\"`: Only when the project is affected by the current change set.\n- `\"always\"`: Always run, even if unaffected."
2766
+ },
2767
+ "ServiceConfig": {
474
2768
  "type": "object",
475
- "description": "Defaults for vis check and vis update commands.",
476
- "additionalProperties": false,
477
2769
  "properties": {
478
- "depFields": { "type": "array", "items": { "type": "string" } },
479
- "exclude": { "type": "array", "items": { "type": "string" } },
480
- "format": { "type": "string", "enum": ["table", "json", "minimal"] },
481
- "ignore": { "type": "array", "items": { "type": "string" } },
482
- "include": { "type": "array", "items": { "type": "string" } },
483
- "includeLocked": { "type": "boolean", "default": false },
484
- "install": { "type": "boolean" },
485
- "minimumReleaseAge": { "type": "number" },
486
- "minimumReleaseAgeExclude": { "type": "array", "items": { "type": "string" } },
487
- "packageMode": {
2770
+ "env": {
488
2771
  "type": "object",
489
- "additionalProperties": { "type": "string", "enum": ["latest", "minor", "patch"] }
2772
+ "additionalProperties": {
2773
+ "type": "string"
2774
+ },
2775
+ "description": "Env vars to expose to dependent tasks when this service is registered. Merged into the dependent task's env after the task's own envFile and before the task's explicit `env` overrides — the dependent task wins on key collisions.\n\nNote: only this `env` map propagates to dependents. The service target's own `envFile` is loaded into the **service process** at start time but is *not* forwarded — dependents must declare any shared values they need either here or in their own envFile. This boundary is intentional: envFiles often contain operator-only secrets (deploy keys, admin tokens) that should not leak into downstream test commands."
2776
+ },
2777
+ "killGracePeriodMs": {
2778
+ "type": "number",
2779
+ "description": "Grace period in milliseconds between SIGTERM and SIGKILL when the service is stopped.",
2780
+ "default": 5000
490
2781
  },
491
- "prerelease": { "type": "boolean" },
492
- "security": { "type": "boolean" },
493
- "target": { "type": "string", "enum": ["latest", "minor", "patch"] }
494
- }
2782
+ "port": {
2783
+ "type": "number",
2784
+ "description": "Optional port the service listens on. Used as the default for `readiness.tcp.port` when no explicit probe is configured, and surfaced by `vis service list`."
2785
+ },
2786
+ "readiness": {
2787
+ "type": "object",
2788
+ "properties": {
2789
+ "tcp": {
2790
+ "type": "object",
2791
+ "properties": {
2792
+ "host": {
2793
+ "type": "string"
2794
+ },
2795
+ "port": {
2796
+ "type": "number"
2797
+ },
2798
+ "timeoutMs": {
2799
+ "type": "number"
2800
+ }
2801
+ },
2802
+ "required": [
2803
+ "port"
2804
+ ],
2805
+ "additionalProperties": false
2806
+ }
2807
+ },
2808
+ "required": [
2809
+ "tcp"
2810
+ ],
2811
+ "additionalProperties": false,
2812
+ "description": "Readiness probe configuration. v1 supports TCP only."
2813
+ }
2814
+ },
2815
+ "additionalProperties": false,
2816
+ "description": "Configuration block declared on a target to mark it as a long-lived \"service\" — eligible to be started/stopped via `vis service` and auto-attached when other tasks depend on it.\n\nTargets must also carry `preset: \"server\"` (or the equivalent `persistent: true`) for the service-mode lifecycle to apply."
495
2817
  },
496
- "versionConstraint": {
2818
+ "TargetType": {
497
2819
  "type": "string",
498
- "description": "Minimum vis CLI version required. Accepts semver ranges (e.g. \">=1.0.0\", \"^1.2.0\")."
2820
+ "enum": [
2821
+ "build",
2822
+ "run",
2823
+ "test"
2824
+ ],
2825
+ "description": "Semantic classification for a target.\n- `build`: Generates one or more artifacts; cached by default.\n- `test`: Validation task (lint, typecheck, unit test). Default type.\n- `run`: One-off or long-running process. Not cached by default."
2826
+ },
2827
+ "TaskDefaultsBlock": {
2828
+ "type": "object",
2829
+ "properties": {
2830
+ "scope": {
2831
+ "$ref": "#/$defs/TaskDefaultsScope",
2832
+ "description": "Optional scope predicate; if omitted, the block applies universally."
2833
+ },
2834
+ "targets": {
2835
+ "type": "object",
2836
+ "additionalProperties": {
2837
+ "type": "object",
2838
+ "properties": {
2839
+ "aliases": {
2840
+ "type": "array",
2841
+ "items": {
2842
+ "type": "string"
2843
+ },
2844
+ "description": "Alternate names that resolve to this target on the CLI. Useful for shortening long canonical names (`test` ↔ `t`) or for offering migration-friendly aliases when renaming targets. Aliases must be globally unique within the workspace."
2845
+ },
2846
+ "description": {
2847
+ "type": "string",
2848
+ "description": "One-line description surfaced by `vis list` and (in future) per-task `--help`. Kept short — longer docs belong in project READMEs or vis.config.ts comments."
2849
+ },
2850
+ "inferred": {
2851
+ "type": "boolean",
2852
+ "description": "True when the target was synthesized by a Project Crystal-style detector (see {@link ../inference } ) rather than declared by a package.json script, project.json, or vis.task.ts file. Surfaced by `vis list --inferred` and used by tooling to distinguish implicit defaults from explicit user intent."
2853
+ },
2854
+ "options": {
2855
+ "$ref": "#/$defs/VisTargetOptions",
2856
+ "description": "Vis-specific target options."
2857
+ },
2858
+ "preset": {
2859
+ "$ref": "#/$defs/TargetPreset",
2860
+ "description": "Preset applied before user-specified options."
2861
+ },
2862
+ "type": {
2863
+ "$ref": "#/$defs/TargetType",
2864
+ "description": "Semantic task type. Affects caching defaults and CI filtering.",
2865
+ "default": "test"
2866
+ },
2867
+ "always": {
2868
+ "type": "boolean",
2869
+ "description": "When `true`, this target runs after the main task graph completes — even if upstream tasks failed. Useful for cleanup, teardown, notifications, or anything that should fire regardless of build outcome. Always-tasks are not part of the normal dependency graph and never block other tasks."
2870
+ },
2871
+ "cache": {
2872
+ "type": "boolean",
2873
+ "description": "Whether this target is cacheable"
2874
+ },
2875
+ "cacheOnWarning": {
2876
+ "type": "boolean",
2877
+ "description": "When `false`, exit-0 runs whose terminal output matched any {@link TargetConfiguration.warningPattern } are not seeded into the cache. Defaults to `true` — warnings are surfaced on the result (`hadWarnings: true`) but caching still happens, matching the \"succeeded with warnings is incremental\" behaviour rush, lage and wireit users have repeatedly asked for."
2878
+ },
2879
+ "cacheRestore": {
2880
+ "type": "object",
2881
+ "properties": {
2882
+ "preserveMtime": {
2883
+ "type": "boolean",
2884
+ "description": "Restore each file's modification time from the captured tar header (second precision). When `false`, restored files take the current wall-clock time, matching the legacy behaviour."
2885
+ },
2886
+ "preservePerms": {
2887
+ "type": "boolean",
2888
+ "description": "Restore each file's POSIX mode bits (rwx triplets, low 12 bits). When `false`, restored files take the process umask. Only meaningful on POSIX hosts; Windows ignores tar mode."
2889
+ }
2890
+ },
2891
+ "additionalProperties": false,
2892
+ "description": "Fine-grained controls over how cached outputs are rehydrated. See {@link CacheRestoreOptions } . Both fields default to `true` (faithful restore); flip individually when downstream tooling needs the legacy \"now\"-stamped behaviour."
2893
+ },
2894
+ "command": {
2895
+ "type": "string",
2896
+ "description": "The command to run (alternative to executor)"
2897
+ },
2898
+ "configurations": {
2899
+ "type": "object",
2900
+ "additionalProperties": {
2901
+ "type": "object",
2902
+ "additionalProperties": {}
2903
+ },
2904
+ "description": "Named configurations (e.g., \"production\", \"development\")"
2905
+ },
2906
+ "dependsOn": {
2907
+ "type": "array",
2908
+ "items": {
2909
+ "anyOf": [
2910
+ {
2911
+ "type": "string"
2912
+ },
2913
+ {
2914
+ "type": "object",
2915
+ "properties": {
2916
+ "dependencies": {
2917
+ "type": "boolean",
2918
+ "description": "Whether this is a dependency on the same project"
2919
+ },
2920
+ "params": {
2921
+ "type": "string",
2922
+ "enum": [
2923
+ "forward",
2924
+ "ignore"
2925
+ ],
2926
+ "description": "Params to pass through"
2927
+ },
2928
+ "projects": {
2929
+ "anyOf": [
2930
+ {
2931
+ "type": "string"
2932
+ },
2933
+ {
2934
+ "type": "array",
2935
+ "items": {
2936
+ "type": "string"
2937
+ }
2938
+ }
2939
+ ],
2940
+ "description": "The project name (if different from the current project)"
2941
+ },
2942
+ "target": {
2943
+ "type": "string",
2944
+ "description": "The target name"
2945
+ }
2946
+ },
2947
+ "required": [
2948
+ "target"
2949
+ ],
2950
+ "additionalProperties": false,
2951
+ "description": "Defines a dependency on another target."
2952
+ }
2953
+ ]
2954
+ },
2955
+ "description": "Other targets this target depends on"
2956
+ },
2957
+ "executor": {
2958
+ "type": "string",
2959
+ "description": "The executor/command to run"
2960
+ },
2961
+ "inputs": {
2962
+ "type": "array",
2963
+ "items": {
2964
+ "anyOf": [
2965
+ {
2966
+ "type": "string"
2967
+ },
2968
+ {
2969
+ "anyOf": [
2970
+ {
2971
+ "type": "object",
2972
+ "properties": {
2973
+ "fileset": {
2974
+ "anyOf": [
2975
+ {
2976
+ "type": "object",
2977
+ "properties": {
2978
+ "base": {
2979
+ "type": "string",
2980
+ "enum": [
2981
+ "package",
2982
+ "workspace"
2983
+ ],
2984
+ "description": "Anchor for the pattern."
2985
+ },
2986
+ "pattern": {
2987
+ "type": "string",
2988
+ "description": "Glob pattern (may start with `!` for negation)."
2989
+ }
2990
+ },
2991
+ "required": [
2992
+ "base",
2993
+ "pattern"
2994
+ ],
2995
+ "additionalProperties": false,
2996
+ "description": "Object form of a fileset pattern, for anchoring to the workspace root."
2997
+ },
2998
+ {
2999
+ "type": "string"
3000
+ }
3001
+ ]
3002
+ }
3003
+ },
3004
+ "required": [
3005
+ "fileset"
3006
+ ],
3007
+ "additionalProperties": false,
3008
+ "description": "An input based on file patterns.\n\n`fileset` may be a bare glob string (package-root relative) or an object form `{ pattern, base }` to anchor explicitly to the workspace root. Negation (`!` prefix) works in both forms."
3009
+ },
3010
+ {
3011
+ "type": "object",
3012
+ "properties": {
3013
+ "runtime": {
3014
+ "type": "string"
3015
+ }
3016
+ },
3017
+ "required": [
3018
+ "runtime"
3019
+ ],
3020
+ "additionalProperties": false,
3021
+ "description": "An input based on a runtime command."
3022
+ },
3023
+ {
3024
+ "type": "object",
3025
+ "properties": {
3026
+ "env": {
3027
+ "type": "string"
3028
+ }
3029
+ },
3030
+ "required": [
3031
+ "env"
3032
+ ],
3033
+ "additionalProperties": false,
3034
+ "description": "An input based on environment variables."
3035
+ },
3036
+ {
3037
+ "type": "object",
3038
+ "properties": {
3039
+ "externalDependencies": {
3040
+ "type": "array",
3041
+ "items": {
3042
+ "type": "string"
3043
+ }
3044
+ }
3045
+ },
3046
+ "required": [
3047
+ "externalDependencies"
3048
+ ],
3049
+ "additionalProperties": false,
3050
+ "description": "An input based on external dependency versions."
3051
+ }
3052
+ ],
3053
+ "description": "Defines an input for cache invalidation."
3054
+ }
3055
+ ]
3056
+ },
3057
+ "description": "Input patterns for cache invalidation"
3058
+ },
3059
+ "outputs": {
3060
+ "type": "array",
3061
+ "items": {
3062
+ "type": "string"
3063
+ },
3064
+ "description": "Output patterns produced by this target"
3065
+ },
3066
+ "parallelism": {
3067
+ "type": "boolean",
3068
+ "description": "Whether this target supports parallel execution"
3069
+ },
3070
+ "warningPattern": {
3071
+ "anyOf": [
3072
+ {
3073
+ "type": "string"
3074
+ },
3075
+ {
3076
+ "type": "array",
3077
+ "items": {
3078
+ "type": "string"
3079
+ }
3080
+ }
3081
+ ],
3082
+ "description": "Regex source string(s) that mark a successful task as having emitted warnings. The orchestrator scans the task's combined terminal output after a 0-exit and, on first match, sets `hadWarnings` on the result. Combine with `cacheOnWarning: false` to skip caching for warning-tainted runs. Both bare strings and arrays are accepted; arrays are tested in order.\n\n ```ts warningPattern: [\"\\\\bwarning\\\\b\", \"TS\\\\d{4}\"] ```"
3083
+ },
3084
+ "when": {
3085
+ "type": "object",
3086
+ "properties": {
3087
+ "branch": {
3088
+ "anyOf": [
3089
+ {
3090
+ "type": "string"
3091
+ },
3092
+ {
3093
+ "type": "array",
3094
+ "items": {
3095
+ "type": "string"
3096
+ }
3097
+ }
3098
+ ],
3099
+ "description": "Match against the current git branch (HEAD)."
3100
+ },
3101
+ "ci": {
3102
+ "type": "boolean",
3103
+ "description": "Run only when invoked inside CI when `true`, only outside CI when `false`. Detects CI via the `CI` env var (the convention GitHub Actions, GitLab, CircleCI, Jenkins, etc. all share)."
3104
+ },
3105
+ "env": {
3106
+ "anyOf": [
3107
+ {
3108
+ "anyOf": [
3109
+ {
3110
+ "type": "string"
3111
+ },
3112
+ {
3113
+ "type": "object",
3114
+ "properties": {
3115
+ "equals": {
3116
+ "type": "string",
3117
+ "description": "Match this exact value. Mutually exclusive with `exists`."
3118
+ },
3119
+ "exists": {
3120
+ "type": "boolean",
3121
+ "description": "Assert the variable is set & non-empty (`true`) or unset/empty (`false`)."
3122
+ },
3123
+ "name": {
3124
+ "type": "string",
3125
+ "description": "Variable name."
3126
+ }
3127
+ },
3128
+ "required": [
3129
+ "name"
3130
+ ],
3131
+ "additionalProperties": false
3132
+ }
3133
+ ],
3134
+ "description": "An environment-variable match. The string form is shorthand for `{ name, exists: true }` (set + non-empty). The object form supports either presence assertions or exact-value matching."
3135
+ },
3136
+ {
3137
+ "type": "array",
3138
+ "items": {
3139
+ "anyOf": [
3140
+ {
3141
+ "type": "string"
3142
+ },
3143
+ {
3144
+ "type": "object",
3145
+ "properties": {
3146
+ "equals": {
3147
+ "type": "string",
3148
+ "description": "Match this exact value. Mutually exclusive with `exists`."
3149
+ },
3150
+ "exists": {
3151
+ "type": "boolean",
3152
+ "description": "Assert the variable is set & non-empty (`true`) or unset/empty (`false`)."
3153
+ },
3154
+ "name": {
3155
+ "type": "string",
3156
+ "description": "Variable name."
3157
+ }
3158
+ },
3159
+ "required": [
3160
+ "name"
3161
+ ],
3162
+ "additionalProperties": false
3163
+ }
3164
+ ],
3165
+ "description": "An environment-variable match. The string form is shorthand for `{ name, exists: true }` (set + non-empty). The object form supports either presence assertions or exact-value matching."
3166
+ }
3167
+ }
3168
+ ],
3169
+ "description": "Match against environment variables. A bare string asserts the variable is set and non-empty; the object form lets you match an exact value or just assert presence/absence."
3170
+ },
3171
+ "not": {
3172
+ "type": "object",
3173
+ "properties": {
3174
+ "branch": {
3175
+ "anyOf": [
3176
+ {
3177
+ "type": "string"
3178
+ },
3179
+ {
3180
+ "type": "array",
3181
+ "items": {
3182
+ "type": "string"
3183
+ }
3184
+ }
3185
+ ]
3186
+ },
3187
+ "ci": {
3188
+ "type": "boolean"
3189
+ },
3190
+ "env": {
3191
+ "anyOf": [
3192
+ {
3193
+ "anyOf": [
3194
+ {
3195
+ "type": "string"
3196
+ },
3197
+ {
3198
+ "type": "object",
3199
+ "properties": {
3200
+ "equals": {
3201
+ "type": "string",
3202
+ "description": "Match this exact value. Mutually exclusive with `exists`."
3203
+ },
3204
+ "exists": {
3205
+ "type": "boolean",
3206
+ "description": "Assert the variable is set & non-empty (`true`) or unset/empty (`false`)."
3207
+ },
3208
+ "name": {
3209
+ "type": "string",
3210
+ "description": "Variable name."
3211
+ }
3212
+ },
3213
+ "required": [
3214
+ "name"
3215
+ ],
3216
+ "additionalProperties": false
3217
+ }
3218
+ ],
3219
+ "description": "An environment-variable match. The string form is shorthand for `{ name, exists: true }` (set + non-empty). The object form supports either presence assertions or exact-value matching."
3220
+ },
3221
+ {
3222
+ "type": "array",
3223
+ "items": {
3224
+ "anyOf": [
3225
+ {
3226
+ "type": "string"
3227
+ },
3228
+ {
3229
+ "type": "object",
3230
+ "properties": {
3231
+ "equals": {
3232
+ "type": "string",
3233
+ "description": "Match this exact value. Mutually exclusive with `exists`."
3234
+ },
3235
+ "exists": {
3236
+ "type": "boolean",
3237
+ "description": "Assert the variable is set & non-empty (`true`) or unset/empty (`false`)."
3238
+ },
3239
+ "name": {
3240
+ "type": "string",
3241
+ "description": "Variable name."
3242
+ }
3243
+ },
3244
+ "required": [
3245
+ "name"
3246
+ ],
3247
+ "additionalProperties": false
3248
+ }
3249
+ ],
3250
+ "description": "An environment-variable match. The string form is shorthand for `{ name, exists: true }` (set + non-empty). The object form supports either presence assertions or exact-value matching."
3251
+ }
3252
+ }
3253
+ ]
3254
+ },
3255
+ "os": {
3256
+ "anyOf": [
3257
+ {
3258
+ "type": "string",
3259
+ "enum": [
3260
+ "aix",
3261
+ "darwin",
3262
+ "freebsd",
3263
+ "linux",
3264
+ "openbsd",
3265
+ "sunos",
3266
+ "windows",
3267
+ "win32"
3268
+ ],
3269
+ "description": "Aliased platform list — `\"windows\"` is sugar for Node's `\"win32\"`."
3270
+ },
3271
+ {
3272
+ "type": "array",
3273
+ "items": {
3274
+ "type": "string",
3275
+ "enum": [
3276
+ "aix",
3277
+ "darwin",
3278
+ "freebsd",
3279
+ "linux",
3280
+ "openbsd",
3281
+ "sunos",
3282
+ "windows",
3283
+ "win32"
3284
+ ],
3285
+ "description": "Aliased platform list — `\"windows\"` is sugar for Node's `\"win32\"`."
3286
+ }
3287
+ }
3288
+ ]
3289
+ }
3290
+ },
3291
+ "additionalProperties": false,
3292
+ "description": "Negative mirrors. A task runs only when *all* `not.*` clauses fail."
3293
+ },
3294
+ "os": {
3295
+ "anyOf": [
3296
+ {
3297
+ "type": "string",
3298
+ "enum": [
3299
+ "aix",
3300
+ "darwin",
3301
+ "freebsd",
3302
+ "linux",
3303
+ "openbsd",
3304
+ "sunos",
3305
+ "windows",
3306
+ "win32"
3307
+ ],
3308
+ "description": "Aliased platform list — `\"windows\"` is sugar for Node's `\"win32\"`."
3309
+ },
3310
+ {
3311
+ "type": "array",
3312
+ "items": {
3313
+ "type": "string",
3314
+ "enum": [
3315
+ "aix",
3316
+ "darwin",
3317
+ "freebsd",
3318
+ "linux",
3319
+ "openbsd",
3320
+ "sunos",
3321
+ "windows",
3322
+ "win32"
3323
+ ],
3324
+ "description": "Aliased platform list — `\"windows\"` is sugar for Node's `\"win32\"`."
3325
+ }
3326
+ }
3327
+ ],
3328
+ "description": "Match `process.platform` (`\"linux\" | \"darwin\" | \"win32\" | \"freebsd\" | \"openbsd\" | \"sunos\" | \"aix\"`). Pass `\"windows\"` as an alias for `\"win32\"` — easier to remember and matches what people type."
3329
+ }
3330
+ },
3331
+ "additionalProperties": false,
3332
+ "description": "Predicate that gates execution. When the condition evaluates to `false` for the current environment, the task is skipped (marked `\"skipped\"`, not failed). Combine with `os`, `env`, `branch`, and `ci` clauses for granular control:\n\n ```ts when: { os: \"linux\", ci: true, env: \"DEPLOY_TOKEN\" } ```"
3333
+ }
3334
+ },
3335
+ "additionalProperties": false
3336
+ },
3337
+ "description": "Target default configurations."
3338
+ }
3339
+ },
3340
+ "required": [
3341
+ "targets"
3342
+ ],
3343
+ "additionalProperties": false,
3344
+ "description": "A single task-defaults block — a set of target defaults gated by an optional scope predicate."
3345
+ },
3346
+ "TaskDefaultsScope": {
3347
+ "type": "object",
3348
+ "properties": {
3349
+ "language": {
3350
+ "anyOf": [
3351
+ {
3352
+ "type": "string"
3353
+ },
3354
+ {
3355
+ "type": "array",
3356
+ "items": {
3357
+ "type": "string"
3358
+ }
3359
+ }
3360
+ ],
3361
+ "description": "Match on primary language."
3362
+ },
3363
+ "layer": {
3364
+ "anyOf": [
3365
+ {
3366
+ "type": "string",
3367
+ "enum": [
3368
+ "application",
3369
+ "automation",
3370
+ "configuration",
3371
+ "library",
3372
+ "scaffolding",
3373
+ "tool"
3374
+ ],
3375
+ "description": "Project layer, used for constraint inheritance and query filtering."
3376
+ },
3377
+ {
3378
+ "type": "array",
3379
+ "items": {
3380
+ "anyOf": [
3381
+ {
3382
+ "type": "string",
3383
+ "const": "application"
3384
+ },
3385
+ {
3386
+ "type": "string",
3387
+ "const": "automation"
3388
+ },
3389
+ {
3390
+ "type": "string",
3391
+ "const": "configuration"
3392
+ },
3393
+ {
3394
+ "type": "string",
3395
+ "const": "library"
3396
+ },
3397
+ {
3398
+ "type": "string",
3399
+ "const": "scaffolding"
3400
+ },
3401
+ {
3402
+ "type": "string",
3403
+ "const": "tool"
3404
+ },
3405
+ {
3406
+ "not": {}
3407
+ }
3408
+ ],
3409
+ "description": "Project layer, used for constraint inheritance and query filtering."
3410
+ }
3411
+ }
3412
+ ],
3413
+ "description": "Match on project layer."
3414
+ },
3415
+ "projectType": {
3416
+ "type": "string",
3417
+ "enum": [
3418
+ "application",
3419
+ "library"
3420
+ ],
3421
+ "description": "Match on project type."
3422
+ },
3423
+ "stack": {
3424
+ "anyOf": [
3425
+ {
3426
+ "type": "string",
3427
+ "enum": [
3428
+ "backend",
3429
+ "data",
3430
+ "frontend",
3431
+ "infrastructure",
3432
+ "systems"
3433
+ ],
3434
+ "description": "Tech stack."
3435
+ },
3436
+ {
3437
+ "type": "array",
3438
+ "items": {
3439
+ "anyOf": [
3440
+ {
3441
+ "type": "string",
3442
+ "const": "backend"
3443
+ },
3444
+ {
3445
+ "type": "string",
3446
+ "const": "data"
3447
+ },
3448
+ {
3449
+ "type": "string",
3450
+ "const": "frontend"
3451
+ },
3452
+ {
3453
+ "type": "string",
3454
+ "const": "infrastructure"
3455
+ },
3456
+ {
3457
+ "type": "string",
3458
+ "const": "systems"
3459
+ },
3460
+ {
3461
+ "not": {}
3462
+ }
3463
+ ],
3464
+ "description": "Tech stack."
3465
+ }
3466
+ }
3467
+ ],
3468
+ "description": "Match on project stack."
3469
+ },
3470
+ "tags": {
3471
+ "type": "array",
3472
+ "items": {
3473
+ "type": "string"
3474
+ },
3475
+ "description": "Match projects tagged with any of these tags."
3476
+ }
3477
+ },
3478
+ "additionalProperties": false,
3479
+ "description": "A scope predicate used by {@link VisConfig.taskDefaults } . All listed constraints must match for the block to apply."
499
3480
  }
500
3481
  }
501
3482
  }