diff --git a/packages/loopover-miner/lib/manage-status.js b/packages/loopover-miner/lib/manage-status.js index 3101cadb40..de37958b3e 100644 --- a/packages/loopover-miner/lib/manage-status.js +++ b/packages/loopover-miner/lib/manage-status.js @@ -1,7 +1,7 @@ import { initEventLedger } from "./event-ledger.js"; import { initPortfolioQueueStore } from "./portfolio-queue.js"; import { initRunStateStore } from "./run-state.js"; -import { argsWantJson, reportCliFailure } from "./cli-error.js"; +import { argsWantJson, describeCliError, reportCliFailure } from "./cli-error.js"; /** Event vocabulary for manage-phase PR snapshots written by manage poll. (#2325) */ export const MANAGE_PR_UPDATE_EVENT = "manage_pr_update"; @@ -233,6 +233,10 @@ export function runManageStatus(args = [], options = {}) { console.log(`${renderManageStatusTable(rows)}\n\n${renderRunPortfolioTable(runPortfolio)}`); } return 0; + } catch (error) { + // Collecting/rendering manage status touches three SQLite stores; a read/render failure must surface as a + // clean CLI error (honoring --json), not an unhandled throw -- matching runOrbExportCli / runQueueList (#7236). + return reportCliFailure(parsed.json, describeCliError(error)); } finally { if (ownsPortfolioQueue) portfolioQueue.close(); if (ownsEventLedger) eventLedger.close(); diff --git a/test/unit/miner-manage-status.test.ts b/test/unit/miner-manage-status.test.ts index e5744a8465..f10a1d36b7 100644 --- a/test/unit/miner-manage-status.test.ts +++ b/test/unit/miner-manage-status.test.ts @@ -275,6 +275,32 @@ describe("loopover-miner manage status (#2325)", () => { ]); }); + it("reports a clean CLI failure (honoring --json) when collecting status throws, instead of an unhandled throw (#7236)", () => { + const throwingQueue = { + listQueue() { + throw new Error("boom: portfolio-queue read failed"); + }, + close() {}, + }; + const initStores = { + initPortfolioQueue: () => throwingQueue, + initEventLedger: () => ({ readEvents: () => [], close() {} }), + initRunStateStore: () => ({ listRunStates: () => [], close() {} }), + } as unknown as Parameters[1]; + + const error = vi.spyOn(console, "error").mockImplementation(() => {}); + expect(() => runManageStatus([], initStores)).not.toThrow(); + expect(runManageStatus([], initStores)).toBe(2); + expect(String(error.mock.calls.at(-1)?.[0])).toContain("boom: portfolio-queue read failed"); + + const log = vi.spyOn(console, "log").mockImplementation(() => {}); + expect(runManageStatus(["--json"], initStores)).toBe(2); + expect(JSON.parse(String(log.mock.calls.at(-1)?.[0]))).toEqual({ + ok: false, + error: "boom: portfolio-queue read failed", + }); + }); + it("rejects unknown CLI options", () => { const error = vi.spyOn(console, "error").mockImplementation(() => {}); expect(runManageStatus(["--verbose"])).toBe(2);