| 1 | import { t, type DictKey } from "./i18n"; |
| 2 | import { errorMessage } from "./controllerNotices"; |
| 3 | import type { MessageActionScope } from "./messageActions"; |
| 4 | import { app } from "./bridge"; |
| 5 | import type { TabMeta } from "./types"; |
| 6 | export { settleForkConversationForTab } from "./forkWorktree"; |
| 7 | |
| 8 | export async function restoreNavigationBackend(sourceTabId: string, targetTabId: string, sourceTab?: TabMeta): Promise<{ |
| 9 | restoredTabId: string; |
| 10 | restoredMeta?: TabMeta; |
| 11 | } | null> { |
| 12 | if (sourceTabId !== targetTabId && await app.SetActiveTab(sourceTabId).then(() => true).catch(() => false)) { |
| 13 | return { restoredTabId: sourceTabId }; |
| 14 | } |
| 15 | if (!sourceTab?.topicId) return null; |
| 16 | try { |
| 17 | const restoredMeta = sourceTab.sessionPath |
| 18 | ? await app.OpenTopicSession(sourceTab.scope, sourceTab.workspaceRoot, sourceTab.topicId, sourceTab.sessionPath) |
| 19 | : await app.ActivateTopic(sourceTab.scope, sourceTab.workspaceRoot, sourceTab.topicId, ""); |
| 20 | return { restoredTabId: restoredMeta.id, restoredMeta }; |
| 21 | } catch { |
| 22 | return null; |
| 23 | } |
| 24 | } |
| 25 | |
| 26 | export function messageActionBusyText(scope: MessageActionScope): string { |
| 27 | switch (scope) { |
| 28 | case "fork": |
| 29 | case "fork-worktree": return t("rewind.busyFork"); |
| 30 | case "summ-from": return t("rewind.busySummFrom"); |
| 31 | case "summ-upto": return t("rewind.busySummUpto"); |
| 32 | case "conversation": return t("rewind.busyConversation"); |
| 33 | case "code": return t("rewind.busyCode"); |
| 34 | default: return t("rewind.busyBoth"); |
| 35 | } |
| 36 | } |
| 37 | |
| 38 | type SettingNoticeKeys = { |
| 39 | busy: DictKey; |
| 40 | busyRunning: DictKey; |
| 41 | busyPrompt: DictKey; |
| 42 | busyJobs: DictKey; |
| 43 | leaseHeld: DictKey; |
| 44 | starting: DictKey; |
| 45 | startupFailed: DictKey; |
| 46 | retry: DictKey; |
| 47 | failed: DictKey; |
| 48 | }; |
| 49 | |
| 50 | function settingSwitchNoticeText(err: unknown, setting: "effort" | "model" | "token mode", keys: SettingNoticeKeys): string { |
| 51 | const msg = errorMessage(err).trim() || "unknown error"; |
| 52 | const lower = msg.toLowerCase(); |
| 53 | if (lower.includes("finish or cancel") && lower.includes(`before changing ${setting}`)) { |
| 54 | const detail = /running=(true|false);\s*pending_prompt=(true|false);\s*background_jobs=(\d+)/i.exec(msg); |
| 55 | if (detail?.[2] === "true") return t(keys.busyPrompt); |
| 56 | if (detail?.[1] === "true") return t(keys.busyRunning); |
| 57 | const jobs = Number(detail?.[3] ?? 0); |
| 58 | if (jobs > 0) return t(keys.busyJobs, { n: jobs }); |
| 59 | return t(keys.busy); |
| 60 | } |
| 61 | if (lower.includes("already open in another reasonix window") || lower.includes("session lease held")) return t(keys.leaseHeld); |
| 62 | if (lower.includes("workspace is still starting")) return t(keys.starting); |
| 63 | if (lower.startsWith("workspace failed to start")) return t(keys.startupFailed, { err: msg }); |
| 64 | if (lower.includes(`changed while switching ${setting}`) || (lower.includes("tab ") && lower.includes("not found"))) return t(keys.retry); |
| 65 | return t(keys.failed, { err: msg }); |
| 66 | } |
| 67 | |
| 68 | export function effortSwitchNoticeText(err: unknown): string { |
| 69 | return settingSwitchNoticeText(err, "effort", { |
| 70 | busy: "status.effortSwitchBusy", |
| 71 | busyRunning: "status.effortSwitchBusyRunning", |
| 72 | busyPrompt: "status.effortSwitchBusyPrompt", |
| 73 | busyJobs: "status.effortSwitchBusyJobs", |
| 74 | leaseHeld: "status.effortSwitchLeaseHeld", |
| 75 | starting: "status.effortSwitchStarting", |
| 76 | startupFailed: "status.effortSwitchStartupFailed", |
| 77 | retry: "status.effortSwitchRetry", |
| 78 | failed: "status.effortSwitchFailed", |
| 79 | }); |
| 80 | } |
| 81 | |
| 82 | export function modelSwitchNoticeText(err: unknown): string { |
| 83 | const msg = errorMessage(err).trim() || "unknown error"; |
| 84 | const unknownModel = /^unknown model (.+)$/i.exec(msg); |
| 85 | if (unknownModel) return t("status.modelSwitchUnknown", { model: unknownModel[1] }); |
| 86 | const unavailable = /^model (.+) is not available because provider (.+) is not added$/i.exec(msg); |
| 87 | if (unavailable) return t("status.modelSwitchProviderUnavailable", { model: unavailable[1], provider: unavailable[2] }); |
| 88 | return settingSwitchNoticeText(msg, "model", { |
| 89 | busy: "status.modelSwitchBusy", |
| 90 | busyRunning: "status.modelSwitchBusyRunning", |
| 91 | busyPrompt: "status.modelSwitchBusyPrompt", |
| 92 | busyJobs: "status.modelSwitchBusyJobs", |
| 93 | leaseHeld: "status.modelSwitchLeaseHeld", |
| 94 | starting: "status.modelSwitchStarting", |
| 95 | startupFailed: "status.modelSwitchStartupFailed", |
| 96 | retry: "status.modelSwitchRetry", |
| 97 | failed: "status.modelSwitchFailed", |
| 98 | }); |
| 99 | } |
| 100 |