From b8080182d7d994e5895fd7d1ada96712ead4970f Mon Sep 17 00:00:00 2001 From: fcfsprojects Date: Fri, 19 Jun 2026 11:25:34 +0000 Subject: [PATCH] fix: atomic config write and handle missing v2 job budget in non-TTY output Fix #40: saveConfig now writes to a temp file and atomically renames to the final path, preventing truncated/partial JSON if the process is interrupted mid-write. Fix #39: non-TTY job list output no longer crashes on BigInt(null) when a v2 job has no budget set. Mirrors the TTY path which already prints 'N/A' for missing budgets. --- src/commands/job.ts | 4 +++- src/lib/config.ts | 9 +++++++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/commands/job.ts b/src/commands/job.ts index c5ff121..45b2de0 100644 --- a/src/commands/job.ts +++ b/src/commands/job.ts @@ -109,7 +109,9 @@ export function registerJobCommands(program: Command): void { ); for (const j of allJobs) { const budget = !j.legacy - ? formatUnits(BigInt(j.budget), 6) + ? j.budget + ? formatUnits(BigInt(j.budget), 6) + : "N/A" : j.budget; console.log( `${j.onChainJobId}\t${j.chainId}\t${j.clientAddress}\t${j.providerAddress}\t${budget}\t${j.jobStatus}\t${j.legacy}` diff --git a/src/lib/config.ts b/src/lib/config.ts index 863aced..60eb9a1 100644 --- a/src/lib/config.ts +++ b/src/lib/config.ts @@ -1,6 +1,6 @@ import { existsSync, mkdirSync, readFileSync, renameSync, writeFileSync } from "fs"; import { homedir } from "os"; -import { resolve } from "path"; +import { join, resolve } from "path"; import { getPassword, setPassword, @@ -59,7 +59,12 @@ function loadConfig(): Config { function saveConfig(config: Config): void { mkdirSync(CONFIG_DIR, { recursive: true }); - writeFileSync(CONFIG_PATH, JSON.stringify(config, null, 2) + "\n"); + // Write to a temp file first, then atomically rename to the final path. + // This prevents a truncated/partial JSON file if the process is interrupted + // mid-write, which would make loadConfig return an empty object on next run. + const tmpPath = join(CONFIG_DIR, `${CONFIG_FILENAME}.tmp`); + writeFileSync(tmpPath, JSON.stringify(config, null, 2) + "\n"); + renameSync(tmpPath, CONFIG_PATH); } function isKeychainUnavailable(err: unknown): boolean {