Open History to see the last commit
1import {
2 managedRuntimeModeDenial,
3 type ManagedPolicySummary,
4 type RuntimeMode,
5} from "@t3tools/contracts";
6
7export const RUNTIME_MODE_CHOICES: ReadonlyArray<{
8 readonly mode: RuntimeMode;
9 readonly label: string;
10 readonly description: string;
11}> = [
12 {
13 mode: "approval-required",
14 label: "Supervised",
15 description: "Ask before commands and file changes.",
16 },
17 {
18 mode: "auto-accept-edits",
19 label: "Auto-accept edits",
20 description: "Auto-approve edits, ask before other actions.",
21 },
22 {
23 mode: "auto",
24 label: "Auto",
25 description: "Supported providers approve routine actions; others still ask.",
26 },
27 {
28 mode: "full-access",
29 label: "Full access",
30 description: "Allow commands and edits without prompts.",
31 },
32];
33
34export function runtimeModeChoicesForSupportedModes(
35 supportedRuntimeModes: ReadonlyArray<RuntimeMode> | undefined,
36) {
37 return supportedRuntimeModes && supportedRuntimeModes.length > 0
38 ? RUNTIME_MODE_CHOICES.filter((choice) => supportedRuntimeModes.includes(choice.mode))
39 : RUNTIME_MODE_CHOICES;
40}
41
42export type RuntimeModeChoice = (typeof RUNTIME_MODE_CHOICES)[number] & {
43 /** Set when a target environment's managed policy caps runtime modes below this one. */
44 readonly disabledReason?: string;
45};
46
47/**
48 * Marks modes above a managed runtime ceiling. A control acting on several environments is
49 * managed when any of them is, so the first target that refuses a mode supplies its reason.
50 */
51export function withManagedRuntimeModeLimits(
52 choices: ReadonlyArray<RuntimeModeChoice>,
53 policies: ReadonlyArray<ManagedPolicySummary | undefined>,
54): ReadonlyArray<RuntimeModeChoice> {
55 return choices.map((choice) => {
56 const reason = policies
57 .map((policy) => managedRuntimeModeDenial(policy, choice.mode))
58 .find((denial) => denial !== undefined);
59 return reason === undefined ? choice : { ...choice, disabledReason: reason };
60 });
61}
62
63/**
64 * A new thread's mode: the draft's choice unless the managed ceiling refuses it, then the
65 * default, which the server already reads back at or below the ceiling.
66 */
67export function resolveNewThreadRuntimeMode(
68 draftMode: RuntimeMode | undefined,
69 defaultMode: RuntimeMode,
70 policy: ManagedPolicySummary | undefined,
71): RuntimeMode {
72 return draftMode !== undefined && managedRuntimeModeDenial(policy, draftMode) === undefined
73 ? draftMode
74 : defaultMode;
75}
76
77export function compatibleRuntimeModeForChoices(
78 runtimeMode: RuntimeMode,
79 choices: ReadonlyArray<{ readonly mode: RuntimeMode }>,
80): RuntimeMode {
81 return choices.some((choice) => choice.mode === runtimeMode)
82 ? runtimeMode
83 : (choices[0]?.mode ?? runtimeMode);
84}
85
86export { selectableProviderOptionChoices as selectableChoices } from "@t3tools/client-runtime/model-traits";