hatchkit 0.1.43 → 0.1.47

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.
@@ -54,9 +54,35 @@ pkg.version = next;
54
54
  writeFileSync(pkgPath, `${JSON.stringify(pkg, null, 2)}\n`, "utf-8");
55
55
  console.log(` release-bump: ${current} → ${next}`);
56
56
 
57
- // Stage + commit + tag from the repo root so the path in the commit
58
- // is `cli/package.json` regardless of where the script was invoked.
59
- sh(`git add ${JSON.stringify(join("cli", "package.json"))}`, { cwd: repoRoot });
57
+ // Bump `@hatchkit/dev-*` workspace packages in lockstep with the CLI.
58
+ // The CLI's runtime references the plugin version range as
59
+ // `^${cliVersion}` (see devPluginNextVersionRange in dev-setup.ts), so
60
+ // every release must guarantee the plugin packages exist on npm at the
61
+ // same version. release-packages.mjs publishes them right after this
62
+ // script bumps + commits the lockstep set.
63
+ const stagedPaths = [join("cli", "package.json")];
64
+ const lockstepPackages = ["dev-shared", "dev-plugin-next", "dev-plugin-vite"];
65
+ for (const name of lockstepPackages) {
66
+ const subPath = join(repoRoot, "packages", name, "package.json");
67
+ let subPkg;
68
+ try {
69
+ subPkg = JSON.parse(readFileSync(subPath, "utf-8"));
70
+ } catch (err) {
71
+ console.error(` release-bump: missing packages/${name}/package.json — ${err.message}`);
72
+ process.exit(1);
73
+ }
74
+ if (subPkg.version === next) continue;
75
+ subPkg.version = next;
76
+ writeFileSync(subPath, `${JSON.stringify(subPkg, null, 2)}\n`, "utf-8");
77
+ stagedPaths.push(join("packages", name, "package.json"));
78
+ console.log(` release-bump: packages/${name} → ${next}`);
79
+ }
80
+
81
+ // Stage + commit + tag from the repo root so the paths in the commit
82
+ // are repo-relative regardless of where the script was invoked.
83
+ for (const p of stagedPaths) {
84
+ sh(`git add ${JSON.stringify(p)}`, { cwd: repoRoot });
85
+ }
60
86
  sh(`git commit -m ${JSON.stringify(`chore: release v${next}`)}`, { cwd: repoRoot });
61
87
  sh(`git tag ${JSON.stringify(`v${next}`)}`, { cwd: repoRoot });
62
88
  console.log(` release-bump: committed + tagged v${next}`);
@@ -0,0 +1,131 @@
1
+ #!/usr/bin/env node
2
+ /*
3
+ * release-packages — build + publish the `@hatchkit/dev-*` workspace
4
+ * packages alongside the CLI. Runs BEFORE the CLI itself publishes so
5
+ * that scaffolds generated by the just-published CLI find their plugin
6
+ * dep on the registry.
7
+ *
8
+ * Publish order is topological:
9
+ * 1. @hatchkit/dev-shared (no @hatchkit/* deps)
10
+ * 2. @hatchkit/dev-plugin-next (depends on dev-shared)
11
+ * 3. @hatchkit/dev-plugin-vite (depends on dev-shared)
12
+ *
13
+ * Version sync: every `@hatchkit/dev-*` package matches the CLI's
14
+ * version. release-bump.mjs handles the bump in lockstep, so by the
15
+ * time we get here the package.jsons are already aligned. This script
16
+ * verifies that invariant and refuses to publish if anything drifted
17
+ * (a manual `npm version` in one package would do it).
18
+ *
19
+ * Idempotent w.r.t. already-published versions: each `npm publish`
20
+ * that hits "you cannot publish over the previously published versions"
21
+ * is treated as success (the version already exists on npm — that's
22
+ * what we wanted). Real failures (auth, network) propagate.
23
+ *
24
+ * Skip with RELEASE_SKIP_PACKAGES=1.
25
+ */
26
+
27
+ import { execSync, spawnSync } from "node:child_process";
28
+ import { existsSync, readFileSync } from "node:fs";
29
+ import { dirname, join } from "node:path";
30
+ import { fileURLToPath } from "node:url";
31
+
32
+ if (process.env.RELEASE_SKIP_PACKAGES === "1") {
33
+ console.log(" release-packages: RELEASE_SKIP_PACKAGES=1 — skipping.");
34
+ process.exit(0);
35
+ }
36
+
37
+ const here = dirname(fileURLToPath(import.meta.url));
38
+ const cliDir = join(here, "..");
39
+ const repoRoot = sh("git rev-parse --show-toplevel");
40
+
41
+ const PACKAGES = ["dev-shared", "dev-plugin-next", "dev-plugin-vite"];
42
+
43
+ const cliVersion = readJson(join(cliDir, "package.json")).version;
44
+ if (!cliVersion) {
45
+ console.error(" release-packages: couldn't read cli/package.json version. Aborting.");
46
+ process.exit(1);
47
+ }
48
+
49
+ // Sanity check: every dev-* package must already be bumped to cliVersion.
50
+ // release-bump.mjs does this; if someone skipped it, fail loud.
51
+ for (const name of PACKAGES) {
52
+ const pkgPath = join(repoRoot, "packages", name, "package.json");
53
+ if (!existsSync(pkgPath)) {
54
+ console.error(` release-packages: missing packages/${name}/package.json — aborting.`);
55
+ process.exit(1);
56
+ }
57
+ const pkg = readJson(pkgPath);
58
+ if (pkg.version !== cliVersion) {
59
+ console.error(
60
+ ` release-packages: packages/${name}/package.json is at ${pkg.version} but CLI is at ${cliVersion}.`,
61
+ );
62
+ console.error(
63
+ " release-bump.mjs should have aligned these. Did you run a release flow out of order?",
64
+ );
65
+ process.exit(1);
66
+ }
67
+ }
68
+
69
+ console.log(` release-packages: aligning @hatchkit/dev-* packages at v${cliVersion}.`);
70
+
71
+ for (const name of PACKAGES) {
72
+ const pkgDir = join(repoRoot, "packages", name);
73
+ console.log(`\n ── packages/${name}`);
74
+
75
+ // Build the workspace package. pnpm honours each package's own build
76
+ // script (tsc → dist).
77
+ shStream("pnpm", ["run", "build"], { cwd: pkgDir });
78
+
79
+ // Publish. pnpm publish from the package dir handles workspace:*
80
+ // dep rewrites (the dev plugins both depend on @hatchkit/dev-shared
81
+ // via workspace:*; pnpm replaces with the matching real version on
82
+ // publish). `--no-git-checks` because release-prep.mjs already
83
+ // confirmed the tree is clean and the commit/tag came from
84
+ // release-bump.mjs.
85
+ const publish = spawnSync(
86
+ "pnpm",
87
+ ["publish", "--access", "public", "--no-git-checks"],
88
+ { cwd: pkgDir, stdio: ["ignore", "pipe", "pipe"], encoding: "utf-8" },
89
+ );
90
+ process.stdout.write(publish.stdout);
91
+ if (publish.status === 0) continue;
92
+
93
+ // Treat "version already published" as success — the goal is "this
94
+ // version exists on npm", and re-runs of a partially-completed
95
+ // release should be self-healing rather than re-bumping.
96
+ const stderr = publish.stderr ?? "";
97
+ if (
98
+ /You cannot publish over the previously published versions?/i.test(stderr) ||
99
+ /403 Forbidden.*cannot publish over/i.test(stderr)
100
+ ) {
101
+ console.log(` release-packages: @hatchkit/${name}@${cliVersion} already on npm — skipping.`);
102
+ continue;
103
+ }
104
+
105
+ console.error(`\n ✗ release-packages: pnpm publish failed for ${name}.\n`);
106
+ process.stderr.write(stderr);
107
+ process.exit(1);
108
+ }
109
+
110
+ console.log(`\n ✓ release-packages: all @hatchkit/dev-* packages at v${cliVersion} on npm.`);
111
+
112
+ function readJson(path) {
113
+ try {
114
+ return JSON.parse(readFileSync(path, "utf-8"));
115
+ } catch (err) {
116
+ console.error(` release-packages: couldn't read ${path} — ${err.message}`);
117
+ process.exit(1);
118
+ }
119
+ }
120
+
121
+ function sh(cmd, opts = {}) {
122
+ return execSync(cmd, { encoding: "utf-8", ...opts }).trim();
123
+ }
124
+
125
+ function shStream(bin, args, opts = {}) {
126
+ const res = spawnSync(bin, args, { stdio: "inherit", ...opts });
127
+ if (res.status !== 0) {
128
+ console.error(` release-packages: ${bin} ${args.join(" ")} failed (exit ${res.status}).`);
129
+ process.exit(res.status ?? 1);
130
+ }
131
+ }