@vibgrate/cli 0.1.1

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.
@@ -0,0 +1,29 @@
1
+ import {
2
+ runScan,
3
+ writeJsonFile
4
+ } from "./chunk-DLRBJYO6.js";
5
+
6
+ // src/commands/baseline.ts
7
+ import * as path from "path";
8
+ import { Command } from "commander";
9
+ import chalk from "chalk";
10
+ async function runBaseline(rootDir) {
11
+ console.log(chalk.dim("Creating baseline..."));
12
+ const artifact = await runScan(rootDir, {
13
+ format: "text",
14
+ concurrency: 8
15
+ });
16
+ const baselinePath = path.join(rootDir, ".vibgrate", "baseline.json");
17
+ await writeJsonFile(baselinePath, artifact);
18
+ console.log(chalk.green("\u2714") + ` Baseline saved to ${chalk.bold(".vibgrate/baseline.json")}`);
19
+ console.log(chalk.dim(` Baseline score: ${artifact.drift.score}/100`));
20
+ }
21
+ var baselineCommand = new Command("baseline").description("Create a drift baseline snapshot").argument("[path]", "Path to baseline", ".").action(async (targetPath) => {
22
+ const rootDir = path.resolve(targetPath);
23
+ await runBaseline(rootDir);
24
+ });
25
+
26
+ export {
27
+ runBaseline,
28
+ baselineCommand
29
+ };
package/dist/cli.d.ts ADDED
@@ -0,0 +1 @@
1
+ #!/usr/bin/env node
package/dist/cli.js ADDED
@@ -0,0 +1,377 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ formatMarkdown
4
+ } from "./chunk-AMOJCCF5.js";
5
+ import {
6
+ baselineCommand
7
+ } from "./chunk-OHAVLM6P.js";
8
+ import {
9
+ VERSION,
10
+ ensureDir,
11
+ formatText,
12
+ pathExists,
13
+ readJsonFile,
14
+ readTextFile,
15
+ scanCommand,
16
+ writeDefaultConfig,
17
+ writeTextFile
18
+ } from "./chunk-DLRBJYO6.js";
19
+
20
+ // src/cli.ts
21
+ import { Command as Command6 } from "commander";
22
+ import chalk6 from "chalk";
23
+
24
+ // src/commands/init.ts
25
+ import * as path from "path";
26
+ import { Command } from "commander";
27
+ import chalk from "chalk";
28
+ var initCommand = new Command("init").description("Initialize vibgrate in a project").argument("[path]", "Path to initialize", ".").option("--baseline", "Create initial baseline after init").option("--yes", "Skip confirmation prompts").action(async (targetPath, opts) => {
29
+ const rootDir = path.resolve(targetPath);
30
+ const vibgrateDir = path.join(rootDir, ".vibgrate");
31
+ await ensureDir(vibgrateDir);
32
+ console.log(chalk.green("\u2714") + ` Created ${chalk.bold(".vibgrate/")} directory`);
33
+ const configPath = path.join(rootDir, "vibgrate.config.ts");
34
+ if (await pathExists(configPath)) {
35
+ console.log(chalk.dim(" vibgrate.config.ts already exists, skipping"));
36
+ } else {
37
+ await writeDefaultConfig(rootDir);
38
+ console.log(chalk.green("\u2714") + ` Created ${chalk.bold("vibgrate.config.ts")}`);
39
+ }
40
+ if (opts.baseline) {
41
+ const { runBaseline } = await import("./baseline-AENFLFQT.js");
42
+ await runBaseline(rootDir);
43
+ }
44
+ console.log("");
45
+ console.log(chalk.bold("Next steps:"));
46
+ console.log(` ${chalk.cyan("vibgrate scan .")} Scan for upgrade drift`);
47
+ console.log(` ${chalk.cyan("vibgrate baseline .")} Create a drift baseline`);
48
+ console.log("");
49
+ });
50
+
51
+ // src/commands/report.ts
52
+ import * as path2 from "path";
53
+ import { Command as Command2 } from "commander";
54
+ import chalk2 from "chalk";
55
+ var reportCommand = new Command2("report").description("Generate a drift report from a scan artifact").option("--in <file>", "Input artifact file", ".vibgrate/scan_result.json").option("--format <format>", "Output format (md|text|json)", "text").action(async (opts) => {
56
+ const artifactPath = path2.resolve(opts.in);
57
+ if (!await pathExists(artifactPath)) {
58
+ console.error(chalk2.red(`Artifact not found: ${artifactPath}`));
59
+ console.error(chalk2.dim('Run "vibgrate scan" first to generate a scan artifact.'));
60
+ process.exit(1);
61
+ }
62
+ const artifact = await readJsonFile(artifactPath);
63
+ switch (opts.format) {
64
+ case "md":
65
+ console.log(formatMarkdown(artifact));
66
+ break;
67
+ case "json":
68
+ console.log(JSON.stringify(artifact, null, 2));
69
+ break;
70
+ case "text":
71
+ default:
72
+ console.log(formatText(artifact));
73
+ break;
74
+ }
75
+ });
76
+
77
+ // src/commands/dsn.ts
78
+ import * as crypto from "crypto";
79
+ import * as path3 from "path";
80
+ import { Command as Command3 } from "commander";
81
+ import chalk3 from "chalk";
82
+ var REGION_HOSTS = {
83
+ us: "us.ingest.vibgrate.com",
84
+ eu: "eu.ingest.vibgrate.com"
85
+ };
86
+ function resolveIngestHost(region, ingest) {
87
+ if (ingest) {
88
+ try {
89
+ return new URL(ingest).host;
90
+ } catch {
91
+ throw new Error(`Invalid ingest URL: ${ingest}`);
92
+ }
93
+ }
94
+ const r = (region ?? "us").toLowerCase();
95
+ const host = REGION_HOSTS[r];
96
+ if (!host) {
97
+ throw new Error(`Unknown region "${r}". Supported: ${Object.keys(REGION_HOSTS).join(", ")}`);
98
+ }
99
+ return host;
100
+ }
101
+ var dsnCommand = new Command3("dsn").description("Manage DSN tokens");
102
+ dsnCommand.command("create").description("Create a new DSN token").option("--ingest <url>", "Ingest API URL (overrides --region)").option("--region <region>", "Data residency region (us, eu)", "us").requiredOption("--workspace <id>", "Workspace ID").option("--write <path>", "Write DSN to file").action(async (opts) => {
103
+ const keyId = crypto.randomBytes(8).toString("hex");
104
+ const secret = crypto.randomBytes(32).toString("hex");
105
+ let ingestHost;
106
+ try {
107
+ ingestHost = resolveIngestHost(opts.region, opts.ingest);
108
+ } catch (e) {
109
+ console.error(chalk3.red(e instanceof Error ? e.message : String(e)));
110
+ process.exit(1);
111
+ }
112
+ const dsn = `vibgrate+https://${keyId}:${secret}@${ingestHost}/${opts.workspace}`;
113
+ console.log(chalk3.green("\u2714") + " DSN created");
114
+ console.log("");
115
+ console.log(chalk3.bold("DSN:"));
116
+ console.log(` ${dsn}`);
117
+ console.log("");
118
+ console.log(chalk3.bold("Key ID:"));
119
+ console.log(` ${keyId}`);
120
+ console.log("");
121
+ console.log(chalk3.dim("Set this as VIBGRATE_DSN in your CI environment."));
122
+ console.log(chalk3.dim("The secret must be registered on your Vibgrate ingest API."));
123
+ if (opts.write) {
124
+ const writePath = path3.resolve(opts.write);
125
+ await writeTextFile(writePath, dsn + "\n");
126
+ console.log("");
127
+ console.log(chalk3.green("\u2714") + ` DSN written to ${opts.write}`);
128
+ console.log(chalk3.yellow("\u26A0") + " Add this file to .gitignore!");
129
+ }
130
+ });
131
+
132
+ // src/commands/push.ts
133
+ import * as crypto2 from "crypto";
134
+ import * as path4 from "path";
135
+ import { Command as Command4 } from "commander";
136
+ import chalk4 from "chalk";
137
+ function parseDsn(dsn) {
138
+ const match = dsn.match(/^vibgrate\+https:\/\/([^:]+):([^@]+)@([^/]+)\/(.+)$/);
139
+ if (!match) return null;
140
+ return {
141
+ keyId: match[1],
142
+ secret: match[2],
143
+ host: match[3],
144
+ workspaceId: match[4]
145
+ };
146
+ }
147
+ function computeHmac(body, secret) {
148
+ return crypto2.createHmac("sha256", secret).update(body).digest("base64");
149
+ }
150
+ var pushCommand = new Command4("push").description("Push scan results to Vibgrate API").option("--dsn <dsn>", "DSN token (or use VIBGRATE_DSN env)").option("--region <region>", "Override data residency region (us, eu)").option("--file <file>", "Scan artifact file", ".vibgrate/scan_result.json").option("--strict", "Fail on upload errors").action(async (opts) => {
151
+ const dsn = opts.dsn || process.env.VIBGRATE_DSN;
152
+ if (!dsn) {
153
+ console.error(chalk4.red("No DSN provided."));
154
+ console.error(chalk4.dim("Set VIBGRATE_DSN environment variable or use --dsn flag."));
155
+ if (opts.strict) process.exit(1);
156
+ return;
157
+ }
158
+ const parsed = parseDsn(dsn);
159
+ if (!parsed) {
160
+ console.error(chalk4.red("Invalid DSN format."));
161
+ console.error(chalk4.dim("Expected: vibgrate+https://<key_id>:<secret>@<host>/<workspace_id>"));
162
+ if (opts.strict) process.exit(1);
163
+ return;
164
+ }
165
+ const filePath = path4.resolve(opts.file);
166
+ if (!await pathExists(filePath)) {
167
+ console.error(chalk4.red(`Scan artifact not found: ${filePath}`));
168
+ console.error(chalk4.dim('Run "vibgrate scan" first.'));
169
+ if (opts.strict) process.exit(1);
170
+ return;
171
+ }
172
+ const body = await readTextFile(filePath);
173
+ const timestamp = String(Date.now());
174
+ const hmac = computeHmac(body, parsed.secret);
175
+ let host = parsed.host;
176
+ if (opts.region) {
177
+ try {
178
+ host = resolveIngestHost(opts.region);
179
+ } catch (e) {
180
+ console.error(chalk4.red(e instanceof Error ? e.message : String(e)));
181
+ if (opts.strict) process.exit(1);
182
+ return;
183
+ }
184
+ }
185
+ const url = `https://${host}/v1/ingest/scan`;
186
+ console.log(chalk4.dim(`Uploading to ${host}...`));
187
+ try {
188
+ const response = await fetch(url, {
189
+ method: "POST",
190
+ headers: {
191
+ "Content-Type": "application/json",
192
+ "X-Vibgrate-Timestamp": timestamp,
193
+ "Authorization": `VibgrateDSN ${parsed.keyId}:${hmac}`
194
+ },
195
+ body
196
+ });
197
+ if (!response.ok) {
198
+ const text = await response.text();
199
+ throw new Error(`HTTP ${response.status}: ${text}`);
200
+ }
201
+ const result = await response.json();
202
+ console.log(chalk4.green("\u2714") + ` Uploaded successfully (${result.ingestId ?? "ok"})`);
203
+ } catch (e) {
204
+ const msg = e instanceof Error ? e.message : String(e);
205
+ console.error(chalk4.red(`Upload failed: ${msg}`));
206
+ if (opts.strict) process.exit(1);
207
+ }
208
+ });
209
+
210
+ // src/commands/update.ts
211
+ import { execSync } from "child_process";
212
+ import * as path6 from "path";
213
+ import { Command as Command5 } from "commander";
214
+ import chalk5 from "chalk";
215
+
216
+ // src/utils/update-check.ts
217
+ import * as fs from "fs/promises";
218
+ import * as path5 from "path";
219
+ import * as os from "os";
220
+ import semver from "semver";
221
+ var REGISTRY_URL = "https://registry.npmjs.org/@vibgrate%2fcli/latest";
222
+ var CACHE_DIR = path5.join(os.homedir(), ".vibgrate");
223
+ var CACHE_FILE = path5.join(CACHE_DIR, "update-check.json");
224
+ var CHECK_INTERVAL_MS = 12 * 60 * 60 * 1e3;
225
+ async function checkForUpdate() {
226
+ try {
227
+ const cached = await readCache();
228
+ if (cached && Date.now() - cached.checkedAt < CHECK_INTERVAL_MS) {
229
+ return {
230
+ current: VERSION,
231
+ latest: cached.latest,
232
+ updateAvailable: semver.gt(cached.latest, VERSION)
233
+ };
234
+ }
235
+ const controller = new AbortController();
236
+ const timeout = setTimeout(() => controller.abort(), 5e3);
237
+ const response = await fetch(REGISTRY_URL, {
238
+ headers: { Accept: "application/json" },
239
+ signal: controller.signal
240
+ });
241
+ clearTimeout(timeout);
242
+ if (!response.ok) return null;
243
+ const data = await response.json();
244
+ const latest = data.version;
245
+ if (!latest || !semver.valid(latest)) return null;
246
+ await writeCache({ latest, checkedAt: Date.now() });
247
+ return {
248
+ current: VERSION,
249
+ latest,
250
+ updateAvailable: semver.gt(latest, VERSION)
251
+ };
252
+ } catch {
253
+ return null;
254
+ }
255
+ }
256
+ async function fetchLatestVersion() {
257
+ try {
258
+ const controller = new AbortController();
259
+ const timeout = setTimeout(() => controller.abort(), 1e4);
260
+ const response = await fetch(REGISTRY_URL, {
261
+ headers: { Accept: "application/json" },
262
+ signal: controller.signal
263
+ });
264
+ clearTimeout(timeout);
265
+ if (!response.ok) return null;
266
+ const data = await response.json();
267
+ const latest = data.version;
268
+ if (!latest || !semver.valid(latest)) return null;
269
+ await writeCache({ latest, checkedAt: Date.now() });
270
+ return latest;
271
+ } catch {
272
+ return null;
273
+ }
274
+ }
275
+ async function readCache() {
276
+ try {
277
+ const raw = await fs.readFile(CACHE_FILE, "utf-8");
278
+ const data = JSON.parse(raw);
279
+ if (data.latest && typeof data.checkedAt === "number") return data;
280
+ return null;
281
+ } catch {
282
+ return null;
283
+ }
284
+ }
285
+ async function writeCache(data) {
286
+ try {
287
+ await fs.mkdir(CACHE_DIR, { recursive: true });
288
+ await fs.writeFile(CACHE_FILE, JSON.stringify(data), "utf-8");
289
+ } catch {
290
+ }
291
+ }
292
+
293
+ // src/commands/update.ts
294
+ async function detectPackageManager(cwd) {
295
+ if (await pathExists(path6.join(cwd, "pnpm-lock.yaml"))) return "pnpm";
296
+ if (await pathExists(path6.join(cwd, "bun.lockb"))) return "bun";
297
+ if (await pathExists(path6.join(cwd, "yarn.lock"))) return "yarn";
298
+ return "npm";
299
+ }
300
+ function getInstallCommand(pm, pkg, version, isDev) {
301
+ const spec = `${pkg}@${version}`;
302
+ switch (pm) {
303
+ case "pnpm":
304
+ return isDev ? `pnpm add -D ${spec}` : `pnpm add ${spec}`;
305
+ case "yarn":
306
+ return isDev ? `yarn add --dev ${spec}` : `yarn add ${spec}`;
307
+ case "bun":
308
+ return isDev ? `bun add -d ${spec}` : `bun add ${spec}`;
309
+ case "npm":
310
+ default:
311
+ return isDev ? `npm install --save-dev ${spec}` : `npm install ${spec}`;
312
+ }
313
+ }
314
+ async function isDevDependency(cwd) {
315
+ try {
316
+ const pkgPath = path6.join(cwd, "package.json");
317
+ const raw = await (await import("fs/promises")).readFile(pkgPath, "utf-8");
318
+ const pkg = JSON.parse(raw);
319
+ return Boolean(pkg.devDependencies?.["@vibgrate/cli"]);
320
+ } catch {
321
+ return true;
322
+ }
323
+ }
324
+ var updateCommand = new Command5("update").description("Update vibgrate to the latest version").option("--check", "Only check for updates, do not install").option("--pm <manager>", "Package manager to use (npm, pnpm, yarn, bun)").action(async (opts) => {
325
+ console.log(chalk5.dim(`Current version: ${VERSION}`));
326
+ console.log(chalk5.dim("Checking npm registry..."));
327
+ const latest = await fetchLatestVersion();
328
+ if (!latest) {
329
+ console.error(chalk5.red("Could not reach the npm registry. Check your network connection."));
330
+ process.exit(1);
331
+ }
332
+ const semver2 = await import("semver");
333
+ if (!semver2.gt(latest, VERSION)) {
334
+ console.log(chalk5.green("\u2714") + ` You are on the latest version (${VERSION}).`);
335
+ return;
336
+ }
337
+ console.log(chalk5.yellow(`Update available: ${VERSION} \u2192 ${latest}`));
338
+ if (opts.check) {
339
+ console.log(chalk5.dim('Run "vibgrate update" to install.'));
340
+ return;
341
+ }
342
+ const cwd = process.cwd();
343
+ const pm = opts.pm || await detectPackageManager(cwd);
344
+ const isDev = await isDevDependency(cwd);
345
+ const cmd = getInstallCommand(pm, "@vibgrate/cli", latest, isDev);
346
+ console.log(chalk5.dim(`Using ${pm}: ${cmd}`));
347
+ try {
348
+ execSync(cmd, { cwd, stdio: "inherit" });
349
+ console.log(chalk5.green("\u2714") + ` Updated to @vibgrate/cli@${latest}`);
350
+ } catch {
351
+ console.error(chalk5.red(`Update failed. Run manually: ${cmd}`));
352
+ process.exit(1);
353
+ }
354
+ });
355
+
356
+ // src/cli.ts
357
+ var program = new Command6();
358
+ program.name("vibgrate").description("Continuous Upgrade Drift Intelligence for Node & .NET").version(VERSION);
359
+ program.addCommand(initCommand);
360
+ program.addCommand(scanCommand);
361
+ program.addCommand(baselineCommand);
362
+ program.addCommand(reportCommand);
363
+ program.addCommand(dsnCommand);
364
+ program.addCommand(pushCommand);
365
+ program.addCommand(updateCommand);
366
+ program.parseAsync().then(async () => {
367
+ const update = await checkForUpdate();
368
+ if (update?.updateAvailable) {
369
+ console.error("");
370
+ console.error(chalk6.yellow(` Update available: ${update.current} \u2192 ${update.latest}`));
371
+ console.error(chalk6.dim(' Run "vibgrate update" to install the latest version.'));
372
+ console.error("");
373
+ }
374
+ }).catch((err) => {
375
+ console.error(err);
376
+ process.exit(1);
377
+ });
@@ -0,0 +1,126 @@
1
+ type DepSection = 'dependencies' | 'devDependencies' | 'peerDependencies' | 'optionalDependencies';
2
+ type RiskLevel = 'low' | 'moderate' | 'high';
3
+ type ProjectType = 'node' | 'dotnet';
4
+ type OutputFormat = 'text' | 'json' | 'sarif';
5
+ interface DependencyRow {
6
+ package: string;
7
+ section: DepSection;
8
+ currentSpec: string;
9
+ resolvedVersion: string | null;
10
+ latestStable: string | null;
11
+ majorsBehind: number | null;
12
+ drift: 'current' | 'minor-behind' | 'major-behind' | 'unknown';
13
+ }
14
+ interface DetectedFramework {
15
+ name: string;
16
+ currentVersion: string | null;
17
+ latestVersion: string | null;
18
+ majorsBehind: number | null;
19
+ }
20
+ interface ProjectScan {
21
+ type: ProjectType;
22
+ path: string;
23
+ name: string;
24
+ runtime?: string;
25
+ runtimeLatest?: string;
26
+ runtimeMajorsBehind?: number;
27
+ targetFramework?: string;
28
+ frameworks: DetectedFramework[];
29
+ dependencies: DependencyRow[];
30
+ dependencyAgeBuckets: {
31
+ current: number;
32
+ oneBehind: number;
33
+ twoPlusBehind: number;
34
+ unknown: number;
35
+ };
36
+ }
37
+ interface DriftScore {
38
+ score: number;
39
+ riskLevel: RiskLevel;
40
+ components: {
41
+ runtimeScore: number;
42
+ frameworkScore: number;
43
+ dependencyScore: number;
44
+ eolScore: number;
45
+ };
46
+ }
47
+ interface Finding {
48
+ ruleId: string;
49
+ level: 'warning' | 'error' | 'note';
50
+ message: string;
51
+ location: string;
52
+ details?: Record<string, unknown>;
53
+ }
54
+ type VcsType = 'git' | 'unknown';
55
+ interface VcsInfo {
56
+ type: VcsType;
57
+ sha?: string;
58
+ shortSha?: string;
59
+ branch?: string;
60
+ }
61
+ interface ScanArtifact {
62
+ schemaVersion: '1.0';
63
+ timestamp: string;
64
+ vibgrateVersion: string;
65
+ rootPath: string;
66
+ vcs?: VcsInfo;
67
+ projects: ProjectScan[];
68
+ drift: DriftScore;
69
+ findings: Finding[];
70
+ baseline?: string;
71
+ delta?: number;
72
+ }
73
+ interface ScanOptions {
74
+ out?: string;
75
+ format: OutputFormat;
76
+ failOn?: 'warn' | 'error';
77
+ baseline?: string;
78
+ changedOnly?: boolean;
79
+ concurrency: number;
80
+ }
81
+ interface ScannerToggle {
82
+ enabled: boolean;
83
+ }
84
+ interface ScannersConfig {
85
+ platformMatrix?: ScannerToggle;
86
+ dependencyRisk?: ScannerToggle;
87
+ dependencyGraph?: ScannerToggle;
88
+ toolingInventory?: ScannerToggle;
89
+ buildDeploy?: ScannerToggle;
90
+ tsModernity?: ScannerToggle;
91
+ breakingChangeExposure?: ScannerToggle;
92
+ fileHotspots?: ScannerToggle;
93
+ securityPosture?: ScannerToggle;
94
+ serviceDependencies?: ScannerToggle;
95
+ }
96
+ interface VibgrateConfig {
97
+ include?: string[];
98
+ exclude?: string[];
99
+ scanners?: ScannersConfig | false;
100
+ thresholds?: {
101
+ failOnError?: {
102
+ eolDays?: number;
103
+ frameworkMajorLag?: number;
104
+ dependencyTwoPlusPercent?: number;
105
+ };
106
+ warn?: {
107
+ frameworkMajorLag?: number;
108
+ dependencyTwoPlusPercent?: number;
109
+ };
110
+ };
111
+ }
112
+
113
+ declare function runScan(rootDir: string, opts: ScanOptions): Promise<ScanArtifact>;
114
+
115
+ declare function computeDriftScore(projects: ProjectScan[]): DriftScore;
116
+ declare function generateFindings(projects: ProjectScan[], config?: VibgrateConfig): Finding[];
117
+
118
+ declare function formatText(artifact: ScanArtifact): string;
119
+
120
+ /** Generate a SARIF 2.1.0 document from scan artifact */
121
+ declare function formatSarif(artifact: ScanArtifact): object;
122
+
123
+ /** Generate a Markdown report from scan artifact */
124
+ declare function formatMarkdown(artifact: ScanArtifact): string;
125
+
126
+ export { type DependencyRow, type DriftScore, type Finding, type ProjectScan, type RiskLevel, type ScanArtifact, type ScanOptions, type VibgrateConfig, computeDriftScore, formatMarkdown, formatSarif, formatText, generateFindings, runScan };
package/dist/index.js ADDED
@@ -0,0 +1,18 @@
1
+ import {
2
+ formatMarkdown
3
+ } from "./chunk-AMOJCCF5.js";
4
+ import {
5
+ computeDriftScore,
6
+ formatSarif,
7
+ formatText,
8
+ generateFindings,
9
+ runScan
10
+ } from "./chunk-DLRBJYO6.js";
11
+ export {
12
+ computeDriftScore,
13
+ formatMarkdown,
14
+ formatSarif,
15
+ formatText,
16
+ generateFindings,
17
+ runScan
18
+ };
package/package.json ADDED
@@ -0,0 +1,57 @@
1
+ {
2
+ "name": "@vibgrate/cli",
3
+ "version": "0.1.1",
4
+ "description": "CLI for measuring upgrade drift across Node & .NET projects",
5
+ "type": "module",
6
+ "bin": {
7
+ "vibgrate": "./dist/cli.js"
8
+ },
9
+ "main": "./dist/index.js",
10
+ "types": "./dist/index.d.ts",
11
+ "exports": {
12
+ ".": {
13
+ "types": "./dist/index.d.ts",
14
+ "import": "./dist/index.js"
15
+ }
16
+ },
17
+ "files": [
18
+ "dist"
19
+ ],
20
+ "scripts": {
21
+ "build": "tsup src/cli.ts src/index.ts --format esm --dts --clean",
22
+ "dev": "tsx src/cli.ts",
23
+ "lint": "eslint src",
24
+ "typecheck": "tsc --noEmit",
25
+ "test": "vitest run"
26
+ },
27
+ "keywords": [
28
+ "upgrade",
29
+ "drift",
30
+ "dependencies",
31
+ "cli",
32
+ "node",
33
+ "dotnet",
34
+ "sarif"
35
+ ],
36
+ "author": "Vibgrate",
37
+ "license": "UNLICENSED",
38
+ "devDependencies": {
39
+ "@types/node": "^20.0.0",
40
+ "@types/semver": "^7.5.0",
41
+ "eslint": "^9.0.0",
42
+ "tsup": "^8.0.0",
43
+ "tsx": "^4.0.0",
44
+ "typescript": "^5.4.0",
45
+ "vitest": "^2.0.0"
46
+ },
47
+ "dependencies": {
48
+ "chalk": "^5.3.0",
49
+ "commander": "^12.0.0",
50
+ "fast-xml-parser": "^4.3.0",
51
+ "semver": "^7.6.0",
52
+ "zod": "^3.23.0"
53
+ },
54
+ "engines": {
55
+ "node": ">=20.0.0"
56
+ }
57
+ }