@rightkit/agent-ui-settings 0.0.0-stage → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (100) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/LICENSE-APACHE +201 -0
  3. package/LICENSE-MIT +21 -0
  4. package/README.md +44 -2
  5. package/dist/appName.d.ts +1 -0
  6. package/dist/appName.js +1 -0
  7. package/dist/components/PluginContributionHost.d.ts +17 -0
  8. package/dist/components/PluginContributionHost.js +23 -0
  9. package/dist/components/ReadinessCard.d.ts +4 -0
  10. package/dist/components/ReadinessCard.js +19 -0
  11. package/dist/components/remote/RemoteDevicesPanel.d.ts +7 -0
  12. package/dist/components/remote/RemoteDevicesPanel.js +153 -0
  13. package/dist/components/remote/RemoteHostsPanel.d.ts +8 -0
  14. package/dist/components/remote/RemoteHostsPanel.js +139 -0
  15. package/dist/components/settings/analytics/AnalyticsConsentCard.d.ts +14 -0
  16. package/dist/components/settings/analytics/AnalyticsConsentCard.js +22 -0
  17. package/dist/components/settings/cliUpdate/CliUpdatePanel.d.ts +9 -0
  18. package/dist/components/settings/cliUpdate/CliUpdatePanel.js +18 -0
  19. package/dist/components/settings/helpers.d.ts +7 -0
  20. package/dist/components/settings/helpers.js +40 -0
  21. package/dist/components/settings/keyboard/KeyboardShortcutsSettings.d.ts +12 -0
  22. package/dist/components/settings/keyboard/KeyboardShortcutsSettings.js +75 -0
  23. package/dist/components/settings/keyboard/ShortcutRecordingDialog.d.ts +27 -0
  24. package/dist/components/settings/keyboard/ShortcutRecordingDialog.js +154 -0
  25. package/dist/components/settings/marketplace/McpDiscoverPanel.d.ts +34 -0
  26. package/dist/components/settings/marketplace/McpDiscoverPanel.js +66 -0
  27. package/dist/components/settings/marketplace/SkillMarketplace.d.ts +22 -0
  28. package/dist/components/settings/marketplace/SkillMarketplace.js +51 -0
  29. package/dist/components/settings/tabs/ApiKeyAccounts.d.ts +9 -0
  30. package/dist/components/settings/tabs/ApiKeyAccounts.js +67 -0
  31. package/dist/components/settings/tabs/AppearanceTab.d.ts +1 -0
  32. package/dist/components/settings/tabs/AppearanceTab.js +31 -0
  33. package/dist/components/settings/tabs/AppleSyncPanel.d.ts +14 -0
  34. package/dist/components/settings/tabs/AppleSyncPanel.js +65 -0
  35. package/dist/components/settings/tabs/ChildProviderPolicy.d.ts +9 -0
  36. package/dist/components/settings/tabs/ChildProviderPolicy.js +84 -0
  37. package/dist/components/settings/tabs/ConductorsTab.d.ts +6 -0
  38. package/dist/components/settings/tabs/ConductorsTab.js +135 -0
  39. package/dist/components/settings/tabs/DiagnosticsTab.d.ts +13 -0
  40. package/dist/components/settings/tabs/DiagnosticsTab.js +39 -0
  41. package/dist/components/settings/tabs/ExecutionBackendsTab.d.ts +29 -0
  42. package/dist/components/settings/tabs/ExecutionBackendsTab.js +13 -0
  43. package/dist/components/settings/tabs/LicenseTab.d.ts +20 -0
  44. package/dist/components/settings/tabs/LicenseTab.js +66 -0
  45. package/dist/components/settings/tabs/LinkComputerPanel.d.ts +6 -0
  46. package/dist/components/settings/tabs/LinkComputerPanel.js +39 -0
  47. package/dist/components/settings/tabs/LspTab.d.ts +11 -0
  48. package/dist/components/settings/tabs/LspTab.js +34 -0
  49. package/dist/components/settings/tabs/MemoryTab.d.ts +7 -0
  50. package/dist/components/settings/tabs/MemoryTab.js +68 -0
  51. package/dist/components/settings/tabs/ProvidersTab.d.ts +10 -0
  52. package/dist/components/settings/tabs/ProvidersTab.js +214 -0
  53. package/dist/components/settings/tabs/RepairTab.d.ts +6 -0
  54. package/dist/components/settings/tabs/RepairTab.js +44 -0
  55. package/dist/components/settings/tabs/RootModelPicker.d.ts +10 -0
  56. package/dist/components/settings/tabs/RootModelPicker.js +42 -0
  57. package/dist/components/settings/tabs/RuntimeMiddlewareTab.d.ts +8 -0
  58. package/dist/components/settings/tabs/RuntimeMiddlewareTab.js +12 -0
  59. package/dist/components/settings/tabs/WorkspaceTab.d.ts +6 -0
  60. package/dist/components/settings/tabs/WorkspaceTab.js +9 -0
  61. package/dist/components/settings/tabs/execution/CoreSandboxTierPanel.d.ts +9 -0
  62. package/dist/components/settings/tabs/execution/CoreSandboxTierPanel.js +43 -0
  63. package/dist/components/settings/tabs/execution/ExecutionBackendCard.d.ts +20 -0
  64. package/dist/components/settings/tabs/execution/ExecutionBackendCard.js +48 -0
  65. package/dist/components/settings/tabs/execution/ExecutionBackendLimitsForm.d.ts +10 -0
  66. package/dist/components/settings/tabs/execution/ExecutionBackendLimitsForm.js +62 -0
  67. package/dist/components/settings/tabs/execution/ExecutionBackendList.d.ts +19 -0
  68. package/dist/components/settings/tabs/execution/ExecutionBackendList.js +8 -0
  69. package/dist/components/settings/tabs/execution/ExecutionNetworkProfilesPanel.d.ts +16 -0
  70. package/dist/components/settings/tabs/execution/ExecutionNetworkProfilesPanel.js +53 -0
  71. package/dist/components/settings/tabs/execution/RemoteStatusCard.d.ts +2 -0
  72. package/dist/components/settings/tabs/execution/RemoteStatusCard.js +5 -0
  73. package/dist/components/settings/tabs/execution/TextSettingInput.d.ts +15 -0
  74. package/dist/components/settings/tabs/execution/TextSettingInput.js +10 -0
  75. package/dist/components/settings/tabs/execution/types.d.ts +27 -0
  76. package/dist/components/settings/tabs/execution/types.js +1 -0
  77. package/dist/components/settings/tabs/models/ModelEmptyStates.d.ts +12 -0
  78. package/dist/components/settings/tabs/models/ModelEmptyStates.js +63 -0
  79. package/dist/components/settings/tabs/permissions/PersistentPermissionRuleList.d.ts +7 -0
  80. package/dist/components/settings/tabs/permissions/PersistentPermissionRuleList.js +15 -0
  81. package/dist/components/settings/tabs/plugins/InstalledPluginsList.d.ts +6 -0
  82. package/dist/components/settings/tabs/plugins/InstalledPluginsList.js +38 -0
  83. package/dist/components/settings/tabs/remote/RemoteChannelsPanel.d.ts +4 -0
  84. package/dist/components/settings/tabs/remote/RemoteChannelsPanel.js +14 -0
  85. package/dist/components/settings/tabs/remote/RemoteStatusCard.d.ts +8 -0
  86. package/dist/components/settings/tabs/remote/RemoteStatusCard.js +6 -0
  87. package/dist/components/settings/tabs/remote/TelegramStatusPanel.d.ts +6 -0
  88. package/dist/components/settings/tabs/remote/TelegramStatusPanel.js +41 -0
  89. package/dist/components/settings/tabs/shared.d.ts +18 -0
  90. package/dist/components/settings/tabs/shared.js +36 -0
  91. package/dist/components/settings/tabs/skills/SkillShared.d.ts +20 -0
  92. package/dist/components/settings/tabs/skills/SkillShared.js +28 -0
  93. package/dist/components/settings/tabs/skills/SkillTrainingRunList.d.ts +6 -0
  94. package/dist/components/settings/tabs/skills/SkillTrainingRunList.js +11 -0
  95. package/dist/components/settings/tools/ManagedToolHealthPanel.d.ts +16 -0
  96. package/dist/components/settings/tools/ManagedToolHealthPanel.js +24 -0
  97. package/dist/env.d.ts +59 -0
  98. package/dist/index.d.ts +31 -0
  99. package/dist/index.js +33 -0
  100. package/package.json +165 -3
@@ -0,0 +1,214 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useCallback, useEffect, useState } from "react";
3
+ import Icon from "@rightkit/agent-ui-core/components/Icon";
4
+ import { buildProviderCardSnapshots, getProviderDisplay, readyOnlyChildPolicy, shortLabelForProvider, } from "@rightkit/agent-ui-core/lib/cliProviders";
5
+ import { getCliDelegationPolicy, listCliProviders, mutateCliProvider, setCliDelegationPolicy, } from "@rightkit/agent-ui-core/lib/daemon/cli-providers";
6
+ import ChildProviderPolicy from "./ChildProviderPolicy.js";
7
+ import ApiKeyAccounts from "./ApiKeyAccounts.js";
8
+ import { createDirectConnection, deleteDirectConnection, getInferenceLoad, listInferenceCatalog, listInferenceConnections, probeInferenceConnection, } from "@rightkit/agent-ui-core/lib/daemon/inference";
9
+ import { hostAppName } from "../../../appName.js";
10
+ function Disclosure({ label, children }) {
11
+ const [open, setOpen] = useState(false);
12
+ return (_jsxs("div", { className: "rounded-xl border border-line", children: [_jsxs("button", { type: "button", "aria-expanded": open, onClick: () => setOpen((v) => !v), className: "flex w-full items-center justify-between gap-2 px-4 py-2.5 text-[13px] font-semibold text-text-2 cursor-pointer border-0 bg-transparent hover:text-text focus-visible:outline focus-visible:outline-2 focus-visible:outline-accent", children: [_jsx("span", { children: label }), _jsx("span", { "aria-hidden": "true", className: `transition-transform duration-150 ${open ? "rotate-180" : ""}`, children: _jsx(Icon, { name: "chevron", size: 12 }) })] }), open ? _jsx("div", { className: "flex flex-col gap-2 border-t border-line p-4", children: children }) : null] }));
13
+ }
14
+ function eligibilityBadgeFor(snapshot) {
15
+ switch (snapshot.eligibility.kind) {
16
+ case "ready":
17
+ return { label: "Ready", tone: "border-success/40 text-success" };
18
+ case "compatibility_read_only":
19
+ return { label: "Compatibility", tone: "border-warning/40 text-warning" };
20
+ case "login_required":
21
+ return { label: "Login required", tone: "border-warning/40 text-warning" };
22
+ case "harness_verification_required":
23
+ return { label: "Harness verification", tone: "border-warning/40 text-warning" };
24
+ case "version_unsupported":
25
+ return { label: "Version unsupported", tone: "border-danger/40 text-danger" };
26
+ case "unqualified":
27
+ return { label: "Unqualified", tone: "border-danger/40 text-danger" };
28
+ default:
29
+ return { label: "Unknown", tone: "border-line-2 text-text-3" };
30
+ }
31
+ }
32
+ function isolationLabelFor(mode) {
33
+ if (mode === "exclusive_coderight_gateway")
34
+ return `${hostAppName()} gateway`;
35
+ if (mode === "native_read_only_compatibility")
36
+ return "Read-only compatibility";
37
+ return mode;
38
+ }
39
+ function eligibilityReason(snapshot) {
40
+ if (snapshot.eligibility.kind === "unqualified") {
41
+ return snapshot.eligibility.reasons.join("; ");
42
+ }
43
+ if (snapshot.eligibility.kind === "compatibility_read_only") {
44
+ return `Native vendor is read-only; ${hostAppName()} owns every stateful effect.`;
45
+ }
46
+ if (snapshot.eligibility.kind === "login_required") {
47
+ return "Sign in via the vendor CLI to attach this provider.";
48
+ }
49
+ if (snapshot.eligibility.kind === "harness_verification_required") {
50
+ return "Harness attestation pending — re-qualify once the binary is installed.";
51
+ }
52
+ return null;
53
+ }
54
+ export default function ProvidersTab({ settings, config, sessionId, onLoginCliProvider, }) {
55
+ const [providers, setProviders] = useState([]);
56
+ const [attestationError, setAttestationError] = useState(null);
57
+ const [pendingProvider, setPendingProvider] = useState(null);
58
+ const [delegationPolicy, setDelegationPolicyState] = useState(null);
59
+ const [connections, setConnections] = useState([]);
60
+ const [catalogGroups, setCatalogGroups] = useState([]);
61
+ const [load, setLoad] = useState(null);
62
+ useEffect(() => {
63
+ let cancelled = false;
64
+ const load = async () => {
65
+ if (!config)
66
+ return;
67
+ try {
68
+ const snapshot = await listCliProviders(config);
69
+ if (!cancelled) {
70
+ setProviders(snapshot.providers);
71
+ setAttestationError(null);
72
+ }
73
+ if (!sessionId) {
74
+ if (!cancelled)
75
+ setDelegationPolicyState(null);
76
+ return;
77
+ }
78
+ try {
79
+ const policy = await getCliDelegationPolicy(config, sessionId);
80
+ if (!cancelled)
81
+ setDelegationPolicyState(policy);
82
+ }
83
+ catch (error) {
84
+ if (!cancelled) {
85
+ setDelegationPolicyState(null);
86
+ setAttestationError(error instanceof Error ? error.message : "Delegation policy unavailable");
87
+ }
88
+ }
89
+ }
90
+ catch (err) {
91
+ if (!cancelled) {
92
+ setAttestationError(err instanceof Error ? err.message : "unavailable");
93
+ }
94
+ }
95
+ };
96
+ void load();
97
+ return () => {
98
+ cancelled = true;
99
+ };
100
+ }, [config, sessionId]);
101
+ const refreshInference = useCallback(async () => {
102
+ if (!config)
103
+ return;
104
+ const [nextConnections, nextCatalog, nextLoad] = await Promise.all([
105
+ listInferenceConnections(config),
106
+ listInferenceCatalog(config),
107
+ getInferenceLoad(config),
108
+ ]);
109
+ setConnections(nextConnections);
110
+ setCatalogGroups(nextCatalog);
111
+ setLoad(nextLoad);
112
+ }, [config]);
113
+ useEffect(() => {
114
+ void refreshInference().catch((error) => setAttestationError(error instanceof Error ? error.message : "Inference authority unavailable"));
115
+ }, [refreshInference]);
116
+ const addConnection = async () => {
117
+ if (!config)
118
+ return;
119
+ try {
120
+ await createDirectConnection(config, {
121
+ name: "New Direct connection",
122
+ protocol: "openai_compatible",
123
+ normalizedBaseUrl: "http://127.0.0.1:11434",
124
+ authKind: "none",
125
+ authHeaderName: null,
126
+ publicHeaders: {},
127
+ manualModelIds: [],
128
+ trustPrivateNetwork: false,
129
+ });
130
+ await refreshInference();
131
+ }
132
+ catch (error) {
133
+ setAttestationError(error instanceof Error ? error.message : "Could not add Direct connection");
134
+ }
135
+ };
136
+ const updateDelegationPolicy = async (policy) => {
137
+ if (!config || !sessionId)
138
+ return;
139
+ policy = readyOnlyChildPolicy(policy, providers);
140
+ const previous = delegationPolicy;
141
+ setDelegationPolicyState(policy);
142
+ try {
143
+ setDelegationPolicyState(await setCliDelegationPolicy(config, sessionId, policy));
144
+ setAttestationError(null);
145
+ }
146
+ catch (error) {
147
+ setDelegationPolicyState(previous);
148
+ setAttestationError(error instanceof Error ? error.message : "Delegation policy update failed");
149
+ }
150
+ };
151
+ const runProviderAction = async (provider, action) => {
152
+ if (!config)
153
+ return;
154
+ setPendingProvider(provider);
155
+ setAttestationError(null);
156
+ try {
157
+ const snapshot = await mutateCliProvider(config, provider, action);
158
+ setProviders(snapshot.providers);
159
+ if (action === "login")
160
+ onLoginCliProvider?.(provider);
161
+ }
162
+ catch (error) {
163
+ setAttestationError(error instanceof Error ? error.message : "Provider action failed");
164
+ }
165
+ finally {
166
+ setPendingProvider(null);
167
+ }
168
+ };
169
+ const snapshots = buildProviderCardSnapshots({ providers });
170
+ const configuredCount = snapshots.filter((s) => s.auth.launchReady).length;
171
+ const detectedCount = snapshots.filter((s) => s.auth.detectedSignedIn).length;
172
+ const summaryParts = [`${configuredCount} of ${snapshots.length} launch-ready`];
173
+ if (detectedCount > 0)
174
+ summaryParts.push(`${detectedCount} ambient sign-in${detectedCount === 1 ? "" : "s"} detected`);
175
+ if (snapshots.length - configuredCount > 0) {
176
+ summaryParts.push(`${snapshots.length - configuredCount} need${snapshots.length - configuredCount === 1 ? "s" : ""} routing or verification`);
177
+ }
178
+ const providerCounts = new Map();
179
+ if (settings) {
180
+ for (const model of settings.models) {
181
+ providerCounts.set(model.provider, (providerCounts.get(model.provider) ?? 0) + 1);
182
+ }
183
+ }
184
+ return (_jsxs("section", { className: "flex flex-col gap-5 p-6", children: [_jsxs("div", { className: "flex flex-col gap-1", children: [_jsx("h3", { className: "text-[16px] font-bold text-text", children: "Providers" }), _jsx("p", { className: "text-[13px] font-semibold text-text", children: summaryParts.join(" · ") }), _jsxs("p", { className: "text-[12px] text-text-3", children: ["Keep each CLI's authentication inside its own vendor login. ", hostAppName(), " stores only non-secret profile metadata. API keys go straight to the system credential store."] }), attestationError ? (_jsxs("p", { className: "text-[11px] text-text-3", children: ["Harness attestations unavailable: ", attestationError] })) : null] }), _jsxs("section", { className: "rounded-xl border border-line bg-panel p-4", "aria-label": "Inference authorities", children: [_jsxs("div", { className: "mb-3 flex items-center justify-between gap-3", children: [_jsxs("div", { children: [_jsx("h4", { className: "text-[13px] font-semibold text-text", children: "Direct Connections" }), _jsx("p", { className: "text-[12px] text-text-3", children: "OpenAI- & Anthropic-compatible endpoints. Keys remain in system keychain." })] }), _jsx("button", { type: "button", onClick: () => void addConnection(), className: "rounded-lg border border-line px-3 py-2 text-[12px] text-text hover:bg-panel-2", children: "Add connection" })] }), _jsx("div", { className: "flex flex-col gap-2", children: connections.map((connection) => (_jsxs("article", { className: "flex items-center gap-3 rounded-lg border border-line/70 px-3 py-2", children: [_jsxs("div", { className: "min-w-0 flex-1", children: [_jsx("strong", { className: "block truncate text-[12px] text-text", children: connection.name }), _jsxs("span", { className: "block truncate text-[11px] text-text-3", children: [connection.protocol.replace("_", " "), " \u00B7 ", connection.normalizedBaseUrl, " \u00B7", " ", connection.credentialConfigured ? "key configured" : "no key"] })] }), _jsx("button", { type: "button", className: "rounded border border-line px-2 py-1 text-[11px] text-text-2", onClick: () => config &&
185
+ void probeInferenceConnection(config, "direct", connection.id)
186
+ .then(refreshInference)
187
+ .catch((error) => setAttestationError(error instanceof Error ? error.message : "Probe failed")), children: "Probe" }), _jsx("button", { type: "button", className: "rounded border border-danger/40 px-2 py-1 text-[11px] text-danger", onClick: () => config &&
188
+ void deleteDirectConnection(config, connection.id)
189
+ .then(refreshInference)
190
+ .catch((error) => setAttestationError(error instanceof Error ? error.message : "Delete failed")), children: "Delete" })] }, connection.id))) }), load ? (_jsxs("p", { className: "mt-3 text-[12px] text-text-3", "aria-live": "polite", children: [load.activeAgents, "/", load.activeLimit, " active \u00B7 ", load.queuedAgents, " queued"] })) : null] }), _jsx(ApiKeyAccounts, { config: config }), _jsx("div", { className: "grid gap-3", children: snapshots.map((snapshot) => (_jsx(ProviderCard, { snapshot: snapshot, pending: pendingProvider === snapshot.providerId, onAction: runProviderAction }, snapshot.providerId))) }), _jsx(Disclosure, { label: "Advanced: model \u2192 provider mapping", children: providerCounts.size > 0 ? ([...providerCounts.entries()].map(([name, count]) => (_jsxs("article", { className: "grid grid-cols-[minmax(0,1fr)_240px] items-center gap-3 px-1 h-9 border-b border-line/60 last:border-b-0", children: [_jsx("div", { className: "flex flex-col min-w-0", children: _jsx("strong", { className: "text-[13px] font-semibold text-text truncate", children: shortLabelForProvider(name) }) }), _jsxs("div", { className: "flex items-center gap-2 text-[12px] text-text-3", children: [_jsxs("span", { className: "truncate", children: [count, " model", count !== 1 ? "s" : "", " configured"] }), _jsx("code", { className: "text-[11px] font-mono text-accent-2", children: "configured" })] })] }, name)))) : (_jsx("p", { className: "text-[13px] text-text-3", children: "No providers configured." })) }), delegationPolicy ? (_jsx(Disclosure, { label: "Child provider policy", children: _jsx(ChildProviderPolicy, { policy: delegationPolicy, onChange: (policy) => void updateDelegationPolicy(policy) }) })) : null] }));
191
+ }
192
+ function ProviderCard({ snapshot, pending, onAction, }) {
193
+ const display = getProviderDisplay(snapshot.providerId);
194
+ const badge = eligibilityBadgeFor(snapshot);
195
+ const reason = eligibilityReason(snapshot);
196
+ const status = snapshot.auth.launchReady
197
+ ? "Launch-ready"
198
+ : snapshot.auth.detectedSignedIn
199
+ ? `Signed in outside ${hostAppName()}`
200
+ : "No vendor sign-in detected";
201
+ const versionLabel = snapshot.attestation?.attestation.binaryVersion ?? "—";
202
+ const isolatedMode = snapshot.attestation?.attestation.isolationMode ?? display.isolationMode;
203
+ return (_jsxs("article", { className: `rounded-xl border p-4 ${snapshot.eligibility.kind === "ready" ? "border-accent/50 bg-panel" : "border-line/70 bg-panel/70"}`, "data-testid": `provider-card-${snapshot.providerId}`, children: [_jsxs("div", { className: "mb-3 flex items-start justify-between gap-3", children: [_jsxs("div", { className: "min-w-0", children: [_jsx("strong", { className: "text-[13px] font-semibold text-text", children: display.displayName }), _jsx("p", { className: "mt-0.5 truncate text-[12px] text-text-3", children: status }), snapshot.profile?.accountFingerprint ? (_jsxs("p", { className: "mt-0.5 text-[11px] font-mono text-text-3", children: ["fingerprint \u00B7 ", snapshot.profile.accountFingerprint] })) : null] }), _jsxs("div", { className: "flex flex-col items-end gap-1", children: [_jsx("span", { className: `rounded-full border px-2 py-0.5 text-[10px] font-semibold uppercase tracking-wide ${badge.tone}`, "data-testid": `provider-card-${snapshot.providerId}-eligibility`, children: badge.label }), _jsx("span", { className: "rounded-full border border-line-2 px-2 py-0.5 text-[10px] font-mono text-text-3", children: isolationLabelFor(isolatedMode) })] })] }), _jsxs("dl", { className: "mb-3 grid grid-cols-2 gap-x-4 gap-y-1 text-[12px]", children: [_jsx("dt", { className: "text-text-3", children: "Binary version" }), _jsx("dd", { className: "truncate font-mono text-text-2", children: versionLabel }), _jsx("dt", { className: "text-text-3", children: "Harness status" }), _jsx("dd", { className: "truncate text-text-2", children: snapshot.attestation
204
+ ? snapshot.attestation.qualified
205
+ ? `Verified ${snapshot.attestation.ageLabel ?? "recently"}`
206
+ : `Failed probes (${snapshot.attestation.attestation.failedProbes.length})`
207
+ : "Awaiting first attestation" })] }), reason ? (_jsx("p", { className: "mb-3 rounded-md border border-line-2 bg-bg/40 p-2 text-[12px] text-text-2", children: reason })) : null, _jsx("button", { className: snapshot.eligibility.kind === "ready"
208
+ ? "rounded-lg bg-accent px-3 py-2 text-[12px] font-semibold text-on-accent disabled:opacity-40"
209
+ : "rounded-lg border border-line px-3 py-2 text-[12px] font-semibold text-text-2 hover:bg-panel hover:text-text disabled:opacity-40", disabled: pending || !snapshot.binaryInstalled, onClick: () => onAction(snapshot.providerId, snapshot.auth.state === "unqualified" ? "verify-harness" : "login"), type: "button", "data-testid": `provider-card-${snapshot.providerId}-sign-in`, children: pending
210
+ ? "Working…"
211
+ : snapshot.auth.state === "unqualified"
212
+ ? "Verify harness"
213
+ : `Sign in with ${display.shortLabel}` })] }, snapshot.providerId));
214
+ }
@@ -0,0 +1,6 @@
1
+ import { type CliProviderId } from "@rightkit/agent-ui-core/lib/cliProviders";
2
+ export interface RepairTabProps {
3
+ providerId?: CliProviderId | null;
4
+ onCompleted?: (action: string) => void;
5
+ }
6
+ export default function RepairTab({ providerId, onCompleted }: RepairTabProps): import("react").JSX.Element;
@@ -0,0 +1,44 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useState } from "react";
3
+ import { invoke } from "@rightkit/agent-ui-core/host/tauriHost";
4
+ import { CLI_PROVIDER_IDS, getProviderDisplay, } from "@rightkit/agent-ui-core/lib/cliProviders";
5
+ const ACTIONS = [
6
+ {
7
+ id: "recover_binding",
8
+ label: "Recover binding",
9
+ description: "Restore the active provider binding without changing credentials.",
10
+ },
11
+ {
12
+ id: "re_qualify_harness",
13
+ label: "Re-qualify harness",
14
+ description: "Run the provider harness qualification probes again.",
15
+ },
16
+ {
17
+ id: "clear_active_binding",
18
+ label: "Clear active binding",
19
+ description: "Stop using the current provider binding for new work.",
20
+ },
21
+ ];
22
+ export default function RepairTab({ providerId, onCompleted }) {
23
+ const [pending, setPending] = useState(null);
24
+ const [message, setMessage] = useState(null);
25
+ const [error, setError] = useState(null);
26
+ const target = providerId ?? null;
27
+ const run = async (action) => {
28
+ setPending(action);
29
+ setMessage(null);
30
+ setError(null);
31
+ try {
32
+ await invoke(action, target ? { providerId: target } : undefined);
33
+ setMessage(`${ACTIONS.find((item) => item.id === action)?.label} completed.`);
34
+ onCompleted?.(action);
35
+ }
36
+ catch (reason) {
37
+ setError(reason instanceof Error ? reason.message : "The repair action is unavailable.");
38
+ }
39
+ finally {
40
+ setPending(null);
41
+ }
42
+ };
43
+ return (_jsxs("section", { className: "flex max-w-[720px] flex-col gap-4 p-6", "data-testid": "repair-tab", children: [_jsxs("header", { children: [_jsx("h3", { className: "text-[16px] font-bold text-text", children: "Continuity and repair" }), _jsxs("p", { className: "mt-1 text-[12px] text-text-3", children: ["Repair provider continuity without exposing or replacing vendor CLI credentials.", target ? ` Current provider: ${getProviderDisplay(target).displayName}.` : ""] })] }), message ? (_jsx("p", { className: "rounded-md border border-success/40 bg-success/10 p-2 text-[12px] text-success", children: message })) : null, error ? (_jsx("p", { className: "rounded-md border border-danger/40 bg-danger/10 p-2 text-[12px] text-danger", children: error })) : null, _jsx("div", { className: "flex flex-col gap-2", children: ACTIONS.map((item) => (_jsxs("article", { className: "flex items-center justify-between gap-4 rounded-xl border border-line bg-panel p-3", children: [_jsxs("div", { className: "min-w-0", children: [_jsx("strong", { className: "block text-[13px] text-text", children: item.label }), _jsx("p", { className: "text-[11px] text-text-3", children: item.description })] }), _jsx("button", { type: "button", onClick: () => void run(item.id), disabled: pending !== null, className: "shrink-0 rounded-md border border-line px-3 py-1.5 text-[12px] font-semibold text-text-2 hover:border-accent hover:text-text disabled:opacity-50", children: pending === item.id ? "Working…" : item.label })] }, item.id))) }), _jsxs("p", { className: "text-[11px] text-text-3", children: ["Supported providers:", " ", CLI_PROVIDER_IDS.map((id) => getProviderDisplay(id).shortLabel).join(", "), "."] })] }));
44
+ }
@@ -0,0 +1,10 @@
1
+ import type { CatalogGroup, InferenceSelection } from "@rightkit/agent-ui-core/lib/types/inference";
2
+ export interface RootModelPickerProps {
3
+ catalogGroups: CatalogGroup[];
4
+ value?: InferenceSelection | null;
5
+ onSelect: (selection: InferenceSelection) => void;
6
+ error?: string | null;
7
+ compact?: boolean;
8
+ }
9
+ /** Authority-first selector shared by Settings & composer. */
10
+ export default function RootModelPicker({ catalogGroups: allCatalogGroups, value, onSelect, error, compact, }: RootModelPickerProps): import("react").JSX.Element;
@@ -0,0 +1,42 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { inferenceSelectionKey, selectionForCatalogModel } from "@rightkit/agent-ui-core/lib/types/inference";
3
+ function modelSubtitle(group, model) {
4
+ if (group.authority === "direct") {
5
+ try {
6
+ return `${group.protocol.replace("_", " ")} · ${new URL(group.name).host}`;
7
+ }
8
+ catch {
9
+ return group.protocol.replace("_", " ");
10
+ }
11
+ }
12
+ const identity = [model.ownedBy, model.root, model.parent].filter(Boolean).join(" · ");
13
+ const limits = [
14
+ model.contextLength && `${model.contextLength.toLocaleString()} ctx`,
15
+ model.maxInputTokens && `${model.maxInputTokens.toLocaleString()} in`,
16
+ model.maxOutputTokens && `${model.maxOutputTokens.toLocaleString()} out`,
17
+ ]
18
+ .filter(Boolean)
19
+ .join(" · ");
20
+ return ([identity, model.capabilities.join(", "), limits]
21
+ .filter(Boolean)
22
+ .join(" · ") || "Direct catalog");
23
+ }
24
+ /** Authority-first selector shared by Settings & composer. */
25
+ export default function RootModelPicker({ catalogGroups: allCatalogGroups, value, onSelect, error, compact = false, }) {
26
+ // Settings saves an inference selection, which names an in-app connection; a config-route
27
+ // group (authority "config") is chosen on the session instead.
28
+ const catalogGroups = allCatalogGroups.filter((group) => group.authority !== "config");
29
+ const current = inferenceSelectionKey(value);
30
+ const valid = catalogGroups.some((group) => group.models.some((model) => inferenceSelectionKey(selectionForCatalogModel(group, model.id)) === current));
31
+ return (_jsxs("div", { className: "flex flex-col gap-3", "data-testid": "inference-picker", children: [error ? (_jsx("p", { className: "rounded-md border border-danger/40 bg-danger/10 p-2 text-[12px] text-danger", children: error })) : null, value && !valid ? (_jsx("p", { className: "rounded-md border border-warning/40 bg-warning/10 p-2 text-[12px] text-warning", "aria-live": "polite", children: "Saved selection is unavailable. Probe or repair its connection before choosing a replacement." })) : null, catalogGroups.map((group) => {
32
+ const models = group.models.filter((model) => !model.id.startsWith("auto/"));
33
+ if (models.length === 0)
34
+ return null;
35
+ return (_jsxs("section", { className: "rounded-lg border border-line bg-panel", "aria-label": `Direct Connections: ${group.name}`, children: [_jsxs("header", { className: "border-b border-line px-3 py-2", children: [_jsx("strong", { className: "block text-[12px] text-text", children: "Direct Connections" }), _jsxs("span", { className: "text-[11px] text-text-3", children: [group.name, " \u00B7 ", group.state.replaceAll("_", " ")] })] }), _jsx("ul", { className: compact ? "grid grid-cols-2 gap-1 p-1" : "flex flex-col gap-1 p-1", children: models.map((model) => {
36
+ const selection = selectionForCatalogModel(group, model.id);
37
+ const active = current === inferenceSelectionKey(selection);
38
+ const disabled = !model.selectable || group.state !== "ready";
39
+ return (_jsx("li", { children: _jsxs("button", { type: "button", "aria-pressed": active, disabled: disabled, onClick: () => onSelect(selection), className: `flex w-full items-center gap-2 rounded-md border px-2.5 py-2 text-left text-[12px] disabled:opacity-50 ${active ? "border-accent bg-panel-2" : "border-transparent hover:border-line hover:bg-panel-2"}`, children: [_jsxs("span", { className: "min-w-0 flex-1", children: [_jsx("strong", { className: "block truncate text-text", children: model.id }), _jsx("span", { className: "block truncate text-[11px] text-text-3", children: model.unavailableReason ?? modelSubtitle(group, model) })] }), active ? (_jsx("span", { "aria-hidden": "true", className: "text-accent", children: "\u2713" })) : null] }) }, model.id));
40
+ }) })] }, `${group.authority}:${group.connectionId}`));
41
+ }), catalogGroups.length === 0 ? (_jsx("p", { className: "text-[12px] text-text-3", children: "No Direct connections are ready. Add a connection to continue." })) : null] }));
42
+ }
@@ -0,0 +1,8 @@
1
+ import type { MiddlewareRegistrySnapshot } from "@rightkit/agent-ui-core/lib/types";
2
+ export default function RuntimeMiddlewareTab({ middlewareSnapshot, pendingId, error, onRefresh, onToggle, }: {
3
+ middlewareSnapshot: MiddlewareRegistrySnapshot;
4
+ pendingId: string | null;
5
+ error: string | null;
6
+ onRefresh: () => void;
7
+ onToggle: (id: string, enabled: boolean) => void;
8
+ }): import("react").JSX.Element;
@@ -0,0 +1,12 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import Icon from "@rightkit/agent-ui-core/components/Icon";
3
+ import { OfflinePanel } from "./shared.js";
4
+ function formatMiddlewarePhase(phase) {
5
+ return phase.replace(/([A-Z])/g, " $1").replace(/^./, (value) => value.toUpperCase());
6
+ }
7
+ function RuntimeMiddlewareStat({ label, value }) {
8
+ return (_jsxs("div", { className: "rounded-xl border border-line bg-panel p-3", children: [_jsx("span", { className: "block text-[11px] uppercase text-text-3", children: label }), _jsx("strong", { className: "mt-1 block text-[18px] text-text", children: value })] }));
9
+ }
10
+ export default function RuntimeMiddlewareTab({ middlewareSnapshot, pendingId, error, onRefresh, onToggle, }) {
11
+ return (_jsxs("section", { className: "flex flex-col gap-5 p-6", children: [_jsxs("div", { className: "flex items-start gap-3", children: [_jsxs("div", { className: "flex flex-col gap-1 flex-1 min-w-0", children: [_jsx("h3", { className: "text-[16px] font-bold text-text", children: "Runtime middleware" }), _jsx("p", { className: "text-[13px] text-text-2 truncate", children: "Inspect and enable local middleware that observes or gates runtime execution." })] }), _jsxs("button", { type: "button", className: "inline-flex items-center gap-2 h-9 px-4 rounded-lg border border-line bg-transparent text-text-2 text-[13px] cursor-pointer hover:bg-panel hover:text-text disabled:opacity-40", disabled: pendingId === "refresh", onClick: onRefresh, children: [_jsx(Icon, { name: "refresh" }), " ", pendingId === "refresh" ? "Refreshing" : "Refresh"] })] }), error ? _jsx(OfflinePanel, { title: "Runtime middleware unavailable.", action: error }) : null, _jsxs("div", { className: "grid grid-cols-3 gap-3", children: [_jsx(RuntimeMiddlewareStat, { label: "Middleware", value: middlewareSnapshot.middleware.length }), _jsx(RuntimeMiddlewareStat, { label: "Spans", value: middlewareSnapshot.spans.length }), _jsx(RuntimeMiddlewareStat, { label: "Observations", value: middlewareSnapshot.observations.length })] }), _jsx("div", { className: "flex flex-col divide-y divide-line rounded-xl border border-line overflow-hidden", children: middlewareSnapshot.middleware.length ? (middlewareSnapshot.middleware.map((definition) => (_jsxs("article", { className: "grid grid-cols-[minmax(0,1fr)_auto] gap-4 bg-panel px-4 py-3", children: [_jsxs("div", { className: "min-w-0", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx("strong", { className: "min-w-0 truncate text-[13px] font-semibold text-text", title: definition.title, children: definition.title }), _jsx("span", { className: "shrink-0 rounded border border-line bg-bg px-1.5 py-0.5 text-[10px] text-text-3", children: definition.enabled ? "enabled" : "disabled" })] }), _jsx("p", { className: "mt-1 line-clamp-2 text-[12px] leading-snug text-text-2", title: definition.description, children: definition.description }), _jsxs("div", { className: "mt-2 flex flex-wrap gap-2 text-[11px] text-text-3", children: [_jsxs("code", { className: "rounded border border-line bg-bg px-1.5 py-0.5", children: ["phase ", formatMiddlewarePhase(definition.phase)] }), _jsxs("code", { className: "rounded border border-line bg-bg px-1.5 py-0.5", children: ["effect ", definition.effect] }), _jsxs("code", { className: "rounded border border-line bg-bg px-1.5 py-0.5", children: ["source ", definition.source] }), definition.tool ? (_jsxs("code", { className: "min-w-0 max-w-full truncate rounded border border-line bg-bg px-1.5 py-0.5", title: `tool ${definition.tool}`, children: ["tool ", definition.tool] })) : null, definition.requiresToolset ? (_jsxs("code", { className: "min-w-0 max-w-full truncate rounded border border-line bg-bg px-1.5 py-0.5", title: `toolset ${definition.requiresToolset}`, children: ["toolset ", definition.requiresToolset] })) : null] })] }), _jsx("button", { type: "button", className: "inline-flex items-center justify-center h-8 min-w-[86px] px-3 rounded-lg border border-line bg-transparent text-text-2 text-[12px] cursor-pointer hover:bg-bg hover:text-text disabled:opacity-40", disabled: pendingId === definition.id || pendingId === "refresh", onClick: () => onToggle(definition.id, !definition.enabled), children: pendingId === definition.id ? "Saving" : definition.enabled ? "Disable" : "Enable" })] }, definition.id)))) : (_jsx(OfflinePanel, { title: "No middleware registered.", action: "Refresh after the runtime starts to inspect built-in and plugin middleware." })) })] }));
12
+ }
@@ -0,0 +1,6 @@
1
+ import type { SettingsConfigStatus } from "@rightkit/agent-ui-core/lib/types";
2
+ export default function WorkspaceTab({ workspaceRoot, settingsConfigStatus, onOpenWorkspace, }: {
3
+ workspaceRoot: string;
4
+ settingsConfigStatus: SettingsConfigStatus | null;
5
+ onOpenWorkspace: () => void;
6
+ }): import("react").JSX.Element;
@@ -0,0 +1,9 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import Icon from "@rightkit/agent-ui-core/components/Icon";
3
+ import { hostAppName } from "../../../appName.js";
4
+ export default function WorkspaceTab({ workspaceRoot, settingsConfigStatus, onOpenWorkspace, }) {
5
+ const hasWorkspace = workspaceRoot.trim().length > 0;
6
+ return (_jsxs("section", { className: "flex flex-col gap-5 p-6", children: [_jsxs("div", { className: "flex flex-col gap-1", children: [_jsx("h3", { className: "text-[16px] font-bold text-text", children: "Workspace" }), _jsxs("p", { className: "text-[13px] text-text-2", children: [hostAppName(), " should always make the active folder, repo mode, and state storage obvious."] })] }), !hasWorkspace ? (_jsx("div", { className: "cr-panel-reveal max-w-[720px] rounded-xl border border-[color-mix(in_srgb,var(--color-accent)_28%,var(--color-line))] bg-panel px-4 py-4", children: _jsxs("div", { className: "flex items-start gap-3", children: [_jsx("span", { className: "grid h-9 w-9 flex-shrink-0 place-items-center rounded-lg border border-[color-mix(in_srgb,var(--color-accent)_35%,var(--color-line))] bg-[color-mix(in_srgb,var(--color-accent)_8%,transparent)] text-accent", children: _jsx(Icon, { name: "folder", size: 15 }) }), _jsxs("div", { className: "min-w-0 flex-1", children: [_jsxs("strong", { className: "block text-[14px] font-semibold text-text", children: ["Open a workspace to activate ", hostAppName()] }), _jsxs("p", { className: "mt-1 max-w-[560px] text-[13px] leading-[1.5] text-text-2", children: ["Settings, model roles, skills, permissions, and transcript state attach to the active repo. Start by choosing the local folder ", hostAppName(), " should work in."] }), _jsxs("button", { type: "button", className: "cr-control-pill mt-3 inline-flex h-9 items-center gap-2 rounded-lg border-0 bg-accent px-4 text-[13px] font-semibold text-on-accent hover:opacity-90", onClick: onOpenWorkspace, children: [_jsx(Icon, { name: "folder", size: 14 }), " Open local folder"] })] })] }) })) : null, _jsxs("div", { className: "flex flex-col gap-3 max-w-[560px]", children: [_jsxs("div", { className: "flex items-center gap-4 px-4 py-3 rounded-xl border border-line bg-panel", children: [_jsx("span", { className: "text-[12px] text-text-3 w-24 flex-shrink-0", children: "Active folder" }), _jsx("strong", { className: "text-[13px] font-medium text-text truncate", children: workspaceRoot || "None selected" })] }), _jsxs("div", { className: "flex items-center gap-4 px-4 py-3 rounded-xl border border-line bg-panel", children: [_jsx("span", { className: "text-[12px] text-text-3 w-24 flex-shrink-0", children: "State file" }), _jsx("strong", { className: "text-[13px] font-medium text-text truncate", children: workspaceRoot ? `${workspaceRoot}/.coderight/config.toml` : "Select a workspace first" })] }), hasWorkspace ? (_jsxs("button", { type: "button", className: "cr-control-pill inline-flex h-9 items-center gap-2 rounded-lg border border-line bg-transparent px-4 text-[13px] text-text-2 cursor-pointer hover:bg-panel hover:text-text self-start", onClick: onOpenWorkspace, children: [_jsx(Icon, { name: "folder" }), " Change workspace"] })) : null] }), _jsxs("div", { className: "flex flex-col gap-3 max-w-[720px]", children: [_jsxs("div", { className: "flex items-center justify-between gap-3", children: [_jsx("h4", { className: "text-[13px] font-semibold text-text", children: "Config files" }), settingsConfigStatus ? (_jsx("span", { className: "text-[11px] text-text-3 truncate", children: settingsConfigStatus.fingerprint.slice(0, 19) })) : null] }), _jsxs("div", { className: "rounded-xl border border-line bg-panel overflow-hidden", children: [(settingsConfigStatus?.files ?? []).map((file) => (_jsxs("div", { className: "grid grid-cols-[88px_72px_1fr] gap-3 px-4 py-3 border-b border-line last:border-b-0 items-center", children: [_jsx("span", { className: "text-[12px] text-text-3 capitalize", children: file.scope }), _jsx("span", { className: `justify-self-start px-2 py-0.5 rounded-full text-[11px] border ${file.exists
7
+ ? "text-accent-2 border-accent-2/40 bg-accent-2/10"
8
+ : "text-text-3 border-line bg-panel-2"}`, children: file.exists ? "Loaded" : "Missing" }), _jsx("span", { className: "text-[12px] text-text-2 truncate", children: file.path })] }, `${file.scope}:${file.path}`))), !settingsConfigStatus ? (_jsx("div", { className: "px-4 py-3 text-[12px] text-text-3", children: "Config metadata loads with settings." })) : null] })] })] }));
9
+ }
@@ -0,0 +1,9 @@
1
+ import type { CoreSandboxSettings, CoreSandboxTier, DiagnosticsReport } from "@rightkit/agent-ui-core/lib/types";
2
+ interface CoreSandboxTierPanelProps {
3
+ report: DiagnosticsReport | null;
4
+ settings: CoreSandboxSettings | null;
5
+ pending: boolean;
6
+ onSaveTier: (tier: CoreSandboxTier) => void;
7
+ }
8
+ export declare function CoreSandboxTierPanel({ report, settings, pending, onSaveTier, }: CoreSandboxTierPanelProps): import("react").JSX.Element;
9
+ export {};
@@ -0,0 +1,43 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Select } from "@rightkit/react-shell/react";
3
+ import { useEffect, useState } from "react";
4
+ import { hostOption } from "../../../../appName.js";
5
+ import Icon from "@rightkit/agent-ui-core/components/Icon";
6
+ import { diagnosticsLabel, diagnosticsStatusClass } from "../shared.js";
7
+ import { RemoteStatusCard } from "./RemoteStatusCard.js";
8
+ const CORE_SANDBOX_TIERS = [
9
+ {
10
+ value: "landlock-seccomp",
11
+ label: "Landlock + seccomp",
12
+ detail: "Default local shell filesystem and syscall guard where Linux supports it.",
13
+ },
14
+ {
15
+ value: "landlock",
16
+ label: "Landlock",
17
+ detail: "Filesystem guard only; useful when syscall filtering needs to stay off.",
18
+ },
19
+ {
20
+ value: "none",
21
+ label: "Disabled",
22
+ detail: "Trusted workloads only; diagnostics will warn on this setting.",
23
+ },
24
+ ];
25
+ export function CoreSandboxTierPanel({ report, settings, pending, onSaveTier, }) {
26
+ const sandboxCheck = report?.checks.find((check) => check.id === "core_sandbox");
27
+ const [draftTier, setDraftTier] = useState(settings?.workspaceTier ?? settings?.tier ?? "landlock-seccomp");
28
+ const persistedWorkspaceTier = settings?.workspaceTier ?? settings?.tier;
29
+ useEffect(() => {
30
+ if (persistedWorkspaceTier) {
31
+ setDraftTier(persistedWorkspaceTier);
32
+ }
33
+ }, [persistedWorkspaceTier]);
34
+ const selectedTier = CORE_SANDBOX_TIERS.find((option) => option.value === draftTier);
35
+ const savedWorkspaceTier = persistedWorkspaceTier;
36
+ const tierDirty = settings ? draftTier !== savedWorkspaceTier : draftTier !== "landlock-seccomp";
37
+ return (_jsxs("section", { className: "grid grid-cols-1 gap-3 rounded-xl border border-line bg-panel p-4 max-w-[980px]", children: [_jsxs("div", { className: "flex items-start justify-between gap-3", children: [_jsxs("div", { className: "min-w-0", children: [_jsx("h4", { className: "text-[13px] font-semibold text-text", children: "Core tool sandbox" }), _jsxs("p", { className: "mt-1 text-[12px] text-text-3", children: [hostOption("sandboxTierEnv"), " is the operator minimum; a workspace may only tighten it."] })] }), sandboxCheck ? (_jsx("span", { className: `shrink-0 px-2 py-0.5 rounded-full border text-[11px] ${diagnosticsStatusClass(sandboxCheck.status)}`, children: diagnosticsLabel(sandboxCheck.status) })) : (_jsx("span", { className: "shrink-0 px-2 py-0.5 rounded-full border border-line text-[11px] text-text-3", children: "Not loaded" }))] }), _jsxs("div", { className: "grid gap-3 md:grid-cols-[minmax(0,1fr)_auto] items-end", children: [_jsxs("label", { className: "flex flex-col gap-1 min-w-0", children: [_jsx("span", { className: "text-[10px] uppercase tracking-[0.08em] text-text-3", children: "Sandbox tier" }), _jsx(Select, { value: draftTier, options: [...CORE_SANDBOX_TIERS.map((option) => ({ value: option.value, label: option.label }))], onChange: (value) => setDraftTier(value), label: "Sandbox tier", className: "h-9 min-w-0 rounded-lg border border-line bg-panel-2 px-2 text-[13px] text-text outline-none focus:border-accent/60" }), _jsx("span", { className: "text-[11px] text-text-3", children: selectedTier?.detail ?? "Choose how local shell commands request isolation." })] }), _jsxs("button", { type: "button", className: "inline-flex items-center justify-center gap-2 h-9 px-4 rounded-lg border border-line bg-transparent text-text-2 text-[13px] cursor-pointer hover:bg-panel-2 hover:text-text disabled:opacity-40 whitespace-nowrap", disabled: pending || !tierDirty, onClick: () => onSaveTier(draftTier), children: [_jsx(Icon, { name: "check" }), pending ? "Saving tier" : "Save tier"] })] }), _jsxs("div", { className: "grid gap-2 md:grid-cols-4", children: [_jsx(RemoteStatusCard, { title: "Saved tier", value: sandboxTierLabel(savedWorkspaceTier), status: sandboxCheck?.status ?? "warn", detail: settings
38
+ ? `effective ${sandboxTierLabel(settings.tier)} · ${settings.source} · ${settings.storePath}`
39
+ : "Load execution settings to inspect the saved workspace tier." }), _jsx(RemoteStatusCard, { title: "Mode", value: "Local OS", status: sandboxCheck?.status ?? "warn", detail: "Linux hosts use Landlock/seccomp where available; non-Linux hosts report an honest warning." }), _jsx(RemoteStatusCard, { title: "Current", value: sandboxCheck ? diagnosticsLabel(sandboxCheck.status) : "Not loaded", status: sandboxCheck?.status ?? "warn", detail: sandboxCheck?.detail ?? "Refresh diagnostics to inspect core sandbox posture." }), _jsx(RemoteStatusCard, { title: "Fix", value: sandboxCheck?.fix ? "Action available" : "No action", status: sandboxCheck?.status ?? "pass", detail: sandboxCheck?.fix || "Sandbox posture is explicit for this daemon." })] })] }));
40
+ }
41
+ function sandboxTierLabel(tier) {
42
+ return CORE_SANDBOX_TIERS.find((option) => option.value === tier)?.label ?? "Not saved";
43
+ }
@@ -0,0 +1,20 @@
1
+ import type { BackendDoctorReport, ExecutionBackendConfig, ExecutionNetworkProfile } from "@rightkit/agent-ui-core/lib/types";
2
+ import type { NetworkProfileChange, ResourceLimitsChange } from "./types.js";
3
+ interface ExecutionBackendCardProps {
4
+ backend: ExecutionBackendConfig;
5
+ isDefault: boolean;
6
+ doctorReport?: BackendDoctorReport;
7
+ doctorPending: boolean;
8
+ defaultPending: boolean;
9
+ enabledPending: boolean;
10
+ limitsPending: boolean;
11
+ networkPending: boolean;
12
+ networkProfiles: ExecutionNetworkProfile[];
13
+ onDoctor: () => void;
14
+ onSetDefault: () => void;
15
+ onSetEnabled: () => void;
16
+ onSaveResourceLimits: ResourceLimitsChange;
17
+ onSaveNetworkProfile: NetworkProfileChange;
18
+ }
19
+ export declare function ExecutionBackendCard({ backend, isDefault, doctorReport, doctorPending, defaultPending, enabledPending, limitsPending, networkPending, networkProfiles, onDoctor, onSetDefault, onSetEnabled, onSaveResourceLimits, onSaveNetworkProfile, }: ExecutionBackendCardProps): import("react").JSX.Element;
20
+ export {};
@@ -0,0 +1,48 @@
1
+ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Select } from "@rightkit/react-shell/react";
3
+ import { useState } from "react";
4
+ import Icon from "@rightkit/agent-ui-core/components/Icon";
5
+ import { ExecutionBackendLimitsForm } from "./ExecutionBackendLimitsForm.js";
6
+ export function ExecutionBackendCard({ backend, isDefault, doctorReport, doctorPending, defaultPending, enabledPending, limitsPending, networkPending, networkProfiles, onDoctor, onSetDefault, onSetEnabled, onSaveResourceLimits, onSaveNetworkProfile, }) {
7
+ const [resourceDraft, setResourceDraft] = useState(() => initialResourceDraft(backend));
8
+ const [networkDraft, setNetworkDraft] = useState(backend.networkProfile ?? "");
9
+ const verdict = doctorReport?.verdict ?? (backend.enabled ? "warn" : "block");
10
+ const networkDirty = networkDraft !== (backend.networkProfile ?? "");
11
+ return (_jsxs("article", { className: "grid grid-cols-[minmax(0,1.1fr)_minmax(0,1.4fr)_minmax(0,1.2fr)_auto] gap-4 px-4 py-4", children: [_jsxs("div", { className: "flex flex-col gap-2 min-w-0", children: [_jsx(BackendIdentity, { backend: backend, isDefault: isDefault }), _jsx("span", { className: "text-[12px] text-text-3 break-all", children: backend.workspaceLayout.root })] }), _jsx(ExecutionBackendLimitsForm, { backend: backend, draft: resourceDraft, pending: limitsPending, onDraftChange: (update) => setResourceDraft((current) => update(current)), onSave: onSaveResourceLimits }), _jsx(DoctorPanel, { backend: backend, doctorReport: doctorReport, verdict: verdict, networkDraft: networkDraft, networkProfiles: networkProfiles, networkDirty: networkDirty, networkPending: networkPending, onNetworkDraftChange: setNetworkDraft, onSaveNetworkProfile: onSaveNetworkProfile }), _jsx(BackendActions, { backend: backend, isDefault: isDefault, doctorPending: doctorPending, defaultPending: defaultPending, enabledPending: enabledPending, onDoctor: onDoctor, onSetDefault: onSetDefault, onSetEnabled: onSetEnabled })] }));
12
+ }
13
+ function BackendIdentity({ backend, isDefault, }) {
14
+ return (_jsxs(_Fragment, { children: [_jsxs("div", { className: "flex items-center gap-2 min-w-0", children: [_jsx("strong", { className: "text-[13px] text-text truncate", children: backend.name }), isDefault ? (_jsx("span", { className: "px-2 py-0.5 rounded-full border border-accent-2/40 text-accent-2 text-[11px]", children: "default" })) : null, _jsx("span", { className: `px-2 py-0.5 rounded-full border text-[11px] ${backend.enabled ? "border-accent-2/40 text-accent-2" : "border-danger/40 text-danger"}`, children: backend.enabled ? "enabled" : "disabled" })] }), _jsxs("span", { className: "text-[12px] text-text-3 truncate", children: [backend.kind, " \u00B7 ", backend.id] })] }));
15
+ }
16
+ function DoctorPanel({ backend, doctorReport, verdict, networkDraft, networkProfiles, networkDirty, networkPending, onNetworkDraftChange, onSaveNetworkProfile, }) {
17
+ return (_jsxs("div", { className: "flex flex-col gap-2 min-w-0", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx("span", { className: "text-[11px] uppercase tracking-[0.08em] text-text-3", children: "Doctor" }), _jsx("span", { className: `px-2 py-0.5 rounded-full border text-[11px] ${executionVerdictClass(verdict)}`, children: doctorReport ? verdictLabel(doctorReport.verdict) : "Not run" })] }), _jsxs("span", { className: "text-[12px] text-text-3 truncate", children: ["Network: ", backend.networkProfile || "none"] }), _jsxs("div", { className: "grid grid-cols-[minmax(0,1fr)_auto] gap-2", children: [_jsxs("label", { className: "flex flex-col gap-1 min-w-0", children: [_jsx("span", { className: "text-[10px] uppercase tracking-[0.08em] text-text-3", children: "Profile" }), _jsx(Select, { value: networkDraft, options: [{ value: "", label: "None" }, ...networkProfiles.map((profile) => ({ value: profile.id, label: profile.name }))], onChange: (value) => onNetworkDraftChange(value), label: "Profile", className: "h-8 min-w-0 rounded-lg border border-line bg-panel px-2 text-[12px] text-text outline-none focus:border-accent/60" })] }), _jsxs("button", { type: "button", className: "self-end inline-flex items-center justify-center gap-2 h-8 px-3 rounded-lg border border-line bg-transparent text-text-2 text-[13px] cursor-pointer hover:bg-panel hover:text-text disabled:opacity-40 whitespace-nowrap", disabled: !networkDirty || networkPending, onClick: () => onSaveNetworkProfile(networkDraft.trim() || null), children: [_jsx(Icon, { name: "check" }), networkPending ? "Saving" : "Apply"] })] }), doctorReport ? (_jsx("div", { className: "flex flex-col gap-1", children: doctorReport.checks.slice(0, 3).map((check) => (_jsxs("span", { className: "text-[12px] text-text-2 truncate", children: [verdictLabel(check.verdict), " \u00B7 ", check.label] }, check.id))) })) : (_jsx("span", { className: "text-[12px] text-text-3", children: "Run doctor before selecting this for real work." }))] }));
18
+ }
19
+ function BackendActions({ backend, isDefault, doctorPending, defaultPending, enabledPending, onDoctor, onSetDefault, onSetEnabled, }) {
20
+ return (_jsxs("div", { className: "flex flex-col items-stretch gap-2", children: [_jsx(ActionButton, { disabled: isDefault || enabledPending, onClick: onSetEnabled, icon: backend.enabled ? "pause" : "play", pending: enabledPending, savingLabel: "Saving", idleLabel: backend.enabled ? "Disable" : "Enable" }), _jsx(ActionButton, { disabled: isDefault || !backend.enabled || defaultPending, onClick: onSetDefault, icon: "check", pending: defaultPending, savingLabel: "Setting", idleLabel: "Set default" }), _jsx(ActionButton, { disabled: doctorPending, onClick: onDoctor, icon: "activity", pending: doctorPending, savingLabel: "Checking", idleLabel: "Run doctor" })] }));
21
+ }
22
+ function ActionButton({ disabled, onClick, icon, pending, savingLabel, idleLabel, }) {
23
+ return (_jsxs("button", { type: "button", className: "inline-flex items-center justify-center gap-2 h-8 px-3 rounded-lg border border-line bg-transparent text-text-2 text-[13px] cursor-pointer hover:bg-panel hover:text-text disabled:opacity-40 whitespace-nowrap", disabled: disabled, onClick: onClick, children: [_jsx(Icon, { name: icon }), pending ? savingLabel : idleLabel] }));
24
+ }
25
+ function initialResourceDraft(backend) {
26
+ return {
27
+ cpu: formatLimitInput(backend.resourceLimits.cpu),
28
+ memoryMb: formatLimitInput(backend.resourceLimits.memoryMb),
29
+ diskMb: formatLimitInput(backend.resourceLimits.diskMb),
30
+ };
31
+ }
32
+ function formatLimitInput(value) {
33
+ return value ? String(value) : "";
34
+ }
35
+ function executionVerdictClass(status) {
36
+ if (status === "pass")
37
+ return "border-accent-2/40 text-accent-2";
38
+ if (status === "warn")
39
+ return "border-accent/40 text-accent";
40
+ return "border-danger/40 text-danger";
41
+ }
42
+ function verdictLabel(verdict) {
43
+ if (verdict === "pass")
44
+ return "Pass";
45
+ if (verdict === "warn")
46
+ return "Warn";
47
+ return "Block";
48
+ }
@@ -0,0 +1,10 @@
1
+ import type { ResourceLimitsDraft, ResourceLimitsChange, ExecutionBackendConfig } from "./types.js";
2
+ interface ExecutionBackendLimitsFormProps {
3
+ backend: ExecutionBackendConfig;
4
+ draft: ResourceLimitsDraft;
5
+ pending: boolean;
6
+ onDraftChange: (update: (draft: ResourceLimitsDraft) => ResourceLimitsDraft) => void;
7
+ onSave: ResourceLimitsChange;
8
+ }
9
+ export declare function ExecutionBackendLimitsForm({ backend, draft, pending, onDraftChange, onSave, }: ExecutionBackendLimitsFormProps): import("react").JSX.Element;
10
+ export {};
@@ -0,0 +1,62 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { ResourceLimitInput } from "./TextSettingInput.js";
3
+ import Icon from "@rightkit/agent-ui-core/components/Icon";
4
+ export function ExecutionBackendLimitsForm({ backend, draft, pending, onDraftChange, onSave, }) {
5
+ const baseline = resourceLimitsDraft(backend);
6
+ const dirty = draft.cpu !== baseline.cpu ||
7
+ draft.memoryMb !== baseline.memoryMb ||
8
+ draft.diskMb !== baseline.diskMb;
9
+ const valid = resourceDraftValid(draft);
10
+ const formatted = formatResourceLimits(backend);
11
+ return (_jsxs("div", { className: "flex flex-col gap-2 min-w-0", children: [_jsx("span", { className: "text-[11px] uppercase tracking-[0.08em] text-text-3", children: "Capabilities" }), _jsx(CapabilitiesList, { backend: backend }), _jsxs("span", { className: "text-[12px] text-text-3", children: ["Resources: ", formatted] }), _jsxs("div", { className: "grid grid-cols-3 gap-2", children: [_jsx(ResourceLimitInput, { label: "CPU", value: draft.cpu, onChange: (cpu) => onDraftChange((current) => ({ ...current, cpu })) }), _jsx(ResourceLimitInput, { label: "RAM MB", value: draft.memoryMb, onChange: (memoryMb) => onDraftChange((current) => ({ ...current, memoryMb })) }), _jsx(ResourceLimitInput, { label: "Disk MB", value: draft.diskMb, onChange: (diskMb) => onDraftChange((current) => ({ ...current, diskMb })) })] }), _jsxs("button", { type: "button", className: "inline-flex items-center justify-center gap-2 h-8 px-3 rounded-lg border border-line bg-transparent text-text-2 text-[13px] cursor-pointer hover:bg-panel hover:text-text disabled:opacity-40 whitespace-nowrap", disabled: !dirty || pending || !valid, onClick: () => onSave(parseResourceLimitsDraft(draft)), children: [_jsx(Icon, { name: "check" }), pending ? "Saving caps" : "Apply caps"] })] }));
12
+ }
13
+ function CapabilitiesList({ backend }) {
14
+ const labels = Object.entries(backend.supports)
15
+ .filter(([, enabled]) => enabled)
16
+ .map(([name]) => capabilityLabel(name));
17
+ if (labels.length === 0) {
18
+ return _jsx("span", { className: "text-[12px] text-text-3", children: "No live controls advertised" });
19
+ }
20
+ return (_jsx("div", { className: "flex flex-wrap gap-1.5", children: labels.map((label) => (_jsx("span", { className: "px-2 py-0.5 rounded-full border border-line bg-panel text-[11px] text-text-2", children: label }, label))) }));
21
+ }
22
+ function capabilityLabel(value) {
23
+ return value.replace(/([A-Z])/g, " $1").replace(/^./, (match) => match.toUpperCase());
24
+ }
25
+ function resourceLimitsDraft(backend) {
26
+ return {
27
+ cpu: formatLimitInput(backend.resourceLimits.cpu),
28
+ memoryMb: formatLimitInput(backend.resourceLimits.memoryMb),
29
+ diskMb: formatLimitInput(backend.resourceLimits.diskMb),
30
+ };
31
+ }
32
+ function formatLimitInput(value) {
33
+ return value ? String(value) : "";
34
+ }
35
+ function resourceDraftValid(draft) {
36
+ return [draft.cpu, draft.memoryMb, draft.diskMb].every((value) => {
37
+ if (!value.trim())
38
+ return true;
39
+ const parsed = Number(value);
40
+ return Number.isInteger(parsed) && parsed > 0;
41
+ });
42
+ }
43
+ function parseResourceLimitsDraft(draft) {
44
+ return {
45
+ cpu: parseOptionalPositiveInt(draft.cpu),
46
+ memoryMb: parseOptionalPositiveInt(draft.memoryMb),
47
+ diskMb: parseOptionalPositiveInt(draft.diskMb),
48
+ };
49
+ }
50
+ function parseOptionalPositiveInt(value) {
51
+ const trimmed = value.trim();
52
+ return trimmed ? Number(trimmed) : null;
53
+ }
54
+ function formatResourceLimits(backend) {
55
+ const limits = backend.resourceLimits;
56
+ const parts = [
57
+ limits.cpu ? `${limits.cpu} CPU` : null,
58
+ limits.memoryMb ? `${limits.memoryMb} MB RAM` : null,
59
+ limits.diskMb ? `${limits.diskMb} MB disk` : null,
60
+ ].filter(Boolean);
61
+ return parts.length ? parts.join(" · ") : "not capped";
62
+ }