@xpufx/paseo-top 0.4.3 → 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.
Files changed (130) hide show
  1. package/OVERVIEW.md +17 -0
  2. package/client/host-ui.tsx +184 -0
  3. package/client/multi-host-view.tsx +57 -43
  4. package/client/multi-host.ts +36 -13
  5. package/client/pill-labels.ts +124 -7
  6. package/client/pill.tsx +724 -669
  7. package/client/resources-query.ts +1 -1
  8. package/client/settings-events.ts +33 -0
  9. package/client/settings-ui.tsx +86 -9
  10. package/client/surface.tsx +310 -274
  11. package/client/telemetry-copy.ts +8 -2
  12. package/client/telemetry.tsx +372 -321
  13. package/client/turn-panel.tsx +126 -104
  14. package/client/vendor/paseo-plugin-helper/{host.ts → core/host.ts} +21 -61
  15. package/client/vendor/paseo-plugin-helper/core/index.ts +76 -0
  16. package/client/vendor/paseo-plugin-helper/core/plugin-load-count.ts +89 -0
  17. package/client/vendor/paseo-plugin-helper/{query-refresh.ts → core/query-refresh.ts} +2 -2
  18. package/client/vendor/paseo-plugin-helper/{query.ts → core/query.ts} +2 -2
  19. package/client/vendor/paseo-plugin-helper/{settings.ts → core/settings.ts} +1 -1
  20. package/client/vendor/paseo-plugin-helper/{shared-settings.ts → core/shared-settings.ts} +2 -2
  21. package/client/vendor/paseo-plugin-helper/{utils → lifecycle}/clipboard.ts +2 -2
  22. package/client/vendor/paseo-plugin-helper/lifecycle/flair.ts +26 -0
  23. package/client/vendor/paseo-plugin-helper/{theme/color-utils.ts → lifecycle/host-color.ts} +95 -38
  24. package/client/vendor/paseo-plugin-helper/lifecycle/host-theme.tsx +109 -0
  25. package/client/vendor/paseo-plugin-helper/lifecycle/index.ts +23 -0
  26. package/client/vendor/paseo-plugin-helper/lifecycle/multi-host.ts +66 -0
  27. package/client/vendor/paseo-plugin-helper/{panel.tsx → lifecycle/panel.tsx} +7 -7
  28. package/client/vendor/paseo-plugin-helper/{pill.tsx → lifecycle/pill.tsx} +118 -338
  29. package/client/vendor/paseo-plugin-helper/lifecycle/providers.tsx +46 -0
  30. package/client/vendor/paseo-plugin-helper/lifecycle/scroll-owner.ts +26 -0
  31. package/client/vendor/paseo-plugin-helper/lifecycle/surface.tsx +140 -0
  32. package/client/vendor/paseo-plugin-helper/ui/color.ts +1 -0
  33. package/client/vendor/paseo-plugin-helper/ui/content.tsx +1326 -0
  34. package/client/vendor/paseo-plugin-helper/ui/controls.tsx +1018 -0
  35. package/client/vendor/paseo-plugin-helper/{components/DataTable.tsx → ui/data.tsx} +55 -47
  36. package/client/vendor/paseo-plugin-helper/ui/index.ts +44 -0
  37. package/client/vendor/paseo-plugin-helper/ui/layout.tsx +263 -0
  38. package/client/vendor/paseo-plugin-helper/ui/modal.tsx +111 -0
  39. package/client/vendor/paseo-plugin-helper/ui/plugin-reload-banner.tsx +119 -0
  40. package/client/vendor/paseo-plugin-helper/{settings-screen.tsx → ui/settings-screen.tsx} +3 -3
  41. package/client/vendor/paseo-plugin-helper/ui/settings.ts +36 -0
  42. package/client/vendor/paseo-plugin-helper/ui/text.tsx +821 -0
  43. package/client/vendor/paseo-plugin-helper/ui/theme.tsx +1 -0
  44. package/client/vendor/permission-audit/client.tsx +706 -0
  45. package/client/vendor/permission-audit/index.tsx +1 -0
  46. package/index.client.tsx +58 -37
  47. package/index.server.ts +256 -227
  48. package/package.json +14 -2
  49. package/paseo-plugin.json +2 -0
  50. package/screenshots/1-paseo-top-modal-system.jpg +0 -0
  51. package/screenshots/2-paseo-top-modal-workspace.jpg +0 -0
  52. package/screenshots/3-paseo-top-modal-settings.jpg +0 -0
  53. package/screenshots/4-paseo-top-modal-about.jpg +0 -0
  54. package/screenshots/paseo-top-dashboard.jpg +0 -0
  55. package/screenshots/paseo-top-general-view.jpg +0 -0
  56. package/server/resources.ts +98 -0
  57. package/server/vendor/paseo-plugin-helper/custom-pills.ts +70 -0
  58. package/server/vendor/paseo-plugin-helper/index.ts +4 -0
  59. package/server/vendor/paseo-plugin-helper/logger.ts +5 -16
  60. package/server/vendor/paseo-plugin-helper/mcp-injection.ts +20 -2
  61. package/server/vendor/paseo-plugin-helper/plugins.ts +184 -19
  62. package/server/vendor/paseo-plugin-helper/rpc-guard.ts +2 -2
  63. package/server/vendor/paseo-plugin-helper/storage-guard.ts +294 -0
  64. package/server/vendor/paseo-plugin-helper/storage.ts +36 -2
  65. package/server/vendor/paseo-plugin-helper/telemetry.ts +486 -0
  66. package/server/vendor/paseo-plugin-helper/tickets.ts +1232 -0
  67. package/server/vendor/permission-audit/index.ts +1 -0
  68. package/server/vendor/permission-audit/server.ts +839 -0
  69. package/shared/helper-version.ts +20 -0
  70. package/shared/multi-host.ts +156 -155
  71. package/shared/resources.ts +146 -1
  72. package/shared/vendor/paseo-plugin-helper/async.ts +14 -7
  73. package/shared/vendor/paseo-plugin-helper/features.ts +244 -0
  74. package/shared/vendor/paseo-plugin-helper/forge.ts +27 -0
  75. package/shared/vendor/paseo-plugin-helper/index.ts +2 -0
  76. package/shared/vendor/paseo-plugin-helper/tickets.ts +1104 -0
  77. package/shared/vendor/permission-audit/filter.ts +61 -0
  78. package/shared/vendor/permission-audit/index.ts +2 -0
  79. package/shared/vendor/permission-audit/shared.ts +119 -0
  80. package/shared/version.ts +1 -1
  81. package/client/vendor/paseo-plugin-helper/components/AboutSection.tsx +0 -493
  82. package/client/vendor/paseo-plugin-helper/components/AttentionBeacon.tsx +0 -250
  83. package/client/vendor/paseo-plugin-helper/components/Badge.tsx +0 -156
  84. package/client/vendor/paseo-plugin-helper/components/Button.tsx +0 -184
  85. package/client/vendor/paseo-plugin-helper/components/Card.tsx +0 -225
  86. package/client/vendor/paseo-plugin-helper/components/CodeBlock.tsx +0 -196
  87. package/client/vendor/paseo-plugin-helper/components/Collapsible.tsx +0 -277
  88. package/client/vendor/paseo-plugin-helper/components/CommandBox.tsx +0 -172
  89. package/client/vendor/paseo-plugin-helper/components/CopyButton.tsx +0 -180
  90. package/client/vendor/paseo-plugin-helper/components/EmptyState.tsx +0 -97
  91. package/client/vendor/paseo-plugin-helper/components/HighlightedText.tsx +0 -70
  92. package/client/vendor/paseo-plugin-helper/components/InlineButton.tsx +0 -75
  93. package/client/vendor/paseo-plugin-helper/components/KeyValue.tsx +0 -446
  94. package/client/vendor/paseo-plugin-helper/components/MetricGauge.tsx +0 -247
  95. package/client/vendor/paseo-plugin-helper/components/ProgressBar.tsx +0 -117
  96. package/client/vendor/paseo-plugin-helper/components/Responsive.tsx +0 -53
  97. package/client/vendor/paseo-plugin-helper/components/SearchInput.tsx +0 -118
  98. package/client/vendor/paseo-plugin-helper/components/SectionHeader.tsx +0 -80
  99. package/client/vendor/paseo-plugin-helper/components/Select.tsx +0 -215
  100. package/client/vendor/paseo-plugin-helper/components/StatusDot.tsx +0 -80
  101. package/client/vendor/paseo-plugin-helper/components/Tabs.tsx +0 -319
  102. package/client/vendor/paseo-plugin-helper/components/TextInput.tsx +0 -150
  103. package/client/vendor/paseo-plugin-helper/components/Toggle.tsx +0 -163
  104. package/client/vendor/paseo-plugin-helper/components/TruncatedText.tsx +0 -157
  105. package/client/vendor/paseo-plugin-helper/components/index.ts +0 -25
  106. package/client/vendor/paseo-plugin-helper/custom-pills.tsx +0 -224
  107. package/client/vendor/paseo-plugin-helper/forge-icon.tsx +0 -79
  108. package/client/vendor/paseo-plugin-helper/icon.tsx +0 -39
  109. package/client/vendor/paseo-plugin-helper/index.ts +0 -29
  110. package/client/vendor/paseo-plugin-helper/layout/ActionBar.tsx +0 -49
  111. package/client/vendor/paseo-plugin-helper/layout/FormRow.tsx +0 -103
  112. package/client/vendor/paseo-plugin-helper/layout/Grid.tsx +0 -65
  113. package/client/vendor/paseo-plugin-helper/layout/ModalBody.tsx +0 -378
  114. package/client/vendor/paseo-plugin-helper/layout/ModalContent.tsx +0 -51
  115. package/client/vendor/paseo-plugin-helper/layout/Row.tsx +0 -39
  116. package/client/vendor/paseo-plugin-helper/layout/Stack.tsx +0 -39
  117. package/client/vendor/paseo-plugin-helper/layout/index.ts +0 -7
  118. package/client/vendor/paseo-plugin-helper/styles/index.ts +0 -1
  119. package/client/vendor/paseo-plugin-helper/styles/recipes.ts +0 -550
  120. package/client/vendor/paseo-plugin-helper/surface.tsx +0 -80
  121. package/client/vendor/paseo-plugin-helper/theme/flair.ts +0 -76
  122. package/client/vendor/paseo-plugin-helper/theme/host-variables.ts +0 -121
  123. package/client/vendor/paseo-plugin-helper/theme/index.ts +0 -7
  124. package/client/vendor/paseo-plugin-helper/theme/provider.tsx +0 -178
  125. package/client/vendor/paseo-plugin-helper/theme/responsive.ts +0 -213
  126. package/client/vendor/paseo-plugin-helper/theme/tokens.ts +0 -200
  127. package/client/vendor/paseo-plugin-helper/theme/useResponsive.ts +0 -57
  128. /package/client/vendor/paseo-plugin-helper/{command-center.ts → core/command-center.ts} +0 -0
  129. /package/client/vendor/paseo-plugin-helper/{snapshot.ts → core/snapshot.ts} +0 -0
  130. /package/client/vendor/paseo-plugin-helper/{utils → lifecycle}/haptics.ts +0 -0
@@ -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
- Badge,
8
- Card,
9
- CardHeader,
10
- EmptyState,
11
- KeyValue,
12
- KeyValueGroup,
13
- ModalBody,
14
- PluginThemeProvider,
15
- Row,
16
- SectionHeader,
17
- Stack,
18
- usePluginTheme,
19
- } from "./vendor/paseo-plugin-helper/index";
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 the helper
43
- * theme provider (unlike `registerWorkspacePanel`), so the body is wrapped here.
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
- <PluginThemeProvider theme={theme} layout={layout}>
48
- <TurnCounterBody agentId={agentId} />
49
- </PluginThemeProvider>
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, padding } = usePluginTheme();
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
- <ModalBody
89
- size="large"
90
- headerMode="pinned"
91
- refreshing={turnsQuery.isFetching}
92
- onRefresh={() => void turnsQuery.refetch()}
93
- header={
94
- <Row justify="space-between" align="center" gap="sm">
95
- <Text style={{ color: colors.foreground, fontSize: 18, fontWeight: "700" }}>
96
- Turn Counter
97
- </Text>
98
- {agent?.status ? (
99
- <Badge
100
- label={agent.status}
101
- variant={agent.status === "running" ? "success" : "neutral"}
102
- size="sm"
103
- dot
104
- />
105
- ) : null}
106
- </Row>
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
- <Text style={{ color: colors.foregroundMuted, fontSize: 12 }}>
143
- {turnsQuery.isPending ? "Reading timeline…" : "No user turns recorded yet."}
144
- </Text>
145
- )}
146
- </Card>
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
- {turnsQuery.error ? (
149
- <Text selectable style={{ color: colors.statusDanger, fontSize: 12 }}>
150
- Failed to read timeline: {String(turnsQuery.error)}
151
- </Text>
152
- ) : null}
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
- {ordered.length > 0 ? (
155
- <>
156
- <SectionHeader title="Turns" count={ordered.length} />
157
- <Stack gap="sm">
158
- {ordered.map((turn) => (
159
- <Card key={turn.seq} variant="elevated">
160
- <KeyValueGroup columns={1}>
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
- </KeyValueGroup>
169
- </Card>
170
- ))}
171
- </Stack>
172
- </>
173
- ) : !turnsQuery.isPending && !turnsQuery.error ? (
174
- <EmptyState
175
- icon="MessageSquare"
176
- title="No turns yet"
177
- description="Send the agent a message and its first turn will appear here."
178
- />
179
- ) : null}
180
- </ModalBody>
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;
@@ -14,20 +14,23 @@ import type {
14
14
  TextInput as RNTextInput,
15
15
  TextInputProps,
16
16
  } from "react-native";
17
+ import type {
18
+ PluginButtonRegistration,
19
+ PluginComposerPillContribution,
20
+ } from "@getpaseo/plugin/client";
17
21
 
18
22
  /**
19
23
  * Structural host types for Paseo client integration.
20
24
  *
21
- * These interfaces describe the shapes `paseo-plugin-helper/client` needs
22
- * from the Paseo host app. They are intentionally decoupled from any
23
- * Paseo SDK version: this module (and every client module built on
24
- * it) contains zero Paseo SDK imports, so a single published helper
25
- * bundle satisfies both the Paseo v0.7 SDK entry points and the Paseo
26
- * v0.8 runtime-owned entry points.
25
+ * These interfaces describe the shapes the helper's client runtime needs
26
+ * from the Paseo host app: the runtime dependencies the plugin injects once
27
+ * in its client entry — the host theme, the layout, the icon/Modal primitives,
28
+ * the agents feed — so they can be supplied from any entry point.
27
29
  *
28
- * The plugin author provides the real host implementations once, in the
29
- * client entry, using whichever specifiers match their installed SDK.
30
- * See docs/client.md for the per-version import paths.
30
+ * The composer pill is the exception: the host owns that contribution's shape,
31
+ * so it is imported from the Paseo SDK rather than restated here. A restated
32
+ * copy is what let a pre-0.9 `{Component, onPress}` pill through the type
33
+ * system (#666).
31
34
  */
32
35
 
33
36
  export interface HostThemeColors {
@@ -107,9 +110,15 @@ export type HostAgentUpdate =
107
110
  | { kind: "remove"; agentId: string }
108
111
  | { kind: string; agent: HostAgentRef };
109
112
 
113
+ export interface HostAgentListOptions {
114
+ subscribe?: Record<string, unknown>;
115
+ signal?: AbortSignal;
116
+ [key: string]: unknown;
117
+ }
118
+
110
119
  export interface HostAgentsApi {
111
120
  subscribe(cb: (update: HostAgentUpdate) => void): () => void;
112
- list(): Promise<{ entries: Array<{ agent: HostAgentRef }> }>;
121
+ list(options?: any): Promise<any>;
113
122
  }
114
123
 
115
124
  export type PluginCleanup = () => void;
@@ -148,7 +157,7 @@ export function initClientHelpers(host: ClientHostDeps): void {
148
157
  export function getClientHost(): ClientHostDeps {
149
158
  if (!deps) {
150
159
  throw new Error(
151
- "paseo-plugin-helper/client used before initClientHelpers(). " +
160
+ "paseo-plugin-helper used before initClientHelpers(). " +
152
161
  "Call initClientHelpers({ Icon, Modal, useRpc, useToast }) in the plugin client entry.",
153
162
  );
154
163
  }
@@ -216,57 +225,8 @@ export interface HostSurfaceProps {
216
225
  };
217
226
  }
218
227
 
219
- export interface ComposerPillContribution {
220
- id: string;
221
- title: string;
222
- workspaceId: string;
223
- agentId: string;
224
- Component: ComponentType<HostPillProps>;
225
- onPress(): void | Promise<void>;
226
- }
227
-
228
- export type ComposerPillButtonIcon = string | ComponentType<any>;
229
-
230
- export interface ComposerPillButtonDescriptor {
231
- title: string;
232
- icon: ComposerPillButtonIcon;
233
- label?: string;
234
- visible?: boolean;
235
- disabled?: boolean;
236
- behavior:
237
- | { kind: "action"; onPress(): void | Promise<void> }
238
- | { kind: "popover"; Content: ComponentType<any> };
239
- }
240
-
241
- export interface ComposerPillButtonContribution {
242
- id: string;
243
- workspaceId: string;
244
- agentId: string;
245
- button: ComposerPillButtonDescriptor;
246
- }
247
-
248
- export interface ComposerPillSdkContribution {
249
- id: string;
250
- workspaceId: string;
251
- agentId: string;
252
- button: Record<string, any>;
253
- [key: string]: any;
254
- }
255
-
256
- export interface ComposerPillRegistrationHandle {
257
- update(patch: Record<string, any>): void;
258
- remove(): void;
259
- }
260
-
261
- export type ComposerPillRegistration = PluginCleanup | ComposerPillRegistrationHandle;
262
-
263
228
  export interface ComposerPillRegistrar {
264
- addComposerPill(
265
- contribution:
266
- | ComposerPillContribution
267
- | ComposerPillButtonContribution
268
- | ComposerPillSdkContribution,
269
- ): ComposerPillRegistration;
229
+ addComposerPill(contribution: PluginComposerPillContribution): PluginButtonRegistration;
270
230
  paseo: {
271
231
  agents: HostAgentsApi;
272
232
  };
@@ -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 "../../../shared/vendor/paseo-plugin-helper/rpc";
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 "../../../shared/vendor/paseo-plugin-helper/rpc";
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 "../../../shared/vendor/paseo-plugin-helper/rpc";
3
- import type { RpcInput, RpcOutput } from "../../../shared/vendor/paseo-plugin-helper/rpc";
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 "../../../shared/vendor/paseo-plugin-helper/settings";
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 "../../../shared/vendor/paseo-plugin-helper/settings";
2
- import { SuiteSettingsContract, type SuiteSettings } from "../../../shared/vendor/paseo-plugin-helper/suite-settings";
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,
@@ -1,5 +1,5 @@
1
- import type { HostToast } from "../host";
2
- import { getOptionalClientHost } from "../host";
1
+ import type { HostToast } from "../core/host";
2
+ import { getOptionalClientHost } from "../core/host";
3
3
 
4
4
  export interface CopyToClipboardOptions {
5
5
  toast?: HostToast;
@@ -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
+ }