@trolleroof/tui 0.2.3
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/README.md +349 -0
- package/dist/index.js +8404 -0
- package/overlay-release.json +4 -0
- package/package.json +48 -0
- package/scripts/build-overlay-web.ts +34 -0
- package/scripts/dev-harness.sh +81 -0
- package/scripts/dev-harness.test.sh +33 -0
- package/scripts/export-bc.ts +124 -0
- package/scripts/install-adapters.sh +192 -0
- package/scripts/install-adapters.test.sh +69 -0
- package/scripts/manage-hermes-hooks.py +39 -0
- package/scripts/materialize-agents-plugin.sh +85 -0
- package/scripts/overlay.test.ts +106 -0
- package/scripts/overlay.ts +385 -0
- package/scripts/plugin-update.test.ts +318 -0
- package/scripts/plugin-update.ts +378 -0
- package/scripts/preview-overlay.ts +153 -0
- package/scripts/run-plugin-update.test.ts +31 -0
- package/scripts/run-plugin-update.ts +65 -0
- package/scripts/version-bump.test.ts +76 -0
- package/scripts/version-bump.ts +89 -0
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
/**
|
|
3
|
+
* Serve a browser preview of the Arcade overlay at production frame sizes.
|
|
4
|
+
* Rebuilds the web bundle, then hosts overlay/dist + overlay/preview.html.
|
|
5
|
+
*
|
|
6
|
+
* bun run preview:overlay
|
|
7
|
+
* bun run preview:overlay -- --game=connect4
|
|
8
|
+
* → http://127.0.0.1:4173/?game=connect4
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { spawn } from "node:child_process";
|
|
12
|
+
import { existsSync } from "node:fs";
|
|
13
|
+
import { join, normalize, relative, resolve } from "node:path";
|
|
14
|
+
|
|
15
|
+
const ROOT = join(import.meta.dir, "..");
|
|
16
|
+
const DIST = join(ROOT, "overlay", "dist");
|
|
17
|
+
const PREVIEW_HTML = join(ROOT, "overlay", "preview.html");
|
|
18
|
+
const HOST = process.env.GAMEPIGEON_PREVIEW_HOST ?? "127.0.0.1";
|
|
19
|
+
const DEFAULT_PORT = Number(process.env.GAMEPIGEON_PREVIEW_PORT ?? 4173);
|
|
20
|
+
|
|
21
|
+
function parseArgs(argv: string[]): { game?: string; variation?: string; scores?: string; open: boolean; help: boolean } {
|
|
22
|
+
let game: string | undefined;
|
|
23
|
+
let variation: string | undefined;
|
|
24
|
+
let scores: string | undefined;
|
|
25
|
+
let open = true;
|
|
26
|
+
let help = false;
|
|
27
|
+
for (const arg of argv) {
|
|
28
|
+
if (arg === "--help" || arg === "-h") help = true;
|
|
29
|
+
else if (arg === "--no-open") open = false;
|
|
30
|
+
else if (arg === "--open") open = true;
|
|
31
|
+
else if (arg.startsWith("--game=")) game = arg.slice("--game=".length) || undefined;
|
|
32
|
+
else if (arg.startsWith("--variation=")) variation = arg.slice("--variation=".length) || undefined;
|
|
33
|
+
else if (arg.startsWith("--scores=")) scores = arg.slice("--scores=".length) || undefined;
|
|
34
|
+
}
|
|
35
|
+
return { game, variation, scores, open, help };
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function printHelp(): void {
|
|
39
|
+
console.log(`Usage: bun run preview:overlay [-- --game=<id>] [-- --variation=<id>] [-- --scores=demo] [-- --no-open]
|
|
40
|
+
|
|
41
|
+
Rebuilds the overlay web bundle and serves a browser preview at the real
|
|
42
|
+
Tauri frame sizes (520×740 compact / 720×780 expanded).
|
|
43
|
+
|
|
44
|
+
Options (after --):
|
|
45
|
+
--game=<id> Deep-link into a game (e.g. connect4)
|
|
46
|
+
--variation=<id> Optional variation id (default: classic)
|
|
47
|
+
--scores=demo Populate preview-only sample leaderboard runs
|
|
48
|
+
--open / --no-open Open the default browser (default: open)
|
|
49
|
+
-h, --help Show this help
|
|
50
|
+
|
|
51
|
+
Env:
|
|
52
|
+
GAMEPIGEON_PREVIEW_HOST bind host (default 127.0.0.1)
|
|
53
|
+
GAMEPIGEON_PREVIEW_PORT preferred port (default 4173; falls back if busy)
|
|
54
|
+
`);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function run(command: string, args: string[]): Promise<number> {
|
|
58
|
+
return new Promise((resolveExit, reject) => {
|
|
59
|
+
const child = spawn(command, args, { cwd: ROOT, stdio: "inherit" });
|
|
60
|
+
child.on("error", reject);
|
|
61
|
+
child.on("exit", (code) => resolveExit(code ?? 1));
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function openBrowser(url: string): void {
|
|
66
|
+
const opener = process.platform === "darwin" ? "open" : process.platform === "win32" ? "cmd" : "xdg-open";
|
|
67
|
+
const args = process.platform === "win32" ? ["/c", "start", "", url] : [url];
|
|
68
|
+
spawn(opener, args, { stdio: "ignore", detached: true }).unref();
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const args = parseArgs(process.argv.slice(2));
|
|
72
|
+
if (args.help) {
|
|
73
|
+
printHelp();
|
|
74
|
+
process.exit(0);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const buildCode = await run("bun", ["run", "build:overlay:web"]);
|
|
78
|
+
if (buildCode !== 0) process.exit(buildCode);
|
|
79
|
+
|
|
80
|
+
if (!existsSync(join(DIST, "index.html"))) {
|
|
81
|
+
console.error(`Missing ${join(DIST, "index.html")} — expected overlay web assets.`);
|
|
82
|
+
process.exit(1);
|
|
83
|
+
}
|
|
84
|
+
if (!existsSync(PREVIEW_HTML)) {
|
|
85
|
+
console.error(`Missing ${PREVIEW_HTML}`);
|
|
86
|
+
process.exit(1);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const previewBytes = await Bun.file(PREVIEW_HTML).bytes();
|
|
90
|
+
|
|
91
|
+
function distFile(pathname: string): string | null {
|
|
92
|
+
const cleaned = normalize(pathname).replace(/^(\.\.[/\\])+/, "");
|
|
93
|
+
const filePath = resolve(DIST, cleaned.replace(/^[/\\]+/, ""));
|
|
94
|
+
const rel = relative(DIST, filePath);
|
|
95
|
+
if (!rel || rel.startsWith("..") || rel.includes("..")) return null;
|
|
96
|
+
return filePath;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const fetchHandler = {
|
|
100
|
+
async fetch(request: Request): Promise<Response> {
|
|
101
|
+
const url = new URL(request.url);
|
|
102
|
+
if (url.pathname === "/" || url.pathname === "/preview.html") {
|
|
103
|
+
return new Response(previewBytes, {
|
|
104
|
+
headers: {
|
|
105
|
+
"Content-Type": "text/html; charset=utf-8",
|
|
106
|
+
"Cache-Control": "no-store",
|
|
107
|
+
},
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
const filePath = distFile(url.pathname);
|
|
112
|
+
if (!filePath) return new Response("Forbidden", { status: 403 });
|
|
113
|
+
const file = Bun.file(filePath);
|
|
114
|
+
if (!(await file.exists())) {
|
|
115
|
+
return new Response("Not found", { status: 404 });
|
|
116
|
+
}
|
|
117
|
+
return new Response(file, {
|
|
118
|
+
headers: { "Cache-Control": "no-store" },
|
|
119
|
+
});
|
|
120
|
+
},
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
function startServer(port: number) {
|
|
124
|
+
return Bun.serve({
|
|
125
|
+
hostname: HOST,
|
|
126
|
+
port,
|
|
127
|
+
...fetchHandler,
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
let server: ReturnType<typeof Bun.serve>;
|
|
132
|
+
try {
|
|
133
|
+
server = startServer(DEFAULT_PORT);
|
|
134
|
+
} catch (error) {
|
|
135
|
+
const code = (error as { code?: string }).code;
|
|
136
|
+
if (code !== "EADDRINUSE") throw error;
|
|
137
|
+
console.warn(`Port ${DEFAULT_PORT} is busy — trying the next free port…`);
|
|
138
|
+
server = startServer(0);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
const query = new URLSearchParams();
|
|
142
|
+
if (args.game) query.set("game", args.game);
|
|
143
|
+
if (args.variation) query.set("variation", args.variation);
|
|
144
|
+
if (args.scores) query.set("scores", args.scores);
|
|
145
|
+
const suffix = query.toString() ? `/?${query}` : "/";
|
|
146
|
+
const base = `http://${server.hostname}:${server.port}`;
|
|
147
|
+
const url = `${base}${suffix}`;
|
|
148
|
+
|
|
149
|
+
console.log(`Arcade browser preview → ${url}`);
|
|
150
|
+
if (!args.game) console.log(`Deep-link example → ${base}/?game=connect4`);
|
|
151
|
+
console.log("Ctrl+C to stop.");
|
|
152
|
+
|
|
153
|
+
if (args.open) openBrowser(url);
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { describe, expect, test } from "bun:test";
|
|
2
|
+
import { runPluginUpgrade } from "./run-plugin-update.js";
|
|
3
|
+
|
|
4
|
+
describe("runPluginUpgrade", () => {
|
|
5
|
+
test("reports marketplace failures without throwing", async () => {
|
|
6
|
+
const originalSpawn = Bun.spawn;
|
|
7
|
+
Bun.spawn = ((command: string[]) => ({
|
|
8
|
+
stdout: new ReadableStream({
|
|
9
|
+
start(controller) {
|
|
10
|
+
controller.enqueue(new TextEncoder().encode(""));
|
|
11
|
+
controller.close();
|
|
12
|
+
},
|
|
13
|
+
}),
|
|
14
|
+
stderr: new ReadableStream({
|
|
15
|
+
start(controller) {
|
|
16
|
+
controller.enqueue(new TextEncoder().encode("network error"));
|
|
17
|
+
controller.close();
|
|
18
|
+
},
|
|
19
|
+
}),
|
|
20
|
+
exited: Promise.resolve(1),
|
|
21
|
+
})) as typeof Bun.spawn;
|
|
22
|
+
|
|
23
|
+
try {
|
|
24
|
+
const result = await runPluginUpgrade();
|
|
25
|
+
expect(result.ok).toBe(false);
|
|
26
|
+
expect(result.message.length).toBeGreaterThan(0);
|
|
27
|
+
} finally {
|
|
28
|
+
Bun.spawn = originalSpawn;
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
});
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { resolvePluginUpdatePaths, runPluginUpdateClear } from "./plugin-update.js";
|
|
2
|
+
|
|
3
|
+
const MARKETPLACE = "tui-gamepigeon";
|
|
4
|
+
const PLUGIN = "tui-gamepigeon@tui-gamepigeon";
|
|
5
|
+
const REPO_URL = "https://github.com/Trolleroof/tui-gamepigeon.git";
|
|
6
|
+
|
|
7
|
+
export interface PluginUpgradeResult {
|
|
8
|
+
ok: boolean;
|
|
9
|
+
message: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
async function runStep(command: string[], cwd?: string): Promise<{ ok: boolean; output: string }> {
|
|
13
|
+
const proc = Bun.spawn(command, {
|
|
14
|
+
cwd,
|
|
15
|
+
stdout: "pipe",
|
|
16
|
+
stderr: "pipe",
|
|
17
|
+
});
|
|
18
|
+
const stdout = await new Response(proc.stdout).text();
|
|
19
|
+
const stderr = await new Response(proc.stderr).text();
|
|
20
|
+
const code = await proc.exited;
|
|
21
|
+
const output = `${stdout}${stderr}`.trim();
|
|
22
|
+
return { ok: code === 0, output };
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export async function runPluginUpgrade(): Promise<PluginUpgradeResult> {
|
|
26
|
+
let marketplace = await runStep(["claude", "plugin", "marketplace", "update", MARKETPLACE]);
|
|
27
|
+
if (!marketplace.ok) {
|
|
28
|
+
marketplace = await runStep(["claude", "plugin", "marketplace", "add", REPO_URL]);
|
|
29
|
+
if (marketplace.ok) {
|
|
30
|
+
await runStep(["claude", "plugin", "marketplace", "remove", MARKETPLACE]);
|
|
31
|
+
} else {
|
|
32
|
+
return {
|
|
33
|
+
ok: false,
|
|
34
|
+
message: marketplace.output || "Could not refresh the Arcade marketplace. Check your network and try again.",
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
let plugin = await runStep(["claude", "plugin", "update", PLUGIN]);
|
|
40
|
+
if (!plugin.ok) {
|
|
41
|
+
plugin = await runStep(["claude", "plugin", "install", PLUGIN, "--scope", "user"]);
|
|
42
|
+
}
|
|
43
|
+
if (!plugin.ok) {
|
|
44
|
+
return {
|
|
45
|
+
ok: false,
|
|
46
|
+
message: plugin.output || "Plugin update failed. Please try again or report an issue on GitHub.",
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
runPluginUpdateClear(resolvePluginUpdatePaths());
|
|
51
|
+
return {
|
|
52
|
+
ok: true,
|
|
53
|
+
message: "Arcade updated. Run /reload-plugins or restart Claude Code to apply the new plugin.",
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
if (import.meta.main) {
|
|
58
|
+
const result = await runPluginUpgrade();
|
|
59
|
+
if (result.ok) {
|
|
60
|
+
console.log(result.message);
|
|
61
|
+
} else {
|
|
62
|
+
console.error(result.message);
|
|
63
|
+
process.exitCode = 1;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { describe, expect, test } from "bun:test";
|
|
2
|
+
import { readFileSync } from "node:fs";
|
|
3
|
+
import { dirname, join } from "node:path";
|
|
4
|
+
import { fileURLToPath } from "node:url";
|
|
5
|
+
import { VERSION_FILES, applyVersion, nextVersion } from "./version-bump.ts";
|
|
6
|
+
|
|
7
|
+
const ROOT_DIR = join(dirname(fileURLToPath(import.meta.url)), "..");
|
|
8
|
+
|
|
9
|
+
describe("nextVersion", () => {
|
|
10
|
+
test("bumps each component", () => {
|
|
11
|
+
expect(nextVersion("0.2.1", "patch")).toBe("0.2.2");
|
|
12
|
+
expect(nextVersion("0.2.1", "minor")).toBe("0.3.0");
|
|
13
|
+
expect(nextVersion("0.2.1", "major")).toBe("1.0.0");
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
test("resets lower components", () => {
|
|
17
|
+
expect(nextVersion("1.9.9", "major")).toBe("2.0.0");
|
|
18
|
+
expect(nextVersion("1.9.9", "minor")).toBe("1.10.0");
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
test("accepts an explicit version", () => {
|
|
22
|
+
expect(nextVersion("0.2.1", "1.4.0")).toBe("1.4.0");
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
test("rejects garbage rather than silently patching", () => {
|
|
26
|
+
expect(() => nextVersion("0.2.1", "latest")).toThrow();
|
|
27
|
+
});
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
describe("applyVersion", () => {
|
|
31
|
+
test("sets the top-level version", () => {
|
|
32
|
+
const out = applyVersion("package.json", '{"name":"x","version":"0.1.0"}', "0.2.0");
|
|
33
|
+
expect(JSON.parse(out).version).toBe("0.2.0");
|
|
34
|
+
expect(JSON.parse(out).name).toBe("x");
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
test("reaches into marketplace plugin entries", () => {
|
|
38
|
+
const out = applyVersion(
|
|
39
|
+
".claude-plugin/marketplace.json",
|
|
40
|
+
'{"plugins":[{"name":"x","version":"0.1.0"}]}',
|
|
41
|
+
"0.2.0",
|
|
42
|
+
);
|
|
43
|
+
expect(JSON.parse(out).plugins[0].version).toBe("0.2.0");
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
test("preserves surrounding formatting", () => {
|
|
47
|
+
const source = '{\n "keywords": ["a", "b"],\n "version": "0.1.0"\n}\n';
|
|
48
|
+
expect(applyVersion("package.json", source, "0.2.0")).toBe(
|
|
49
|
+
'{\n "keywords": ["a", "b"],\n "version": "0.2.0"\n}\n',
|
|
50
|
+
);
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
test("throws when there is no version to bump", () => {
|
|
54
|
+
expect(() => applyVersion("package.json", '{"name":"x"}', "0.2.0")).toThrow();
|
|
55
|
+
});
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
describe("VERSION_FILES", () => {
|
|
59
|
+
// A version file that drifts out of this list stops being bumped, which is how
|
|
60
|
+
// .codex-plugin/plugin.json fell a release behind.
|
|
61
|
+
test("every listed file exists and carries a version", () => {
|
|
62
|
+
for (const file of VERSION_FILES) {
|
|
63
|
+
const json = JSON.parse(readFileSync(join(ROOT_DIR, file), "utf8"));
|
|
64
|
+
const version = file.endsWith("marketplace.json") ? json.plugins?.[0]?.version : json.version;
|
|
65
|
+
expect(version, `${file} has no version`).toMatch(/^\d+\.\d+\.\d+$/);
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
test("all version files agree", () => {
|
|
70
|
+
const versions = VERSION_FILES.map((file) => {
|
|
71
|
+
const json = JSON.parse(readFileSync(join(ROOT_DIR, file), "utf8"));
|
|
72
|
+
return file.endsWith("marketplace.json") ? json.plugins[0].version : json.version;
|
|
73
|
+
});
|
|
74
|
+
expect(new Set(versions).size, `versions drifted: ${versions.join(", ")}`).toBe(1);
|
|
75
|
+
});
|
|
76
|
+
});
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bumps the project version everywhere it is declared, so cutting a release is
|
|
3
|
+
* one command. This only updates the version and commits it — CI does nothing
|
|
4
|
+
* until you explicitly push a matching `overlay-v<version>` tag, which is
|
|
5
|
+
* what actually publishes the release and repoints the update manifest:
|
|
6
|
+
*
|
|
7
|
+
* bun run version:bump # 0.2.1 -> 0.2.2
|
|
8
|
+
* bun run version:bump minor # 0.2.1 -> 0.3.0
|
|
9
|
+
* bun run version:bump 1.0.0 # explicit
|
|
10
|
+
* bun run version:bump --no-commit
|
|
11
|
+
* git push origin main
|
|
12
|
+
* git tag overlay-v<version> && git push origin overlay-v<version>
|
|
13
|
+
*/
|
|
14
|
+
import { readFileSync, writeFileSync } from "node:fs";
|
|
15
|
+
import { dirname, join } from "node:path";
|
|
16
|
+
import { fileURLToPath } from "node:url";
|
|
17
|
+
|
|
18
|
+
const ROOT_DIR = join(dirname(fileURLToPath(import.meta.url)), "..");
|
|
19
|
+
|
|
20
|
+
export type Release = "patch" | "minor" | "major";
|
|
21
|
+
|
|
22
|
+
const SEMVER = /^(\d+)\.(\d+)\.(\d+)$/;
|
|
23
|
+
|
|
24
|
+
export function nextVersion(current: string, bump: Release | string): string {
|
|
25
|
+
if (SEMVER.test(bump)) return bump;
|
|
26
|
+
const match = SEMVER.exec(current);
|
|
27
|
+
if (!match) throw new Error(`Current version is not semver: ${current}`);
|
|
28
|
+
const [major, minor, patch] = match.slice(1, 4).map(Number);
|
|
29
|
+
if (bump === "major") return `${major + 1}.0.0`;
|
|
30
|
+
if (bump === "minor") return `${major}.${minor + 1}.0`;
|
|
31
|
+
if (bump === "patch") return `${major}.${minor}.${patch + 1}`;
|
|
32
|
+
throw new Error(`Expected patch|minor|major or an explicit x.y.z version, got: ${bump}`);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/** Every file carrying the version. */
|
|
36
|
+
export const VERSION_FILES = [
|
|
37
|
+
"package.json",
|
|
38
|
+
".claude-plugin/plugin.json",
|
|
39
|
+
".codex-plugin/plugin.json",
|
|
40
|
+
".claude-plugin/marketplace.json",
|
|
41
|
+
] as const;
|
|
42
|
+
|
|
43
|
+
const VERSION_FIELD = /("version"\s*:\s*")\d+\.\d+\.\d+(")/g;
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Rewrites the version in place rather than round-tripping through JSON.parse,
|
|
47
|
+
* which would reflow every hand-formatted array in these files and bury the one
|
|
48
|
+
* line that actually changed. `marketplace.json` nests its version inside a
|
|
49
|
+
* plugin entry, so this replaces every occurrence — none of these files carry a
|
|
50
|
+
* `version` field that should stay put.
|
|
51
|
+
*/
|
|
52
|
+
export function applyVersion(file: string, source: string, version: string): string {
|
|
53
|
+
const updated = source.replace(VERSION_FIELD, `$1${version}$2`);
|
|
54
|
+
if (updated === source && !source.includes(`"${version}"`)) {
|
|
55
|
+
throw new Error(`No version field found in ${file}`);
|
|
56
|
+
}
|
|
57
|
+
return updated;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
if (import.meta.main) {
|
|
61
|
+
const args = process.argv.slice(2);
|
|
62
|
+
const commit = !args.includes("--no-commit");
|
|
63
|
+
const bump = args.find((arg) => !arg.startsWith("--")) ?? "patch";
|
|
64
|
+
|
|
65
|
+
const pkgPath = join(ROOT_DIR, "package.json");
|
|
66
|
+
const current = JSON.parse(readFileSync(pkgPath, "utf8")).version as string;
|
|
67
|
+
const version = nextVersion(current, bump);
|
|
68
|
+
|
|
69
|
+
for (const file of VERSION_FILES) {
|
|
70
|
+
const path = join(ROOT_DIR, file);
|
|
71
|
+
writeFileSync(path, applyVersion(file, readFileSync(path, "utf8"), version));
|
|
72
|
+
}
|
|
73
|
+
console.log(`${current} -> ${version}`);
|
|
74
|
+
|
|
75
|
+
if (commit) {
|
|
76
|
+
const git = Bun.spawnSync(
|
|
77
|
+
["git", "commit", "-m", `Bump version to ${version}`, "--", ...VERSION_FILES],
|
|
78
|
+
{ cwd: ROOT_DIR, stdout: "inherit", stderr: "inherit" },
|
|
79
|
+
);
|
|
80
|
+
if (git.exitCode !== 0) process.exitCode = 1;
|
|
81
|
+
else {
|
|
82
|
+
console.log(
|
|
83
|
+
`Committed. Push to main, then run:\n` +
|
|
84
|
+
` git tag overlay-v${version} && git push origin overlay-v${version}\n` +
|
|
85
|
+
`to publish the release.`,
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|