@varlock/bumpy 0.0.0 → 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/plugin.json +13 -0
- package/dist/add-u5V9V3L7.mjs +131 -0
- package/dist/ai-B8ZL2x8z.mjs +82 -0
- package/dist/apply-release-plan-DtU3rVyL.mjs +132 -0
- package/dist/changelog-github-n-3zV1p9.mjs +59 -0
- package/dist/changeset-ClCYsChu.mjs +75 -0
- package/dist/check-CkRubvuk.mjs +57 -0
- package/dist/ci-8KWWhjXl.mjs +224 -0
- package/dist/cli.d.mts +1 -0
- package/dist/cli.mjs +210 -0
- package/dist/config-CJ2orhTL.mjs +215 -0
- package/dist/dep-graph-DiLeAhl9.mjs +64 -0
- package/dist/fs-DbNNEyzq.mjs +51 -0
- package/dist/generate-oOFD9ABC.mjs +158 -0
- package/dist/index.d.mts +254 -0
- package/dist/index.mjs +9 -0
- package/dist/init-Blw2GfC_.mjs +22 -0
- package/dist/js-yaml-DpZfOoD4.mjs +2031 -0
- package/dist/logger-ZqggsyGZ.mjs +176 -0
- package/dist/migrate-DvOrXSw0.mjs +114 -0
- package/dist/names-C-u50ofE.mjs +143 -0
- package/dist/prompt-BP8toAOI.mjs +46 -0
- package/dist/publish-DZ3m7qkX.mjs +197 -0
- package/dist/publish-pipeline-1M5GmbdP.mjs +291 -0
- package/dist/release-plan-CFnutSHD.mjs +173 -0
- package/dist/semver-DWO6NFKN.mjs +1360 -0
- package/dist/shell-DPlltpzb.mjs +44 -0
- package/dist/status-DRpq_Mha.mjs +106 -0
- package/dist/version-CJwf8XIA.mjs +81 -0
- package/dist/workspace-mVjawG8g.mjs +183 -0
- package/package.json +36 -6
- package/skills/add-change/SKILL.md +108 -0
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
//#region \0rolldown/runtime.js
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __commonJSMin = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports);
|
|
9
|
+
var __exportAll = (all, no_symbols) => {
|
|
10
|
+
let target = {};
|
|
11
|
+
for (var name in all) __defProp(target, name, {
|
|
12
|
+
get: all[name],
|
|
13
|
+
enumerable: true
|
|
14
|
+
});
|
|
15
|
+
if (!no_symbols) __defProp(target, Symbol.toStringTag, { value: "Module" });
|
|
16
|
+
return target;
|
|
17
|
+
};
|
|
18
|
+
var __copyProps = (to, from, except, desc) => {
|
|
19
|
+
if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
|
|
20
|
+
key = keys[i];
|
|
21
|
+
if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
|
|
22
|
+
get: ((k) => from[k]).bind(null, key),
|
|
23
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
return to;
|
|
27
|
+
};
|
|
28
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
|
|
29
|
+
value: mod,
|
|
30
|
+
enumerable: true
|
|
31
|
+
}) : target, mod));
|
|
32
|
+
const { Ansis, fg, bg, rgb, bgRgb, hex, bgHex, reset, inverse, hidden, visible, bold, dim, italic, underline, strikethrough, black, red, green, yellow, blue, magenta, cyan, white, gray, redBright, greenBright, yellowBright, blueBright, magentaBright, cyanBright, whiteBright, bgBlack, bgRed, bgGreen, bgYellow, bgBlue, bgMagenta, bgCyan, bgWhite, bgGray, bgRedBright, bgGreenBright, bgYellowBright, bgBlueBright, bgMagentaBright, bgCyanBright, bgWhiteBright } = (/* @__PURE__ */ __toESM((/* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
33
|
+
let e, t, r, { defineProperty: l, setPrototypeOf: n, create: o, keys: s } = Object, i = "", { round: c, max: a } = Math, p = (e) => {
|
|
34
|
+
let t = /([a-f\d]{3,6})/i.exec(e)?.[1], r = t?.length, l = parseInt(6 ^ r ? 3 ^ r ? "0" : t[0] + t[0] + t[1] + t[1] + t[2] + t[2] : t, 16);
|
|
35
|
+
return [
|
|
36
|
+
l >> 16 & 255,
|
|
37
|
+
l >> 8 & 255,
|
|
38
|
+
255 & l
|
|
39
|
+
];
|
|
40
|
+
}, u = (e, t, r) => e ^ t || t ^ r ? 16 + 36 * c(e / 51) + 6 * c(t / 51) + c(r / 51) : 8 > e ? 16 : e > 248 ? 231 : c(24 * (e - 8) / 247) + 232, d = (e) => {
|
|
41
|
+
let t, r, l, n, o;
|
|
42
|
+
return 8 > e ? 30 + e : 16 > e ? e - 8 + 90 : (232 > e ? (o = (e -= 16) % 36, t = (e / 36 | 0) / 5, r = (o / 6 | 0) / 5, l = o % 6 / 5) : t = r = l = (10 * (e - 232) + 8) / 255, n = 2 * a(t, r, l), n ? 30 + (c(l) << 2 | c(r) << 1 | c(t)) + (2 ^ n ? 0 : 60) : 30);
|
|
43
|
+
}, f = (() => {
|
|
44
|
+
let r = (e) => o.some(((t) => e.test(t))), l = globalThis, n = l.process ?? {}, o = n.argv ?? [], i = n.env ?? {}, c = -1;
|
|
45
|
+
try {
|
|
46
|
+
e = "," + s(i).join(",");
|
|
47
|
+
} catch (e) {
|
|
48
|
+
i = {}, c = 0;
|
|
49
|
+
}
|
|
50
|
+
let a = "FORCE_COLOR", p = {
|
|
51
|
+
false: 0,
|
|
52
|
+
0: 0,
|
|
53
|
+
1: 1,
|
|
54
|
+
2: 2,
|
|
55
|
+
3: 3
|
|
56
|
+
}[i[a]] ?? -1, u = a in i && p || r(/^--color=?(true|always)?$/);
|
|
57
|
+
return u && (c = p), ~c || (c = ((r, l, n) => (t = r.TERM, {
|
|
58
|
+
"24bit": 3,
|
|
59
|
+
truecolor: 3,
|
|
60
|
+
ansi256: 2,
|
|
61
|
+
ansi: 1
|
|
62
|
+
}[r.COLORTERM] || (r.CI ? /,GITHUB/.test(e) ? 3 : 1 : l && "dumb" !== t ? n ? 3 : /-256/.test(t) ? 2 : 1 : 0)))(i, !!i.PM2_HOME || i.NEXT_RUNTIME?.includes("edge") || !!n.stdout?.isTTY, "win32" === n.platform)), !p || i.NO_COLOR || r(/^--(no-color|color=(false|never))$/) ? 0 : l.window?.chrome || u && !c ? 3 : c;
|
|
63
|
+
})(), g = {
|
|
64
|
+
open: i,
|
|
65
|
+
close: i
|
|
66
|
+
}, h = 39, b = 49, O = {}, m = ({ p: e }, { open: t, close: l }) => {
|
|
67
|
+
let o = (e, ...r) => {
|
|
68
|
+
if (!e) {
|
|
69
|
+
if (t && t === l) return t;
|
|
70
|
+
if ((e ?? i) === i) return i;
|
|
71
|
+
}
|
|
72
|
+
let n, s = e.raw ? String.raw({ raw: e }, ...r) : i + e, c = o.p, a = c.o, p = c.c;
|
|
73
|
+
if (s.includes("\x1B")) for (; c; c = c.p) {
|
|
74
|
+
let { open: e, close: t } = c, r = t.length, l = i, o = 0;
|
|
75
|
+
if (r) for (; ~(n = s.indexOf(t, o)); o = n + r) l += s.slice(o, n) + e;
|
|
76
|
+
s = l + s.slice(o);
|
|
77
|
+
}
|
|
78
|
+
return a + (s.includes("\n") ? s.replace(/(\r?\n)/g, p + "$1" + a) : s) + p;
|
|
79
|
+
}, s = t, c = l;
|
|
80
|
+
return e && (s = e.o + t, c = l + e.c), n(o, r), o.p = {
|
|
81
|
+
open: t,
|
|
82
|
+
close: l,
|
|
83
|
+
o: s,
|
|
84
|
+
c,
|
|
85
|
+
p: e
|
|
86
|
+
}, o.open = s, o.close = c, o;
|
|
87
|
+
};
|
|
88
|
+
const w = new function e(t = f) {
|
|
89
|
+
let s = {
|
|
90
|
+
Ansis: e,
|
|
91
|
+
level: t,
|
|
92
|
+
isSupported: () => a,
|
|
93
|
+
strip: (e) => e.replace(/[][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]/g, i),
|
|
94
|
+
extend(e) {
|
|
95
|
+
for (let t in e) {
|
|
96
|
+
let r = e[t], l = (typeof r)[0];
|
|
97
|
+
"s" === l ? (c(t, T(...p(r))), c(_(t), v(...p(r)))) : c(t, r, "f" === l);
|
|
98
|
+
}
|
|
99
|
+
return r = o({}, O), n(s, r), s;
|
|
100
|
+
}
|
|
101
|
+
}, c = (e, t, r) => {
|
|
102
|
+
O[e] = { get() {
|
|
103
|
+
let n = r ? (...e) => m(this, t(...e)) : m(this, t);
|
|
104
|
+
return l(this, e, { value: n }), n;
|
|
105
|
+
} };
|
|
106
|
+
}, a = t > 0, w = (e, t) => a ? {
|
|
107
|
+
open: `[${e}m`,
|
|
108
|
+
close: `[${t}m`
|
|
109
|
+
} : g, y = (e) => (t) => e(...p(t)), R = (e, t) => (r, l, n) => w(`${e}8;2;${r};${l};${n}`, t), $ = (e, t) => (r, l, n) => w(((e, t, r) => d(u(e, t, r)))(r, l, n) + e, t), x = (e) => (t, r, l) => e(u(t, r, l)), T = R(3, h), v = R(4, b), C = (e) => w("38;5;" + e, h), E = (e) => w("48;5;" + e, b);
|
|
110
|
+
2 === t ? (T = x(C), v = x(E)) : 1 === t && (T = $(0, h), v = $(10, b), C = (e) => w(d(e), h), E = (e) => w(d(e) + 10, b));
|
|
111
|
+
let M, I = {
|
|
112
|
+
fg: C,
|
|
113
|
+
bg: E,
|
|
114
|
+
rgb: T,
|
|
115
|
+
bgRgb: v,
|
|
116
|
+
hex: y(T),
|
|
117
|
+
bgHex: y(v),
|
|
118
|
+
visible: g,
|
|
119
|
+
reset: w(0, 0),
|
|
120
|
+
bold: w(1, 22),
|
|
121
|
+
dim: w(2, 22),
|
|
122
|
+
italic: w(3, 23),
|
|
123
|
+
underline: w(4, 24),
|
|
124
|
+
inverse: w(7, 27),
|
|
125
|
+
hidden: w(8, 28),
|
|
126
|
+
strikethrough: w(9, 29)
|
|
127
|
+
}, _ = (e) => "bg" + e[0].toUpperCase() + e.slice(1), k = "Bright";
|
|
128
|
+
return "black,red,green,yellow,blue,magenta,cyan,white,gray".split(",").map(((e, t) => {
|
|
129
|
+
M = _(e), 8 > t ? (I[e + k] = w(90 + t, h), I[M + k] = w(100 + t, b)) : t = 60, I[e] = w(30 + t, h), I[M] = w(40 + t, b);
|
|
130
|
+
})), s.extend(I);
|
|
131
|
+
}();
|
|
132
|
+
module.exports = w, w.default = w;
|
|
133
|
+
})))(), 1)).default;
|
|
134
|
+
//#endregion
|
|
135
|
+
//#region src/utils/logger.ts
|
|
136
|
+
const log = {
|
|
137
|
+
info(msg) {
|
|
138
|
+
console.log(`${blue`info`} ${msg}`);
|
|
139
|
+
},
|
|
140
|
+
success(msg) {
|
|
141
|
+
console.log(`${green`done`} ${msg}`);
|
|
142
|
+
},
|
|
143
|
+
warn(msg) {
|
|
144
|
+
console.log(`${yellow`warn`} ${msg}`);
|
|
145
|
+
},
|
|
146
|
+
error(msg) {
|
|
147
|
+
console.error(`${red`error`} ${msg}`);
|
|
148
|
+
},
|
|
149
|
+
step(msg) {
|
|
150
|
+
console.log(`${cyan`=>`} ${msg}`);
|
|
151
|
+
},
|
|
152
|
+
dim(msg) {
|
|
153
|
+
console.log(dim`${msg}`);
|
|
154
|
+
},
|
|
155
|
+
bold(msg) {
|
|
156
|
+
console.log(bold`${msg}`);
|
|
157
|
+
},
|
|
158
|
+
table(rows) {
|
|
159
|
+
if (rows.length === 0) return;
|
|
160
|
+
const colWidths = rows[0].map((_, i) => Math.max(...rows.map((r) => (r[i] ?? "").length)));
|
|
161
|
+
for (const row of rows) console.log(row.map((cell, i) => cell.padEnd(colWidths[i])).join(" "));
|
|
162
|
+
}
|
|
163
|
+
};
|
|
164
|
+
function colorize(text, color) {
|
|
165
|
+
return {
|
|
166
|
+
red,
|
|
167
|
+
green,
|
|
168
|
+
yellow,
|
|
169
|
+
blue,
|
|
170
|
+
cyan,
|
|
171
|
+
dim,
|
|
172
|
+
bold
|
|
173
|
+
}[color](text);
|
|
174
|
+
}
|
|
175
|
+
//#endregion
|
|
176
|
+
export { __toESM as a, __exportAll as i, log as n, __commonJSMin as r, colorize as t };
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import { n as log } from "./logger-ZqggsyGZ.mjs";
|
|
2
|
+
import { a as readJson, n as exists, o as readText } from "./fs-DbNNEyzq.mjs";
|
|
3
|
+
import { r as getBumpyDir } from "./config-CJ2orhTL.mjs";
|
|
4
|
+
import { i as writeChangeset } from "./changeset-ClCYsChu.mjs";
|
|
5
|
+
import { n as confirm } from "./prompt-BP8toAOI.mjs";
|
|
6
|
+
import { initCommand } from "./init-Blw2GfC_.mjs";
|
|
7
|
+
import { resolve } from "node:path";
|
|
8
|
+
import { readdir } from "node:fs/promises";
|
|
9
|
+
//#region src/commands/migrate.ts
|
|
10
|
+
async function migrateCommand(rootDir, opts) {
|
|
11
|
+
const changesetDir = resolve(rootDir, ".changeset");
|
|
12
|
+
if (!await exists(changesetDir)) {
|
|
13
|
+
log.error("No .changeset/ directory found. Nothing to migrate.");
|
|
14
|
+
process.exit(1);
|
|
15
|
+
}
|
|
16
|
+
const bumpyDir = getBumpyDir(rootDir);
|
|
17
|
+
if (!await exists(resolve(bumpyDir, "_config.json"))) {
|
|
18
|
+
log.step("Initializing .bumpy/ directory...");
|
|
19
|
+
await initCommand(rootDir);
|
|
20
|
+
}
|
|
21
|
+
const changesetConfigPath = resolve(changesetDir, "config.json");
|
|
22
|
+
if (await exists(changesetConfigPath)) {
|
|
23
|
+
log.step("Migrating config from .changeset/config.json...");
|
|
24
|
+
await migrateConfig(changesetConfigPath, bumpyDir);
|
|
25
|
+
}
|
|
26
|
+
const mdFiles = (await readdir(changesetDir)).filter((f) => f.endsWith(".md") && f !== "README.md");
|
|
27
|
+
if (mdFiles.length > 0) {
|
|
28
|
+
log.step(`Migrating ${mdFiles.length} pending changeset(s)...`);
|
|
29
|
+
let migrated = 0;
|
|
30
|
+
for (const file of mdFiles) {
|
|
31
|
+
const result = parseChangesetFile(await readText(resolve(changesetDir, file)));
|
|
32
|
+
if (!result) {
|
|
33
|
+
log.warn(` Skipped ${file} (could not parse)`);
|
|
34
|
+
continue;
|
|
35
|
+
}
|
|
36
|
+
const name = file.replace(/\.md$/, "");
|
|
37
|
+
if (await exists(resolve(bumpyDir, file))) {
|
|
38
|
+
log.dim(` Skipped ${file} (already exists in .bumpy/)`);
|
|
39
|
+
continue;
|
|
40
|
+
}
|
|
41
|
+
await writeChangeset(rootDir, name, result.releases, result.summary);
|
|
42
|
+
migrated++;
|
|
43
|
+
log.dim(` Migrated ${file}`);
|
|
44
|
+
}
|
|
45
|
+
log.success(`Migrated ${migrated} changeset(s)`);
|
|
46
|
+
} else log.info("No pending changesets to migrate.");
|
|
47
|
+
if (!opts.force) {
|
|
48
|
+
console.log();
|
|
49
|
+
if (await confirm("Remove .changeset/ directory?", false)) {
|
|
50
|
+
const { rm } = await import("node:fs/promises");
|
|
51
|
+
await rm(changesetDir, { recursive: true });
|
|
52
|
+
log.success("Removed .changeset/ directory");
|
|
53
|
+
} else log.dim("Keeping .changeset/ — you can remove it manually when ready.");
|
|
54
|
+
}
|
|
55
|
+
console.log();
|
|
56
|
+
log.success("Migration complete!");
|
|
57
|
+
log.dim("Review .bumpy/_config.json and adjust settings as needed.");
|
|
58
|
+
log.dim("Key differences from changesets:");
|
|
59
|
+
log.dim(" - peerDependency bumps only propagate on major (not minor)");
|
|
60
|
+
log.dim(" - Use 'patch-isolated'/'minor-isolated' to skip propagation");
|
|
61
|
+
log.dim(" - Per-package config goes in package.json[\"bumpy\"]");
|
|
62
|
+
}
|
|
63
|
+
async function migrateConfig(changesetConfigPath, bumpyDir) {
|
|
64
|
+
const csConfig = await readJson(changesetConfigPath);
|
|
65
|
+
const bumpyConfigPath = resolve(bumpyDir, "_config.json");
|
|
66
|
+
let bumpyConfig = {};
|
|
67
|
+
if (await exists(bumpyConfigPath)) bumpyConfig = await readJson(bumpyConfigPath);
|
|
68
|
+
for (const field of [
|
|
69
|
+
"baseBranch",
|
|
70
|
+
"access",
|
|
71
|
+
"commit",
|
|
72
|
+
"fixed",
|
|
73
|
+
"linked",
|
|
74
|
+
"ignore",
|
|
75
|
+
"updateInternalDependencies",
|
|
76
|
+
"privatePackages"
|
|
77
|
+
]) if (csConfig[field] !== void 0) bumpyConfig[field] = csConfig[field];
|
|
78
|
+
const { writeJson } = await import("./fs-DbNNEyzq.mjs").then((n) => n.r);
|
|
79
|
+
await writeJson(bumpyConfigPath, bumpyConfig);
|
|
80
|
+
log.dim(" Migrated config fields: " + Object.keys(bumpyConfig).filter((k) => k !== "baseBranch" || bumpyConfig[k] !== "main").join(", "));
|
|
81
|
+
}
|
|
82
|
+
/** Parse a changesets-format markdown file */
|
|
83
|
+
function parseChangesetFile(content) {
|
|
84
|
+
const match = content.match(/^---\n([\s\S]*?)\n---\n?([\s\S]*)$/);
|
|
85
|
+
if (!match) return null;
|
|
86
|
+
const frontmatter = match[1].trim();
|
|
87
|
+
const summary = match[2].trim();
|
|
88
|
+
if (!frontmatter) return null;
|
|
89
|
+
const releases = [];
|
|
90
|
+
for (const line of frontmatter.split("\n")) {
|
|
91
|
+
const trimmed = line.trim();
|
|
92
|
+
if (!trimmed) continue;
|
|
93
|
+
const lineMatch = trimmed.match(/^"?([^"]+)"?\s*:\s*(.+)$/);
|
|
94
|
+
if (!lineMatch) continue;
|
|
95
|
+
const name = lineMatch[1].trim();
|
|
96
|
+
const type = lineMatch[2].trim();
|
|
97
|
+
if (type === "none") continue;
|
|
98
|
+
if ([
|
|
99
|
+
"major",
|
|
100
|
+
"minor",
|
|
101
|
+
"patch"
|
|
102
|
+
].includes(type)) releases.push({
|
|
103
|
+
name,
|
|
104
|
+
type
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
if (releases.length === 0 && !summary) return null;
|
|
108
|
+
return {
|
|
109
|
+
releases,
|
|
110
|
+
summary
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
//#endregion
|
|
114
|
+
export { migrateCommand };
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
//#region src/utils/names.ts
|
|
2
|
+
/** Generate a random adjective-noun name for changeset files */
|
|
3
|
+
function randomName() {
|
|
4
|
+
return `${ADJECTIVES[Math.floor(Math.random() * ADJECTIVES.length)]}-${NOUNS[Math.floor(Math.random() * NOUNS.length)]}`;
|
|
5
|
+
}
|
|
6
|
+
/** Sanitize a user-provided name into a valid filename slug */
|
|
7
|
+
function slugify(name) {
|
|
8
|
+
return name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
|
|
9
|
+
}
|
|
10
|
+
const ADJECTIVES = [
|
|
11
|
+
"brave",
|
|
12
|
+
"calm",
|
|
13
|
+
"dark",
|
|
14
|
+
"eager",
|
|
15
|
+
"fair",
|
|
16
|
+
"gentle",
|
|
17
|
+
"happy",
|
|
18
|
+
"icy",
|
|
19
|
+
"jolly",
|
|
20
|
+
"keen",
|
|
21
|
+
"lively",
|
|
22
|
+
"merry",
|
|
23
|
+
"neat",
|
|
24
|
+
"odd",
|
|
25
|
+
"proud",
|
|
26
|
+
"quiet",
|
|
27
|
+
"rare",
|
|
28
|
+
"shy",
|
|
29
|
+
"tall",
|
|
30
|
+
"warm",
|
|
31
|
+
"young",
|
|
32
|
+
"bold",
|
|
33
|
+
"cool",
|
|
34
|
+
"dry",
|
|
35
|
+
"fast",
|
|
36
|
+
"glad",
|
|
37
|
+
"huge",
|
|
38
|
+
"kind",
|
|
39
|
+
"lazy",
|
|
40
|
+
"mild",
|
|
41
|
+
"new",
|
|
42
|
+
"old",
|
|
43
|
+
"pink",
|
|
44
|
+
"red",
|
|
45
|
+
"safe",
|
|
46
|
+
"thin",
|
|
47
|
+
"vast",
|
|
48
|
+
"wide",
|
|
49
|
+
"witty",
|
|
50
|
+
"zany",
|
|
51
|
+
"bright",
|
|
52
|
+
"clean",
|
|
53
|
+
"deep",
|
|
54
|
+
"fresh",
|
|
55
|
+
"grand",
|
|
56
|
+
"light",
|
|
57
|
+
"pure",
|
|
58
|
+
"rich",
|
|
59
|
+
"sharp",
|
|
60
|
+
"smooth",
|
|
61
|
+
"soft",
|
|
62
|
+
"swift",
|
|
63
|
+
"tough",
|
|
64
|
+
"wild",
|
|
65
|
+
"wise",
|
|
66
|
+
"tidy",
|
|
67
|
+
"silver",
|
|
68
|
+
"golden",
|
|
69
|
+
"copper",
|
|
70
|
+
"amber",
|
|
71
|
+
"coral",
|
|
72
|
+
"jade",
|
|
73
|
+
"violet",
|
|
74
|
+
"rusty"
|
|
75
|
+
];
|
|
76
|
+
const NOUNS = [
|
|
77
|
+
"ant",
|
|
78
|
+
"bee",
|
|
79
|
+
"cat",
|
|
80
|
+
"dog",
|
|
81
|
+
"elk",
|
|
82
|
+
"fox",
|
|
83
|
+
"gnu",
|
|
84
|
+
"hen",
|
|
85
|
+
"ibis",
|
|
86
|
+
"jay",
|
|
87
|
+
"koi",
|
|
88
|
+
"lark",
|
|
89
|
+
"moth",
|
|
90
|
+
"newt",
|
|
91
|
+
"owl",
|
|
92
|
+
"pug",
|
|
93
|
+
"quail",
|
|
94
|
+
"ram",
|
|
95
|
+
"seal",
|
|
96
|
+
"toad",
|
|
97
|
+
"urchin",
|
|
98
|
+
"vole",
|
|
99
|
+
"wasp",
|
|
100
|
+
"yak",
|
|
101
|
+
"bass",
|
|
102
|
+
"clam",
|
|
103
|
+
"dove",
|
|
104
|
+
"eel",
|
|
105
|
+
"frog",
|
|
106
|
+
"goat",
|
|
107
|
+
"hawk",
|
|
108
|
+
"igloo",
|
|
109
|
+
"jade",
|
|
110
|
+
"kite",
|
|
111
|
+
"lake",
|
|
112
|
+
"moon",
|
|
113
|
+
"nest",
|
|
114
|
+
"oak",
|
|
115
|
+
"pine",
|
|
116
|
+
"reef",
|
|
117
|
+
"star",
|
|
118
|
+
"tree",
|
|
119
|
+
"wave",
|
|
120
|
+
"fern",
|
|
121
|
+
"lily",
|
|
122
|
+
"rose",
|
|
123
|
+
"sage",
|
|
124
|
+
"vine",
|
|
125
|
+
"dawn",
|
|
126
|
+
"dusk",
|
|
127
|
+
"mist",
|
|
128
|
+
"rain",
|
|
129
|
+
"snow",
|
|
130
|
+
"wind",
|
|
131
|
+
"glow",
|
|
132
|
+
"haze",
|
|
133
|
+
"crab",
|
|
134
|
+
"deer",
|
|
135
|
+
"finch",
|
|
136
|
+
"heron",
|
|
137
|
+
"crane",
|
|
138
|
+
"robin",
|
|
139
|
+
"swift",
|
|
140
|
+
"trout"
|
|
141
|
+
];
|
|
142
|
+
//#endregion
|
|
143
|
+
export { slugify as n, randomName as t };
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import * as readline from "node:readline";
|
|
2
|
+
//#region src/utils/prompt.ts
|
|
3
|
+
function createInterface() {
|
|
4
|
+
return readline.createInterface({
|
|
5
|
+
input: process.stdin,
|
|
6
|
+
output: process.stdout
|
|
7
|
+
});
|
|
8
|
+
}
|
|
9
|
+
async function ask(question, defaultValue) {
|
|
10
|
+
const rl = createInterface();
|
|
11
|
+
const suffix = defaultValue ? ` (${defaultValue})` : "";
|
|
12
|
+
return new Promise((resolve) => {
|
|
13
|
+
rl.question(`${question}${suffix}: `, (answer) => {
|
|
14
|
+
rl.close();
|
|
15
|
+
resolve(answer.trim() || defaultValue || "");
|
|
16
|
+
});
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
async function confirm(question, defaultYes = true) {
|
|
20
|
+
const answer = await ask(`${question} [${defaultYes ? "Y/n" : "y/N"}]`);
|
|
21
|
+
if (!answer) return defaultYes;
|
|
22
|
+
return answer.toLowerCase().startsWith("y");
|
|
23
|
+
}
|
|
24
|
+
async function select(question, options) {
|
|
25
|
+
console.log(question);
|
|
26
|
+
for (let i = 0; i < options.length; i++) console.log(` ${i + 1}) ${options[i].label}`);
|
|
27
|
+
const answer = await ask("Choose");
|
|
28
|
+
const idx = parseInt(answer, 10) - 1;
|
|
29
|
+
if (idx >= 0 && idx < options.length) return options[idx].value;
|
|
30
|
+
const match = options.find((o) => o.value === answer || o.label.toLowerCase() === answer.toLowerCase());
|
|
31
|
+
if (match) return match.value;
|
|
32
|
+
return options[0].value;
|
|
33
|
+
}
|
|
34
|
+
async function multiSelect(question, options) {
|
|
35
|
+
console.log(question);
|
|
36
|
+
for (let i = 0; i < options.length; i++) {
|
|
37
|
+
const mark = options[i].checked ? "[x]" : "[ ]";
|
|
38
|
+
console.log(` ${i + 1}) ${mark} ${options[i].label}`);
|
|
39
|
+
}
|
|
40
|
+
const answer = await ask("Select (comma-separated numbers, or 'all')");
|
|
41
|
+
if (answer.toLowerCase() === "all") return options.map((o) => o.value);
|
|
42
|
+
if (!answer) return options.filter((o) => o.checked).map((o) => o.value);
|
|
43
|
+
return answer.split(",").map((s) => parseInt(s.trim(), 10) - 1).filter((i) => i >= 0 && i < options.length).map((i) => options[i].value);
|
|
44
|
+
}
|
|
45
|
+
//#endregion
|
|
46
|
+
export { select as i, confirm as n, multiSelect as r, ask as t };
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
import { n as log, t as colorize } from "./logger-ZqggsyGZ.mjs";
|
|
2
|
+
import { a as loadConfig } from "./config-CJ2orhTL.mjs";
|
|
3
|
+
import { n as discoverWorkspace, r as detectWorkspaces } from "./workspace-mVjawG8g.mjs";
|
|
4
|
+
import { t as DependencyGraph } from "./dep-graph-DiLeAhl9.mjs";
|
|
5
|
+
import { i as tryRun, n as runAsync } from "./shell-DPlltpzb.mjs";
|
|
6
|
+
import { n as hasUncommittedChanges, r as pushWithTags, t as publishPackages } from "./publish-pipeline-1M5GmbdP.mjs";
|
|
7
|
+
//#region src/core/github-release.ts
|
|
8
|
+
/** Create individual GitHub releases for each published package */
|
|
9
|
+
async function createIndividualReleases(releases, changesets, rootDir, opts = {}) {
|
|
10
|
+
if (!isGhAvailable()) {
|
|
11
|
+
log.dim(" gh CLI not found — skipping GitHub releases");
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
for (const release of releases) {
|
|
15
|
+
const tag = `${release.name}@${release.newVersion}`;
|
|
16
|
+
const body = buildReleaseBody(release, changesets);
|
|
17
|
+
const title = `${release.name} v${release.newVersion}`;
|
|
18
|
+
if (opts.dryRun) {
|
|
19
|
+
log.dim(` Would create GitHub release: ${title}`);
|
|
20
|
+
continue;
|
|
21
|
+
}
|
|
22
|
+
try {
|
|
23
|
+
await runAsync(`gh release create "${tag}" --title "${escapeShell(title)}" --notes "${escapeShell(body)}"`, { cwd: rootDir });
|
|
24
|
+
log.dim(` Created GitHub release: ${title}`);
|
|
25
|
+
} catch (err) {
|
|
26
|
+
log.warn(` Failed to create GitHub release for ${tag}: ${err instanceof Error ? err.message : err}`);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
/** Create a single aggregated GitHub release for all published packages */
|
|
31
|
+
async function createAggregateRelease(releases, changesets, rootDir, opts = {}) {
|
|
32
|
+
if (!isGhAvailable()) {
|
|
33
|
+
log.dim(" gh CLI not found — skipping GitHub release");
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
if (releases.length === 0) return;
|
|
37
|
+
const date = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
38
|
+
const title = (opts.title || "Release {{date}}").replace("{{date}}", date);
|
|
39
|
+
const tag = `release-${date}`;
|
|
40
|
+
const body = buildAggregateBody(releases, changesets);
|
|
41
|
+
if (opts.dryRun) {
|
|
42
|
+
log.dim(` Would create aggregate GitHub release: ${title}`);
|
|
43
|
+
log.dim(` Tag: ${tag}`);
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
try {
|
|
47
|
+
tryRun(`git tag "${tag}"`, { cwd: rootDir });
|
|
48
|
+
await runAsync(`gh release create "${tag}" --title "${escapeShell(title)}" --notes "${escapeShell(body)}"`, { cwd: rootDir });
|
|
49
|
+
log.success(`Created aggregate GitHub release: ${title}`);
|
|
50
|
+
} catch (err) {
|
|
51
|
+
log.warn(`Failed to create aggregate GitHub release: ${err instanceof Error ? err.message : err}`);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
function buildReleaseBody(release, changesets) {
|
|
55
|
+
const lines = [];
|
|
56
|
+
const relevant = changesets.filter((cs) => release.changesets.includes(cs.id));
|
|
57
|
+
if (relevant.length > 0) {
|
|
58
|
+
for (const cs of relevant) if (cs.summary) lines.push(`- ${cs.summary.split("\n")[0]}`);
|
|
59
|
+
}
|
|
60
|
+
if (release.isDependencyBump && relevant.length === 0) lines.push("- Updated dependencies");
|
|
61
|
+
return lines.join("\n") || "No changelog entries.";
|
|
62
|
+
}
|
|
63
|
+
function buildAggregateBody(releases, changesets) {
|
|
64
|
+
const lines = [];
|
|
65
|
+
const groups = [
|
|
66
|
+
["Major Changes", releases.filter((r) => r.type === "major")],
|
|
67
|
+
["Minor Changes", releases.filter((r) => r.type === "minor")],
|
|
68
|
+
["Patch Changes", releases.filter((r) => r.type === "patch")]
|
|
69
|
+
];
|
|
70
|
+
for (const [heading, group] of groups) {
|
|
71
|
+
if (group.length === 0) continue;
|
|
72
|
+
lines.push(`## ${heading}\n`);
|
|
73
|
+
for (const release of group) {
|
|
74
|
+
lines.push(`### ${release.name} v${release.newVersion}\n`);
|
|
75
|
+
const relevant = changesets.filter((cs) => release.changesets.includes(cs.id));
|
|
76
|
+
if (relevant.length > 0) {
|
|
77
|
+
for (const cs of relevant) if (cs.summary) lines.push(`- ${cs.summary.split("\n")[0]}`);
|
|
78
|
+
} else if (release.isDependencyBump) lines.push("- Updated dependencies");
|
|
79
|
+
else if (release.isCascadeBump) lines.push("- Version bump via cascade rule");
|
|
80
|
+
lines.push("");
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
return lines.join("\n").trim() || "No changelog entries.";
|
|
84
|
+
}
|
|
85
|
+
function isGhAvailable() {
|
|
86
|
+
return tryRun("gh --version") !== null;
|
|
87
|
+
}
|
|
88
|
+
function escapeShell(str) {
|
|
89
|
+
return str.replace(/"/g, "\\\"").replace(/\n/g, "\\n");
|
|
90
|
+
}
|
|
91
|
+
//#endregion
|
|
92
|
+
//#region src/commands/publish.ts
|
|
93
|
+
/**
|
|
94
|
+
* Publish packages that have been versioned but not yet published.
|
|
95
|
+
* Detects unpublished versions by comparing package.json versions against npm registry.
|
|
96
|
+
*/
|
|
97
|
+
async function publishCommand(rootDir, opts) {
|
|
98
|
+
const config = await loadConfig(rootDir);
|
|
99
|
+
const { packages, catalogs } = await discoverWorkspace(rootDir, config);
|
|
100
|
+
const { packageManager: detectedPm } = await detectWorkspaces(rootDir);
|
|
101
|
+
const depGraph = new DependencyGraph(packages);
|
|
102
|
+
if (!opts.dryRun && hasUncommittedChanges({ cwd: rootDir })) {
|
|
103
|
+
log.warn("You have uncommitted changes. Commit or stash them before publishing.");
|
|
104
|
+
process.exit(1);
|
|
105
|
+
}
|
|
106
|
+
let toPublish = await findUnpublishedPackages(packages, config);
|
|
107
|
+
if (opts.filter) {
|
|
108
|
+
const { matchGlob } = await import("./config-CJ2orhTL.mjs").then((n) => n.t);
|
|
109
|
+
const patterns = opts.filter.split(",").map((p) => p.trim());
|
|
110
|
+
toPublish = toPublish.filter((r) => patterns.some((p) => matchGlob(r.name, p)));
|
|
111
|
+
}
|
|
112
|
+
if (toPublish.length === 0) {
|
|
113
|
+
log.info("No unpublished packages found.");
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
const releasePlan = {
|
|
117
|
+
changesets: [],
|
|
118
|
+
releases: toPublish
|
|
119
|
+
};
|
|
120
|
+
if (opts.dryRun) log.bold("Dry run — would publish:");
|
|
121
|
+
else log.bold("Publishing:");
|
|
122
|
+
for (const r of toPublish) console.log(` ${r.name}@${colorize(r.newVersion, "cyan")}`);
|
|
123
|
+
console.log();
|
|
124
|
+
const result = await publishPackages(releasePlan, packages, depGraph, config, rootDir, {
|
|
125
|
+
dryRun: opts.dryRun,
|
|
126
|
+
tag: opts.tag
|
|
127
|
+
}, catalogs, detectedPm);
|
|
128
|
+
if (result.published.length > 0) log.success(`Published ${result.published.length} package(s)`);
|
|
129
|
+
if (result.skipped.length > 0) log.dim(`Skipped ${result.skipped.length}: ${result.skipped.map((s) => s.name).join(", ")}`);
|
|
130
|
+
if (result.failed.length > 0) {
|
|
131
|
+
log.error(`Failed ${result.failed.length}: ${result.failed.map((f) => `${f.name} (${f.error})`).join(", ")}`);
|
|
132
|
+
process.exit(1);
|
|
133
|
+
}
|
|
134
|
+
if (!opts.dryRun && !opts.noPush && result.published.length > 0) try {
|
|
135
|
+
log.step("Pushing tags...");
|
|
136
|
+
pushWithTags({ cwd: rootDir });
|
|
137
|
+
log.success("Pushed tags to remote");
|
|
138
|
+
} catch (err) {
|
|
139
|
+
log.warn(`Failed to push tags: ${err instanceof Error ? err.message : err}`);
|
|
140
|
+
}
|
|
141
|
+
if (result.published.length > 0) {
|
|
142
|
+
const publishedReleases = releasePlan.releases.filter((r) => result.published.some((p) => p.name === r.name));
|
|
143
|
+
const aggConfig = config.aggregateRelease;
|
|
144
|
+
const isAggregate = aggConfig === true || typeof aggConfig === "object" && aggConfig.enabled;
|
|
145
|
+
const aggTitle = typeof aggConfig === "object" ? aggConfig.title : void 0;
|
|
146
|
+
if (isAggregate) await createAggregateRelease(publishedReleases, releasePlan.changesets, rootDir, {
|
|
147
|
+
dryRun: opts.dryRun,
|
|
148
|
+
title: aggTitle
|
|
149
|
+
});
|
|
150
|
+
else await createIndividualReleases(publishedReleases, releasePlan.changesets, rootDir, { dryRun: opts.dryRun });
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Find packages whose current version is not yet published.
|
|
155
|
+
*
|
|
156
|
+
* Detection strategy (per package):
|
|
157
|
+
* 1. Custom `checkPublished` command → run it, compare output to current version
|
|
158
|
+
* 2. `skipNpmPublish` or custom `publishCommand` → check git tags
|
|
159
|
+
* 3. Default → check npm registry via `npm info`
|
|
160
|
+
*/
|
|
161
|
+
async function findUnpublishedPackages(packages, _config) {
|
|
162
|
+
const unpublished = [];
|
|
163
|
+
for (const [name, pkg] of packages) {
|
|
164
|
+
if (pkg.private && !pkg.bumpy?.publishCommand) continue;
|
|
165
|
+
if (pkg.version === "0.0.0") continue;
|
|
166
|
+
if (!await checkIfPublished(name, pkg.version, pkg.bumpy)) unpublished.push({
|
|
167
|
+
name,
|
|
168
|
+
type: "patch",
|
|
169
|
+
oldVersion: pkg.version,
|
|
170
|
+
newVersion: pkg.version,
|
|
171
|
+
changesets: [],
|
|
172
|
+
isDependencyBump: false,
|
|
173
|
+
isCascadeBump: false
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
return unpublished;
|
|
177
|
+
}
|
|
178
|
+
async function checkIfPublished(name, version, pkgConfig) {
|
|
179
|
+
const { runAsync } = await import("./shell-DPlltpzb.mjs").then((n) => n.r);
|
|
180
|
+
const { tryRun } = await import("./shell-DPlltpzb.mjs").then((n) => n.r);
|
|
181
|
+
if (pkgConfig?.checkPublished) try {
|
|
182
|
+
return (await runAsync(pkgConfig.checkPublished)).trim() === version;
|
|
183
|
+
} catch {
|
|
184
|
+
return false;
|
|
185
|
+
}
|
|
186
|
+
if (pkgConfig?.skipNpmPublish || pkgConfig?.publishCommand) {
|
|
187
|
+
const tag = `${name}@${version}`;
|
|
188
|
+
return tryRun(`git tag -l "${tag}"`) === tag;
|
|
189
|
+
}
|
|
190
|
+
try {
|
|
191
|
+
return await runAsync(`npm info "${name}@${version}" version ${pkgConfig?.registry ? `--registry ${pkgConfig.registry}` : ""}`.trim()) === version;
|
|
192
|
+
} catch {
|
|
193
|
+
return false;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
//#endregion
|
|
197
|
+
export { publishCommand };
|