@wrongstack/plugins 0.250.0 → 0.256.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/index.js +190 -98
- package/dist/semver-bump.d.ts +13 -1
- package/dist/semver-bump.js +186 -93
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { execFileSync, execSync } from 'child_process';
|
|
2
|
-
import { watch, existsSync,
|
|
2
|
+
import { watch, existsSync, readFileSync, writeFileSync, readdirSync } from 'fs';
|
|
3
3
|
import * as path from 'path';
|
|
4
4
|
import { isAbsolute, join } from 'path';
|
|
5
5
|
import { expectDefined, deepMerge as deepMerge$1 } from '@wrongstack/core';
|
|
@@ -135,7 +135,7 @@ async function runAutoDoc(input, api) {
|
|
|
135
135
|
const results = [];
|
|
136
136
|
for (const file of input.files) {
|
|
137
137
|
try {
|
|
138
|
-
const { readFileSync: readFileSync2, writeFileSync } = await import('fs');
|
|
138
|
+
const { readFileSync: readFileSync2, writeFileSync: writeFileSync2 } = await import('fs');
|
|
139
139
|
let content;
|
|
140
140
|
try {
|
|
141
141
|
content = readFileSync2(file, "utf-8");
|
|
@@ -152,7 +152,7 @@ async function runAutoDoc(input, api) {
|
|
|
152
152
|
results.push({ file, entity: entity.name });
|
|
153
153
|
}
|
|
154
154
|
if (!input.dryRun && results.length > 0) {
|
|
155
|
-
|
|
155
|
+
writeFileSync2(file, modified, "utf-8");
|
|
156
156
|
api.log.info(`auto-doc: updated ${file}`);
|
|
157
157
|
}
|
|
158
158
|
} catch (err) {
|
|
@@ -2255,8 +2255,8 @@ var plugin9 = {
|
|
|
2255
2255
|
if (isAbsolute(outputPath) || outputPath.includes("..")) {
|
|
2256
2256
|
return { ok: false, error: 'outputPath must be a relative path without ".." components' };
|
|
2257
2257
|
}
|
|
2258
|
-
const { writeFileSync } = await import('fs');
|
|
2259
|
-
|
|
2258
|
+
const { writeFileSync: writeFileSync2 } = await import('fs');
|
|
2259
|
+
writeFileSync2(outputPath, result, "utf-8");
|
|
2260
2260
|
return {
|
|
2261
2261
|
ok: true,
|
|
2262
2262
|
outputPath,
|
|
@@ -2319,8 +2319,8 @@ var plugin9 = {
|
|
|
2319
2319
|
if (isAbsolute(outputPath) || outputPath.includes("..")) {
|
|
2320
2320
|
return { ok: false, error: 'outputPath must be a relative path without ".." components' };
|
|
2321
2321
|
}
|
|
2322
|
-
const { writeFileSync } = await import('fs');
|
|
2323
|
-
|
|
2322
|
+
const { writeFileSync: writeFileSync2 } = await import('fs');
|
|
2323
|
+
writeFileSync2(outputPath, result, "utf-8");
|
|
2324
2324
|
return {
|
|
2325
2325
|
ok: true,
|
|
2326
2326
|
templatePath,
|
|
@@ -2439,10 +2439,25 @@ function getPackageJson(cwd) {
|
|
|
2439
2439
|
return null;
|
|
2440
2440
|
}
|
|
2441
2441
|
}
|
|
2442
|
+
function collectManifests(root) {
|
|
2443
|
+
const paths = [];
|
|
2444
|
+
const rootPkg = join(root, "package.json");
|
|
2445
|
+
if (existsSync(rootPkg)) paths.push(rootPkg);
|
|
2446
|
+
for (const group of ["packages", "apps"]) {
|
|
2447
|
+
const groupDir = join(root, group);
|
|
2448
|
+
if (!existsSync(groupDir)) continue;
|
|
2449
|
+
for (const entry of readdirSync(groupDir, { withFileTypes: true })) {
|
|
2450
|
+
if (!entry.isDirectory()) continue;
|
|
2451
|
+
const candidate = join(groupDir, entry.name, "package.json");
|
|
2452
|
+
if (existsSync(candidate)) paths.push(candidate);
|
|
2453
|
+
}
|
|
2454
|
+
}
|
|
2455
|
+
return paths;
|
|
2456
|
+
}
|
|
2442
2457
|
function parseVersion(v) {
|
|
2443
2458
|
const m = v.match(/^v?(\d+)\.(\d+)\.(\d+)/);
|
|
2444
2459
|
if (!m) return [0, 0, 0];
|
|
2445
|
-
return [Number.parseInt(expectDefined(m[1])), Number.parseInt(expectDefined(m[2])), Number.parseInt(expectDefined(m[3]))];
|
|
2460
|
+
return [Number.parseInt(expectDefined(m[1]), 10), Number.parseInt(expectDefined(m[2]), 10), Number.parseInt(expectDefined(m[3]), 10)];
|
|
2446
2461
|
}
|
|
2447
2462
|
function bumpVersion(version, part) {
|
|
2448
2463
|
let [major, minor, patch] = parseVersion(version);
|
|
@@ -2460,6 +2475,15 @@ function bumpVersion(version, part) {
|
|
|
2460
2475
|
}
|
|
2461
2476
|
return `${major}.${minor}.${patch}`;
|
|
2462
2477
|
}
|
|
2478
|
+
function parseConventional(subject) {
|
|
2479
|
+
const m = subject.match(/^(\w+)(!)?(?:\(([^)]+)\))?(!)?:\s+(.+)/);
|
|
2480
|
+
return {
|
|
2481
|
+
type: m?.[1] ?? "chore",
|
|
2482
|
+
breaking: !!(m?.[2] ?? m?.[4]),
|
|
2483
|
+
scope: m?.[3],
|
|
2484
|
+
message: m?.[5] ?? subject
|
|
2485
|
+
};
|
|
2486
|
+
}
|
|
2463
2487
|
function getRecentCommits(sinceTag, cwd) {
|
|
2464
2488
|
const range = sinceTag ? `${sinceTag}..HEAD` : "-30";
|
|
2465
2489
|
const output = runGit2(["log", range, "--format=%H %s"], cwd);
|
|
@@ -2468,25 +2492,12 @@ function getRecentCommits(sinceTag, cwd) {
|
|
|
2468
2492
|
const spaceIdx = line.indexOf(" ");
|
|
2469
2493
|
const hash = line.slice(0, spaceIdx);
|
|
2470
2494
|
const message = line.slice(spaceIdx + 1);
|
|
2471
|
-
|
|
2472
|
-
const type = m?.[1] ?? "chore";
|
|
2473
|
-
const breaking = !!m?.[2];
|
|
2474
|
-
const scope = m?.[2];
|
|
2475
|
-
const msg = m?.[3] ?? message;
|
|
2476
|
-
return { hash, type, scope, message: msg, breaking };
|
|
2495
|
+
return { hash, ...parseConventional(message) };
|
|
2477
2496
|
});
|
|
2478
2497
|
}
|
|
2479
2498
|
function determineBump(commits) {
|
|
2480
|
-
|
|
2481
|
-
|
|
2482
|
-
return "major";
|
|
2483
|
-
}
|
|
2484
|
-
}
|
|
2485
|
-
for (const c of commits) {
|
|
2486
|
-
if (c.type === "feat" || c.type === "refactor" && c.scope) {
|
|
2487
|
-
return "minor";
|
|
2488
|
-
}
|
|
2489
|
-
}
|
|
2499
|
+
if (commits.some((c) => c.breaking)) return "major";
|
|
2500
|
+
if (commits.some((c) => c.type === "feat")) return "minor";
|
|
2490
2501
|
return "patch";
|
|
2491
2502
|
}
|
|
2492
2503
|
function generateChangelog(commits) {
|
|
@@ -2548,12 +2559,13 @@ var plugin10 = {
|
|
|
2548
2559
|
version: "0.1.0",
|
|
2549
2560
|
description: "Conventional-commit-driven semver version bumps with changelog generation",
|
|
2550
2561
|
apiVersion: API_VERSION9,
|
|
2551
|
-
capabilities: { tools: true },
|
|
2562
|
+
capabilities: { tools: true, slashCommands: true },
|
|
2552
2563
|
defaultConfig: {
|
|
2553
2564
|
tagPrefix: "v",
|
|
2554
2565
|
changelogFile: "CHANGELOG.md",
|
|
2555
2566
|
autoTag: true,
|
|
2556
|
-
tagMessage: "Release {{version}}"
|
|
2567
|
+
tagMessage: "Release {{version}}",
|
|
2568
|
+
defaultPart: "patch"
|
|
2557
2569
|
},
|
|
2558
2570
|
configSchema: {
|
|
2559
2571
|
type: "object",
|
|
@@ -2561,12 +2573,114 @@ var plugin10 = {
|
|
|
2561
2573
|
tagPrefix: { type: "string", default: "v" },
|
|
2562
2574
|
changelogFile: { type: "string", default: "CHANGELOG.md" },
|
|
2563
2575
|
autoTag: { type: "boolean", default: true },
|
|
2564
|
-
tagMessage: { type: "string", default: "Release {{version}}" }
|
|
2576
|
+
tagMessage: { type: "string", default: "Release {{version}}" },
|
|
2577
|
+
defaultPart: { type: "string", enum: ["major", "minor", "patch", "auto"], default: "patch" }
|
|
2565
2578
|
}
|
|
2566
2579
|
},
|
|
2567
2580
|
setup(api) {
|
|
2568
2581
|
const tagPrefix = api.config.extensions?.["semver-bump"]?.["tagPrefix"] ?? "v";
|
|
2569
2582
|
const autoTag = api.config.extensions?.["semver-bump"]?.["autoTag"] ?? true;
|
|
2583
|
+
const VALID_PARTS = ["major", "minor", "patch", "auto"];
|
|
2584
|
+
function readDefaultPart(cfg) {
|
|
2585
|
+
const raw = cfg.extensions?.["semver-bump"]?.["defaultPart"];
|
|
2586
|
+
return VALID_PARTS.includes(raw) ? raw : "patch";
|
|
2587
|
+
}
|
|
2588
|
+
let defaultPart = readDefaultPart(api.config);
|
|
2589
|
+
api.onConfigChange?.((next) => {
|
|
2590
|
+
defaultPart = readDefaultPart(next);
|
|
2591
|
+
});
|
|
2592
|
+
async function performBump(part, dryRun, cwd) {
|
|
2593
|
+
const pkg = getPackageJson(cwd);
|
|
2594
|
+
if (!pkg) {
|
|
2595
|
+
return { ok: false, error: "No package.json found" };
|
|
2596
|
+
}
|
|
2597
|
+
const currentVersion = pkg.version;
|
|
2598
|
+
let bumpPart = part;
|
|
2599
|
+
let commits = [];
|
|
2600
|
+
if (part === "auto") {
|
|
2601
|
+
let lastTag;
|
|
2602
|
+
try {
|
|
2603
|
+
const tagsOutput = runGit2(["describe", "--tags", "--abbrev=0"], cwd);
|
|
2604
|
+
lastTag = tagsOutput || void 0;
|
|
2605
|
+
} catch {
|
|
2606
|
+
}
|
|
2607
|
+
try {
|
|
2608
|
+
commits = getRecentCommits(lastTag, cwd);
|
|
2609
|
+
} catch (err) {
|
|
2610
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
2611
|
+
return { ok: false, error: `Git error: ${msg}`, bumpPart: "patch" };
|
|
2612
|
+
}
|
|
2613
|
+
bumpPart = determineBump(commits);
|
|
2614
|
+
} else {
|
|
2615
|
+
bumpPart = part;
|
|
2616
|
+
}
|
|
2617
|
+
const newVersion = bumpVersion(currentVersion, bumpPart);
|
|
2618
|
+
if (dryRun) {
|
|
2619
|
+
return {
|
|
2620
|
+
ok: true,
|
|
2621
|
+
dryRun: true,
|
|
2622
|
+
currentVersion,
|
|
2623
|
+
suggestedBump: bumpPart,
|
|
2624
|
+
newVersion,
|
|
2625
|
+
commitCount: part === "auto" ? commits.length : void 0,
|
|
2626
|
+
message: `Would bump ${currentVersion} \u2192 ${newVersion} (${bumpPart})`
|
|
2627
|
+
};
|
|
2628
|
+
}
|
|
2629
|
+
const root = cwd ?? process.cwd();
|
|
2630
|
+
const bumpScript = join(root, "scripts", "bump-version.mjs");
|
|
2631
|
+
const changed = collectManifests(root);
|
|
2632
|
+
if (existsSync(bumpScript)) {
|
|
2633
|
+
try {
|
|
2634
|
+
execFileSync(process.execPath, [bumpScript, "set", newVersion], {
|
|
2635
|
+
cwd: root,
|
|
2636
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
2637
|
+
timeout: 3e4,
|
|
2638
|
+
windowsHide: true
|
|
2639
|
+
});
|
|
2640
|
+
} catch (err) {
|
|
2641
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
2642
|
+
return { ok: false, error: `bump script failed: ${msg}` };
|
|
2643
|
+
}
|
|
2644
|
+
for (const rel of ["package.json", "package-lock.json", "src/lib/utils.ts", "index.html"]) {
|
|
2645
|
+
const p = join(root, "website", rel);
|
|
2646
|
+
if (existsSync(p)) changed.push(p);
|
|
2647
|
+
}
|
|
2648
|
+
} else {
|
|
2649
|
+
for (const manifest of changed) {
|
|
2650
|
+
const pkgData = JSON.parse(readFileSync(manifest, "utf-8"));
|
|
2651
|
+
pkgData.version = newVersion;
|
|
2652
|
+
writeFileSync(manifest, JSON.stringify(pkgData, null, 2) + "\n", "utf-8");
|
|
2653
|
+
}
|
|
2654
|
+
}
|
|
2655
|
+
try {
|
|
2656
|
+
runGit2(["add", "--", ...changed], cwd);
|
|
2657
|
+
runGit2(["commit", "-m", `chore: bump version to ${newVersion}`], cwd);
|
|
2658
|
+
} catch {
|
|
2659
|
+
}
|
|
2660
|
+
if (autoTag) {
|
|
2661
|
+
try {
|
|
2662
|
+
runGit2(["tag", "-a", `${tagPrefix}${newVersion}`, "-m", `Release ${newVersion}`], cwd);
|
|
2663
|
+
} catch {
|
|
2664
|
+
}
|
|
2665
|
+
}
|
|
2666
|
+
api.log.info("semver-bump: bumped", { from: currentVersion, to: newVersion, bump: bumpPart });
|
|
2667
|
+
api.metrics.counter("version_bump", 1, { bump: bumpPart });
|
|
2668
|
+
await api.session.append({
|
|
2669
|
+
type: "semver-bump:bumped",
|
|
2670
|
+
ts: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2671
|
+
from: currentVersion,
|
|
2672
|
+
to: newVersion,
|
|
2673
|
+
bump: bumpPart
|
|
2674
|
+
});
|
|
2675
|
+
return {
|
|
2676
|
+
ok: true,
|
|
2677
|
+
currentVersion,
|
|
2678
|
+
newVersion,
|
|
2679
|
+
bump: bumpPart,
|
|
2680
|
+
tag: `${tagPrefix}${newVersion}`,
|
|
2681
|
+
message: `Bumped ${currentVersion} \u2192 ${newVersion} (${bumpPart})`
|
|
2682
|
+
};
|
|
2683
|
+
}
|
|
2570
2684
|
api.tools.register({
|
|
2571
2685
|
name: "semver_bump",
|
|
2572
2686
|
description: "Determine the next version bump from conventional commits since the last tag, or force a specific bump. Creates a git tag.",
|
|
@@ -2575,7 +2689,7 @@ var plugin10 = {
|
|
|
2575
2689
|
properties: {
|
|
2576
2690
|
cwd: { type: "string", description: "Working directory (defaults to project root)" },
|
|
2577
2691
|
dryRun: { type: "boolean", default: false },
|
|
2578
|
-
part: { type: "string", enum: ["major", "minor", "patch", "auto"], default:
|
|
2692
|
+
part: { type: "string", enum: ["major", "minor", "patch", "auto"], default: defaultPart, description: "Version part to bump. Omitted \u2192 the configured default (/settings semver-part, factory default: patch). Use auto to infer from commits." }
|
|
2579
2693
|
}
|
|
2580
2694
|
},
|
|
2581
2695
|
permission: "confirm",
|
|
@@ -2583,76 +2697,62 @@ var plugin10 = {
|
|
|
2583
2697
|
async execute(input) {
|
|
2584
2698
|
const cwd = input["cwd"];
|
|
2585
2699
|
const dryRun = input["dryRun"] ?? false;
|
|
2586
|
-
const part = input["part"] ??
|
|
2587
|
-
|
|
2588
|
-
|
|
2589
|
-
|
|
2590
|
-
|
|
2591
|
-
|
|
2592
|
-
|
|
2593
|
-
|
|
2594
|
-
|
|
2700
|
+
const part = input["part"] ?? defaultPart;
|
|
2701
|
+
return performBump(part, dryRun, cwd);
|
|
2702
|
+
}
|
|
2703
|
+
});
|
|
2704
|
+
api.slashCommands.register({
|
|
2705
|
+
name: "semver",
|
|
2706
|
+
description: "Show the current version or bump it (patch/minor/major/auto)",
|
|
2707
|
+
category: "Run",
|
|
2708
|
+
argsHint: "[status|patch|minor|major|auto] [--dry]",
|
|
2709
|
+
help: [
|
|
2710
|
+
"/semver Show current version, latest tag and the suggested bump",
|
|
2711
|
+
"/semver status Same as bare /semver",
|
|
2712
|
+
"/semver patch Bump the patch version (commit + tag)",
|
|
2713
|
+
"/semver minor Bump the minor version (commit + tag)",
|
|
2714
|
+
"/semver major Bump the major version (commit + tag)",
|
|
2715
|
+
"/semver auto Infer the bump from conventional commits since the last tag",
|
|
2716
|
+
"/semver <part> --dry Preview without writing anything"
|
|
2717
|
+
].join("\n"),
|
|
2718
|
+
async run(args, ctx) {
|
|
2719
|
+
const tokens = args.trim().split(/\s+/).filter(Boolean);
|
|
2720
|
+
const dry = tokens.includes("--dry") || tokens.includes("--dry-run");
|
|
2721
|
+
const mode = tokens.find((t) => !t.startsWith("--")) ?? "status";
|
|
2722
|
+
const cwd = ctx?.cwd;
|
|
2723
|
+
if (mode === "status") {
|
|
2724
|
+
const pkg = getPackageJson(cwd);
|
|
2725
|
+
if (!pkg) return { message: "No package.json found" };
|
|
2595
2726
|
let lastTag;
|
|
2596
2727
|
try {
|
|
2597
|
-
|
|
2598
|
-
lastTag = tagsOutput || void 0;
|
|
2728
|
+
lastTag = runGit2(["describe", "--tags", "--abbrev=0"], cwd) || void 0;
|
|
2599
2729
|
} catch {
|
|
2600
2730
|
}
|
|
2731
|
+
let suggestion = "patch";
|
|
2732
|
+
let commitCount = 0;
|
|
2601
2733
|
try {
|
|
2602
|
-
commits = getRecentCommits(lastTag, cwd);
|
|
2603
|
-
|
|
2604
|
-
|
|
2605
|
-
|
|
2734
|
+
const commits = getRecentCommits(lastTag, cwd);
|
|
2735
|
+
commitCount = commits.length;
|
|
2736
|
+
suggestion = determineBump(commits);
|
|
2737
|
+
} catch {
|
|
2606
2738
|
}
|
|
2607
|
-
bumpPart = determineBump(commits);
|
|
2608
|
-
} else {
|
|
2609
|
-
bumpPart = part;
|
|
2610
|
-
}
|
|
2611
|
-
const newVersion = bumpVersion(currentVersion, bumpPart);
|
|
2612
|
-
if (dryRun) {
|
|
2613
2739
|
return {
|
|
2614
|
-
|
|
2615
|
-
|
|
2616
|
-
|
|
2617
|
-
|
|
2618
|
-
|
|
2619
|
-
|
|
2620
|
-
|
|
2740
|
+
message: [
|
|
2741
|
+
`Current version: ${pkg.version}`,
|
|
2742
|
+
`Latest tag: ${lastTag ?? "(none)"}`,
|
|
2743
|
+
`Commits since: ${commitCount}`,
|
|
2744
|
+
`Suggested bump: ${suggestion} \u2192 ${bumpVersion(pkg.version, suggestion)}`,
|
|
2745
|
+
`Default part: ${defaultPart} (change: /settings semver-part)`,
|
|
2746
|
+
"",
|
|
2747
|
+
"Run /semver patch|minor|major|auto to apply (add --dry to preview)."
|
|
2748
|
+
].join("\n")
|
|
2621
2749
|
};
|
|
2622
2750
|
}
|
|
2623
|
-
|
|
2624
|
-
|
|
2625
|
-
const pkgData = JSON.parse(fs.readFileSync(pkgPath, "utf-8"));
|
|
2626
|
-
pkgData.version = newVersion;
|
|
2627
|
-
fs.writeFileSync(pkgPath, JSON.stringify(pkgData, null, 2) + "\n", "utf-8");
|
|
2628
|
-
try {
|
|
2629
|
-
runGit2(["add", "package.json"], cwd);
|
|
2630
|
-
runGit2(["commit", "-m", `chore: bump version to ${newVersion}`], cwd);
|
|
2631
|
-
} catch {
|
|
2751
|
+
if (mode !== "patch" && mode !== "minor" && mode !== "major" && mode !== "auto") {
|
|
2752
|
+
return { message: `Unknown mode "${mode}". Use status, patch, minor, major or auto.` };
|
|
2632
2753
|
}
|
|
2633
|
-
|
|
2634
|
-
|
|
2635
|
-
runGit2(["tag", "-a", `${tagPrefix}${newVersion}`, "-m", `Release ${newVersion}`], cwd);
|
|
2636
|
-
} catch {
|
|
2637
|
-
}
|
|
2638
|
-
}
|
|
2639
|
-
api.log.info("semver-bump: bumped", { from: currentVersion, to: newVersion, bump: bumpPart });
|
|
2640
|
-
api.metrics.counter("version_bump", 1, { bump: bumpPart });
|
|
2641
|
-
await api.session.append({
|
|
2642
|
-
type: "semver-bump:bumped",
|
|
2643
|
-
ts: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2644
|
-
from: currentVersion,
|
|
2645
|
-
to: newVersion,
|
|
2646
|
-
bump: bumpPart
|
|
2647
|
-
});
|
|
2648
|
-
return {
|
|
2649
|
-
ok: true,
|
|
2650
|
-
currentVersion,
|
|
2651
|
-
newVersion,
|
|
2652
|
-
bump: bumpPart,
|
|
2653
|
-
tag: `${tagPrefix}${newVersion}`,
|
|
2654
|
-
message: `Bumped ${currentVersion} \u2192 ${newVersion} (${bumpPart})`
|
|
2655
|
-
};
|
|
2754
|
+
const result = await performBump(mode, dry, cwd);
|
|
2755
|
+
return { message: String(result["message"] ?? result["error"] ?? JSON.stringify(result)) };
|
|
2656
2756
|
}
|
|
2657
2757
|
});
|
|
2658
2758
|
api.tools.register({
|
|
@@ -2677,7 +2777,7 @@ var plugin10 = {
|
|
|
2677
2777
|
latestTag = tagsOutput || null;
|
|
2678
2778
|
if (latestTag) {
|
|
2679
2779
|
const countOutput = runGit2(["rev-list", "--count", `${latestTag}..HEAD`], cwd);
|
|
2680
|
-
commitsSinceTag = Number.parseInt(countOutput) || 0;
|
|
2780
|
+
commitsSinceTag = Number.parseInt(countOutput, 10) || 0;
|
|
2681
2781
|
}
|
|
2682
2782
|
} catch {
|
|
2683
2783
|
latestTag = null;
|
|
@@ -2718,15 +2818,7 @@ var plugin10 = {
|
|
|
2718
2818
|
const spaceIdx = line.indexOf(" ");
|
|
2719
2819
|
const hash = line.slice(0, spaceIdx);
|
|
2720
2820
|
const message = line.slice(spaceIdx + 1);
|
|
2721
|
-
|
|
2722
|
-
const type = m?.[1] ?? "chore";
|
|
2723
|
-
return {
|
|
2724
|
-
hash,
|
|
2725
|
-
type,
|
|
2726
|
-
scope: m?.[2],
|
|
2727
|
-
message: m?.[3] ?? message,
|
|
2728
|
-
breaking: !!m?.[2]
|
|
2729
|
-
};
|
|
2821
|
+
return { hash, ...parseConventional(message) };
|
|
2730
2822
|
});
|
|
2731
2823
|
} catch (err) {
|
|
2732
2824
|
return { ok: false, error: `Failed to get git log: ${err}` };
|
package/dist/semver-bump.d.ts
CHANGED
|
@@ -9,6 +9,18 @@ import { Plugin } from '@wrongstack/core';
|
|
|
9
9
|
* - semver_changelog: Generate a changelog between two versions
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
|
+
type BumpType = 'major' | 'minor' | 'patch' | 'auto';
|
|
13
|
+
interface ConventionalCommit {
|
|
14
|
+
hash: string;
|
|
15
|
+
type: string;
|
|
16
|
+
scope?: string | undefined;
|
|
17
|
+
message: string;
|
|
18
|
+
breaking: boolean;
|
|
19
|
+
}
|
|
20
|
+
/** Parse a conventional-commit subject line. Accepts the breaking `!` both
|
|
21
|
+
* before and after the scope (`feat!: x`, `feat(api)!: x`). */
|
|
22
|
+
declare function parseConventional(subject: string): Omit<ConventionalCommit, 'hash'>;
|
|
23
|
+
declare function determineBump(commits: ConventionalCommit[]): BumpType;
|
|
12
24
|
declare const plugin: Plugin;
|
|
13
25
|
|
|
14
|
-
export { plugin as default };
|
|
26
|
+
export { plugin as default, determineBump, parseConventional };
|
package/dist/semver-bump.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { expectDefined } from '@wrongstack/core';
|
|
2
2
|
import { execFileSync } from 'child_process';
|
|
3
|
-
import { existsSync, readFileSync } from 'fs';
|
|
3
|
+
import { existsSync, readFileSync, writeFileSync, readdirSync } from 'fs';
|
|
4
|
+
import { join } from 'path';
|
|
4
5
|
|
|
5
6
|
// src/semver-bump/index.ts
|
|
6
7
|
var API_VERSION = "^0.1.10";
|
|
@@ -28,10 +29,25 @@ function getPackageJson(cwd) {
|
|
|
28
29
|
return null;
|
|
29
30
|
}
|
|
30
31
|
}
|
|
32
|
+
function collectManifests(root) {
|
|
33
|
+
const paths = [];
|
|
34
|
+
const rootPkg = join(root, "package.json");
|
|
35
|
+
if (existsSync(rootPkg)) paths.push(rootPkg);
|
|
36
|
+
for (const group of ["packages", "apps"]) {
|
|
37
|
+
const groupDir = join(root, group);
|
|
38
|
+
if (!existsSync(groupDir)) continue;
|
|
39
|
+
for (const entry of readdirSync(groupDir, { withFileTypes: true })) {
|
|
40
|
+
if (!entry.isDirectory()) continue;
|
|
41
|
+
const candidate = join(groupDir, entry.name, "package.json");
|
|
42
|
+
if (existsSync(candidate)) paths.push(candidate);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return paths;
|
|
46
|
+
}
|
|
31
47
|
function parseVersion(v) {
|
|
32
48
|
const m = v.match(/^v?(\d+)\.(\d+)\.(\d+)/);
|
|
33
49
|
if (!m) return [0, 0, 0];
|
|
34
|
-
return [Number.parseInt(expectDefined(m[1])), Number.parseInt(expectDefined(m[2])), Number.parseInt(expectDefined(m[3]))];
|
|
50
|
+
return [Number.parseInt(expectDefined(m[1]), 10), Number.parseInt(expectDefined(m[2]), 10), Number.parseInt(expectDefined(m[3]), 10)];
|
|
35
51
|
}
|
|
36
52
|
function bumpVersion(version, part) {
|
|
37
53
|
let [major, minor, patch] = parseVersion(version);
|
|
@@ -49,6 +65,15 @@ function bumpVersion(version, part) {
|
|
|
49
65
|
}
|
|
50
66
|
return `${major}.${minor}.${patch}`;
|
|
51
67
|
}
|
|
68
|
+
function parseConventional(subject) {
|
|
69
|
+
const m = subject.match(/^(\w+)(!)?(?:\(([^)]+)\))?(!)?:\s+(.+)/);
|
|
70
|
+
return {
|
|
71
|
+
type: m?.[1] ?? "chore",
|
|
72
|
+
breaking: !!(m?.[2] ?? m?.[4]),
|
|
73
|
+
scope: m?.[3],
|
|
74
|
+
message: m?.[5] ?? subject
|
|
75
|
+
};
|
|
76
|
+
}
|
|
52
77
|
function getRecentCommits(sinceTag, cwd) {
|
|
53
78
|
const range = sinceTag ? `${sinceTag}..HEAD` : "-30";
|
|
54
79
|
const output = runGit(["log", range, "--format=%H %s"], cwd);
|
|
@@ -57,25 +82,12 @@ function getRecentCommits(sinceTag, cwd) {
|
|
|
57
82
|
const spaceIdx = line.indexOf(" ");
|
|
58
83
|
const hash = line.slice(0, spaceIdx);
|
|
59
84
|
const message = line.slice(spaceIdx + 1);
|
|
60
|
-
|
|
61
|
-
const type = m?.[1] ?? "chore";
|
|
62
|
-
const breaking = !!m?.[2];
|
|
63
|
-
const scope = m?.[2];
|
|
64
|
-
const msg = m?.[3] ?? message;
|
|
65
|
-
return { hash, type, scope, message: msg, breaking };
|
|
85
|
+
return { hash, ...parseConventional(message) };
|
|
66
86
|
});
|
|
67
87
|
}
|
|
68
88
|
function determineBump(commits) {
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
return "major";
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
for (const c of commits) {
|
|
75
|
-
if (c.type === "feat" || c.type === "refactor" && c.scope) {
|
|
76
|
-
return "minor";
|
|
77
|
-
}
|
|
78
|
-
}
|
|
89
|
+
if (commits.some((c) => c.breaking)) return "major";
|
|
90
|
+
if (commits.some((c) => c.type === "feat")) return "minor";
|
|
79
91
|
return "patch";
|
|
80
92
|
}
|
|
81
93
|
function generateChangelog(commits) {
|
|
@@ -137,12 +149,13 @@ var plugin = {
|
|
|
137
149
|
version: "0.1.0",
|
|
138
150
|
description: "Conventional-commit-driven semver version bumps with changelog generation",
|
|
139
151
|
apiVersion: API_VERSION,
|
|
140
|
-
capabilities: { tools: true },
|
|
152
|
+
capabilities: { tools: true, slashCommands: true },
|
|
141
153
|
defaultConfig: {
|
|
142
154
|
tagPrefix: "v",
|
|
143
155
|
changelogFile: "CHANGELOG.md",
|
|
144
156
|
autoTag: true,
|
|
145
|
-
tagMessage: "Release {{version}}"
|
|
157
|
+
tagMessage: "Release {{version}}",
|
|
158
|
+
defaultPart: "patch"
|
|
146
159
|
},
|
|
147
160
|
configSchema: {
|
|
148
161
|
type: "object",
|
|
@@ -150,12 +163,114 @@ var plugin = {
|
|
|
150
163
|
tagPrefix: { type: "string", default: "v" },
|
|
151
164
|
changelogFile: { type: "string", default: "CHANGELOG.md" },
|
|
152
165
|
autoTag: { type: "boolean", default: true },
|
|
153
|
-
tagMessage: { type: "string", default: "Release {{version}}" }
|
|
166
|
+
tagMessage: { type: "string", default: "Release {{version}}" },
|
|
167
|
+
defaultPart: { type: "string", enum: ["major", "minor", "patch", "auto"], default: "patch" }
|
|
154
168
|
}
|
|
155
169
|
},
|
|
156
170
|
setup(api) {
|
|
157
171
|
const tagPrefix = api.config.extensions?.["semver-bump"]?.["tagPrefix"] ?? "v";
|
|
158
172
|
const autoTag = api.config.extensions?.["semver-bump"]?.["autoTag"] ?? true;
|
|
173
|
+
const VALID_PARTS = ["major", "minor", "patch", "auto"];
|
|
174
|
+
function readDefaultPart(cfg) {
|
|
175
|
+
const raw = cfg.extensions?.["semver-bump"]?.["defaultPart"];
|
|
176
|
+
return VALID_PARTS.includes(raw) ? raw : "patch";
|
|
177
|
+
}
|
|
178
|
+
let defaultPart = readDefaultPart(api.config);
|
|
179
|
+
api.onConfigChange?.((next) => {
|
|
180
|
+
defaultPart = readDefaultPart(next);
|
|
181
|
+
});
|
|
182
|
+
async function performBump(part, dryRun, cwd) {
|
|
183
|
+
const pkg = getPackageJson(cwd);
|
|
184
|
+
if (!pkg) {
|
|
185
|
+
return { ok: false, error: "No package.json found" };
|
|
186
|
+
}
|
|
187
|
+
const currentVersion = pkg.version;
|
|
188
|
+
let bumpPart = part;
|
|
189
|
+
let commits = [];
|
|
190
|
+
if (part === "auto") {
|
|
191
|
+
let lastTag;
|
|
192
|
+
try {
|
|
193
|
+
const tagsOutput = runGit(["describe", "--tags", "--abbrev=0"], cwd);
|
|
194
|
+
lastTag = tagsOutput || void 0;
|
|
195
|
+
} catch {
|
|
196
|
+
}
|
|
197
|
+
try {
|
|
198
|
+
commits = getRecentCommits(lastTag, cwd);
|
|
199
|
+
} catch (err) {
|
|
200
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
201
|
+
return { ok: false, error: `Git error: ${msg}`, bumpPart: "patch" };
|
|
202
|
+
}
|
|
203
|
+
bumpPart = determineBump(commits);
|
|
204
|
+
} else {
|
|
205
|
+
bumpPart = part;
|
|
206
|
+
}
|
|
207
|
+
const newVersion = bumpVersion(currentVersion, bumpPart);
|
|
208
|
+
if (dryRun) {
|
|
209
|
+
return {
|
|
210
|
+
ok: true,
|
|
211
|
+
dryRun: true,
|
|
212
|
+
currentVersion,
|
|
213
|
+
suggestedBump: bumpPart,
|
|
214
|
+
newVersion,
|
|
215
|
+
commitCount: part === "auto" ? commits.length : void 0,
|
|
216
|
+
message: `Would bump ${currentVersion} \u2192 ${newVersion} (${bumpPart})`
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
const root = cwd ?? process.cwd();
|
|
220
|
+
const bumpScript = join(root, "scripts", "bump-version.mjs");
|
|
221
|
+
const changed = collectManifests(root);
|
|
222
|
+
if (existsSync(bumpScript)) {
|
|
223
|
+
try {
|
|
224
|
+
execFileSync(process.execPath, [bumpScript, "set", newVersion], {
|
|
225
|
+
cwd: root,
|
|
226
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
227
|
+
timeout: 3e4,
|
|
228
|
+
windowsHide: true
|
|
229
|
+
});
|
|
230
|
+
} catch (err) {
|
|
231
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
232
|
+
return { ok: false, error: `bump script failed: ${msg}` };
|
|
233
|
+
}
|
|
234
|
+
for (const rel of ["package.json", "package-lock.json", "src/lib/utils.ts", "index.html"]) {
|
|
235
|
+
const p = join(root, "website", rel);
|
|
236
|
+
if (existsSync(p)) changed.push(p);
|
|
237
|
+
}
|
|
238
|
+
} else {
|
|
239
|
+
for (const manifest of changed) {
|
|
240
|
+
const pkgData = JSON.parse(readFileSync(manifest, "utf-8"));
|
|
241
|
+
pkgData.version = newVersion;
|
|
242
|
+
writeFileSync(manifest, JSON.stringify(pkgData, null, 2) + "\n", "utf-8");
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
try {
|
|
246
|
+
runGit(["add", "--", ...changed], cwd);
|
|
247
|
+
runGit(["commit", "-m", `chore: bump version to ${newVersion}`], cwd);
|
|
248
|
+
} catch {
|
|
249
|
+
}
|
|
250
|
+
if (autoTag) {
|
|
251
|
+
try {
|
|
252
|
+
runGit(["tag", "-a", `${tagPrefix}${newVersion}`, "-m", `Release ${newVersion}`], cwd);
|
|
253
|
+
} catch {
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
api.log.info("semver-bump: bumped", { from: currentVersion, to: newVersion, bump: bumpPart });
|
|
257
|
+
api.metrics.counter("version_bump", 1, { bump: bumpPart });
|
|
258
|
+
await api.session.append({
|
|
259
|
+
type: "semver-bump:bumped",
|
|
260
|
+
ts: (/* @__PURE__ */ new Date()).toISOString(),
|
|
261
|
+
from: currentVersion,
|
|
262
|
+
to: newVersion,
|
|
263
|
+
bump: bumpPart
|
|
264
|
+
});
|
|
265
|
+
return {
|
|
266
|
+
ok: true,
|
|
267
|
+
currentVersion,
|
|
268
|
+
newVersion,
|
|
269
|
+
bump: bumpPart,
|
|
270
|
+
tag: `${tagPrefix}${newVersion}`,
|
|
271
|
+
message: `Bumped ${currentVersion} \u2192 ${newVersion} (${bumpPart})`
|
|
272
|
+
};
|
|
273
|
+
}
|
|
159
274
|
api.tools.register({
|
|
160
275
|
name: "semver_bump",
|
|
161
276
|
description: "Determine the next version bump from conventional commits since the last tag, or force a specific bump. Creates a git tag.",
|
|
@@ -164,7 +279,7 @@ var plugin = {
|
|
|
164
279
|
properties: {
|
|
165
280
|
cwd: { type: "string", description: "Working directory (defaults to project root)" },
|
|
166
281
|
dryRun: { type: "boolean", default: false },
|
|
167
|
-
part: { type: "string", enum: ["major", "minor", "patch", "auto"], default:
|
|
282
|
+
part: { type: "string", enum: ["major", "minor", "patch", "auto"], default: defaultPart, description: "Version part to bump. Omitted \u2192 the configured default (/settings semver-part, factory default: patch). Use auto to infer from commits." }
|
|
168
283
|
}
|
|
169
284
|
},
|
|
170
285
|
permission: "confirm",
|
|
@@ -172,76 +287,62 @@ var plugin = {
|
|
|
172
287
|
async execute(input) {
|
|
173
288
|
const cwd = input["cwd"];
|
|
174
289
|
const dryRun = input["dryRun"] ?? false;
|
|
175
|
-
const part = input["part"] ??
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
290
|
+
const part = input["part"] ?? defaultPart;
|
|
291
|
+
return performBump(part, dryRun, cwd);
|
|
292
|
+
}
|
|
293
|
+
});
|
|
294
|
+
api.slashCommands.register({
|
|
295
|
+
name: "semver",
|
|
296
|
+
description: "Show the current version or bump it (patch/minor/major/auto)",
|
|
297
|
+
category: "Run",
|
|
298
|
+
argsHint: "[status|patch|minor|major|auto] [--dry]",
|
|
299
|
+
help: [
|
|
300
|
+
"/semver Show current version, latest tag and the suggested bump",
|
|
301
|
+
"/semver status Same as bare /semver",
|
|
302
|
+
"/semver patch Bump the patch version (commit + tag)",
|
|
303
|
+
"/semver minor Bump the minor version (commit + tag)",
|
|
304
|
+
"/semver major Bump the major version (commit + tag)",
|
|
305
|
+
"/semver auto Infer the bump from conventional commits since the last tag",
|
|
306
|
+
"/semver <part> --dry Preview without writing anything"
|
|
307
|
+
].join("\n"),
|
|
308
|
+
async run(args, ctx) {
|
|
309
|
+
const tokens = args.trim().split(/\s+/).filter(Boolean);
|
|
310
|
+
const dry = tokens.includes("--dry") || tokens.includes("--dry-run");
|
|
311
|
+
const mode = tokens.find((t) => !t.startsWith("--")) ?? "status";
|
|
312
|
+
const cwd = ctx?.cwd;
|
|
313
|
+
if (mode === "status") {
|
|
314
|
+
const pkg = getPackageJson(cwd);
|
|
315
|
+
if (!pkg) return { message: "No package.json found" };
|
|
184
316
|
let lastTag;
|
|
185
317
|
try {
|
|
186
|
-
|
|
187
|
-
lastTag = tagsOutput || void 0;
|
|
318
|
+
lastTag = runGit(["describe", "--tags", "--abbrev=0"], cwd) || void 0;
|
|
188
319
|
} catch {
|
|
189
320
|
}
|
|
321
|
+
let suggestion = "patch";
|
|
322
|
+
let commitCount = 0;
|
|
190
323
|
try {
|
|
191
|
-
commits = getRecentCommits(lastTag, cwd);
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
324
|
+
const commits = getRecentCommits(lastTag, cwd);
|
|
325
|
+
commitCount = commits.length;
|
|
326
|
+
suggestion = determineBump(commits);
|
|
327
|
+
} catch {
|
|
195
328
|
}
|
|
196
|
-
bumpPart = determineBump(commits);
|
|
197
|
-
} else {
|
|
198
|
-
bumpPart = part;
|
|
199
|
-
}
|
|
200
|
-
const newVersion = bumpVersion(currentVersion, bumpPart);
|
|
201
|
-
if (dryRun) {
|
|
202
329
|
return {
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
330
|
+
message: [
|
|
331
|
+
`Current version: ${pkg.version}`,
|
|
332
|
+
`Latest tag: ${lastTag ?? "(none)"}`,
|
|
333
|
+
`Commits since: ${commitCount}`,
|
|
334
|
+
`Suggested bump: ${suggestion} \u2192 ${bumpVersion(pkg.version, suggestion)}`,
|
|
335
|
+
`Default part: ${defaultPart} (change: /settings semver-part)`,
|
|
336
|
+
"",
|
|
337
|
+
"Run /semver patch|minor|major|auto to apply (add --dry to preview)."
|
|
338
|
+
].join("\n")
|
|
210
339
|
};
|
|
211
340
|
}
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
const pkgData = JSON.parse(fs.readFileSync(pkgPath, "utf-8"));
|
|
215
|
-
pkgData.version = newVersion;
|
|
216
|
-
fs.writeFileSync(pkgPath, JSON.stringify(pkgData, null, 2) + "\n", "utf-8");
|
|
217
|
-
try {
|
|
218
|
-
runGit(["add", "package.json"], cwd);
|
|
219
|
-
runGit(["commit", "-m", `chore: bump version to ${newVersion}`], cwd);
|
|
220
|
-
} catch {
|
|
221
|
-
}
|
|
222
|
-
if (autoTag) {
|
|
223
|
-
try {
|
|
224
|
-
runGit(["tag", "-a", `${tagPrefix}${newVersion}`, "-m", `Release ${newVersion}`], cwd);
|
|
225
|
-
} catch {
|
|
226
|
-
}
|
|
341
|
+
if (mode !== "patch" && mode !== "minor" && mode !== "major" && mode !== "auto") {
|
|
342
|
+
return { message: `Unknown mode "${mode}". Use status, patch, minor, major or auto.` };
|
|
227
343
|
}
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
await api.session.append({
|
|
231
|
-
type: "semver-bump:bumped",
|
|
232
|
-
ts: (/* @__PURE__ */ new Date()).toISOString(),
|
|
233
|
-
from: currentVersion,
|
|
234
|
-
to: newVersion,
|
|
235
|
-
bump: bumpPart
|
|
236
|
-
});
|
|
237
|
-
return {
|
|
238
|
-
ok: true,
|
|
239
|
-
currentVersion,
|
|
240
|
-
newVersion,
|
|
241
|
-
bump: bumpPart,
|
|
242
|
-
tag: `${tagPrefix}${newVersion}`,
|
|
243
|
-
message: `Bumped ${currentVersion} \u2192 ${newVersion} (${bumpPart})`
|
|
244
|
-
};
|
|
344
|
+
const result = await performBump(mode, dry, cwd);
|
|
345
|
+
return { message: String(result["message"] ?? result["error"] ?? JSON.stringify(result)) };
|
|
245
346
|
}
|
|
246
347
|
});
|
|
247
348
|
api.tools.register({
|
|
@@ -266,7 +367,7 @@ var plugin = {
|
|
|
266
367
|
latestTag = tagsOutput || null;
|
|
267
368
|
if (latestTag) {
|
|
268
369
|
const countOutput = runGit(["rev-list", "--count", `${latestTag}..HEAD`], cwd);
|
|
269
|
-
commitsSinceTag = Number.parseInt(countOutput) || 0;
|
|
370
|
+
commitsSinceTag = Number.parseInt(countOutput, 10) || 0;
|
|
270
371
|
}
|
|
271
372
|
} catch {
|
|
272
373
|
latestTag = null;
|
|
@@ -307,15 +408,7 @@ var plugin = {
|
|
|
307
408
|
const spaceIdx = line.indexOf(" ");
|
|
308
409
|
const hash = line.slice(0, spaceIdx);
|
|
309
410
|
const message = line.slice(spaceIdx + 1);
|
|
310
|
-
|
|
311
|
-
const type = m?.[1] ?? "chore";
|
|
312
|
-
return {
|
|
313
|
-
hash,
|
|
314
|
-
type,
|
|
315
|
-
scope: m?.[2],
|
|
316
|
-
message: m?.[3] ?? message,
|
|
317
|
-
breaking: !!m?.[2]
|
|
318
|
-
};
|
|
411
|
+
return { hash, ...parseConventional(message) };
|
|
319
412
|
});
|
|
320
413
|
} catch (err) {
|
|
321
414
|
return { ok: false, error: `Failed to get git log: ${err}` };
|
|
@@ -345,4 +438,4 @@ var plugin = {
|
|
|
345
438
|
};
|
|
346
439
|
var semver_bump_default = plugin;
|
|
347
440
|
|
|
348
|
-
export { semver_bump_default as default };
|
|
441
|
+
export { semver_bump_default as default, determineBump, parseConventional };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wrongstack/plugins",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.256.0",
|
|
4
4
|
"description": "Official WrongStack plugin collection — auto-doc, git-autocommit, shell-check, cost-tracker, file-watcher, web-search, json-path, cron, template-engine, semver-bump",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "ECOSTACK TECHNOLOGY OÜ",
|
|
@@ -57,13 +57,13 @@
|
|
|
57
57
|
"dist"
|
|
58
58
|
],
|
|
59
59
|
"devDependencies": {
|
|
60
|
-
"@types/node": "^25.9.
|
|
60
|
+
"@types/node": "^25.9.3",
|
|
61
61
|
"tsup": "^8.5.1",
|
|
62
62
|
"typescript": "^6.0.3",
|
|
63
63
|
"vitest": "^4.1.8"
|
|
64
64
|
},
|
|
65
65
|
"dependencies": {
|
|
66
|
-
"@wrongstack/core": "0.
|
|
66
|
+
"@wrongstack/core": "0.256.0"
|
|
67
67
|
},
|
|
68
68
|
"scripts": {
|
|
69
69
|
"build": "tsup",
|