@omercnet/paseo-context-mode 3.1.3 → 3.1.4-next.434.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.
- package/OVERVIEW.md +3 -3
- package/README.md +13 -15
- package/client/analytics-dashboard.tsx +745 -613
- package/client/controls.tsx +295 -0
- package/client/diagnostics-section.tsx +178 -0
- package/client/{context-mode-footer.tsx → footer.tsx} +22 -20
- package/client/knowledge-section.tsx +725 -697
- package/client/{context-mode-pill.tsx → pill.tsx} +5 -5
- package/client/scoped-knowledge-section.tsx +14 -20
- package/client/screen-scope.ts +12 -6
- package/client/settings-screen.tsx +94 -97
- package/client/surface.tsx +377 -0
- package/index.client.tsx +3 -3
- package/index.server.ts +18 -27
- package/npm-shrinkwrap.json +8 -1747
- package/package.json +7 -7
- package/server/actions.ts +91 -102
- package/server/analytics.ts +257 -308
- package/server/binary.ts +119 -94
- package/server/database.ts +463 -0
- package/server/handlers.ts +40 -95
- package/server/integration.ts +230 -361
- package/server/knowledge.ts +65 -137
- package/server/mcp-process.ts +135 -86
- package/server/storage-discovery.ts +46 -199
- package/shared/actions.ts +2 -27
- package/shared/analytics.ts +60 -33
- package/shared/contracts.ts +16 -47
- package/shared/knowledge.ts +62 -65
- package/shared/providers.ts +62 -0
- package/shared/settings.ts +33 -18
- package/client/actions-section.tsx +0 -621
- package/client/context-mode-surface.tsx +0 -444
- package/server/context-mode-db.ts +0 -481
- package/shared/index.ts +0 -5
|
@@ -1,444 +0,0 @@
|
|
|
1
|
-
import { type PluginSurfaceProps, useRpc, useSettings } from "@getpaseo/plugin/client";
|
|
2
|
-
import { Icon } from "@getpaseo/plugin/client/react-native";
|
|
3
|
-
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
|
4
|
-
import { useEffect, useMemo, useState } from "react";
|
|
5
|
-
import { ActivityIndicator, Pressable, ScrollView, Text, View } from "react-native";
|
|
6
|
-
import {
|
|
7
|
-
type BinaryStatus,
|
|
8
|
-
contextModeSettings,
|
|
9
|
-
getContextModeIntegrationAudit,
|
|
10
|
-
getContextModeStats,
|
|
11
|
-
getContextModeStatus,
|
|
12
|
-
type IntegrationAudit,
|
|
13
|
-
} from "../shared";
|
|
14
|
-
import { ActionsSection } from "./actions-section";
|
|
15
|
-
import { AnalyticsDashboard } from "./analytics-dashboard";
|
|
16
|
-
import { BUILTIN_KNOWLEDGE_PROVIDERS, KnowledgeSection } from "./knowledge-section";
|
|
17
|
-
import { ScopedKnowledgeSection } from "./scoped-knowledge-section";
|
|
18
|
-
import { parseScreenParams, type SurfaceTab } from "./screen-scope";
|
|
19
|
-
|
|
20
|
-
interface ContextModeSurfaceProps extends PluginSurfaceProps {
|
|
21
|
-
onOpenSettings(): void;
|
|
22
|
-
params?: Record<string, string>;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
function statusLabel(status: BinaryStatus): string {
|
|
26
|
-
if (status.state === "ready") return "Connected";
|
|
27
|
-
if (status.code === "not-installed") return "Not installed";
|
|
28
|
-
if (status.code === "unsupported") return "Unsupported";
|
|
29
|
-
return "Unavailable";
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
const SURFACE_TABS: ReadonlyArray<{ id: SurfaceTab; label: string }> = [
|
|
33
|
-
{ id: "savings", label: "Savings" },
|
|
34
|
-
{ id: "knowledge", label: "Knowledge" },
|
|
35
|
-
{ id: "setup", label: "Setup" },
|
|
36
|
-
];
|
|
37
|
-
|
|
38
|
-
export function ContextModeSurface({
|
|
39
|
-
theme,
|
|
40
|
-
host,
|
|
41
|
-
layout,
|
|
42
|
-
onOpenSettings,
|
|
43
|
-
params,
|
|
44
|
-
}: ContextModeSurfaceProps) {
|
|
45
|
-
const settings = useSettings(contextModeSettings);
|
|
46
|
-
const loadStatus = useRpc(getContextModeStatus);
|
|
47
|
-
const loadStats = useRpc(getContextModeStats);
|
|
48
|
-
const loadIntegrationAudit = useRpc(getContextModeIntegrationAudit);
|
|
49
|
-
const queryClient = useQueryClient();
|
|
50
|
-
const screenParams = parseScreenParams(params ?? {});
|
|
51
|
-
const [activeTab, setActiveTab] = useState<SurfaceTab>(screenParams.section);
|
|
52
|
-
useEffect(
|
|
53
|
-
() => setActiveTab(screenParams.section),
|
|
54
|
-
[screenParams.section, screenParams.agentId, screenParams.workspaceId],
|
|
55
|
-
);
|
|
56
|
-
const readySettings = settings.status === "ready" ? settings : null;
|
|
57
|
-
const refreshInterval = readySettings?.values.refreshIntervalMs ?? 15_000;
|
|
58
|
-
const statusKey = ["context-mode", host.id, "status"] as const;
|
|
59
|
-
const statsKey = ["context-mode", host.id, "stats"] as const;
|
|
60
|
-
const integrationKey = ["context-mode", host.id, "integration"] as const;
|
|
61
|
-
const status = useQuery({
|
|
62
|
-
queryKey: statusKey,
|
|
63
|
-
queryFn: () => loadStatus({ fresh: false }),
|
|
64
|
-
refetchInterval: refreshInterval,
|
|
65
|
-
enabled: readySettings !== null,
|
|
66
|
-
});
|
|
67
|
-
const stats = useQuery({
|
|
68
|
-
queryKey: statsKey,
|
|
69
|
-
queryFn: () => loadStats({ fresh: false }),
|
|
70
|
-
refetchInterval: refreshInterval,
|
|
71
|
-
enabled: readySettings !== null && status.data?.state === "ready",
|
|
72
|
-
});
|
|
73
|
-
const integration = useQuery({
|
|
74
|
-
queryKey: integrationKey,
|
|
75
|
-
queryFn: () => loadIntegrationAudit({ fresh: false }),
|
|
76
|
-
refetchInterval: refreshInterval,
|
|
77
|
-
enabled: readySettings !== null,
|
|
78
|
-
});
|
|
79
|
-
const auditedProviders = integration.data?.providers.map(({ provider }) => provider) ?? [];
|
|
80
|
-
const knowledgeProviders = auditedProviders.length
|
|
81
|
-
? auditedProviders
|
|
82
|
-
: BUILTIN_KNOWLEDGE_PROVIDERS;
|
|
83
|
-
const refresh = useMutation({
|
|
84
|
-
mutationFn: async () => {
|
|
85
|
-
const nextStatus = await loadStatus({ fresh: true });
|
|
86
|
-
const nextIntegration = await loadIntegrationAudit({ fresh: true });
|
|
87
|
-
const nextStats =
|
|
88
|
-
nextStatus.state === "ready" && nextStatus.supportsStats
|
|
89
|
-
? await loadStats({ fresh: true })
|
|
90
|
-
: undefined;
|
|
91
|
-
return { nextStatus, nextIntegration, nextStats };
|
|
92
|
-
},
|
|
93
|
-
onSuccess({ nextStatus, nextIntegration, nextStats }) {
|
|
94
|
-
queryClient.setQueryData(statusKey, nextStatus);
|
|
95
|
-
queryClient.setQueryData(integrationKey, nextIntegration);
|
|
96
|
-
if (nextStats) queryClient.setQueryData(statsKey, nextStats);
|
|
97
|
-
void queryClient.invalidateQueries({
|
|
98
|
-
queryKey: ["context-mode", host.id, "analytics-dashboard"],
|
|
99
|
-
});
|
|
100
|
-
},
|
|
101
|
-
});
|
|
102
|
-
const styles = useMemo(
|
|
103
|
-
() => ({
|
|
104
|
-
screen: {
|
|
105
|
-
flex: 1,
|
|
106
|
-
backgroundColor: theme.colors.surface0,
|
|
107
|
-
},
|
|
108
|
-
content: {
|
|
109
|
-
padding: layout.compact ? 14 : 24,
|
|
110
|
-
gap: layout.compact ? 14 : 20,
|
|
111
|
-
width: "100%" as const,
|
|
112
|
-
maxWidth: 920,
|
|
113
|
-
alignSelf: "center" as const,
|
|
114
|
-
},
|
|
115
|
-
header: { flexDirection: "row" as const, alignItems: "center" as const, gap: 12 },
|
|
116
|
-
headerCopy: { flex: 1, gap: 2 },
|
|
117
|
-
title: {
|
|
118
|
-
color: theme.colors.foreground,
|
|
119
|
-
fontSize: layout.compact ? 22 : 28,
|
|
120
|
-
fontWeight: "700" as const,
|
|
121
|
-
},
|
|
122
|
-
subtitle: { color: theme.colors.foregroundMuted, fontSize: 13 },
|
|
123
|
-
section: { gap: 8 },
|
|
124
|
-
sectionTitle: {
|
|
125
|
-
color: theme.colors.foreground,
|
|
126
|
-
fontSize: 15,
|
|
127
|
-
fontWeight: "700" as const,
|
|
128
|
-
},
|
|
129
|
-
card: {
|
|
130
|
-
gap: 10,
|
|
131
|
-
borderWidth: 1,
|
|
132
|
-
borderColor: theme.colors.border,
|
|
133
|
-
borderRadius: 12,
|
|
134
|
-
padding: layout.compact ? 12 : 16,
|
|
135
|
-
backgroundColor: theme.colors.surface1,
|
|
136
|
-
},
|
|
137
|
-
row: { flexDirection: "row" as const, alignItems: "center" as const, gap: 8 },
|
|
138
|
-
grow: { flex: 1 },
|
|
139
|
-
label: { color: theme.colors.foregroundMuted, fontSize: 12 },
|
|
140
|
-
value: { color: theme.colors.foreground, fontSize: 14 },
|
|
141
|
-
success: { color: theme.colors.statusSuccess, fontWeight: "600" as const },
|
|
142
|
-
warning: { color: theme.colors.statusWarning, fontWeight: "600" as const },
|
|
143
|
-
error: { color: theme.colors.statusDanger },
|
|
144
|
-
output: {
|
|
145
|
-
color: theme.colors.foreground,
|
|
146
|
-
fontFamily: "monospace",
|
|
147
|
-
fontSize: layout.compact ? 11 : 12,
|
|
148
|
-
lineHeight: layout.compact ? 16 : 18,
|
|
149
|
-
},
|
|
150
|
-
button: {
|
|
151
|
-
minHeight: 36,
|
|
152
|
-
paddingHorizontal: 12,
|
|
153
|
-
paddingVertical: 8,
|
|
154
|
-
borderRadius: 8,
|
|
155
|
-
backgroundColor: theme.colors.surface2,
|
|
156
|
-
alignItems: "center" as const,
|
|
157
|
-
justifyContent: "center" as const,
|
|
158
|
-
},
|
|
159
|
-
primaryButton: { backgroundColor: theme.colors.accent },
|
|
160
|
-
buttonText: { color: theme.colors.foreground, fontWeight: "600" as const },
|
|
161
|
-
primaryButtonText: { color: theme.colors.accentForeground, fontWeight: "600" as const },
|
|
162
|
-
actions: { flexDirection: "row" as const, flexWrap: "wrap" as const, gap: 8 },
|
|
163
|
-
healthLine: {
|
|
164
|
-
flexDirection: "row" as const,
|
|
165
|
-
alignItems: "center" as const,
|
|
166
|
-
flexWrap: "wrap" as const,
|
|
167
|
-
gap: 8,
|
|
168
|
-
},
|
|
169
|
-
chip: {
|
|
170
|
-
borderRadius: 999,
|
|
171
|
-
paddingHorizontal: 9,
|
|
172
|
-
paddingVertical: 5,
|
|
173
|
-
backgroundColor: theme.colors.surface2,
|
|
174
|
-
},
|
|
175
|
-
chipText: { color: theme.colors.foreground, fontSize: 11, fontWeight: "600" as const },
|
|
176
|
-
tabRow: {
|
|
177
|
-
flexDirection: "row" as const,
|
|
178
|
-
gap: 6,
|
|
179
|
-
padding: 4,
|
|
180
|
-
borderRadius: 10,
|
|
181
|
-
backgroundColor: theme.colors.surface1,
|
|
182
|
-
},
|
|
183
|
-
tab: {
|
|
184
|
-
flex: 1,
|
|
185
|
-
minHeight: 38,
|
|
186
|
-
alignItems: "center" as const,
|
|
187
|
-
justifyContent: "center" as const,
|
|
188
|
-
borderRadius: 8,
|
|
189
|
-
paddingHorizontal: 10,
|
|
190
|
-
},
|
|
191
|
-
tabActive: { backgroundColor: theme.colors.surface2 },
|
|
192
|
-
tabText: { color: theme.colors.foregroundMuted, fontWeight: "600" as const },
|
|
193
|
-
tabTextActive: { color: theme.colors.foreground },
|
|
194
|
-
tabPanel: { width: "100%" as const },
|
|
195
|
-
tabPanelHidden: { display: "none" as const },
|
|
196
|
-
}),
|
|
197
|
-
[layout.compact, theme],
|
|
198
|
-
);
|
|
199
|
-
|
|
200
|
-
if (settings.status === "loading") {
|
|
201
|
-
return (
|
|
202
|
-
<View style={[styles.screen, { alignItems: "center", justifyContent: "center" }]}>
|
|
203
|
-
<ActivityIndicator color={theme.colors.accent} />
|
|
204
|
-
<Text style={styles.subtitle}>Loading Context Mode settings…</Text>
|
|
205
|
-
</View>
|
|
206
|
-
);
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
if (settings.status !== "ready") {
|
|
210
|
-
return (
|
|
211
|
-
<View style={[styles.screen, styles.content]}>
|
|
212
|
-
<Text style={styles.title}>Context Mode</Text>
|
|
213
|
-
<Text accessibilityRole="alert" style={styles.error}>
|
|
214
|
-
{settings.error}
|
|
215
|
-
</Text>
|
|
216
|
-
<Pressable accessibilityRole="button" onPress={settings.reload} style={styles.button}>
|
|
217
|
-
<Text style={styles.buttonText}>Reload settings</Text>
|
|
218
|
-
</Pressable>
|
|
219
|
-
</View>
|
|
220
|
-
);
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
const statusData = status.data;
|
|
224
|
-
|
|
225
|
-
return (
|
|
226
|
-
<ScrollView style={styles.screen} contentContainerStyle={styles.content}>
|
|
227
|
-
<View style={styles.header}>
|
|
228
|
-
<Icon name="Gauge" size={layout.compact ? 24 : 30} color={theme.colors.accent} />
|
|
229
|
-
<View style={styles.headerCopy}>
|
|
230
|
-
<Text style={styles.title}>Context Mode</Text>
|
|
231
|
-
<Text style={styles.subtitle}>Context saved across your agents on {host.label}</Text>
|
|
232
|
-
</View>
|
|
233
|
-
</View>
|
|
234
|
-
|
|
235
|
-
<AnalyticsDashboard
|
|
236
|
-
display="hero"
|
|
237
|
-
fallback={stats.data?.state === "ready" ? stats.data.output : null}
|
|
238
|
-
health={
|
|
239
|
-
<HealthStrip
|
|
240
|
-
audit={integration.data}
|
|
241
|
-
auditError={integration.error}
|
|
242
|
-
auditPending={integration.isPending}
|
|
243
|
-
onOpenSettings={onOpenSettings}
|
|
244
|
-
onRefresh={() => refresh.mutate()}
|
|
245
|
-
refreshError={refresh.error}
|
|
246
|
-
refreshPending={refresh.isPending}
|
|
247
|
-
status={statusData}
|
|
248
|
-
statusError={status.error}
|
|
249
|
-
statusPending={status.isPending}
|
|
250
|
-
styles={styles}
|
|
251
|
-
/>
|
|
252
|
-
}
|
|
253
|
-
host={host}
|
|
254
|
-
layout={layout}
|
|
255
|
-
theme={theme}
|
|
256
|
-
/>
|
|
257
|
-
|
|
258
|
-
<View accessibilityRole="tablist" style={styles.tabRow}>
|
|
259
|
-
{SURFACE_TABS.map((tab) => {
|
|
260
|
-
const selected = activeTab === tab.id;
|
|
261
|
-
return (
|
|
262
|
-
<Pressable
|
|
263
|
-
key={tab.id}
|
|
264
|
-
accessibilityRole="tab"
|
|
265
|
-
accessibilityState={{ selected }}
|
|
266
|
-
onPress={() => setActiveTab(tab.id)}
|
|
267
|
-
style={[styles.tab, selected ? styles.tabActive : null]}
|
|
268
|
-
>
|
|
269
|
-
<Text style={[styles.tabText, selected ? styles.tabTextActive : null]}>
|
|
270
|
-
{tab.label}
|
|
271
|
-
</Text>
|
|
272
|
-
</Pressable>
|
|
273
|
-
);
|
|
274
|
-
})}
|
|
275
|
-
</View>
|
|
276
|
-
|
|
277
|
-
<View style={[styles.tabPanel, activeTab === "savings" ? null : styles.tabPanelHidden]}>
|
|
278
|
-
<AnalyticsDashboard
|
|
279
|
-
display="details"
|
|
280
|
-
fallback={stats.data?.state === "ready" ? stats.data.output : null}
|
|
281
|
-
host={host}
|
|
282
|
-
layout={layout}
|
|
283
|
-
theme={theme}
|
|
284
|
-
/>
|
|
285
|
-
</View>
|
|
286
|
-
<View style={[styles.tabPanel, activeTab === "knowledge" ? null : styles.tabPanelHidden]}>
|
|
287
|
-
{activeTab !== "knowledge" ? null : integration.isLoading ? (
|
|
288
|
-
<Text style={{ color: theme.colors.foregroundMuted }}>Loading providers…</Text>
|
|
289
|
-
) : screenParams.agentId || screenParams.workspaceId ? (
|
|
290
|
-
<ScopedKnowledgeSection
|
|
291
|
-
key={JSON.stringify([host.id, screenParams.agentId, screenParams.workspaceId])}
|
|
292
|
-
params={screenParams}
|
|
293
|
-
host={host}
|
|
294
|
-
layout={layout}
|
|
295
|
-
theme={theme}
|
|
296
|
-
providers={knowledgeProviders}
|
|
297
|
-
/>
|
|
298
|
-
) : (
|
|
299
|
-
<KnowledgeSection
|
|
300
|
-
key={host.id}
|
|
301
|
-
host={host}
|
|
302
|
-
layout={layout}
|
|
303
|
-
theme={theme}
|
|
304
|
-
providers={knowledgeProviders}
|
|
305
|
-
/>
|
|
306
|
-
)}
|
|
307
|
-
</View>
|
|
308
|
-
<View style={[styles.tabPanel, activeTab === "setup" ? null : styles.tabPanelHidden]}>
|
|
309
|
-
<ActionsSection key={host.id} layout={layout} theme={theme} />
|
|
310
|
-
</View>
|
|
311
|
-
</ScrollView>
|
|
312
|
-
);
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
function HealthStrip({
|
|
316
|
-
audit,
|
|
317
|
-
auditError,
|
|
318
|
-
auditPending,
|
|
319
|
-
onOpenSettings,
|
|
320
|
-
onRefresh,
|
|
321
|
-
refreshError,
|
|
322
|
-
refreshPending,
|
|
323
|
-
status,
|
|
324
|
-
statusError,
|
|
325
|
-
statusPending,
|
|
326
|
-
styles,
|
|
327
|
-
}: {
|
|
328
|
-
audit: IntegrationAudit | undefined;
|
|
329
|
-
auditError: unknown;
|
|
330
|
-
auditPending: boolean;
|
|
331
|
-
onOpenSettings(): void;
|
|
332
|
-
onRefresh(): void;
|
|
333
|
-
refreshError: unknown;
|
|
334
|
-
refreshPending: boolean;
|
|
335
|
-
status: BinaryStatus | undefined;
|
|
336
|
-
statusError: unknown;
|
|
337
|
-
statusPending: boolean;
|
|
338
|
-
styles: {
|
|
339
|
-
actions: object;
|
|
340
|
-
button: object;
|
|
341
|
-
buttonText: object;
|
|
342
|
-
card: object;
|
|
343
|
-
chip: object;
|
|
344
|
-
chipText: object;
|
|
345
|
-
error: object;
|
|
346
|
-
grow: object;
|
|
347
|
-
healthLine: object;
|
|
348
|
-
label: object;
|
|
349
|
-
success: object;
|
|
350
|
-
subtitle: object;
|
|
351
|
-
value: object;
|
|
352
|
-
warning: object;
|
|
353
|
-
};
|
|
354
|
-
}) {
|
|
355
|
-
const [expanded, setExpanded] = useState(false);
|
|
356
|
-
const covered =
|
|
357
|
-
audit?.providers.filter((provider) => provider.activation !== "disabled").length ?? 0;
|
|
358
|
-
const total = audit?.providers.length ?? 0;
|
|
359
|
-
const nativeCount =
|
|
360
|
-
audit?.providers.filter((provider) => provider.activation === "native").length ?? 0;
|
|
361
|
-
const mcpCount = audit?.providers.filter((provider) => provider.activation === "mcp").length ?? 0;
|
|
362
|
-
const statusReady = status?.state === "ready";
|
|
363
|
-
const error = statusError ?? auditError ?? refreshError;
|
|
364
|
-
|
|
365
|
-
return (
|
|
366
|
-
<View style={styles.card}>
|
|
367
|
-
<View style={styles.healthLine}>
|
|
368
|
-
{statusPending || auditPending ? <ActivityIndicator size="small" /> : null}
|
|
369
|
-
<Text style={statusReady ? styles.success : styles.warning}>
|
|
370
|
-
{status ? statusLabel(status) : "Checking"}
|
|
371
|
-
</Text>
|
|
372
|
-
{statusReady && status.version ? <Text style={styles.value}>v{status.version}</Text> : null}
|
|
373
|
-
<View style={styles.grow} />
|
|
374
|
-
<Text style={styles.value}>
|
|
375
|
-
{total > 0 ? `${covered} of ${total} providers covered` : "Coverage unavailable"}
|
|
376
|
-
</Text>
|
|
377
|
-
</View>
|
|
378
|
-
|
|
379
|
-
{status?.state === "unavailable" ? (
|
|
380
|
-
<Text style={styles.subtitle}>{status.message}</Text>
|
|
381
|
-
) : null}
|
|
382
|
-
{error ? (
|
|
383
|
-
<Text accessibilityRole="alert" style={styles.error}>
|
|
384
|
-
{error instanceof Error ? error.message : String(error)}
|
|
385
|
-
</Text>
|
|
386
|
-
) : null}
|
|
387
|
-
{statusReady && (!status.supportsDoctor || !status.supportsStats) ? (
|
|
388
|
-
<Text style={styles.warning}>
|
|
389
|
-
Some Context Mode health or savings tools are unavailable.
|
|
390
|
-
</Text>
|
|
391
|
-
) : null}
|
|
392
|
-
|
|
393
|
-
<View style={styles.actions}>
|
|
394
|
-
<Pressable
|
|
395
|
-
accessibilityRole="button"
|
|
396
|
-
accessibilityState={{ expanded }}
|
|
397
|
-
onPress={() => setExpanded((value) => !value)}
|
|
398
|
-
style={styles.button}
|
|
399
|
-
>
|
|
400
|
-
<Text style={styles.buttonText}>{expanded ? "Hide coverage" : "Coverage details"}</Text>
|
|
401
|
-
</Pressable>
|
|
402
|
-
<Pressable
|
|
403
|
-
accessibilityRole="button"
|
|
404
|
-
disabled={refreshPending}
|
|
405
|
-
onPress={onRefresh}
|
|
406
|
-
style={styles.button}
|
|
407
|
-
>
|
|
408
|
-
<Text style={styles.buttonText}>{refreshPending ? "Refreshing…" : "Refresh"}</Text>
|
|
409
|
-
</Pressable>
|
|
410
|
-
<Pressable accessibilityRole="button" onPress={onOpenSettings} style={styles.button}>
|
|
411
|
-
<Text style={styles.buttonText}>Settings</Text>
|
|
412
|
-
</Pressable>
|
|
413
|
-
</View>
|
|
414
|
-
|
|
415
|
-
{expanded && audit ? (
|
|
416
|
-
<View style={{ gap: 8 }}>
|
|
417
|
-
{mcpCount > 0 ? (
|
|
418
|
-
<Text style={styles.subtitle}>
|
|
419
|
-
MCP coverage applies to new agents. Existing agents may need recreation or manual
|
|
420
|
-
setup.
|
|
421
|
-
</Text>
|
|
422
|
-
) : null}
|
|
423
|
-
<View style={styles.actions}>
|
|
424
|
-
{audit.providers.map((provider) => (
|
|
425
|
-
<View key={provider.provider} style={styles.chip}>
|
|
426
|
-
<Text style={styles.chipText}>
|
|
427
|
-
{provider.provider} ·{" "}
|
|
428
|
-
{provider.activation === "native"
|
|
429
|
-
? "Native"
|
|
430
|
-
: provider.activation === "mcp"
|
|
431
|
-
? "MCP · new agents"
|
|
432
|
-
: "Off"}
|
|
433
|
-
</Text>
|
|
434
|
-
</View>
|
|
435
|
-
))}
|
|
436
|
-
</View>
|
|
437
|
-
<Text style={styles.label}>
|
|
438
|
-
{nativeCount} native · {mcpCount} MCP · {total - covered} off
|
|
439
|
-
</Text>
|
|
440
|
-
</View>
|
|
441
|
-
) : null}
|
|
442
|
-
</View>
|
|
443
|
-
);
|
|
444
|
-
}
|