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

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 (120) hide show
  1. package/CHANGELOG.md +95 -42
  2. package/LICENSE.md +213 -0
  3. package/README.md +8 -4
  4. package/dist/bin.js +9 -1
  5. package/dist/config/index.d.ts +1818 -0
  6. package/dist/config/index.js +2 -0
  7. package/dist/generate/index.d.ts +1 -1
  8. package/dist/generate/index.js +3 -1
  9. package/dist/packem_chunks/applyDefaults.js +336 -0
  10. package/dist/packem_chunks/bin.js +9554 -64
  11. package/dist/packem_chunks/doctor-probe.js +112 -0
  12. package/dist/packem_chunks/fix.js +229 -48
  13. package/dist/packem_chunks/handler.js +99 -1
  14. package/dist/packem_chunks/handler10.js +53 -1
  15. package/dist/packem_chunks/handler11.js +32 -1
  16. package/dist/packem_chunks/handler12.js +100 -2
  17. package/dist/packem_chunks/handler13.js +25 -1
  18. package/dist/packem_chunks/handler14.js +916 -5
  19. package/dist/packem_chunks/handler15.js +206 -1
  20. package/dist/packem_chunks/handler16.js +122 -18
  21. package/dist/packem_chunks/handler17.js +13 -1
  22. package/dist/packem_chunks/handler18.js +106 -1
  23. package/dist/packem_chunks/handler19.js +19 -1
  24. package/dist/packem_chunks/handler2.js +75 -1
  25. package/dist/packem_chunks/handler20.js +29 -1
  26. package/dist/packem_chunks/handler21.js +222 -1
  27. package/dist/packem_chunks/handler22.js +237 -5
  28. package/dist/packem_chunks/handler23.js +101 -1
  29. package/dist/packem_chunks/handler24.js +110 -1
  30. package/dist/packem_chunks/handler25.js +402 -5
  31. package/dist/packem_chunks/handler26.js +13 -1
  32. package/dist/packem_chunks/handler27.js +63 -3
  33. package/dist/packem_chunks/handler28.js +34 -1
  34. package/dist/packem_chunks/handler29.js +458 -7
  35. package/dist/packem_chunks/handler3.js +95 -2
  36. package/dist/packem_chunks/handler30.js +168 -21
  37. package/dist/packem_chunks/handler31.js +530 -3
  38. package/dist/packem_chunks/handler32.js +214 -2
  39. package/dist/packem_chunks/handler33.js +119 -24
  40. package/dist/packem_chunks/handler34.js +630 -2
  41. package/dist/packem_chunks/handler35.js +283 -19
  42. package/dist/packem_chunks/handler36.js +521 -407
  43. package/dist/packem_chunks/handler37.js +762 -22
  44. package/dist/packem_chunks/handler38.js +989 -22
  45. package/dist/packem_chunks/handler39.js +574 -22
  46. package/dist/packem_chunks/handler4.js +90 -4
  47. package/dist/packem_chunks/handler40.js +1685 -3
  48. package/dist/packem_chunks/handler41.js +1088 -10
  49. package/dist/packem_chunks/handler42.js +785 -141
  50. package/dist/packem_chunks/handler43.js +2658 -42
  51. package/dist/packem_chunks/handler44.js +3886 -3
  52. package/dist/packem_chunks/handler45.js +2568 -21
  53. package/dist/packem_chunks/handler46.js +3769 -0
  54. package/dist/packem_chunks/handler47.js +1491 -0
  55. package/dist/packem_chunks/handler5.js +174 -2
  56. package/dist/packem_chunks/handler6.js +95 -13
  57. package/dist/packem_chunks/handler7.js +115 -8
  58. package/dist/packem_chunks/handler8.js +12 -1
  59. package/dist/packem_chunks/handler9.js +29 -1
  60. package/dist/packem_chunks/heal-accept.js +522 -0
  61. package/dist/packem_chunks/heal.js +673 -0
  62. package/dist/packem_chunks/index.js +873 -7
  63. package/dist/packem_chunks/loader.js +23 -1
  64. package/dist/packem_shared/VisUpdateApp-D-Yz_wvg.js +1316 -0
  65. package/dist/packem_shared/_commonjsHelpers-BqLXS_qQ.js +5 -0
  66. package/dist/packem_shared/ai-analysis-CHeB1joD.js +367 -0
  67. package/dist/packem_shared/ai-cache-Be_jexe4.js +142 -0
  68. package/dist/packem_shared/ai-fix-B9iQVcD2.js +379 -0
  69. package/dist/packem_shared/cache-directory-2qvs4goY.js +98 -0
  70. package/dist/packem_shared/catalog-BJTtyi-O.js +1371 -0
  71. package/dist/packem_shared/dependency-scan-A0KSklpG.js +188 -0
  72. package/dist/packem_shared/docker-2iZzc280.js +181 -0
  73. package/dist/packem_shared/failure-log-Cz3Z4SKL.js +100 -0
  74. package/dist/packem_shared/flakiness-goTxXuCX.js +180 -0
  75. package/dist/packem_shared/otel-DCvqCTz_.js +158 -0
  76. package/dist/packem_shared/otelPlugin-DFaLDvJf.js +3 -0
  77. package/dist/packem_shared/registry-CbqXI0rc.js +272 -0
  78. package/dist/packem_shared/run-summary-utils-PVMl4aIh.js +130 -0
  79. package/dist/packem_shared/runtime-check-Cobi3p6l.js +127 -0
  80. package/dist/packem_shared/selectors-SM69TfqC.js +194 -0
  81. package/dist/packem_shared/symbols-Ta7g2nU-.js +14 -0
  82. package/dist/packem_shared/toolchain-BdZd9eBi.js +975 -0
  83. package/dist/packem_shared/typosquats-C-bCh3PX.js +1210 -0
  84. package/dist/packem_shared/use-measured-height-CNP0vT4M.js +20 -0
  85. package/dist/packem_shared/utils-CthVdBPS.js +40 -0
  86. package/dist/packem_shared/xxh3-Ck8mXNg1.js +239 -0
  87. package/index.js +727 -555
  88. package/package.json +35 -17
  89. package/schemas/project.schema.json +8 -10
  90. package/schemas/vis-config.schema.json +132 -8
  91. package/skills/vis/SKILL.md +96 -0
  92. package/templates/buildkite-ci/.buildkite/pipeline.yml.tera +85 -0
  93. package/templates/buildkite-ci/template.yml +20 -0
  94. package/dist/errors/index.d.ts +0 -26
  95. package/dist/errors/index.js +0 -1
  96. package/dist/packem_chunks/config.js +0 -2
  97. package/dist/packem_shared/VisConfigCycleError-CAYNC7d-.js +0 -1
  98. package/dist/packem_shared/VisConfigError-B5LP1zRf.js +0 -1
  99. package/dist/packem_shared/VisConfigLoadError-CeqBSd2Z.js +0 -2
  100. package/dist/packem_shared/VisConfigNotFoundError-DZ9KC527.js +0 -5
  101. package/dist/packem_shared/VisUpdateApp-D-L4_-Iu.js +0 -1
  102. package/dist/packem_shared/_commonjsHelpers-D6W6KoPK.js +0 -1
  103. package/dist/packem_shared/ai-analysis-CGuy7dfE.js +0 -67
  104. package/dist/packem_shared/ai-cache-Bynt6Y9x.js +0 -1
  105. package/dist/packem_shared/cache-directory-D72ZEag2.js +0 -1
  106. package/dist/packem_shared/catalog-BVPerCwG.js +0 -12
  107. package/dist/packem_shared/dependency-scan-Du0tBu64.js +0 -2
  108. package/dist/packem_shared/docker-BcfqH4Av.js +0 -2
  109. package/dist/packem_shared/failure-log-DqYen0LC.js +0 -2
  110. package/dist/packem_shared/flakiness-DSIHZGBT.js +0 -1
  111. package/dist/packem_shared/run-summary-utils-C24Aaf9E.js +0 -1
  112. package/dist/packem_shared/runtime-check-CGHal8SO.js +0 -1
  113. package/dist/packem_shared/selectors-CfH9ZY08.js +0 -3
  114. package/dist/packem_shared/symbols-CQmER5MT.js +0 -1
  115. package/dist/packem_shared/target-merge-DNa-6eWu.js +0 -1
  116. package/dist/packem_shared/toolchain-DQfTQY8E.js +0 -5
  117. package/dist/packem_shared/typosquats-DOR8izpX.js +0 -1
  118. package/dist/packem_shared/use-measured-height-DjYgUOKk.js +0 -1
  119. package/dist/packem_shared/utils-DrNg0XTR.js +0 -1
  120. package/dist/packem_shared/xxh3-DrAUNq4n.js +0 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@visulima/vis",
3
- "version": "1.0.0-alpha.10",
3
+ "version": "1.0.0-alpha.11",
4
4
  "description": "A CLI task runner for monorepo workspaces, powered by @visulima/task-runner",
5
5
  "keywords": [
6
6
  "build",
@@ -45,8 +45,8 @@
45
45
  },
46
46
  "exports": {
47
47
  "./config": {
48
- "types": "./dist/config.d.ts",
49
- "default": "./dist/config.js"
48
+ "types": "./dist/config/index.d.ts",
49
+ "default": "./dist/config/index.js"
50
50
  },
51
51
  "./generate": {
52
52
  "types": "./dist/generate/index.d.ts",
@@ -67,6 +67,8 @@
67
67
  "files": [
68
68
  "dist/**",
69
69
  "schemas/**",
70
+ "skills/**",
71
+ "templates/**",
70
72
  "index.js",
71
73
  "index.d.ts",
72
74
  "README.md",
@@ -77,22 +79,22 @@
77
79
  "@bomb.sh/tab": "^0.0.15",
78
80
  "@socketsecurity/registry": "^2.0.2",
79
81
  "@visulima/ansi": "4.0.0-alpha.13",
80
- "@visulima/cerebro": "3.0.0-alpha.13",
82
+ "@visulima/cerebro": "3.0.0-alpha.14",
81
83
  "@visulima/colorize": "2.0.0-alpha.10",
82
84
  "@visulima/find-ai-runner": "1.0.0-alpha.5",
83
85
  "@visulima/find-cache-dir": "3.0.0-alpha.9",
84
- "@visulima/fs": "5.0.0-alpha.12",
86
+ "@visulima/fs": "5.0.0-alpha.13",
85
87
  "@visulima/humanizer": "3.0.0-alpha.11",
86
88
  "@visulima/interactive-manager": "1.0.0-alpha.2",
87
- "@visulima/package": "5.0.0-alpha.11",
89
+ "@visulima/package": "5.0.0-alpha.12",
88
90
  "@visulima/pail": "4.0.0-alpha.12",
89
91
  "@visulima/path": "3.0.0-alpha.10",
90
92
  "@visulima/redact": "3.0.0-alpha.10",
91
93
  "@visulima/secret-scanner": "1.0.0-alpha.1",
92
94
  "@visulima/spinner": "1.0.0-alpha.1",
93
95
  "@visulima/string": "3.0.0-alpha.11",
94
- "@visulima/task-runner": "1.0.0-alpha.8",
95
- "@visulima/tui": "1.0.0-alpha.5",
96
+ "@visulima/task-runner": "1.0.0-alpha.9",
97
+ "@visulima/tui": "1.0.0-alpha.6",
96
98
  "execa": "^9.6.1",
97
99
  "giget": "^3.2.0",
98
100
  "hookable": "^6.1.1",
@@ -104,18 +106,34 @@
104
106
  "react-reconciler": ">=0.33.0",
105
107
  "semver": "^7.7.4",
106
108
  "smol-toml": "^1.6.1",
107
- "yaml": "2.8.3",
109
+ "yaml": "2.8.4",
108
110
  "zeptomatch": "^2.1.0"
109
111
  },
112
+ "peerDependencies": {
113
+ "@gitbeaker/rest": ">=42.0.0",
114
+ "@octokit/rest": ">=21.0.0",
115
+ "@opentelemetry/api": "1.9.1"
116
+ },
117
+ "peerDependenciesMeta": {
118
+ "@gitbeaker/rest": {
119
+ "optional": true
120
+ },
121
+ "@octokit/rest": {
122
+ "optional": true
123
+ },
124
+ "@opentelemetry/api": {
125
+ "optional": true
126
+ }
127
+ },
110
128
  "optionalDependencies": {
111
- "@visulima/vis-binding-darwin-arm64": "1.0.0-alpha.10",
112
- "@visulima/vis-binding-darwin-x64": "1.0.0-alpha.10",
113
- "@visulima/vis-binding-linux-arm64-gnu": "1.0.0-alpha.10",
114
- "@visulima/vis-binding-linux-x64-musl": "1.0.0-alpha.10",
115
- "@visulima/vis-binding-linux-arm64-musl": "1.0.0-alpha.10",
116
- "@visulima/vis-binding-linux-x64-gnu": "1.0.0-alpha.10",
117
- "@visulima/vis-binding-win32-arm64-msvc": "1.0.0-alpha.10",
118
- "@visulima/vis-binding-win32-x64-msvc": "1.0.0-alpha.10"
129
+ "@visulima/vis-binding-darwin-arm64": "1.0.0-alpha.11",
130
+ "@visulima/vis-binding-linux-arm64-musl": "1.0.0-alpha.11",
131
+ "@visulima/vis-binding-darwin-x64": "1.0.0-alpha.11",
132
+ "@visulima/vis-binding-linux-x64-gnu": "1.0.0-alpha.11",
133
+ "@visulima/vis-binding-linux-arm64-gnu": "1.0.0-alpha.11",
134
+ "@visulima/vis-binding-linux-x64-musl": "1.0.0-alpha.11",
135
+ "@visulima/vis-binding-win32-arm64-msvc": "1.0.0-alpha.11",
136
+ "@visulima/vis-binding-win32-x64-msvc": "1.0.0-alpha.11"
119
137
  },
120
138
  "engines": {
121
139
  "node": "^22.14.0 || >=24.10.0"
@@ -125,10 +125,10 @@
125
125
  },
126
126
  "inputs": {
127
127
  "type": "array",
128
- "description": "Input patterns for cache invalidation. Supports file globs, @filegroup:<name> references, and structured input definitions.",
128
+ "description": "Input patterns for cache invalidation. Strings may be bare globs (\"src/**/*.ts\"), @filegroup:<name> references, named-input refs, or URI form: file://path, glob://pattern, env://NAME, func://command, dep://pkg-a,pkg-b. Object form is also accepted for explicit fileset/env/runtime/externalDependencies.",
129
129
  "items": {
130
130
  "oneOf": [
131
- { "type": "string" },
131
+ { "$ref": "#/$defs/inputString" },
132
132
  { "$ref": "#/$defs/fileSetInput" },
133
133
  { "$ref": "#/$defs/environmentInput" },
134
134
  { "$ref": "#/$defs/runtimeInput" },
@@ -294,6 +294,10 @@
294
294
  }
295
295
  }
296
296
  },
297
+ "inputString": {
298
+ "type": "string",
299
+ "description": "Input pattern. Bare globs (\"src/**/*.ts\"), @filegroup:<name>/named-input refs, or URI form: file://path | glob://pattern | env://NAME | func://command | dep://pkg-a,pkg-b. Negation (\"!\") works for fileset forms (file://, glob://, bare globs)."
300
+ },
297
301
  "fileSetInput": {
298
302
  "type": "object",
299
303
  "required": ["fileset"],
@@ -358,10 +362,7 @@
358
362
  ]
359
363
  },
360
364
  "envMatcherList": {
361
- "oneOf": [
362
- { "$ref": "#/$defs/envMatcher" },
363
- { "type": "array", "items": { "$ref": "#/$defs/envMatcher" } }
364
- ]
365
+ "oneOf": [{ "$ref": "#/$defs/envMatcher" }, { "type": "array", "items": { "$ref": "#/$defs/envMatcher" } }]
365
366
  },
366
367
  "platformList": {
367
368
  "oneOf": [
@@ -379,10 +380,7 @@
379
380
  ]
380
381
  },
381
382
  "branchList": {
382
- "oneOf": [
383
- { "type": "string" },
384
- { "type": "array", "items": { "type": "string" } }
385
- ]
383
+ "oneOf": [{ "type": "string" }, { "type": "array", "items": { "type": "string" } }]
386
384
  },
387
385
  "whenCondition": {
388
386
  "type": "object",
@@ -105,6 +105,58 @@
105
105
  }
106
106
  }
107
107
  },
108
+ "inferTargets": {
109
+ "default": false,
110
+ "oneOf": [
111
+ { "type": "boolean" },
112
+ {
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
+ ]
155
+ }
156
+ }
157
+ ],
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."
159
+ },
108
160
  "create": {
109
161
  "type": "object",
110
162
  "description": "Configuration for vis create scaffolding command.",
@@ -132,6 +184,18 @@
132
184
  "description": "Package override mappings applied during migration.",
133
185
  "additionalProperties": { "type": "string" }
134
186
  },
187
+ "preflight": {
188
+ "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
+ "properties": {
192
+ "lockfile": {
193
+ "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."
196
+ }
197
+ }
198
+ },
135
199
  "security": {
136
200
  "type": "object",
137
201
  "description": "Supply-chain security settings.",
@@ -239,10 +303,10 @@
239
303
  },
240
304
  "fileGroups": {
241
305
  "type": "object",
242
- "description": "Named file-group patterns, reusable via @filegroup:<name> in target inputs.",
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://).",
243
307
  "additionalProperties": {
244
308
  "type": "array",
245
- "items": { "type": "string" }
309
+ "items": { "$ref": "project.schema.json#/$defs/inputString" }
246
310
  }
247
311
  },
248
312
  "namedInputs": {
@@ -252,7 +316,7 @@
252
316
  "type": "array",
253
317
  "items": {
254
318
  "oneOf": [
255
- { "type": "string" },
319
+ { "$ref": "project.schema.json#/$defs/inputString" },
256
320
  { "$ref": "project.schema.json#/$defs/fileSetInput" },
257
321
  { "$ref": "project.schema.json#/$defs/environmentInput" },
258
322
  { "$ref": "project.schema.json#/$defs/runtimeInput" },
@@ -326,11 +390,71 @@
326
390
  "required": ["url"],
327
391
  "additionalProperties": false,
328
392
  "properties": {
329
- "url": { "type": "string" },
330
- "token": { "type": "string" },
331
- "teamId": { "type": "string" },
332
- "read": { "type": "boolean", "default": true },
333
- "write": { "type": "boolean", "default": true }
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)."
402
+ },
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."
408
+ },
409
+ "token": {
410
+ "type": "string",
411
+ "description": "HTTP backend bearer token sent as 'Authorization: Bearer …'. For REAPI, use 'bearerToken' instead."
412
+ },
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."
420
+ },
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." }
429
+ }
430
+ },
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."
434
+ },
435
+ "bearerToken": {
436
+ "type": "string",
437
+ "description": "REAPI-only: bearer token sent in gRPC 'authorization: Bearer …' metadata."
438
+ },
439
+ "instanceName": {
440
+ "type": "string",
441
+ "description": "REAPI-only: 'instance_name' for multi-tenant servers (single gRPC endpoint hosting multiple logical caches)."
442
+ },
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)."
447
+ },
448
+ "read": {
449
+ "type": "boolean",
450
+ "deprecated": true,
451
+ "description": "Deprecated. Use 'mode' instead. Setting both still works but emits a one-time warning."
452
+ },
453
+ "write": {
454
+ "type": "boolean",
455
+ "deprecated": true,
456
+ "description": "Deprecated. Use 'mode' instead. Setting both still works but emits a one-time warning."
457
+ }
334
458
  }
335
459
  }
336
460
  }
@@ -0,0 +1,96 @@
1
+ ---
2
+ name: vis
3
+ description: Use when the workspace contains a vis.config.ts (or vis.config.js/json) at the repo root, or when the user mentions "vis", "task-runner", or "@visulima/vis". This skill orchestrates the vis MCP server's eight read-only tools to inspect projects, plan task graphs, and diagnose remote-cache rotations.
4
+ ---
5
+
6
+ # Working with the `vis` task runner
7
+
8
+ `vis` is the Visulima monorepo task runner — a Turborepo/Nx-class tool with a remote cache, REAPI gRPC backend, and project graph. When this skill is active you have the **`@visulima/vis-mcp` server** mounted, exposing eight read-only tools. Use them in preference to running `vis` shell commands yourself: the tools give you structured JSON and run faster.
9
+
10
+ The MCP server deliberately does NOT execute targets or scaffold templates — Nx-style "agent prepares, human executes". When the user wants to run `<project>:<target>` or `vis generate <template>`, prepare the command (use `list_targets`/`describe_template` to confirm it exists and capture required arguments) and ask the user to run it themselves; afterwards use `get_run_logs` to read the result of any task run.
11
+
12
+ ## Tools available
13
+
14
+ | Tool | Purpose |
15
+ | ------------------- | --------------------------------------------------------------------------------------------------------------------------------- |
16
+ | `list_projects` | All projects in the workspace, optionally filtered by a vis query (`tag=frontend`, `type=application`, …) |
17
+ | `describe_project` | Full metadata for one project: language, layer, tags, root path, all targets |
18
+ | `list_targets` | Per-target rows across the workspace, optionally narrowed to a single project |
19
+ | `list_templates` | Scaffolding templates discovered in `.vis/templates/`, `.moon/templates/`, and `vis.config.ts` `generator.templates` |
20
+ | `describe_template` | Variable schema, default destination, and description for a single template — required before suggesting a `vis generate` command |
21
+ | `get_run_logs` | Most recent run summary from `.task-runner/`, or a specific `runId`, optionally filtered to one task |
22
+ | `cache_why` | Diff a task's cache hash against the previous run — pinpoints what changed (command, nodes, runtime, implicit deps) |
23
+ | `cache_hash` | Recorded hash and per-input hash details for a task |
24
+
25
+ ## Workflow patterns
26
+
27
+ ### Discovery — "what's in this repo?"
28
+
29
+ Default opening move when the user asks about the workspace:
30
+
31
+ 1. `list_projects` (no filter). Shows everything with categories and target counts.
32
+ 2. If they ask about a specific package, `describe_project` for the full picture rather than re-running list with a filter.
33
+
34
+ ### Plan a build
35
+
36
+ 1. `list_targets` (optionally with `project: "@scope/name"`) to see what `build`/`test`/`lint`/etc. targets exist.
37
+ 2. Tell the user the exact command (`vis run @scope/name:build`) and let them run it.
38
+ 3. Use `get_run_logs` afterwards to inspect status, cache hits, and stderr tails.
39
+
40
+ ### Investigate a cache miss
41
+
42
+ When a build that should have been cached re-ran:
43
+
44
+ 1. `get_run_logs` (no args → latest summary) — surfaces all task statuses for the last run.
45
+ 2. For any task with status `success` but `cacheStatus: "miss"`, call `cache_why` with that `taskId`. It diffs hashDetails against the previous run and tells you which input rotated (command string, file content, `implicitDependency`, runtime version, …).
46
+ 3. If `cache_why` shows the change but the user wants to see the raw hash inputs, `cache_hash` returns the full per-input breakdown.
47
+
48
+ ### Scaffold a new package or component
49
+
50
+ When the user asks for "a new X" / "scaffold Y":
51
+
52
+ 1. `list_templates` — pick the template whose `name` or `description` matches the user's request.
53
+ 2. `describe_template` with that name — read the `variables[]` schema. Identify which variables are `required` and which have sensible `default` values.
54
+ 3. Construct the command: `vis generate <name> -- --var1=value1 --var2=value2`. For interactive prompts, drop the `--` overrides and let the user step through. For `--defaults`-friendly templates, add `--defaults` to skip prompts.
55
+ 4. Hand the command to the user to execute. Don't fabricate variable values — if the user hasn't told you what to pass for a required variable, ask.
56
+
57
+ #### Worked example
58
+
59
+ User: _"Scaffold a new React button component called PrimaryButton."_
60
+
61
+ 1. Call `list_templates` → response contains an entry `{ "name": "component", "source": "native", "description": "Scaffold a React component" }`. That's the closest match.
62
+ 2. Call `describe_template` with `{ "name": "component" }` → response shows `variables`:
63
+ ```json
64
+ [
65
+ { "name": "name", "type": "string", "required": true, "prompt": "Component name?" },
66
+ { "name": "withTest", "type": "boolean", "required": false, "default": true },
67
+ { "name": "style", "type": "enum", "required": false, "default": "primary", "values": ["primary", "secondary"] }
68
+ ]
69
+ ```
70
+ 3. The user supplied `name` (`PrimaryButton`) and implied `style=primary` (default already matches). `withTest` is unspecified — the default is fine, no need to override.
71
+ 4. Suggested command for the user to run:
72
+ ```sh
73
+ vis generate component -- --name=PrimaryButton --style=primary
74
+ ```
75
+ Do **not** invent values for required variables the user never mentioned — ask first.
76
+
77
+ ### Diagnose a failed run
78
+
79
+ 1. `get_run_logs` to see which task(s) failed.
80
+ 2. `get_run_logs` with `taskId` set to the failing task — returns just that entry, including the captured stderr tail.
81
+ 3. Decide: is it a code bug (read the project's source), a cache poisoning issue (`cache_why`), or environmental (look at the run summary's `runtime` block)?
82
+
83
+ ## Safety rules
84
+
85
+ - **All tools are read-only.** The server does not execute targets. If the user wants something built/tested/linted, give them the command and let them run it.
86
+ - **All tools run in the directory where `vis-mcp` was launched.** Override at server startup by setting `VIS_MCP_WORKSPACE_ROOT`. You can read that path from the server's stderr boot line: `[vis-mcp] ready (workspace: …)`.
87
+
88
+ ## When NOT to use this skill
89
+
90
+ - The user wants to write a `vis.config.ts` — that's editing source, not running the CLI. Use Read/Edit/Write on the config file directly.
91
+ - The user is asking about Turborepo, Nx, or Bazel specifically (not vis). The tools won't help with those.
92
+ - The repo has no `vis.config.*` and no mention of vis. Don't volunteer the tools.
93
+
94
+ ## Tool-result conventions
95
+
96
+ All tools return JSON-encoded text in the standard MCP `content[].text` slot. On error, `isError: true` is set and the text payload is `{"error": "<message>"}`. Parse the JSON before reasoning about it — the text field is structured data, not prose.
@@ -0,0 +1,85 @@
1
+ ---
2
+ to: ".buildkite/pipeline.yml"
3
+ ---
4
+ # Generated by `vis generate buildkite-ci`.
5
+ # Run `vis ci` against affected packages on every build.{% if withHeal %}
6
+ # Heal block: on failure, `vis ai heal` posts a Buildkite annotation; an
7
+ # allow-listed maintainer manually unblocks the block step to apply +
8
+ # commit the patch via `vis ai heal accept`. The unblocker email
9
+ # (BUILDKITE_UNBLOCKER_EMAIL) must be listed in `ai.heal.allowedActors`
10
+ # in vis.config.ts or the accept step refuses to commit.{% endif %}
11
+
12
+ steps:
13
+ - label: ":hammer: vis ci"
14
+ key: ci
15
+ timeout_in_minutes: 30
16
+ command: |
17
+ {% if packageManager == "pnpm" %} corepack enable
18
+ pnpm install --frozen-lockfile
19
+ pnpm vis ci {{ targets }}
20
+ {% endif %}{% if packageManager == "npm" %} npm ci
21
+ npx vis ci {{ targets }}
22
+ {% endif %}{% if packageManager == "yarn" %} corepack enable
23
+ yarn install --immutable
24
+ yarn vis ci {{ targets }}
25
+ {% endif %}{% if packageManager == "bun" %} bun install --frozen-lockfile
26
+ bunx vis ci {{ targets }}
27
+ {% endif %} agents:
28
+ queue: {{ agentQueue }}
29
+ {% if withHeal %}
30
+ - label: ":sparkles: vis ai heal"
31
+ key: heal-propose
32
+ depends_on: ci
33
+ timeout_in_minutes: 30
34
+ # Only run when CI failed and the build is for a PR — heal-accept
35
+ # has nowhere to commit on push-event builds.
36
+ if: build.failed_jobs > 0 && build.pull_request.id != null
37
+ command: |
38
+ {% if packageManager == "pnpm" %} corepack enable
39
+ pnpm install --frozen-lockfile
40
+ pnpm vis ai heal
41
+ {% endif %}{% if packageManager == "npm" %} npm ci
42
+ npx vis ai heal
43
+ {% endif %}{% if packageManager == "yarn" %} corepack enable
44
+ yarn install --immutable
45
+ yarn vis ai heal
46
+ {% endif %}{% if packageManager == "bun" %} bun install --frozen-lockfile
47
+ bunx vis ai heal
48
+ {% endif %} agents:
49
+ queue: {{ agentQueue }}
50
+ # Buildkite has no commit API of its own — `vis ai heal accept`
51
+ # derives the upstream provider from BUILDKITE_REPO and commits
52
+ # through GitHub or GitLab. Set GITHUB_TOKEN or GITLAB_TOKEN on
53
+ # the agent (matching your remote) so heal accept can land the patch.
54
+
55
+ - block: ":white_check_mark: Apply AI heal patch?"
56
+ key: heal-gate
57
+ depends_on: heal-propose
58
+ if: build.failed_jobs > 0 && build.pull_request.id != null
59
+ prompt: |
60
+ Unblocking applies and commits the patch from the heal annotation.
61
+ The unblocker email (BUILDKITE_UNBLOCKER_EMAIL) must be listed in
62
+ `ai.heal.allowedActors` in vis.config.ts, otherwise the accept
63
+ step will refuse to commit.
64
+
65
+ - label: ":robot_face: vis ai heal accept"
66
+ key: heal-accept
67
+ depends_on: heal-gate
68
+ timeout_in_minutes: 30
69
+ # Defense in depth — heal-accept can't push to a fork and has no
70
+ # commit target on push-event builds. Refuse early.
71
+ if: build.pull_request.id != null
72
+ command: |
73
+ {% if packageManager == "pnpm" %} corepack enable
74
+ pnpm install --frozen-lockfile
75
+ pnpm vis ai heal accept
76
+ {% endif %}{% if packageManager == "npm" %} npm ci
77
+ npx vis ai heal accept
78
+ {% endif %}{% if packageManager == "yarn" %} corepack enable
79
+ yarn install --immutable
80
+ yarn vis ai heal accept
81
+ {% endif %}{% if packageManager == "bun" %} bun install --frozen-lockfile
82
+ bunx vis ai heal accept
83
+ {% endif %} agents:
84
+ queue: {{ agentQueue }}
85
+ {% endif %}
@@ -0,0 +1,20 @@
1
+ title: Buildkite CI
2
+ description: A Buildkite pipeline.yml that runs `vis ci` against affected packages, with an optional `vis ai heal` block-step flow.
3
+ variables:
4
+ targets:
5
+ type: string
6
+ default: "lint,test,build"
7
+ prompt: Comma-separated list of `vis ci` targets to run
8
+ packageManager:
9
+ type: enum
10
+ values: [pnpm, npm, yarn, bun]
11
+ default: pnpm
12
+ prompt: Package manager (used in the install line)
13
+ withHeal:
14
+ type: boolean
15
+ default: false
16
+ prompt: Include the `vis ai heal` propose + block-step accept flow?
17
+ agentQueue:
18
+ type: string
19
+ default: default
20
+ prompt: Buildkite agent queue to schedule on
@@ -1,26 +0,0 @@
1
- /**
2
- * Base class for all `vis.config.ts` / `vis.task.ts` loader failures.
3
- * Consumers switch on `instanceof VisConfigError` to distinguish loader
4
- * failures from arbitrary user-code exceptions thrown inside a config.
5
- */
6
- declare class VisConfigError extends Error {
7
- readonly chain: ReadonlyArray<string>;
8
- constructor(message: string, chain: ReadonlyArray<string>, options?: ErrorOptions);
9
- }
10
- /** An `extends` chain re-enters a path that is still loading. */
11
- declare class VisConfigCycleError extends VisConfigError {
12
- constructor(reentered: string, chain: ReadonlyArray<string>);
13
- }
14
- /**
15
- * Wraps any throw raised by jiti while compiling a `vis.config.ts` /
16
- * `vis.task.ts`. Without this wrapper a user's syntax error surfaces as
17
- * "TypeError in workspace.ts" — which sends them debugging the wrong file.
18
- */
19
- declare class VisConfigLoadError extends VisConfigError {
20
- constructor(filePath: string, chain: ReadonlyArray<string>, cause: unknown);
21
- }
22
- /** An entry in `extends` could not be resolved on disk or via npm. */
23
- declare class VisConfigNotFoundError extends VisConfigError {
24
- constructor(specifier: string, chain: ReadonlyArray<string>, attempted: ReadonlyArray<string>);
25
- }
26
- export { VisConfigCycleError, VisConfigError, VisConfigLoadError, VisConfigNotFoundError };
@@ -1 +0,0 @@
1
- import{VisConfigCycleError as f}from"../packem_shared/VisConfigCycleError-CAYNC7d-.js";import{VisConfigError as e}from"../packem_shared/VisConfigError-B5LP1zRf.js";import{VisConfigLoadError as t}from"../packem_shared/VisConfigLoadError-CeqBSd2Z.js";import{VisConfigNotFoundError as g}from"../packem_shared/VisConfigNotFoundError-DZ9KC527.js";export{f as VisConfigCycleError,e as VisConfigError,t as VisConfigLoadError,g as VisConfigNotFoundError};
@@ -1,2 +0,0 @@
1
- var x=Object.defineProperty;var m=(e,t)=>x(e,"name",{value:t,configurable:!0});import{createRequire as A}from"node:module";import{findCacheDirSync as D}from"@visulima/find-cache-dir";import{isAccessibleSync as d,ensureDirSync as y,readJsonSync as V,writeJsonSync as T}from"@visulima/fs";import{join as f,dirname as v,isAbsolute as B}from"@visulima/path";import{createJiti as b}from"jiti";import{m as J}from"../packem_shared/target-merge-DNa-6eWu.js";import{VisConfigCycleError as L}from"../packem_shared/VisConfigCycleError-CAYNC7d-.js";import{VisConfigLoadError as S}from"../packem_shared/VisConfigLoadError-CeqBSd2Z.js";import{VisConfigNotFoundError as C}from"../packem_shared/VisConfigNotFoundError-DZ9KC527.js";const R=A(import.meta.url),l=typeof globalThis<"u"&&typeof globalThis.process<"u"?globalThis.process:process,g=m(e=>{if(typeof l<"u"&&l.versions&&l.versions.node){const[t,s]=l.versions.node.split(".").map(Number);if(t>22||t===22&&s>=3||t===20&&s>=16)return l.getBuiltinModule(e)}return R(e)},"__cjs_getBuiltinModule"),{createHash:j}=g("node:crypto"),{readdirSync:_,copyFileSync:I,unlinkSync:P,readFileSync:$}=g("node:fs"),{createRequire:q}=g("node:module"),{tmpdir:N}=g("node:os");var M=Object.defineProperty,n=m((e,t)=>M(e,"name",{value:t,configurable:!0}),"r");const F=["vis.config.ts","vis.config.mts","vis.config.cts","vis.config.js","vis.config.mjs","vis.config.cjs"],U=new Set(F),G=["vis.task.ts","vis.task.mts","vis.task.cts","vis.task.js","vis.task.mjs","vis.task.cjs"],W=new Set(G),z={blockExoticSubdeps:!0,strictDepBuilds:!0,trustPolicy:"no-downgrade",trustPolicyIgnoreAfter:43200},H=n(e=>({...z,...e}),"mergeSecurityDefaults"),k=n(e=>({...e,security:H(e.security),update:{security:!0,target:"minor",...e.update}}),"applyDefaults"),K=n(e=>{let t;try{t=_(e)}catch{return}const s=new Set(t.filter(r=>U.has(r)));for(const r of F)if(s.has(r))return f(e,r)},"findVisConfigFile"),Y=n(e=>{let t;try{t=_(e)}catch{return}const s=new Set(t.filter(r=>W.has(r)));for(const r of G)if(s.has(r))return f(e,r)},"findVisTaskConfigFile"),w=n(e=>j("sha256").update($(e)).digest("hex"),"hashFileContents"),Q=n(e=>{const t=j("sha256"),s=[...e].sort();for(const r of s)t.update(r),t.update(":"),t.update(w(r)),t.update(`
2
- `);return t.digest("hex")},"hashConfigChain"),X=n(e=>{const t=f(e,"node_modules");if(d(t)){const r=f(t,".cache","vis");return y(r),f(r,"vis-config-cache.json")}const s=D("vis",{create:!0,cwd:e});return s?f(s,"vis-config-cache.json"):void 0},"getConfigCachePath"),Z=n((e,t)=>{if(d(e))try{const s=V(e);if(s.hash===t)return s.config}catch{}},"readConfigCache"),ee=n((e,t,s)=>{try{y(v(e)),T(e,{config:s,hash:t})}catch{}},"writeConfigCache"),te=n(e=>e===void 0?[]:Array.isArray(e)?e:[e],"normalizeExtends"),se=n((e,t,s)=>{if(B(e))throw new C(e,[...s,t],["Absolute paths in `extends` are not supported. Use a relative path or an npm package name."]);const r=[];if(e.startsWith("./")||e.startsWith("../")){const o=v(t),i=f(o,e);if(r.push(i),d(i))return i;throw new C(e,[...s,t],r)}try{return q(t).resolve(e)}catch{throw r.push(`require.resolve("${e}") from ${t}`),new C(e,[...s,t],r)}},"resolveExtendsSpecifier"),E=n(async(e,t,s)=>{const r=w(t),o=t.slice(t.lastIndexOf(".")),i=f(N(),`vis-config-${r}${o}`);I(t,i);let c;try{c=await e.import(i,{default:!0,try:!0})??{}}catch(a){throw new S(t,s,a)}finally{try{P(i)}catch{}}try{return(typeof c=="function"?await c()??{}:c)??{}}catch(a){throw new S(t,s,a)}},"loadRawConfig"),re=n((e,t)=>{const s={...e,...t};if(e.targetDefaults||t.targetDefaults){const r=new Set([...Object.keys(e.targetDefaults??{}),...Object.keys(t.targetDefaults??{})]),o={};for(const i of r)o[i]=J(e.targetDefaults?.[i],t.targetDefaults?.[i]);s.targetDefaults=o}return(e.taskDefaults||t.taskDefaults)&&(s.taskDefaults=[...e.taskDefaults??[],...t.taskDefaults??[]]),(e.fileGroups||t.fileGroups)&&(s.fileGroups={...e.fileGroups,...t.fileGroups}),(e.taskGroups||t.taskGroups)&&(s.taskGroups={...e.taskGroups,...t.taskGroups}),(e.security||t.security)&&(s.security={...e.security,...t.security}),(e.update||t.update)&&(s.update={...e.update,...t.update}),(e.taskRunnerOptions||t.taskRunnerOptions)&&(s.taskRunnerOptions={...e.taskRunnerOptions,...t.taskRunnerOptions}),delete s.extends,s},"mergeVisConfigs"),O=n(async(e,t,s,r,o,i)=>{if(r.has(t))throw new L(t,s);if(!o.has(t)){r.add(t);try{const c=await E(e,t,s),a=te(c.extends);for(const u of a){const p=se(u,t,s);await O(e,p,[...s,t],r,o,i)}o.set(t,c),i.push(t)}finally{r.delete(t)}}},"resolveConfigChain"),Ce=n(async e=>{const t=K(e);if(!t)return k({});const s=b(e,{fsCache:!1,moduleCache:!1}),r=new Set,o=new Map,i=[];await O(s,t,[],r,o,i);const c=Q(i),a=X(e);if(a){const h=Z(a,c);if(h)return h}let u={};for(const h of i)u=re(u,o.get(h));const p=k(u);return a&&ee(a,c,p),p},"loadVisConfig"),ie=n(e=>e.replaceAll(/[^\w.-]+/g,"_"),"sanitizeProjectName"),ne=n((e,t)=>{const s=f(e,"node_modules"),r=ie(t);if(d(s)){const i=f(s,".cache","vis","task-configs");return y(i),f(i,`${r}.json`)}const o=D("vis",{create:!0,cwd:e});return o?f(o,"task-configs",`${r}.json`):void 0},"getVisTaskCachePath"),oe=n((e,t)=>{if(d(e))try{const s=V(e);if(s.hash===t)return s.config}catch{}},"readVisTaskCache"),ae=n((e,t,s)=>{try{y(v(e)),T(e,{config:s,hash:t})}catch{}},"writeVisTaskCache"),ke=n(async(e,t,s)=>{const r=Y(t);if(!r)return;const o=w(r),i=ne(e,s);if(i){const u=oe(i,o);if(u)return u}const c=b(t,{fsCache:!1,moduleCache:!1}),a=await E(c,r,[]);return i&&ae(i,o,a),a},"loadVisTaskConfig");n(e=>e,"defineTaskConfig");n(e=>k(e),"defineConfig");n(e=>e,"definePlugin");export{F as CONFIG_FILES,z as SECURITY_DEFAULTS,G as TASK_CONFIG_FILES,k as applyDefaults,K as findVisConfigFile,Y as findVisTaskConfigFile,Ce as loadVisConfig,ke as loadVisTaskConfig};
@@ -1 +0,0 @@
1
- var t=Object.defineProperty;var o=(e,r)=>t(e,"name",{value:r,configurable:!0});import{VisConfigError as c}from"./VisConfigError-B5LP1zRf.js";var s=Object.defineProperty,a=o((e,r)=>s(e,"name",{value:r,configurable:!0}),"e");class C extends c{static{o(this,"VisConfigCycleError")}static{a(this,"VisConfigCycleError")}constructor(r,i){const n=[...i,`${r} (re-enters)`].join(" → ");super(`Config cycle: ${n}`,i)}}export{C as VisConfigCycleError};
@@ -1 +0,0 @@
1
- var n=Object.defineProperty;var e=(t,r)=>n(t,"name",{value:r,configurable:!0});var o=Object.defineProperty,a=e((t,r)=>o(t,"name",{value:r,configurable:!0}),"s");class h extends Error{static{e(this,"VisConfigError")}static{a(this,"VisConfigError")}chain;constructor(r,s,i){super(r,i),this.name=this.constructor.name,this.chain=s}}export{h as VisConfigError};
@@ -1,2 +0,0 @@
1
- var n=Object.defineProperty;var t=(o,r)=>n(o,"name",{value:r,configurable:!0});import{VisConfigError as c}from"./VisConfigError-B5LP1zRf.js";var g=Object.defineProperty,f=t((o,r)=>g(o,"name",{value:r,configurable:!0}),"t");class u extends c{static{t(this,"VisConfigLoadError")}static{f(this,"VisConfigLoadError")}constructor(r,i,e){const a=e instanceof Error?e.message:String(e),s=i.length>0?`
2
- Chain: ${i.join(" → ")}`:"";super(`Failed to load ${r}: ${a}${s}`,i,{cause:e})}}export{u as VisConfigLoadError};
@@ -1,5 +0,0 @@
1
- var c=Object.defineProperty;var n=(o,r)=>c(o,"name",{value:r,configurable:!0});import{VisConfigError as f}from"./VisConfigError-B5LP1zRf.js";var g=Object.defineProperty,i=n((o,r)=>g(o,"name",{value:r,configurable:!0}),"t");const l=i(o=>o.join(" → "),"formatChain");class h extends f{static{n(this,"VisConfigNotFoundError")}static{i(this,"VisConfigNotFoundError")}constructor(r,t,e){const s=t.length>0?t[t.length-1]:"<unknown>",a=e.length>0?`
2
- Tried:
3
- ${e.join(`
4
- `)}`:"";super(`Cannot resolve "${r}" extended from ${s}.${a}
5
- Chain: ${l(t)}`,t)}}export{h as VisConfigNotFoundError};