@xpufx/paseo-top 0.4.3 → 0.4.4

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 (33) hide show
  1. package/client/pill-labels.ts +30 -6
  2. package/client/pill.tsx +40 -61
  3. package/client/settings-events.ts +33 -0
  4. package/client/surface.tsx +6 -2
  5. package/client/vendor/paseo-plugin-helper/components/Badge.tsx +12 -0
  6. package/client/vendor/paseo-plugin-helper/components/Button.tsx +22 -2
  7. package/client/vendor/paseo-plugin-helper/components/Card.tsx +32 -0
  8. package/client/vendor/paseo-plugin-helper/components/DataTable.tsx +17 -1
  9. package/client/vendor/paseo-plugin-helper/components/InlineButton.tsx +14 -1
  10. package/client/vendor/paseo-plugin-helper/components/InteractiveRow.tsx +142 -0
  11. package/client/vendor/paseo-plugin-helper/components/SearchInput.tsx +16 -2
  12. package/client/vendor/paseo-plugin-helper/components/SectionHeader.tsx +7 -0
  13. package/client/vendor/paseo-plugin-helper/components/Select.tsx +131 -63
  14. package/client/vendor/paseo-plugin-helper/components/index.ts +1 -0
  15. package/client/vendor/paseo-plugin-helper/custom-pills.tsx +4 -3
  16. package/client/vendor/paseo-plugin-helper/host.ts +12 -58
  17. package/client/vendor/paseo-plugin-helper/index.ts +1 -0
  18. package/client/vendor/paseo-plugin-helper/layout/ModalBody.tsx +17 -27
  19. package/client/vendor/paseo-plugin-helper/pill.tsx +68 -321
  20. package/client/vendor/paseo-plugin-helper/surface.tsx +62 -2
  21. package/client/vendor/paseo-plugin-helper/tickets.tsx +766 -0
  22. package/index.server.ts +7 -0
  23. package/package.json +11 -2
  24. package/server/vendor/paseo-plugin-helper/index.ts +2 -0
  25. package/server/vendor/paseo-plugin-helper/mcp-injection.ts +20 -2
  26. package/server/vendor/paseo-plugin-helper/plugins.ts +184 -19
  27. package/server/vendor/paseo-plugin-helper/tickets.ts +1281 -0
  28. package/shared/helper-version.ts +20 -0
  29. package/shared/multi-host.ts +11 -4
  30. package/shared/resources.ts +1 -1
  31. package/shared/vendor/paseo-plugin-helper/index.ts +1 -0
  32. package/shared/vendor/paseo-plugin-helper/tickets.ts +1010 -0
  33. package/shared/version.ts +1 -1
@@ -0,0 +1,142 @@
1
+ import React, { useCallback, useState, type ReactNode } from "react";
2
+ import {
3
+ Pressable,
4
+ type AccessibilityRole,
5
+ type GestureResponderEvent,
6
+ type StyleProp,
7
+ type ViewStyle,
8
+ } from "react-native";
9
+ import { usePluginTheme } from "../theme/provider";
10
+
11
+ export interface InteractiveRowProps {
12
+ /** Arbitrary row content — status dots, badges, text, metric readouts. */
13
+ children?: ReactNode;
14
+ /**
15
+ * Press handler. Receives the raw event so callers can control propagation
16
+ * (e.g. a nested status light calling `event.stopPropagation()`).
17
+ */
18
+ onPress?: (event: GestureResponderEvent) => void;
19
+ /** Native / RN-web tooltip text attached to the hit area. */
20
+ title?: string;
21
+ disabled?: boolean;
22
+ accessibilityRole?: AccessibilityRole;
23
+ accessibilityLabel?: string;
24
+ accessibilityHint?: string;
25
+ testID?: string;
26
+ /** Base layout style, merged before the interaction layers. */
27
+ style?: StyleProp<ViewStyle>;
28
+ /** Extra style layered only while hovered (and not disabled). */
29
+ hoverStyle?: StyleProp<ViewStyle>;
30
+ /** Apply a subtle theme accent tint while hovered. Default: false. */
31
+ hoverTint?: boolean;
32
+ /** Accent opacity used by `hoverTint`. Default: 0.05. */
33
+ hoverTintOpacity?: number;
34
+ /** Opacity while pressed. Default: 0.7. */
35
+ pressedOpacity?: number;
36
+ /** Opacity while hovered but not pressed. Defaults to `opacity`. */
37
+ hoveredOpacity?: number;
38
+ /** Opacity at rest. Default: 1. */
39
+ opacity?: number;
40
+ /** Opacity when disabled. Default: 0.45. */
41
+ disabledOpacity?: number;
42
+ /** Expanded touch target beyond the visual bounds. */
43
+ hitSlop?: number;
44
+ /** Notified whenever the hover state flips, for callers that tint their own children. */
45
+ onHoverChange?: (hovered: boolean) => void;
46
+ }
47
+
48
+ /**
49
+ * Hover-aware, pressable row container for dense interactive content (#580).
50
+ *
51
+ * Owns the interaction concerns a labeled `Button` cannot: a hover state (with
52
+ * optional accent tint), an RN-web `title` tooltip, pressed opacity, a pointer
53
+ * cursor, and an `onPress` that forwards the event for `stopPropagation`.
54
+ * Content is arbitrary, so a status dot, badges, and metric readouts compose
55
+ * inside without wrapping each in its own control.
56
+ */
57
+ export function InteractiveRow({
58
+ children,
59
+ onPress,
60
+ title,
61
+ disabled = false,
62
+ accessibilityRole,
63
+ accessibilityLabel,
64
+ accessibilityHint,
65
+ testID,
66
+ style,
67
+ hoverStyle,
68
+ hoverTint = false,
69
+ hoverTintOpacity = 0.05,
70
+ pressedOpacity = 0.7,
71
+ hoveredOpacity,
72
+ opacity = 1,
73
+ disabledOpacity = 0.45,
74
+ hitSlop,
75
+ onHoverChange,
76
+ }: InteractiveRowProps) {
77
+ const { colors, alpha } = usePluginTheme();
78
+ const [hovered, setHovered] = useState(false);
79
+ const [pressed, setPressed] = useState(false);
80
+
81
+ const handleMouseEnter = useCallback(() => {
82
+ if (disabled) return;
83
+ setHovered(true);
84
+ onHoverChange?.(true);
85
+ }, [disabled, onHoverChange]);
86
+
87
+ const handleMouseLeave = useCallback(() => {
88
+ setHovered(false);
89
+ onHoverChange?.(false);
90
+ }, [onHoverChange]);
91
+
92
+ // `title` is an RN-web DOM passthrough absent from the native prop types, and
93
+ // `onMouseEnter`/`onMouseLeave` are the RN-web hover hooks the dense rows
94
+ // already relied on; attach both via an untyped spread to keep the runtime
95
+ // semantics identical to the hand-rolled rows (#580).
96
+ const webProps = {
97
+ onMouseEnter: handleMouseEnter,
98
+ onMouseLeave: handleMouseLeave,
99
+ ...(title ? { title } : {}),
100
+ } as any;
101
+
102
+ const interactive = hovered && !disabled;
103
+ const hoverBackground = interactive && hoverTint
104
+ ? { backgroundColor: alpha(colors.accent, hoverTintOpacity) }
105
+ : null;
106
+ const restingOpacity = interactive ? (hoveredOpacity ?? opacity) : opacity;
107
+
108
+ return (
109
+ <Pressable
110
+ {...webProps}
111
+ onPress={onPress}
112
+ onPressIn={() => setPressed(true)}
113
+ onPressOut={() => setPressed(false)}
114
+ disabled={disabled}
115
+ accessibilityRole={accessibilityRole ?? (onPress ? "button" : undefined)}
116
+ accessibilityLabel={accessibilityLabel}
117
+ accessibilityHint={accessibilityHint}
118
+ testID={testID}
119
+ hitSlop={hitSlop}
120
+ style={[
121
+ { cursor: onPress && !disabled ? "pointer" : "auto" },
122
+ // A pressable wraps arbitrary content (titles, badges, metric readouts)
123
+ // and must never widen its parent: Yoga defaults `flexShrink` to 0, so
124
+ // without a shrink budget a long label forces the whole row past the
125
+ // viewport. Declared before `style` so callers can still override.
126
+ { flexShrink: 1, maxWidth: "100%" },
127
+ style,
128
+ hoverBackground,
129
+ interactive ? hoverStyle : null,
130
+ {
131
+ opacity: disabled
132
+ ? disabledOpacity
133
+ : pressed
134
+ ? pressedOpacity
135
+ : restingOpacity,
136
+ },
137
+ ]}
138
+ >
139
+ {children}
140
+ </Pressable>
141
+ );
142
+ }
@@ -18,6 +18,15 @@ export interface SearchInputProps {
18
18
  onChangeText: (text: string) => void;
19
19
  placeholder?: string;
20
20
  onClear?: () => void;
21
+ /**
22
+ * Painted box height, opt-in per call site. Unset keeps the original
23
+ * `isCompact ? 36 : 40` box so no untouched surface changes appearance.
24
+ * 26 matches the compact `size="sm"` button recipe (~26px) so a search field
25
+ * can sit beside filter pills in one row without inflating it (#645); a
26
+ * height of 26 or less also switches the input to the 12px `sm` label size,
27
+ * anything taller keeps the prior 13/14.
28
+ */
29
+ height?: number;
21
30
  style?: StyleProp<ViewStyle>;
22
31
  inputStyle?: StyleProp<TextStyle>;
23
32
  testID?: string;
@@ -31,6 +40,7 @@ export function SearchInput({
31
40
  onChangeText,
32
41
  placeholder = "Search...",
33
42
  onClear,
43
+ height,
34
44
  style,
35
45
  inputStyle,
36
46
  testID,
@@ -40,6 +50,10 @@ export function SearchInput({
40
50
  RNTextInput) as ComponentType<RNTextInputProps & { ref?: Ref<RNTextInputInstance> }>;
41
51
  const { colors, resolveRadius, isCompact } = usePluginTheme();
42
52
  const radius = resolveRadius("sm");
53
+ // Unspecified keeps the original compact-aware default so every call site
54
+ // that does not opt in renders exactly as before (#645's scope was the
55
+ // uppidi-fleet filter rows only).
56
+ const resolvedHeight = height ?? (isCompact ? 36 : 40);
43
57
 
44
58
  const handleClear = () => {
45
59
  onChangeText("");
@@ -54,7 +68,7 @@ export function SearchInput({
54
68
  backgroundColor: colors.surface1,
55
69
  borderColor: colors.border,
56
70
  borderRadius: radius,
57
- height: isCompact ? 36 : 40,
71
+ height: resolvedHeight,
58
72
  },
59
73
  style,
60
74
  ]}
@@ -72,7 +86,7 @@ export function SearchInput({
72
86
  styles.input,
73
87
  {
74
88
  color: colors.foreground,
75
- fontSize: isCompact ? 13 : 14,
89
+ fontSize: height !== undefined && height <= 26 ? 12 : isCompact ? 13 : 14,
76
90
  },
77
91
  inputStyle,
78
92
  ]}
@@ -41,6 +41,8 @@ export function SectionHeader({
41
41
  return (
42
42
  <View style={[styles.container, style]}>
43
43
  <Text
44
+ numberOfLines={1}
45
+ ellipsizeMode="tail"
44
46
  style={[
45
47
  styles.title,
46
48
  {
@@ -73,8 +75,13 @@ const styles = StyleSheet.create({
73
75
  gap: 8,
74
76
  marginTop: 8,
75
77
  marginBottom: 2,
78
+ flexShrink: 1,
79
+ maxWidth: "100%",
76
80
  },
77
81
  title: {
78
82
  letterSpacing: 0.8,
83
+ // Section titles are caller-supplied and unbounded; the title must be
84
+ // allowed to compress for `numberOfLines` to engage.
85
+ flexShrink: 1,
79
86
  },
80
87
  });
@@ -1,9 +1,11 @@
1
- import React, { useState } from "react";
1
+ import React, { useRef, useState } from "react";
2
2
  import {
3
+ Modal,
3
4
  Pressable,
4
5
  ScrollView as FallbackScrollView,
5
6
  StyleSheet,
6
7
  Text,
8
+ TouchableWithoutFeedback,
7
9
  View,
8
10
  type StyleProp,
9
11
  type ViewStyle,
@@ -32,10 +34,25 @@ export interface SelectProps {
32
34
 
33
35
  const OPTION_LIST_MAX_HEIGHT = 216;
34
36
 
37
+ interface TriggerCoords {
38
+ x: number;
39
+ y: number;
40
+ width: number;
41
+ height: number;
42
+ }
43
+
44
+ // When `measureInWindow` is unavailable or never invokes its callback (node
45
+ // test renderers, host shims), the menu still opens anchored to a zeroed box
46
+ // rather than swallowing the press.
47
+ const FALLBACK_COORDS: TriggerCoords = { x: 0, y: 0, width: 0, height: 0 };
48
+
35
49
  /**
36
50
  * Compact single-choice picker sized to sit inside a {@link FormRow}. The
37
- * closed trigger stays one line tall; opening reveals a bounded, scrollable
38
- * option list, so a long list degrades to scrolling rather than overflow.
51
+ * closed trigger stays one line tall; opening mounts the menu in a root
52
+ * transparent `<Modal>` overlay portal, so a long list never expands the
53
+ * trigger's parent container, is never clipped by an ancestor
54
+ * `overflow: "hidden"` (Card/Tabs/Modal), and always paints above later
55
+ * siblings regardless of local stacking context.
39
56
  */
40
57
  export function Select({
41
58
  value,
@@ -48,12 +65,14 @@ export function Select({
48
65
  style,
49
66
  }: SelectProps) {
50
67
  const { Icon } = getClientHost();
51
- // The dropdown option list is a bounded box nested inside the host sheet,
52
- // so it scrolls with a plain React Native ScrollView — never the host
53
- // sheet-gesture scroller (#219).
68
+ // The option list is mounted in the root modal overlay, so it scrolls with
69
+ // a plain React Native ScrollView — never the host sheet-gesture scroller
70
+ // (#219) and never a scroller owned by the trigger's parent.
54
71
  const { colors, resolveRadius, typography, isCompact, touchTargetMin, alpha } =
55
72
  usePluginTheme();
56
73
  const [open, setOpen] = useState(false);
74
+ const [coords, setCoords] = useState<TriggerCoords | null>(null);
75
+ const triggerRef = useRef<View>(null);
57
76
 
58
77
  const caption = typography?.caption ?? {
59
78
  fontSize: 11,
@@ -76,14 +95,40 @@ export function Select({
76
95
 
77
96
  const triggerMinHeight = size === "sm" ? 28 : Math.max(34, touchTargetMin);
78
97
 
98
+ const openAt = (next: TriggerCoords) => {
99
+ setCoords(next);
100
+ setOpen(true);
101
+ };
102
+
103
+ const handleToggle = () => {
104
+ if (isOpen) {
105
+ setOpen(false);
106
+ return;
107
+ }
108
+
109
+ const node = triggerRef.current;
110
+ // A node/shim without `measureInWindow` (node test renderers, stripped
111
+ // host shims) still opens anchored to a zeroed box rather than swallowing
112
+ // the press (#520).
113
+ if (!node || typeof node.measureInWindow !== "function") {
114
+ openAt(FALLBACK_COORDS);
115
+ return;
116
+ }
117
+
118
+ node.measureInWindow((x, y, width, height) => {
119
+ openAt({ x, y, width, height });
120
+ });
121
+ };
122
+
79
123
  return (
80
124
  <View style={[styles.container, style]}>
81
125
  <Pressable
126
+ ref={triggerRef}
82
127
  accessibilityRole="button"
83
128
  accessibilityLabel={label ? `${label}: ${display}` : display}
84
129
  accessibilityState={{ expanded: isOpen, disabled }}
85
130
  disabled={!canOpen}
86
- onPress={() => setOpen((prev) => !prev)}
131
+ onPress={handleToggle}
87
132
  style={({ pressed }) => [
88
133
  styles.trigger,
89
134
  {
@@ -122,67 +167,84 @@ export function Select({
122
167
  />
123
168
  </Pressable>
124
169
 
125
- {isOpen ? (
126
- <View
127
- style={[
128
- styles.optionList,
129
- {
130
- borderRadius: radius,
131
- borderColor: colors.border,
132
- backgroundColor: colors.surface0,
133
- marginTop: spacing.xs,
134
- },
135
- ]}
170
+ {isOpen && coords ? (
171
+ <Modal
172
+ transparent
173
+ visible={isOpen}
174
+ animationType="none"
175
+ onRequestClose={() => setOpen(false)}
136
176
  >
137
- <FallbackScrollView
138
- nestedScrollEnabled
139
- keyboardShouldPersistTaps="handled"
140
- style={{ maxHeight: OPTION_LIST_MAX_HEIGHT }}
177
+ <TouchableWithoutFeedback
178
+ accessibilityRole="button"
179
+ accessibilityLabel="Dismiss options"
180
+ onPress={() => setOpen(false)}
181
+ >
182
+ <View style={StyleSheet.absoluteFill} />
183
+ </TouchableWithoutFeedback>
184
+
185
+ <View
186
+ style={[
187
+ styles.overlayList,
188
+ {
189
+ top: coords.y + coords.height + spacing.xs,
190
+ left: coords.x,
191
+ minWidth: coords.width,
192
+ borderRadius: radius,
193
+ borderColor: colors.border,
194
+ backgroundColor: colors.surface0,
195
+ },
196
+ ]}
141
197
  >
142
- {options.map((option) => {
143
- const isSelected = option.value === value;
144
- return (
145
- <Pressable
146
- key={option.value}
147
- accessibilityRole="button"
148
- accessibilityLabel={option.label}
149
- accessibilityState={{ selected: isSelected }}
150
- onPress={() => {
151
- onValueChange(option.value);
152
- setOpen(false);
153
- }}
154
- style={({ pressed }) => [
155
- styles.option,
156
- {
157
- paddingVertical,
158
- paddingHorizontal,
159
- backgroundColor: isSelected
160
- ? colors.surface2
161
- : pressed
162
- ? alpha(colors.surface2, 0.5)
163
- : "transparent",
164
- },
165
- ]}
166
- >
167
- <Text
168
- numberOfLines={1}
169
- style={[
170
- styles.optionText,
198
+ <FallbackScrollView
199
+ nestedScrollEnabled
200
+ keyboardShouldPersistTaps="handled"
201
+ style={{ maxHeight: OPTION_LIST_MAX_HEIGHT }}
202
+ >
203
+ {options.map((option) => {
204
+ const isSelected = option.value === value;
205
+ return (
206
+ <Pressable
207
+ key={option.value}
208
+ accessibilityRole="button"
209
+ accessibilityLabel={option.label}
210
+ accessibilityState={{ selected: isSelected }}
211
+ onPress={() => {
212
+ onValueChange(option.value);
213
+ setOpen(false);
214
+ }}
215
+ style={({ pressed }) => [
216
+ styles.option,
171
217
  {
172
- color: isSelected ? colors.foreground : colors.foregroundMuted,
173
- fontSize: isCompact ? fontSize : fontSize + 1,
174
- lineHeight,
175
- fontWeight: isSelected ? "600" : "400",
218
+ paddingVertical,
219
+ paddingHorizontal,
220
+ backgroundColor: isSelected
221
+ ? colors.surface2
222
+ : pressed
223
+ ? alpha(colors.surface2, 0.5)
224
+ : "transparent",
176
225
  },
177
226
  ]}
178
227
  >
179
- {option.label}
180
- </Text>
181
- </Pressable>
182
- );
183
- })}
184
- </FallbackScrollView>
185
- </View>
228
+ <Text
229
+ numberOfLines={1}
230
+ style={[
231
+ styles.optionText,
232
+ {
233
+ color: isSelected ? colors.foreground : colors.foregroundMuted,
234
+ fontSize: isCompact ? fontSize : fontSize + 1,
235
+ lineHeight,
236
+ fontWeight: isSelected ? "600" : "400",
237
+ },
238
+ ]}
239
+ >
240
+ {option.label}
241
+ </Text>
242
+ </Pressable>
243
+ );
244
+ })}
245
+ </FallbackScrollView>
246
+ </View>
247
+ </Modal>
186
248
  ) : null}
187
249
  </View>
188
250
  );
@@ -203,9 +265,15 @@ const styles = StyleSheet.create({
203
265
  flexShrink: 1,
204
266
  minWidth: 0,
205
267
  },
206
- optionList: {
268
+ overlayList: {
269
+ position: "absolute",
207
270
  borderWidth: 1,
208
271
  overflow: "hidden",
272
+ elevation: 20,
273
+ shadowColor: "#000",
274
+ shadowOffset: { width: 0, height: 4 },
275
+ shadowOpacity: 0.25,
276
+ shadowRadius: 8,
209
277
  },
210
278
  option: {},
211
279
  optionText: {
@@ -1,5 +1,6 @@
1
1
  export * from "./Button";
2
2
  export * from "./InlineButton";
3
+ export * from "./InteractiveRow";
3
4
  export * from "./AttentionBeacon";
4
5
  export * from "./Badge";
5
6
  export * from "./StatusDot";
@@ -17,8 +17,10 @@ export interface CustomPillBodyProps {
17
17
  }
18
18
 
19
19
  /**
20
- * Standard pill body renderer for a custom metric pill in the composer trackbar.
21
- * Automatically adapts to responsive compact/mobile modes and shows threshold status.
20
+ * Standard pill body renderer for a custom metric pill. The host renders the
21
+ * composer pill body itself, so reach for this from a pill's own surface
22
+ * (`renderModal`) rather than from the trackbar; it adapts to responsive
23
+ * compact/mobile modes and shows threshold status.
22
24
  */
23
25
  export function CustomPillBody({ state }: CustomPillBodyProps) {
24
26
  const { Icon } = getClientHost();
@@ -145,7 +147,6 @@ export function registerCustomPills(
145
147
  flair: options.flair,
146
148
  resolveLabel: () =>
147
149
  pill.displayValue ? `${pill.title} ${pill.displayValue}` : pill.title,
148
- renderPill: () => <CustomPillBody state={pill} />,
149
150
  renderModal: () => {
150
151
  const [refreshing, setRefreshing] = useState(false);
151
152
  const [currentOutput, setCurrentOutput] = useState<string | undefined>(
@@ -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
25
  * 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.
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 {
@@ -216,57 +219,8 @@ export interface HostSurfaceProps {
216
219
  };
217
220
  }
218
221
 
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
222
  export interface ComposerPillRegistrar {
264
- addComposerPill(
265
- contribution:
266
- | ComposerPillContribution
267
- | ComposerPillButtonContribution
268
- | ComposerPillSdkContribution,
269
- ): ComposerPillRegistration;
223
+ addComposerPill(contribution: PluginComposerPillContribution): PluginButtonRegistration;
270
224
  paseo: {
271
225
  agents: HostAgentsApi;
272
226
  };
@@ -27,3 +27,4 @@ export {
27
27
  type ForgeMarkInput,
28
28
  type ResolvedForgeMark,
29
29
  } from "../../../shared/vendor/paseo-plugin-helper/forge";
30
+ export * from "./tickets";