Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
4cc1676
emulator pull progress
BilalG1 Apr 15, 2026
a65022b
emulator fast-start via VM snapshot + live secret rotation
BilalG1 Apr 15, 2026
30dbdff
faster snapshot resume via mapped-ram + rotation opt-out
BilalG1 Apr 15, 2026
6021a04
build QEMU 10.2.2 from source in CI for mapped-ram support
BilalG1 Apr 15, 2026
0c0d726
build stack-cli's workspace deps in emulator CI
BilalG1 Apr 15, 2026
b03486e
fix emulator pull --pr/--run snapshot detection
BilalG1 Apr 15, 2026
0b3a9cf
fix sentinel marker path in docker/server entrypoint
BilalG1 Apr 15, 2026
cfdc882
Merge remote-tracking branch 'origin/dev' into local-emulator-qol-fixes
BilalG1 Apr 15, 2026
2c8ad4c
address unresolved PR review comments on snapshot resume path
BilalG1 Apr 15, 2026
76f9543
simplify emulator fast-start: tighter polls, drop dead wrappers
BilalG1 Apr 15, 2026
3586115
fix snapshot resume host fs + restore standalone run-emulator.sh path
BilalG1 Apr 15, 2026
037755b
retry tsdown migration build to survive qemu-user futex hangs
BilalG1 Apr 15, 2026
894c1ce
fix CLI artifact download + build arm64 emulator on macOS runner
BilalG1 Apr 16, 2026
54ecda8
fix colima on GHA macOS: use QEMU backend instead of VZ driver
BilalG1 Apr 16, 2026
49a20ed
split arm64 build: Docker on Linux, QEMU snapshot on macOS
BilalG1 Apr 16, 2026
11531eb
fix check_deps: skip docker requirement when SKIP_DOCKER_BUILD=1
BilalG1 Apr 16, 2026
7534637
fix lint warning + remove invalid `local` in top-level loop
BilalG1 Apr 16, 2026
288b80e
fix empty array expansion under bash 3.2 (macOS)
BilalG1 Apr 16, 2026
d94aa66
capture emulator snapshot locally during pull instead of shipping fro…
BilalG1 Apr 16, 2026
7db9fe4
fix CI verify step: use freshly-built qcow2 via STACK_EMULATOR_HOME
BilalG1 Apr 16, 2026
510ef38
fix PCI slot mismatch in snapshot capture + stale runtime ISO on dire…
BilalG1 Apr 16, 2026
39b5c08
fix smoke test: skip shell ISO regen when CLI already wrote it
BilalG1 Apr 16, 2026
7acb3ed
fix capture path: guard against set -u + preserve cmd_capture's empty…
BilalG1 Apr 16, 2026
38974ca
Merge branch 'dev' into local-emulator-qol-fixes
BilalG1 Apr 20, 2026
8f9b9c1
emulator build: split snapshot-bake from savevm capture
BilalG1 Apr 20, 2026
fbd3207
seed: bump session activity events tx timeout to 30s
BilalG1 Apr 20, 2026
c8630c6
emulator: bump Postgres statement_timeout 30s → 120s
BilalG1 Apr 20, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
simplify emulator fast-start: tighter polls, drop dead wrappers
- run-emulator.sh: drop wait_for_condition poll interval from 1s to 0.2s
- emulator.ts: replace existsSync+readFileSync TOCTOU in readInternalPck
  with try/ENOENT; tighten initial backoff to 50ms; drop redundant
  mkdirSync in startEmulator; surface stop-failure on stderr instead of
  swallowing silently
- iso.ts: inline trivial buildRootDirRecordInVD wrapper
  • Loading branch information
BilalG1 committed Apr 15, 2026
commit 76f954353673e7e1e46bd73087039dba124027e8
2 changes: 1 addition & 1 deletion docker/local-emulator/qemu/run-emulator.sh
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,7 @@ wait_for_condition() {
log "${label} ready in ${elapsed}s"
return 0
fi
sleep 1
sleep 0.2
elapsed=$((SECONDS - started))
printf "\r [%3ds] %s..." "$elapsed" "$label"
done
Expand Down
16 changes: 9 additions & 7 deletions packages/stack-cli/src/commands/emulator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,11 +57,13 @@ function internalPckPath(): string {
async function readInternalPck(timeoutMs = 60_000): Promise<string> {
const path = internalPckPath();
const deadline = Date.now() + timeoutMs;
let delay = 250;
let delay = 50;
while (Date.now() < deadline) {
if (existsSync(path)) {
try {
const contents = readFileSync(path, "utf-8").trim();
if (contents) return contents;
} catch (e) {
if ((e as NodeJS.ErrnoException).code !== "ENOENT") throw e;
}
await new Promise((r) => setTimeout(r, delay));
delay = Math.min(delay * 2, 2000);
Expand Down Expand Up @@ -223,7 +225,6 @@ function isEmulatorRunning(): boolean {
}

async function startEmulator(arch: "arm64" | "amd64"): Promise<void> {
mkdirSync(emulatorImageDir(), { recursive: true });
const img = join(emulatorImageDir(), `stack-emulator-${arch}.qcow2`);
if (!existsSync(img)) {
console.log("No emulator image found. Pulling latest...");
Expand Down Expand Up @@ -518,9 +519,6 @@ export function registerEmulatorCommand(program: Command) {
}
if (!existsSync(dest)) throw new CliError(`Expected image not found at ${dest} after download.`);
console.log(`Downloaded: ${dest}`);
// CI publishes both files inside the single qemu-emulator-${arch}
// artifact, so the first download already extracts the snapshot when
// present. Older builds may not include it.
if (existsSync(snapshotDest)) {
console.log(`Downloaded: ${snapshotDest}`);
} else {
Expand Down Expand Up @@ -617,8 +615,12 @@ export function registerEmulatorCommand(program: Command) {
process.exit(exitCode);
} else {
console.log("\nStopping emulator...");
const warnStopFailed = (e: unknown) => {
const msg = e instanceof Error ? e.message : String(e);
process.stderr.write(`Failed to stop emulator cleanly: ${msg}\n`);
};
runEmulator("stop")
.catch(() => { /* best-effort stop */ })
.catch(warnStopFailed)
.finally(() => process.exit(exitCode));
}
});
Expand Down
14 changes: 5 additions & 9 deletions packages/stack-cli/src/lib/iso.ts
Original file line number Diff line number Diff line change
Expand Up @@ -259,13 +259,6 @@ function buildVolumeDescriptorTerminator(): Buffer {
return buf;
}

// Builds the 34-byte root directory record that lives inside the volume
// descriptor (BP 157-190 of PVD/SVD). Identical layout to a regular directory
// record but identifier is the single byte 0x00.
function buildRootDirRecordInVD(rootSector: number, rootSize: number, recDate: Buffer): Buffer {
return buildDirRecord(rootSector, rootSize, true, recDate, Buffer.from([0x00]));
}

export type IsoFile = { name: string, data: Buffer };

export function buildIso(volumeId: string, files: IsoFile[]): Buffer {
Expand Down Expand Up @@ -317,8 +310,11 @@ export function buildIso(volumeId: string, files: IsoFile[]): Buffer {
const totalSectors = nextSector;
const pathTableSize = 10;

const isoRootDirRecordVD = buildRootDirRecordInVD(isoRootSector, SECTOR, recDate);
const jolietRootDirRecordVD = buildRootDirRecordInVD(jolietRootSector, SECTOR, recDate);
// Root directory record inside the volume descriptor (BP 157-190 of PVD/SVD):
// same layout as a regular dir record but the identifier is the single byte 0x00.
const rootIdent = Buffer.from([0x00]);
const isoRootDirRecordVD = buildDirRecord(isoRootSector, SECTOR, true, recDate, rootIdent);
const jolietRootDirRecordVD = buildDirRecord(jolietRootSector, SECTOR, true, recDate, rootIdent);

const pvd = buildVolumeDescriptor({
joliet: false,
Expand Down
Loading