verelease 0.1.2-alpha.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/dist/bin.js ADDED
@@ -0,0 +1,2380 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/cli.ts
4
+ import { resolve as resolve2, join as join10 } from "path";
5
+ import { writeFile as writeFile5, mkdir as mkdir5, readFile as readFile5, unlink } from "fs/promises";
6
+
7
+ // ../workspace/dist/graph.js
8
+ var PackageGraphImpl = class {
9
+ nodes = /* @__PURE__ */ new Map();
10
+ constructor(packages) {
11
+ this.buildGraph(packages);
12
+ }
13
+ buildGraph(packages) {
14
+ const packageNames = new Set(packages.map((p) => p.name));
15
+ for (const pkg of packages) {
16
+ this.nodes.set(pkg.name, {
17
+ pkg,
18
+ dependencies: /* @__PURE__ */ new Map(),
19
+ dependents: /* @__PURE__ */ new Set()
20
+ });
21
+ }
22
+ for (const pkg of packages) {
23
+ const node = this.nodes.get(pkg.name);
24
+ const manifest = pkg.manifest;
25
+ const depSections = [
26
+ ["dependencies", manifest.dependencies],
27
+ ["devDependencies", manifest.devDependencies],
28
+ ["peerDependencies", manifest.peerDependencies],
29
+ ["optionalDependencies", manifest.optionalDependencies]
30
+ ];
31
+ for (const [depType, deps] of depSections) {
32
+ if (!deps)
33
+ continue;
34
+ for (const [depName, range] of Object.entries(deps)) {
35
+ if (!packageNames.has(depName))
36
+ continue;
37
+ let protocol = "standard";
38
+ let rawProtocolPrefix = "";
39
+ if (range.startsWith("workspace:")) {
40
+ protocol = "workspace";
41
+ rawProtocolPrefix = "workspace:";
42
+ } else if (range.startsWith("file:")) {
43
+ protocol = "file";
44
+ rawProtocolPrefix = "file:";
45
+ } else if (range.startsWith("link:")) {
46
+ protocol = "link";
47
+ rawProtocolPrefix = "link:";
48
+ }
49
+ node.dependencies.set(depName, {
50
+ name: depName,
51
+ currentRange: range,
52
+ type: depType,
53
+ protocol,
54
+ rawProtocolPrefix
55
+ });
56
+ const depNode = this.nodes.get(depName);
57
+ if (depNode) {
58
+ depNode.dependents.add(pkg.name);
59
+ }
60
+ }
61
+ }
62
+ }
63
+ }
64
+ getTopologicalOrder() {
65
+ const inDegree = /* @__PURE__ */ new Map();
66
+ for (const [name, node] of this.nodes) {
67
+ inDegree.set(name, node.dependencies.size);
68
+ }
69
+ const queue = [];
70
+ for (const [name, degree] of inDegree) {
71
+ if (degree === 0) {
72
+ queue.push(name);
73
+ }
74
+ }
75
+ const order = [];
76
+ while (queue.length > 0) {
77
+ const current = queue.shift();
78
+ order.push(current);
79
+ const currentNode = this.nodes.get(current);
80
+ if (!currentNode)
81
+ continue;
82
+ for (const depName of currentNode.dependents) {
83
+ const currentInDegree = inDegree.get(depName);
84
+ const newInDegree = currentInDegree - 1;
85
+ inDegree.set(depName, newInDegree);
86
+ if (newInDegree === 0) {
87
+ queue.push(depName);
88
+ }
89
+ }
90
+ }
91
+ if (order.length < this.nodes.size) {
92
+ for (const name of this.nodes.keys()) {
93
+ if (!order.includes(name)) {
94
+ order.push(name);
95
+ }
96
+ }
97
+ }
98
+ return order;
99
+ }
100
+ getDirectDependents(packageName) {
101
+ const node = this.nodes.get(packageName);
102
+ if (!node)
103
+ return [];
104
+ return Array.from(node.dependents);
105
+ }
106
+ getAllTransitiveDependents(packageName) {
107
+ const visited = /* @__PURE__ */ new Set();
108
+ const queue = [...this.getDirectDependents(packageName)];
109
+ while (queue.length > 0) {
110
+ const current = queue.shift();
111
+ if (!visited.has(current)) {
112
+ visited.add(current);
113
+ const dependents = this.getDirectDependents(current);
114
+ for (const dep of dependents) {
115
+ if (!visited.has(dep)) {
116
+ queue.push(dep);
117
+ }
118
+ }
119
+ }
120
+ }
121
+ return Array.from(visited);
122
+ }
123
+ hasCycle() {
124
+ return this.getCycles().length > 0;
125
+ }
126
+ getCycles() {
127
+ const visited = /* @__PURE__ */ new Set();
128
+ const recStack = /* @__PURE__ */ new Set();
129
+ const cycles = [];
130
+ const dfs = (nodeName, path) => {
131
+ visited.add(nodeName);
132
+ recStack.add(nodeName);
133
+ path.push(nodeName);
134
+ const node = this.nodes.get(nodeName);
135
+ if (node) {
136
+ for (const depName of node.dependencies.keys()) {
137
+ if (!visited.has(depName)) {
138
+ dfs(depName, [...path]);
139
+ } else if (recStack.has(depName)) {
140
+ const cycleStartIndex = path.indexOf(depName);
141
+ if (cycleStartIndex !== -1) {
142
+ cycles.push(path.slice(cycleStartIndex).concat(depName));
143
+ }
144
+ }
145
+ }
146
+ }
147
+ recStack.delete(nodeName);
148
+ };
149
+ for (const name of this.nodes.keys()) {
150
+ if (!visited.has(name)) {
151
+ dfs(name, []);
152
+ }
153
+ }
154
+ return cycles;
155
+ }
156
+ };
157
+
158
+ // ../workspace/dist/resolver.js
159
+ import { readFile, stat, readdir } from "fs/promises";
160
+ import { join, relative, resolve } from "path";
161
+ import { parse as parseYaml } from "yaml";
162
+ async function fileExists(path) {
163
+ try {
164
+ const s = await stat(path);
165
+ return s.isFile();
166
+ } catch {
167
+ return false;
168
+ }
169
+ }
170
+ async function dirExists(path) {
171
+ try {
172
+ const s = await stat(path);
173
+ return s.isDirectory();
174
+ } catch {
175
+ return false;
176
+ }
177
+ }
178
+ var DefaultWorkspaceResolver = class {
179
+ name = "default-workspace-resolver";
180
+ async supports(rootDir) {
181
+ const pnpmWorkspace = join(rootDir, "pnpm-workspace.yaml");
182
+ const packageJson = join(rootDir, "package.json");
183
+ return await fileExists(pnpmWorkspace) || await fileExists(packageJson);
184
+ }
185
+ async resolve(rootDir) {
186
+ const absRootDir = resolve(rootDir);
187
+ const pnpmWorkspacePath = join(absRootDir, "pnpm-workspace.yaml");
188
+ const rootPkgJsonPath = join(absRootDir, "package.json");
189
+ let packageManager = "unknown";
190
+ let patterns = [];
191
+ if (await fileExists(pnpmWorkspacePath)) {
192
+ packageManager = "pnpm";
193
+ const content = await readFile(pnpmWorkspacePath, "utf8");
194
+ const parsed = parseYaml(content);
195
+ if (parsed && Array.isArray(parsed.packages)) {
196
+ patterns = parsed.packages;
197
+ }
198
+ } else if (await fileExists(rootPkgJsonPath)) {
199
+ const content = await readFile(rootPkgJsonPath, "utf8");
200
+ const parsed = JSON.parse(content);
201
+ if (Array.isArray(parsed.workspaces)) {
202
+ patterns = parsed.workspaces;
203
+ packageManager = "npm";
204
+ } else if (parsed.workspaces && Array.isArray(parsed.workspaces.packages)) {
205
+ patterns = parsed.workspaces.packages;
206
+ packageManager = "yarn";
207
+ } else {
208
+ const pkg = {
209
+ name: parsed.name || "unnamed-package",
210
+ version: parsed.version || "0.0.0",
211
+ directory: absRootDir,
212
+ manifestPath: rootPkgJsonPath,
213
+ manifest: parsed,
214
+ isPrivate: !!parsed.private,
215
+ relativeDir: "."
216
+ };
217
+ const graph2 = new PackageGraphImpl([pkg]);
218
+ return {
219
+ rootDirectory: absRootDir,
220
+ packageManager: "npm",
221
+ packages: [pkg],
222
+ graph: graph2
223
+ };
224
+ }
225
+ }
226
+ if (patterns.length === 0) {
227
+ patterns = ["packages/*"];
228
+ }
229
+ const matchedDirs = /* @__PURE__ */ new Set();
230
+ for (const pattern of patterns) {
231
+ if (pattern.endsWith("/*")) {
232
+ const baseDir = join(absRootDir, pattern.slice(0, -2));
233
+ if (await dirExists(baseDir)) {
234
+ const entries = await readdir(baseDir, { withFileTypes: true });
235
+ for (const entry of entries) {
236
+ if (entry.isDirectory()) {
237
+ matchedDirs.add(join(baseDir, entry.name));
238
+ }
239
+ }
240
+ }
241
+ } else {
242
+ const exactDir = join(absRootDir, pattern);
243
+ if (await dirExists(exactDir)) {
244
+ matchedDirs.add(exactDir);
245
+ }
246
+ }
247
+ }
248
+ const packages = [];
249
+ for (const dir of matchedDirs) {
250
+ const manifestPath = join(dir, "package.json");
251
+ if (await fileExists(manifestPath)) {
252
+ try {
253
+ const content = await readFile(manifestPath, "utf8");
254
+ const manifest = JSON.parse(content);
255
+ if (manifest.name && manifest.version) {
256
+ packages.push({
257
+ name: manifest.name,
258
+ version: manifest.version,
259
+ directory: dir,
260
+ manifestPath,
261
+ manifest,
262
+ isPrivate: !!manifest.private,
263
+ relativeDir: relative(absRootDir, dir)
264
+ });
265
+ }
266
+ } catch {
267
+ }
268
+ }
269
+ }
270
+ const graph = new PackageGraphImpl(packages);
271
+ return {
272
+ rootDirectory: absRootDir,
273
+ packageManager,
274
+ packages,
275
+ graph
276
+ };
277
+ }
278
+ };
279
+
280
+ // ../workspace/dist/propagator.js
281
+ import semver from "semver";
282
+ var VersionPropagator = class {
283
+ graph;
284
+ constructor(graph) {
285
+ this.graph = graph;
286
+ }
287
+ propagate(initialBumps, options = {}) {
288
+ const bumps = new Map(initialBumps);
289
+ const dependencyUpdates = /* @__PURE__ */ new Map();
290
+ const dependentBump = options.dependentBumpStrategy || "patch";
291
+ let queue = Array.from(bumps.keys());
292
+ while (queue.length > 0) {
293
+ const changedPkgName = queue.shift();
294
+ const changedTarget = bumps.get(changedPkgName);
295
+ if (changedTarget.bump === "none")
296
+ continue;
297
+ const directDependents = this.graph.getDirectDependents(changedPkgName);
298
+ for (const dependentName of directDependents) {
299
+ const depNode = this.graph.nodes.get(dependentName);
300
+ if (!depNode)
301
+ continue;
302
+ const ref = depNode.dependencies.get(changedPkgName);
303
+ if (!ref)
304
+ continue;
305
+ const { currentRange, rawProtocolPrefix } = ref;
306
+ let cleanRange = currentRange;
307
+ if (rawProtocolPrefix) {
308
+ cleanRange = currentRange.slice(rawProtocolPrefix.length);
309
+ }
310
+ let isSatisfied = false;
311
+ if (cleanRange === "*" || cleanRange === "") {
312
+ isSatisfied = true;
313
+ } else {
314
+ isSatisfied = semver.satisfies(changedTarget.proposedVersion, cleanRange);
315
+ }
316
+ if (!isSatisfied) {
317
+ let newRange = `^${changedTarget.proposedVersion}`;
318
+ if (cleanRange.startsWith("~")) {
319
+ newRange = `~${changedTarget.proposedVersion}`;
320
+ }
321
+ if (rawProtocolPrefix) {
322
+ newRange = `${rawProtocolPrefix}${newRange}`;
323
+ }
324
+ if (!dependencyUpdates.has(dependentName)) {
325
+ dependencyUpdates.set(dependentName, []);
326
+ }
327
+ dependencyUpdates.get(dependentName).push({
328
+ dependencyName: changedPkgName,
329
+ previousRange: currentRange,
330
+ newRange,
331
+ type: ref.type
332
+ });
333
+ const existingDependentBump = bumps.get(dependentName);
334
+ if (!existingDependentBump || existingDependentBump.bump === "none") {
335
+ const currentVer = depNode.pkg.version;
336
+ const nextVer = semver.inc(currentVer, dependentBump) || currentVer;
337
+ const newTarget = {
338
+ name: dependentName,
339
+ currentVersion: currentVer,
340
+ proposedVersion: nextVer,
341
+ bump: dependentBump,
342
+ reasons: [
343
+ `Dependency ${changedPkgName} bumped to ${changedTarget.proposedVersion}, violating range ${currentRange}`
344
+ ]
345
+ };
346
+ bumps.set(dependentName, newTarget);
347
+ queue.push(dependentName);
348
+ }
349
+ }
350
+ }
351
+ }
352
+ return {
353
+ bumps,
354
+ dependencyUpdates
355
+ };
356
+ }
357
+ };
358
+
359
+ // ../semver/dist/engine.js
360
+ import semver2 from "semver";
361
+ var DefaultSemVerDecisionEngine = class {
362
+ evaluate(packageName, currentVersion, evidence, policy = {}, channel = "stable") {
363
+ const validCurrent = semver2.valid(currentVersion);
364
+ if (!validCurrent) {
365
+ throw new Error(`Invalid SemVer string for package ${packageName}: ${currentVersion}`);
366
+ }
367
+ const currentParsed = semver2.parse(validCurrent);
368
+ const isZeroMajor = currentParsed.major === 0;
369
+ if (policy.evaluate) {
370
+ const customBump = policy.evaluate(evidence, { packageName, currentVersion });
371
+ if (customBump) {
372
+ return this.createDecision(packageName, currentVersion, customBump, evidence, [`Determined by custom policy evaluation: ${customBump}`], 1, policy, channel);
373
+ }
374
+ }
375
+ let bump = "none";
376
+ const reasons = [];
377
+ let confidenceSum = 0;
378
+ let confidenceCount = 0;
379
+ const majorEvidence = evidence.filter((e) => e.severity === "major");
380
+ const minorEvidence = evidence.filter((e) => e.severity === "minor");
381
+ const patchEvidence = evidence.filter((e) => e.severity === "patch");
382
+ if (majorEvidence.length > 0) {
383
+ if (isZeroMajor && policy.zeroMajor?.breaking === "minor") {
384
+ bump = "minor";
385
+ reasons.push(`Detected breaking compatibility changes in 0.x package under zeroMajor policy -> minor bump`);
386
+ } else {
387
+ bump = "major";
388
+ reasons.push(`Detected ${majorEvidence.length} breaking compatibility changes:`);
389
+ }
390
+ for (const e of majorEvidence) {
391
+ reasons.push(` - [${e.source}] ${e.title}: ${e.description}`);
392
+ confidenceSum += e.confidence;
393
+ confidenceCount++;
394
+ }
395
+ } else if (minorEvidence.length > 0) {
396
+ bump = "minor";
397
+ reasons.push(`Detected ${minorEvidence.length} backward-compatible additions:`);
398
+ for (const e of minorEvidence) {
399
+ reasons.push(` - [${e.source}] ${e.title}: ${e.description}`);
400
+ confidenceSum += e.confidence;
401
+ confidenceCount++;
402
+ }
403
+ } else if (patchEvidence.length > 0) {
404
+ bump = "patch";
405
+ reasons.push(`Detected ${patchEvidence.length} backwards-compatible patches:`);
406
+ for (const e of patchEvidence) {
407
+ reasons.push(` - [${e.source}] ${e.title}: ${e.description}`);
408
+ confidenceSum += e.confidence;
409
+ confidenceCount++;
410
+ }
411
+ } else {
412
+ bump = "none";
413
+ reasons.push("No compatibility changes detected requiring a version bump.");
414
+ }
415
+ const confidence = confidenceCount > 0 ? confidenceSum / confidenceCount : 1;
416
+ return this.createDecision(packageName, currentVersion, bump, evidence, reasons, confidence, policy, channel);
417
+ }
418
+ createDecision(packageName, currentVersion, bump, evidence, reasons, confidence, policy, channel) {
419
+ let proposedVersion = currentVersion;
420
+ if (bump !== "none") {
421
+ if (channel && channel !== "stable") {
422
+ const parsed = semver2.parse(currentVersion);
423
+ const currentPrerelease = parsed.prerelease;
424
+ if (currentPrerelease.length > 0 && currentPrerelease[0] === channel) {
425
+ proposedVersion = semver2.inc(currentVersion, "prerelease", channel) || currentVersion;
426
+ } else {
427
+ const baseBump = `pre${bump}`;
428
+ proposedVersion = semver2.inc(currentVersion, baseBump, channel) || currentVersion;
429
+ }
430
+ } else {
431
+ proposedVersion = semver2.inc(currentVersion, bump) || currentVersion;
432
+ }
433
+ }
434
+ const requiresApproval = bump === "major" && !!policy.requireHumanApprovalForMajor || policy.minimumConfidenceForAutomaticRelease !== void 0 && confidence < policy.minimumConfidenceForAutomaticRelease;
435
+ return {
436
+ packageName,
437
+ currentVersion,
438
+ bump,
439
+ proposedVersion,
440
+ confidence,
441
+ reasons,
442
+ evidence,
443
+ requiresApproval
444
+ };
445
+ }
446
+ };
447
+
448
+ // ../contracts/dist/store.js
449
+ import { readFile as readFile2, writeFile, mkdir, readdir as readdir2 } from "fs/promises";
450
+ import { join as join2 } from "path";
451
+ import semver3 from "semver";
452
+ var FileContractStore = class {
453
+ directory;
454
+ constructor(directory) {
455
+ this.directory = directory;
456
+ }
457
+ async ensureDir() {
458
+ try {
459
+ await mkdir(this.directory, { recursive: true });
460
+ } catch {
461
+ }
462
+ }
463
+ async listContracts(packageName) {
464
+ await this.ensureDir();
465
+ const contracts = [];
466
+ try {
467
+ const files = await readdir2(this.directory, { recursive: true });
468
+ for (const file of files) {
469
+ if (typeof file === "string" && file.endsWith(".json")) {
470
+ const fullPath = join2(this.directory, file);
471
+ try {
472
+ const content = await readFile2(fullPath, "utf8");
473
+ const parsed = JSON.parse(content);
474
+ if (!packageName || parsed.package === packageName) {
475
+ contracts.push(parsed);
476
+ }
477
+ } catch {
478
+ }
479
+ }
480
+ }
481
+ } catch {
482
+ }
483
+ return contracts;
484
+ }
485
+ async getContract(id) {
486
+ const contracts = await this.listContracts();
487
+ return contracts.find((c) => c.id === id) || null;
488
+ }
489
+ async saveContract(contract) {
490
+ await this.ensureDir();
491
+ const sanitizedPackage = contract.package.replace(/[^a-zA-Z0-9_-]/g, "_");
492
+ const sanitizedId = contract.id.replace(/[^a-zA-Z0-9_-]/g, "_");
493
+ const filePath = join2(this.directory, `${sanitizedPackage}__${sanitizedId}.json`);
494
+ await writeFile(filePath, JSON.stringify(contract, null, 2), "utf8");
495
+ }
496
+ async getActiveContracts(packageName, targetVersion) {
497
+ const all = await this.listContracts(packageName);
498
+ return all.filter((contract) => {
499
+ if (contract.introducedIn && semver3.valid(contract.introducedIn)) {
500
+ if (semver3.gt(contract.introducedIn, targetVersion)) {
501
+ return false;
502
+ }
503
+ }
504
+ if (contract.removedIn && semver3.valid(contract.removedIn)) {
505
+ if (semver3.lte(contract.removedIn, targetVersion)) {
506
+ return false;
507
+ }
508
+ }
509
+ return true;
510
+ });
511
+ }
512
+ };
513
+
514
+ // ../contracts/dist/packer.js
515
+ import { execFile } from "child_process";
516
+ import { promisify } from "util";
517
+ import { mkdtemp, rm, mkdir as mkdir2 } from "fs/promises";
518
+ import { join as join3 } from "path";
519
+ import { tmpdir } from "os";
520
+ import * as tar from "tar";
521
+ var execFileAsync = promisify(execFile);
522
+ var CandidatePacker = class {
523
+ async pack(packageDir, packageName, version) {
524
+ const tempDir = await mkdtemp(join3(tmpdir(), "verelease-candidate-"));
525
+ const tarballDest = tempDir;
526
+ const { stdout } = await execFileAsync("npm", ["pack", "--pack-destination", tarballDest], {
527
+ cwd: packageDir
528
+ });
529
+ const tarballFilename = stdout.trim().split("\n").pop().trim();
530
+ const tarballPath = join3(tarballDest, tarballFilename);
531
+ const unpackedDir = join3(tempDir, "unpacked");
532
+ await mkdir2(unpackedDir, { recursive: true });
533
+ await tar.x({
534
+ file: tarballPath,
535
+ cwd: unpackedDir,
536
+ strip: 1
537
+ // npm pack packages inside 'package/' directory
538
+ });
539
+ return {
540
+ packageName,
541
+ version,
542
+ tarballPath,
543
+ unpackedDir
544
+ };
545
+ }
546
+ async cleanup(packResult) {
547
+ try {
548
+ const parentDir = join3(packResult.unpackedDir, "..");
549
+ await rm(parentDir, { recursive: true, force: true });
550
+ } catch {
551
+ }
552
+ }
553
+ };
554
+
555
+ // ../contracts/dist/runner.js
556
+ import { mkdir as mkdir3, symlink, rm as rm2, writeFile as writeFile2, copyFile } from "fs/promises";
557
+ import { join as join4, basename } from "path";
558
+ import { tmpdir as tmpdir2 } from "os";
559
+ import { mkdtemp as mkdtemp2 } from "fs/promises";
560
+
561
+ // ../test-adapter-node/dist/node-test.js
562
+ import { spawn } from "child_process";
563
+ var NodeTestAdapter = class {
564
+ options;
565
+ name = "node:test";
566
+ constructor(options = {}) {
567
+ this.options = options;
568
+ }
569
+ async detect(ctx) {
570
+ const scripts = ctx.manifest.scripts || {};
571
+ const hasNodeTestScript = Object.values(scripts).some((s) => s.includes("node --test"));
572
+ const hasTestFiles = ctx.files.some((f) => f.endsWith(".test.js") || f.endsWith(".test.mjs") || f.endsWith(".test.ts") || f.endsWith(".test.cjs"));
573
+ if (hasNodeTestScript) {
574
+ return { supported: true, confidence: 0.95 };
575
+ }
576
+ if (hasTestFiles) {
577
+ return { supported: true, confidence: 0.7 };
578
+ }
579
+ return { supported: false, confidence: 0 };
580
+ }
581
+ async run(ctx) {
582
+ const startedAt = (/* @__PURE__ */ new Date()).toISOString();
583
+ const startTime = Date.now();
584
+ const reporter = this.options.reporter || "tap";
585
+ const loaderArgs = this.options.loaderArgs || [];
586
+ const testFiles = ctx.testFiles && ctx.testFiles.length > 0 ? ctx.testFiles : [];
587
+ const command = [
588
+ "node",
589
+ ...loaderArgs,
590
+ "--test",
591
+ `--test-reporter=${reporter}`,
592
+ ...testFiles,
593
+ ...ctx.extraArgs || []
594
+ ];
595
+ return new Promise((resolve3) => {
596
+ const cleanEnv = {
597
+ ...process.env,
598
+ ...ctx.env,
599
+ ...ctx.isolatedNodeModulesPath ? { NODE_PATH: ctx.isolatedNodeModulesPath } : {}
600
+ };
601
+ for (const k of Object.keys(cleanEnv)) {
602
+ if (k.startsWith("NODE_TEST_")) {
603
+ delete cleanEnv[k];
604
+ }
605
+ }
606
+ const child = spawn(command[0], command.slice(1), {
607
+ cwd: ctx.packagePath,
608
+ env: cleanEnv,
609
+ stdio: ["ignore", "pipe", "pipe"]
610
+ });
611
+ let stdout = "";
612
+ let stderr = "";
613
+ child.stdout?.on("data", (chunk) => {
614
+ stdout += chunk.toString();
615
+ });
616
+ child.stderr?.on("data", (chunk) => {
617
+ stderr += chunk.toString();
618
+ });
619
+ child.on("close", (code) => {
620
+ const durationMs = Date.now() - startTime;
621
+ const success = code === 0;
622
+ const { suites, total, passed, failed, skipped, diagnostics } = this.parseOutput(stdout, stderr, success);
623
+ resolve3({
624
+ adapter: this.name,
625
+ runtime: process.version,
626
+ command,
627
+ startedAt,
628
+ durationMs,
629
+ success,
630
+ suites,
631
+ diagnostics,
632
+ totalTests: total,
633
+ passedTests: passed,
634
+ failedTests: failed,
635
+ skippedTests: skipped
636
+ });
637
+ });
638
+ child.on("error", (err) => {
639
+ const durationMs = Date.now() - startTime;
640
+ resolve3({
641
+ adapter: this.name,
642
+ runtime: process.version,
643
+ command,
644
+ startedAt,
645
+ durationMs,
646
+ success: false,
647
+ suites: [],
648
+ diagnostics: [{ severity: "error", message: err.message, stack: err.stack }],
649
+ totalTests: 1,
650
+ passedTests: 0,
651
+ failedTests: 1,
652
+ skippedTests: 0
653
+ });
654
+ });
655
+ });
656
+ }
657
+ parseOutput(stdout, stderr, overallSuccess) {
658
+ const lines = stdout.split("\n");
659
+ const testCases = [];
660
+ const diagnostics = [];
661
+ let currentFailure;
662
+ let currentTestName = "";
663
+ for (let i = 0; i < lines.length; i++) {
664
+ const line = lines[i].trim();
665
+ if (line.startsWith("ok ") || line.startsWith("not ok ")) {
666
+ const isOk = line.startsWith("ok ");
667
+ const isSkipped = line.includes("# SKIP") || line.includes("# skip");
668
+ const isTodo = line.includes("# TODO") || line.includes("# todo");
669
+ let name = line.replace(/^(ok|not ok)\s+\d+\s+-?\s*/, "");
670
+ const timeMatch = name.match(/# time=([\d.]+)ms/);
671
+ const durationMs = timeMatch ? parseFloat(timeMatch[1]) : void 0;
672
+ name = name.replace(/#.*$/, "").trim();
673
+ let status = "passed";
674
+ if (isSkipped) {
675
+ status = "skipped";
676
+ } else if (isTodo) {
677
+ status = "todo";
678
+ } else if (!isOk) {
679
+ status = "failed";
680
+ }
681
+ const tc = {
682
+ name: name || `Test #${testCases.length + 1}`,
683
+ status,
684
+ durationMs
685
+ };
686
+ if (!isOk) {
687
+ const failureLines = [];
688
+ let j = i + 1;
689
+ while (j < lines.length && (lines[j].startsWith(" ") || lines[j].startsWith("---"))) {
690
+ failureLines.push(lines[j]);
691
+ j++;
692
+ }
693
+ if (failureLines.length > 0) {
694
+ tc.failure = {
695
+ message: failureLines.join("\n").trim()
696
+ };
697
+ } else {
698
+ tc.failure = {
699
+ message: "Test failed"
700
+ };
701
+ }
702
+ }
703
+ testCases.push(tc);
704
+ }
705
+ }
706
+ if (stderr.trim()) {
707
+ diagnostics.push({
708
+ severity: "warning",
709
+ message: stderr.trim()
710
+ });
711
+ }
712
+ if (testCases.length === 0) {
713
+ testCases.push({
714
+ name: "node:test execution",
715
+ status: overallSuccess ? "passed" : "failed",
716
+ failure: overallSuccess ? void 0 : {
717
+ message: stderr || stdout || "Execution failed"
718
+ }
719
+ });
720
+ }
721
+ const passed = testCases.filter((t) => t.status === "passed").length;
722
+ const failed = testCases.filter((t) => t.status === "failed").length;
723
+ const skipped = testCases.filter((t) => t.status === "skipped" || t.status === "todo").length;
724
+ const total = testCases.length;
725
+ const suite = {
726
+ name: "node:test",
727
+ status: failed === 0 && overallSuccess ? "passed" : "failed",
728
+ tests: testCases
729
+ };
730
+ return {
731
+ suites: [suite],
732
+ total,
733
+ passed,
734
+ failed,
735
+ skipped,
736
+ diagnostics
737
+ };
738
+ }
739
+ };
740
+
741
+ // ../contracts/dist/runner.js
742
+ var ContractRunner = class {
743
+ testAdapter;
744
+ constructor(testAdapter = new NodeTestAdapter()) {
745
+ this.testAdapter = testAdapter;
746
+ }
747
+ async runContract(contract, candidate) {
748
+ const startTime = Date.now();
749
+ const consumerEnvDir = await mkdtemp2(join4(tmpdir2(), "verelease-consumer-"));
750
+ const nodeModulesDir = join4(consumerEnvDir, "node_modules");
751
+ try {
752
+ await writeFile2(join4(consumerEnvDir, "package.json"), JSON.stringify({ name: "consumer-fixture", type: "module" }, null, 2), "utf8");
753
+ let targetPkgLink = join4(nodeModulesDir, candidate.packageName);
754
+ if (candidate.packageName.startsWith("@")) {
755
+ const [scope, pkgName] = candidate.packageName.split("/");
756
+ const scopeDir = join4(nodeModulesDir, scope);
757
+ await mkdir3(scopeDir, { recursive: true });
758
+ targetPkgLink = join4(scopeDir, pkgName);
759
+ } else {
760
+ await mkdir3(nodeModulesDir, { recursive: true });
761
+ }
762
+ await symlink(candidate.unpackedDir, targetPkgLink, "junction");
763
+ const isolatedTestName = basename(contract.testFile);
764
+ const isolatedTestPath = join4(consumerEnvDir, isolatedTestName);
765
+ await copyFile(contract.testFile, isolatedTestPath);
766
+ const testRun = await this.testAdapter.run({
767
+ packagePath: consumerEnvDir,
768
+ targetPackageName: candidate.packageName,
769
+ testFiles: [isolatedTestPath],
770
+ isolatedNodeModulesPath: nodeModulesDir
771
+ });
772
+ const durationMs = Date.now() - startTime;
773
+ const failed = !testRun.success || testRun.failedTests > 0;
774
+ let evidence;
775
+ if (failed) {
776
+ const failureDetails = testRun.suites[0]?.tests.find((t) => t.status === "failed")?.failure?.message || "Historical contract failed";
777
+ evidence = {
778
+ id: `contract.fail:${contract.id}`,
779
+ package: candidate.packageName,
780
+ source: "contract",
781
+ severity: contract.severity || "major",
782
+ confidence: 0.98,
783
+ title: `Historical Contract Failed: ${contract.title}`,
784
+ description: `Contract "${contract.id}" (${contract.category}) failed against candidate package.
785
+ Details: ${failureDetails}`,
786
+ files: [contract.testFile],
787
+ contracts: [contract.id],
788
+ metadata: {
789
+ contractId: contract.id,
790
+ introducedIn: contract.introducedIn,
791
+ category: contract.category,
792
+ diagnostics: testRun.diagnostics
793
+ }
794
+ };
795
+ }
796
+ return {
797
+ contract,
798
+ status: failed ? "failed" : "passed",
799
+ testResult: testRun.suites[0]?.tests[0],
800
+ evidence,
801
+ durationMs
802
+ };
803
+ } finally {
804
+ try {
805
+ await rm2(consumerEnvDir, { recursive: true, force: true });
806
+ } catch {
807
+ }
808
+ }
809
+ }
810
+ };
811
+
812
+ // ../contracts/dist/analyzer.js
813
+ var ContractCompatibilityAnalyzer = class {
814
+ store;
815
+ runner;
816
+ packer;
817
+ name = "contract-compatibility-analyzer";
818
+ constructor(store, runner = new ContractRunner(), packer = new CandidatePacker()) {
819
+ this.store = store;
820
+ this.runner = runner;
821
+ this.packer = packer;
822
+ }
823
+ async analyze(context) {
824
+ const activeContracts = await this.store.getActiveContracts(context.packageName, context.currentVersion);
825
+ if (activeContracts.length === 0) {
826
+ return [];
827
+ }
828
+ const packResult = await this.packer.pack(context.packagePath, context.packageName, context.currentVersion);
829
+ const evidenceList = [];
830
+ try {
831
+ for (const contract of activeContracts) {
832
+ const result = await this.runner.runContract(contract, packResult);
833
+ if (result.evidence) {
834
+ evidenceList.push(result.evidence);
835
+ }
836
+ }
837
+ } finally {
838
+ await this.packer.cleanup(packResult);
839
+ }
840
+ return evidenceList;
841
+ }
842
+ };
843
+
844
+ // ../api-diff/dist/extractor.js
845
+ import ts from "typescript";
846
+ var ApiExtractor = class {
847
+ extractFromSource(sourceCode, fileName = "index.ts") {
848
+ const sourceFile = ts.createSourceFile(fileName, sourceCode, ts.ScriptTarget.Latest, true, ts.ScriptKind.TS);
849
+ const exports = {};
850
+ const visit = (node) => {
851
+ const modifiers = ts.canHaveModifiers(node) ? ts.getModifiers(node) : void 0;
852
+ const isExported = (ts.getCombinedModifierFlags(node) & ts.ModifierFlags.Export) !== 0 || !!modifiers?.some((m) => m.kind === ts.SyntaxKind.ExportKeyword);
853
+ if (ts.isFunctionDeclaration(node) && node.name && isExported) {
854
+ const fnName = node.name.text;
855
+ const parameters = node.parameters.map((param) => {
856
+ return {
857
+ name: param.name.getText(sourceFile),
858
+ isOptional: !!param.questionToken || !!param.initializer,
859
+ typeString: param.type ? param.type.getText(sourceFile) : "any"
860
+ };
861
+ });
862
+ exports[fnName] = {
863
+ kind: "function",
864
+ name: fnName,
865
+ parameters,
866
+ returnType: node.type ? node.type.getText(sourceFile) : "void",
867
+ isAsync: !!modifiers?.some((m) => m.kind === ts.SyntaxKind.AsyncKeyword)
868
+ };
869
+ } else if (ts.isVariableStatement(node) && isExported) {
870
+ for (const decl of node.declarationList.declarations) {
871
+ if (ts.isIdentifier(decl.name)) {
872
+ const varName = decl.name.text;
873
+ exports[varName] = {
874
+ kind: "variable",
875
+ name: varName,
876
+ typeString: decl.type ? decl.type.getText(sourceFile) : "any"
877
+ };
878
+ }
879
+ }
880
+ } else if (ts.isClassDeclaration(node) && node.name && isExported) {
881
+ const className = node.name.text;
882
+ const methods = {};
883
+ const properties = {};
884
+ for (const member of node.members) {
885
+ if (ts.isMethodDeclaration(member) && member.name) {
886
+ const methodName = member.name.getText(sourceFile);
887
+ const memberModifiers = ts.canHaveModifiers(member) ? ts.getModifiers(member) : void 0;
888
+ methods[methodName] = {
889
+ kind: "function",
890
+ name: methodName,
891
+ parameters: member.parameters.map((p) => ({
892
+ name: p.name.getText(sourceFile),
893
+ isOptional: !!p.questionToken || !!p.initializer,
894
+ typeString: p.type ? p.type.getText(sourceFile) : "any"
895
+ })),
896
+ returnType: member.type ? member.type.getText(sourceFile) : "void",
897
+ isAsync: !!memberModifiers?.some((m) => m.kind === ts.SyntaxKind.AsyncKeyword)
898
+ };
899
+ } else if (ts.isPropertyDeclaration(member) && member.name) {
900
+ const propName = member.name.getText(sourceFile);
901
+ properties[propName] = {
902
+ name: propName,
903
+ isOptional: !!member.questionToken,
904
+ typeString: member.type ? member.type.getText(sourceFile) : "any"
905
+ };
906
+ }
907
+ }
908
+ exports[className] = {
909
+ kind: "class",
910
+ name: className,
911
+ methods,
912
+ properties
913
+ };
914
+ } else if (ts.isInterfaceDeclaration(node) && node.name && isExported) {
915
+ const ifaceName = node.name.text;
916
+ const properties = {};
917
+ for (const member of node.members) {
918
+ if (ts.isPropertySignature(member) && member.name) {
919
+ const propName = member.name.getText(sourceFile);
920
+ properties[propName] = {
921
+ name: propName,
922
+ isOptional: !!member.questionToken,
923
+ typeString: member.type ? member.type.getText(sourceFile) : "any"
924
+ };
925
+ }
926
+ }
927
+ exports[ifaceName] = {
928
+ kind: "interface",
929
+ name: ifaceName,
930
+ properties
931
+ };
932
+ }
933
+ ts.forEachChild(node, visit);
934
+ };
935
+ ts.forEachChild(sourceFile, visit);
936
+ return { exports };
937
+ }
938
+ };
939
+
940
+ // ../api-diff/dist/diff.js
941
+ var ApiDiffEngine = class {
942
+ diff(packageName, baseline, candidate) {
943
+ const evidence = [];
944
+ const baselineExports = baseline.exports;
945
+ const candidateExports = candidate.exports;
946
+ for (const [name, baseSym] of Object.entries(baselineExports)) {
947
+ if (!candidateExports[name]) {
948
+ evidence.push({
949
+ id: `api.export.removed:${name}`,
950
+ package: packageName,
951
+ source: "api",
952
+ severity: "major",
953
+ confidence: 1,
954
+ title: `Public export removed: ${name}`,
955
+ description: `Exported ${baseSym.kind} "${name}" was removed from the public API surface.`
956
+ });
957
+ continue;
958
+ }
959
+ const candSym = candidateExports[name];
960
+ if (baseSym.kind !== candSym.kind) {
961
+ evidence.push({
962
+ id: `api.export.kindChanged:${name}`,
963
+ package: packageName,
964
+ source: "api",
965
+ severity: "major",
966
+ confidence: 1,
967
+ title: `Public export kind changed: ${name}`,
968
+ description: `Export "${name}" changed from ${baseSym.kind} to ${candSym.kind}.`
969
+ });
970
+ continue;
971
+ }
972
+ if (baseSym.kind === "function" && candSym.kind === "function") {
973
+ this.diffFunction(packageName, name, baseSym, candSym, evidence);
974
+ } else if (baseSym.kind === "interface" && candSym.kind === "interface") {
975
+ this.diffInterface(packageName, name, baseSym, candSym, evidence);
976
+ }
977
+ }
978
+ for (const [name, candSym] of Object.entries(candidateExports)) {
979
+ if (!baselineExports[name]) {
980
+ evidence.push({
981
+ id: `api.export.added:${name}`,
982
+ package: packageName,
983
+ source: "api",
984
+ severity: "minor",
985
+ confidence: 0.95,
986
+ title: `New public export added: ${name}`,
987
+ description: `New ${candSym.kind} "${name}" added to the public API surface.`
988
+ });
989
+ }
990
+ }
991
+ return evidence;
992
+ }
993
+ diffFunction(packageName, fnName, baseFn, candFn, evidence) {
994
+ const baseParams = baseFn.parameters;
995
+ const candParams = candFn.parameters;
996
+ if (candParams.length < baseParams.length) {
997
+ evidence.push({
998
+ id: `api.function.paramRemoved:${fnName}`,
999
+ package: packageName,
1000
+ source: "api",
1001
+ severity: "major",
1002
+ confidence: 0.98,
1003
+ title: `Parameter removed in function: ${fnName}`,
1004
+ description: `Function "${fnName}" parameter count decreased from ${baseParams.length} to ${candParams.length}.`
1005
+ });
1006
+ return;
1007
+ }
1008
+ for (let i = baseParams.length; i < candParams.length; i++) {
1009
+ const addedParam = candParams[i];
1010
+ if (!addedParam.isOptional) {
1011
+ evidence.push({
1012
+ id: `api.function.requiredParamAdded:${fnName}:${addedParam.name}`,
1013
+ package: packageName,
1014
+ source: "api",
1015
+ severity: "major",
1016
+ confidence: 0.98,
1017
+ title: `Required parameter added to function: ${fnName}`,
1018
+ description: `Function "${fnName}" added a required parameter "${addedParam.name}". Existing calls with fewer arguments will fail.`
1019
+ });
1020
+ } else {
1021
+ evidence.push({
1022
+ id: `api.function.optionalParamAdded:${fnName}:${addedParam.name}`,
1023
+ package: packageName,
1024
+ source: "api",
1025
+ severity: "minor",
1026
+ confidence: 0.95,
1027
+ title: `Optional parameter added to function: ${fnName}`,
1028
+ description: `Function "${fnName}" added an optional parameter "${addedParam.name}".`
1029
+ });
1030
+ }
1031
+ }
1032
+ for (let i = 0; i < baseParams.length; i++) {
1033
+ const baseP = baseParams[i];
1034
+ const candP = candParams[i];
1035
+ if (baseP.isOptional && !candP.isOptional) {
1036
+ evidence.push({
1037
+ id: `api.function.paramBecameRequired:${fnName}:${candP.name}`,
1038
+ package: packageName,
1039
+ source: "api",
1040
+ severity: "major",
1041
+ confidence: 0.98,
1042
+ title: `Parameter became required in function: ${fnName}`,
1043
+ description: `Parameter "${candP.name}" of function "${fnName}" was optional and is now required.`
1044
+ });
1045
+ } else if (baseP.typeString !== candP.typeString && baseP.typeString !== "any" && candP.typeString !== "any") {
1046
+ evidence.push({
1047
+ id: `api.function.paramTypeChanged:${fnName}:${candP.name}`,
1048
+ package: packageName,
1049
+ source: "api",
1050
+ severity: "major",
1051
+ confidence: 0.9,
1052
+ title: `Parameter type changed in function: ${fnName}`,
1053
+ description: `Parameter "${candP.name}" in function "${fnName}" changed type from "${baseP.typeString}" to "${candP.typeString}".`
1054
+ });
1055
+ }
1056
+ }
1057
+ }
1058
+ diffInterface(packageName, ifaceName, baseIface, candIface, evidence) {
1059
+ for (const [propName, prop] of Object.entries(baseIface.properties)) {
1060
+ if (!candIface.properties[propName]) {
1061
+ evidence.push({
1062
+ id: `api.interface.propertyRemoved:${ifaceName}:${propName}`,
1063
+ package: packageName,
1064
+ source: "types",
1065
+ severity: "major",
1066
+ confidence: 0.95,
1067
+ title: `Property removed from interface: ${ifaceName}.${propName}`,
1068
+ description: `Interface "${ifaceName}" removed property "${propName}".`
1069
+ });
1070
+ }
1071
+ }
1072
+ for (const [propName, prop] of Object.entries(candIface.properties)) {
1073
+ if (!baseIface.properties[propName]) {
1074
+ if (!prop.isOptional) {
1075
+ evidence.push({
1076
+ id: `api.interface.requiredPropertyAdded:${ifaceName}:${propName}`,
1077
+ package: packageName,
1078
+ source: "types",
1079
+ severity: "major",
1080
+ confidence: 0.95,
1081
+ title: `Required property added to interface: ${ifaceName}.${propName}`,
1082
+ description: `Interface "${ifaceName}" added required property "${propName}". Consumers implementing this interface will fail.`
1083
+ });
1084
+ } else {
1085
+ evidence.push({
1086
+ id: `api.interface.optionalPropertyAdded:${ifaceName}:${propName}`,
1087
+ package: packageName,
1088
+ source: "types",
1089
+ severity: "minor",
1090
+ confidence: 0.9,
1091
+ title: `Optional property added to interface: ${ifaceName}.${propName}`,
1092
+ description: `Interface "${ifaceName}" added optional property "${propName}".`
1093
+ });
1094
+ }
1095
+ }
1096
+ }
1097
+ }
1098
+ };
1099
+
1100
+ // ../api-diff/dist/analyzer.js
1101
+ import { readFile as readFile3, stat as stat2 } from "fs/promises";
1102
+ import { join as join5 } from "path";
1103
+ async function fileExists2(path) {
1104
+ try {
1105
+ const s = await stat2(path);
1106
+ return s.isFile();
1107
+ } catch {
1108
+ return false;
1109
+ }
1110
+ }
1111
+ var ApiDiffAnalyzer = class {
1112
+ extractor;
1113
+ engine;
1114
+ name = "api-diff-analyzer";
1115
+ constructor(extractor = new ApiExtractor(), engine = new ApiDiffEngine()) {
1116
+ this.extractor = extractor;
1117
+ this.engine = engine;
1118
+ }
1119
+ async analyze(context) {
1120
+ const candidateEntrypoint = await this.findEntrypoint(context.packagePath);
1121
+ if (!candidateEntrypoint) {
1122
+ return [];
1123
+ }
1124
+ const candidateSource = await readFile3(candidateEntrypoint, "utf8");
1125
+ const candidateSnapshot = this.extractor.extractFromSource(candidateSource, candidateEntrypoint);
1126
+ let baselineSnapshot;
1127
+ if (context.baselinePath && await fileExists2(context.baselinePath)) {
1128
+ const baseSource = await readFile3(context.baselinePath, "utf8");
1129
+ if (context.baselinePath.endsWith(".json")) {
1130
+ baselineSnapshot = JSON.parse(baseSource);
1131
+ } else {
1132
+ baselineSnapshot = this.extractor.extractFromSource(baseSource, context.baselinePath);
1133
+ }
1134
+ }
1135
+ if (!baselineSnapshot) {
1136
+ return [];
1137
+ }
1138
+ return this.engine.diff(context.packageName, baselineSnapshot, candidateSnapshot);
1139
+ }
1140
+ async findEntrypoint(pkgDir) {
1141
+ const candidates = [
1142
+ join5(pkgDir, "src", "index.ts"),
1143
+ join5(pkgDir, "src", "index.js"),
1144
+ join5(pkgDir, "index.ts"),
1145
+ join5(pkgDir, "index.js"),
1146
+ join5(pkgDir, "dist", "index.d.ts")
1147
+ ];
1148
+ for (const c of candidates) {
1149
+ if (await fileExists2(c)) {
1150
+ return c;
1151
+ }
1152
+ }
1153
+ return null;
1154
+ }
1155
+ };
1156
+
1157
+ // ../manifest/dist/mutator.js
1158
+ import { readFile as readFile4, writeFile as writeFile3, stat as stat3 } from "fs/promises";
1159
+ import { join as join6 } from "path";
1160
+ async function fileExists3(path) {
1161
+ try {
1162
+ const s = await stat3(path);
1163
+ return s.isFile();
1164
+ } catch {
1165
+ return false;
1166
+ }
1167
+ }
1168
+ var TransactionalManifestMutator = class {
1169
+ async applyPlan(plan) {
1170
+ const backups = [];
1171
+ const modifiedFiles = [];
1172
+ const filesToTouch = /* @__PURE__ */ new Set();
1173
+ for (const pkgPlan of plan.packages) {
1174
+ if (pkgPlan.bump !== "none") {
1175
+ const pkgJson = join6(pkgPlan.directory, "package.json");
1176
+ const jsrJson = join6(pkgPlan.directory, "jsr.json");
1177
+ const denoJson = join6(pkgPlan.directory, "deno.json");
1178
+ if (await fileExists3(pkgJson))
1179
+ filesToTouch.add(pkgJson);
1180
+ if (await fileExists3(jsrJson))
1181
+ filesToTouch.add(jsrJson);
1182
+ if (await fileExists3(denoJson))
1183
+ filesToTouch.add(denoJson);
1184
+ }
1185
+ for (const update of pkgPlan.dependentUpdates) {
1186
+ const depPkgPlan = plan.packages.find((p) => p.name === update.dependentName);
1187
+ if (depPkgPlan) {
1188
+ const depPkgJson = join6(depPkgPlan.directory, "package.json");
1189
+ if (await fileExists3(depPkgJson))
1190
+ filesToTouch.add(depPkgJson);
1191
+ }
1192
+ }
1193
+ }
1194
+ for (const filePath of filesToTouch) {
1195
+ const originalContent = await readFile4(filePath, "utf8");
1196
+ backups.push({ filePath, originalContent });
1197
+ }
1198
+ try {
1199
+ const versionMap = /* @__PURE__ */ new Map();
1200
+ for (const pkgPlan of plan.packages) {
1201
+ if (pkgPlan.bump !== "none") {
1202
+ versionMap.set(pkgPlan.name, pkgPlan.proposedVersion);
1203
+ }
1204
+ }
1205
+ const depUpdateMap = /* @__PURE__ */ new Map();
1206
+ for (const pkgPlan of plan.packages) {
1207
+ for (const depUp of pkgPlan.dependentUpdates) {
1208
+ if (!depUpdateMap.has(depUp.dependentName)) {
1209
+ depUpdateMap.set(depUp.dependentName, []);
1210
+ }
1211
+ depUpdateMap.get(depUp.dependentName).push({
1212
+ dependencyName: depUp.dependencyName,
1213
+ newRange: depUp.newRange,
1214
+ type: depUp.dependencyType
1215
+ });
1216
+ }
1217
+ }
1218
+ for (const pkgPlan of plan.packages) {
1219
+ const pkgJsonPath = join6(pkgPlan.directory, "package.json");
1220
+ if (filesToTouch.has(pkgJsonPath)) {
1221
+ const content = await readFile4(pkgJsonPath, "utf8");
1222
+ const parsed = JSON.parse(content);
1223
+ if (versionMap.has(pkgPlan.name)) {
1224
+ parsed.version = versionMap.get(pkgPlan.name);
1225
+ }
1226
+ const depUpdates = depUpdateMap.get(pkgPlan.name);
1227
+ if (depUpdates) {
1228
+ for (const up of depUpdates) {
1229
+ const sec = parsed[up.type];
1230
+ if (sec && sec[up.dependencyName]) {
1231
+ sec[up.dependencyName] = up.newRange;
1232
+ }
1233
+ }
1234
+ }
1235
+ await writeFile3(pkgJsonPath, JSON.stringify(parsed, null, 2) + "\n", "utf8");
1236
+ modifiedFiles.push(pkgJsonPath);
1237
+ }
1238
+ const jsrJsonPath = join6(pkgPlan.directory, "jsr.json");
1239
+ if (filesToTouch.has(jsrJsonPath)) {
1240
+ const content = await readFile4(jsrJsonPath, "utf8");
1241
+ const parsed = JSON.parse(content);
1242
+ if (versionMap.has(pkgPlan.name)) {
1243
+ parsed.version = versionMap.get(pkgPlan.name);
1244
+ }
1245
+ await writeFile3(jsrJsonPath, JSON.stringify(parsed, null, 2) + "\n", "utf8");
1246
+ modifiedFiles.push(jsrJsonPath);
1247
+ }
1248
+ const denoJsonPath = join6(pkgPlan.directory, "deno.json");
1249
+ if (filesToTouch.has(denoJsonPath)) {
1250
+ const content = await readFile4(denoJsonPath, "utf8");
1251
+ const parsed = JSON.parse(content);
1252
+ if (versionMap.has(pkgPlan.name)) {
1253
+ parsed.version = versionMap.get(pkgPlan.name);
1254
+ }
1255
+ await writeFile3(denoJsonPath, JSON.stringify(parsed, null, 2) + "\n", "utf8");
1256
+ modifiedFiles.push(denoJsonPath);
1257
+ }
1258
+ }
1259
+ } catch (err) {
1260
+ for (const b of backups) {
1261
+ await writeFile3(b.filePath, b.originalContent, "utf8");
1262
+ }
1263
+ throw err;
1264
+ }
1265
+ const transaction = {
1266
+ id: `tx-${Date.now()}`,
1267
+ plan,
1268
+ backups,
1269
+ modifiedFiles,
1270
+ appliedAt: (/* @__PURE__ */ new Date()).toISOString(),
1271
+ async rollback() {
1272
+ for (const b of backups) {
1273
+ await writeFile3(b.filePath, b.originalContent, "utf8");
1274
+ }
1275
+ },
1276
+ async commit() {
1277
+ }
1278
+ };
1279
+ return transaction;
1280
+ }
1281
+ };
1282
+
1283
+ // ../manifest/dist/lockfile.js
1284
+ import { execFile as execFile2 } from "child_process";
1285
+ import { promisify as promisify2 } from "util";
1286
+ import { stat as stat4 } from "fs/promises";
1287
+ import { join as join7 } from "path";
1288
+ var execFileAsync2 = promisify2(execFile2);
1289
+ async function fileExists4(path) {
1290
+ try {
1291
+ const s = await stat4(path);
1292
+ return s.isFile();
1293
+ } catch {
1294
+ return false;
1295
+ }
1296
+ }
1297
+ var PnpmLockfileAdapter = class {
1298
+ packageManager = "pnpm";
1299
+ async regenerateLockfile(rootDirectory) {
1300
+ const start = Date.now();
1301
+ try {
1302
+ const { stdout, stderr } = await execFileAsync2("pnpm", ["install", "--lockfile-only"], {
1303
+ cwd: rootDirectory
1304
+ });
1305
+ return {
1306
+ success: true,
1307
+ output: (stdout + "\n" + stderr).trim(),
1308
+ durationMs: Date.now() - start
1309
+ };
1310
+ } catch (err) {
1311
+ return {
1312
+ success: false,
1313
+ output: err.message || String(err),
1314
+ durationMs: Date.now() - start
1315
+ };
1316
+ }
1317
+ }
1318
+ };
1319
+ var NpmLockfileAdapter = class {
1320
+ packageManager = "npm";
1321
+ async regenerateLockfile(rootDirectory) {
1322
+ const start = Date.now();
1323
+ try {
1324
+ const { stdout, stderr } = await execFileAsync2("npm", ["install", "--package-lock-only"], {
1325
+ cwd: rootDirectory
1326
+ });
1327
+ return {
1328
+ success: true,
1329
+ output: (stdout + "\n" + stderr).trim(),
1330
+ durationMs: Date.now() - start
1331
+ };
1332
+ } catch (err) {
1333
+ return {
1334
+ success: false,
1335
+ output: err.message || String(err),
1336
+ durationMs: Date.now() - start
1337
+ };
1338
+ }
1339
+ }
1340
+ };
1341
+ var AutoLockfileAdapter = class {
1342
+ packageManager = "npm";
1343
+ async regenerateLockfile(rootDirectory) {
1344
+ if (await fileExists4(join7(rootDirectory, "pnpm-lock.yaml"))) {
1345
+ this.packageManager = "pnpm";
1346
+ return new PnpmLockfileAdapter().regenerateLockfile(rootDirectory);
1347
+ }
1348
+ if (await fileExists4(join7(rootDirectory, "package-lock.json"))) {
1349
+ this.packageManager = "npm";
1350
+ return new NpmLockfileAdapter().regenerateLockfile(rootDirectory);
1351
+ }
1352
+ return new NpmLockfileAdapter().regenerateLockfile(rootDirectory);
1353
+ }
1354
+ };
1355
+
1356
+ // ../publisher-npm/dist/publisher.js
1357
+ import { execFile as execFile3, spawn as spawn2 } from "child_process";
1358
+ import { promisify as promisify3 } from "util";
1359
+ var execFileAsync3 = promisify3(execFile3);
1360
+ function openBrowser(url) {
1361
+ const platform = process.platform;
1362
+ try {
1363
+ if (platform === "darwin") {
1364
+ execFile3("open", [url]);
1365
+ } else if (platform === "win32") {
1366
+ execFile3("cmd", ["/c", "start", '""', url]);
1367
+ } else {
1368
+ execFile3("xdg-open", [url]);
1369
+ }
1370
+ } catch {
1371
+ }
1372
+ }
1373
+ async function pollForWebAuthToken(doneUrl, timeoutMs = 9e4) {
1374
+ const start = Date.now();
1375
+ const pollIntervalMs = 1500;
1376
+ while (Date.now() - start < timeoutMs) {
1377
+ try {
1378
+ const res = await fetch(doneUrl, {
1379
+ headers: { "user-agent": "verelease-npm-publisher" }
1380
+ });
1381
+ if (res.status === 200) {
1382
+ const json = await res.json();
1383
+ if (json && json.token) {
1384
+ return json.token;
1385
+ }
1386
+ }
1387
+ } catch {
1388
+ }
1389
+ await new Promise((resolve3) => setTimeout(resolve3, pollIntervalMs));
1390
+ }
1391
+ return null;
1392
+ }
1393
+ var NpmPublishProvider = class {
1394
+ options;
1395
+ name = "npm";
1396
+ constructor(options = {}) {
1397
+ this.options = options;
1398
+ }
1399
+ getDistTag(channel) {
1400
+ if (!channel || channel === "stable") {
1401
+ return "latest";
1402
+ }
1403
+ return channel;
1404
+ }
1405
+ async prepare(ctx) {
1406
+ try {
1407
+ await execFileAsync3("npm", ["pack", "--dry-run"], {
1408
+ cwd: ctx.packagePlan.directory
1409
+ });
1410
+ } catch (err) {
1411
+ throw new Error(`Failed packing verification for package ${ctx.packagePlan.name}: ${err.message || String(err)}`);
1412
+ }
1413
+ }
1414
+ async publish(ctx) {
1415
+ const startTime = Date.now();
1416
+ const distTag = ctx.tag || this.getDistTag(ctx.packagePlan.channel);
1417
+ const args = ["publish", "--tag", distTag];
1418
+ if (ctx.dryRun) {
1419
+ args.push("--dry-run");
1420
+ }
1421
+ const access = ctx.access || this.options.defaultAccess || "public";
1422
+ args.push("--access", access);
1423
+ const hasOidc = !!(process.env.ACTIONS_ID_TOKEN_REQUEST_URL || process.env.ACTIONS_ID_TOKEN_REQUEST_TOKEN);
1424
+ const useProvenance = ctx.provenance ?? this.options.provenance ?? hasOidc;
1425
+ if (useProvenance) {
1426
+ args.push("--provenance");
1427
+ }
1428
+ if (ctx.registryUrl) {
1429
+ args.push("--registry", ctx.registryUrl);
1430
+ }
1431
+ if (ctx.extraArgs) {
1432
+ args.push(...ctx.extraArgs);
1433
+ }
1434
+ const isInteractive = this.options.interactive ?? (!ctx.dryRun && !process.env.CI && process.stdin.isTTY);
1435
+ if (isInteractive) {
1436
+ console.log(`
1437
+ \u{1F510} Interactive terminal detected for npm publish:`);
1438
+ console.log(` \u2022 WebAuthn / Passkey / Touch ID: press ENTER when prompted to open browser.`);
1439
+ console.log(` \u2022 Authenticator App: enter your 6-digit TOTP code if prompted.
1440
+ `);
1441
+ return new Promise((resolve3) => {
1442
+ const child = spawn2("npm", args, {
1443
+ cwd: ctx.packagePlan.directory,
1444
+ stdio: "inherit"
1445
+ });
1446
+ child.on("close", (code) => {
1447
+ if (code === 0) {
1448
+ resolve3({
1449
+ provider: this.name,
1450
+ packageName: ctx.packagePlan.name,
1451
+ version: ctx.packagePlan.proposedVersion,
1452
+ published: true,
1453
+ dryRun: ctx.dryRun,
1454
+ distTag,
1455
+ durationMs: Date.now() - startTime,
1456
+ output: "Interactive publish completed successfully."
1457
+ });
1458
+ } else {
1459
+ resolve3({
1460
+ provider: this.name,
1461
+ packageName: ctx.packagePlan.name,
1462
+ version: ctx.packagePlan.proposedVersion,
1463
+ published: false,
1464
+ dryRun: ctx.dryRun,
1465
+ distTag,
1466
+ durationMs: Date.now() - startTime,
1467
+ output: "",
1468
+ error: `npm publish exited with code ${code} (2FA authentication failed, timed out, or was aborted)`
1469
+ });
1470
+ }
1471
+ });
1472
+ child.on("error", (err) => {
1473
+ resolve3({
1474
+ provider: this.name,
1475
+ packageName: ctx.packagePlan.name,
1476
+ version: ctx.packagePlan.proposedVersion,
1477
+ published: false,
1478
+ dryRun: ctx.dryRun,
1479
+ distTag,
1480
+ durationMs: Date.now() - startTime,
1481
+ output: "",
1482
+ error: err.message
1483
+ });
1484
+ });
1485
+ });
1486
+ }
1487
+ try {
1488
+ const { stdout, stderr } = await execFileAsync3("npm", args, {
1489
+ cwd: ctx.packagePlan.directory
1490
+ });
1491
+ return {
1492
+ provider: this.name,
1493
+ packageName: ctx.packagePlan.name,
1494
+ version: ctx.packagePlan.proposedVersion,
1495
+ published: true,
1496
+ dryRun: ctx.dryRun,
1497
+ distTag,
1498
+ durationMs: Date.now() - startTime,
1499
+ output: (stdout + "\n" + stderr).trim()
1500
+ };
1501
+ } catch (err) {
1502
+ const combinedOutput = `${err.stdout || ""}
1503
+ ${err.stderr || ""}
1504
+ ${err.message || ""}`;
1505
+ const authUrlMatch = combinedOutput.match(/https:\/\/www\.npmjs\.com\/auth\/cli\/[^\s\x1b"']+/);
1506
+ const doneUrlMatch = combinedOutput.match(/https:\/\/registry\.npmjs\.org\/-\/v1\/done\?authId=[^\s\x1b"']+/);
1507
+ if (authUrlMatch && doneUrlMatch && !ctx.dryRun) {
1508
+ const authUrl = authUrlMatch[0];
1509
+ const doneUrl = doneUrlMatch[0];
1510
+ console.log(`
1511
+ \x1B[36m\u{1F511} WebAuthn / Security Key 2FA Detected!\x1B[0m`);
1512
+ console.log(` Your npm account uses Touch ID / security key (WebAuthn) instead of a 6-digit code.`);
1513
+ console.log(` Opening browser to authenticate:`);
1514
+ console.log(` \u{1F449} \x1B[4m${authUrl}\x1B[0m
1515
+ `);
1516
+ openBrowser(authUrl);
1517
+ console.log(`\u23F3 Waiting for Touch ID / security key approval in your browser (up to 90s)...`);
1518
+ const token = await pollForWebAuthToken(doneUrl, 9e4);
1519
+ if (token) {
1520
+ console.log(`\x1B[32m\u2713 Touch ID / Passkey approved! Completing publish...\x1B[0m
1521
+ `);
1522
+ return this.publish({
1523
+ ...ctx,
1524
+ extraArgs: [...ctx.extraArgs || [], "--otp", token]
1525
+ });
1526
+ } else {
1527
+ console.error(`\x1B[31m\u274C WebAuthn approval timed out or was cancelled.\x1B[0m
1528
+ `);
1529
+ }
1530
+ }
1531
+ return {
1532
+ provider: this.name,
1533
+ packageName: ctx.packagePlan.name,
1534
+ version: ctx.packagePlan.proposedVersion,
1535
+ published: false,
1536
+ dryRun: ctx.dryRun,
1537
+ distTag,
1538
+ durationMs: Date.now() - startTime,
1539
+ output: err.stdout || "",
1540
+ error: err.message || String(err)
1541
+ };
1542
+ }
1543
+ }
1544
+ async getPublishedVersions(packageName) {
1545
+ try {
1546
+ const { stdout } = await execFileAsync3("npm", ["view", packageName, "versions", "--json"]);
1547
+ const parsed = JSON.parse(stdout.trim());
1548
+ if (Array.isArray(parsed)) {
1549
+ return parsed;
1550
+ }
1551
+ if (typeof parsed === "string") {
1552
+ return [parsed];
1553
+ }
1554
+ return [];
1555
+ } catch {
1556
+ return [];
1557
+ }
1558
+ }
1559
+ };
1560
+
1561
+ // ../config/dist/config.js
1562
+ import { stat as stat5 } from "fs/promises";
1563
+ import { join as join8 } from "path";
1564
+ import { pathToFileURL } from "url";
1565
+ async function fileExists5(path) {
1566
+ try {
1567
+ const s = await stat5(path);
1568
+ return s.isFile();
1569
+ } catch {
1570
+ return false;
1571
+ }
1572
+ }
1573
+ async function loadConfig(rootDir) {
1574
+ const candidateNames = [
1575
+ "verelease.config.ts",
1576
+ "verelease.config.mts",
1577
+ "verelease.config.js",
1578
+ "verelease.config.mjs",
1579
+ "autoversion.config.ts",
1580
+ "autoversion.config.mts",
1581
+ "autoversion.config.js",
1582
+ "autoversion.config.mjs"
1583
+ ];
1584
+ for (const name of candidateNames) {
1585
+ const fullPath = join8(rootDir, name);
1586
+ if (await fileExists5(fullPath)) {
1587
+ try {
1588
+ const fileUrl = pathToFileURL(fullPath).href;
1589
+ const mod = await import(fileUrl);
1590
+ return mod.default || mod;
1591
+ } catch {
1592
+ }
1593
+ }
1594
+ }
1595
+ return {
1596
+ workspace: { mode: "auto" },
1597
+ versioning: { strategy: "independent" },
1598
+ contracts: { directory: ".verelease/contracts" },
1599
+ releases: { channels: ["stable", "alpha", "beta", "rc"] },
1600
+ publish: [{ provider: "npm", access: "public" }]
1601
+ };
1602
+ }
1603
+
1604
+ // ../ai/dist/schemas.js
1605
+ import { z } from "zod";
1606
+ var ChangelogSchema = z.object({
1607
+ breakingChanges: z.array(z.string()).default([]),
1608
+ added: z.array(z.string()).default([]),
1609
+ fixed: z.array(z.string()).default([]),
1610
+ migrationSummary: z.string().optional()
1611
+ });
1612
+ var MigrationGuideSchema = z.object({
1613
+ summary: z.string(),
1614
+ breakingChanges: z.array(z.object({
1615
+ title: z.string(),
1616
+ explanation: z.string(),
1617
+ before: z.string().optional(),
1618
+ after: z.string().optional(),
1619
+ automatable: z.boolean().default(false)
1620
+ })).default([]),
1621
+ manualSteps: z.array(z.string()).default([]),
1622
+ warnings: z.array(z.string()).default([])
1623
+ });
1624
+ var MigrationScriptSchema = z.object({
1625
+ description: z.string(),
1626
+ scriptContent: z.string(),
1627
+ fileExtension: z.enum(["ts", "js"]).default("js")
1628
+ });
1629
+
1630
+ // ../ai/dist/changelog.js
1631
+ function renderChangelogMarkdown(version, date, data) {
1632
+ const parts = [`# ${version} (${date})`, ""];
1633
+ if (data.breakingChanges.length > 0) {
1634
+ parts.push("## \u26A0\uFE0F Breaking Changes");
1635
+ for (const item of data.breakingChanges) {
1636
+ parts.push(`- ${item}`);
1637
+ }
1638
+ parts.push("");
1639
+ }
1640
+ if (data.added.length > 0) {
1641
+ parts.push("## \u2728 Added");
1642
+ for (const item of data.added) {
1643
+ parts.push(`- ${item}`);
1644
+ }
1645
+ parts.push("");
1646
+ }
1647
+ if (data.fixed.length > 0) {
1648
+ parts.push("## \u{1F41B} Fixed");
1649
+ for (const item of data.fixed) {
1650
+ parts.push(`- ${item}`);
1651
+ }
1652
+ parts.push("");
1653
+ }
1654
+ if (data.migrationSummary) {
1655
+ parts.push("## \u{1F4D6} Migration");
1656
+ parts.push(data.migrationSummary);
1657
+ parts.push("");
1658
+ }
1659
+ return parts.join("\n");
1660
+ }
1661
+ function synthesizeChangelogFromEvidence(input) {
1662
+ const date = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
1663
+ const breaking = [];
1664
+ const added = [];
1665
+ const fixed = [];
1666
+ for (const ev of input.evidence) {
1667
+ if (ev.severity === "major") {
1668
+ breaking.push(`${ev.title}: ${ev.description}`);
1669
+ } else if (ev.severity === "minor") {
1670
+ added.push(`${ev.title}: ${ev.description}`);
1671
+ } else if (ev.severity === "patch") {
1672
+ fixed.push(`${ev.title}: ${ev.description}`);
1673
+ }
1674
+ }
1675
+ if (input.commits) {
1676
+ for (const commit of input.commits) {
1677
+ const msg = commit.message.toLowerCase();
1678
+ if (msg.startsWith("feat")) {
1679
+ added.push(commit.message);
1680
+ } else if (msg.startsWith("fix")) {
1681
+ fixed.push(commit.message);
1682
+ }
1683
+ }
1684
+ }
1685
+ const structured = {
1686
+ breakingChanges: Array.from(new Set(breaking)),
1687
+ added: Array.from(new Set(added)),
1688
+ fixed: Array.from(new Set(fixed)),
1689
+ migrationSummary: breaking.length > 0 ? `See the generated migration guide for upgrading from ${input.previousVersion} to ${input.newVersion}.` : void 0
1690
+ };
1691
+ const markdown = renderChangelogMarkdown(input.newVersion, date, structured);
1692
+ return {
1693
+ version: input.newVersion,
1694
+ date,
1695
+ markdown,
1696
+ structured
1697
+ };
1698
+ }
1699
+
1700
+ // ../ai/dist/migration-guide.js
1701
+ function renderMigrationGuideMarkdown(packageName, fromVersion, toVersion, data) {
1702
+ const parts = [
1703
+ `# Migrating ${packageName} from ${fromVersion} to ${toVersion}`,
1704
+ "",
1705
+ data.summary,
1706
+ ""
1707
+ ];
1708
+ if (data.breakingChanges.length > 0) {
1709
+ parts.push("## Breaking Changes");
1710
+ parts.push("");
1711
+ for (const change of data.breakingChanges) {
1712
+ parts.push(`### ${change.title}`);
1713
+ parts.push("");
1714
+ parts.push(change.explanation);
1715
+ parts.push("");
1716
+ if (change.before) {
1717
+ parts.push("Before:");
1718
+ parts.push("```ts");
1719
+ parts.push(change.before.trim());
1720
+ parts.push("```");
1721
+ parts.push("");
1722
+ }
1723
+ if (change.after) {
1724
+ parts.push("After:");
1725
+ parts.push("```ts");
1726
+ parts.push(change.after.trim());
1727
+ parts.push("```");
1728
+ parts.push("");
1729
+ }
1730
+ if (change.automatable) {
1731
+ parts.push("> \u{1F4A1} **Note:** This breaking change is machine-transformable via Verelease codemod.");
1732
+ parts.push("");
1733
+ }
1734
+ }
1735
+ }
1736
+ if (data.manualSteps.length > 0) {
1737
+ parts.push("## Manual Steps");
1738
+ parts.push("");
1739
+ for (const step of data.manualSteps) {
1740
+ parts.push(`1. ${step}`);
1741
+ }
1742
+ parts.push("");
1743
+ }
1744
+ if (data.warnings.length > 0) {
1745
+ parts.push("## Warnings");
1746
+ parts.push("");
1747
+ for (const warning of data.warnings) {
1748
+ parts.push(`- \u26A0\uFE0F ${warning}`);
1749
+ }
1750
+ parts.push("");
1751
+ }
1752
+ return parts.join("\n");
1753
+ }
1754
+ function synthesizeMigrationGuideFromEvidence(input) {
1755
+ const breakingItems = [];
1756
+ for (const ev of input.breakingChanges) {
1757
+ let before;
1758
+ let after;
1759
+ if (ev.title.includes("createRouter")) {
1760
+ before = `import { createRouter } from "${input.packageName}";
1761
+ const router = createRouter({ routes });`;
1762
+ after = `import { createRouter } from "${input.packageName}";
1763
+ const router = createRouter(routes);`;
1764
+ }
1765
+ breakingItems.push({
1766
+ title: ev.title,
1767
+ explanation: ev.description,
1768
+ before,
1769
+ after,
1770
+ automatable: !!before
1771
+ });
1772
+ }
1773
+ const structured = {
1774
+ summary: `This guide provides steps for upgrading ${input.packageName} from version ${input.previousVersion} to ${input.newVersion}.`,
1775
+ breakingChanges: breakingItems,
1776
+ manualSteps: [
1777
+ `Update dependency range for ${input.packageName} to ^${input.newVersion} in package.json`,
1778
+ "Run your test suite to verify compatibility"
1779
+ ],
1780
+ warnings: [
1781
+ "Review all breaking changes above before deploying to production."
1782
+ ]
1783
+ };
1784
+ const markdown = renderMigrationGuideMarkdown(input.packageName, input.previousVersion, input.newVersion, structured);
1785
+ return {
1786
+ packageName: input.packageName,
1787
+ fromVersion: input.previousVersion,
1788
+ toVersion: input.newVersion,
1789
+ markdown,
1790
+ structured
1791
+ };
1792
+ }
1793
+
1794
+ // ../ai/dist/migration-script.js
1795
+ function synthesizeMigrationScriptFromEvidence(input) {
1796
+ const scriptContent = `
1797
+ import { readFileSync, writeFileSync, readdirSync, statSync } from "node:fs";
1798
+ import { join } from "node:path";
1799
+
1800
+ function walkAndTransform(dir) {
1801
+ const entries = readdirSync(dir, { withFileTypes: true });
1802
+ for (const entry of entries) {
1803
+ const fullPath = join(dir, entry.name);
1804
+ if (entry.isDirectory() && entry.name !== "node_modules" && entry.name !== ".git") {
1805
+ walkAndTransform(fullPath);
1806
+ } else if (entry.isFile() && (/\\.(js|ts|mjs|jsx|tsx)$/).test(entry.name)) {
1807
+ let content = readFileSync(fullPath, "utf8");
1808
+ let changed = false;
1809
+
1810
+ // Transform createRouter({ routes: ... }) -> createRouter(...)
1811
+ const regex = /createRouter\\s*\\(\\s*\\{\\s*routes:\\s*([^}]+)\\s*\\}\\s*\\)/g;
1812
+ if (regex.test(content)) {
1813
+ content = content.replace(regex, "createRouter($1)");
1814
+ changed = true;
1815
+ }
1816
+
1817
+ if (changed) {
1818
+ writeFileSync(fullPath, content, "utf8");
1819
+ console.log("Transformed:", fullPath);
1820
+ }
1821
+ }
1822
+ }
1823
+ }
1824
+
1825
+ const targetDir = process.argv[2] || process.cwd();
1826
+ walkAndTransform(targetDir);
1827
+ `;
1828
+ return {
1829
+ id: `codemod-${input.packageName.replace(/[^a-zA-Z0-9]/g, "_")}-${input.fromVersion}-to-${input.toVersion}`,
1830
+ packageName: input.packageName,
1831
+ fromVersion: input.fromVersion,
1832
+ toVersion: input.toVersion,
1833
+ scriptContent: scriptContent.trim(),
1834
+ fileExtension: "js",
1835
+ description: `Automated codemod to migrate ${input.packageName} from ${input.fromVersion} to ${input.toVersion}`
1836
+ };
1837
+ }
1838
+
1839
+ // ../ai/dist/validation.js
1840
+ import { cp, mkdtemp as mkdtemp3, rm as rm3, writeFile as writeFile4, mkdir as mkdir4, symlink as symlink2, readdir as readdir3 } from "fs/promises";
1841
+ import { execFile as execFile4 } from "child_process";
1842
+ import { promisify as promisify4 } from "util";
1843
+ import { join as join9 } from "path";
1844
+ import { tmpdir as tmpdir3 } from "os";
1845
+ import * as tar2 from "tar";
1846
+ var execFileAsync4 = promisify4(execFile4);
1847
+
1848
+ // ../ai/dist/provider.js
1849
+ var TanStackReleaseAI = class {
1850
+ client;
1851
+ constructor(client) {
1852
+ this.client = client;
1853
+ }
1854
+ async generateChangelog(input) {
1855
+ if (this.client?.generateStructured) {
1856
+ try {
1857
+ const prompt = `Generate a changelog for package ${input.packageName} from version ${input.previousVersion} to ${input.newVersion} based on the following evidence:
1858
+ ${JSON.stringify(input.evidence, null, 2)}`;
1859
+ const structured = await this.client.generateStructured({
1860
+ schema: ChangelogSchema,
1861
+ prompt
1862
+ });
1863
+ const date = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
1864
+ const markdown = renderChangelogMarkdown(input.newVersion, date, structured);
1865
+ return {
1866
+ version: input.newVersion,
1867
+ date,
1868
+ markdown,
1869
+ structured
1870
+ };
1871
+ } catch {
1872
+ }
1873
+ }
1874
+ return synthesizeChangelogFromEvidence(input);
1875
+ }
1876
+ async generateMigrationGuide(input) {
1877
+ if (this.client?.generateStructured) {
1878
+ try {
1879
+ const prompt = `Generate a migration guide for upgrading package ${input.packageName} from ${input.previousVersion} to ${input.newVersion} based on breaking changes:
1880
+ ${JSON.stringify(input.breakingChanges, null, 2)}`;
1881
+ const structured = await this.client.generateStructured({
1882
+ schema: MigrationGuideSchema,
1883
+ prompt
1884
+ });
1885
+ const markdown = renderMigrationGuideMarkdown(input.packageName, input.previousVersion, input.newVersion, structured);
1886
+ return {
1887
+ packageName: input.packageName,
1888
+ fromVersion: input.previousVersion,
1889
+ toVersion: input.newVersion,
1890
+ markdown,
1891
+ structured
1892
+ };
1893
+ } catch {
1894
+ }
1895
+ }
1896
+ return synthesizeMigrationGuideFromEvidence(input);
1897
+ }
1898
+ async generateMigrationScript(input) {
1899
+ return synthesizeMigrationScriptFromEvidence(input);
1900
+ }
1901
+ };
1902
+
1903
+ // ../git/dist/git.js
1904
+ import { execFile as execFile5 } from "child_process";
1905
+ import { promisify as promisify5 } from "util";
1906
+ var execFileAsync5 = promisify5(execFile5);
1907
+ var GitManager = class {
1908
+ cwd;
1909
+ constructor(cwd = process.cwd()) {
1910
+ this.cwd = cwd;
1911
+ }
1912
+ formatTagName(options) {
1913
+ if (options.customFormat) {
1914
+ return options.customFormat(options.packageName, options.version);
1915
+ }
1916
+ if (options.strategy === "fixed") {
1917
+ return `v${options.version}`;
1918
+ }
1919
+ return `${options.packageName}@${options.version}`;
1920
+ }
1921
+ async isClean() {
1922
+ const { stdout } = await execFileAsync5("git", ["status", "--porcelain"], {
1923
+ cwd: this.cwd
1924
+ });
1925
+ return stdout.trim().length === 0;
1926
+ }
1927
+ async getHeadCommit() {
1928
+ const { stdout } = await execFileAsync5("git", ["rev-parse", "HEAD"], {
1929
+ cwd: this.cwd
1930
+ });
1931
+ return stdout.trim();
1932
+ }
1933
+ async createTag(tagName, message) {
1934
+ const args = ["tag", "-a", tagName, "-m", message || `Release ${tagName}`];
1935
+ await execFileAsync5("git", args, { cwd: this.cwd });
1936
+ }
1937
+ async createReleaseCommit(files, message = "chore(release): publish") {
1938
+ if (files.length > 0) {
1939
+ await execFileAsync5("git", ["add", ...files], { cwd: this.cwd });
1940
+ } else {
1941
+ await execFileAsync5("git", ["add", "-A"], { cwd: this.cwd });
1942
+ }
1943
+ await execFileAsync5("git", ["commit", "-m", message], { cwd: this.cwd });
1944
+ return this.getHeadCommit();
1945
+ }
1946
+ };
1947
+
1948
+ // src/cli.ts
1949
+ import semver4 from "semver";
1950
+ var VereleaseCli = class {
1951
+ cwd;
1952
+ constructor(options = {}) {
1953
+ this.cwd = resolve2(options.cwd || process.cwd());
1954
+ }
1955
+ async createPlan(options = {}) {
1956
+ const config = await loadConfig(this.cwd);
1957
+ const resolver = new DefaultWorkspaceResolver();
1958
+ const discovery = await resolver.resolve(this.cwd);
1959
+ const contractStore = new FileContractStore(
1960
+ join10(this.cwd, config.contracts?.directory || ".verelease/contracts")
1961
+ );
1962
+ const contractAnalyzer = new ContractCompatibilityAnalyzer(contractStore);
1963
+ const apiDiffAnalyzer = new ApiDiffAnalyzer();
1964
+ const semverEngine = new DefaultSemVerDecisionEngine();
1965
+ const npmPublisher = new NpmPublishProvider();
1966
+ const evidenceMap = /* @__PURE__ */ new Map();
1967
+ const initialBumps = /* @__PURE__ */ new Map();
1968
+ for (const pkg of discovery.packages) {
1969
+ const evidence = [];
1970
+ try {
1971
+ const contractEv = await contractAnalyzer.analyze({
1972
+ packageName: pkg.name,
1973
+ packagePath: pkg.directory,
1974
+ currentVersion: pkg.version
1975
+ });
1976
+ evidence.push(...contractEv);
1977
+ } catch {
1978
+ }
1979
+ try {
1980
+ const apiEv = await apiDiffAnalyzer.analyze({
1981
+ packageName: pkg.name,
1982
+ packagePath: pkg.directory,
1983
+ currentVersion: pkg.version
1984
+ });
1985
+ evidence.push(...apiEv);
1986
+ } catch {
1987
+ }
1988
+ evidenceMap.set(pkg.name, evidence);
1989
+ const decision = semverEngine.evaluate(
1990
+ pkg.name,
1991
+ pkg.version,
1992
+ evidence,
1993
+ config.versioning,
1994
+ options.channel || "stable"
1995
+ );
1996
+ const forced = options.forceBump?.[pkg.name] || options.defaultBump;
1997
+ let bump = forced || decision.bump;
1998
+ let proposedVersion = decision.proposedVersion;
1999
+ const reasons = [...decision.reasons];
2000
+ if (forced && decision.bump === "none") {
2001
+ const channel = options.channel || config.versioning?.channel || "stable";
2002
+ if (channel !== "stable") {
2003
+ const baseBump = `pre${forced}`;
2004
+ proposedVersion = semver4.inc(pkg.version, baseBump, channel) || pkg.version;
2005
+ } else {
2006
+ proposedVersion = semver4.inc(pkg.version, forced) || pkg.version;
2007
+ }
2008
+ reasons.push(`Bump manually requested (${forced}) for channel ${channel}`);
2009
+ }
2010
+ if (!pkg.isPrivate) {
2011
+ try {
2012
+ const publishedVersions = await npmPublisher.getPublishedVersions(pkg.name);
2013
+ const channel = options.channel || config.versioning?.channel || "stable";
2014
+ if (publishedVersions.includes(proposedVersion) || bump !== "none" && publishedVersions.includes(pkg.version)) {
2015
+ reasons.push(`Version ${proposedVersion} is already published on npm registry.`);
2016
+ let nextCandidate = proposedVersion;
2017
+ if (channel !== "stable") {
2018
+ const baseBump = bump === "none" ? "patch" : bump;
2019
+ const parsed = semver4.parse(pkg.version);
2020
+ if (parsed.prerelease.length > 0 && parsed.prerelease[0] === channel) {
2021
+ nextCandidate = semver4.inc(pkg.version, "prerelease", channel) || pkg.version;
2022
+ } else {
2023
+ nextCandidate = semver4.inc(pkg.version, `pre${baseBump}`, channel) || pkg.version;
2024
+ }
2025
+ while (publishedVersions.includes(nextCandidate)) {
2026
+ nextCandidate = semver4.inc(nextCandidate, "prerelease", channel) || nextCandidate;
2027
+ }
2028
+ } else {
2029
+ const baseBump = bump === "none" ? "patch" : bump;
2030
+ nextCandidate = semver4.inc(pkg.version, baseBump) || pkg.version;
2031
+ while (publishedVersions.includes(nextCandidate)) {
2032
+ nextCandidate = semver4.inc(nextCandidate, "patch") || nextCandidate;
2033
+ }
2034
+ }
2035
+ proposedVersion = nextCandidate;
2036
+ bump = bump === "none" ? "patch" : bump;
2037
+ reasons.push(`Automatically resolved next available registry version: ${proposedVersion}`);
2038
+ }
2039
+ } catch {
2040
+ }
2041
+ }
2042
+ initialBumps.set(pkg.name, {
2043
+ name: pkg.name,
2044
+ currentVersion: pkg.version,
2045
+ proposedVersion,
2046
+ bump,
2047
+ reasons
2048
+ });
2049
+ }
2050
+ const propagator = new VersionPropagator(discovery.graph);
2051
+ const { bumps: finalBumps, dependencyUpdates } = propagator.propagate(initialBumps);
2052
+ const publishOrder = discovery.graph.getTopologicalOrder();
2053
+ const packagePlans = [];
2054
+ for (const pkgName of publishOrder) {
2055
+ const pkg = discovery.packages.find((p) => p.name === pkgName);
2056
+ if (!pkg) continue;
2057
+ const bumpTarget = finalBumps.get(pkgName);
2058
+ const evidence = evidenceMap.get(pkgName) || [];
2059
+ const depUpdates = dependencyUpdates.get(pkgName) || [];
2060
+ const decision = semverEngine.evaluate(
2061
+ pkg.name,
2062
+ pkg.version,
2063
+ evidence,
2064
+ config.versioning,
2065
+ options.channel || "stable"
2066
+ );
2067
+ packagePlans.push({
2068
+ name: pkg.name,
2069
+ directory: pkg.directory,
2070
+ currentVersion: pkg.version,
2071
+ proposedVersion: bumpTarget.proposedVersion,
2072
+ bump: bumpTarget.bump,
2073
+ channel: options.channel || "stable",
2074
+ evidence,
2075
+ reasons: bumpTarget.reasons,
2076
+ confidence: decision.confidence,
2077
+ requiresApproval: decision.requiresApproval,
2078
+ dependentUpdates: depUpdates.map((d) => ({
2079
+ dependentName: pkgName,
2080
+ dependencyName: d.dependencyName,
2081
+ dependencyType: d.type,
2082
+ previousRange: d.previousRange,
2083
+ newRange: d.newRange
2084
+ })),
2085
+ filesToUpdate: [pkg.manifestPath],
2086
+ publish: !pkg.isPrivate && bumpTarget.bump !== "none"
2087
+ });
2088
+ }
2089
+ const plan = {
2090
+ schemaVersion: 1,
2091
+ id: `plan-${Date.now()}`,
2092
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
2093
+ rootDirectory: this.cwd,
2094
+ channel: options.channel || "stable",
2095
+ packages: packagePlans,
2096
+ publishOrder,
2097
+ summary: {
2098
+ totalPackages: packagePlans.length,
2099
+ bumpedPackages: packagePlans.filter((p) => p.bump !== "none").length,
2100
+ majorBumps: packagePlans.filter((p) => p.bump === "major").length,
2101
+ minorBumps: packagePlans.filter((p) => p.bump === "minor").length,
2102
+ patchBumps: packagePlans.filter((p) => p.bump === "patch").length,
2103
+ noneBumps: packagePlans.filter((p) => p.bump === "none").length
2104
+ }
2105
+ };
2106
+ return { plan, evidenceMap };
2107
+ }
2108
+ async runPlanCommand(options = {}) {
2109
+ const { plan } = await this.createPlan(options);
2110
+ if (options.json) {
2111
+ console.log(JSON.stringify(plan, null, 2));
2112
+ return plan;
2113
+ }
2114
+ this.printPlan(plan);
2115
+ try {
2116
+ const verelDir = join10(this.cwd, ".verelease");
2117
+ await mkdir5(verelDir, { recursive: true });
2118
+ await writeFile5(
2119
+ join10(verelDir, "release-plan.json"),
2120
+ JSON.stringify(plan, null, 2),
2121
+ "utf8"
2122
+ );
2123
+ } catch {
2124
+ }
2125
+ return plan;
2126
+ }
2127
+ async runReleaseCommand(options = {}) {
2128
+ const { plan, evidenceMap } = await this.createPlan(options);
2129
+ console.log(`
2130
+ \u{1F680} Verelease Pipeline [Channel: ${plan.channel}, Dry-run: ${!!options.dryRun}]
2131
+ `);
2132
+ this.printPlan(plan);
2133
+ if (plan.summary.bumpedPackages === 0) {
2134
+ console.log("\n\u2728 No packages require release.");
2135
+ return;
2136
+ }
2137
+ const mutator = new TransactionalManifestMutator();
2138
+ const lockfileAdapter = new AutoLockfileAdapter();
2139
+ const npmPublisher = new NpmPublishProvider();
2140
+ const ai = new TanStackReleaseAI();
2141
+ const git = new GitManager(this.cwd);
2142
+ let transaction;
2143
+ const changelogBackups = /* @__PURE__ */ new Map();
2144
+ if (!options.dryRun) {
2145
+ console.log("\n\u{1F4E6} Applying version bumps to manifests...");
2146
+ transaction = await mutator.applyPlan(plan);
2147
+ console.log(`\u2713 Updated ${transaction.modifiedFiles.length} manifest files`);
2148
+ console.log(`
2149
+ \u{1F512} Regenerating lockfile using ${lockfileAdapter.packageManager}...`);
2150
+ const lockRes = await lockfileAdapter.regenerateLockfile(this.cwd);
2151
+ if (!lockRes.success) {
2152
+ console.error(`\u274C Lockfile regeneration failed: ${lockRes.output}`);
2153
+ await transaction.rollback();
2154
+ console.log("\u21A9 Rolled back manifest updates");
2155
+ process.exit(1);
2156
+ }
2157
+ console.log("\u2713 Lockfile regenerated successfully");
2158
+ console.log("\n\u{1F916} Generating changelogs & migration documentation via AI layer...");
2159
+ for (const pkgPlan of plan.packages) {
2160
+ if (pkgPlan.bump === "none") continue;
2161
+ const evidence = evidenceMap.get(pkgPlan.name) || [];
2162
+ const changelog = await ai.generateChangelog({
2163
+ packageName: pkgPlan.name,
2164
+ previousVersion: pkgPlan.currentVersion,
2165
+ newVersion: pkgPlan.proposedVersion,
2166
+ evidence
2167
+ });
2168
+ const changelogPath = join10(pkgPlan.directory, "CHANGELOG.md");
2169
+ let existingChangelog = null;
2170
+ try {
2171
+ existingChangelog = await readFile5(changelogPath, "utf8");
2172
+ } catch {
2173
+ existingChangelog = null;
2174
+ }
2175
+ changelogBackups.set(changelogPath, existingChangelog);
2176
+ await writeFile5(
2177
+ changelogPath,
2178
+ `${changelog.markdown}
2179
+
2180
+ ${existingChangelog || ""}`.trim() + "\n",
2181
+ "utf8"
2182
+ );
2183
+ console.log(` \u2713 Updated ${pkgPlan.name} CHANGELOG.md`);
2184
+ if (pkgPlan.bump === "major") {
2185
+ const breakingEvidence = evidence.filter((e) => e.severity === "major");
2186
+ const guide = await ai.generateMigrationGuide({
2187
+ packageName: pkgPlan.name,
2188
+ previousVersion: pkgPlan.currentVersion,
2189
+ newVersion: pkgPlan.proposedVersion,
2190
+ breakingChanges: breakingEvidence
2191
+ });
2192
+ const migrationsDir = join10(pkgPlan.directory, "docs", "migrations");
2193
+ await mkdir5(migrationsDir, { recursive: true });
2194
+ const guidePath = join10(
2195
+ migrationsDir,
2196
+ `${pkgPlan.currentVersion.split(".")[0]}-to-${pkgPlan.proposedVersion.split(".")[0]}.md`
2197
+ );
2198
+ await writeFile5(guidePath, guide.markdown, "utf8");
2199
+ console.log(` \u2713 Generated migration guide: ${guidePath}`);
2200
+ }
2201
+ }
2202
+ if (options.tag) {
2203
+ try {
2204
+ console.log("\n\u{1F3F7}\uFE0F Creating Git release commit and tags...");
2205
+ await git.createReleaseCommit([], `chore(release): publish version ${plan.id}`);
2206
+ for (const pkgPlan of plan.packages) {
2207
+ if (pkgPlan.publish) {
2208
+ const tagName = git.formatTagName({
2209
+ packageName: pkgPlan.name,
2210
+ version: pkgPlan.proposedVersion
2211
+ });
2212
+ await git.createTag(tagName);
2213
+ console.log(` \u2713 Created git tag: ${tagName}`);
2214
+ }
2215
+ }
2216
+ } catch (err) {
2217
+ console.warn(` \u26A0\uFE0F Git tagging warning: ${err.message || String(err)}`);
2218
+ }
2219
+ }
2220
+ } else {
2221
+ console.log("\n[DRY RUN] Skipped manifest, lockfile, changelog mutations, and git tags.");
2222
+ }
2223
+ console.log("\n\u{1F4E4} Publishing packages in dependency order:");
2224
+ for (const pkgName of plan.publishOrder) {
2225
+ const pkgPlan = plan.packages.find((p) => p.name === pkgName);
2226
+ if (!pkgPlan || !pkgPlan.publish) continue;
2227
+ console.log(`
2228
+ \u2192 Publishing ${pkgPlan.name}@${pkgPlan.proposedVersion}...`);
2229
+ const result = await npmPublisher.publish({
2230
+ packagePlan: pkgPlan,
2231
+ fullPlan: plan,
2232
+ dryRun: !!options.dryRun,
2233
+ extraArgs: options.otp ? ["--otp", options.otp] : void 0
2234
+ });
2235
+ if (result.published) {
2236
+ console.log(` \u2713 ${pkgPlan.name}@${pkgPlan.proposedVersion} published [tag: ${result.distTag}]`);
2237
+ } else {
2238
+ console.error(` \u274C Failed to publish ${pkgPlan.name}: ${result.error}`);
2239
+ if (!options.dryRun) {
2240
+ console.log("\n\u21A9 Rolling back manifest updates due to publish failure...");
2241
+ if (transaction) {
2242
+ await transaction.rollback();
2243
+ console.log(" \u2713 Restored manifests to previous versions");
2244
+ }
2245
+ for (const [chPath, original] of changelogBackups) {
2246
+ try {
2247
+ if (original === null) {
2248
+ await unlink(chPath);
2249
+ } else {
2250
+ await writeFile5(chPath, original, "utf8");
2251
+ }
2252
+ } catch {
2253
+ }
2254
+ }
2255
+ console.log(" \u2713 Restored changelog files");
2256
+ await lockfileAdapter.regenerateLockfile(this.cwd);
2257
+ console.log(" \u2713 Synchronized lockfile\n");
2258
+ process.exit(1);
2259
+ }
2260
+ }
2261
+ }
2262
+ console.log("\n\u{1F389} Release completed successfully!");
2263
+ }
2264
+ async runExplainCommand(packageName) {
2265
+ const { plan, evidenceMap } = await this.createPlan();
2266
+ const pkgPlan = plan.packages.find((p) => p.name === packageName);
2267
+ if (!pkgPlan) {
2268
+ console.error(`Package "${packageName}" not found in workspace.`);
2269
+ return;
2270
+ }
2271
+ const evidence = evidenceMap.get(packageName) || [];
2272
+ console.log(`
2273
+ \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550`);
2274
+ console.log(` EXPLANATION FOR ${packageName}`);
2275
+ console.log(`\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
2276
+ `);
2277
+ console.log(`Current Version: ${pkgPlan.currentVersion}`);
2278
+ console.log(`Proposed Version: ${pkgPlan.proposedVersion} [${pkgPlan.bump.toUpperCase()}]`);
2279
+ console.log(`Confidence: ${(pkgPlan.confidence * 100).toFixed(0)}%`);
2280
+ console.log(`Requires Review: ${pkgPlan.requiresApproval ? "YES" : "NO"}
2281
+ `);
2282
+ console.log(`Evidence items (${evidence.length}):`);
2283
+ for (const ev of evidence) {
2284
+ console.log(` \u2022 [${ev.source.toUpperCase()}] (${ev.severity.toUpperCase()}) ${ev.title}`);
2285
+ console.log(` ${ev.description}
2286
+ `);
2287
+ }
2288
+ if (pkgPlan.reasons.length > 0) {
2289
+ console.log("Decision reasons:");
2290
+ for (const reason of pkgPlan.reasons) {
2291
+ console.log(` ${reason}`);
2292
+ }
2293
+ }
2294
+ }
2295
+ printPlan(plan) {
2296
+ console.log(`
2297
+ \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550`);
2298
+ console.log(` VERELEASE RELEASE PLAN`);
2299
+ console.log(` Channel: ${plan.channel} | Packages: ${plan.summary.totalPackages} | Bumps: ${plan.summary.bumpedPackages}`);
2300
+ console.log(`\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
2301
+ `);
2302
+ for (const pkg of plan.packages) {
2303
+ const bumpColor = pkg.bump === "major" ? "\u{1F534} MAJOR" : pkg.bump === "minor" ? "\u{1F7E1} MINOR" : pkg.bump === "patch" ? "\u{1F7E2} PATCH" : "\u26AA NONE";
2304
+ console.log(`${pkg.name}: ${pkg.currentVersion} \u2192 ${pkg.proposedVersion} [${bumpColor}]`);
2305
+ console.log(` Confidence: ${(pkg.confidence * 100).toFixed(0)}% | Publish: ${pkg.publish ? "YES" : "NO"}`);
2306
+ if (pkg.reasons.length > 0) {
2307
+ console.log(" Reasons:");
2308
+ for (const reason of pkg.reasons) {
2309
+ console.log(` ${reason}`);
2310
+ }
2311
+ }
2312
+ if (pkg.dependentUpdates.length > 0) {
2313
+ console.log(" Dependent Updates:");
2314
+ for (const dep of pkg.dependentUpdates) {
2315
+ console.log(` ${dep.dependentName} depends on ${dep.dependencyName} (${dep.previousRange} \u2192 ${dep.newRange})`);
2316
+ }
2317
+ }
2318
+ console.log("");
2319
+ }
2320
+ }
2321
+ };
2322
+
2323
+ // src/bin.ts
2324
+ async function main() {
2325
+ const args = process.argv.slice(2);
2326
+ const command = args[0] || "plan";
2327
+ const options = {
2328
+ dryRun: args.includes("--dry-run"),
2329
+ json: args.includes("--json"),
2330
+ tag: args.includes("--tag")
2331
+ };
2332
+ const channelIdx = args.indexOf("--channel");
2333
+ if (channelIdx !== -1 && args[channelIdx + 1]) {
2334
+ options.channel = args[channelIdx + 1];
2335
+ }
2336
+ const bumpIdx = args.indexOf("--bump");
2337
+ if (bumpIdx !== -1 && args[bumpIdx + 1]) {
2338
+ options.defaultBump = args[bumpIdx + 1];
2339
+ }
2340
+ const cwdIdx = args.indexOf("--cwd");
2341
+ if (cwdIdx !== -1 && args[cwdIdx + 1]) {
2342
+ options.cwd = args[cwdIdx + 1];
2343
+ }
2344
+ const otpIdx = args.indexOf("--otp");
2345
+ if (otpIdx !== -1 && args[otpIdx + 1]) {
2346
+ options.otp = args[otpIdx + 1];
2347
+ }
2348
+ const cli = new VereleaseCli(options);
2349
+ try {
2350
+ switch (command) {
2351
+ case "plan":
2352
+ await cli.runPlanCommand(options);
2353
+ break;
2354
+ case "release":
2355
+ await cli.runReleaseCommand(options);
2356
+ break;
2357
+ case "version":
2358
+ await cli.runReleaseCommand({ ...options, dryRun: false });
2359
+ break;
2360
+ case "explain":
2361
+ const targetPkg = args[1];
2362
+ if (!targetPkg) {
2363
+ console.error("Please specify a package name to explain, e.g.: verel explain @acme/core");
2364
+ process.exit(1);
2365
+ }
2366
+ await cli.runExplainCommand(targetPkg);
2367
+ break;
2368
+ default:
2369
+ console.log(`Unknown command: ${command}`);
2370
+ console.log(`Available commands: plan, release, version, explain`);
2371
+ process.exit(1);
2372
+ }
2373
+ } catch (err) {
2374
+ console.error(`
2375
+ \u274C Error: ${err.message || String(err)}`);
2376
+ process.exit(1);
2377
+ }
2378
+ }
2379
+ main();
2380
+ //# sourceMappingURL=bin.js.map