Open History to see the last commit
1import {
2 TrimmedNonEmptyString,
3 ServerProviderCompatibilityStatus,
4 type ProviderDriverKind,
5 type ServerProvider,
6 type ServerProviderCompatibilityAdvisory,
7} from "@t3tools/contracts";
8import { satisfiesSemverRange } from "@t3tools/shared/semver";
9import * as Schema from "effect/Schema";
10import packageJson from "../../package.json" with { type: "json" };
11
12const StableVersion = TrimmedNonEmptyString.pipe(
13 Schema.check(Schema.makeFilter((value) => /^\d+\.\d+\.\d+$/.test(value))),
14);
15const VersionRange = TrimmedNonEmptyString.pipe(
16 Schema.check(
17 Schema.makeFilter((value) =>
18 value.split("||").every((group) => {
19 const tokens = group.trim().split(/\s+/);
20 return tokens.every((token) => /^(?:\^|>=|>|<=|<|=)?v?\d+(?:\.\d+){0,2}$/.test(token));
21 }),
22 ),
23 ),
24);
25const Policy = Schema.Struct({
26 driver: TrimmedNonEmptyString,
27 t3CodeRange: VersionRange,
28 recommendedRange: Schema.optionalKey(VersionRange),
29 recommendedVersion: Schema.optionalKey(StableVersion),
30 ranges: Schema.Array(
31 Schema.Struct({
32 range: VersionRange,
33 status: ServerProviderCompatibilityStatus,
34 }),
35 ),
36});
37
38export const ProviderCompatibilityPolicy = Policy.pipe(
39 Schema.check(
40 Schema.makeFilter(
41 (policy) => {
42 const version = policy.recommendedVersion;
43 if (version === undefined) return true;
44 return (
45 (policy.recommendedRange === undefined ||
46 satisfiesSemverRange(version, policy.recommendedRange)) &&
47 policy.ranges.find((entry) => satisfiesSemverRange(version, entry.range))?.status ===
48 "supported"
49 );
50 },
51 { expected: "a recommended version in a supported range" },
52 ),
53 ),
54);
55export type ProviderCompatibilityPolicy = typeof ProviderCompatibilityPolicy.Type;
56
57export function resolveProviderCompatibility(
58 policies: ReadonlyArray<ProviderCompatibilityPolicy> | undefined,
59 driver: ProviderDriverKind,
60 version: string | null,
61 t3CodeVersion = packageJson.version,
62): ServerProviderCompatibilityAdvisory | undefined {
63 const policy = policies?.find(
64 (entry) => entry.driver === driver && satisfiesSemverRange(t3CodeVersion, entry.t3CodeRange),
65 );
66 if (!policy) return undefined;
67 const unprefixed = version?.replace(/^v/, "");
68 // Strip Cursor build hashes, Google ACP release prefixes and Muse revisions; leave semver prereleases unknown.
69 const stable =
70 driver === "cursor"
71 ? unprefixed?.replace(/^(\d{4}\.\d{2}\.\d{2})-[a-f0-9]+$/, "$1")
72 : driver === "antigravity"
73 ? unprefixed?.replace(/^agy_acp_server_(\d+\.\d+\.\d+)$/, "$1")
74 : driver === "muse"
75 ? unprefixed?.replace(/^(\d+\.\d+\.\d+)-R\d+(?:\.\d+)?$/, "$1")
76 : unprefixed;
77 const status =
78 stable && /^\d+\.\d+\.\d+$/.test(stable)
79 ? (policy.ranges.find((entry) => satisfiesSemverRange(stable, entry.range))?.status ??
80 "unknown")
81 : "unknown";
82 const message =
83 status === "broken"
84 ? "This provider version is known to be incompatible with this T3 Code release."
85 : status === "unsupported"
86 ? "This provider version is outside the supported range for this T3 Code release."
87 : status === "graceful"
88 ? "This provider version has limited compatibility with this T3 Code release."
89 : null;
90 const recommendedVersion = policy.recommendedVersion ?? null;
91 const recommendedRange = policy.recommendedRange ?? null;
92 const recommendation = recommendedVersion ?? recommendedRange;
93 return {
94 status,
95 message: message && recommendation ? `${message} Use ${recommendation}.` : message,
96 recommendedVersion,
97 recommendedRange,
98 };
99}
100
101export function applyProviderCompatibility(
102 snapshot: ServerProvider,
103 policies: ReadonlyArray<ProviderCompatibilityPolicy> | undefined,
104 fallback: ReadonlyArray<ProviderCompatibilityPolicy> | undefined,
105): ServerProvider {
106 const { compatibilityAdvisory: _previous, ...base } = snapshot;
107 if (!snapshot.enabled || !snapshot.installed) return base;
108 const advisory =
109 resolveProviderCompatibility(policies, snapshot.driver, snapshot.version) ??
110 resolveProviderCompatibility(fallback, snapshot.driver, snapshot.version);
111 const latestVersion = snapshot.versionAdvisory?.latestVersion;
112 const latestAdvisory = latestVersion
113 ? (resolveProviderCompatibility(policies, snapshot.driver, latestVersion) ??
114 resolveProviderCompatibility(fallback, snapshot.driver, latestVersion))
115 : undefined;
116 const updateCommand = snapshot.versionAdvisory?.updateCommand;
117 // The maintenance resolver emits this command only for confirmed Homebrew installs.
118 const needsHomebrewRefresh =
119 updateCommand?.startsWith("brew upgrade ") &&
120 (advisory?.status === "unsupported" || advisory?.status === "broken") &&
121 (latestAdvisory?.status === "unsupported" || latestAdvisory?.status === "broken");
122 return advisory
123 ? {
124 ...base,
125 compatibilityAdvisory: {
126 ...advisory,
127 message: needsHomebrewRefresh
128 ? `${advisory.message} Homebrew's local package metadata may be stale. Run brew update && ${updateCommand} on this environment's host, then refresh provider status.`
129 : advisory.message,
130 ...(latestAdvisory ? { latestVersionStatus: latestAdvisory.status } : {}),
131 },
132 }
133 : base;
134}