| 1 | import { readFileSync } from "node:fs"; |
| 2 | import { activeWorkBusyNoticeText } from "../lib/capabilityMutations"; |
| 3 | import { t } from "../lib/i18n"; |
| 4 | import { effortSwitchNoticeText, modelSwitchNoticeText } from "../lib/controllerSwitchNotices"; |
| 5 | |
| 6 | function ok(value: unknown, message: string) { |
| 7 | if (!value) throw new Error(message); |
| 8 | } |
| 9 | |
| 10 | const activeWorkError = (running: boolean, pendingPrompt: boolean, backgroundJobs: number) => |
| 11 | new Error(`active work is still running; running=${running}; pending_prompt=${pendingPrompt}; background_jobs=${backgroundJobs}; finish or cancel the current turn, answer pending prompts, and stop background jobs before changing MCP server`); |
| 12 | |
| 13 | ok( |
| 14 | activeWorkBusyNoticeText(activeWorkError(true, false, 0), t) === "This setting cannot change while the current answer is running. Stop it first.", |
| 15 | "capability mutations localize a running answer without exposing debug fields", |
| 16 | ); |
| 17 | ok( |
| 18 | activeWorkBusyNoticeText(activeWorkError(true, true, 0), t) === "This setting cannot change while a confirmation is waiting. Handle it first.", |
| 19 | "a pending prompt takes priority over the running-answer explanation", |
| 20 | ); |
| 21 | ok( |
| 22 | activeWorkBusyNoticeText(activeWorkError(false, false, 2), t) === "This setting cannot change while background work is active. Active jobs: 2. Stop them first.", |
| 23 | "capability mutations report the blocking background-job count", |
| 24 | ); |
| 25 | ok( |
| 26 | activeWorkBusyNoticeText(activeWorkError(false, false, 1), t) === "This setting cannot change while background work is active. Active jobs: 1. Stop them first.", |
| 27 | "a single background job uses grammatically neutral guidance", |
| 28 | ); |
| 29 | ok( |
| 30 | modelSwitchNoticeText(activeWorkError(false, false, 1).message.replace("MCP server", "model")) === "The model cannot change while background work is active. Active jobs: 1. Open Background jobs in the status bar to stop them.", |
| 31 | "model switching uses grammatically neutral single-job guidance", |
| 32 | ); |
| 33 | ok( |
| 34 | effortSwitchNoticeText(activeWorkError(false, false, 1).message.replace("MCP server", "effort")) === "Reasoning effort cannot change while background work is active. Active jobs: 1. Open Background jobs in the status bar to stop them.", |
| 35 | "effort switching uses grammatically neutral single-job guidance", |
| 36 | ); |
| 37 | ok( |
| 38 | activeWorkBusyNoticeText( |
| 39 | new Error("active work is still running; finish or cancel the current turn before changing MCP server"), |
| 40 | t, |
| 41 | ) === "This setting cannot change yet. Stop the current answer, handle pending prompts, or wait for background jobs to finish.", |
| 42 | "busy errors without structured details use a friendly generic explanation", |
| 43 | ); |
| 44 | ok( |
| 45 | activeWorkBusyNoticeText(new Error("MCP server executable was not found"), t) === null, |
| 46 | "non-busy capability failures keep their original actionable error", |
| 47 | ); |
| 48 | const capabilitiesSource = readFileSync(new URL("../components/CapabilitiesPanel.tsx", import.meta.url), "utf8"); |
| 49 | ok( |
| 50 | (capabilitiesSource.match(/setErr\(activeWorkBusyNoticeText\(e, t\) \?\?/g) ?? []).length === 4, |
| 51 | "all four capability mutation surfaces localize active-work failures", |
| 52 | ); |
| 53 | const subagentsSource = readFileSync(new URL("../components/SubagentsPanel.tsx", import.meta.url), "utf8"); |
| 54 | ok( |
| 55 | (subagentsSource.match(/setErr\(activeWorkBusyNoticeText\(e, t\) \?\?/g) ?? []).length === 1, |
| 56 | "subagent profile mutations localize active-work failures", |
| 57 | ); |
| 58 |