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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (120) hide show
  1. package/CHANGELOG.md +403 -12
  2. package/LICENSE.md +283 -0
  3. package/README.md +254 -9
  4. package/dist/bin.js +9 -146
  5. package/dist/config/index.d.ts +1818 -0
  6. package/dist/config/index.js +2 -0
  7. package/dist/generate/index.d.ts +157 -0
  8. package/dist/generate/index.js +3 -0
  9. package/dist/packem_chunks/applyDefaults.js +336 -0
  10. package/dist/packem_chunks/bin.js +9577 -0
  11. package/dist/packem_chunks/doctor-probe.js +112 -0
  12. package/dist/packem_chunks/fix.js +234 -0
  13. package/dist/packem_chunks/handler.js +99 -0
  14. package/dist/packem_chunks/handler10.js +53 -0
  15. package/dist/packem_chunks/handler11.js +32 -0
  16. package/dist/packem_chunks/handler12.js +100 -0
  17. package/dist/packem_chunks/handler13.js +25 -0
  18. package/dist/packem_chunks/handler14.js +916 -0
  19. package/dist/packem_chunks/handler15.js +206 -0
  20. package/dist/packem_chunks/handler16.js +124 -0
  21. package/dist/packem_chunks/handler17.js +13 -0
  22. package/dist/packem_chunks/handler18.js +106 -0
  23. package/dist/packem_chunks/handler19.js +19 -0
  24. package/dist/packem_chunks/handler2.js +75 -0
  25. package/dist/packem_chunks/handler20.js +29 -0
  26. package/dist/packem_chunks/handler21.js +222 -0
  27. package/dist/packem_chunks/handler22.js +237 -0
  28. package/dist/packem_chunks/handler23.js +101 -0
  29. package/dist/packem_chunks/handler24.js +110 -0
  30. package/dist/packem_chunks/handler25.js +402 -0
  31. package/dist/packem_chunks/handler26.js +13 -0
  32. package/dist/packem_chunks/handler27.js +63 -0
  33. package/dist/packem_chunks/handler28.js +34 -0
  34. package/dist/packem_chunks/handler29.js +458 -0
  35. package/dist/packem_chunks/handler3.js +95 -0
  36. package/dist/packem_chunks/handler30.js +170 -0
  37. package/dist/packem_chunks/handler31.js +530 -0
  38. package/dist/packem_chunks/handler32.js +214 -0
  39. package/dist/packem_chunks/handler33.js +119 -0
  40. package/dist/packem_chunks/handler34.js +630 -0
  41. package/dist/packem_chunks/handler35.js +283 -0
  42. package/dist/packem_chunks/handler36.js +542 -0
  43. package/dist/packem_chunks/handler37.js +762 -0
  44. package/dist/packem_chunks/handler38.js +989 -0
  45. package/dist/packem_chunks/handler39.js +574 -0
  46. package/dist/packem_chunks/handler4.js +90 -0
  47. package/dist/packem_chunks/handler40.js +1685 -0
  48. package/dist/packem_chunks/handler41.js +1088 -0
  49. package/dist/packem_chunks/handler42.js +797 -0
  50. package/dist/packem_chunks/handler43.js +2658 -0
  51. package/dist/packem_chunks/handler44.js +3886 -0
  52. package/dist/packem_chunks/handler45.js +2574 -0
  53. package/dist/packem_chunks/handler46.js +3769 -0
  54. package/dist/packem_chunks/handler47.js +1491 -0
  55. package/dist/packem_chunks/handler5.js +174 -0
  56. package/dist/packem_chunks/handler6.js +95 -0
  57. package/dist/packem_chunks/handler7.js +115 -0
  58. package/dist/packem_chunks/handler8.js +12 -0
  59. package/dist/packem_chunks/handler9.js +29 -0
  60. package/dist/packem_chunks/heal-accept.js +522 -0
  61. package/dist/packem_chunks/heal.js +673 -0
  62. package/dist/packem_chunks/index.js +873 -0
  63. package/dist/packem_chunks/loader.js +23 -0
  64. package/dist/packem_shared/VisUpdateApp-D-Yz_wvg.js +1316 -0
  65. package/dist/packem_shared/_commonjsHelpers-BqLXS_qQ.js +5 -0
  66. package/dist/packem_shared/ai-analysis-CHeB1joD.js +367 -0
  67. package/dist/packem_shared/ai-cache-Be_jexe4.js +142 -0
  68. package/dist/packem_shared/ai-fix-B9iQVcD2.js +379 -0
  69. package/dist/packem_shared/cache-directory-2qvs4goY.js +98 -0
  70. package/dist/packem_shared/catalog-BJTtyi-O.js +1371 -0
  71. package/dist/packem_shared/dependency-scan-A0KSklpG.js +188 -0
  72. package/dist/packem_shared/docker-2iZzc280.js +181 -0
  73. package/dist/packem_shared/failure-log-Cz3Z4SKL.js +100 -0
  74. package/dist/packem_shared/flakiness-goTxXuCX.js +180 -0
  75. package/dist/packem_shared/otel-DCvqCTz_.js +158 -0
  76. package/dist/packem_shared/otelPlugin-DFaLDvJf.js +3 -0
  77. package/dist/packem_shared/registry-CbqXI0rc.js +272 -0
  78. package/dist/packem_shared/run-summary-utils-PVMl4aIh.js +130 -0
  79. package/dist/packem_shared/runtime-check-Cobi3p6l.js +127 -0
  80. package/dist/packem_shared/selectors-SM69TfqC.js +194 -0
  81. package/dist/packem_shared/symbols-Ta7g2nU-.js +14 -0
  82. package/dist/packem_shared/toolchain-BdZd9eBi.js +975 -0
  83. package/dist/packem_shared/typosquats-C-bCh3PX.js +1210 -0
  84. package/dist/packem_shared/use-measured-height-CNP0vT4M.js +20 -0
  85. package/dist/packem_shared/utils-CthVdBPS.js +40 -0
  86. package/dist/packem_shared/xxh3-Ck8mXNg1.js +239 -0
  87. package/index.js +773 -0
  88. package/package.json +82 -21
  89. package/schemas/project.schema.json +420 -0
  90. package/schemas/vis-config.schema.json +501 -0
  91. package/skills/vis/SKILL.md +96 -0
  92. package/templates/buildkite-ci/.buildkite/pipeline.yml.tera +85 -0
  93. package/templates/buildkite-ci/template.yml +20 -0
  94. package/dist/ai-analysis.d.ts +0 -40
  95. package/dist/ai-cache.d.ts +0 -21
  96. package/dist/bin.d.ts +0 -1
  97. package/dist/catalog.d.ts +0 -110
  98. package/dist/commands/affected.d.ts +0 -3
  99. package/dist/commands/ai.d.ts +0 -3
  100. package/dist/commands/analyze.d.ts +0 -3
  101. package/dist/commands/check.d.ts +0 -3
  102. package/dist/commands/graph.d.ts +0 -3
  103. package/dist/commands/hook/constants.d.ts +0 -8
  104. package/dist/commands/hook/index.d.ts +0 -3
  105. package/dist/commands/hook/install.d.ts +0 -7
  106. package/dist/commands/hook/migrate.d.ts +0 -27
  107. package/dist/commands/hook/uninstall.d.ts +0 -3
  108. package/dist/commands/migrate/constants.d.ts +0 -12
  109. package/dist/commands/migrate/deps.d.ts +0 -32
  110. package/dist/commands/migrate/index.d.ts +0 -3
  111. package/dist/commands/migrate/json.d.ts +0 -20
  112. package/dist/commands/migrate/lint-staged.d.ts +0 -62
  113. package/dist/commands/migrate/types.d.ts +0 -20
  114. package/dist/commands/run.d.ts +0 -3
  115. package/dist/commands/staged.d.ts +0 -3
  116. package/dist/commands/update.d.ts +0 -3
  117. package/dist/config.d.ts +0 -40
  118. package/dist/config.js +0 -1
  119. package/dist/package-manager.d.ts +0 -23
  120. package/dist/workspace.d.ts +0 -58
@@ -0,0 +1,458 @@
1
+ import { createRequire as __cjs_createRequire } from "node:module";
2
+
3
+ const __cjs_require = __cjs_createRequire(import.meta.url);
4
+
5
+ const __cjs_getProcess = typeof globalThis !== "undefined" && typeof globalThis.process !== "undefined" ? globalThis.process : process;
6
+
7
+ const __cjs_getBuiltinModule = (module) => {
8
+ // Check if we're in Node.js and version supports getBuiltinModule
9
+ if (typeof __cjs_getProcess !== "undefined" && __cjs_getProcess.versions && __cjs_getProcess.versions.node) {
10
+ const [major, minor] = __cjs_getProcess.versions.node.split(".").map(Number);
11
+ // Node.js 20.16.0+ and 22.3.0+
12
+ if (major > 22 || (major === 22 && minor >= 3) || (major === 20 && minor >= 16)) {
13
+ return __cjs_getProcess.getBuiltinModule(module);
14
+ }
15
+ }
16
+ // Fallback to createRequire
17
+ return __cjs_require(module);
18
+ };
19
+
20
+ const {
21
+ createInterface
22
+ } = __cjs_getBuiltinModule("node:readline");
23
+ import { green, dim, red, yellow } from '@visulima/colorize';
24
+ import { readJsonSync, writeJsonSync } from '@visulima/fs';
25
+ import { findPackageManagerSync } from '@visulima/package';
26
+ import { join } from '@visulima/path';
27
+ import { coerce } from 'semver';
28
+ import { r as resolveInstaller, F as runAdd, a as buildSocketOptions, p as pail, f as fetchSocketReports, d as discoverWorkspace, x as runInstall, t as findAcceptedRisk, G as formatReportSummary, H as scoreLabel, I as formatAcceptedRiskSnippet, J as getFullPackageName, j as scoreColor, D as DEFAULT_LOW_SCORE_THRESHOLD } from './bin.js';
29
+ import { r as runTyposquatCheck } from '../packem_shared/typosquats-C-bCh3PX.js';
30
+ import { r as readCatalogs } from '../packem_shared/catalog-BJTtyi-O.js';
31
+ import { p as parsePackageArgument, t as toStringArray } from '../packem_shared/utils-CthVdBPS.js';
32
+
33
+ const buildCatalogRef = (catalogName) => catalogName === "default" ? "catalog:" : `catalog:${catalogName}`;
34
+ const labelForCatalog = (catalogName) => catalogName === "default" ? "default catalog" : `catalog "${catalogName}"`;
35
+ const resolveFromCatalogs = (name, catalogs) => {
36
+ const matchedCatalogs = [];
37
+ for (const [key, deps] of catalogs) {
38
+ if (key.includes(":")) {
39
+ continue;
40
+ }
41
+ if (deps.has(name)) {
42
+ matchedCatalogs.push(key);
43
+ }
44
+ }
45
+ if (matchedCatalogs.length === 0) {
46
+ return void 0;
47
+ }
48
+ if (matchedCatalogs.length === 1) {
49
+ const [only] = matchedCatalogs;
50
+ return { source: labelForCatalog(only), spec: buildCatalogRef(only) };
51
+ }
52
+ const preferred = matchedCatalogs.find((c) => c === "default") ?? matchedCatalogs[0];
53
+ const others = matchedCatalogs.filter((c) => c !== preferred);
54
+ return {
55
+ candidates: [...matchedCatalogs],
56
+ conflict: true,
57
+ source: `${labelForCatalog(preferred)} (also in: ${others.map(labelForCatalog).join(", ")})`,
58
+ spec: buildCatalogRef(preferred)
59
+ };
60
+ };
61
+ const resolveFromSiblings = (name, catalogs) => {
62
+ const tally = /* @__PURE__ */ new Map();
63
+ for (const [key, deps] of catalogs) {
64
+ if (!key.includes(":")) {
65
+ continue;
66
+ }
67
+ const range = deps.get(name);
68
+ if (range !== void 0) {
69
+ tally.set(range, (tally.get(range) ?? 0) + 1);
70
+ }
71
+ }
72
+ if (tally.size === 0) {
73
+ return void 0;
74
+ }
75
+ const entries = [...tally.entries()];
76
+ const total = entries.reduce((a, [, count]) => a + count, 0);
77
+ if (entries.length === 1) {
78
+ const [[range]] = entries;
79
+ return {
80
+ source: `siblings (${String(total)} pkg${total === 1 ? "" : "s"} on ${range})`,
81
+ spec: range
82
+ };
83
+ }
84
+ const sorted = [...entries].sort((a, b) => b[1] - a[1]);
85
+ const [chosen, chosenCount] = sorted[0];
86
+ const others = sorted.slice(1).map(([range, count]) => `${range} (×${String(count)})`);
87
+ return {
88
+ candidates: sorted.map(([range]) => range),
89
+ conflict: true,
90
+ source: `siblings (most common: ${chosen} ×${String(chosenCount)}; conflicts: ${others.join(", ")})`,
91
+ spec: chosen
92
+ };
93
+ };
94
+ const conformToCatalog = (name, catalogs) => {
95
+ const fromCatalog = resolveFromCatalogs(name, catalogs);
96
+ if (fromCatalog) {
97
+ return fromCatalog;
98
+ }
99
+ return resolveFromSiblings(name, catalogs);
100
+ };
101
+
102
+ const resolveLatestVersions = async (packageNames, timeoutMs = 1e4) => {
103
+ const results = /* @__PURE__ */ new Map();
104
+ const controller = new AbortController();
105
+ const timeout = setTimeout(() => {
106
+ controller.abort();
107
+ }, timeoutMs);
108
+ try {
109
+ const fetches = packageNames.map(async (name) => {
110
+ try {
111
+ const response = await fetch(`https://registry.npmjs.org/${name}/latest`, {
112
+ headers: { Accept: "application/json" },
113
+ signal: controller.signal
114
+ });
115
+ if (response.ok) {
116
+ const data = await response.json();
117
+ if (data.version) {
118
+ results.set(name, data.version);
119
+ }
120
+ }
121
+ } catch {
122
+ }
123
+ });
124
+ await Promise.all(fetches);
125
+ } finally {
126
+ clearTimeout(timeout);
127
+ }
128
+ return results;
129
+ };
130
+ const displaySecurityReports = (reports, minimumScore, acceptedRisks) => {
131
+ const lowScorePackages = [];
132
+ for (const report of reports.values()) {
133
+ const { overall } = report.score;
134
+ const color = scoreColor(overall);
135
+ const pct = `${String(Math.round(overall * 100))}%`;
136
+ const alertCount = report.alerts.length;
137
+ const fullName = getFullPackageName(report);
138
+ const accepted = findAcceptedRisk(fullName, report.version, acceptedRisks);
139
+ const colorFunction = color === "red" ? red : color === "yellow" ? yellow : green;
140
+ if (accepted) {
141
+ pail.info(` ${colorFunction(pct)} ${formatReportSummary(report)} ${dim(`[accepted: ${accepted.reason}]`)}`);
142
+ } else {
143
+ pail.info(` ${colorFunction(pct)} ${formatReportSummary(report)}`);
144
+ }
145
+ if (alertCount > 0) {
146
+ const critHigh = report.alerts.filter((a) => a.severity === "critical" || a.severity === "high").length;
147
+ if (critHigh > 0) {
148
+ pail.warn(` ${String(critHigh)} critical/high alert${critHigh === 1 ? "" : "s"}`);
149
+ }
150
+ }
151
+ if (overall < minimumScore && !accepted) {
152
+ lowScorePackages.push(report);
153
+ }
154
+ }
155
+ return lowScorePackages;
156
+ };
157
+ const confirmLowScorePackages = async (lowScorePackages, minimumScore) => {
158
+ const rl = createInterface({ input: process.stdin, output: process.stdout });
159
+ const ask = (question) => new Promise((resolve) => {
160
+ rl.question(question, (answer2) => {
161
+ resolve(answer2.trim());
162
+ });
163
+ });
164
+ const pct = String(Math.round(minimumScore * 100));
165
+ pail.warn("");
166
+ pail.warn(`${String(lowScorePackages.length)} package${lowScorePackages.length === 1 ? "" : "s"} scored below the minimum threshold (${pct}%):`);
167
+ for (const report of lowScorePackages) {
168
+ const name = getFullPackageName(report);
169
+ const score = `${String(Math.round(report.score.overall * 100))}%`;
170
+ pail.warn(` • ${name}@${report.version} — score: ${score} (${scoreLabel(report.score.overall)})`);
171
+ }
172
+ pail.warn("");
173
+ const answer = await ask("Continue adding these packages? [y/N] ");
174
+ if (answer.toLowerCase() !== "y" && answer.toLowerCase() !== "yes") {
175
+ rl.close();
176
+ return false;
177
+ }
178
+ const rememberAnswer = await ask("Remember this decision? (prints config snippet) [y/N] ");
179
+ rl.close();
180
+ if (rememberAnswer.toLowerCase() === "y" || rememberAnswer.toLowerCase() === "yes") {
181
+ pail.notice("");
182
+ pail.notice("Add the following to security.socket.acceptedRisks in vis.config.ts:");
183
+ pail.notice("");
184
+ for (const report of lowScorePackages) {
185
+ const fullName = getFullPackageName(report);
186
+ const snippet = formatAcceptedRiskSnippet(fullName, report.version, report.score.overall, "Reviewed and accepted");
187
+ pail.notice(snippet);
188
+ }
189
+ pail.notice("");
190
+ }
191
+ return true;
192
+ };
193
+ const runSocketPreCheck = async (packages, socketOptions, minimumScore, acceptedRisks) => {
194
+ const parsed = packages.map(parsePackageArgument);
195
+ const coercedSpecs = /* @__PURE__ */ new Map();
196
+ for (const p of parsed) {
197
+ if (p.versionSpec) {
198
+ const coerced = coerce(p.versionSpec);
199
+ if (coerced) {
200
+ coercedSpecs.set(p.name, coerced.version);
201
+ }
202
+ }
203
+ }
204
+ const needsResolution = parsed.filter((p) => !coercedSpecs.has(p.name)).map((p) => p.name);
205
+ const resolvedVersions = needsResolution.length > 0 ? await resolveLatestVersions(needsResolution) : /* @__PURE__ */ new Map();
206
+ const lookupPackages = [];
207
+ for (const p of parsed) {
208
+ const version = coercedSpecs.get(p.name) ?? resolvedVersions.get(p.name);
209
+ if (version) {
210
+ lookupPackages.push({ name: p.name, version });
211
+ }
212
+ }
213
+ if (lookupPackages.length === 0) {
214
+ return true;
215
+ }
216
+ pail.info("");
217
+ pail.info("Socket.dev security check:");
218
+ const reports = await fetchSocketReports(lookupPackages, socketOptions);
219
+ if (reports.size === 0) {
220
+ pail.info(" Could not fetch security data. Proceeding.");
221
+ return true;
222
+ }
223
+ const lowScorePackages = displaySecurityReports(reports, minimumScore, acceptedRisks);
224
+ if (lowScorePackages.length === 0) {
225
+ pail.info("");
226
+ return true;
227
+ }
228
+ if (!process.stdin.isTTY) {
229
+ pail.warn(
230
+ `Aborting: ${String(lowScorePackages.length)} package${lowScorePackages.length === 1 ? "" : "s"} below minimum score. Use --no-socket-check to skip.`
231
+ );
232
+ return false;
233
+ }
234
+ return confirmLowScorePackages(lowScorePackages, minimumScore);
235
+ };
236
+ const SIBLING_SECTIONS = ["dependencies", "devDependencies", "peerDependencies", "optionalDependencies"];
237
+ const pickDepSection = (options) => {
238
+ if (options.savePeer) {
239
+ return "peerDependencies";
240
+ }
241
+ if (options.saveOptional) {
242
+ return "optionalDependencies";
243
+ }
244
+ if (options.saveDev) {
245
+ return "devDependencies";
246
+ }
247
+ return "dependencies";
248
+ };
249
+ const applyExactPrefix = (spec, exact) => {
250
+ if (spec.startsWith("catalog:")) {
251
+ return spec;
252
+ }
253
+ if (!exact) {
254
+ return spec;
255
+ }
256
+ return spec.replace(/^[\^~]/, "");
257
+ };
258
+ const planConformedSpecs = async (packages, catalogs) => {
259
+ const slots = [];
260
+ for (const argument of packages) {
261
+ const { name, versionSpec } = parsePackageArgument(argument);
262
+ if (!name) {
263
+ continue;
264
+ }
265
+ if (versionSpec !== void 0) {
266
+ slots.push({ explicit: versionSpec, name });
267
+ continue;
268
+ }
269
+ const conformed = conformToCatalog(name, catalogs);
270
+ if (conformed) {
271
+ if (conformed.conflict) {
272
+ pail.warn(`${name}: ambiguous constraint — picking ${conformed.spec} (${conformed.source}). Pass ${name}@<version> to override.`);
273
+ }
274
+ slots.push({ entry: { name, source: conformed.source, spec: conformed.spec }, kind: "resolved", name });
275
+ continue;
276
+ }
277
+ slots.push({ kind: "missing", name });
278
+ }
279
+ const missingNames = slots.filter((s) => "kind" in s && s.kind === "missing").map((s) => s.name);
280
+ const latest = missingNames.length > 0 ? await resolveLatestVersions(missingNames) : /* @__PURE__ */ new Map();
281
+ return slots.map((slot) => {
282
+ if ("explicit" in slot) {
283
+ return { name: slot.name, source: "explicit", spec: slot.explicit };
284
+ }
285
+ if (slot.kind === "resolved") {
286
+ return slot.entry;
287
+ }
288
+ const version = latest.get(slot.name);
289
+ if (version === void 0) {
290
+ throw new Error(`--to: cannot resolve a version for "${slot.name}" (not in any catalog or sibling, and registry lookup failed). Pass ${slot.name}@<version> explicitly.`);
291
+ }
292
+ const spec = `^${version}`;
293
+ pail.info(`${slot.name}: no existing constraint — using registry latest (${spec}). Add to a catalog to share this version across workspace packages.`);
294
+ return { name: slot.name, source: "registry latest", spec };
295
+ });
296
+ };
297
+ const applyPlannedSpecsToPackageJson = (pkgJson, planned, section, exact) => {
298
+ for (const { name, spec } of planned) {
299
+ const finalSpec = applyExactPrefix(spec, exact);
300
+ for (const otherSection of SIBLING_SECTIONS) {
301
+ if (otherSection === section) {
302
+ continue;
303
+ }
304
+ const block2 = pkgJson[otherSection];
305
+ if (block2?.[name] !== void 0) {
306
+ delete block2[name];
307
+ if (Object.keys(block2).length === 0) {
308
+ delete pkgJson[otherSection];
309
+ }
310
+ }
311
+ }
312
+ let block = pkgJson[section];
313
+ if (block === void 0) {
314
+ block = {};
315
+ pkgJson[section] = block;
316
+ }
317
+ block[name] = finalSpec;
318
+ }
319
+ };
320
+ const applyConformedAdd = async ({
321
+ ignoreScripts,
322
+ logger,
323
+ options,
324
+ packages,
325
+ pm,
326
+ target,
327
+ visConfig,
328
+ workspaceRoot
329
+ }) => {
330
+ const { workspace } = discoverWorkspace(workspaceRoot, visConfig ?? {});
331
+ const project = workspace.projects[target];
332
+ if (!project) {
333
+ const available = Object.keys(workspace.projects).sort();
334
+ throw new Error(
335
+ `--to: workspace package "${target}" not found. Available: ${available.length > 0 ? available.slice(0, 10).join(", ") : "(none)"}${available.length > 10 ? `, ... (${String(available.length - 10)} more)` : ""}.`
336
+ );
337
+ }
338
+ const targetPkgPath = join(workspaceRoot, project.root, "package.json");
339
+ const { packageManager } = findPackageManagerSync(workspaceRoot);
340
+ const catalogs = readCatalogs(workspaceRoot, packageManager);
341
+ const section = pickDepSection(options);
342
+ const exact = options.exact ?? false;
343
+ const planned = await planConformedSpecs(packages, catalogs);
344
+ if (planned.length === 0) {
345
+ return 0;
346
+ }
347
+ const pkgJson = readJsonSync(targetPkgPath);
348
+ applyPlannedSpecsToPackageJson(pkgJson, planned, section, exact);
349
+ writeJsonSync(targetPkgPath, pkgJson, { detectIndent: true, overwrite: true });
350
+ for (const entry of planned) {
351
+ const finalSpec = applyExactPrefix(entry.spec, exact);
352
+ pail.info(`${green("+")} ${entry.name}@${finalSpec} → ${target}/${section} (${dim(entry.source)})`);
353
+ }
354
+ return runInstall(
355
+ pm,
356
+ {
357
+ dev: false,
358
+ filter: [],
359
+ force: false,
360
+ frozenLockfile: false,
361
+ ignoreScripts,
362
+ lockfileOnly: false,
363
+ noOptional: false,
364
+ offline: false,
365
+ prod: false,
366
+ recursive: false,
367
+ silent: false,
368
+ workspaceRoot: false
369
+ },
370
+ workspaceRoot,
371
+ logger
372
+ );
373
+ };
374
+ const execute = async ({ argument, logger, options, visConfig, workspaceRoot: wsRoot }) => {
375
+ let packages = argument;
376
+ if (!packages || packages.length === 0) {
377
+ throw new Error("No packages specified. Usage: vis add <packages...>");
378
+ }
379
+ if (!options.noTyposquatCheck) {
380
+ const parsed = packages.map((p) => parsePackageArgument(p));
381
+ const result = await runTyposquatCheck(
382
+ parsed.map((p) => p.name),
383
+ visConfig?.security?.typosquatAllowlist
384
+ );
385
+ if (!result.ok) {
386
+ process.exitCode = 1;
387
+ return;
388
+ }
389
+ packages = parsed.map((p, i) => {
390
+ const corrected = result.packages[i];
391
+ if (corrected !== p.name) {
392
+ return p.versionSpec ? `${corrected}@${p.versionSpec}` : corrected ?? "";
393
+ }
394
+ return packages[i] ?? "";
395
+ });
396
+ }
397
+ if (!options.noSocketCheck) {
398
+ const socketOptions = buildSocketOptions(visConfig?.security?.socket);
399
+ if (socketOptions) {
400
+ const minimumScore = socketOptions.minimumScore ?? DEFAULT_LOW_SCORE_THRESHOLD;
401
+ const shouldContinue = await runSocketPreCheck(packages, socketOptions, minimumScore, visConfig?.security?.socket?.acceptedRisks);
402
+ if (!shouldContinue) {
403
+ process.exitCode = 1;
404
+ return;
405
+ }
406
+ }
407
+ }
408
+ const cwd = process.cwd();
409
+ const pm = resolveInstaller(wsRoot ?? cwd, { configBackend: visConfig?.install?.backend });
410
+ const ignoreScripts = !options.runScripts;
411
+ if (options.to) {
412
+ if (options.global || options.workspaceRoot) {
413
+ throw new Error("--to is incompatible with --global / --workspace-root.");
414
+ }
415
+ if (options.filter && toStringArray(options.filter).length > 0) {
416
+ throw new Error("--to and --filter are mutually exclusive — --to already targets one package.");
417
+ }
418
+ if (!wsRoot) {
419
+ throw new Error("--to requires a monorepo workspace. Run from inside a pnpm/bun/yarn/npm workspace.");
420
+ }
421
+ const code2 = await applyConformedAdd({
422
+ ignoreScripts,
423
+ logger,
424
+ options,
425
+ packages,
426
+ pm,
427
+ target: options.to,
428
+ visConfig,
429
+ workspaceRoot: wsRoot
430
+ });
431
+ if (code2 !== 0) {
432
+ process.exitCode = code2;
433
+ }
434
+ return;
435
+ }
436
+ const code = runAdd(
437
+ pm,
438
+ {
439
+ exact: options.exact || false,
440
+ filter: toStringArray(options.filter),
441
+ global: options.global || false,
442
+ optional: options.saveOptional || false,
443
+ packages,
444
+ peer: options.savePeer || false,
445
+ saveDev: options.saveDev || false,
446
+ workspace: options.workspace || false,
447
+ workspaceRoot: options.workspaceRoot || false
448
+ },
449
+ cwd,
450
+ logger,
451
+ { ignoreScripts }
452
+ );
453
+ if (code !== 0) {
454
+ process.exitCode = code;
455
+ }
456
+ };
457
+
458
+ export { execute as default };
@@ -0,0 +1,95 @@
1
+ import { findPackageManagerSync } from '@visulima/package';
2
+ import { v as validateAnalysisType, r as runAiAnalysis, f as formatAiAnalysis } from '../packem_shared/ai-analysis-CHeB1joD.js';
3
+ import { f as fetchSocketReports, a as buildSocketOptions } from './bin.js';
4
+ import { r as readCatalogs, f as fetchPackageVersions, p as parseVersion, a as fetchVulnerabilities, g as getUpdateType, e as extractPrefix } from '../packem_shared/catalog-BJTtyi-O.js';
5
+
6
+ const VERSION_PREFIX_REGEX = /^[\^~>=<]+/;
7
+ const execute = async ({ argument, logger, options, visConfig, workspaceRoot: wsRoot }) => {
8
+ if (!wsRoot) {
9
+ throw new Error("Could not determine workspace root. Run this command inside a monorepo.");
10
+ }
11
+ const positionalArguments = argument;
12
+ const packageName = positionalArguments[0];
13
+ if (!packageName) {
14
+ throw new Error("Package name is required. Usage: vis analyze <package> [version]");
15
+ }
16
+ const targetVersionArgument = positionalArguments[1];
17
+ const { packageManager } = findPackageManagerSync(wsRoot);
18
+ let currentRange;
19
+ let catalogName = "default";
20
+ const catalogs = readCatalogs(wsRoot, packageManager);
21
+ for (const [name, deps] of catalogs) {
22
+ const range = deps.get(packageName);
23
+ if (range) {
24
+ currentRange = range;
25
+ catalogName = name;
26
+ break;
27
+ }
28
+ }
29
+ if (!currentRange) {
30
+ throw new Error(`Package "${packageName}" not found in any catalog or package.json. Make sure it exists in your workspace dependencies.`);
31
+ }
32
+ let targetVersion;
33
+ if (targetVersionArgument) {
34
+ targetVersion = targetVersionArgument;
35
+ } else {
36
+ logger.info(`Fetching latest version for ${packageName}...
37
+ `);
38
+ const info = await fetchPackageVersions(packageName);
39
+ if (!info.latest) {
40
+ throw new Error(`Could not determine latest version for "${packageName}".`);
41
+ }
42
+ targetVersion = info.latest;
43
+ }
44
+ const current = parseVersion(currentRange);
45
+ const target = parseVersion(targetVersion);
46
+ if (!current || !target) {
47
+ throw new Error(`Could not parse versions: current="${currentRange}", target="${targetVersion}".`);
48
+ }
49
+ const updateType = getUpdateType(current, target);
50
+ if (updateType === "none") {
51
+ logger.info(`${packageName} is already at ${targetVersion}. Nothing to analyze.`);
52
+ return;
53
+ }
54
+ const prefix = extractPrefix(currentRange);
55
+ const entry = {
56
+ catalogName,
57
+ currentRange,
58
+ newRange: `${prefix}${targetVersion}`,
59
+ packageName,
60
+ targetVersion,
61
+ updateType
62
+ };
63
+ const analysisType = validateAnalysisType(options.aiType ?? "impact");
64
+ if (analysisType === "security" || options.security) {
65
+ logger.info("Checking for known vulnerabilities...\n");
66
+ const version = currentRange.replace(VERSION_PREFIX_REGEX, "");
67
+ const vulnMap = await fetchVulnerabilities([{ name: packageName, version }]);
68
+ const vulns = vulnMap.get(packageName);
69
+ if (vulns && vulns.length > 0) {
70
+ entry.vulnerabilities = vulns;
71
+ }
72
+ const socketOptions = buildSocketOptions(visConfig?.security?.socket);
73
+ if (socketOptions) {
74
+ const reports = await fetchSocketReports([{ name: packageName, version }], socketOptions);
75
+ const report = reports.get(`${packageName}@${version}`);
76
+ if (report) {
77
+ entry.socketReport = {
78
+ alerts: report.alerts,
79
+ license: report.license,
80
+ score: report.score
81
+ };
82
+ }
83
+ }
84
+ }
85
+ const result = await runAiAnalysis([entry], logger, visConfig?.ai, analysisType);
86
+ const format = options.format ?? "table";
87
+ if (format === "json") {
88
+ process.stdout.write(`${JSON.stringify(result, void 0, 2)}
89
+ `);
90
+ } else {
91
+ logger.info(formatAiAnalysis(result));
92
+ }
93
+ };
94
+
95
+ export { execute as default };