@xpufx/paseo-top 0.4.4 → 0.4.7
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 +18 -0
- package/client/host-ui.tsx +184 -0
- package/client/multi-host-view.tsx +57 -43
- package/client/multi-host.ts +36 -13
- package/client/pill-labels.ts +94 -1
- package/client/pill.tsx +692 -616
- package/client/resources-query.ts +1 -1
- package/client/settings-events.ts +1 -1
- package/client/settings-ui.tsx +86 -9
- package/client/surface.tsx +308 -276
- package/client/telemetry-copy.ts +8 -2
- package/client/telemetry.tsx +372 -321
- package/client/turn-panel.tsx +126 -104
- package/client/vendor/paseo-plugin-helper/{host.ts → core/host.ts} +9 -3
- package/client/vendor/paseo-plugin-helper/core/index.ts +76 -0
- package/client/vendor/paseo-plugin-helper/core/plugin-load-count.ts +89 -0
- package/client/vendor/paseo-plugin-helper/{query-refresh.ts → core/query-refresh.ts} +2 -2
- package/client/vendor/paseo-plugin-helper/{query.ts → core/query.ts} +2 -2
- package/client/vendor/paseo-plugin-helper/{settings.ts → core/settings.ts} +1 -1
- package/client/vendor/paseo-plugin-helper/{shared-settings.ts → core/shared-settings.ts} +2 -2
- package/client/vendor/paseo-plugin-helper/{utils → lifecycle}/clipboard.ts +2 -2
- package/client/vendor/paseo-plugin-helper/lifecycle/flair.ts +26 -0
- package/client/vendor/paseo-plugin-helper/{theme/color-utils.ts → lifecycle/host-color.ts} +95 -38
- package/client/vendor/paseo-plugin-helper/lifecycle/host-theme.tsx +109 -0
- package/client/vendor/paseo-plugin-helper/lifecycle/index.ts +23 -0
- package/client/vendor/paseo-plugin-helper/lifecycle/multi-host.ts +66 -0
- package/client/vendor/paseo-plugin-helper/{panel.tsx → lifecycle/panel.tsx} +7 -7
- package/client/vendor/paseo-plugin-helper/{pill.tsx → lifecycle/pill.tsx} +51 -18
- package/client/vendor/paseo-plugin-helper/lifecycle/providers.tsx +46 -0
- package/client/vendor/paseo-plugin-helper/lifecycle/scroll-owner.ts +26 -0
- package/client/vendor/paseo-plugin-helper/{surface.tsx → lifecycle/surface.tsx} +6 -6
- package/client/vendor/paseo-plugin-helper/ui/color.ts +1 -0
- package/client/vendor/paseo-plugin-helper/ui/content.tsx +1326 -0
- package/client/vendor/paseo-plugin-helper/ui/controls.tsx +1018 -0
- package/client/vendor/paseo-plugin-helper/{components/DataTable.tsx → ui/data.tsx} +50 -58
- package/client/vendor/paseo-plugin-helper/ui/index.ts +44 -0
- package/client/vendor/paseo-plugin-helper/ui/layout.tsx +263 -0
- package/client/vendor/paseo-plugin-helper/ui/modal.tsx +111 -0
- package/client/vendor/paseo-plugin-helper/ui/plugin-reload-banner.tsx +119 -0
- package/client/vendor/paseo-plugin-helper/{settings-screen.tsx → ui/settings-screen.tsx} +3 -3
- package/client/vendor/paseo-plugin-helper/ui/settings.ts +36 -0
- package/client/vendor/paseo-plugin-helper/ui/text.tsx +821 -0
- package/client/vendor/paseo-plugin-helper/ui/theme.tsx +1 -0
- package/client/vendor/permission-audit/client.tsx +706 -0
- package/client/vendor/permission-audit/index.tsx +1 -0
- package/index.client.tsx +58 -37
- package/index.server.ts +256 -234
- package/npm-shrinkwrap.json +44 -0
- package/package.json +8 -4
- package/paseo-plugin.json +2 -0
- package/screenshots/1-paseo-top-modal-system.jpg +0 -0
- package/screenshots/2-paseo-top-modal-workspace.jpg +0 -0
- package/screenshots/3-paseo-top-modal-settings.jpg +0 -0
- package/screenshots/4-paseo-top-modal-about.jpg +0 -0
- package/screenshots/paseo-top-dashboard.jpg +0 -0
- package/screenshots/paseo-top-general-view.jpg +0 -0
- package/server/resources.ts +98 -0
- package/server/vendor/paseo-plugin-helper/custom-pills.ts +70 -0
- package/server/vendor/paseo-plugin-helper/index.ts +2 -0
- package/server/vendor/paseo-plugin-helper/logger.ts +5 -16
- package/server/vendor/paseo-plugin-helper/rpc-guard.ts +2 -2
- package/server/vendor/paseo-plugin-helper/storage-guard.ts +294 -0
- package/server/vendor/paseo-plugin-helper/storage.ts +36 -2
- package/server/vendor/paseo-plugin-helper/telemetry.ts +486 -0
- package/server/vendor/paseo-plugin-helper/tickets.ts +18 -67
- package/server/vendor/permission-audit/index.ts +1 -0
- package/server/vendor/permission-audit/server.ts +839 -0
- package/shared/helper-version.ts +1 -1
- package/shared/multi-host.ts +153 -159
- package/shared/resources.ts +145 -0
- package/shared/vendor/paseo-plugin-helper/async.ts +14 -7
- package/shared/vendor/paseo-plugin-helper/features.ts +244 -0
- package/shared/vendor/paseo-plugin-helper/forge.ts +27 -0
- package/shared/vendor/paseo-plugin-helper/index.ts +1 -0
- package/shared/vendor/paseo-plugin-helper/tickets.ts +122 -28
- package/shared/vendor/permission-audit/filter.ts +61 -0
- package/shared/vendor/permission-audit/index.ts +2 -0
- package/shared/vendor/permission-audit/shared.ts +119 -0
- package/shared/version.ts +1 -1
- package/client/vendor/paseo-plugin-helper/components/AboutSection.tsx +0 -493
- package/client/vendor/paseo-plugin-helper/components/AttentionBeacon.tsx +0 -250
- package/client/vendor/paseo-plugin-helper/components/Badge.tsx +0 -168
- package/client/vendor/paseo-plugin-helper/components/Button.tsx +0 -204
- package/client/vendor/paseo-plugin-helper/components/Card.tsx +0 -257
- package/client/vendor/paseo-plugin-helper/components/CodeBlock.tsx +0 -196
- package/client/vendor/paseo-plugin-helper/components/Collapsible.tsx +0 -277
- package/client/vendor/paseo-plugin-helper/components/CommandBox.tsx +0 -172
- package/client/vendor/paseo-plugin-helper/components/CopyButton.tsx +0 -180
- package/client/vendor/paseo-plugin-helper/components/EmptyState.tsx +0 -97
- package/client/vendor/paseo-plugin-helper/components/HighlightedText.tsx +0 -70
- package/client/vendor/paseo-plugin-helper/components/InlineButton.tsx +0 -88
- package/client/vendor/paseo-plugin-helper/components/InteractiveRow.tsx +0 -142
- package/client/vendor/paseo-plugin-helper/components/KeyValue.tsx +0 -446
- package/client/vendor/paseo-plugin-helper/components/MetricGauge.tsx +0 -247
- package/client/vendor/paseo-plugin-helper/components/ProgressBar.tsx +0 -117
- package/client/vendor/paseo-plugin-helper/components/Responsive.tsx +0 -53
- package/client/vendor/paseo-plugin-helper/components/SearchInput.tsx +0 -132
- package/client/vendor/paseo-plugin-helper/components/SectionHeader.tsx +0 -87
- package/client/vendor/paseo-plugin-helper/components/Select.tsx +0 -283
- package/client/vendor/paseo-plugin-helper/components/StatusDot.tsx +0 -80
- package/client/vendor/paseo-plugin-helper/components/Tabs.tsx +0 -319
- package/client/vendor/paseo-plugin-helper/components/TextInput.tsx +0 -150
- package/client/vendor/paseo-plugin-helper/components/Toggle.tsx +0 -163
- package/client/vendor/paseo-plugin-helper/components/TruncatedText.tsx +0 -157
- package/client/vendor/paseo-plugin-helper/components/index.ts +0 -26
- package/client/vendor/paseo-plugin-helper/custom-pills.tsx +0 -225
- package/client/vendor/paseo-plugin-helper/forge-icon.tsx +0 -79
- package/client/vendor/paseo-plugin-helper/icon.tsx +0 -39
- package/client/vendor/paseo-plugin-helper/index.ts +0 -30
- package/client/vendor/paseo-plugin-helper/layout/ActionBar.tsx +0 -49
- package/client/vendor/paseo-plugin-helper/layout/FormRow.tsx +0 -103
- package/client/vendor/paseo-plugin-helper/layout/Grid.tsx +0 -65
- package/client/vendor/paseo-plugin-helper/layout/ModalBody.tsx +0 -368
- package/client/vendor/paseo-plugin-helper/layout/ModalContent.tsx +0 -51
- package/client/vendor/paseo-plugin-helper/layout/Row.tsx +0 -39
- package/client/vendor/paseo-plugin-helper/layout/Stack.tsx +0 -39
- package/client/vendor/paseo-plugin-helper/layout/index.ts +0 -7
- package/client/vendor/paseo-plugin-helper/styles/index.ts +0 -1
- package/client/vendor/paseo-plugin-helper/styles/recipes.ts +0 -550
- package/client/vendor/paseo-plugin-helper/theme/flair.ts +0 -76
- package/client/vendor/paseo-plugin-helper/theme/host-variables.ts +0 -121
- package/client/vendor/paseo-plugin-helper/theme/index.ts +0 -7
- package/client/vendor/paseo-plugin-helper/theme/provider.tsx +0 -178
- package/client/vendor/paseo-plugin-helper/theme/responsive.ts +0 -213
- package/client/vendor/paseo-plugin-helper/theme/tokens.ts +0 -200
- package/client/vendor/paseo-plugin-helper/theme/useResponsive.ts +0 -57
- package/client/vendor/paseo-plugin-helper/tickets.tsx +0 -766
- /package/client/vendor/paseo-plugin-helper/{command-center.ts → core/command-center.ts} +0 -0
- /package/client/vendor/paseo-plugin-helper/{snapshot.ts → core/snapshot.ts} +0 -0
- /package/client/vendor/paseo-plugin-helper/{utils → lifecycle}/haptics.ts +0 -0
package/client/pill.tsx
CHANGED
|
@@ -7,46 +7,52 @@ import {
|
|
|
7
7
|
useRpc,
|
|
8
8
|
type PluginClientContext,
|
|
9
9
|
} from "@getpaseo/plugin/client";
|
|
10
|
+
import { Icon } from "@getpaseo/plugin/client/react-native";
|
|
10
11
|
import {
|
|
11
12
|
registerComposerPill,
|
|
12
13
|
registerSidebarSurface,
|
|
13
|
-
|
|
14
|
+
triggerHaptic,
|
|
14
15
|
type SidebarSurfaceRegistrar,
|
|
15
16
|
type PillLiveContext,
|
|
16
17
|
type RegisterComposerPillOptions,
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
Row,
|
|
22
|
-
KeyValue,
|
|
23
|
-
KeyValueGroup,
|
|
24
|
-
ProgressBar,
|
|
25
|
-
MetricGauge,
|
|
26
|
-
Tabs,
|
|
27
|
-
Toggle,
|
|
28
|
-
Badge,
|
|
29
|
-
Icon,
|
|
30
|
-
AboutSection,
|
|
31
|
-
CustomPillModalContent,
|
|
18
|
+
type RenderModalProps,
|
|
19
|
+
} from "./vendor/paseo-plugin-helper/lifecycle/index";
|
|
20
|
+
import {
|
|
21
|
+
getClientHost,
|
|
32
22
|
useRpcQuery,
|
|
33
23
|
usePluginSettings,
|
|
34
|
-
|
|
35
|
-
getStatusColor,
|
|
36
|
-
triggerHaptic,
|
|
24
|
+
type ComposerPillRegistrar,
|
|
37
25
|
type HostPillProps,
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
26
|
+
} from "./vendor/paseo-plugin-helper/core/index";
|
|
27
|
+
import {
|
|
28
|
+
HostAboutSection,
|
|
29
|
+
HostBadge,
|
|
30
|
+
HostButton,
|
|
31
|
+
HostCard,
|
|
32
|
+
HostCardHeader,
|
|
33
|
+
HostCopyButton,
|
|
34
|
+
HostKeyValue,
|
|
35
|
+
HostLayoutProvider,
|
|
36
|
+
HostMetricGauge,
|
|
37
|
+
HostModalSection,
|
|
38
|
+
HostProgressBar,
|
|
39
|
+
HostRow,
|
|
40
|
+
HostStack,
|
|
41
|
+
HostTabs,
|
|
42
|
+
HostThemeProvider,
|
|
43
|
+
HostToggle,
|
|
44
|
+
getStatusColor,
|
|
45
|
+
useHostLayout,
|
|
46
|
+
useHostTheme,
|
|
47
|
+
} from "./host-ui";
|
|
43
48
|
import {
|
|
44
49
|
formatBytes,
|
|
45
50
|
formatUptime,
|
|
46
51
|
resolveMetricStatus,
|
|
47
52
|
type MetricThresholds,
|
|
53
|
+
type ThemeColors,
|
|
48
54
|
} from "../shared/vendor/paseo-plugin-helper/index";
|
|
49
|
-
import { PermissionAuditView } from "permission-audit
|
|
55
|
+
import { PermissionAuditView } from "./vendor/permission-audit";
|
|
50
56
|
import {
|
|
51
57
|
getSystemResourcesRpc,
|
|
52
58
|
topSettingsContract,
|
|
@@ -54,14 +60,18 @@ import {
|
|
|
54
60
|
listCustomPillsRpc,
|
|
55
61
|
runCustomPillModalCommandRpc,
|
|
56
62
|
isPillEnabled,
|
|
57
|
-
|
|
63
|
+
isTimelineEnabled,
|
|
58
64
|
legacyFlagView,
|
|
59
65
|
isMcpSurfaceEnabled,
|
|
60
66
|
customPillEffectiveEnabled,
|
|
61
67
|
METRIC_DEFINITIONS,
|
|
62
68
|
DEFAULT_METRIC_SURFACES,
|
|
63
|
-
checkboxesFromTarget,
|
|
64
69
|
targetFromCheckboxes,
|
|
70
|
+
CPU_THRESHOLDS,
|
|
71
|
+
MEM_THRESHOLDS,
|
|
72
|
+
MODAL_TABS,
|
|
73
|
+
aboutExtraItems,
|
|
74
|
+
hasAnyLegacyPillFlagEnabled,
|
|
65
75
|
type SystemResources,
|
|
66
76
|
type TopSettings,
|
|
67
77
|
type CustomPillStateOutput,
|
|
@@ -72,7 +82,7 @@ import { PLUGIN_VERSION } from "../shared/version";
|
|
|
72
82
|
import { TopDashboardSurface } from "./surface";
|
|
73
83
|
import { addSettingsListener, removeSettingsListener, notifySettingsChanged } from "./settings-events";
|
|
74
84
|
import { useTopResourceQuery, useCustomPillsQuery } from "./resources-query";
|
|
75
|
-
import { ChoiceChips } from "./settings-ui";
|
|
85
|
+
import { ChoiceChips, MultiChoiceChips } from "./settings-ui";
|
|
76
86
|
import {
|
|
77
87
|
buildAllLabel,
|
|
78
88
|
describeSegment,
|
|
@@ -90,6 +100,11 @@ import {
|
|
|
90
100
|
|
|
91
101
|
const EMPTY_PARAMS = {};
|
|
92
102
|
|
|
103
|
+
const TIMELINE_CADENCE_OPTIONS = Array.from({ length: 11 }, (_, n) => ({
|
|
104
|
+
id: n,
|
|
105
|
+
label: n === 0 ? "Never" : n === 1 ? "Every turn" : `${n}`,
|
|
106
|
+
}));
|
|
107
|
+
|
|
93
108
|
function formatWorktreeLocation(dir: string | null | undefined): string {
|
|
94
109
|
if (!dir) return "";
|
|
95
110
|
// Check for Paseo-managed worktree: ~/.paseo/worktrees/<hash>/<slug>
|
|
@@ -133,25 +148,9 @@ function formatIdleDuration(isoString: string | null | undefined): string {
|
|
|
133
148
|
return `${days}d ${hours % 24}h`;
|
|
134
149
|
}
|
|
135
150
|
|
|
136
|
-
const CPU_THRESHOLDS: MetricThresholds = { warning: 60, danger: 85 };
|
|
137
|
-
const MEM_THRESHOLDS: MetricThresholds = { warning: 70, danger: 85 };
|
|
138
|
-
|
|
139
|
-
const TABS = [
|
|
140
|
-
{ id: "system", label: "System", shortLabel: "System", icon: "Activity" },
|
|
141
|
-
{ id: "context", label: "Workspace", shortLabel: "Workspace", icon: "GitBranch" },
|
|
142
|
-
{ id: "permissions", label: "Permissions", shortLabel: "Permissions", icon: "ShieldCheck" },
|
|
143
|
-
{ id: "settings", label: "Settings", shortLabel: "Settings", icon: "Sliders" },
|
|
144
|
-
{ id: "about", label: "About", shortLabel: "About", icon: "Info" },
|
|
145
|
-
];
|
|
146
|
-
|
|
147
|
-
const TIMELINE_CADENCE_OPTIONS = Array.from({ length: 11 }, (_, n) => ({
|
|
148
|
-
id: n,
|
|
149
|
-
label: n === 0 ? "Never" : n === 1 ? "Every turn" : `${n}`,
|
|
150
|
-
}));
|
|
151
|
-
|
|
152
151
|
function getMetricColors(
|
|
153
152
|
data: SystemResources | undefined,
|
|
154
|
-
colors:
|
|
153
|
+
colors: ThemeColors,
|
|
155
154
|
) {
|
|
156
155
|
if (
|
|
157
156
|
!data ||
|
|
@@ -189,6 +188,7 @@ export function getItemTab(item: PillItemType): "system" | "context" {
|
|
|
189
188
|
case "tokens":
|
|
190
189
|
case "tools":
|
|
191
190
|
case "turns":
|
|
191
|
+
case "velocity":
|
|
192
192
|
return "system";
|
|
193
193
|
case "branch":
|
|
194
194
|
case "worktree":
|
|
@@ -203,28 +203,15 @@ export function getItemTab(item: PillItemType): "system" | "context" {
|
|
|
203
203
|
|
|
204
204
|
const currentCycleTabByAgent = new Map<string, ModalTab>();
|
|
205
205
|
|
|
206
|
-
// The 0.8 host popover is a narrow column, so
|
|
207
|
-
//
|
|
208
|
-
//
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
/>
|
|
216
|
-
);
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
function CompactCardHeader(props: CardHeaderProps) {
|
|
220
|
-
return (
|
|
221
|
-
<CardHeader titleStyle={styles.compactCardTitle} {...props} />
|
|
222
|
-
);
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
function CompactBadge(props: BadgeProps) {
|
|
226
|
-
return <Badge textStyle={styles.compactBadgeText} {...props} />;
|
|
227
|
-
}
|
|
206
|
+
// The 0.8 host popover is a narrow column, so modal-path text renders a few
|
|
207
|
+
// points under the ui/ adapter defaults. These spread props apply that
|
|
208
|
+
// compact rhythm at each call site.
|
|
209
|
+
const compactKvProps = {
|
|
210
|
+
labelStyle: { fontSize: 9 },
|
|
211
|
+
valueStyle: { fontSize: 10 },
|
|
212
|
+
} as const;
|
|
213
|
+
const compactCardTitleProp = { titleStyle: { fontSize: 11 } } as const;
|
|
214
|
+
const compactBadgeProp = { textStyle: { fontSize: 9 } } as const;
|
|
228
215
|
|
|
229
216
|
interface LiveSnapshot extends SegmentSnapshot {
|
|
230
217
|
workspaceDirectory?: string | null;
|
|
@@ -352,7 +339,16 @@ async function customPillSnapshot(): Promise<CustomPillStateOutput[]> {
|
|
|
352
339
|
* per-metric pills, custom metric pills) so the presentation model cannot
|
|
353
340
|
* diverge: all are centered surfaces with a pinned popover width. Call sites
|
|
354
341
|
* only describe what is pill-specific.
|
|
342
|
+
*
|
|
343
|
+
* `onError` is wired here once for every variant: the helper reports
|
|
344
|
+
* registration and resolveLabel failures through `options.onError` in addition
|
|
345
|
+
* to its own console warning, so without this default a failing pill RPC left
|
|
346
|
+
* the pill missing with no trace outside the helper log. The toast is
|
|
347
|
+
* throttled per pill+agent so a persistently failing RPC cannot spam the host.
|
|
355
348
|
*/
|
|
349
|
+
const PILL_ERROR_TOAST_THROTTLE_MS = 60_000;
|
|
350
|
+
const lastPillErrorToastAt = new Map<string, number>();
|
|
351
|
+
|
|
356
352
|
function registerTopPill(
|
|
357
353
|
client: ComposerPillRegistrar | PluginClientContext,
|
|
358
354
|
options: Omit<RegisterComposerPillOptions<ModalTab>, "presentation" | "popoverWidth"> & {
|
|
@@ -362,8 +358,29 @@ function registerTopPill(
|
|
|
362
358
|
) {
|
|
363
359
|
return registerComposerPill<ModalTab>(client as ComposerPillRegistrar, {
|
|
364
360
|
popoverWidth: 360,
|
|
361
|
+
// The host `<Modal.Content scrollable>` is the one scroll owner (#219,
|
|
362
|
+
// #975, #1054); the plugin body renders fluid content with no nested
|
|
363
|
+
// scroller so the host owns the mobile gesture.
|
|
364
|
+
hostScroll: true,
|
|
365
365
|
...options,
|
|
366
366
|
presentation: options.presentation ?? "centered",
|
|
367
|
+
onError:
|
|
368
|
+
options.onError ??
|
|
369
|
+
(({ agentId, workspaceId, error }) => {
|
|
370
|
+
console.error(
|
|
371
|
+
`[top] pill "${options.id}" failed (agent ${agentId}, workspace ${workspaceId}): ${error.message}`,
|
|
372
|
+
);
|
|
373
|
+
const key = `${options.id}:${agentId}`;
|
|
374
|
+
const now = Date.now();
|
|
375
|
+
if (now - (lastPillErrorToastAt.get(key) ?? 0) >= PILL_ERROR_TOAST_THROTTLE_MS) {
|
|
376
|
+
lastPillErrorToastAt.set(key, now);
|
|
377
|
+
try {
|
|
378
|
+
getClientHost().useToast().error?.(`top pill failed: ${error.message}`);
|
|
379
|
+
} catch {
|
|
380
|
+
// No host toast wired; the console error above is the trace.
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
}),
|
|
367
384
|
});
|
|
368
385
|
}
|
|
369
386
|
|
|
@@ -390,7 +407,7 @@ function PillItemContent({
|
|
|
390
407
|
worktreeLocationText,
|
|
391
408
|
isOpen,
|
|
392
409
|
}: PillItemContentProps) {
|
|
393
|
-
const { colors } =
|
|
410
|
+
const { colors } = useHostTheme();
|
|
394
411
|
const { cpuColor, memColor } = getMetricColors(data, colors);
|
|
395
412
|
const descriptor = describeSegment(item, { data, agent, agentId, worktreeLocationText });
|
|
396
413
|
const toneColor = (tone: SegmentTone): string => {
|
|
@@ -415,7 +432,7 @@ function PillItemContent({
|
|
|
415
432
|
};
|
|
416
433
|
|
|
417
434
|
return (
|
|
418
|
-
<
|
|
435
|
+
<HostRow gap={4} align="center" style={styles.pillContainer}>
|
|
419
436
|
{descriptor.iconTone !== "none" ? (
|
|
420
437
|
<Icon name={descriptor.icon} size={12} color={toneColor(descriptor.iconTone)} />
|
|
421
438
|
) : null}
|
|
@@ -444,7 +461,7 @@ function PillItemContent({
|
|
|
444
461
|
</Text>
|
|
445
462
|
) : null}
|
|
446
463
|
</Text>
|
|
447
|
-
</
|
|
464
|
+
</HostRow>
|
|
448
465
|
);
|
|
449
466
|
}
|
|
450
467
|
|
|
@@ -452,19 +469,19 @@ export { notifySettingsChanged } from "./settings-events";
|
|
|
452
469
|
type SettingsListener = import("./settings-events").SettingsListener;
|
|
453
470
|
|
|
454
471
|
function PillOffline() {
|
|
455
|
-
const { colors } =
|
|
472
|
+
const { colors } = useHostTheme();
|
|
456
473
|
return (
|
|
457
|
-
<
|
|
474
|
+
<HostRow gap={4} align="center" style={styles.pillContainer}>
|
|
458
475
|
<Icon name="Ghost" size={13} color={colors.statusDanger} />
|
|
459
476
|
<Text numberOfLines={1} style={[styles.pillText, { color: colors.foregroundMuted }]}>
|
|
460
477
|
Offline
|
|
461
478
|
</Text>
|
|
462
|
-
</
|
|
479
|
+
</HostRow>
|
|
463
480
|
);
|
|
464
481
|
}
|
|
465
482
|
|
|
466
483
|
function PillLoading() {
|
|
467
|
-
const { colors } =
|
|
484
|
+
const { colors } = useHostTheme();
|
|
468
485
|
return (
|
|
469
486
|
<Text numberOfLines={1} style={[styles.pillText, { color: colors.foregroundMuted }]}>
|
|
470
487
|
top...
|
|
@@ -473,19 +490,19 @@ function PillLoading() {
|
|
|
473
490
|
}
|
|
474
491
|
|
|
475
492
|
function PillEmpty() {
|
|
476
|
-
const { colors } =
|
|
493
|
+
const { colors } = useHostTheme();
|
|
477
494
|
return (
|
|
478
|
-
<
|
|
495
|
+
<HostRow gap={4} align="center" style={styles.pillContainer}>
|
|
479
496
|
<Icon name="Activity" size={12} color={colors.accent} />
|
|
480
497
|
<Text numberOfLines={1} style={[styles.pillText, { color: colors.foregroundMuted }]}>
|
|
481
498
|
top
|
|
482
499
|
</Text>
|
|
483
|
-
</
|
|
500
|
+
</HostRow>
|
|
484
501
|
);
|
|
485
502
|
}
|
|
486
503
|
|
|
487
504
|
function McpLoadingPill() {
|
|
488
|
-
const { colors } =
|
|
505
|
+
const { colors } = useHostTheme();
|
|
489
506
|
return (
|
|
490
507
|
<Text numberOfLines={1} style={[styles.pillText, { color: colors.foregroundMuted }]}>
|
|
491
508
|
MCP…
|
|
@@ -543,9 +560,9 @@ function AllInOnePill({
|
|
|
543
560
|
worktreeLocationText,
|
|
544
561
|
isOpen,
|
|
545
562
|
}: AllInOnePillProps) {
|
|
546
|
-
const { colors } =
|
|
563
|
+
const { colors } = useHostTheme();
|
|
547
564
|
return (
|
|
548
|
-
<
|
|
565
|
+
<HostRow gap={6} align="center" style={styles.allInOneContainer}>
|
|
549
566
|
{items.map((item, idx) => (
|
|
550
567
|
<React.Fragment key={item}>
|
|
551
568
|
{idx > 0 && (
|
|
@@ -561,7 +578,7 @@ function AllInOnePill({
|
|
|
561
578
|
/>
|
|
562
579
|
</React.Fragment>
|
|
563
580
|
))}
|
|
564
|
-
</
|
|
581
|
+
</HostRow>
|
|
565
582
|
);
|
|
566
583
|
}
|
|
567
584
|
|
|
@@ -584,7 +601,18 @@ export interface SingleItemPillViewProps extends PillBodyProps {
|
|
|
584
601
|
defaultTab?: ModalTab;
|
|
585
602
|
}
|
|
586
603
|
|
|
587
|
-
export function SingleItemPillView({
|
|
604
|
+
export function SingleItemPillView(props: SingleItemPillViewProps) {
|
|
605
|
+
// Legacy pill body view (see PillBodyProps): kept for the #507 render
|
|
606
|
+
// regression tests. The host theme prop flows through HostThemeProvider so
|
|
607
|
+
// the ui/ adapters inside resolve real host colors.
|
|
608
|
+
return (
|
|
609
|
+
<HostThemeProvider theme={props.theme}>
|
|
610
|
+
<SingleItemPillViewBody {...props} />
|
|
611
|
+
</HostThemeProvider>
|
|
612
|
+
);
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
function SingleItemPillViewBody({
|
|
588
616
|
item,
|
|
589
617
|
workspaceId,
|
|
590
618
|
agentId,
|
|
@@ -664,7 +692,18 @@ export function SingleItemPillView({
|
|
|
664
692
|
);
|
|
665
693
|
}
|
|
666
694
|
|
|
667
|
-
function PillView(
|
|
695
|
+
function PillView(props: PillBodyProps) {
|
|
696
|
+
// Legacy pill body view (see PillBodyProps): kept for the #507 render
|
|
697
|
+
// regression tests. The host theme prop flows through HostThemeProvider so
|
|
698
|
+
// the ui/ adapters inside resolve real host colors.
|
|
699
|
+
return (
|
|
700
|
+
<HostThemeProvider theme={props.theme}>
|
|
701
|
+
<PillViewBody {...props} />
|
|
702
|
+
</HostThemeProvider>
|
|
703
|
+
);
|
|
704
|
+
}
|
|
705
|
+
|
|
706
|
+
function PillViewBody({ isOpen, open, workspaceId, agentId }: PillBodyProps) {
|
|
668
707
|
// No background settings poll here: the hook re-verifies on mount and
|
|
669
708
|
// window focus, and mutations invalidate the shared settings cache.
|
|
670
709
|
// Polling from every mounted pill/modal/surface multiplied daemon reads
|
|
@@ -686,18 +725,7 @@ function PillView({ isOpen, open, workspaceId, agentId }: PillBodyProps) {
|
|
|
686
725
|
lastUsage: a?.lastUsage,
|
|
687
726
|
}));
|
|
688
727
|
|
|
689
|
-
const hasAnyEnabled =
|
|
690
|
-
flags.showCpuRam ||
|
|
691
|
-
flags.showBranch ||
|
|
692
|
-
flags.showWorktree ||
|
|
693
|
-
flags.showAgentTitle ||
|
|
694
|
-
flags.showAgent ||
|
|
695
|
-
flags.showAgentProvider ||
|
|
696
|
-
flags.showAgentActivity ||
|
|
697
|
-
flags.showAgentId ||
|
|
698
|
-
flags.showLoad ||
|
|
699
|
-
flags.showUptime ||
|
|
700
|
-
(flags.showMcp);
|
|
728
|
+
const hasAnyEnabled = hasAnyLegacyPillFlagEnabled(flags) || flags.showMcp;
|
|
701
729
|
|
|
702
730
|
// If no items are selected, fallback to CPU & RAM without mutating saved settings
|
|
703
731
|
const effectiveShowCpuRam = flags.showCpuRam || !hasAnyEnabled;
|
|
@@ -784,6 +812,9 @@ function PillView({ isOpen, open, workspaceId, agentId }: PillBodyProps) {
|
|
|
784
812
|
if (settings.metricSurfaces && isPillEnabled(settings.metricSurfaces.turns)) {
|
|
785
813
|
items.push("turns");
|
|
786
814
|
}
|
|
815
|
+
if (settings.metricSurfaces && isPillEnabled(settings.metricSurfaces.velocity)) {
|
|
816
|
+
items.push("velocity");
|
|
817
|
+
}
|
|
787
818
|
|
|
788
819
|
// Legacy render fallback only. On the supported 0.8 host the pill is
|
|
789
820
|
// host-rendered from `resolveLabel`, which advances the cycle on the shared
|
|
@@ -839,12 +870,11 @@ interface ResourceModalProps extends RenderModalProps<ModalTab> {
|
|
|
839
870
|
initialTab?: ModalTab;
|
|
840
871
|
}
|
|
841
872
|
|
|
842
|
-
function
|
|
873
|
+
function MetricPillSelector({
|
|
843
874
|
settings,
|
|
844
875
|
updateSettings,
|
|
845
876
|
notifySettingsChanged,
|
|
846
877
|
mcpInstalled,
|
|
847
|
-
mcpRunning,
|
|
848
878
|
customPills,
|
|
849
879
|
customOverrides,
|
|
850
880
|
onCustomToggle,
|
|
@@ -853,141 +883,119 @@ function MetricSurfaceMatrix({
|
|
|
853
883
|
updateSettings: (updates: Partial<TopSettings>) => void;
|
|
854
884
|
notifySettingsChanged: (s: TopSettings) => void;
|
|
855
885
|
mcpInstalled: boolean;
|
|
856
|
-
mcpRunning?: boolean | null;
|
|
857
886
|
customPills: Array<{ id: string; title: string; sourceFile?: string; enabled: boolean }>;
|
|
858
887
|
customOverrides: Record<string, boolean> | undefined;
|
|
859
888
|
onCustomToggle: (id: string, val: boolean) => void;
|
|
860
889
|
}) {
|
|
861
|
-
const { colors
|
|
890
|
+
const { colors } = useHostTheme();
|
|
862
891
|
const surfaces = settings.metricSurfaces ?? DEFAULT_METRIC_SURFACES;
|
|
863
|
-
const
|
|
864
|
-
|
|
865
|
-
const
|
|
866
|
-
|
|
867
|
-
|
|
892
|
+
const masterOn = settings.showCustomPills ?? true;
|
|
893
|
+
|
|
894
|
+
const builtInOptions = METRIC_DEFINITIONS.map((def) => ({
|
|
895
|
+
id: def.id,
|
|
896
|
+
label: def.title,
|
|
897
|
+
icon: def.icon,
|
|
898
|
+
disabled: def.id === "mcp" && !mcpInstalled,
|
|
899
|
+
}));
|
|
900
|
+
|
|
901
|
+
const selectedBuiltIns = METRIC_DEFINITIONS
|
|
902
|
+
.filter((def) => isPillEnabled(surfaces[def.id]))
|
|
903
|
+
.map((def) => def.id);
|
|
904
|
+
|
|
905
|
+
const toggleMetric = (metricId: MetricId) => {
|
|
906
|
+
triggerHaptic("light");
|
|
907
|
+
const currentPill = isPillEnabled(surfaces[metricId]);
|
|
908
|
+
const currentTimeline = isTimelineEnabled(surfaces[metricId]);
|
|
909
|
+
const next = {
|
|
910
|
+
...surfaces,
|
|
911
|
+
[metricId]: targetFromCheckboxes(!currentPill, currentTimeline),
|
|
912
|
+
};
|
|
913
|
+
const nextSettings = { ...settings, metricSurfaces: next };
|
|
914
|
+
updateSettings({ metricSurfaces: next });
|
|
915
|
+
notifySettingsChanged(nextSettings);
|
|
916
|
+
};
|
|
917
|
+
|
|
918
|
+
const selectAll = () => {
|
|
919
|
+
triggerHaptic("medium");
|
|
920
|
+
const next = { ...surfaces };
|
|
921
|
+
for (const def of METRIC_DEFINITIONS) {
|
|
922
|
+
if (def.id === "mcp" && !mcpInstalled) continue;
|
|
923
|
+
const currentTimeline = isTimelineEnabled(surfaces[def.id]);
|
|
924
|
+
next[def.id] = targetFromCheckboxes(true, currentTimeline);
|
|
925
|
+
}
|
|
926
|
+
const nextSettings = { ...settings, metricSurfaces: next };
|
|
927
|
+
updateSettings({ metricSurfaces: next });
|
|
928
|
+
notifySettingsChanged(nextSettings);
|
|
929
|
+
};
|
|
930
|
+
|
|
931
|
+
const clearAll = () => {
|
|
932
|
+
triggerHaptic("medium");
|
|
933
|
+
const next = { ...surfaces };
|
|
934
|
+
for (const def of METRIC_DEFINITIONS) {
|
|
935
|
+
const currentTimeline = isTimelineEnabled(surfaces[def.id]);
|
|
936
|
+
next[def.id] = targetFromCheckboxes(false, currentTimeline);
|
|
937
|
+
}
|
|
938
|
+
const nextSettings = { ...settings, metricSurfaces: next };
|
|
868
939
|
updateSettings({ metricSurfaces: next });
|
|
869
|
-
notifySettingsChanged(
|
|
940
|
+
notifySettingsChanged(nextSettings);
|
|
870
941
|
};
|
|
942
|
+
|
|
871
943
|
return (
|
|
872
|
-
<
|
|
873
|
-
<
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
944
|
+
<HostStack gap={10}>
|
|
945
|
+
<MultiChoiceChips
|
|
946
|
+
options={builtInOptions}
|
|
947
|
+
selected={selectedBuiltIns}
|
|
948
|
+
onToggle={toggleMetric}
|
|
949
|
+
onSelectAll={selectAll}
|
|
950
|
+
onClearAll={clearAll}
|
|
951
|
+
/>
|
|
952
|
+
{customPills.length > 0 && (
|
|
953
|
+
<HostStack gap={6}>
|
|
954
|
+
<Text style={{ fontSize: 10, fontWeight: "600", color: colors.foregroundMuted }}>
|
|
955
|
+
Custom Metric Pills
|
|
883
956
|
</Text>
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
setTarget(
|
|
906
|
-
def.id,
|
|
907
|
-
targetFromCheckboxes(nextBoxes.pill, nextBoxes.timeline),
|
|
908
|
-
);
|
|
909
|
-
};
|
|
910
|
-
return (
|
|
911
|
-
<View
|
|
912
|
-
key={def.id}
|
|
913
|
-
style={[
|
|
914
|
-
styles.metricMatrixRow,
|
|
915
|
-
isCompact && styles.metricMatrixRowCompact,
|
|
916
|
-
{ minHeight: matrixRowMinHeight },
|
|
917
|
-
index < METRIC_DEFINITIONS.length - 1
|
|
918
|
-
? {
|
|
919
|
-
borderBottomWidth: 1,
|
|
920
|
-
borderBottomColor: colors.border,
|
|
921
|
-
}
|
|
922
|
-
: undefined,
|
|
923
|
-
]}
|
|
924
|
-
>
|
|
925
|
-
<View style={styles.metricMatrixLabel}>
|
|
926
|
-
<Text style={[styles.metricMatrixTitle, { color: colors.foreground }]}>
|
|
927
|
-
{def.title}
|
|
928
|
-
</Text>
|
|
929
|
-
{note ? (
|
|
930
|
-
<Text style={[styles.metricMatrixNote, { color: colors.foregroundMuted }]}>
|
|
931
|
-
{note}
|
|
932
|
-
</Text>
|
|
933
|
-
) : null}
|
|
934
|
-
</View>
|
|
935
|
-
<View style={[styles.metricMatrixTargets, isCompact && styles.metricMatrixTargetsCompact]}>
|
|
936
|
-
<Toggle
|
|
937
|
-
value={boxes.pill}
|
|
938
|
-
disabled={disabled}
|
|
939
|
-
onValueChange={(val) => setBox("pill", val)}
|
|
940
|
-
style={styles.matrixToggle}
|
|
941
|
-
/>
|
|
942
|
-
<Toggle
|
|
943
|
-
value={boxes.timeline && !def.pillOnly}
|
|
944
|
-
disabled={disabled || timelineDisabled}
|
|
945
|
-
onValueChange={(val) => setBox("timeline", val)}
|
|
946
|
-
style={styles.matrixToggle}
|
|
947
|
-
/>
|
|
948
|
-
</View>
|
|
949
|
-
</View>
|
|
950
|
-
);
|
|
951
|
-
})}
|
|
952
|
-
{customPills.map((pill) => {
|
|
953
|
-
const masterOn = settings.showCustomPills ?? true;
|
|
954
|
-
const enabled = customPillEffectiveEnabled(masterOn, customOverrides, pill);
|
|
955
|
-
return (
|
|
956
|
-
<View
|
|
957
|
-
key={`custom-${pill.id}`}
|
|
958
|
-
style={styles.metricMatrixRow}
|
|
959
|
-
>
|
|
960
|
-
<View style={styles.metricMatrixLabel}>
|
|
961
|
-
<Text style={[styles.metricMatrixTitle, { color: colors.foreground }]}>
|
|
962
|
-
{pill.title}
|
|
963
|
-
</Text>
|
|
964
|
-
<Text style={[styles.metricMatrixNote, { color: colors.foregroundMuted }]}>
|
|
965
|
-
custom pill
|
|
966
|
-
</Text>
|
|
967
|
-
</View>
|
|
968
|
-
<View style={[styles.metricMatrixTargets, isCompact && styles.metricMatrixTargetsCompact]}>
|
|
969
|
-
<Toggle
|
|
970
|
-
value={enabled}
|
|
971
|
-
disabled={!masterOn}
|
|
972
|
-
onValueChange={(val) => onCustomToggle(pill.id, val)}
|
|
973
|
-
style={styles.matrixToggle}
|
|
974
|
-
/>
|
|
975
|
-
<Toggle
|
|
976
|
-
value={false}
|
|
977
|
-
disabled={true}
|
|
978
|
-
onValueChange={() => {}}
|
|
979
|
-
style={styles.matrixToggle}
|
|
980
|
-
/>
|
|
981
|
-
</View>
|
|
982
|
-
</View>
|
|
983
|
-
);
|
|
984
|
-
})}
|
|
985
|
-
</View>
|
|
957
|
+
<MultiChoiceChips
|
|
958
|
+
options={customPills.map((pill) => ({
|
|
959
|
+
id: pill.id,
|
|
960
|
+
label: pill.title,
|
|
961
|
+
icon: "Sliders",
|
|
962
|
+
disabled: !masterOn,
|
|
963
|
+
}))}
|
|
964
|
+
selected={customPills
|
|
965
|
+
.filter((pill) => customPillEffectiveEnabled(masterOn, customOverrides, pill))
|
|
966
|
+
.map((pill) => pill.id)}
|
|
967
|
+
onToggle={(pillId) => {
|
|
968
|
+
triggerHaptic("light");
|
|
969
|
+
const pill = customPills.find((p) => p.id === pillId);
|
|
970
|
+
if (!pill) return;
|
|
971
|
+
const current = customPillEffectiveEnabled(masterOn, customOverrides, pill);
|
|
972
|
+
onCustomToggle(pillId, !current);
|
|
973
|
+
}}
|
|
974
|
+
/>
|
|
975
|
+
</HostStack>
|
|
976
|
+
)}
|
|
977
|
+
</HostStack>
|
|
986
978
|
);
|
|
987
979
|
}
|
|
988
980
|
|
|
989
|
-
function ResourceModal(
|
|
990
|
-
|
|
981
|
+
function ResourceModal(props: ResourceModalProps) {
|
|
982
|
+
return (
|
|
983
|
+
<HostThemeProvider theme={props.theme}>
|
|
984
|
+
<HostLayoutProvider layout={props.layout}>
|
|
985
|
+
<ResourceModalBody {...props} />
|
|
986
|
+
</HostLayoutProvider>
|
|
987
|
+
</HostThemeProvider>
|
|
988
|
+
);
|
|
989
|
+
}
|
|
990
|
+
|
|
991
|
+
function ResourceModalBody({ workspaceId, agentId, initialTab, payload, theme, layout }: ResourceModalProps) {
|
|
992
|
+
const { colors } = useHostTheme();
|
|
993
|
+
const { compact } = useHostLayout();
|
|
994
|
+
// Host-density padding rhythm (the helper's "comfortable" scale): the host
|
|
995
|
+
// owns density now, so the modal keeps the same numeric values locally.
|
|
996
|
+
const padding = compact
|
|
997
|
+
? { horizontal: 12, vertical: 10, gap: 8 }
|
|
998
|
+
: { horizontal: 16, vertical: 14, gap: 12 };
|
|
991
999
|
// Settings re-verify on mount/focus via hook defaults; the settings tab
|
|
992
1000
|
// refetches explicitly below. No background poll: the modal only lives
|
|
993
1001
|
// while open. Custom-pill definitions are a separate data source and keep
|
|
@@ -1063,18 +1071,7 @@ function ResourceModal({ theme, workspaceId, agentId, initialTab, payload }: Res
|
|
|
1063
1071
|
});
|
|
1064
1072
|
}, [agentId, data, agent, workspace?.directory]);
|
|
1065
1073
|
|
|
1066
|
-
const hasAnyPillEnabled =
|
|
1067
|
-
flags.showCpuRam ||
|
|
1068
|
-
flags.showBranch ||
|
|
1069
|
-
flags.showWorktree ||
|
|
1070
|
-
flags.showAgentTitle ||
|
|
1071
|
-
flags.showAgent ||
|
|
1072
|
-
flags.showAgentProvider ||
|
|
1073
|
-
flags.showAgentActivity ||
|
|
1074
|
-
flags.showAgentId ||
|
|
1075
|
-
flags.showLoad ||
|
|
1076
|
-
flags.showUptime ||
|
|
1077
|
-
isMcpEnabled;
|
|
1074
|
+
const hasAnyPillEnabled = hasAnyLegacyPillFlagEnabled(flags) || isMcpEnabled;
|
|
1078
1075
|
|
|
1079
1076
|
const handleRefresh = () => {
|
|
1080
1077
|
triggerHaptic("light");
|
|
@@ -1088,8 +1085,8 @@ function ResourceModal({ theme, workspaceId, agentId, initialTab, payload }: Res
|
|
|
1088
1085
|
};
|
|
1089
1086
|
|
|
1090
1087
|
const navbar = (
|
|
1091
|
-
<
|
|
1092
|
-
tabs={
|
|
1088
|
+
<HostTabs
|
|
1089
|
+
tabs={[...MODAL_TABS]}
|
|
1093
1090
|
activeTab={activeTab}
|
|
1094
1091
|
onTabChange={handleTabChange}
|
|
1095
1092
|
/>
|
|
@@ -1099,235 +1096,251 @@ function ResourceModal({ theme, workspaceId, agentId, initialTab, payload }: Res
|
|
|
1099
1096
|
paddingHorizontal: padding.horizontal,
|
|
1100
1097
|
paddingTop: padding.vertical,
|
|
1101
1098
|
paddingBottom: Math.round(padding.gap / 2),
|
|
1102
|
-
|
|
1099
|
+
position: "sticky" as const,
|
|
1100
|
+
top: 0,
|
|
1101
|
+
zIndex: 10,
|
|
1102
|
+
} as any;
|
|
1103
1103
|
|
|
1104
1104
|
if (isError && !data) {
|
|
1105
1105
|
return (
|
|
1106
|
-
<
|
|
1107
|
-
style={
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
<Icon name="Ghost" size={24} color={colors.statusDanger} />
|
|
1119
|
-
<Text style={[styles.errorText, { color: colors.statusDanger }]}>
|
|
1120
|
-
{error instanceof Error ? error.message : "Failed to load metrics"}
|
|
1121
|
-
</Text>
|
|
1106
|
+
<HostModalSection>
|
|
1107
|
+
<View style={styles.modalColumn}>
|
|
1108
|
+
<View style={navbarStyle}>{navbar}</View>
|
|
1109
|
+
<View style={styles.modalContent}>
|
|
1110
|
+
<HostCard variant="elevated">
|
|
1111
|
+
<View style={styles.errorBox}>
|
|
1112
|
+
<Icon name="Ghost" size={24} color={colors.statusDanger} />
|
|
1113
|
+
<Text style={[styles.errorText, { color: colors.statusDanger }]}>
|
|
1114
|
+
{error instanceof Error ? error.message : "Failed to load metrics"}
|
|
1115
|
+
</Text>
|
|
1116
|
+
</View>
|
|
1117
|
+
</HostCard>
|
|
1122
1118
|
</View>
|
|
1123
|
-
</
|
|
1124
|
-
</
|
|
1119
|
+
</View>
|
|
1120
|
+
</HostModalSection>
|
|
1125
1121
|
);
|
|
1126
1122
|
}
|
|
1127
1123
|
|
|
1128
1124
|
const { cpuColor, memColor } = getMetricColors(data, colors);
|
|
1129
1125
|
|
|
1130
1126
|
return (
|
|
1131
|
-
<
|
|
1132
|
-
style={
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
<ProgressBar
|
|
1191
|
-
value={data?.cpuUsagePercent ?? 0}
|
|
1192
|
-
thresholds={CPU_THRESHOLDS}
|
|
1193
|
-
height={8}
|
|
1194
|
-
/>
|
|
1127
|
+
<HostModalSection>
|
|
1128
|
+
<View style={styles.modalColumn}>
|
|
1129
|
+
<View style={navbarStyle}>{navbar}</View>
|
|
1130
|
+
<View style={styles.modalContent}>
|
|
1131
|
+
{activeTab === "system" && (
|
|
1132
|
+
<>
|
|
1133
|
+
{/* Dual Metric Gauges Hero */}
|
|
1134
|
+
<HostCard variant="elevated">
|
|
1135
|
+
<HostRow justify="between" align="center" style={styles.gaugeContainer}>
|
|
1136
|
+
<HostMetricGauge
|
|
1137
|
+
value={data?.cpuUsagePercent ?? 0}
|
|
1138
|
+
thresholds={CPU_THRESHOLDS}
|
|
1139
|
+
label="CPU Load"
|
|
1140
|
+
size={72}
|
|
1141
|
+
/>
|
|
1142
|
+
<HostMetricGauge
|
|
1143
|
+
value={data?.memoryUsedPercent ?? 0}
|
|
1144
|
+
thresholds={MEM_THRESHOLDS}
|
|
1145
|
+
label="RAM Used"
|
|
1146
|
+
size={72}
|
|
1147
|
+
/>
|
|
1148
|
+
</HostRow>
|
|
1149
|
+
</HostCard>
|
|
1150
|
+
|
|
1151
|
+
{/* Host Meta Card */}
|
|
1152
|
+
<HostCard variant="elevated">
|
|
1153
|
+
<HostStack gap={12}>
|
|
1154
|
+
<HostKeyValue
|
|
1155
|
+
label="Host"
|
|
1156
|
+
value={data?.hostname ?? "Unknown"}
|
|
1157
|
+
copyable
|
|
1158
|
+
{...compactKvProps}
|
|
1159
|
+
/>
|
|
1160
|
+
<HostKeyValue
|
|
1161
|
+
label="Uptime"
|
|
1162
|
+
value={data?.uptimeSeconds ? formatUptime(data?.uptimeSeconds) : "--"}
|
|
1163
|
+
{...compactKvProps}
|
|
1164
|
+
/>
|
|
1165
|
+
</HostStack>
|
|
1166
|
+
<HostKeyValue
|
|
1167
|
+
label="Processor"
|
|
1168
|
+
value={data?.cpuModel ?? "--"}
|
|
1169
|
+
subValue={data?.cpuCores ? `(${data?.cpuCores} cores)` : undefined}
|
|
1170
|
+
{...compactKvProps}
|
|
1171
|
+
/>
|
|
1172
|
+
</HostCard>
|
|
1173
|
+
|
|
1174
|
+
{/* CPU Utilization Card */}
|
|
1175
|
+
<HostCard variant="elevated">
|
|
1176
|
+
<HostCardHeader
|
|
1177
|
+
title="CPU Details"
|
|
1178
|
+
{...compactCardTitleProp}
|
|
1179
|
+
value={
|
|
1180
|
+
<Text style={[styles.metricHighlight, { color: cpuColor }]}>
|
|
1181
|
+
{data?.cpuUsagePercent ?? 0}%
|
|
1182
|
+
</Text>
|
|
1183
|
+
}
|
|
1184
|
+
/>
|
|
1195
1185
|
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
</Card>
|
|
1186
|
+
<HostProgressBar
|
|
1187
|
+
value={data?.cpuUsagePercent ?? 0}
|
|
1188
|
+
thresholds={CPU_THRESHOLDS}
|
|
1189
|
+
height={8}
|
|
1190
|
+
/>
|
|
1202
1191
|
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1192
|
+
<HostKeyValue
|
|
1193
|
+
label="Load Average (1m, 5m, 15m)"
|
|
1194
|
+
value={data?.loadAvg ? data?.loadAvg.map((n) => n.toFixed(2)).join(" ") : "-- -- --"}
|
|
1195
|
+
mono
|
|
1196
|
+
{...compactKvProps}
|
|
1197
|
+
/>
|
|
1198
|
+
</HostCard>
|
|
1199
|
+
|
|
1200
|
+
{/* Memory Card */}
|
|
1201
|
+
<HostCard variant="elevated">
|
|
1202
|
+
<HostCardHeader
|
|
1203
|
+
title="Memory Details"
|
|
1204
|
+
{...compactCardTitleProp}
|
|
1205
|
+
value={
|
|
1206
|
+
<Text style={[styles.metricHighlight, { color: memColor }]}>
|
|
1207
|
+
{data?.memoryUsedPercent ?? 0}%
|
|
1208
|
+
</Text>
|
|
1209
|
+
}
|
|
1210
|
+
/>
|
|
1213
1211
|
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1212
|
+
<HostProgressBar
|
|
1213
|
+
value={data?.memoryUsedPercent ?? 0}
|
|
1214
|
+
thresholds={MEM_THRESHOLDS}
|
|
1215
|
+
height={8}
|
|
1216
|
+
/>
|
|
1219
1217
|
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1218
|
+
<HostKeyValue
|
|
1219
|
+
label="Used / Total"
|
|
1220
|
+
value={`${formatBytes(data?.memoryUsedBytes ?? 0)} / ${formatBytes(data?.memoryTotalBytes ?? 0)}`}
|
|
1221
|
+
{...compactKvProps}
|
|
1222
|
+
/>
|
|
1223
|
+
</HostCard>
|
|
1224
|
+
|
|
1225
|
+
{/* MCP Servers Card */}
|
|
1226
|
+
{Boolean(data?.mcpInstalled) && (
|
|
1227
|
+
<HostCard variant="elevated">
|
|
1228
|
+
<HostCardHeader
|
|
1229
|
+
title="MCP Servers"
|
|
1230
|
+
subtitle="Source: paseo-mcp-tools"
|
|
1231
|
+
icon="Server"
|
|
1232
|
+
{...compactCardTitleProp}
|
|
1233
|
+
value={
|
|
1234
|
+
data?.mcp ? (
|
|
1235
|
+
<HostBadge
|
|
1236
|
+
label={data?.mcp.isStale ? "Stale Snapshot" : "Live"}
|
|
1237
|
+
variant={data?.mcp.isStale ? "warning" : "success"}
|
|
1238
|
+
dot
|
|
1239
|
+
{...compactBadgeProp}
|
|
1240
|
+
/>
|
|
1241
|
+
) : (
|
|
1242
|
+
<HostBadge
|
|
1243
|
+
label="No Data"
|
|
1244
|
+
variant="neutral"
|
|
1245
|
+
{...compactBadgeProp}
|
|
1246
|
+
/>
|
|
1247
|
+
)
|
|
1248
|
+
}
|
|
1239
1249
|
/>
|
|
1240
|
-
) : (
|
|
1241
|
-
<CompactBadge label="No Data" variant="neutral" />
|
|
1242
|
-
)
|
|
1243
|
-
}
|
|
1244
|
-
/>
|
|
1245
1250
|
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1251
|
+
{data?.mcp ? (
|
|
1252
|
+
<>
|
|
1253
|
+
<HostStack gap={12}>
|
|
1254
|
+
<HostKeyValue
|
|
1255
|
+
label="Health"
|
|
1256
|
+
value={`${data?.mcp.healthy} healthy / ${data?.mcp.total} total`}
|
|
1257
|
+
{...compactKvProps}
|
|
1258
|
+
/>
|
|
1259
|
+
<HostKeyValue
|
|
1260
|
+
label="Snapshot Updated"
|
|
1261
|
+
value={formatTimeAgo(data?.mcp.updatedAt)}
|
|
1262
|
+
{...compactKvProps}
|
|
1263
|
+
/>
|
|
1264
|
+
<HostKeyValue
|
|
1265
|
+
label="Data Provider"
|
|
1266
|
+
value="paseo-mcp-tools"
|
|
1267
|
+
{...compactKvProps}
|
|
1268
|
+
/>
|
|
1269
|
+
</HostStack>
|
|
1270
|
+
|
|
1271
|
+
{data?.mcp.servers && data?.mcp.servers.length > 0 ? (
|
|
1272
|
+
<View style={styles.mcpList}>
|
|
1273
|
+
{data?.mcp.servers.map((srv) => {
|
|
1274
|
+
const badgeVariant: "success" | "warning" | "danger" | "neutral" =
|
|
1275
|
+
srv.status === "healthy"
|
|
1276
|
+
? "success"
|
|
1277
|
+
: srv.status === "degraded"
|
|
1278
|
+
? "warning"
|
|
1279
|
+
: srv.status === "down"
|
|
1280
|
+
? "danger"
|
|
1281
|
+
: "neutral";
|
|
1282
|
+
return (
|
|
1283
|
+
<HostRow
|
|
1284
|
+
key={srv.name}
|
|
1285
|
+
justify="between"
|
|
1286
|
+
align="center"
|
|
1287
|
+
style={styles.mcpRow}
|
|
1288
|
+
>
|
|
1289
|
+
<HostRow gap={8} align="center" style={styles.mcpInfo}>
|
|
1290
|
+
<Text
|
|
1291
|
+
numberOfLines={1}
|
|
1292
|
+
style={[styles.mcpName, { color: colors.foreground }]}
|
|
1293
|
+
>
|
|
1294
|
+
{srv.name}
|
|
1295
|
+
</Text>
|
|
1296
|
+
<Text style={[styles.mcpLatency, { color: colors.foregroundMuted }]}>
|
|
1297
|
+
{srv.latencyMs >= 0 ? `${srv.latencyMs}ms` : "timeout"}
|
|
1298
|
+
</Text>
|
|
1299
|
+
</HostRow>
|
|
1300
|
+
<HostBadge {...compactBadgeProp} label={srv.status} variant={badgeVariant} />
|
|
1301
|
+
</HostRow>
|
|
1302
|
+
);
|
|
1303
|
+
})}
|
|
1288
1304
|
</View>
|
|
1289
|
-
)
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
)}
|
|
1303
|
-
</Card>
|
|
1304
|
-
)}
|
|
1305
|
+
) : (
|
|
1306
|
+
<Text style={[styles.mcpEmpty, { color: colors.foregroundMuted }]}>
|
|
1307
|
+
No MCP servers configured
|
|
1308
|
+
</Text>
|
|
1309
|
+
)}
|
|
1310
|
+
</>
|
|
1311
|
+
) : (
|
|
1312
|
+
<Text style={[styles.mcpEmpty, { color: colors.foregroundMuted }]}>
|
|
1313
|
+
Waiting for status snapshot from paseo-mcp-tools...
|
|
1314
|
+
</Text>
|
|
1315
|
+
)}
|
|
1316
|
+
</HostCard>
|
|
1317
|
+
)}
|
|
1305
1318
|
|
|
1306
1319
|
{/* Custom Metric Pills Card */}
|
|
1307
1320
|
{Boolean(data?.customPills && data?.customPills.length > 0) && (
|
|
1308
|
-
<
|
|
1309
|
-
<
|
|
1321
|
+
<HostCard variant="elevated">
|
|
1322
|
+
<HostCardHeader {...compactCardTitleProp}
|
|
1310
1323
|
title="Custom Metric Pills"
|
|
1311
1324
|
subtitle="Discovered from ~/.paseo/top/pills"
|
|
1312
1325
|
icon="Sliders"
|
|
1313
1326
|
value={
|
|
1314
|
-
<
|
|
1327
|
+
<HostBadge {...compactBadgeProp}
|
|
1315
1328
|
label={`${data?.customPills?.length ?? 0} active`}
|
|
1316
1329
|
variant="accent"
|
|
1317
1330
|
/>
|
|
1318
1331
|
}
|
|
1319
1332
|
/>
|
|
1320
|
-
<
|
|
1333
|
+
<HostStack gap={12}>
|
|
1321
1334
|
{(data?.customPills ?? []).map((cp) => (
|
|
1322
|
-
<
|
|
1335
|
+
<HostKeyValue {...compactKvProps}
|
|
1323
1336
|
key={cp.id}
|
|
1324
1337
|
label={cp.title}
|
|
1325
1338
|
value={cp.displayValue}
|
|
1326
1339
|
subValue={cp.status !== "neutral" ? `(${cp.status})` : undefined}
|
|
1327
1340
|
/>
|
|
1328
1341
|
))}
|
|
1329
|
-
</
|
|
1330
|
-
</
|
|
1342
|
+
</HostStack>
|
|
1343
|
+
</HostCard>
|
|
1331
1344
|
)}
|
|
1332
1345
|
</>
|
|
1333
1346
|
)}
|
|
@@ -1335,48 +1348,48 @@ function ResourceModal({ theme, workspaceId, agentId, initialTab, payload }: Res
|
|
|
1335
1348
|
{activeTab === "context" && (
|
|
1336
1349
|
<>
|
|
1337
1350
|
{/* Workspace Information */}
|
|
1338
|
-
<
|
|
1339
|
-
<
|
|
1351
|
+
<HostCard variant="elevated">
|
|
1352
|
+
<HostCardHeader {...compactCardTitleProp}
|
|
1340
1353
|
title="Workspace & Git"
|
|
1341
1354
|
icon="GitBranch"
|
|
1342
1355
|
value={
|
|
1343
1356
|
workspace?.status ? (
|
|
1344
|
-
<
|
|
1357
|
+
<HostBadge {...compactBadgeProp} label={workspace.status} variant="info" />
|
|
1345
1358
|
) : undefined
|
|
1346
1359
|
}
|
|
1347
1360
|
/>
|
|
1348
|
-
<
|
|
1349
|
-
<
|
|
1350
|
-
<
|
|
1351
|
-
</
|
|
1361
|
+
<HostStack gap={12}>
|
|
1362
|
+
<HostKeyValue {...compactKvProps} label="Git Branch" value={data?.branch || "Unknown"} />
|
|
1363
|
+
<HostKeyValue {...compactKvProps} label="Kind" value={workspace?.kind || "Unknown"} />
|
|
1364
|
+
</HostStack>
|
|
1352
1365
|
{workspace?.directory ? (
|
|
1353
|
-
<
|
|
1366
|
+
<HostKeyValue {...compactKvProps} label="Worktree Location" value={workspace.directory} copyable mono />
|
|
1354
1367
|
) : null}
|
|
1355
1368
|
{workspace?.name ? (
|
|
1356
|
-
<
|
|
1369
|
+
<HostKeyValue {...compactKvProps} label="Workspace Name" value={workspace.name} />
|
|
1357
1370
|
) : null}
|
|
1358
1371
|
{workspace?.title && workspace.title !== workspace.name ? (
|
|
1359
|
-
<
|
|
1372
|
+
<HostKeyValue {...compactKvProps} label="Workspace Title" value={workspace.title} />
|
|
1360
1373
|
) : null}
|
|
1361
1374
|
{workspace?.projectDisplayName ? (
|
|
1362
|
-
<
|
|
1375
|
+
<HostKeyValue {...compactKvProps} label="Project" value={workspace.projectDisplayName} />
|
|
1363
1376
|
) : null}
|
|
1364
1377
|
{workspace?.diffStat ? (
|
|
1365
|
-
<
|
|
1378
|
+
<HostKeyValue {...compactKvProps}
|
|
1366
1379
|
label="Git Changes"
|
|
1367
1380
|
value={`+${workspace.diffStat.additions} -${workspace.diffStat.deletions}`}
|
|
1368
1381
|
/>
|
|
1369
1382
|
) : null}
|
|
1370
|
-
</
|
|
1383
|
+
</HostCard>
|
|
1371
1384
|
|
|
1372
1385
|
{/* Agent Information */}
|
|
1373
|
-
<
|
|
1374
|
-
<
|
|
1386
|
+
<HostCard variant="elevated">
|
|
1387
|
+
<HostCardHeader {...compactCardTitleProp}
|
|
1375
1388
|
title={agent?.title ? `Agent: ${agent.title}` : "Agent Session"}
|
|
1376
1389
|
icon="Bot"
|
|
1377
1390
|
value={
|
|
1378
1391
|
agent?.status ? (
|
|
1379
|
-
<
|
|
1392
|
+
<HostBadge {...compactBadgeProp}
|
|
1380
1393
|
label={agent.status}
|
|
1381
1394
|
variant={agent.status === "running" ? "success" : "info"}
|
|
1382
1395
|
/>
|
|
@@ -1384,17 +1397,17 @@ function ResourceModal({ theme, workspaceId, agentId, initialTab, payload }: Res
|
|
|
1384
1397
|
}
|
|
1385
1398
|
/>
|
|
1386
1399
|
{agent?.title ? (
|
|
1387
|
-
<
|
|
1400
|
+
<HostKeyValue {...compactKvProps} label="Agent Tab" value={agent.title} />
|
|
1388
1401
|
) : null}
|
|
1389
1402
|
{agentId ? (
|
|
1390
|
-
<
|
|
1403
|
+
<HostKeyValue {...compactKvProps} label="Agent ID" value={agentId} copyable mono />
|
|
1391
1404
|
) : null}
|
|
1392
|
-
<
|
|
1393
|
-
<
|
|
1394
|
-
<
|
|
1395
|
-
</
|
|
1396
|
-
<
|
|
1397
|
-
<
|
|
1405
|
+
<HostStack gap={12}>
|
|
1406
|
+
<HostKeyValue {...compactKvProps} label="Model" value={agent?.model || "Standard"} />
|
|
1407
|
+
<HostKeyValue {...compactKvProps} label="Provider" value={agent?.provider || "Default"} />
|
|
1408
|
+
</HostStack>
|
|
1409
|
+
<HostStack gap={12}>
|
|
1410
|
+
<HostKeyValue {...compactKvProps}
|
|
1398
1411
|
label="Last Worked"
|
|
1399
1412
|
value={
|
|
1400
1413
|
agent?.status === "running"
|
|
@@ -1402,7 +1415,7 @@ function ResourceModal({ theme, workspaceId, agentId, initialTab, payload }: Res
|
|
|
1402
1415
|
: formatTimeAgo(agent?.lastActivityAt)
|
|
1403
1416
|
}
|
|
1404
1417
|
/>
|
|
1405
|
-
<
|
|
1418
|
+
<HostKeyValue {...compactKvProps}
|
|
1406
1419
|
label="Inactivity"
|
|
1407
1420
|
value={
|
|
1408
1421
|
agent?.status === "running"
|
|
@@ -1410,25 +1423,25 @@ function ResourceModal({ theme, workspaceId, agentId, initialTab, payload }: Res
|
|
|
1410
1423
|
: formatIdleDuration(agent?.lastActivityAt)
|
|
1411
1424
|
}
|
|
1412
1425
|
/>
|
|
1413
|
-
</
|
|
1426
|
+
</HostStack>
|
|
1414
1427
|
{agent?.cwd ? (
|
|
1415
|
-
<
|
|
1428
|
+
<HostKeyValue {...compactKvProps} label="Working Directory" value={agent.cwd} copyable mono />
|
|
1416
1429
|
) : null}
|
|
1417
|
-
</
|
|
1430
|
+
</HostCard>
|
|
1418
1431
|
|
|
1419
1432
|
{/* Token Usage & Context Window */}
|
|
1420
|
-
<
|
|
1421
|
-
<
|
|
1433
|
+
<HostCard variant="elevated">
|
|
1434
|
+
<HostCardHeader {...compactCardTitleProp}
|
|
1422
1435
|
title="Tokens & Context Window"
|
|
1423
1436
|
icon="Coins"
|
|
1424
1437
|
value={
|
|
1425
1438
|
contextPercent != null ? (
|
|
1426
|
-
<
|
|
1439
|
+
<HostBadge {...compactBadgeProp}
|
|
1427
1440
|
label={`${contextPercent}% ctx`}
|
|
1428
1441
|
variant={contextPercent >= 85 ? "danger" : contextPercent >= 70 ? "warning" : "success"}
|
|
1429
1442
|
/>
|
|
1430
1443
|
) : tokenMetrics?.totalTokens != null ? (
|
|
1431
|
-
<
|
|
1444
|
+
<HostBadge {...compactBadgeProp}
|
|
1432
1445
|
label={`${formatCompactTokens(tokenMetrics.totalTokens)} tok`}
|
|
1433
1446
|
variant="neutral"
|
|
1434
1447
|
/>
|
|
@@ -1438,67 +1451,67 @@ function ResourceModal({ theme, workspaceId, agentId, initialTab, payload }: Res
|
|
|
1438
1451
|
|
|
1439
1452
|
{tokenMetrics?.contextMaxTokens != null && tokenMetrics.contextMaxTokens > 0 ? (
|
|
1440
1453
|
<View style={styles.contextUsageBlock}>
|
|
1441
|
-
<
|
|
1454
|
+
<HostRow justify="between" align="center" style={styles.contextUsageRow}>
|
|
1442
1455
|
<Text style={[styles.compactKvLabel, { color: colors.foregroundMuted }]}>Context Utilization</Text>
|
|
1443
1456
|
<Text style={[styles.compactKvValue, { color: colors.foreground, fontWeight: "600" }]}>
|
|
1444
1457
|
{formatCompactTokens(tokenMetrics.contextUsedTokens ?? 0)} / {formatCompactTokens(tokenMetrics.contextMaxTokens)} ({contextPercent}%)
|
|
1445
1458
|
</Text>
|
|
1446
|
-
</
|
|
1447
|
-
<
|
|
1459
|
+
</HostRow>
|
|
1460
|
+
<HostProgressBar
|
|
1448
1461
|
value={contextPercent ?? 0}
|
|
1449
1462
|
thresholds={{ warning: 70, danger: 85 }}
|
|
1450
1463
|
height={8}
|
|
1451
1464
|
/>
|
|
1452
1465
|
</View>
|
|
1453
1466
|
) : tokenMetrics?.contextUsedTokens != null ? (
|
|
1454
|
-
<
|
|
1467
|
+
<HostKeyValue {...compactKvProps}
|
|
1455
1468
|
label="Context Used"
|
|
1456
|
-
value={`${tokenMetrics.contextUsedTokens.toLocaleString()} (${formatCompactTokens(tokenMetrics.contextUsedTokens)})`}
|
|
1469
|
+
value={`${tokenMetrics.contextUsedTokens.toLocaleString('en-US')} (${formatCompactTokens(tokenMetrics.contextUsedTokens)})`}
|
|
1457
1470
|
/>
|
|
1458
1471
|
) : null}
|
|
1459
1472
|
|
|
1460
|
-
<
|
|
1461
|
-
<
|
|
1473
|
+
<HostStack gap={12}>
|
|
1474
|
+
<HostKeyValue {...compactKvProps}
|
|
1462
1475
|
label="Input Tokens"
|
|
1463
|
-
value={tokenMetrics?.inputTokens != null ? tokenMetrics.inputTokens.toLocaleString() : "--"}
|
|
1476
|
+
value={tokenMetrics?.inputTokens != null ? tokenMetrics.inputTokens.toLocaleString('en-US') : "--"}
|
|
1464
1477
|
subValue={tokenMetrics?.inputTokens != null ? formatCompactTokens(tokenMetrics.inputTokens) : undefined}
|
|
1465
1478
|
/>
|
|
1466
|
-
<
|
|
1479
|
+
<HostKeyValue {...compactKvProps}
|
|
1467
1480
|
label="Output Tokens"
|
|
1468
|
-
value={tokenMetrics?.outputTokens != null ? tokenMetrics.outputTokens.toLocaleString() : "--"}
|
|
1481
|
+
value={tokenMetrics?.outputTokens != null ? tokenMetrics.outputTokens.toLocaleString('en-US') : "--"}
|
|
1469
1482
|
subValue={tokenMetrics?.outputTokens != null ? formatCompactTokens(tokenMetrics.outputTokens) : undefined}
|
|
1470
1483
|
/>
|
|
1471
1484
|
{tokenMetrics?.cachedTokens != null && (
|
|
1472
|
-
<
|
|
1485
|
+
<HostKeyValue {...compactKvProps}
|
|
1473
1486
|
label="Cached Tokens"
|
|
1474
|
-
value={tokenMetrics.cachedTokens.toLocaleString()}
|
|
1487
|
+
value={tokenMetrics.cachedTokens.toLocaleString('en-US')}
|
|
1475
1488
|
subValue={formatCompactTokens(tokenMetrics.cachedTokens)}
|
|
1476
1489
|
/>
|
|
1477
1490
|
)}
|
|
1478
1491
|
{tokenMetrics?.costUsd != null && (
|
|
1479
|
-
<
|
|
1492
|
+
<HostKeyValue {...compactKvProps}
|
|
1480
1493
|
label="Session / Turn Cost"
|
|
1481
1494
|
value={`$${tokenMetrics.costUsd < 0.01 ? tokenMetrics.costUsd.toFixed(4) : tokenMetrics.costUsd.toFixed(2)}`}
|
|
1482
1495
|
/>
|
|
1483
1496
|
)}
|
|
1484
|
-
</
|
|
1497
|
+
</HostStack>
|
|
1485
1498
|
{!tokenMetrics && (
|
|
1486
1499
|
<Text style={[styles.mcpEmpty, { color: colors.foregroundMuted, marginTop: 4 }]}>
|
|
1487
1500
|
No token usage recorded for this agent session yet
|
|
1488
1501
|
</Text>
|
|
1489
1502
|
)}
|
|
1490
|
-
</
|
|
1503
|
+
</HostCard>
|
|
1491
1504
|
</>
|
|
1492
1505
|
)}
|
|
1493
1506
|
|
|
1494
1507
|
{activeTab === "settings" && (
|
|
1495
1508
|
<>
|
|
1496
1509
|
{/* Pill Display Mode */}
|
|
1497
|
-
<
|
|
1498
|
-
<
|
|
1510
|
+
<HostCard variant="elevated">
|
|
1511
|
+
<HostCardHeader {...compactCardTitleProp}
|
|
1499
1512
|
title="Pill Display Mode"
|
|
1500
1513
|
icon="LayoutGrid"
|
|
1501
|
-
subtitle="How active items appear in the composer
|
|
1514
|
+
subtitle="How active items appear in the composer"
|
|
1502
1515
|
/>
|
|
1503
1516
|
<ChoiceChips
|
|
1504
1517
|
options={[
|
|
@@ -1515,7 +1528,7 @@ function ResourceModal({ theme, workspaceId, agentId, initialTab, payload }: Res
|
|
|
1515
1528
|
}}
|
|
1516
1529
|
/>
|
|
1517
1530
|
<View style={styles.settingsSpacer}>
|
|
1518
|
-
<
|
|
1531
|
+
<HostToggle
|
|
1519
1532
|
label="Show Composer Pill"
|
|
1520
1533
|
description="Hide the composer pill entirely; the dashboard stays available from the sidebar"
|
|
1521
1534
|
style={styles.toggleFullWidth}
|
|
@@ -1527,13 +1540,18 @@ function ResourceModal({ theme, workspaceId, agentId, initialTab, payload }: Res
|
|
|
1527
1540
|
}}
|
|
1528
1541
|
/>
|
|
1529
1542
|
</View>
|
|
1530
|
-
</
|
|
1543
|
+
</HostCard>
|
|
1531
1544
|
|
|
1532
1545
|
{/* Active Pill Items Selectors */}
|
|
1533
|
-
<
|
|
1534
|
-
<
|
|
1546
|
+
<HostCard variant="elevated">
|
|
1547
|
+
<HostCardHeader {...compactCardTitleProp}
|
|
1535
1548
|
title="Active Pill Items"
|
|
1536
1549
|
icon="Sliders"
|
|
1550
|
+
value={
|
|
1551
|
+
<Text style={[styles.accentValueText, { color: colors.accent }]}>
|
|
1552
|
+
{`${METRIC_DEFINITIONS.filter((d) => isPillEnabled((settings.metricSurfaces ?? DEFAULT_METRIC_SURFACES)[d.id])).length} active`}
|
|
1553
|
+
</Text>
|
|
1554
|
+
}
|
|
1537
1555
|
subtitle={
|
|
1538
1556
|
!hasAnyPillEnabled
|
|
1539
1557
|
? "None selected -- automatically showing CPU & RAM"
|
|
@@ -1545,12 +1563,11 @@ function ResourceModal({ theme, workspaceId, agentId, initialTab, payload }: Res
|
|
|
1545
1563
|
}
|
|
1546
1564
|
/>
|
|
1547
1565
|
<View style={styles.settingsToggles}>
|
|
1548
|
-
<
|
|
1566
|
+
<MetricPillSelector
|
|
1549
1567
|
settings={settings}
|
|
1550
1568
|
updateSettings={updateSettings}
|
|
1551
1569
|
notifySettingsChanged={notifySettingsChanged}
|
|
1552
1570
|
mcpInstalled={Boolean(data?.mcpInstalled)}
|
|
1553
|
-
mcpRunning={data?.mcpRunning ?? null}
|
|
1554
1571
|
customPills={(customPillList?.pills ?? []).map((pill) => ({
|
|
1555
1572
|
id: pill.id,
|
|
1556
1573
|
title: pill.title,
|
|
@@ -1566,17 +1583,17 @@ function ResourceModal({ theme, workspaceId, agentId, initialTab, payload }: Res
|
|
|
1566
1583
|
}}
|
|
1567
1584
|
/>
|
|
1568
1585
|
</View>
|
|
1569
|
-
</
|
|
1586
|
+
</HostCard>
|
|
1570
1587
|
|
|
1571
1588
|
{/* Custom Metric Pills */}
|
|
1572
|
-
<
|
|
1573
|
-
<
|
|
1589
|
+
<HostCard variant="elevated">
|
|
1590
|
+
<HostCardHeader {...compactCardTitleProp}
|
|
1574
1591
|
title="Custom Metric Pills"
|
|
1575
1592
|
icon="Sliders"
|
|
1576
1593
|
subtitle="Standalone pills discovered from ~/.paseo/top/pills"
|
|
1577
1594
|
/>
|
|
1578
1595
|
<View style={styles.settingsToggles}>
|
|
1579
|
-
<
|
|
1596
|
+
<HostToggle
|
|
1580
1597
|
label="Show Custom Metric Pills"
|
|
1581
1598
|
description="Display pills defined in ~/.paseo/top/pills as standalone composer pills"
|
|
1582
1599
|
style={styles.toggleFullWidth}
|
|
@@ -1590,12 +1607,12 @@ function ResourceModal({ theme, workspaceId, agentId, initialTab, payload }: Res
|
|
|
1590
1607
|
/>
|
|
1591
1608
|
|
|
1592
1609
|
</View>
|
|
1593
|
-
</
|
|
1610
|
+
</HostCard>
|
|
1594
1611
|
|
|
1595
1612
|
{/* Rotation Speed Setting (Cycle mode only) */}
|
|
1596
1613
|
{(settings.pillMode ?? "cycle") === "cycle" && (
|
|
1597
|
-
<
|
|
1598
|
-
<
|
|
1614
|
+
<HostCard variant="elevated">
|
|
1615
|
+
<HostCardHeader {...compactCardTitleProp}
|
|
1599
1616
|
title="Rotation Speed"
|
|
1600
1617
|
icon="Clock"
|
|
1601
1618
|
value={
|
|
@@ -1612,12 +1629,12 @@ function ResourceModal({ theme, workspaceId, agentId, initialTab, payload }: Res
|
|
|
1612
1629
|
updateSettings({ intervalSeconds });
|
|
1613
1630
|
}}
|
|
1614
1631
|
/>
|
|
1615
|
-
</
|
|
1632
|
+
</HostCard>
|
|
1616
1633
|
)}
|
|
1617
1634
|
|
|
1618
1635
|
{/* Timeline Cadence Setting */}
|
|
1619
|
-
<
|
|
1620
|
-
<
|
|
1636
|
+
<HostCard variant="elevated">
|
|
1637
|
+
<HostCardHeader {...compactCardTitleProp}
|
|
1621
1638
|
title="Timeline Cadence"
|
|
1622
1639
|
icon="Clock"
|
|
1623
1640
|
value={
|
|
@@ -1643,30 +1660,92 @@ function ResourceModal({ theme, workspaceId, agentId, initialTab, payload }: Res
|
|
|
1643
1660
|
<Text style={[styles.modeDesc, styles.modeDescSpaced, { color: colors.foregroundMuted }]}>
|
|
1644
1661
|
0 behaves as never; N above 1 stamps every Nth turn
|
|
1645
1662
|
</Text>
|
|
1646
|
-
</
|
|
1663
|
+
</HostCard>
|
|
1664
|
+
|
|
1665
|
+
{/* Timeline Card Metrics Setting */}
|
|
1666
|
+
{(settings.timelineCadence ?? 1) > 0 && (
|
|
1667
|
+
<HostCard variant="elevated">
|
|
1668
|
+
<HostCardHeader {...compactCardTitleProp}
|
|
1669
|
+
title="Timeline Card Metrics"
|
|
1670
|
+
icon="GitCommitHorizontal"
|
|
1671
|
+
value={
|
|
1672
|
+
<Text style={[styles.accentValueText, { color: colors.accent }]}>
|
|
1673
|
+
{`${METRIC_DEFINITIONS.filter((d) => !d.pillOnly && isTimelineEnabled((settings.metricSurfaces ?? DEFAULT_METRIC_SURFACES)[d.id])).length} active`}
|
|
1674
|
+
</Text>
|
|
1675
|
+
}
|
|
1676
|
+
subtitle="Choose which metrics appear on turn summary cards"
|
|
1677
|
+
/>
|
|
1678
|
+
<MultiChoiceChips
|
|
1679
|
+
options={METRIC_DEFINITIONS.filter((d) => !d.pillOnly).map((def) => ({
|
|
1680
|
+
id: def.id,
|
|
1681
|
+
label: def.title,
|
|
1682
|
+
icon: def.icon,
|
|
1683
|
+
disabled: def.id === "mcp" && !data?.mcpInstalled,
|
|
1684
|
+
}))}
|
|
1685
|
+
selected={METRIC_DEFINITIONS.filter((d) => !d.pillOnly && isTimelineEnabled((settings.metricSurfaces ?? DEFAULT_METRIC_SURFACES)[d.id])).map((d) => d.id)}
|
|
1686
|
+
onToggle={(metricId) => {
|
|
1687
|
+
triggerHaptic("light");
|
|
1688
|
+
const surfaces = settings.metricSurfaces ?? DEFAULT_METRIC_SURFACES;
|
|
1689
|
+
const currentPill = isPillEnabled(surfaces[metricId]);
|
|
1690
|
+
const currentTimeline = isTimelineEnabled(surfaces[metricId]);
|
|
1691
|
+
const next = {
|
|
1692
|
+
...surfaces,
|
|
1693
|
+
[metricId]: targetFromCheckboxes(currentPill, !currentTimeline),
|
|
1694
|
+
};
|
|
1695
|
+
updateSettings({ metricSurfaces: next });
|
|
1696
|
+
notifySettingsChanged({ ...settings, metricSurfaces: next });
|
|
1697
|
+
}}
|
|
1698
|
+
onSelectAll={() => {
|
|
1699
|
+
triggerHaptic("medium");
|
|
1700
|
+
const surfaces = settings.metricSurfaces ?? DEFAULT_METRIC_SURFACES;
|
|
1701
|
+
const next = { ...surfaces };
|
|
1702
|
+
for (const def of METRIC_DEFINITIONS) {
|
|
1703
|
+
if (def.pillOnly) continue;
|
|
1704
|
+
if (def.id === "mcp" && !data?.mcpInstalled) continue;
|
|
1705
|
+
const currentPill = isPillEnabled(surfaces[def.id]);
|
|
1706
|
+
next[def.id] = targetFromCheckboxes(currentPill, true);
|
|
1707
|
+
}
|
|
1708
|
+
updateSettings({ metricSurfaces: next });
|
|
1709
|
+
notifySettingsChanged({ ...settings, metricSurfaces: next });
|
|
1710
|
+
}}
|
|
1711
|
+
onClearAll={() => {
|
|
1712
|
+
triggerHaptic("medium");
|
|
1713
|
+
const surfaces = settings.metricSurfaces ?? DEFAULT_METRIC_SURFACES;
|
|
1714
|
+
const next = { ...surfaces };
|
|
1715
|
+
for (const def of METRIC_DEFINITIONS) {
|
|
1716
|
+
if (def.pillOnly) continue;
|
|
1717
|
+
const currentPill = isPillEnabled(surfaces[def.id]);
|
|
1718
|
+
next[def.id] = targetFromCheckboxes(currentPill, false);
|
|
1719
|
+
}
|
|
1720
|
+
updateSettings({ metricSurfaces: next });
|
|
1721
|
+
notifySettingsChanged({ ...settings, metricSurfaces: next });
|
|
1722
|
+
}}
|
|
1723
|
+
/>
|
|
1724
|
+
</HostCard>
|
|
1725
|
+
)}
|
|
1647
1726
|
|
|
1648
1727
|
{/* Default Modal Tab Setting */}
|
|
1649
|
-
<
|
|
1650
|
-
<
|
|
1728
|
+
<HostCard variant="elevated">
|
|
1729
|
+
<HostCardHeader {...compactCardTitleProp}
|
|
1651
1730
|
title="Default Modal Tab"
|
|
1652
1731
|
icon="Sliders"
|
|
1653
1732
|
value={
|
|
1654
1733
|
<Text style={[styles.accentValueText, { color: colors.accent }]}>
|
|
1655
|
-
{
|
|
1734
|
+
{MODAL_TABS.find((t) => t.id === settings.defaultTab)?.label || "System"}
|
|
1656
1735
|
</Text>
|
|
1657
1736
|
}
|
|
1658
1737
|
/>
|
|
1659
1738
|
<ChoiceChips
|
|
1660
|
-
options={
|
|
1739
|
+
options={MODAL_TABS.map((tab) => ({ id: tab.id as ModalTab, label: tab.label }))}
|
|
1661
1740
|
value={settings.defaultTab ?? "system"}
|
|
1662
1741
|
onChange={(defaultTab) => {
|
|
1663
1742
|
triggerHaptic("light");
|
|
1664
1743
|
updateSettings({ defaultTab });
|
|
1665
1744
|
}}
|
|
1666
1745
|
/>
|
|
1667
|
-
</
|
|
1746
|
+
</HostCard>
|
|
1668
1747
|
|
|
1669
|
-
<
|
|
1748
|
+
<HostButton
|
|
1670
1749
|
label="Reset to Defaults"
|
|
1671
1750
|
variant="secondary"
|
|
1672
1751
|
size="sm"
|
|
@@ -1681,40 +1760,19 @@ function ResourceModal({ theme, workspaceId, agentId, initialTab, payload }: Res
|
|
|
1681
1760
|
)}
|
|
1682
1761
|
|
|
1683
1762
|
{activeTab === "permissions" && (
|
|
1684
|
-
<PermissionAuditView variant="compact" />
|
|
1763
|
+
<PermissionAuditView variant="compact" theme={theme} layout={layout} />
|
|
1685
1764
|
)}
|
|
1686
1765
|
|
|
1687
1766
|
{activeTab === "about" && (
|
|
1688
|
-
<
|
|
1767
|
+
<HostAboutSection
|
|
1689
1768
|
name="paseo-top"
|
|
1690
|
-
description="Live host
|
|
1769
|
+
description="Live host and session monitor across composer pills, timeline turns, and an interactive dashboard."
|
|
1691
1770
|
version={data?.version ?? PLUGIN_VERSION}
|
|
1692
1771
|
author="xpufx"
|
|
1693
1772
|
repository="https://github.com/xpufx/paseo-top"
|
|
1694
1773
|
issues="https://github.com/xpufx/paseo-top/issues"
|
|
1695
1774
|
license="MIT"
|
|
1696
|
-
|
|
1697
|
-
extraItems={[
|
|
1698
|
-
{
|
|
1699
|
-
label: "Host Platform",
|
|
1700
|
-
value: data?.platform ? `${data?.platform} (${data?.arch ?? "unknown"})` : "Linux",
|
|
1701
|
-
copyable: true,
|
|
1702
|
-
},
|
|
1703
|
-
{ label: "Host Name", value: data?.hostname ?? "localhost", copyable: true },
|
|
1704
|
-
{ label: "CPU Model", value: data?.cpuModel ?? "unknown", copyable: true },
|
|
1705
|
-
{
|
|
1706
|
-
label: "CPU Cores",
|
|
1707
|
-
value: `${data?.cpuCores ?? 0} cores`,
|
|
1708
|
-
},
|
|
1709
|
-
{
|
|
1710
|
-
label: "Total Memory",
|
|
1711
|
-
value: data?.memoryTotalBytes ? formatBytes(data?.memoryTotalBytes) : "unknown",
|
|
1712
|
-
},
|
|
1713
|
-
{
|
|
1714
|
-
label: "Host Uptime",
|
|
1715
|
-
value: data?.uptimeSeconds ? formatUptime(data?.uptimeSeconds) : "unknown",
|
|
1716
|
-
},
|
|
1717
|
-
]}
|
|
1775
|
+
extraItems={aboutExtraItems(data)}
|
|
1718
1776
|
/>
|
|
1719
1777
|
)}
|
|
1720
1778
|
|
|
@@ -1726,7 +1784,9 @@ function ResourceModal({ theme, workspaceId, agentId, initialTab, payload }: Res
|
|
|
1726
1784
|
</Text>
|
|
1727
1785
|
</View>
|
|
1728
1786
|
)}
|
|
1729
|
-
|
|
1787
|
+
</View>
|
|
1788
|
+
</View>
|
|
1789
|
+
</HostModalSection>
|
|
1730
1790
|
);
|
|
1731
1791
|
}
|
|
1732
1792
|
|
|
@@ -1735,8 +1795,69 @@ interface LiveCustomPillModalProps {
|
|
|
1735
1795
|
initial: CustomPillStateOutput;
|
|
1736
1796
|
}
|
|
1737
1797
|
|
|
1798
|
+
/**
|
|
1799
|
+
* Drilldown modal body for a custom metric pill, built from `ui/` primitives
|
|
1800
|
+
* (the deprecated `client/` `CustomPillModalContent` was dropped in the #847
|
|
1801
|
+
* migration). The host owns the modal frame; this fills it fluidly.
|
|
1802
|
+
*/
|
|
1803
|
+
function CustomPillModalContent({
|
|
1804
|
+
state,
|
|
1805
|
+
onRefresh,
|
|
1806
|
+
isRefreshing = false,
|
|
1807
|
+
}: {
|
|
1808
|
+
state: CustomPillStateOutput;
|
|
1809
|
+
onRefresh?: () => Promise<void> | void;
|
|
1810
|
+
isRefreshing?: boolean;
|
|
1811
|
+
}) {
|
|
1812
|
+
const { colors } = useHostTheme();
|
|
1813
|
+
const displayText =
|
|
1814
|
+
state.modalOutput || state.rawValue || (state.error ? `Error: ${state.error}` : "No output");
|
|
1815
|
+
|
|
1816
|
+
return (
|
|
1817
|
+
<View style={styles.customPillModal}>
|
|
1818
|
+
<HostCard>
|
|
1819
|
+
<HostCardHeader
|
|
1820
|
+
title={state.modalTitle ?? state.title}
|
|
1821
|
+
subtitle={state.modalDescription}
|
|
1822
|
+
icon={state.icon}
|
|
1823
|
+
badge={<HostBadge label={state.displayValue} variant={state.status} />}
|
|
1824
|
+
action={
|
|
1825
|
+
onRefresh ? (
|
|
1826
|
+
<HostButton
|
|
1827
|
+
variant="secondary"
|
|
1828
|
+
size="sm"
|
|
1829
|
+
icon="RefreshCw"
|
|
1830
|
+
loading={isRefreshing}
|
|
1831
|
+
label="Refresh"
|
|
1832
|
+
onPress={() => onRefresh()}
|
|
1833
|
+
/>
|
|
1834
|
+
) : undefined
|
|
1835
|
+
}
|
|
1836
|
+
/>
|
|
1837
|
+
<View style={styles.codeBlock}>
|
|
1838
|
+
<Text
|
|
1839
|
+
selectable
|
|
1840
|
+
numberOfLines={8}
|
|
1841
|
+
style={[styles.codeText, { color: colors.foreground }]}
|
|
1842
|
+
>
|
|
1843
|
+
{displayText}
|
|
1844
|
+
</Text>
|
|
1845
|
+
<HostCopyButton
|
|
1846
|
+
text={displayText}
|
|
1847
|
+
accessibilityLabel="Copy pill output"
|
|
1848
|
+
toastMessage="pill output"
|
|
1849
|
+
/>
|
|
1850
|
+
</View>
|
|
1851
|
+
<Text style={[styles.timestampText, { color: colors.foregroundMuted }]}>
|
|
1852
|
+
Last updated: {new Date(state.lastUpdated).toLocaleTimeString()}
|
|
1853
|
+
</Text>
|
|
1854
|
+
</HostCard>
|
|
1855
|
+
</View>
|
|
1856
|
+
);
|
|
1857
|
+
}
|
|
1858
|
+
|
|
1738
1859
|
function LiveCustomPillModal({ pillId, initial }: LiveCustomPillModalProps) {
|
|
1739
|
-
const { colors } =
|
|
1860
|
+
const { colors } = useHostTheme();
|
|
1740
1861
|
const [refreshing, setRefreshing] = useState(false);
|
|
1741
1862
|
const [outputOverride, setOutputOverride] = useState<string | undefined>(undefined);
|
|
1742
1863
|
const { data, refetch } = useCustomPillsQuery();
|
|
@@ -1871,17 +1992,7 @@ export function contributeClient(client: ComposerPillRegistrar | PluginClientCon
|
|
|
1871
1992
|
activePills.delete("paseo-top");
|
|
1872
1993
|
}
|
|
1873
1994
|
|
|
1874
|
-
const hasAny =
|
|
1875
|
-
flags.showCpuRam ||
|
|
1876
|
-
flags.showBranch ||
|
|
1877
|
-
flags.showWorktree ||
|
|
1878
|
-
flags.showAgentTitle ||
|
|
1879
|
-
flags.showAgent ||
|
|
1880
|
-
flags.showAgentProvider ||
|
|
1881
|
-
flags.showAgentActivity ||
|
|
1882
|
-
flags.showAgentId ||
|
|
1883
|
-
flags.showLoad ||
|
|
1884
|
-
flags.showUptime;
|
|
1995
|
+
const hasAny = hasAnyLegacyPillFlagEnabled(flags);
|
|
1885
1996
|
|
|
1886
1997
|
const effectiveCpu = flags.showCpuRam || !hasAny;
|
|
1887
1998
|
|
|
@@ -2044,6 +2155,16 @@ export function contributeClient(client: ComposerPillRegistrar | PluginClientCon
|
|
|
2044
2155
|
defaultTab: "system",
|
|
2045
2156
|
});
|
|
2046
2157
|
}
|
|
2158
|
+
if (settings.metricSurfaces && isPillEnabled(settings.metricSurfaces.velocity)) {
|
|
2159
|
+
desiredPills.push({
|
|
2160
|
+
id: "paseo-top-velocity",
|
|
2161
|
+
item: "velocity",
|
|
2162
|
+
icon: "Zap",
|
|
2163
|
+
title: "Generation Velocity",
|
|
2164
|
+
modalTitle: "Host System Resources",
|
|
2165
|
+
defaultTab: "system",
|
|
2166
|
+
});
|
|
2167
|
+
}
|
|
2047
2168
|
|
|
2048
2169
|
const desiredIds = new Set(desiredPills.map((p) => p.id));
|
|
2049
2170
|
|
|
@@ -2158,8 +2279,12 @@ export function contributeClient(client: ComposerPillRegistrar | PluginClientCon
|
|
|
2158
2279
|
);
|
|
2159
2280
|
},
|
|
2160
2281
|
refreshIntervalMs: 5000,
|
|
2161
|
-
renderModal: () => (
|
|
2162
|
-
<
|
|
2282
|
+
renderModal: (props) => (
|
|
2283
|
+
<HostThemeProvider theme={props.theme}>
|
|
2284
|
+
<HostLayoutProvider layout={props.layout}>
|
|
2285
|
+
<LiveCustomPillModal pillId={pill.id} initial={pill} />
|
|
2286
|
+
</HostLayoutProvider>
|
|
2287
|
+
</HostThemeProvider>
|
|
2163
2288
|
),
|
|
2164
2289
|
});
|
|
2165
2290
|
activeCustomPills.set(pill.id, cleanup);
|
|
@@ -2213,8 +2338,6 @@ export function contributeClient(client: ComposerPillRegistrar | PluginClientCon
|
|
|
2213
2338
|
// primitive covers.
|
|
2214
2339
|
const styles = {
|
|
2215
2340
|
modalRoot: {
|
|
2216
|
-
flex: 1,
|
|
2217
|
-
minHeight: 0,
|
|
2218
2341
|
width: "100%",
|
|
2219
2342
|
},
|
|
2220
2343
|
pillContainer: {
|
|
@@ -2313,80 +2436,6 @@ const styles = {
|
|
|
2313
2436
|
accentValueText: {
|
|
2314
2437
|
fontWeight: "600",
|
|
2315
2438
|
},
|
|
2316
|
-
metricMatrix: {
|
|
2317
|
-
gap: 0,
|
|
2318
|
-
width: "100%",
|
|
2319
|
-
},
|
|
2320
|
-
metricMatrixCompact: {
|
|
2321
|
-
minWidth: 0,
|
|
2322
|
-
},
|
|
2323
|
-
metricMatrixHeader: {
|
|
2324
|
-
flexDirection: "row",
|
|
2325
|
-
alignItems: "center",
|
|
2326
|
-
justifyContent: "space-between",
|
|
2327
|
-
paddingLeft: 4,
|
|
2328
|
-
paddingRight: 4,
|
|
2329
|
-
paddingBottom: 2,
|
|
2330
|
-
},
|
|
2331
|
-
metricMatrixHeaderCompact: {
|
|
2332
|
-
paddingLeft: 2,
|
|
2333
|
-
paddingRight: 2,
|
|
2334
|
-
},
|
|
2335
|
-
metricMatrixHeaderText: {
|
|
2336
|
-
fontSize: 9,
|
|
2337
|
-
fontWeight: "700",
|
|
2338
|
-
textTransform: "uppercase",
|
|
2339
|
-
letterSpacing: 0.5,
|
|
2340
|
-
},
|
|
2341
|
-
metricMatrixTargetHeader: {
|
|
2342
|
-
flexDirection: "row",
|
|
2343
|
-
alignItems: "center",
|
|
2344
|
-
gap: 28,
|
|
2345
|
-
paddingRight: 10,
|
|
2346
|
-
},
|
|
2347
|
-
metricMatrixTargetHeaderCompact: {
|
|
2348
|
-
gap: 16,
|
|
2349
|
-
paddingRight: 8,
|
|
2350
|
-
},
|
|
2351
|
-
metricMatrixRow: {
|
|
2352
|
-
flexDirection: "row",
|
|
2353
|
-
alignItems: "center",
|
|
2354
|
-
justifyContent: "space-between",
|
|
2355
|
-
paddingLeft: 4,
|
|
2356
|
-
paddingRight: 4,
|
|
2357
|
-
},
|
|
2358
|
-
metricMatrixRowCompact: {
|
|
2359
|
-
paddingLeft: 2,
|
|
2360
|
-
paddingRight: 2,
|
|
2361
|
-
},
|
|
2362
|
-
metricMatrixLabel: {
|
|
2363
|
-
flex: 1,
|
|
2364
|
-
minWidth: 0,
|
|
2365
|
-
paddingVertical: 2,
|
|
2366
|
-
},
|
|
2367
|
-
metricMatrixTitle: {
|
|
2368
|
-
fontSize: 11,
|
|
2369
|
-
fontWeight: "600",
|
|
2370
|
-
},
|
|
2371
|
-
metricMatrixNote: {
|
|
2372
|
-
fontSize: 9,
|
|
2373
|
-
lineHeight: 12,
|
|
2374
|
-
marginTop: 1,
|
|
2375
|
-
},
|
|
2376
|
-
metricMatrixTargets: {
|
|
2377
|
-
flexDirection: "row",
|
|
2378
|
-
alignItems: "center",
|
|
2379
|
-
gap: 16,
|
|
2380
|
-
paddingLeft: 8,
|
|
2381
|
-
},
|
|
2382
|
-
metricMatrixTargetsCompact: {
|
|
2383
|
-
gap: 8,
|
|
2384
|
-
paddingLeft: 4,
|
|
2385
|
-
},
|
|
2386
|
-
matrixToggle: {
|
|
2387
|
-
width: 38,
|
|
2388
|
-
minHeight: 44,
|
|
2389
|
-
},
|
|
2390
2439
|
allInOneContainer: {
|
|
2391
2440
|
flexDirection: "row",
|
|
2392
2441
|
alignItems: "center",
|
|
@@ -2439,4 +2488,31 @@ const styles = {
|
|
|
2439
2488
|
fontStyle: "italic",
|
|
2440
2489
|
paddingVertical: 4,
|
|
2441
2490
|
},
|
|
2491
|
+
modalColumn: {
|
|
2492
|
+
width: "100%",
|
|
2493
|
+
},
|
|
2494
|
+
modalContent: {
|
|
2495
|
+
width: "100%",
|
|
2496
|
+
paddingTop: 6,
|
|
2497
|
+
},
|
|
2498
|
+
customPillModal: {
|
|
2499
|
+
width: "100%",
|
|
2500
|
+
padding: 12,
|
|
2501
|
+
},
|
|
2502
|
+
codeBlock: {
|
|
2503
|
+
flexDirection: "row",
|
|
2504
|
+
alignItems: "flex-start",
|
|
2505
|
+
gap: 8,
|
|
2506
|
+
marginTop: 8,
|
|
2507
|
+
},
|
|
2508
|
+
codeText: {
|
|
2509
|
+
flex: 1,
|
|
2510
|
+
minWidth: 0,
|
|
2511
|
+
fontSize: 11,
|
|
2512
|
+
fontFamily: "monospace",
|
|
2513
|
+
},
|
|
2514
|
+
timestampText: {
|
|
2515
|
+
fontSize: 11,
|
|
2516
|
+
marginTop: 8,
|
|
2517
|
+
},
|
|
2442
2518
|
} as const;
|