@xpufx/paseo-top 0.4.4 → 0.4.5
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 +17 -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 +690 -614
- 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/package.json +7 -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/turn-panel.tsx
CHANGED
|
@@ -1,22 +1,23 @@
|
|
|
1
1
|
import React, { useEffect, useMemo } from "react";
|
|
2
|
-
import { Text } from "react-native";
|
|
2
|
+
import { Text, View } from "react-native";
|
|
3
3
|
import type { PluginAgentPanelProps } from "@getpaseo/plugin/client";
|
|
4
4
|
import { useAgent, usePaseo } from "@getpaseo/plugin/client";
|
|
5
5
|
import { useQuery, useQueryClient } from "@tanstack/react-query";
|
|
6
6
|
import {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
7
|
+
HostBadge,
|
|
8
|
+
HostCard,
|
|
9
|
+
HostCardHeader,
|
|
10
|
+
HostEmptyState,
|
|
11
|
+
HostKeyValue,
|
|
12
|
+
HostLayoutProvider,
|
|
13
|
+
HostRow,
|
|
14
|
+
HostScroll,
|
|
15
|
+
HostSectionHeader,
|
|
16
|
+
HostStack,
|
|
17
|
+
HostThemeProvider,
|
|
18
|
+
useHostLayout,
|
|
19
|
+
useHostTheme,
|
|
20
|
+
} from "./host-ui";
|
|
20
21
|
import {
|
|
21
22
|
currentTurn,
|
|
22
23
|
fetchAllTurns,
|
|
@@ -39,19 +40,24 @@ function previewLine(text: string): string {
|
|
|
39
40
|
* panel is open; full history is paged, so the count does not reset to the
|
|
40
41
|
* tail window on long conversations.
|
|
41
42
|
*
|
|
42
|
-
* Registered with the raw `addWorkspacePanel`, which does not inject
|
|
43
|
-
*
|
|
43
|
+
* Registered with the raw `addWorkspacePanel`, which does not inject a theme
|
|
44
|
+
* provider (unlike `registerWorkspacePanel`), so the body is wrapped here.
|
|
45
|
+
* The panel host supplies no scroller, so HostScroll owns the one scroll
|
|
46
|
+
* region below the pinned header row.
|
|
44
47
|
*/
|
|
45
48
|
export function TurnCounterPanel({ theme, layout, agentId }: PluginAgentPanelProps) {
|
|
46
49
|
return (
|
|
47
|
-
<
|
|
48
|
-
<
|
|
49
|
-
|
|
50
|
+
<HostThemeProvider theme={theme}>
|
|
51
|
+
<HostLayoutProvider layout={layout}>
|
|
52
|
+
<TurnCounterBody agentId={agentId} />
|
|
53
|
+
</HostLayoutProvider>
|
|
54
|
+
</HostThemeProvider>
|
|
50
55
|
);
|
|
51
56
|
}
|
|
52
57
|
|
|
53
58
|
function TurnCounterBody({ agentId }: { agentId: string }) {
|
|
54
|
-
const { colors
|
|
59
|
+
const { colors } = useHostTheme();
|
|
60
|
+
const { compact } = useHostLayout();
|
|
55
61
|
const paseo = usePaseo();
|
|
56
62
|
const queryClient = useQueryClient();
|
|
57
63
|
|
|
@@ -84,99 +90,115 @@ function TurnCounterBody({ agentId }: { agentId: string }) {
|
|
|
84
90
|
// Newest first, so the last turn is the first row the operator sees.
|
|
85
91
|
const ordered = useMemo(() => [...turns].reverse(), [turns]);
|
|
86
92
|
|
|
93
|
+
// Host-density padding (the helper's "comfortable" scale): the host owns
|
|
94
|
+
// density now, so the panel keeps the same numeric rhythm locally.
|
|
95
|
+
const padding = compact
|
|
96
|
+
? { horizontal: 12, vertical: 10, gap: 8 }
|
|
97
|
+
: { horizontal: 16, vertical: 14, gap: 12 };
|
|
98
|
+
|
|
87
99
|
return (
|
|
88
|
-
<
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
headerStyle={{
|
|
109
|
-
backgroundColor: colors.surface0,
|
|
110
|
-
paddingHorizontal: padding.horizontal,
|
|
111
|
-
paddingTop: padding.vertical,
|
|
112
|
-
paddingBottom: padding.gap,
|
|
113
|
-
}}
|
|
114
|
-
contentContainerStyle={{
|
|
115
|
-
gap: padding.gap,
|
|
116
|
-
paddingHorizontal: padding.horizontal,
|
|
117
|
-
paddingBottom: padding.vertical,
|
|
118
|
-
}}
|
|
119
|
-
>
|
|
120
|
-
<Card variant="elevated">
|
|
121
|
-
<CardHeader
|
|
122
|
-
title="Current turn"
|
|
123
|
-
icon="Repeat"
|
|
124
|
-
subtitle="Deterministic from the timeline seq shared with the agent"
|
|
125
|
-
value={
|
|
126
|
-
<Badge
|
|
127
|
-
label={latest ? formatTurnAddress(latest.turn, latest.seq) : "-"}
|
|
128
|
-
variant={latest ? "accent" : "neutral"}
|
|
129
|
-
size="sm"
|
|
130
|
-
/>
|
|
131
|
-
}
|
|
132
|
-
/>
|
|
133
|
-
{latest ? (
|
|
134
|
-
<KeyValue
|
|
135
|
-
label="Address"
|
|
136
|
-
value={formatTurnAddress(latest.turn, latest.seq)}
|
|
137
|
-
subValue={previewLine(latest.preview)}
|
|
138
|
-
copyable
|
|
139
|
-
mono
|
|
100
|
+
<View style={styles.panelRoot}>
|
|
101
|
+
<HostRow
|
|
102
|
+
justify="between"
|
|
103
|
+
align="center"
|
|
104
|
+
gap={8}
|
|
105
|
+
style={{
|
|
106
|
+
paddingHorizontal: padding.horizontal,
|
|
107
|
+
paddingTop: padding.vertical,
|
|
108
|
+
paddingBottom: padding.gap,
|
|
109
|
+
}}
|
|
110
|
+
>
|
|
111
|
+
<Text style={{ color: colors.foreground, fontSize: 18, fontWeight: "700" }}>
|
|
112
|
+
Turn Counter
|
|
113
|
+
</Text>
|
|
114
|
+
{agent?.status ? (
|
|
115
|
+
<HostBadge
|
|
116
|
+
label={agent.status}
|
|
117
|
+
variant={agent.status === "running" ? "success" : "neutral"}
|
|
118
|
+
size="sm"
|
|
119
|
+
dot
|
|
140
120
|
/>
|
|
141
|
-
) :
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
121
|
+
) : null}
|
|
122
|
+
</HostRow>
|
|
123
|
+
<HostScroll
|
|
124
|
+
style={styles.scroll}
|
|
125
|
+
contentContainerStyle={{
|
|
126
|
+
gap: padding.gap,
|
|
127
|
+
paddingHorizontal: padding.horizontal,
|
|
128
|
+
paddingBottom: padding.vertical,
|
|
129
|
+
}}
|
|
130
|
+
>
|
|
131
|
+
<HostCard variant="elevated">
|
|
132
|
+
<HostCardHeader
|
|
133
|
+
title="Current turn"
|
|
134
|
+
icon="Repeat"
|
|
135
|
+
subtitle="Deterministic from the timeline seq shared with the agent"
|
|
136
|
+
value={
|
|
137
|
+
<HostBadge
|
|
138
|
+
label={latest ? formatTurnAddress(latest.turn, latest.seq) : "-"}
|
|
139
|
+
variant={latest ? "accent" : "neutral"}
|
|
140
|
+
size="sm"
|
|
141
|
+
/>
|
|
142
|
+
}
|
|
143
|
+
/>
|
|
144
|
+
{latest ? (
|
|
145
|
+
<HostKeyValue
|
|
146
|
+
label="Address"
|
|
147
|
+
value={formatTurnAddress(latest.turn, latest.seq)}
|
|
148
|
+
subValue={previewLine(latest.preview)}
|
|
149
|
+
copyable
|
|
150
|
+
mono
|
|
151
|
+
/>
|
|
152
|
+
) : (
|
|
153
|
+
<Text style={{ color: colors.foregroundMuted, fontSize: 12 }}>
|
|
154
|
+
{turnsQuery.isPending ? "Reading timeline…" : "No user turns recorded yet."}
|
|
155
|
+
</Text>
|
|
156
|
+
)}
|
|
157
|
+
</HostCard>
|
|
147
158
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
159
|
+
{turnsQuery.error ? (
|
|
160
|
+
<Text selectable style={{ color: colors.statusDanger, fontSize: 12 }}>
|
|
161
|
+
Failed to read timeline: {String(turnsQuery.error)}
|
|
162
|
+
</Text>
|
|
163
|
+
) : null}
|
|
153
164
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
<KeyValue
|
|
165
|
+
{ordered.length > 0 ? (
|
|
166
|
+
<>
|
|
167
|
+
<HostSectionHeader title="Turns" count={ordered.length} />
|
|
168
|
+
<HostStack gap={8}>
|
|
169
|
+
{ordered.map((turn) => (
|
|
170
|
+
<HostCard key={turn.seq} variant="elevated">
|
|
171
|
+
<HostKeyValue
|
|
162
172
|
label={formatTurnAddress(turn.turn, turn.seq)}
|
|
163
173
|
value={previewLine(turn.preview)}
|
|
164
174
|
subValue={`seq ${turn.seq}`}
|
|
165
175
|
copyable
|
|
166
176
|
mono
|
|
167
177
|
/>
|
|
168
|
-
</
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
</
|
|
178
|
+
</HostCard>
|
|
179
|
+
))}
|
|
180
|
+
</HostStack>
|
|
181
|
+
</>
|
|
182
|
+
) : !turnsQuery.isPending && !turnsQuery.error ? (
|
|
183
|
+
<HostEmptyState
|
|
184
|
+
icon="MessageSquare"
|
|
185
|
+
title="No turns yet"
|
|
186
|
+
description="Send the agent a message and its first turn will appear here."
|
|
187
|
+
/>
|
|
188
|
+
) : null}
|
|
189
|
+
</HostScroll>
|
|
190
|
+
</View>
|
|
181
191
|
);
|
|
182
192
|
}
|
|
193
|
+
|
|
194
|
+
const styles = {
|
|
195
|
+
panelRoot: {
|
|
196
|
+
flex: 1,
|
|
197
|
+
minHeight: 0,
|
|
198
|
+
width: "100%",
|
|
199
|
+
},
|
|
200
|
+
scroll: {
|
|
201
|
+
flex: 1,
|
|
202
|
+
minHeight: 0,
|
|
203
|
+
},
|
|
204
|
+
} as const;
|
|
@@ -22,7 +22,7 @@ import type {
|
|
|
22
22
|
/**
|
|
23
23
|
* Structural host types for Paseo client integration.
|
|
24
24
|
*
|
|
25
|
-
* These interfaces describe the shapes
|
|
25
|
+
* These interfaces describe the shapes the helper's client runtime needs
|
|
26
26
|
* from the Paseo host app: the runtime dependencies the plugin injects once
|
|
27
27
|
* in its client entry — the host theme, the layout, the icon/Modal primitives,
|
|
28
28
|
* the agents feed — so they can be supplied from any entry point.
|
|
@@ -110,9 +110,15 @@ export type HostAgentUpdate =
|
|
|
110
110
|
| { kind: "remove"; agentId: string }
|
|
111
111
|
| { kind: string; agent: HostAgentRef };
|
|
112
112
|
|
|
113
|
+
export interface HostAgentListOptions {
|
|
114
|
+
subscribe?: Record<string, unknown>;
|
|
115
|
+
signal?: AbortSignal;
|
|
116
|
+
[key: string]: unknown;
|
|
117
|
+
}
|
|
118
|
+
|
|
113
119
|
export interface HostAgentsApi {
|
|
114
120
|
subscribe(cb: (update: HostAgentUpdate) => void): () => void;
|
|
115
|
-
list(): Promise<
|
|
121
|
+
list(options?: any): Promise<any>;
|
|
116
122
|
}
|
|
117
123
|
|
|
118
124
|
export type PluginCleanup = () => void;
|
|
@@ -151,7 +157,7 @@ export function initClientHelpers(host: ClientHostDeps): void {
|
|
|
151
157
|
export function getClientHost(): ClientHostDeps {
|
|
152
158
|
if (!deps) {
|
|
153
159
|
throw new Error(
|
|
154
|
-
"paseo-plugin-helper
|
|
160
|
+
"paseo-plugin-helper used before initClientHelpers(). " +
|
|
155
161
|
"Call initClientHelpers({ Icon, Modal, useRpc, useToast }) in the plugin client entry.",
|
|
156
162
|
);
|
|
157
163
|
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Paseo Plugin Helper — Core Runtime (Headless, CLIENT-SAFE).
|
|
3
|
+
*
|
|
4
|
+
* Import from `paseo-plugin-helper/core` for everything headless that must
|
|
5
|
+
* also load in the plugin CLIENT bundle: RPC contracts, query/mutation
|
|
6
|
+
* hooks, settings sync hooks, and pure formatters.
|
|
7
|
+
*
|
|
8
|
+
* Client/server boundary (#219): this entry MUST NOT re-export `../server/*`
|
|
9
|
+
* or `../mcp/*` — those pull `node:*` built-ins (fs, child_process, …) which
|
|
10
|
+
* the 0.8 client compiler rejects. Server-only primitives stay in
|
|
11
|
+
* `paseo-plugin-helper/server` (and MCP in `paseo-plugin-helper/mcp`).
|
|
12
|
+
*
|
|
13
|
+
* Purity contract (enforced by `src/__tests__/core-purity.test.ts`):
|
|
14
|
+
* - No runtime import of `react-native` or any UI component.
|
|
15
|
+
* - No `node:*` (or bare Node builtin) imports.
|
|
16
|
+
* - No DOM/CSS variable scraper (`theme/host-variables`).
|
|
17
|
+
* - No layout opinions (`layout/`, `components/`, `ModalBody`, `maxContentWidth`).
|
|
18
|
+
*
|
|
19
|
+
* React (not React Native) is the only view-layer dependency here, via
|
|
20
|
+
* `@tanstack/react-query` hooks. Host RPC access flows through the injected
|
|
21
|
+
* `useRpc` seam in `core/host.ts`, which itself carries only type-level
|
|
22
|
+
* `react-native` imports (erased at runtime).
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
export * from "../../../../shared/vendor/paseo-plugin-helper/rpc";
|
|
26
|
+
export * from "../../../../shared/vendor/paseo-plugin-helper/features";
|
|
27
|
+
export * from "../../../../shared/vendor/paseo-plugin-helper/settings";
|
|
28
|
+
export * from "../../../../shared/vendor/paseo-plugin-helper/suite-settings";
|
|
29
|
+
export * from "../../../../shared/vendor/paseo-plugin-helper/formatters";
|
|
30
|
+
export * from "../../../../shared/vendor/paseo-plugin-helper/async";
|
|
31
|
+
export * from "../../../../shared/vendor/paseo-plugin-helper/highlight";
|
|
32
|
+
export * from "../../../../shared/vendor/paseo-plugin-helper/forge";
|
|
33
|
+
export * from "../../../../shared/vendor/paseo-plugin-helper/custom-pills";
|
|
34
|
+
export * from "../../../../shared/vendor/paseo-plugin-helper/suppressed";
|
|
35
|
+
export * from "../../../../shared/vendor/paseo-plugin-helper/types";
|
|
36
|
+
export * from "../../../../shared/vendor/paseo-plugin-helper/tickets";
|
|
37
|
+
|
|
38
|
+
export {
|
|
39
|
+
initClientHelpers,
|
|
40
|
+
getClientHost,
|
|
41
|
+
getOptionalClientHost,
|
|
42
|
+
isClientHostInitialized,
|
|
43
|
+
selectHostScrollView,
|
|
44
|
+
} from "./host";
|
|
45
|
+
export type {
|
|
46
|
+
ClientHostDeps,
|
|
47
|
+
HostTheme,
|
|
48
|
+
HostThemeColors,
|
|
49
|
+
HostLayout,
|
|
50
|
+
HostToast,
|
|
51
|
+
HostUseToast,
|
|
52
|
+
HostUseRpc,
|
|
53
|
+
HostRpcContract,
|
|
54
|
+
HostCopyText,
|
|
55
|
+
HostAgentsApi,
|
|
56
|
+
HostAgentRef,
|
|
57
|
+
HostAgentUpdate,
|
|
58
|
+
ComposerPillRegistrar,
|
|
59
|
+
HostPillProps,
|
|
60
|
+
HostSurfaceProps,
|
|
61
|
+
PluginCleanup,
|
|
62
|
+
} from "./host";
|
|
63
|
+
|
|
64
|
+
export * from "./query";
|
|
65
|
+
export * from "./query-refresh";
|
|
66
|
+
export * from "./settings";
|
|
67
|
+
export * from "./shared-settings";
|
|
68
|
+
export * from "./snapshot";
|
|
69
|
+
export * from "./command-center";
|
|
70
|
+
export {
|
|
71
|
+
bumpPluginLoadCount,
|
|
72
|
+
getPluginLoadCount,
|
|
73
|
+
isPluginReloaded,
|
|
74
|
+
usePluginReloadNotice,
|
|
75
|
+
type PluginReloadNoticeState,
|
|
76
|
+
} from "./plugin-load-count";
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Paseo Plugin Helper — Bundle Re-Evaluation Tracking (`paseo-plugin-helper/core`).
|
|
3
|
+
*
|
|
4
|
+
* Tracks how many times each plugin bundle has been re-evaluated by the host
|
|
5
|
+
* daemon. Useful for detecting hot-reload / reload cycles so plugins can
|
|
6
|
+
* surface a notice to the user.
|
|
7
|
+
*
|
|
8
|
+
* Contract — headless & client-safe:
|
|
9
|
+
* - No `node:*` imports.
|
|
10
|
+
* - No React Native or DOM scraping.
|
|
11
|
+
* - The only React dependency is the exported hook (used inside React trees).
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
// ---------------------------------------------------------------------------
|
|
15
|
+
// Global store --------------------------------------------------------------
|
|
16
|
+
// ---------------------------------------------------------------------------
|
|
17
|
+
|
|
18
|
+
declare global {
|
|
19
|
+
// eslint-disable-next-line no-var
|
|
20
|
+
var __PASEO_PLUGIN_LOAD_COUNT__: Record<string, number>;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const _store = (globalThis.__PASEO_PLUGIN_LOAD_COUNT__ ||= {});
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Increment and return the load count for *pluginId*.
|
|
27
|
+
*
|
|
28
|
+
* Call this from your plugin's entry-point (or wherever the bundle first
|
|
29
|
+
* executes) so the daemon-side reload counter advances on every evaluation.
|
|
30
|
+
*/
|
|
31
|
+
export function bumpPluginLoadCount(pluginId: string): number {
|
|
32
|
+
_store[pluginId] = (_store[pluginId] || 0) + 1;
|
|
33
|
+
return _store[pluginId];
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Return the current load count for *pluginId* (0 if never bumped).
|
|
38
|
+
*/
|
|
39
|
+
export function getPluginLoadCount(pluginId: string): number {
|
|
40
|
+
return _store[pluginId] || 0;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Return `true` when the plugin has been reloaded at least once
|
|
45
|
+
* (i.e. load count > 1).
|
|
46
|
+
*/
|
|
47
|
+
export function isPluginReloaded(pluginId: string): boolean {
|
|
48
|
+
return (_store[pluginId] || 0) > 1;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// ---------------------------------------------------------------------------
|
|
52
|
+
// React hook ----------------------------------------------------------------
|
|
53
|
+
// ---------------------------------------------------------------------------
|
|
54
|
+
|
|
55
|
+
import { useState } from "react";
|
|
56
|
+
|
|
57
|
+
export interface PluginReloadNoticeState {
|
|
58
|
+
/** Whether the plugin was reloaded (load count > 1). */
|
|
59
|
+
isReloaded: boolean;
|
|
60
|
+
/** Current load count for the plugin. */
|
|
61
|
+
loadCount: number;
|
|
62
|
+
/** Dismiss the reload notice locally. */
|
|
63
|
+
dismiss: () => void;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* React hook that tracks whether a plugin bundle was reloaded.
|
|
68
|
+
*
|
|
69
|
+
* ```ts
|
|
70
|
+
* const { isReloaded, loadCount, dismiss } = usePluginReloadNotice("my-plugin");
|
|
71
|
+
* ```
|
|
72
|
+
*
|
|
73
|
+
* The `dismiss` callback toggles local state only — it does not affect the
|
|
74
|
+
* global counter.
|
|
75
|
+
*/
|
|
76
|
+
export function usePluginReloadNotice(
|
|
77
|
+
pluginId: string,
|
|
78
|
+
): PluginReloadNoticeState {
|
|
79
|
+
const [dismissed, setDismissed] = useState(false);
|
|
80
|
+
|
|
81
|
+
const loadCount = getPluginLoadCount(pluginId);
|
|
82
|
+
const isReloaded = !dismissed && loadCount > 1;
|
|
83
|
+
|
|
84
|
+
return {
|
|
85
|
+
isReloaded,
|
|
86
|
+
loadCount,
|
|
87
|
+
dismiss: () => setDismissed(true),
|
|
88
|
+
};
|
|
89
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { useState, useMemo } from "react";
|
|
2
|
-
import type { PluginRpcContract } from "
|
|
2
|
+
import type { PluginRpcContract } from "../../../../shared/vendor/paseo-plugin-helper/rpc";
|
|
3
3
|
import { useRpcQuery, type RpcQueryOptions } from "./query";
|
|
4
|
-
import type { RpcInput, RpcOutput } from "
|
|
4
|
+
import type { RpcInput, RpcOutput } from "../../../../shared/vendor/paseo-plugin-helper/rpc";
|
|
5
5
|
|
|
6
6
|
export type RefreshRate =
|
|
7
7
|
| "1s"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { getClientHost, type HostRpcContract } from "./host";
|
|
2
|
-
import type { PluginRpcContract } from "
|
|
3
|
-
import type { RpcInput, RpcOutput } from "
|
|
2
|
+
import type { PluginRpcContract } from "../../../../shared/vendor/paseo-plugin-helper/rpc";
|
|
3
|
+
import type { RpcInput, RpcOutput } from "../../../../shared/vendor/paseo-plugin-helper/rpc";
|
|
4
4
|
import {
|
|
5
5
|
useQuery,
|
|
6
6
|
useMutation,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { getClientHost } from "./host";
|
|
2
2
|
import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query";
|
|
3
|
-
import type { SettingsContract } from "
|
|
3
|
+
import type { SettingsContract } from "../../../../shared/vendor/paseo-plugin-helper/settings";
|
|
4
4
|
|
|
5
5
|
export interface UsePluginSettingsOptions<TSettings> {
|
|
6
6
|
/**
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type { SettingsContract } from "
|
|
2
|
-
import { SuiteSettingsContract, type SuiteSettings } from "
|
|
1
|
+
import type { SettingsContract } from "../../../../shared/vendor/paseo-plugin-helper/settings";
|
|
2
|
+
import { SuiteSettingsContract, type SuiteSettings } from "../../../../shared/vendor/paseo-plugin-helper/suite-settings";
|
|
3
3
|
import {
|
|
4
4
|
usePluginSettings,
|
|
5
5
|
type UsePluginSettingsOptions,
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Visual flair vocabulary accepted by the lifecycle registration options.
|
|
3
|
+
*
|
|
4
|
+
* The legacy design system that consumed these presets is gone (#938); the
|
|
5
|
+
* registrars still accept the shape so existing plugin call sites keep
|
|
6
|
+
* type-checking, but the host theme drives every `ui/` adapter.
|
|
7
|
+
*/
|
|
8
|
+
export type RadiusStyle = "sharp" | "rounded" | "pill";
|
|
9
|
+
export type DensityStyle = "compact" | "comfortable" | "spacious";
|
|
10
|
+
export type SurfaceStyle = "flat" | "tinted" | "elevated";
|
|
11
|
+
export type HeadingTransform = "none" | "uppercase";
|
|
12
|
+
|
|
13
|
+
export interface VisualFlair {
|
|
14
|
+
/** Corner radius preset for interactive elements and containers. */
|
|
15
|
+
radius: RadiusStyle;
|
|
16
|
+
/** Spacing and typography density. */
|
|
17
|
+
density: DensityStyle;
|
|
18
|
+
/** Surface background styling for cards, panels, and modal boxes. */
|
|
19
|
+
surfaceStyle: SurfaceStyle;
|
|
20
|
+
/** Optional custom brand accent color. */
|
|
21
|
+
accentColor?: string;
|
|
22
|
+
/** Default border width for cards and bordered elements (default: 1). */
|
|
23
|
+
borderWidth: number;
|
|
24
|
+
/** Text transform for section headers and meta labels. */
|
|
25
|
+
headingTransform: HeadingTransform;
|
|
26
|
+
}
|