Skip to content

Instantly share code, notes, and snippets.

@rksm
Created June 17, 2026 09:36
Show Gist options
  • Select an option

  • Save rksm/736f5af900a95d7ae076c672b97d4188 to your computer and use it in GitHub Desktop.

Select an option

Save rksm/736f5af900a95d7ae076c672b97d4188 to your computer and use it in GitHub Desktop.
postinstall.mjs Effect and simplified JS/Bash variants
import { BunRuntime, BunServices } from "@effect/platform-bun";
import { Clock, Effect, Inspectable, Path, Schema as S, Stream } from "effect";
import { ChildProcess } from "effect/unstable/process";
const STATUS_STREAM = process.stdout;
const IS_TTY = STATUS_STREAM.isTTY === true;
const GREEN = IS_TTY ? "\x1b[32m" : "";
const RED = IS_TTY ? "\x1b[31m" : "";
const DIM = IS_TTY ? "\x1b[90m" : "";
const RESET = IS_TTY ? "\x1b[0m" : "";
const SPINNER = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
class CommandError extends S.TaggedErrorClass()("CommandError", {
command: S.String,
exitCode: S.Int,
output: S.String,
}) {
get message() {
return this.output.length > 0
? `${this.command} exited with code ${this.exitCode}: ${this.output}`
: `${this.command} exited with code ${this.exitCode}`;
}
}
const formatUnknown = (value) => {
if (value instanceof Error) {
return value.message || value.name || Inspectable.toStringUnknown(value);
}
return Inspectable.toStringUnknown(value);
};
const formatTiming = (elapsedMs) => {
const seconds = elapsedMs / 1000;
const value = seconds >= 10 ? seconds.toFixed(0) : seconds.toFixed(2);
return `${DIM}[${value}s]${RESET}`;
};
const renderRow = (label, status, frame) => {
switch (status.kind) {
case "running":
return `${DIM}${SPINNER[frame % SPINNER.length]}${RESET} ${label}`;
case "ok":
return `${GREEN}✓${RESET} ${label} ${status.timing}`;
case "fail":
return `${RED}✗${RESET} ${label} failed ${status.timing}`;
}
};
const startProgress = (labels) => {
const statuses = labels.map(() => ({ kind: "running" }));
let frame = 0;
if (IS_TTY) {
for (let i = 0; i < labels.length; i++) {
STATUS_STREAM.write(`${renderRow(labels[i], statuses[i], 0)}\n`);
}
}
const repaint = () => {
if (!IS_TTY) {
return;
}
STATUS_STREAM.write(`\x1b[${labels.length}A`);
for (let i = 0; i < labels.length; i++) {
STATUS_STREAM.write(`\r\x1b[2K${renderRow(labels[i], statuses[i], frame)}\n`);
}
};
const timer = IS_TTY
? setInterval(() => {
frame++;
repaint();
}, 80)
: null;
return {
setStatus(index, status) {
statuses[index] = status;
if (IS_TTY) {
repaint();
return;
}
if (status.kind !== "running") {
STATUS_STREAM.write(`${renderRow(labels[index], status, 0)}\n`);
}
},
stop() {
if (timer) {
clearInterval(timer);
}
if (IS_TTY) {
repaint();
}
for (let i = 0; i < statuses.length; i++) {
const status = statuses[i];
if (status.kind === "fail") {
STATUS_STREAM.write(`${RED}error${RESET} (${labels[i]}): ${status.reason}\n`);
}
}
},
};
};
const resolvePostinstall = Effect.fn("resolvePostinstall")(function* () {
const path = yield* Path.Path;
const scriptPath = yield* path.fromFileUrl(new URL(import.meta.url));
const rootDir = path.resolve(path.dirname(scriptPath), "..");
const binDir = path.join(rootDir, "node_modules", ".bin");
return {
rootDir,
steps: [
...(process.env.CI === "true"
? []
: [
{
args: [path.join(rootDir, "scripts", "sync-effect-submodule.ts")],
command: process.execPath,
label: "Effect submodule",
timeout: "5 minutes",
},
]),
{
args: ["config", "--hooks-dir", ".githooks"],
command: path.join(binDir, "vp"),
label: "Vite+ config",
timeout: "60 seconds",
},
{
args: ["patch"],
command: path.join(binDir, "effect-tsgo"),
label: "Effect tsgo patch",
timeout: "60 seconds",
},
],
};
});
const runCommand = Effect.fn("runCommand")(function* (cwd, command, args) {
const formatted = [command, ...args].join(" ");
const child = yield* ChildProcess.make(command, args, { cwd, stderr: "pipe", stdout: "pipe" });
const [output, exitCode] = yield* Effect.all([
Stream.mkString(Stream.decodeText(child.all)),
child.exitCode,
]);
const trimmed = output.trim();
if (exitCode !== 0) {
return yield* new CommandError({
command: formatted,
exitCode,
output: trimmed,
});
}
});
const postinstall = Effect.gen(function* () {
const { rootDir, steps } = yield* resolvePostinstall();
yield* Effect.acquireUseRelease(
Effect.sync(() => startProgress(steps.map((step) => step.label))),
(progress) =>
Effect.gen(function* () {
const failures = [];
yield* Effect.all(
steps.map((step, index) =>
Effect.gen(function* () {
const startedAt = yield* Clock.currentTimeMillis;
const result = yield* Effect.result(
runCommand(rootDir, step.command, step.args).pipe(Effect.timeout(step.timeout)),
);
const finishedAt = yield* Clock.currentTimeMillis;
const timing = formatTiming(finishedAt - startedAt);
if (result._tag === "Failure") {
const reason = formatUnknown(result.failure);
progress.setStatus(index, { kind: "fail", reason, timing });
failures.push(result.failure);
return;
}
progress.setStatus(index, { kind: "ok", timing });
}),
),
{ concurrency: "unbounded" },
);
if (failures.length > 0) {
return yield* Effect.fail(failures[0]);
}
}),
(progress) => Effect.sync(() => progress.stop()),
);
});
const program = postinstall.pipe(Effect.scoped, Effect.provide(BunServices.layer));
BunRuntime.runMain(program, { disableErrorReporting: true });
import { spawn } from "node:child_process";
import path from "node:path";
import { fileURLToPath } from "node:url";
const isTty = process.stdout.isTTY === true;
const green = isTty ? "\x1b[32m" : "";
const red = isTty ? "\x1b[31m" : "";
const dim = isTty ? "\x1b[90m" : "";
const reset = isTty ? "\x1b[0m" : "";
const scriptPath = fileURLToPath(import.meta.url);
const rootDir = path.resolve(path.dirname(scriptPath), "..");
const binDir = path.join(rootDir, "node_modules", ".bin");
const steps = [
...(process.env.CI === "true"
? []
: [
{
label: "Effect submodule",
command: process.execPath,
args: [path.join(rootDir, "scripts", "sync-effect-submodule.ts")],
timeoutMs: 5 * 60 * 1000,
},
]),
{
label: "Vite+ config",
command: path.join(binDir, "vp"),
args: ["config", "--hooks-dir", ".githooks"],
timeoutMs: 60 * 1000,
},
{
label: "Effect tsgo patch",
command: path.join(binDir, "effect-tsgo"),
args: ["patch"],
timeoutMs: 60 * 1000,
},
];
function formatTiming(startedAt) {
const seconds = (Date.now() - startedAt) / 1000;
const value = seconds >= 10 ? seconds.toFixed(0) : seconds.toFixed(2);
return `${dim}[${value}s]${reset}`;
}
function runCommand({ command, args, timeoutMs }) {
return new Promise((resolve, reject) => {
const child = spawn(command, args, {
cwd: rootDir,
stdio: ["ignore", "pipe", "pipe"],
});
let output = "";
child.stdout.on("data", (chunk) => {
output += chunk;
});
child.stderr.on("data", (chunk) => {
output += chunk;
});
const timer = setTimeout(() => {
child.kill("SIGTERM");
reject(new Error(`${command} ${args.join(" ")} timed out`));
}, timeoutMs);
child.on("error", (error) => {
clearTimeout(timer);
reject(error);
});
child.on("close", (exitCode) => {
clearTimeout(timer);
if (exitCode === 0) {
resolve();
return;
}
const trimmed = output.trim();
reject(
new Error(
trimmed.length > 0
? `${command} ${args.join(" ")} exited with code ${exitCode}: ${trimmed}`
: `${command} ${args.join(" ")} exited with code ${exitCode}`,
),
);
});
});
}
async function runStep(step) {
const startedAt = Date.now();
try {
await runCommand(step);
console.log(`${green}✓${reset} ${step.label} ${formatTiming(startedAt)}`);
return null;
} catch (error) {
console.error(`${red}✗${reset} ${step.label} failed ${formatTiming(startedAt)}`);
console.error(`${red}error${reset} (${step.label}): ${error.message}`);
return error;
}
}
const failures = (await Promise.all(steps.map(runStep))).filter(Boolean);
if (failures.length > 0) {
process.exitCode = 1;
}
#!/usr/bin/env bash
set -euo pipefail
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
BIN_DIR="$ROOT_DIR/node_modules/.bin"
cd "$ROOT_DIR"
if [ "${CI:-}" != "true" ]; then
bun "$ROOT_DIR/scripts/sync-effect-submodule.ts"
fi
"$BIN_DIR/vp" config --hooks-dir .githooks
"$BIN_DIR/effect-tsgo" patch
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment