@visulima/vis-mcp 1.0.46 → 2.0.0

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.
package/CHANGELOG.md CHANGED
@@ -1,3 +1,507 @@
1
+ ## @visulima/vis-mcp [2.0.0](https://github.com/visulima/visulima/compare/@visulima/vis-mcp@1.0.47...@visulima/vis-mcp@2.0.0) (2026-10-14)
2
+
3
+ ### ⚠ BREAKING CHANGES
4
+
5
+ * **vis:** vis run <target> now exits 1 when no project defines the
6
+ target. Scripts that relied on the silent exit 0 must pass --if-present.
7
+
8
+ Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
9
+
10
+ * feat(task-runner): add tracker kind to trace key
11
+
12
+ The trace key now includes which mechanism observed the file accesses:
13
+ seccomp, strace, interpose, iat or preload. The same workspace traced on
14
+ Linux and macOS can no longer produce the same key for different
15
+ observations.
16
+
17
+ Upgrade notes:
18
+ - Traced entries written after this change are keyed on the new digest.
19
+ Entries written before it stay reachable through the task index and
20
+ are validated against their files as before, so there is no forced
21
+ miss on upgrade.
22
+
23
+ Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
24
+
25
+ * feat(task-runner): fall back to declared hash
26
+
27
+ A traced task whose tracker observed no workspace access was never
28
+ cached. That left targets which declare inputs uncached on hosts without
29
+ a working tracker. When the target declares inputs, such a run is now
30
+ keyed on its declared hash instead. Targets without inputs keep the
31
+ previous behaviour: no cache entry and a warning.
32
+
33
+ The declared hash is computed only when the tracker is empty, so traced
34
+ runs that observe files do no extra hashing. A fallback entry is stored
35
+ without a fingerprint, and the next run validates it by recomputing the
36
+ declared hash. A changed hash is reported as declared-changed. The task
37
+ result and the run summary record hashSource: "declared-fallback".
38
+
39
+ Upgrade notes:
40
+ - Existing entries are unchanged. Only runs that observe no workspace
41
+ access, for targets that declare inputs, gain a cache entry.
42
+
43
+ Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
44
+
45
+ * feat(vis): show declared-fallback key in cache why
46
+
47
+ cache why and cache hash now say when a traced run was keyed on its
48
+ declared hash, and the JSON output carries hashSource. The vis config
49
+ schema is regenerated for the updated autoFingerprint description.
50
+
51
+ Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
52
+
53
+ * docs(vis): describe declared fallback and trace key
54
+
55
+ The caching guide and configuration reference now explain when an empty
56
+ trace is keyed on the declared hash, how a trace key is built, and what
57
+ cache why reports. The RFC marks G1-B and G4 done.
58
+
59
+ Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
60
+
61
+ * docs(task-runner): describe declared fallback for empty traces
62
+
63
+ The empty-fingerprint section now explains both outcomes: a target that
64
+ declares inputs is keyed on its declared hash, and one that does not is
65
+ left uncached with a warning.
66
+
67
+ Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
68
+
69
+ * docs(vis): correct trace caching claim in why-vis
70
+
71
+ A run the tracker cannot observe is keyed on its declared inputs when
72
+ the target declares them. It is not cached otherwise.
73
+
74
+ Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
75
+
76
+ * feat(task-runner): parse top-level && chains
77
+
78
+ Add splitCompoundCommand, a quote-aware splitter that cuts a shell
79
+ command on top-level && only. Anything it does not model (;, ||, a
80
+ background &, subshells, command substitution, heredocs, comments,
81
+ empty segments, cd/export/source/set/trap/exec and VAR=value prefixes)
82
+ leaves the whole command unsplit and reports why.
83
+
84
+ Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
85
+
86
+ * feat(task-runner): add splitCompound segment chains
87
+
88
+ Add the splitCompound target option. A declared-mode target whose
89
+ * **vis:** `vis run` with --filter, --query or --tag that selects no
90
+ project now exits 1. Scripts that relied on the silent exit 0 must pass
91
+ --if-present.
92
+
93
+ Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
94
+
95
+ * test(vis): keep empty --affected results exit 0
96
+
97
+ Pins the behaviour the empty-selection fix must not change: when a --tag
98
+ selects a project that --affected then excludes, the run prints "No
99
+ projects affected by the changes." and returns. A mutation that throws
100
+ there fails the test.
101
+
102
+ The fixture repo runs with GIT_* variables cleared, so it cannot act on
103
+ the repository that a git hook is committing.
104
+
105
+ Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
106
+
107
+ * fix(vis): let ci and affected opt out of empty runs
108
+
109
+ vis run now fails when a target, --query or tag selects no projects, and
110
+ vis ci / vis affected hand their --query to it. A job whose query can
111
+ legitimately match nothing had no way to say so. Add --if-present to both
112
+ and forward it to vis run.
113
+
114
+ Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
115
+
116
+ * fix(task-runner): match excludes inside the workspace
117
+
118
+ The tracker tested its exclude patterns (/dev/, /tmp/, /etc/, ...) against
119
+ the absolute path before checking containment. A workspace under any of
120
+ those directory names, such as ~/dev/project or a /tmp CI checkout,
121
+ recorded no accesses at all on the strace, seccomp, interpose and IAT
122
+ paths, so traced caching never engaged. The Windows IAT check was also a
123
+ lowercase startsWith without a separator boundary, so a workspace /ws/app
124
+ accepted /ws/app-other.
125
+
126
+ Every path now goes through resolveAccessPath: containment first, then the
127
+ patterns against the path inside the workspace.
128
+
129
+ Upgrade notes: traced targets in a workspace under a dev, tmp or etc
130
+ directory now cache where they previously never did. The IAT path no longer
131
+ accepts sibling directories that share the workspace prefix.
132
+
133
+ Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
134
+
135
+ * fix(task-runner): key unset env names apart from empty ones
136
+
137
+ A traced key recorded an unset name and an empty value the same way, so a
138
+ name that went from unset to "" hit a stale entry. An unset name now keys
139
+ differently from an empty one, using the same presence scheme as the
140
+ declared hasher.
141
+
142
+ validate takes the env to check against. It defaults to process.env, so
143
+ existing callers see no change; the next commit passes the child env.
144
+
145
+ Upgrade notes: traced entries that key an env name miss once after
146
+ upgrading, because the stored env key format changed.
147
+
148
+ Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
149
+
150
+ * fix(task-runner): key traced runs on the child env
151
+
152
+ A traced run keyed the parent's env values, so a value the child receives
153
+ from another source (an envFile, service env, VIS_ARG_* or a per-target env)
154
+ was not in the key, and changing it left a stale hit.
155
+
156
+ The key now reads the names it covers from the resolved child env
157
+ (TaskRunnerContext.resolveChildEnv). A name the clean policy hides hashes as
158
+ unset. Validation reads the same env, so a hit needs the values the child
159
+ will see. Untracked names stay out of the key, and the key does not cover
160
+ the whole environment.
161
+
162
+ The key also covers the command the run spawns. TaskRunnerContext.resolveCommand
163
+ supplies it, so caller-side arguments and shell wrapping change the key.
164
+ Without it the project target command is used, as before.
165
+
166
+ TaskRunnerContext.preTraceCheck runs on a cache miss before tracking. A
167
+ returned message fails the task with exit code 1; the child does not spawn
168
+ and nothing is cached.
169
+
170
+ Upgrade notes: a traced key changes when the spawned command differs from
171
+ the configured one. Traced entries that key an env name also miss once,
172
+ as in the previous commit.
173
+
174
+ Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
175
+
176
+ * fix(vis): traced targets run the executor command
177
+
178
+ A traced target ran the raw project command. Forwarded arguments
179
+ (`vis run build -- --flag`) and `affectedFiles: "args"` paths never reached
180
+ the child, `${...}` tokens and a custom `shell` did not apply, and
181
+ `strictEnv` was not checked.
182
+
183
+ The executor and the traced run now share one resolver for the spawned
184
+ command, and one strict-env check that reads the child env the spawn gets.
185
+ Both spawn the same string, and the traced key hashes it, so the arguments
186
+ and affected files change the key.
187
+
188
+ Upgrade notes:
189
+ - Traced targets now receive forwarded arguments and `affectedFiles: "args"`
190
+ paths. A traced run with these misses once, since the key includes them.
191
+ - Traced targets now run their configured command, with tokens expanded and
192
+ any custom shell applied, as the executor does. They used to run the raw
193
+ project command.
194
+ - `strictEnv` (flag or config) now fails a traced target that references an
195
+ unset variable, before the child starts. A traced target that passed with
196
+ an unset reference now fails.
197
+ - Traced keys hash the env values the child receives (see the task-runner
198
+ commits), so traced targets with env names in the key miss once.
199
+
200
+ Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
201
+
202
+ * docs(vis): document the traced key and strict env
203
+
204
+ The caching guide lists what a traced key covers: the spawned command and
205
+ the env values the child receives for the names the key covers. The run
206
+ guide says the strict-env check runs for traced targets too. The RFC
207
+ records the resolution and the gaps that remain: the declared hasher still
208
+ reads process.env for fingerprintEnv and envVars, and persistent targets and
209
+ the TUI retry spawn the raw command, so forwarded arguments do not reach them.
210
+
211
+ Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
212
+
213
+ * fix(vis): persistent and retried tasks keep args
214
+
215
+ Persistent targets and a TUI retry spawned the raw override command, so
216
+ forwarded arguments, affectedFiles args and a custom shell were dropped
217
+ while the first attempt of the same task had them. Both now spawn the
218
+ command the executor and the traced run use.
219
+
220
+ Upgrade notes: vis run <persistent> -- <args> now passes the arguments to
221
+ the persistent command.
222
+
223
+ Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
224
+
225
+ * fix(task-runner): key declared env on the child env
226
+
227
+ The declared hasher read fingerprintEnv, envVars, env:// inputs,
228
+ autoEnvVars and framework names from the parent's process.env, but the
229
+ child also gets values from envFile layering, service env, task arguments
230
+ and per-target env. A cached target keyed on a variable only its env file
231
+ defines kept serving a stale hit after the file changed, and fingerprintEnv
232
+ wildcards never matched names the parent lacked.
233
+
234
+ The hasher takes a childEnv resolver, supplied from resolveChildEnv, and
235
+ keys and expands patterns against the environment the task will receive.
236
+ globalEnv is workspace-wide and still reads the parent's.
237
+
238
+ Upgrade notes: a declared target whose child sees a different value than
239
+ the parent for a keyed name gets one new key, and so one cache miss. Keys
240
+ for names with equal values are unchanged.
241
+
242
+ Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
243
+
244
+ * fix(vis): doctor no longer crashes without a lockfile
245
+
246
+ vis doctor looked the package manager up twice with a strict resolver that
247
+ throws when a workspace has no lockfile and no packageManager field, the
248
+ state of every new project. It crashed with a stack trace instead of
249
+ reporting. Reuse the tolerant detection the command already performed.
250
+
251
+ Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
252
+
253
+ * docs(vis-mcp): fix lint and cache tool text
254
+
255
+ The lint description listed the default adapters without the opt-in
256
+ typecheck adapter. cache_why and cache_hash described hashDetails only,
257
+ but trace-mode tasks have no hashDetails: their reasons are in
258
+ task.cacheMissReasons and their tracked state is in trackedFingerprint.
259
+
260
+ Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
261
+
262
+ * docs(vis): cover run, cache and lint in the skill
263
+
264
+ Add the tools the table left out, correct the tool count, and document
265
+ the empty-selection exit code, the opt-in typecheck adapter, the trace
266
+ miss reasons, and the doctor env coverage check. Replace the cache-miss
267
+ flow's invented status and stderr fields with the real summary fields.
268
+
269
+ Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
270
+
271
+ * docs(vis): sync ai guide tool reference
272
+
273
+ The guide listed eight tools and described a run_task tool that does
274
+ not exist. Add the five missing tools and the trace-mode fields that
275
+ cache_why and cache_hash return.
276
+
277
+ Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
278
+
279
+ * fix(vis-mcp): read the run summary vis really writes
280
+
281
+ list_runs read runId, startedAt, status and tasks[].status, none of which
282
+ the run summary has: it carries id, startTime, stats and per-task
283
+ exitCode. Every run therefore showed as a success with no failures and no
284
+ start time, including failed ones, and get_run_logs echoed an undefined
285
+ run id. Read the real fields, fall back to the old spellings, and test
286
+ against a summary shaped like the one vis writes.
287
+
288
+ Upgrade notes: list_runs now reports failed runs as failures, with their
289
+ start time and task counts.
290
+
291
+ Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
292
+
293
+ * feat(task-runner): chain trace keys per segment
294
+
295
+ A `splitCompound` target with `hashMode: "trace"` (or workspace
296
+ `autoFingerprint`) was refused and ran whole. It now splits like a declared
297
+ target. Each segment runs through the tracker on its own command, and its
298
+ trace key folds in the trace key of the segment before it.
299
+
300
+ - fingerprint: `TaskFingerprint.chainKey` holds the predecessor's trace key.
301
+ It joins `hashFingerprint` only when set, so keys of ordinary tasks do not
302
+ move (a test pins two of them). `validateChain` checks it on lookup, after
303
+ the command and tracker checks and before any file is hashed, and a moved
304
+ predecessor misses with `chain-changed`.
305
+ - orchestrator: a segment after the first keys on its predecessor's trace key.
306
+ A segment whose predecessor has no key this run is neither served nor stored.
307
+ A traced segment publishes its key on a hit as well as on a store.
308
+ - default resolver: reads a segment's command from `overrides`, so the tracker
309
+ and the tracker-kind prediction see that segment's command, not the chain.
310
+ - Refusals kept: `{ auto: true }` outputs, `when`, `always`, custom shell and
311
+ unsupported shell syntax. The trace and auto-fingerprint refusals are removed.
312
+
313
+ Upgrade notes:
314
+
315
+ - Targets that set `splitCompound` together with `hashMode: "trace"` or
316
+ `taskRunner.autoFingerprint` now run as `target#n` segments. They used to run
317
+ whole. Their first run after upgrading misses, because the segment entries
318
+ are new.
319
+ - Keys of targets that do not split are unchanged, both traced and declared.
320
+ - `vis run --dry-run` lists the segments of these targets, each marked `(trace)`.
321
+ - `SplitCompoundOptions` (exported from `@visulima/task-runner`) no longer has
322
+ `autoFingerprint`. Passing it is now a type error. It had no effect once the
323
+ split refusal was gone.
324
+ - The `splitCompound` description in the vis config schemas is regenerated.
325
+
326
+ Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
327
+
328
+ * fix(vis): give segments their target's service env
329
+
330
+ The service env of a run is keyed on the target's id, before a
331
+ `splitCompound` target is split. A segment runs under its own id
332
+ (`target#n`), so its spawn found no service env. A split target therefore
333
+ lost the variables of the services it depends on, in declared mode as well
334
+ as traced mode.
335
+
336
+ `resolveTaskSpawn` now reads a segment's entry from the target it runs in
337
+ place of. Every spawn path reads through that function, so the executor, the
338
+ persistent launch and the retry get the same environment.
339
+
340
+ Upgrade notes:
341
+
342
+ - A `splitCompound` target's segments now receive the service env they used
343
+ to miss. A segment's key changes once after upgrading only when it names a
344
+ service variable, because keys cover the env values the child receives.
345
+
346
+ Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
347
+
348
+ * test(vis): cover traced segments through vis run
349
+
350
+ Runs a `hashMode: "trace"` target with `splitCompound` through the run
351
+ handler. Covers the last-segment-only re-run, the re-run of every segment
352
+ when the first segment's input changes, forwarded arguments on the last
353
+ segment only, and the `(trace)` annotation on each segment in the dry-run
354
+ plan.
355
+
356
+ Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
357
+
358
+ * docs(vis): document traced segment keys
359
+
360
+ The `splitCompound` option no longer refuses trace hashing. The run option
361
+ row and the caching guide now describe how a traced segment's key chains to
362
+ its predecessor, and the cases where a segment is neither served nor stored.
363
+ The RFC marks G3.3 done and records the chain, the kept refusals and the
364
+ limits found while implementing it.
365
+
366
+ Upgrade notes:
367
+
368
+ - The caching guide and the run option table no longer list trace hashing as
369
+ a reason the split is refused. Targets that combine `splitCompound` with
370
+ `hashMode: "trace"` split as described in the previous commits.
371
+
372
+ Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
373
+
374
+ * fix(vis): annotate traced tasks under auto-fingerprint
375
+
376
+ The dry-run plan marked a task `(trace)` only when its own `hashMode` was
377
+ `"trace"`. Under `taskRunner.autoFingerprint` the engine traces every task,
378
+ segments included, so their plan lines showed no trace mark.
379
+
380
+ The annotation now follows the engine: `hashMode: "trace"` or the workspace
381
+ switch.
382
+
383
+ Tests cover the dry-run annotation under the workspace switch, and
384
+ `vis cache why` on a segment that missed because the segment before it moved.
385
+
386
+ Upgrade notes:
387
+
388
+ - Under `taskRunner.autoFingerprint`, `vis run --dry-run` now marks every task
389
+ `(trace)`, including targets that do not split. Before, only per-target trace
390
+ targets were marked. The run itself is unchanged.
391
+
392
+ Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
393
+
394
+ * test(task-runner): guard segment tests for win32
395
+
396
+ Two segment tests use a bare `true` command as a segment whose tracker sees
397
+ nothing. `true` is a POSIX builtin that cmd.exe lacks, so they now skip on
398
+ win32. The clean-environment test passes the platform's essential names
399
+ (SystemRoot on Windows) to the child, so node can start there.
400
+
401
+ Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
402
+
403
+ * docs(vis): correct the chain miss reason in the RFC
404
+
405
+ A moved predecessor misses with `chain-changed`, which `vis cache why` prints
406
+ as `Previous segment changed`. The reason does not name the predecessor, so
407
+ the RFC no longer says it does.
408
+
409
+ Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
410
+
411
+ * fix(vis): report target properties under options
412
+
413
+ splitCompound, hashMode, fingerprintEnv and the other target-level
414
+ properties are read from the target, not from its options bag. Written
415
+ under options they parsed fine and did nothing, and the run.mdx options
416
+ table listed splitCompound there. Warn when a run finds one under options,
417
+ and move splitCompound out of the options table with a note on which keys
418
+ are target-level.
419
+
420
+ Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
421
+
422
+ * fix(task-runner): key dependents on traced hits
423
+
424
+ A traced task published its key only when it ran and stored, not when
425
+ it was served from cache. A declared task that dependsOn it then folded
426
+ the traced key on a cold run and nothing on a warm one, so its key
427
+ flipped with whether the dependency ran. Worse, the key without the
428
+ dependency was shared across dependency states, so after the dependency
429
+ changed and then hit again the dependent was served output built from
430
+ the older state.
431
+
432
+ Publish the key on every traced hit, as segments already did.
433
+
434
+ Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
435
+
436
+ * fix(vis): replace every match in two rewrites
437
+
438
+ CodeQL flagged two string replaces that rewrite only the first match.
439
+ Neither input holds a second match today, but replaceAll states the
440
+ intent and keeps the code scan green.
441
+
442
+ Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
443
+
444
+ * fix(vis): check referenced tsconfigs in build mode
445
+
446
+ tsc -b rejects --noEmit once one project references another (TS6310),
447
+ so a solution-style workspace whose projects import each other could
448
+ never pass the type check. Drop the flag in build mode and document
449
+ that it writes each project's own outDir and tsbuildinfo.
450
+
451
+ Also decide config ownership with a relative path, so a root with
452
+ Windows separators still finds its own tsconfig.
453
+
454
+ Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
455
+
456
+ * fix(vis): keep the GitLab token off self-hosted hosts
457
+
458
+ GITLAB_TOKEN belongs to gitlab.com, but a gitlab://host source names a
459
+ host the template author chose, so the token was sent wherever the URL
460
+ pointed. Skip the environment token there; create.auth, a token in the
461
+ URL and GIGET_AUTH still apply.
462
+
463
+ Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
464
+
465
+ * fix(vis): apply review fixes to create, doctor, run
466
+
467
+ - resolve a create.defaultTemplate alias before the org preflight
468
+ - pass the config to the task overlay loader in the env check
469
+ - keep doctor running when the env coverage check throws
470
+ - retry a split target by segment id
471
+ - declare if-present with negatable() and drop the tag claim from ci
472
+ - correct the clean-env note for traced targets and the splitCompound
473
+ and if-present wording in the docs
474
+
475
+ Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
476
+
477
+ * test: fix windows paths, quoting and env names
478
+
479
+ - pass a file path to node as an argument, not inside a JS string
480
+ - quote only values that contain whitespace, as cmd drops the first
481
+ and last quote of a command that starts with one
482
+ - match env names without regard to case and allow the names Windows
483
+ adds to every process
484
+ - compare paths in the normalised form the code returns
485
+ - expect cmd to leave $VAR unexpanded
486
+
487
+ Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
488
+
489
+ ### Features
490
+
491
+ * **vis:** git templates, clean env cache keys, trace segments ([#969](https://github.com/visulima/visulima/issues/969)) ([f16cf03](https://github.com/visulima/visulima/commit/f16cf038f9827abcf814fa1c2a5821c004d6d746)), closes [id#1](https://github.com/visulima/id/issues/1) [id#2](https://github.com/visulima/id/issues/2)
492
+
493
+
494
+ ### Dependencies
495
+
496
+ * **@visulima/vis:** upgraded to 5.0.0
497
+
498
+ ## @visulima/vis-mcp [1.0.47](https://github.com/visulima/visulima/compare/@visulima/vis-mcp@1.0.46...@visulima/vis-mcp@1.0.47) (2026-10-14)
499
+
500
+
501
+ ### Dependencies
502
+
503
+ * **@visulima/vis:** upgraded to 4.3.1
504
+
1
505
  ## @visulima/vis-mcp [1.0.46](https://github.com/visulima/visulima/compare/@visulima/vis-mcp@1.0.45...@visulima/vis-mcp@1.0.46) (2026-10-13)
2
506
 
3
507
 
package/dist/bin.js CHANGED
@@ -1,3 +1,3 @@
1
1
  #!/usr/bin/env node
2
- import{realpathSync as t}from"node:fs";import{argv as e}from"node:process";import{fileURLToPath as o}from"node:url";import{startMcpServer as a}from"./packem_shared/createMcpServer-C4LuWhpp.js";const i=async()=>{try{await a()}catch(r){process.stderr.write(`[vis-mcp] failed to start: ${r instanceof Error?r.message:String(r)}
2
+ import{realpathSync as t}from"node:fs";import{argv as e}from"node:process";import{fileURLToPath as o}from"node:url";import{startMcpServer as a}from"./packem_shared/createMcpServer-DBbKrHaN.js";const i=async()=>{try{await a()}catch(r){process.stderr.write(`[vis-mcp] failed to start: ${r instanceof Error?r.message:String(r)}
3
3
  `),process.exit(1)}},s=(()=>{const r=e[1];if(r===void 0)return!1;try{return t(r)===t(o(import.meta.url))}catch{return!1}})();s&&await i();export{i as main};
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- import{execVis as t,execVisJson as o}from"./packem_shared/execVis-CInWWszP.js";import{clearListCache as i,listVisJson as p}from"./packem_shared/clearListCache-D-qeI660.js";import{errorResponse as f,okResponse as x,okStructuredResponse as a}from"./packem_shared/errorResponse-D1WOFYuT.js";import{createMcpServer as c,registerAllTools as l,startMcpServer as n}from"./packem_shared/createMcpServer-C4LuWhpp.js";import{registerAdvisoryStatus as d}from"./packem_shared/registerAdvisoryStatus-DnpRlAZ2.js";import{registerAudit as R}from"./packem_shared/registerAudit-ZskmQpJB.js";import{registerCacheHash as V}from"./packem_shared/registerCacheHash-CLFe-S23.js";import{registerCacheWhy as T}from"./packem_shared/registerCacheWhy-DBIgl8ww.js";import{registerDescribeProject as v}from"./packem_shared/registerDescribeProject-zZZrCz2G.js";import{registerDescribeTemplate as C}from"./packem_shared/registerDescribeTemplate-D1DYYNOB.js";import{registerFmt as b}from"./packem_shared/registerFmt-DYE0dqsx.js";import{registerGetRunLogs as y}from"./packem_shared/registerGetRunLogs-CukA12J7.js";import{registerLint as I}from"./packem_shared/registerLint-D_A4H5jb.js";import{registerListProjects as M}from"./packem_shared/registerListProjects-3dPVnYC9.js";import{registerListRuns as G}from"./packem_shared/registerListRuns-BoZ7DRKb.js";import{registerListTargets as O}from"./packem_shared/registerListTargets-95gAK_Bj.js";import{registerListTemplates as q}from"./packem_shared/registerListTemplates-LK8yLlVB.js";import{isSafeOptionValue as z,isSafePositional as B,isValidRunId as E,isValidTaskId as K}from"./packem_shared/isSafeOptionValue-BEUaZ7UP.js";export{i as clearListCache,c as createMcpServer,f as errorResponse,t as execVis,o as execVisJson,z as isSafeOptionValue,B as isSafePositional,E as isValidRunId,K as isValidTaskId,p as listVisJson,x as okResponse,a as okStructuredResponse,d as registerAdvisoryStatus,l as registerAllTools,R as registerAudit,V as registerCacheHash,T as registerCacheWhy,v as registerDescribeProject,C as registerDescribeTemplate,b as registerFmt,y as registerGetRunLogs,I as registerLint,M as registerListProjects,G as registerListRuns,O as registerListTargets,q as registerListTemplates,n as startMcpServer};
1
+ import{execVis as t,execVisJson as o}from"./packem_shared/execVis-CInWWszP.js";import{clearListCache as i,listVisJson as p}from"./packem_shared/clearListCache-D-qeI660.js";import{errorResponse as f,okResponse as x,okStructuredResponse as a}from"./packem_shared/errorResponse-D1WOFYuT.js";import{createMcpServer as c,registerAllTools as l,startMcpServer as n}from"./packem_shared/createMcpServer-DBbKrHaN.js";import{registerAdvisoryStatus as d}from"./packem_shared/registerAdvisoryStatus-DnpRlAZ2.js";import{registerAudit as R}from"./packem_shared/registerAudit-ZskmQpJB.js";import{registerCacheHash as V}from"./packem_shared/registerCacheHash-BGyhpFep.js";import{registerCacheWhy as T}from"./packem_shared/registerCacheWhy-CGuHRmfC.js";import{registerDescribeProject as v}from"./packem_shared/registerDescribeProject-zZZrCz2G.js";import{registerDescribeTemplate as C}from"./packem_shared/registerDescribeTemplate-D1DYYNOB.js";import{registerFmt as b}from"./packem_shared/registerFmt-DYE0dqsx.js";import{registerGetRunLogs as y}from"./packem_shared/registerGetRunLogs-tcoMohKG.js";import{registerLint as I}from"./packem_shared/registerLint-D0jyTg8L.js";import{registerListProjects as M}from"./packem_shared/registerListProjects-3dPVnYC9.js";import{registerListRuns as G}from"./packem_shared/registerListRuns-DA-dMOsv.js";import{registerListTargets as O}from"./packem_shared/registerListTargets-95gAK_Bj.js";import{registerListTemplates as q}from"./packem_shared/registerListTemplates-LK8yLlVB.js";import{isSafeOptionValue as z,isSafePositional as B,isValidRunId as E,isValidTaskId as K}from"./packem_shared/isSafeOptionValue-BEUaZ7UP.js";export{i as clearListCache,c as createMcpServer,f as errorResponse,t as execVis,o as execVisJson,z as isSafeOptionValue,B as isSafePositional,E as isValidRunId,K as isValidTaskId,p as listVisJson,x as okResponse,a as okStructuredResponse,d as registerAdvisoryStatus,l as registerAllTools,R as registerAudit,V as registerCacheHash,T as registerCacheWhy,v as registerDescribeProject,C as registerDescribeTemplate,b as registerFmt,y as registerGetRunLogs,I as registerLint,M as registerListProjects,G as registerListRuns,O as registerListTargets,q as registerListTemplates,n as startMcpServer};
@@ -1,4 +1,4 @@
1
- import"./execVis-CInWWszP.js";import"./clearListCache-D-qeI660.js";import"./errorResponse-D1WOFYuT.js";import{readFile as g}from"node:fs/promises";import{createRequire as l}from"node:module";import{resolve as u,dirname as v}from"node:path";import{pathToFileURL as d,fileURLToPath as h}from"node:url";import{McpServer as b}from"@modelcontextprotocol/sdk/server/mcp.js";import{StdioServerTransport as w}from"@modelcontextprotocol/sdk/server/stdio.js";import{findUp as N}from"@visulima/fs";import{registerAdvisoryStatus as I}from"./registerAdvisoryStatus-DnpRlAZ2.js";import{registerAudit as S}from"./registerAudit-ZskmQpJB.js";import{registerCacheHash as y}from"./registerCacheHash-CLFe-S23.js";import{registerCacheWhy as k}from"./registerCacheWhy-DBIgl8ww.js";import{registerDescribeProject as P}from"./registerDescribeProject-zZZrCz2G.js";import{registerDescribeTemplate as R}from"./registerDescribeTemplate-D1DYYNOB.js";import{registerFmt as V}from"./registerFmt-DYE0dqsx.js";import{registerGetRunLogs as _}from"./registerGetRunLogs-CukA12J7.js";import{registerLint as L}from"./registerLint-D_A4H5jb.js";import{registerListProjects as C}from"./registerListProjects-3dPVnYC9.js";import{registerListRuns as T}from"./registerListRuns-BoZ7DRKb.js";import{registerListTargets as j}from"./registerListTargets-95gAK_Bj.js";import{registerListTemplates as M}from"./registerListTemplates-LK8yLlVB.js";import"./isSafeOptionValue-BEUaZ7UP.js";const c="1.0.0-alpha.35",f=r=>{const[e,o=""]=r.split("-",2);return{core:(e??"").split(".").map(t=>Number.parseInt(t,10)||0),pre:o.length>0?o.split("."):[]}},q=(r,e)=>{if(r===void 0)return e===void 0?0:-1;if(e===void 0)return 1;const o=Number.parseInt(r,10),t=Number.parseInt(e,10);return!Number.isNaN(o)&&!Number.isNaN(t)?o-t:r.localeCompare(e)},E=(r,e)=>{if(r.length===0&&e.length>0)return 1;if(r.length>0&&e.length===0)return-1;const o=Math.max(r.length,e.length);for(let t=0;t<o;t+=1){const i=q(r[t],e[t]);if(i!==0)return i}return 0},$=(r,e)=>{const o=f(r),t=f(e);for(let i=0;i<3;i+=1){const s=(o.core[i]??0)-(t.core[i]??0);if(s!==0)return s}return E(o.pre,t.pre)},O=r=>{!r||$(r,c)>=0||process.stderr.write(`[vis-mcp] warning: @visulima/vis ${r} is older than the required ${c}; lint/fmt/audit tools may fail with opaque errors. Upgrade @visulima/vis to >= ${c}.
1
+ import"./execVis-CInWWszP.js";import"./clearListCache-D-qeI660.js";import"./errorResponse-D1WOFYuT.js";import{readFile as g}from"node:fs/promises";import{createRequire as l}from"node:module";import{resolve as u,dirname as v}from"node:path";import{pathToFileURL as d,fileURLToPath as h}from"node:url";import{McpServer as b}from"@modelcontextprotocol/sdk/server/mcp.js";import{StdioServerTransport as w}from"@modelcontextprotocol/sdk/server/stdio.js";import{findUp as N}from"@visulima/fs";import{registerAdvisoryStatus as I}from"./registerAdvisoryStatus-DnpRlAZ2.js";import{registerAudit as S}from"./registerAudit-ZskmQpJB.js";import{registerCacheHash as y}from"./registerCacheHash-BGyhpFep.js";import{registerCacheWhy as k}from"./registerCacheWhy-CGuHRmfC.js";import{registerDescribeProject as P}from"./registerDescribeProject-zZZrCz2G.js";import{registerDescribeTemplate as R}from"./registerDescribeTemplate-D1DYYNOB.js";import{registerFmt as V}from"./registerFmt-DYE0dqsx.js";import{registerGetRunLogs as _}from"./registerGetRunLogs-tcoMohKG.js";import{registerLint as L}from"./registerLint-D0jyTg8L.js";import{registerListProjects as C}from"./registerListProjects-3dPVnYC9.js";import{registerListRuns as T}from"./registerListRuns-DA-dMOsv.js";import{registerListTargets as j}from"./registerListTargets-95gAK_Bj.js";import{registerListTemplates as M}from"./registerListTemplates-LK8yLlVB.js";import"./isSafeOptionValue-BEUaZ7UP.js";const c="1.0.0-alpha.35",f=r=>{const[e,o=""]=r.split("-",2);return{core:(e??"").split(".").map(t=>Number.parseInt(t,10)||0),pre:o.length>0?o.split("."):[]}},q=(r,e)=>{if(r===void 0)return e===void 0?0:-1;if(e===void 0)return 1;const o=Number.parseInt(r,10),t=Number.parseInt(e,10);return!Number.isNaN(o)&&!Number.isNaN(t)?o-t:r.localeCompare(e)},E=(r,e)=>{if(r.length===0&&e.length>0)return 1;if(r.length>0&&e.length===0)return-1;const o=Math.max(r.length,e.length);for(let t=0;t<o;t+=1){const i=q(r[t],e[t]);if(i!==0)return i}return 0},$=(r,e)=>{const o=f(r),t=f(e);for(let i=0;i<3;i+=1){const s=(o.core[i]??0)-(t.core[i]??0);if(s!==0)return s}return E(o.pre,t.pre)},O=r=>{!r||$(r,c)>=0||process.stderr.write(`[vis-mcp] warning: @visulima/vis ${r} is older than the required ${c}; lint/fmt/audit tools may fail with opaque errors. Upgrade @visulima/vis to >= ${c}.
2
2
  `)},A=r=>{const e=process.env.VIS_MCP_VIS_BIN;if(e)return{binPath:u(e)};const o=[{label:r,require:l(d(`${r}/package.json`))},{label:"vis-mcp install location",require:l(import.meta.url)}],t=[];let i,s;for(const{label:a,require:n}of o)try{i=n.resolve("@visulima/vis/package.json"),s=n("@visulima/vis/package.json");break}catch(m){t.push({error:m,label:a})}if(!i||!s){const a=t.at(-1)?.error,n=t.map(m=>m.label).join(", ");throw new Error(`Cannot resolve \`@visulima/vis\` (tried: ${n}). Install it as a workspace dependency, or set VIS_MCP_VIS_BIN to a vis CLI path.`,{cause:a})}const p=typeof s.bin=="string"?s.bin:s.bin?.vis;if(!p)throw new Error("`@visulima/vis` is installed but does not declare a `vis` bin entry — install a current version.");return{binPath:u(v(i),p),version:s.version}},B=async()=>{try{const r=await N("package.json",{cwd:v(h(import.meta.url))});return r?JSON.parse(await g(r,"utf8")).version??"0.0.0":"0.0.0"}catch(r){return process.stderr.write(`[vis-mcp] failed to read package.json: ${r instanceof Error?r.message:String(r)}
3
3
  `),"0.0.0"}},U=(r,e)=>{C(r,e),P(r,e),j(r,e),M(r,e),R(r,e),_(r,e),T(r,e),k(r,e),y(r,e),S(r,e),I(r,e),L(r,e),V(r,e)},F=async r=>{const e=new b({name:"vis",version:await B()}),o={server:e};return U(o,r),{deps:o,server:e}},ur=async()=>{const r=process.env.VIS_MCP_WORKSPACE_ROOT??process.cwd(),{binPath:e,version:o}=A(r);O(o);const t={visBin:e,workspaceRoot:r},{server:i}=await F(t);await i.connect(new w),process.stderr.write(`[vis-mcp] ready (workspace: ${t.workspaceRoot})
4
4
  `)};export{c as MIN_VIS_VERSION,$ as compareVersions,F as createMcpServer,U as registerAllTools,ur as startMcpServer,O as warnIfVisTooOld};
@@ -0,0 +1 @@
1
+ import*as a from"zod";import{execVisJson as c}from"./execVis-CInWWszP.js";import{errorResponse as s,okResponse as d}from"./errorResponse-D1WOFYuT.js";import{isValidTaskId as p,isValidRunId as h}from"./isSafeOptionValue-BEUaZ7UP.js";const f=({server:n},i)=>{n.registerTool("cache_hash",{annotations:{readOnlyHint:!0},description:"Print the recorded hash and per-input hash details for a task — the contributing inputs (command, nodes, runtime, implicitDeps) that produced it. A trace-mode task has no hashDetails; its result carries `trackedFingerprint` instead (the files, env names and missing paths the run tracked).",inputSchema:{runId:a.string().optional().describe("Run ID to inspect (default: latest)"),taskId:a.string().describe('Task ID like "@my/app:build"')}},async({runId:e,taskId:r})=>{if(!p(r))return s(new Error(`Invalid taskId "${r}". Expected "<project>:<target>".`));if(e!==void 0&&!h(e))return s(new Error(`Invalid runId "${e}". Expected filesystem-safe slug ([A-Za-z0-9_.-]).`));try{const t=["cache","hash",r,"--format=json"];e&&t.push("--run",e);const o=await c(i.visBin,t,{cwd:i.workspaceRoot});return d(o)}catch(t){return s(t)}})};export{f as registerCacheHash};
@@ -0,0 +1 @@
1
+ import*as i from"zod";import{execVisJson as h}from"./execVis-CInWWszP.js";import{errorResponse as a,okResponse as c}from"./errorResponse-D1WOFYuT.js";import{isValidTaskId as d,isValidRunId as p}from"./isSafeOptionValue-BEUaZ7UP.js";const f=({server:n},r)=>{n.registerTool("cache_why",{annotations:{readOnlyHint:!0},description:"Explain why a task's cache hash rotated between runs. When the task has hashDetails (command, nodes, runtime, implicitDeps), diffs them against the previous run to pinpoint what changed. A trace-mode task has no hashDetails, so the diff is empty and the reasons are in `task.cacheMissReasons` (`{ type, detail }` entries, null when there are none). `task.hashSource` is `declared-fallback` when the run was keyed on its declared inputs.",inputSchema:{runId:i.string().optional().describe("Run ID to inspect (default: latest)"),taskId:i.string().describe('Task ID like "@my/app:build"')}},async({runId:e,taskId:t})=>{if(!d(t))return a(new Error(`Invalid taskId "${t}". Expected "<project>:<target>".`));if(e!==void 0&&!p(e))return a(new Error(`Invalid runId "${e}". Expected filesystem-safe slug ([A-Za-z0-9_.-]).`));try{const s=["cache","why",t,"--format=json"];e&&s.push("--run",e);const o=await h(r.visBin,s,{cwd:r.workspaceRoot});return c(o)}catch(s){return a(s)}})};export{f as registerCacheWhy};
@@ -0,0 +1 @@
1
+ import{readFile as f}from"node:fs/promises";import{join as u}from"@visulima/path";import*as l from"zod";import{errorResponse as e,okResponse as m}from"./errorResponse-D1WOFYuT.js";import{isValidRunId as c}from"./isSafeOptionValue-BEUaZ7UP.js";const R=({server:p},n)=>{p.registerTool("get_run_logs",{annotations:{readOnlyHint:!0},description:"Read a vis run summary from .vis/. Returns the most recent run by default, or a specific run when `runId` is set. Optionally filter to a single task with `taskId`.",inputSchema:{runId:l.string().optional().describe("Run ID (default: latest)"),taskId:l.string().optional().describe('Filter to a single task ID like "@my/app:build"')}},async({runId:r,taskId:o})=>{if(r!==void 0&&!c(r))return e(new Error(`Invalid runId "${r}". Expected filesystem-safe slug ([A-Za-z0-9_.-]).`));const i=r?u(n.workspaceRoot,".vis","runs",`${r}.json`):u(n.workspaceRoot,".vis","last-summary.json");try{const s=await f(i,"utf8"),t=JSON.parse(s);if(o){const a=t.tasks?.find(d=>d.taskId===o);return a?m({runId:t.id??t.runId??r,task:a}):e(new Error(`Task "${o}" not found in run "${t.id??t.runId??r??"(unknown)"}".`))}return m(t)}catch(s){return s.code==="ENOENT"?e(new Error(`No run summary at ${i}. Run a task first to populate it.`)):e(s)}})};export{R as registerGetRunLogs};
@@ -0,0 +1 @@
1
+ import*as e from"zod";import{errorResponse as t}from"./errorResponse-D1WOFYuT.js";import{isSafeOptionValue as f,appendPositionalFiles as h}from"./isSafeOptionValue-BEUaZ7UP.js";import{r as s,f as o,a as p}from"./orchestrator-shared-flcsuwN5.js";const g=e.object({findings:e.array(o),runs:e.array(s)}).catchall(e.unknown()),m={exitCode:e.number(),findings:e.array(o),runs:e.array(s)},w=({server:a},l)=>{a.registerTool("lint",{annotations:{readOnlyHint:!0},description:"Run the vis lint orchestrator in check-only mode via `vis lint --format json`. Auto-detects every installed linter (oxlint, biome, eslint, stylelint, ruff, markdownlint, shellcheck, deno-lint) and returns the merged { findings, runs } payload. The `typecheck` adapter (tsc) is opt-in via `lint.adapters.typecheck.enabled`: it checks the whole project even when `files` is set (skipped when none of `files` is TypeScript), and is never cached. This tool never applies fixes — invoke `vis lint --fix` directly for that.",inputSchema:{files:e.array(e.string()).optional().describe("Restrict the run to these files (relative to the workspace root). Empty/omitted = workspace-wide."),maxWarnings:e.int().nonnegative().optional().describe("Forward `--max-warnings N` to every adapter that supports it."),quiet:e.boolean().optional().describe("Suppress warning-severity findings (errors still flow through)."),since:e.string().optional().describe("Forward `--since <ref>` so only files changed vs `<ref>` are linted."),staged:e.boolean().optional().describe("Forward `--staged` so only files in the git index are linted.")},outputSchema:m},async i=>{const n=["lint","--format","json"];if(i.quiet&&n.push("--quiet"),typeof i.maxWarnings=="number"&&n.push("--max-warnings",String(i.maxWarnings)),i.staged)n.push("--staged");else if(i.since!==void 0&&i.since.length>0){if(!f(i.since))return t(new Error(`Invalid --since value "${i.since}". A leading "-" would be parsed as a CLI flag.`));n.push("--since",i.since)}const r=h(n,i.files);return r!==void 0?t(new Error(r)):p(l,"lint",n,g,(c,d)=>({...c,exitCode:d}))})};export{w as registerLint};
@@ -0,0 +1 @@
1
+ import{readdir as w,stat as g,readFile as k}from"node:fs/promises";import{join as c}from"@visulima/path";import*as T from"zod";import{okResponse as f,errorResponse as m}from"./errorResponse-D1WOFYuT.js";const _=/\.json$/,I=t=>t.status==="failure"||t.status==="failed"||typeof t.exitCode=="number"&&t.exitCode!==0,p=t=>typeof t.stats?.failed=="number"?t.stats.failed:t.tasks?.filter(n=>I(n)).length,S=t=>{if(typeof t.status=="string")return t.status;const n=p(t);if(n!==void 0)return n>0?"failure":"success"},R=({server:t},n)=>{t.registerTool("list_runs",{annotations:{readOnlyHint:!0},description:'List recorded vis runs from `.vis/runs/`, most recent first. Each entry includes the run ID, start timestamp, derived status, task count, and failed-task count — use it to discover run IDs for `get_run_logs`, `cache_hash`, or `cache_why` (e.g. "compare this run to the previous one").',inputSchema:{limit:T.int().positive().max(100).optional().describe("Maximum runs to return (default: 20, newest first).")}},async({limit:h})=>{const o=c(n.workspaceRoot,".vis","runs");let d;try{d=(await w(o)).filter(a=>a.endsWith(".json"))}catch(i){return i.code==="ENOENT"?f({count:0,runs:[]}):m(i)}try{const a=(await Promise.all(d.map(async e=>{try{const r=await g(c(o,e));return{file:e,modifiedMs:r.mtimeMs}}catch{return}}))).filter(e=>e!==void 0).toSorted((e,r)=>r.modifiedMs-e.modifiedMs).slice(0,h??20),l=(await Promise.all(a.map(async({file:e,modifiedMs:r})=>{try{const u=await k(c(o,e),"utf8"),s=JSON.parse(u);return{failedTasks:p(s),modifiedMs:r,runId:s.id??s.runId??e.replace(_,""),startedAt:s.startTime??s.startedAt,status:S(s),taskCount:s.stats?.total??s.tasks?.length}}catch{return}}))).filter(e=>e!==void 0).map(e=>{const{failedTasks:r,runId:u,startedAt:s,status:v,taskCount:y}=e;return{failedTasks:r,runId:u,startedAt:s,status:v,taskCount:y}});return f({count:l.length,runs:l})}catch(i){return m(i)}})};export{R as registerListRuns};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@visulima/vis-mcp",
3
- "version": "1.0.46",
3
+ "version": "2.0.0",
4
4
  "description": "MCP (Model Context Protocol) server for @visulima/vis — exposes vis tooling to AI agents over stdio",
5
5
  "keywords": [
6
6
  "agent",
@@ -60,7 +60,7 @@
60
60
  "zod": "4.6.5"
61
61
  },
62
62
  "peerDependencies": {
63
- "@visulima/vis": "4.3.0"
63
+ "@visulima/vis": "5.0.0"
64
64
  },
65
65
  "engines": {
66
66
  "node": "^22.14.0 || >=24.10.0"
@@ -1 +0,0 @@
1
- import*as o from"zod";import{execVisJson as c}from"./execVis-CInWWszP.js";import{errorResponse as i,okResponse as p}from"./errorResponse-D1WOFYuT.js";import{isValidTaskId as d,isValidRunId as h}from"./isSafeOptionValue-BEUaZ7UP.js";const f=({server:a},s)=>{a.registerTool("cache_hash",{annotations:{readOnlyHint:!0},description:"Print the recorded hash and per-input hash details for a task — the contributing inputs (command, nodes, runtime, implicitDeps) that produced it.",inputSchema:{runId:o.string().optional().describe("Run ID to inspect (default: latest)"),taskId:o.string().describe('Task ID like "@my/app:build"')}},async({runId:e,taskId:t})=>{if(!d(t))return i(new Error(`Invalid taskId "${t}". Expected "<project>:<target>".`));if(e!==void 0&&!h(e))return i(new Error(`Invalid runId "${e}". Expected filesystem-safe slug ([A-Za-z0-9_.-]).`));try{const r=["cache","hash",t,"--format=json"];e&&r.push("--run",e);const n=await c(s.visBin,r,{cwd:s.workspaceRoot});return p(n)}catch(r){return i(r)}})};export{f as registerCacheHash};
@@ -1 +0,0 @@
1
- import*as a from"zod";import{execVisJson as c}from"./execVis-CInWWszP.js";import{errorResponse as s,okResponse as p}from"./errorResponse-D1WOFYuT.js";import{isValidTaskId as h,isValidRunId as d}from"./isSafeOptionValue-BEUaZ7UP.js";const f=({server:o},i)=>{o.registerTool("cache_why",{annotations:{readOnlyHint:!0},description:"Explain why a task's cache hash rotated between runs. Diffs the task's hashDetails (command, nodes, runtime, implicitDeps) against the previous run to pinpoint what changed.",inputSchema:{runId:a.string().optional().describe("Run ID to inspect (default: latest)"),taskId:a.string().describe('Task ID like "@my/app:build"')}},async({runId:e,taskId:r})=>{if(!h(r))return s(new Error(`Invalid taskId "${r}". Expected "<project>:<target>".`));if(e!==void 0&&!d(e))return s(new Error(`Invalid runId "${e}". Expected filesystem-safe slug ([A-Za-z0-9_.-]).`));try{const t=["cache","why",r,"--format=json"];e&&t.push("--run",e);const n=await c(i.visBin,t,{cwd:i.workspaceRoot});return p(n)}catch(t){return s(t)}})};export{f as registerCacheWhy};
@@ -1 +0,0 @@
1
- import{readFile as f}from"node:fs/promises";import{join as u}from"@visulima/path";import*as l from"zod";import{errorResponse as e,okResponse as m}from"./errorResponse-D1WOFYuT.js";import{isValidRunId as c}from"./isSafeOptionValue-BEUaZ7UP.js";const R=({server:p},o)=>{p.registerTool("get_run_logs",{annotations:{readOnlyHint:!0},description:"Read a vis run summary from .vis/. Returns the most recent run by default, or a specific run when `runId` is set. Optionally filter to a single task with `taskId`.",inputSchema:{runId:l.string().optional().describe("Run ID (default: latest)"),taskId:l.string().optional().describe('Filter to a single task ID like "@my/app:build"')}},async({runId:r,taskId:n})=>{if(r!==void 0&&!c(r))return e(new Error(`Invalid runId "${r}". Expected filesystem-safe slug ([A-Za-z0-9_.-]).`));const i=r?u(o.workspaceRoot,".vis","runs",`${r}.json`):u(o.workspaceRoot,".vis","last-summary.json");try{const t=await f(i,"utf8"),s=JSON.parse(t);if(n){const a=s.tasks?.find(d=>d.taskId===n);return a?m({runId:s.runId,task:a}):e(new Error(`Task "${n}" not found in run "${s.runId??"(unknown)"}".`))}return m(s)}catch(t){return t.code==="ENOENT"?e(new Error(`No run summary at ${i}. Run a task first to populate it.`)):e(t)}})};export{R as registerGetRunLogs};
@@ -1 +0,0 @@
1
- import*as e from"zod";import{errorResponse as t}from"./errorResponse-D1WOFYuT.js";import{isSafeOptionValue as f,appendPositionalFiles as g}from"./isSafeOptionValue-BEUaZ7UP.js";import{r as s,f as o,a as h}from"./orchestrator-shared-flcsuwN5.js";const m=e.object({findings:e.array(o),runs:e.array(s)}).catchall(e.unknown()),u={exitCode:e.number(),findings:e.array(o),runs:e.array(s)},w=({server:a},l)=>{a.registerTool("lint",{annotations:{readOnlyHint:!0},description:"Run the vis lint orchestrator in check-only mode via `vis lint --format json`. Auto-detects every installed linter (oxlint, biome, eslint, stylelint, ruff, markdownlint, shellcheck, deno-lint) and returns the merged { findings, runs } payload. This tool never applies fixes — invoke `vis lint --fix` directly for that.",inputSchema:{files:e.array(e.string()).optional().describe("Restrict the run to these files (relative to the workspace root). Empty/omitted = workspace-wide."),maxWarnings:e.int().nonnegative().optional().describe("Forward `--max-warnings N` to every adapter that supports it."),quiet:e.boolean().optional().describe("Suppress warning-severity findings (errors still flow through)."),since:e.string().optional().describe("Forward `--since <ref>` so only files changed vs `<ref>` are linted."),staged:e.boolean().optional().describe("Forward `--staged` so only files in the git index are linted.")},outputSchema:u},async r=>{const n=["lint","--format","json"];if(r.quiet&&n.push("--quiet"),typeof r.maxWarnings=="number"&&n.push("--max-warnings",String(r.maxWarnings)),r.staged)n.push("--staged");else if(r.since!==void 0&&r.since.length>0){if(!f(r.since))return t(new Error(`Invalid --since value "${r.since}". A leading "-" would be parsed as a CLI flag.`));n.push("--since",r.since)}const i=g(n,r.files);return i!==void 0?t(new Error(i)):h(l,"lint",n,m,(d,c)=>({...d,exitCode:c}))})};export{w as registerLint};
@@ -1 +0,0 @@
1
- import{readdir as k,stat as w,readFile as y}from"node:fs/promises";import{join as d}from"@visulima/path";import*as g from"zod";import{okResponse as m,errorResponse as p}from"./errorResponse-D1WOFYuT.js";const _=/\.json$/,I=e=>{if(typeof e.status=="string")return e.status;if(e.tasks)return e.tasks.some(a=>a.status==="failure"||a.status==="failed")?"failure":"success"},R=({server:e},a)=>{e.registerTool("list_runs",{annotations:{readOnlyHint:!0},description:'List recorded vis runs from `.vis/runs/`, most recent first. Each entry includes the run ID, start timestamp, derived status, task count, and failed-task count — use it to discover run IDs for `get_run_logs`, `cache_hash`, or `cache_why` (e.g. "compare this run to the previous one").',inputSchema:{limit:g.int().positive().max(100).optional().describe("Maximum runs to return (default: 20, newest first).")}},async({limit:h})=>{const o=d(a.workspaceRoot,".vis","runs");let l;try{l=(await k(o)).filter(u=>u.endsWith(".json"))}catch(n){return n.code==="ENOENT"?m({count:0,runs:[]}):p(n)}try{const u=(await Promise.all(l.map(async t=>{try{const s=await w(d(o,t));return{file:t,modifiedMs:s.mtimeMs}}catch{return}}))).filter(t=>t!==void 0).toSorted((t,s)=>s.modifiedMs-t.modifiedMs).slice(0,h??20),f=(await Promise.all(u.map(async({file:t,modifiedMs:s})=>{try{const c=await y(d(o,t),"utf8"),r=JSON.parse(c);return{failedTasks:r.tasks?.filter(i=>i.status==="failure"||i.status==="failed").length,modifiedMs:s,runId:r.runId??t.replace(_,""),startedAt:r.startedAt,status:I(r),taskCount:r.tasks?.length}}catch{return}}))).filter(t=>t!==void 0).map(t=>{const{failedTasks:s,runId:c,startedAt:r,status:i,taskCount:v}=t;return{failedTasks:s,runId:c,startedAt:r,status:i,taskCount:v}});return m({count:f.length,runs:f})}catch(n){return p(n)}})};export{R as registerListRuns};