@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.
Files changed (130) hide show
  1. package/OVERVIEW.md +18 -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 +94 -1
  6. package/client/pill.tsx +692 -616
  7. package/client/resources-query.ts +1 -1
  8. package/client/settings-events.ts +1 -1
  9. package/client/settings-ui.tsx +86 -9
  10. package/client/surface.tsx +308 -276
  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} +9 -3
  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} +51 -18
  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/{surface.tsx → lifecycle/surface.tsx} +6 -6
  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} +50 -58
  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 -234
  48. package/npm-shrinkwrap.json +44 -0
  49. package/package.json +8 -4
  50. package/paseo-plugin.json +2 -0
  51. package/screenshots/1-paseo-top-modal-system.jpg +0 -0
  52. package/screenshots/2-paseo-top-modal-workspace.jpg +0 -0
  53. package/screenshots/3-paseo-top-modal-settings.jpg +0 -0
  54. package/screenshots/4-paseo-top-modal-about.jpg +0 -0
  55. package/screenshots/paseo-top-dashboard.jpg +0 -0
  56. package/screenshots/paseo-top-general-view.jpg +0 -0
  57. package/server/resources.ts +98 -0
  58. package/server/vendor/paseo-plugin-helper/custom-pills.ts +70 -0
  59. package/server/vendor/paseo-plugin-helper/index.ts +2 -0
  60. package/server/vendor/paseo-plugin-helper/logger.ts +5 -16
  61. package/server/vendor/paseo-plugin-helper/rpc-guard.ts +2 -2
  62. package/server/vendor/paseo-plugin-helper/storage-guard.ts +294 -0
  63. package/server/vendor/paseo-plugin-helper/storage.ts +36 -2
  64. package/server/vendor/paseo-plugin-helper/telemetry.ts +486 -0
  65. package/server/vendor/paseo-plugin-helper/tickets.ts +18 -67
  66. package/server/vendor/permission-audit/index.ts +1 -0
  67. package/server/vendor/permission-audit/server.ts +839 -0
  68. package/shared/helper-version.ts +1 -1
  69. package/shared/multi-host.ts +153 -159
  70. package/shared/resources.ts +145 -0
  71. package/shared/vendor/paseo-plugin-helper/async.ts +14 -7
  72. package/shared/vendor/paseo-plugin-helper/features.ts +244 -0
  73. package/shared/vendor/paseo-plugin-helper/forge.ts +27 -0
  74. package/shared/vendor/paseo-plugin-helper/index.ts +1 -0
  75. package/shared/vendor/paseo-plugin-helper/tickets.ts +122 -28
  76. package/shared/vendor/permission-audit/filter.ts +61 -0
  77. package/shared/vendor/permission-audit/index.ts +2 -0
  78. package/shared/vendor/permission-audit/shared.ts +119 -0
  79. package/shared/version.ts +1 -1
  80. package/client/vendor/paseo-plugin-helper/components/AboutSection.tsx +0 -493
  81. package/client/vendor/paseo-plugin-helper/components/AttentionBeacon.tsx +0 -250
  82. package/client/vendor/paseo-plugin-helper/components/Badge.tsx +0 -168
  83. package/client/vendor/paseo-plugin-helper/components/Button.tsx +0 -204
  84. package/client/vendor/paseo-plugin-helper/components/Card.tsx +0 -257
  85. package/client/vendor/paseo-plugin-helper/components/CodeBlock.tsx +0 -196
  86. package/client/vendor/paseo-plugin-helper/components/Collapsible.tsx +0 -277
  87. package/client/vendor/paseo-plugin-helper/components/CommandBox.tsx +0 -172
  88. package/client/vendor/paseo-plugin-helper/components/CopyButton.tsx +0 -180
  89. package/client/vendor/paseo-plugin-helper/components/EmptyState.tsx +0 -97
  90. package/client/vendor/paseo-plugin-helper/components/HighlightedText.tsx +0 -70
  91. package/client/vendor/paseo-plugin-helper/components/InlineButton.tsx +0 -88
  92. package/client/vendor/paseo-plugin-helper/components/InteractiveRow.tsx +0 -142
  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 -132
  98. package/client/vendor/paseo-plugin-helper/components/SectionHeader.tsx +0 -87
  99. package/client/vendor/paseo-plugin-helper/components/Select.tsx +0 -283
  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 -26
  106. package/client/vendor/paseo-plugin-helper/custom-pills.tsx +0 -225
  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 -30
  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 -368
  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/theme/flair.ts +0 -76
  121. package/client/vendor/paseo-plugin-helper/theme/host-variables.ts +0 -121
  122. package/client/vendor/paseo-plugin-helper/theme/index.ts +0 -7
  123. package/client/vendor/paseo-plugin-helper/theme/provider.tsx +0 -178
  124. package/client/vendor/paseo-plugin-helper/theme/responsive.ts +0 -213
  125. package/client/vendor/paseo-plugin-helper/theme/tokens.ts +0 -200
  126. package/client/vendor/paseo-plugin-helper/theme/useResponsive.ts +0 -57
  127. package/client/vendor/paseo-plugin-helper/tickets.tsx +0 -766
  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;
@@ -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 `paseo-plugin-helper/client` needs
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<{ entries: Array<{ agent: HostAgentRef }> }>;
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/client used before initClientHelpers(). " +
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 "../../../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
+ }