@visulima/vis-mcp 1.0.47 → 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 +497 -0
- package/dist/bin.js +1 -1
- package/dist/index.js +1 -1
- package/dist/packem_shared/{createMcpServer-C4LuWhpp.js → createMcpServer-DBbKrHaN.js} +1 -1
- package/dist/packem_shared/registerCacheHash-BGyhpFep.js +1 -0
- package/dist/packem_shared/registerCacheWhy-CGuHRmfC.js +1 -0
- package/dist/packem_shared/registerGetRunLogs-tcoMohKG.js +1 -0
- package/dist/packem_shared/registerLint-D0jyTg8L.js +1 -0
- package/dist/packem_shared/registerListRuns-DA-dMOsv.js +1 -0
- package/package.json +2 -2
- package/dist/packem_shared/registerCacheHash-CLFe-S23.js +0 -1
- package/dist/packem_shared/registerCacheWhy-DBIgl8ww.js +0 -1
- package/dist/packem_shared/registerGetRunLogs-CukA12J7.js +0 -1
- package/dist/packem_shared/registerLint-D_A4H5jb.js +0 -1
- package/dist/packem_shared/registerListRuns-BoZ7DRKb.js +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,500 @@
|
|
|
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
|
+
|
|
1
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)
|
|
2
499
|
|
|
3
500
|
|
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-
|
|
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-
|
|
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-
|
|
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": "
|
|
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": "
|
|
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};
|