1import type {
2 ServerProvider,
3 ServerProviderVersionAdvisory,
4 ServerProviderCompatibilityAdvisory,
5} from "@t3tools/contracts";
6
7/**
8 * Visual treatment for each server-reported provider status. Centralized so
9 * the default-driver card and per-instance cards share the same language.
10 */
11export const PROVIDER_STATUS_STYLES = {
12 disabled: {
13 dot: "bg-muted-foreground/50",
14 },
15 error: {
16 dot: "bg-destructive",
17 },
18 ready: {
19 dot: "bg-success",
20 },
21 warning: {
22 dot: "bg-warning",
23 },
24} as const;
25
26export type ProviderStatusKey = keyof typeof PROVIDER_STATUS_STYLES;
27
28/**
29 * Derive the headline + detail copy shown under a provider's name in the
30 * settings page. Prefers `provider.message` for server-supplied detail and
31 * falls back to generic phrasing when the server has not yet reported any
32 * state — which happens before the first probe or when an instance names a
33 * driver this build does not ship. A ready provider without account metadata
34 * remains available and does not imply an authentication failure.
35 */
36export function getProviderSummary(provider: ServerProvider | undefined) {
37 if (!provider) {
38 return {
39 headline: "Checking provider status",
40 detail: "Waiting for the server to report installation and authentication details.",
41 };
42 }
43 if (!provider.enabled || provider.status === "disabled") {
44 return {
45 headline: "Disabled",
46 detail:
47 provider.message ?? "This provider is installed but disabled for new sessions in The Knife.",
48 };
49 }
50 if (!provider.installed) {
51 return {
52 headline: "Not found",
53 detail: provider.message ?? "CLI not detected on PATH.",
54 };
55 }
56 if (provider.auth.status === "unauthenticated") {
57 const authLabel = provider.auth.label ?? provider.auth.type;
58 return {
59 headline: authLabel ? `Not authenticated · ${authLabel}` : "Not authenticated",
60 detail: provider.message ?? null,
61 };
62 }
63 if (provider.status === "warning") {
64 return {
65 headline: "Needs attention",
66 detail:
67 provider.message ?? "The provider is installed, but the server could not fully verify it.",
68 };
69 }
70 if (provider.status === "error") {
71 return {
72 headline: "Unavailable",
73 detail: provider.message ?? "The provider failed its startup checks.",
74 };
75 }
76 if (provider.auth.status === "authenticated") {
77 const authLabel = provider.auth.label ?? provider.auth.type;
78 return {
79 headline: authLabel ? `Authenticated · ${authLabel}` : "Authenticated",
80 detail: provider.message ?? null,
81 };
82 }
83 return {
84 headline: "Available",
85 detail: provider.message ?? null,
86 };
87}
88
89/**
90 * Normalize a version string for display. Adds the `v` prefix when the
91 * driver reported a bare version (e.g. `1.2.3`) so cards render
92 * consistently regardless of driver.
93 */
94export function getProviderVersionLabel(version: string | null | undefined) {
95 if (!version) return null;
96 // Antigravity reports a release tag such as `agy_acp_server_20260818_01_RC01`.
97 // Show the date and candidate so the row title keeps room for the name.
98 const antigravity = /^agy_acp_server_(\d{4})(\d{2})(\d{2})_\d+(?:_(\w+))?$/.exec(version);
99 if (antigravity) {
100 const [, year, month, day, candidate] = antigravity;
101 return `${year}-${month}-${day}${candidate ? ` ${candidate}` : ""}`;
102 }
103 // Only bare semver-like versions get a `v` prefix. Other tags are shown as-is.
104 return /^\d/.test(version) ? `v${version}` : version;
105}
106
107const COMPATIBILITY_TITLES = {
108 graceful: "Limited support",
109 unsupported: "Unsupported version",
110 broken: "Known broken version",
111} as const;
112
113/** Compatibility guidance shares the version popover, with safe install actions. */
114export function getProviderVersionAdvisoryPresentation(
115 advisory: ServerProviderVersionAdvisory | undefined,
116 compatibility?: ServerProviderCompatibilityAdvisory | undefined,
117 showCompatibility = true,
118): {
119 readonly title: string;
120 readonly detail: string;
121 readonly updateCommand: string | null;
122 readonly emphasis: "normal" | "strong";
123 readonly targetVersion: string | null;
124} | null {
125 const latestIsIncompatible =
126 compatibility?.latestVersionStatus === "broken" ||
127 compatibility?.latestVersionStatus === "unsupported";
128 if (
129 showCompatibility &&
130 compatibility &&
131 (compatibility.status === "graceful" ||
132 compatibility.status === "unsupported" ||
133 compatibility.status === "broken")
134 ) {
135 const targetVersion = compatibility.recommendedVersion;
136 const recommendation = getProviderVersionLabel(targetVersion) ?? compatibility.recommendedRange;
137 return {
138 title: COMPATIBILITY_TITLES[compatibility.status],
139 detail:
140 compatibility.message ??
141 (recommendation ? `Use ${recommendation} for full support.` : "Update for full support."),
142 updateCommand:
143 targetVersion || latestIsIncompatible ? null : (advisory?.updateCommand ?? null),
144 emphasis: compatibility.status === "graceful" ? "normal" : "strong",
145 targetVersion,
146 };
147 }
148 if (
149 !advisory ||
150 advisory.status === "current" ||
151 advisory.status === "unknown" ||
152 latestIsIncompatible
153 ) {
154 return null;
155 }
156
157 const label = "Update available";
158 const version = advisory.latestVersion;
159 const versionLabel = getProviderVersionLabel(version);
160
161 return {
162 title: label,
163 detail:
164 advisory.message ??
165 (versionLabel
166 ? `${label}: install ${versionLabel}.`
167 : `${label}: install the latest provider version.`),
168 updateCommand: advisory.updateCommand,
169 emphasis: "normal" as const,
170 targetVersion: null,
171 };
172}