@omercnet/paseo-agent-crew 1.1.0-next.198.1 → 1.1.0-next.206.1

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/README.md CHANGED
@@ -56,8 +56,10 @@ Each row exposes the operations available through the public Paseo SDK:
56
56
  - **Open** navigates to the selected agent.
57
57
  - **Expand or collapse** shows or hides a managed branch without changing agent state.
58
58
  - **Nudge** sends a follow-up to an idle or waiting agent.
59
- - **Interrupt and redirect** sends a new direction to a running agent. Paseo stops the active turn
60
- before starting that direction, and the confirmation dialog says so explicitly.
59
+ - **Interrupt and redirect** sends a new direction to a running agent. The dialog defaults to
60
+ **Interrupt**, which stops the active turn before starting that direction. **Prefer steering**
61
+ asks the provider to deliver the message into the running turn instead; a provider that cannot
62
+ steer replaces the turn. The choice resets to **Interrupt** each time the dialog opens.
61
63
  - **Detach** removes a managed child branch from its parent while allowing it to continue
62
64
  independently. Root agents and context-only ancestors do not expose this action.
63
65
  - **Archive** stops and removes the selected agent. Same-workspace descendants may be archived with
@@ -69,6 +71,18 @@ Each row exposes the operations available through the public Paseo SDK:
69
71
  Every mutating control uses a confirmation dialog. Successful actions show a toast; SDK errors are
70
72
  shown without hiding the failure.
71
73
 
74
+ ## Active crews sidebar row
75
+
76
+ On Paseo 0.11 and later, an **Active crews** sidebar header row counts the crews that have a member
77
+ working or waiting for input. Pressing it lists those crews with their workspace; choosing one opens
78
+ that workspace's Agent Crew panel in the Explorer. The list is a popover on wide layouts and a
79
+ bottom sheet on compact ones. Paseo's compact layout does not show Explorer panels, so there the
80
+ jump lands on the workspace. Hide the row from Settings > Sidebar.
81
+
82
+ The row reads the same directory query and subscriptions as the panel, so they stay active while
83
+ the sidebar is mounted. Paseo 0.9 and 0.10 do not support sidebar items; the row is not registered
84
+ there.
85
+
72
86
  ## How it reads state
73
87
 
74
88
  `usePaseo().agents.list()` and `usePaseo().workspaces.list()` page the selected daemon directory at
@@ -99,8 +113,8 @@ Agent Crew intentionally stays inside the public Paseo plugin SDK.
99
113
  - Workspace-less top-level agents are outside every workspace crew; workspace-less descendants of
100
114
  visible members remain in that crew.
101
115
  - It does not add heartbeat controls, private cancellation calls, or direct daemon API access.
102
- - Sending to a running agent interrupts its active turn; there is no separate non-interrupting send
103
- operation.
116
+ - Steering is a preference. Paseo does not report whether a message steered the running turn or
117
+ replaced it, so the toast only says the message was sent.
104
118
  - If the daemon contains more than 2,000 agents, the panel warns that its directory snapshot may
105
119
  omit agents in this workspace or their descendants.
106
120
 
package/client/crew.ts CHANGED
@@ -1,10 +1,23 @@
1
- import type { usePaseo } from "@getpaseo/plugin/client";
1
+ import type {
2
+ PluginClientContext,
3
+ PluginSidebarItemContribution,
4
+ usePaseo,
5
+ } from "@getpaseo/plugin/client";
2
6
 
3
7
  export type PaseoApi = ReturnType<typeof usePaseo>;
4
8
  export type PaseoWorkspace = Awaited<ReturnType<PaseoApi["workspaces"]["list"]>>["entries"][number];
5
9
  export type AgentEntry = Awaited<ReturnType<PaseoApi["agents"]["list"]>>["entries"][number];
6
10
  type AgentSnapshot = AgentEntry["agent"];
7
11
 
12
+ /** Sidebar header items arrived in Paseo 0.11; on older hosts the item is not registered. */
13
+ export function addSidebarHeaderItemIfSupported(
14
+ client: Pick<PluginClientContext, "addSidebarHeaderItem">,
15
+ item: PluginSidebarItemContribution,
16
+ ): () => void {
17
+ if (typeof client.addSidebarHeaderItem !== "function") return () => {};
18
+ return client.addSidebarHeaderItem(item);
19
+ }
20
+
8
21
  export function listenToCrewDirectory(paseo: PaseoApi, invalidate: () => void): () => void {
9
22
  let closed = false;
10
23
  let removeAgentObserver: (() => void) | undefined;
@@ -112,6 +125,13 @@ export function crewState(agent: AgentSnapshot): CrewState {
112
125
  return "idle";
113
126
  }
114
127
 
128
+ export type DeliveryChoice = "steer" | "interrupt";
129
+
130
+ /** Idle agents get a plain send; the choice only applies to a running turn. */
131
+ export function sendOptions(running: boolean, choice: DeliveryChoice) {
132
+ return running ? { activeTurnBehavior: choice } : undefined;
133
+ }
134
+
115
135
  export function isWorking(agent: AgentSnapshot): boolean {
116
136
  return agent.status === "running" || agent.status === "initializing";
117
137
  }
@@ -309,3 +329,52 @@ export function collapseCrewNodes(
309
329
  }
310
330
  return visible;
311
331
  }
332
+
333
+ export interface ActiveCrew {
334
+ workspaceId: string;
335
+ lead: AgentEntry;
336
+ working: number;
337
+ needsInput: number;
338
+ }
339
+
340
+ /** Crews each workspace's panel shows, kept only when a member is working or needs input. */
341
+ export function activeCrews(entries: readonly AgentEntry[]): ActiveCrew[] {
342
+ const workspaceIds = new Set<string>();
343
+ for (const { agent } of entries) {
344
+ if (agent.workspaceId && !agent.archivedAt) workspaceIds.add(agent.workspaceId);
345
+ }
346
+ const crews: ActiveCrew[] = [];
347
+ for (const workspaceId of workspaceIds) {
348
+ let crew: ActiveCrew | undefined;
349
+ for (const node of buildCrewForest(entries, workspaceId)) {
350
+ if (node.depth === 0) {
351
+ crew =
352
+ node.descendantCount > 0
353
+ ? { workspaceId, lead: node.entry, working: 0, needsInput: 0 }
354
+ : undefined;
355
+ if (crew) crews.push(crew);
356
+ }
357
+ if (!crew || !node.member) continue;
358
+ const state = crewState(node.entry.agent);
359
+ if (state === "working") crew.working += 1;
360
+ if (state === "needs-input") crew.needsInput += 1;
361
+ }
362
+ }
363
+ return crews.filter((crew) => crew.working + crew.needsInput > 0);
364
+ }
365
+
366
+ export type CrewPopoverNotice = "loading" | "error" | "empty";
367
+
368
+ /**
369
+ * The note the Active crews popover shows, or null when its crew list speaks for itself. A failed
370
+ * load always wins, even over cached crews, so an outage never reads as "no crew is active".
371
+ */
372
+ export function crewPopoverNotice(input: {
373
+ crewCount: number;
374
+ isPending: boolean;
375
+ error: unknown;
376
+ }): CrewPopoverNotice | null {
377
+ if (input.error) return "error";
378
+ if (input.crewCount > 0) return null;
379
+ return input.isPending ? "loading" : "empty";
380
+ }
package/client/main.tsx CHANGED
@@ -22,12 +22,14 @@ import {
22
22
  collapseCrewNodes,
23
23
  crewCounts,
24
24
  crewState,
25
+ type DeliveryChoice,
25
26
  formatAge,
26
27
  isWorking,
27
28
  listenToCrewDirectory,
28
29
  type PaseoApi,
29
30
  type PaseoWorkspace,
30
31
  parentAgentId,
32
+ sendOptions,
31
33
  } from "./crew";
32
34
 
33
35
  const PAGE_LIMIT = 200;
@@ -43,7 +45,7 @@ type CrewData = {
43
45
  };
44
46
 
45
47
  type CrewAction =
46
- | { kind: "send"; agentId: string; text: string; interrupted: boolean }
48
+ | { kind: "send"; agentId: string; text: string; running: boolean; choice: DeliveryChoice }
47
49
  | { kind: "detach"; agentId: string }
48
50
  | { kind: "archive"; agentId: string };
49
51
 
@@ -96,6 +98,36 @@ async function loadCrewData(paseo: PaseoApi): Promise<CrewData> {
96
98
  };
97
99
  }
98
100
 
101
+ /** Host-wide crew directory, refreshed by agent and workspace subscriptions plus a slow backstop. */
102
+ export function useCrewDirectory(hostId: string) {
103
+ const paseo = usePaseo();
104
+ const queryClient = useQueryClient();
105
+ const queryKey = useMemo(() => ["agent-crew", "directory", hostId], [hostId]);
106
+ const directory = useQuery({
107
+ queryKey,
108
+ queryFn: () => loadCrewData(paseo),
109
+ refetchInterval: BACKSTOP_REFRESH_MS,
110
+ });
111
+
112
+ useEffect(() => {
113
+ let debounce: ReturnType<typeof setTimeout> | undefined;
114
+ const invalidate = () => {
115
+ if (debounce) return;
116
+ debounce = setTimeout(() => {
117
+ debounce = undefined;
118
+ void queryClient.invalidateQueries({ queryKey });
119
+ }, REFRESH_DEBOUNCE_MS);
120
+ };
121
+ const unsubscribeDirectory = listenToCrewDirectory(paseo, invalidate);
122
+ return () => {
123
+ clearTimeout(debounce);
124
+ unsubscribeDirectory();
125
+ };
126
+ }, [paseo, queryClient, queryKey]);
127
+
128
+ return directory;
129
+ }
130
+
99
131
  function ActionButton({
100
132
  accessibilityLabel,
101
133
  color,
@@ -186,14 +218,8 @@ export function AgentCrew({
186
218
  }: PluginWorkspacePanelProps) {
187
219
  const paseo = usePaseo();
188
220
  const toast = useToast();
189
- const queryClient = useQueryClient();
190
221
  const workspaceTitle = useWorkspace(workspaceId, ({ name, title }) => title?.trim() || name);
191
- const queryKey = useMemo(() => ["agent-crew", "directory", host.id], [host.id]);
192
- const { data, error, isPending, isFetching, refetch } = useQuery({
193
- queryKey,
194
- queryFn: () => loadCrewData(paseo),
195
- refetchInterval: BACKSTOP_REFRESH_MS,
196
- });
222
+ const { data, error, isPending, isFetching, refetch } = useCrewDirectory(host.id);
197
223
 
198
224
  const [selectedState, setSelectedState] = useState<CrewState | null>(null);
199
225
  const [query, setQuery] = useState("");
@@ -201,6 +227,7 @@ export function AgentCrew({
201
227
  const [dialog, setDialog] = useState<DialogState>(null);
202
228
  const [permissionDialog, setPermissionDialog] = useState<PermissionDialogState>(null);
203
229
  const [message, setMessage] = useState("");
230
+ const [delivery, setDelivery] = useState<DeliveryChoice>("interrupt");
204
231
  const [collapsedAgentIds, setCollapsedAgentIds] = useState<ReadonlySet<string>>(() => new Set());
205
232
 
206
233
  useEffect(() => {
@@ -208,22 +235,6 @@ export function AgentCrew({
208
235
  return () => clearInterval(clock);
209
236
  }, []);
210
237
 
211
- useEffect(() => {
212
- let debounce: ReturnType<typeof setTimeout> | undefined;
213
- const invalidate = () => {
214
- if (debounce) return;
215
- debounce = setTimeout(() => {
216
- debounce = undefined;
217
- void queryClient.invalidateQueries({ queryKey });
218
- }, REFRESH_DEBOUNCE_MS);
219
- };
220
- const unsubscribeDirectory = listenToCrewDirectory(paseo, invalidate);
221
- return () => {
222
- clearTimeout(debounce);
223
- unsubscribeDirectory();
224
- };
225
- }, [paseo, queryClient, queryKey]);
226
-
227
238
  const allNodes = useMemo(
228
239
  () =>
229
240
  buildCrewForest(data?.entries ?? [], workspaceId, {
@@ -265,7 +276,7 @@ export function AgentCrew({
265
276
  mutationFn: async (input: CrewAction) => {
266
277
  const handle = paseo.agents.ref(input.agentId);
267
278
  if (input.kind === "send") {
268
- await handle.send(input.text);
279
+ await handle.send(input.text, sendOptions(input.running, input.choice));
269
280
  } else if (input.kind === "detach") {
270
281
  await handle.detach();
271
282
  } else {
@@ -274,7 +285,12 @@ export function AgentCrew({
274
285
  },
275
286
  onSuccess: (_result, input) => {
276
287
  if (input.kind === "send") {
277
- toast.show(input.interrupted ? "Agent redirected" : "Nudge sent", { variant: "success" });
288
+ const sent = !input.running
289
+ ? "Nudge sent"
290
+ : input.choice === "interrupt"
291
+ ? "Agent redirected"
292
+ : "Message sent";
293
+ toast.show(sent, { variant: "success" });
278
294
  } else if (input.kind === "detach") {
279
295
  toast.show("Subagent detached", { variant: "success" });
280
296
  } else {
@@ -287,7 +303,7 @@ export function AgentCrew({
287
303
  toast.error(mutationError instanceof Error ? mutationError.message : "Agent action failed");
288
304
  },
289
305
  onSettled: async () => {
290
- await queryClient.invalidateQueries({ queryKey });
306
+ await refetch();
291
307
  },
292
308
  });
293
309
 
@@ -315,7 +331,7 @@ export function AgentCrew({
315
331
  }
316
332
  },
317
333
  onSettled: async () => {
318
- await queryClient.invalidateQueries({ queryKey });
334
+ await refetch();
319
335
  },
320
336
  });
321
337
 
@@ -467,6 +483,18 @@ export function AgentCrew({
467
483
  backgroundColor: theme.colors.surface1,
468
484
  textAlignVertical: "top",
469
485
  },
486
+ deliveryRow: { flexDirection: "row", gap: 8 },
487
+ deliveryOption: {
488
+ flex: 1,
489
+ minHeight: 36,
490
+ alignItems: "center",
491
+ justifyContent: "center",
492
+ borderRadius: 8,
493
+ borderWidth: StyleSheet.hairlineWidth,
494
+ borderColor: theme.colors.border,
495
+ backgroundColor: theme.colors.surface1,
496
+ },
497
+ deliveryOptionActive: { backgroundColor: theme.colors.accent },
470
498
  modalActions: { flexDirection: "row", justifyContent: "flex-end", gap: 8 },
471
499
  secondaryButton: {
472
500
  minHeight: 36,
@@ -528,6 +556,7 @@ export function AgentCrew({
528
556
  );
529
557
  function openDialog(kind: NonNullable<DialogState>["kind"], node: CrewNode) {
530
558
  setMessage("");
559
+ setDelivery("interrupt");
531
560
  setDialog({ kind, node });
532
561
  }
533
562
 
@@ -537,7 +566,13 @@ export function AgentCrew({
537
566
  if (dialog.kind === "message") {
538
567
  const text = message.trim();
539
568
  if (!text) return;
540
- action.mutate({ kind: "send", agentId: agent.id, text, interrupted: isWorking(agent) });
569
+ action.mutate({
570
+ kind: "send",
571
+ agentId: agent.id,
572
+ text,
573
+ running: isWorking(agent),
574
+ choice: delivery,
575
+ });
541
576
  return;
542
577
  }
543
578
  action.mutate({ kind: dialog.kind, agentId: agent.id });
@@ -714,17 +749,26 @@ export function AgentCrew({
714
749
  if (dialog.kind === "message") {
715
750
  const state = crewState(dialog.node.entry.agent);
716
751
  const running = isWorking(dialog.node.entry.agent);
717
- dialogTitle = running ? `Interrupt and redirect ${target}` : `Nudge ${target}`;
718
- dialogCopy = running
719
- ? "This agent is working. Sending a message stops its current turn and starts the new direction."
720
- : state === "needs-input"
721
- ? "This agent is waiting for a permission decision. Sending a message dismisses that request and starts the new direction."
722
- : "Send a concise follow-up with the missing context or next step.";
723
- confirmLabel = running
724
- ? "Interrupt & redirect"
725
- : state === "needs-input"
726
- ? "Dismiss request & nudge"
727
- : "Send nudge";
752
+ const steer = running && delivery === "steer";
753
+ dialogTitle = !running
754
+ ? `Nudge ${target}`
755
+ : steer
756
+ ? `Message ${target}`
757
+ : `Interrupt and redirect ${target}`;
758
+ dialogCopy = steer
759
+ ? "This agent is working. The message is delivered to the running turn if the provider supports steering; otherwise it replaces the turn."
760
+ : running
761
+ ? "This agent is working. Sending a message stops its current turn and starts the new direction."
762
+ : state === "needs-input"
763
+ ? "This agent is waiting for a permission decision. Sending a message dismisses that request and starts the new direction."
764
+ : "Send a concise follow-up with the missing context or next step.";
765
+ confirmLabel = steer
766
+ ? "Send (prefer steering)"
767
+ : running
768
+ ? "Interrupt & redirect"
769
+ : state === "needs-input"
770
+ ? "Dismiss request & nudge"
771
+ : "Send nudge";
728
772
  } else if (dialog.kind === "detach") {
729
773
  dialogTitle = `Detach ${target}?`;
730
774
  dialogCopy =
@@ -895,6 +939,36 @@ export function AgentCrew({
895
939
  <Modal.Content>
896
940
  <View style={panelStyles.modalBody}>
897
941
  <Text style={panelStyles.modalCopy}>{dialogCopy}</Text>
942
+ {dialog?.kind === "message" && isWorking(dialog.node.entry.agent) ? (
943
+ <View style={panelStyles.deliveryRow}>
944
+ {(
945
+ [
946
+ ["interrupt", "Interrupt"],
947
+ ["steer", "Prefer steering"],
948
+ ] as const
949
+ ).map(([value, label]) => (
950
+ <Pressable
951
+ key={value}
952
+ accessibilityRole="button"
953
+ accessibilityState={{ selected: delivery === value }}
954
+ disabled={action.isPending}
955
+ onPress={() => setDelivery(value)}
956
+ style={[
957
+ panelStyles.deliveryOption,
958
+ delivery === value && panelStyles.deliveryOptionActive,
959
+ ]}
960
+ >
961
+ <Text
962
+ style={
963
+ delivery === value ? panelStyles.primaryButtonText : panelStyles.buttonText
964
+ }
965
+ >
966
+ {label}
967
+ </Text>
968
+ </Pressable>
969
+ ))}
970
+ </View>
971
+ ) : null}
898
972
  {dialog?.kind === "message" ? (
899
973
  <TextInput
900
974
  accessibilityLabel="Message to subagent"
@@ -0,0 +1,90 @@
1
+ import type {
2
+ PluginClientContext,
3
+ PluginPopoverProps,
4
+ PluginSidebarItemProps,
5
+ } from "@getpaseo/plugin/client";
6
+ import { useToast } from "@getpaseo/plugin/client/react-native";
7
+ import { SidebarRow } from "@getpaseo/plugin/client/ui";
8
+ import { useMemo } from "react";
9
+ import { Pressable, StyleSheet, Text, View } from "react-native";
10
+ import { activeCrews, agentTitle, crewPopoverNotice } from "./crew";
11
+ import { useCrewDirectory } from "./main";
12
+
13
+ /** The Active crews sidebar row; its popover opens a crew's workspace Agent Crew panel. */
14
+ export function createActiveCrewsItem(client: PluginClientContext) {
15
+ function ActiveCrewsPopover({ theme, host, close }: PluginPopoverProps) {
16
+ const toast = useToast();
17
+ const { data, error, isPending } = useCrewDirectory(host.id);
18
+ const crews = useMemo(() => activeCrews(data?.entries ?? []), [data]);
19
+ const styles = useMemo(
20
+ () =>
21
+ StyleSheet.create({
22
+ row: { gap: 2, paddingHorizontal: 8, paddingVertical: 8, borderRadius: 8 },
23
+ pressed: { backgroundColor: theme.colors.surface2 },
24
+ title: { color: theme.colors.foreground, fontSize: 13, fontWeight: "600" },
25
+ detail: { color: theme.colors.foregroundMuted, fontSize: 12 },
26
+ error: { color: theme.colors.statusDanger, fontSize: 12, marginBottom: 6 },
27
+ }),
28
+ [theme],
29
+ );
30
+ const notice = crewPopoverNotice({ crewCount: crews.length, isPending, error });
31
+ let noticeText = "No crew is working or waiting for input.";
32
+ if (notice === "loading") noticeText = "Loading crews…";
33
+ if (notice === "error") {
34
+ noticeText = error instanceof Error ? error.message : "Could not load crews";
35
+ }
36
+ return (
37
+ <View>
38
+ {notice ? (
39
+ <Text style={notice === "error" ? styles.error : styles.detail}>{noticeText}</Text>
40
+ ) : null}
41
+ {crews.map((crew) => (
42
+ <Pressable
43
+ key={`${crew.workspaceId}:${crew.lead.agent.id}`}
44
+ accessibilityRole="button"
45
+ onPress={() => {
46
+ close();
47
+ try {
48
+ client.openPanel("crew", { workspaceId: crew.workspaceId, location: "explorer" });
49
+ } catch (error) {
50
+ toast.error(error instanceof Error ? error.message : "Could not open Agent Crew");
51
+ }
52
+ }}
53
+ style={({ pressed }) => [styles.row, pressed && styles.pressed]}
54
+ >
55
+ <Text style={styles.title} numberOfLines={1}>
56
+ {agentTitle(crew.lead)}
57
+ </Text>
58
+ <Text style={styles.detail} numberOfLines={1}>
59
+ {[
60
+ data?.workspaceNames.get(crew.workspaceId) ?? "Unknown workspace",
61
+ crew.working > 0 ? `${crew.working} working` : null,
62
+ crew.needsInput > 0 ? `${crew.needsInput} need input` : null,
63
+ ]
64
+ .filter(Boolean)
65
+ .join(" · ")}
66
+ </Text>
67
+ </Pressable>
68
+ ))}
69
+ </View>
70
+ );
71
+ }
72
+
73
+ function ActiveCrewsItem({ theme, host, openPopover }: PluginSidebarItemProps) {
74
+ const { data } = useCrewDirectory(host.id);
75
+ const count = useMemo(() => activeCrews(data?.entries ?? []).length, [data]);
76
+ return (
77
+ <SidebarRow
78
+ icon="Network"
79
+ onPress={() => openPopover(ActiveCrewsPopover)}
80
+ trailing={
81
+ count > 0 ? (
82
+ <Text style={{ color: theme.colors.foregroundMuted, fontSize: 12 }}>{count}</Text>
83
+ ) : undefined
84
+ }
85
+ />
86
+ );
87
+ }
88
+
89
+ return ActiveCrewsItem;
90
+ }
package/index.client.tsx CHANGED
@@ -1,7 +1,9 @@
1
1
  import type { PluginClientContext, PluginSurfaceProps } from "@getpaseo/plugin/client";
2
2
  import { createAutoOpenManager } from "./client/auto-open";
3
+ import { addSidebarHeaderItemIfSupported } from "./client/crew";
3
4
  import { AgentCrew } from "./client/main";
4
5
  import { AgentCrewSettingsScreen } from "./client/settings-screen";
6
+ import { createActiveCrewsItem } from "./client/sidebar";
5
7
  import { agentCrewSettings } from "./shared/settings";
6
8
 
7
9
  export default function contribute(client: PluginClientContext) {
@@ -35,8 +37,14 @@ export default function contribute(client: PluginClientContext) {
35
37
  openPanel("crew", { location: "explorer" });
36
38
  },
37
39
  });
40
+ const removeActiveCrews = addSidebarHeaderItemIfSupported(client, {
41
+ id: "active-crews",
42
+ title: "Active crews",
43
+ Component: createActiveCrewsItem(client),
44
+ });
38
45
 
39
46
  return () => {
47
+ removeActiveCrews();
40
48
  removeOpenCrew();
41
49
  removeWorkspacePanel();
42
50
  removeSettings();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@omercnet/paseo-agent-crew",
3
- "version": "1.1.0-next.198.1",
3
+ "version": "1.1.0-next.206.1",
4
4
  "type": "module",
5
5
  "description": "A Paseo Explorer panel for visualizing and controlling every managed agent crew in a workspace.",
6
6
  "license": "MIT",
@@ -47,10 +47,10 @@
47
47
  },
48
48
  "devDependencies": {
49
49
  "@biomejs/biome": "^2.5.10",
50
- "@getpaseo/cli": "0.10.1",
51
- "@getpaseo/client": "0.10.1",
52
- "@getpaseo/plugin": "0.10.1",
53
- "@getpaseo/protocol": "0.10.1",
50
+ "@getpaseo/cli": "0.11.0-beta.3",
51
+ "@getpaseo/client": "0.11.0-beta.3",
52
+ "@getpaseo/plugin": "0.11.0-beta.3",
53
+ "@getpaseo/protocol": "0.11.0-beta.3",
54
54
  "@tanstack/react-query": "^5.102.3",
55
55
  "@types/node": "^24.10.1",
56
56
  "@types/react": "^19.2.18",