@getcatalystiq/agent-plane-ui 0.1.29 → 0.1.31

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/dist/index.js CHANGED
@@ -1,16 +1,76 @@
1
1
  import { Card, CardHeader, CardTitle, CardContent, useApi, Skeleton, FileTreeEditor } from './chunk-CE2RHDPY.js';
2
2
  export { Card, CardContent, CardDescription, CardHeader, CardTitle, Skeleton, useApi } from './chunk-CE2RHDPY.js';
3
- import { cn, Dialog, DialogContent, DialogHeader, DialogTitle, DialogBody, DialogFooter, Button, Badge, useNavigation, useAgentPlaneClient, DialogDescription, FormField, Input, supportsClaudeRunner, buttonVariants } from './chunk-XFI227OB.js';
3
+ import { cn, useAgentPlaneClient, Dialog, DialogContent, DialogHeader, DialogTitle, DialogBody, DialogFooter, Button, Badge, useNavigation, DialogDescription, FormField, Input, supportsClaudeRunner, buttonVariants } from './chunk-XFI227OB.js';
4
4
  export { AgentPlaneProvider, Badge, Button, Dialog, DialogBody, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, FormField, Input, badgeVariants, buttonVariants, cn, useAgentPlaneClient, useAuthError, useNavigation } from './chunk-XFI227OB.js';
5
+ import * as React4 from 'react';
6
+ import React4__default, { lazy, useState, useRef, useCallback, useEffect, useMemo, Suspense } from 'react';
5
7
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
6
- import * as React from 'react';
7
- import React__default, { lazy, useState, useCallback, useMemo, useRef, useEffect, Suspense } from 'react';
8
8
  import { useSWRConfig } from 'swr';
9
9
  import ReactMarkdown from 'react-markdown';
10
10
  import { Command } from 'cmdk';
11
11
  import * as Popover from '@radix-ui/react-popover';
12
12
  import remarkGfm from 'remark-gfm';
13
+ import * as ToastPrimitives from '@radix-ui/react-toast';
14
+ import { cva } from 'class-variance-authority';
13
15
 
16
+ var ACTIVE_STATUSES = /* @__PURE__ */ new Set(["running", "pending"]);
17
+ function useRunStream(runId, status) {
18
+ const client = useAgentPlaneClient();
19
+ const [events, setEvents] = useState([]);
20
+ const [isStreaming, setIsStreaming] = useState(false);
21
+ const [terminalEvent, setTerminalEvent] = useState(null);
22
+ const [streamingText, setStreamingText] = useState("");
23
+ const [error, setError] = useState(null);
24
+ const abortRef = useRef(null);
25
+ const startStream = useCallback(async (id, signal) => {
26
+ setIsStreaming(true);
27
+ setError(null);
28
+ try {
29
+ const stream = await client.runs.stream(id, { signal });
30
+ for await (const event of stream) {
31
+ if (signal.aborted) break;
32
+ if (event.type === "text_delta") {
33
+ const text = event.text ?? "";
34
+ setStreamingText((prev) => prev + text);
35
+ continue;
36
+ }
37
+ if (event.type === "assistant") {
38
+ setStreamingText("");
39
+ }
40
+ if (event.type === "stream_detached") {
41
+ continue;
42
+ }
43
+ setEvents((prev) => [...prev, event]);
44
+ if (event.type === "result" || event.type === "error") {
45
+ setTerminalEvent(event);
46
+ setIsStreaming(false);
47
+ setStreamingText("");
48
+ return;
49
+ }
50
+ }
51
+ setIsStreaming(false);
52
+ } catch (err) {
53
+ if (signal.aborted) return;
54
+ setError(err instanceof Error ? err : new Error(String(err)));
55
+ setIsStreaming(false);
56
+ }
57
+ }, [client]);
58
+ useEffect(() => {
59
+ if (!runId || !ACTIVE_STATUSES.has(status)) {
60
+ setIsStreaming(false);
61
+ return;
62
+ }
63
+ if (terminalEvent) return;
64
+ const controller = new AbortController();
65
+ abortRef.current = controller;
66
+ startStream(runId, controller.signal);
67
+ return () => {
68
+ controller.abort();
69
+ abortRef.current = null;
70
+ };
71
+ }, [runId, status, startStream, terminalEvent]);
72
+ return { events, isStreaming, terminalEvent, streamingText, error };
73
+ }
14
74
  function Select({ className = "", ...props }) {
15
75
  return /* @__PURE__ */ jsxs("div", { className: "relative w-full", children: [
16
76
  /* @__PURE__ */ jsx(
@@ -27,7 +87,7 @@ function Select({ className = "", ...props }) {
27
87
  ] }) })
28
88
  ] });
29
89
  }
30
- var Textarea = React.forwardRef(
90
+ var Textarea = React4.forwardRef(
31
91
  ({ className, ...props }, ref) => {
32
92
  return /* @__PURE__ */ jsx(
33
93
  "textarea",
@@ -133,7 +193,7 @@ function PaginationBar({
133
193
  return /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between px-3 py-2 border-t border-border bg-muted/20 text-sm", children: [
134
194
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 text-muted-foreground", children: [
135
195
  /* @__PURE__ */ jsx("span", { children: "Rows per page:" }),
136
- PAGE_SIZE_OPTIONS.map((ps) => /* @__PURE__ */ jsx(React__default.Fragment, { children: renderLink(
196
+ PAGE_SIZE_OPTIONS.map((ps) => /* @__PURE__ */ jsx(React4__default.Fragment, { children: renderLink(
137
197
  buildHref(1, ps),
138
198
  ps,
139
199
  `px-2 py-0.5 rounded text-xs ${pageSize === ps ? "bg-primary text-primary-foreground font-medium" : "hover:bg-muted"}`
@@ -299,6 +359,102 @@ function DashboardPage({ initialData, chartComponent: ChartComponent }) {
299
359
  ChartComponent && /* @__PURE__ */ jsx(ChartComponent, { stats: daily_stats })
300
360
  ] });
301
361
  }
362
+ var TOAST_LIMIT = 5;
363
+ var TOAST_REMOVE_DELAY = 1e6;
364
+ var count = 0;
365
+ function genId() {
366
+ count = (count + 1) % Number.MAX_SAFE_INTEGER;
367
+ return count.toString();
368
+ }
369
+ var toastTimeouts = /* @__PURE__ */ new Map();
370
+ function addToRemoveQueue(toastId) {
371
+ if (toastTimeouts.has(toastId)) return;
372
+ const timeout = setTimeout(() => {
373
+ toastTimeouts.delete(toastId);
374
+ dispatch({ type: "REMOVE_TOAST", toastId });
375
+ }, TOAST_REMOVE_DELAY);
376
+ toastTimeouts.set(toastId, timeout);
377
+ }
378
+ function reducer(state, action) {
379
+ switch (action.type) {
380
+ case "ADD_TOAST":
381
+ return {
382
+ ...state,
383
+ toasts: [action.toast, ...state.toasts].slice(0, TOAST_LIMIT)
384
+ };
385
+ case "UPDATE_TOAST":
386
+ return {
387
+ ...state,
388
+ toasts: state.toasts.map(
389
+ (t) => t.id === action.toast.id ? { ...t, ...action.toast } : t
390
+ )
391
+ };
392
+ case "DISMISS_TOAST": {
393
+ const { toastId } = action;
394
+ if (toastId) {
395
+ addToRemoveQueue(toastId);
396
+ } else {
397
+ state.toasts.forEach((t) => addToRemoveQueue(t.id));
398
+ }
399
+ return {
400
+ ...state,
401
+ toasts: state.toasts.map(
402
+ (t) => t.id === toastId || toastId === void 0 ? { ...t, open: false } : t
403
+ )
404
+ };
405
+ }
406
+ case "REMOVE_TOAST":
407
+ if (action.toastId === void 0) {
408
+ return { ...state, toasts: [] };
409
+ }
410
+ return {
411
+ ...state,
412
+ toasts: state.toasts.filter((t) => t.id !== action.toastId)
413
+ };
414
+ }
415
+ }
416
+ var listeners = [];
417
+ var memoryState = { toasts: [] };
418
+ function dispatch(action) {
419
+ memoryState = reducer(memoryState, action);
420
+ listeners.forEach((listener) => listener(memoryState));
421
+ }
422
+ function toast(props) {
423
+ const id = genId();
424
+ const update = (updateProps) => dispatch({ type: "UPDATE_TOAST", toast: { ...updateProps, id } });
425
+ const dismiss2 = () => dispatch({ type: "DISMISS_TOAST", toastId: id });
426
+ dispatch({
427
+ type: "ADD_TOAST",
428
+ toast: {
429
+ ...props,
430
+ id,
431
+ open: true,
432
+ onOpenChange: (open) => {
433
+ if (!open) dismiss2();
434
+ }
435
+ }
436
+ });
437
+ return { id, dismiss: dismiss2, update };
438
+ }
439
+ function dismiss(toastId) {
440
+ const action = toastId !== void 0 ? { type: "DISMISS_TOAST", toastId } : { type: "DISMISS_TOAST" };
441
+ dispatch(action);
442
+ }
443
+ function useToast() {
444
+ const [state, setState] = React4.useState(memoryState);
445
+ React4.useEffect(() => {
446
+ listeners.push(setState);
447
+ return () => {
448
+ const index = listeners.indexOf(setState);
449
+ if (index > -1) listeners.splice(index, 1);
450
+ };
451
+ }, [state]);
452
+ return {
453
+ ...state,
454
+ toast,
455
+ dismiss
456
+ };
457
+ }
302
458
  var SOURCES = [
303
459
  { value: "", label: "All Sources" },
304
460
  { value: "api", label: "API" },
@@ -308,11 +464,18 @@ var SOURCES = [
308
464
  { value: "a2a", label: "A2A" }
309
465
  ];
310
466
  var VALID_SOURCES = SOURCES.filter((s) => s.value).map((s) => s.value);
467
+ var ACTIVE_STATUSES2 = /* @__PURE__ */ new Set(["running", "pending"]);
468
+ var TERMINAL_STATUSES = /* @__PURE__ */ new Set(["completed", "failed", "cancelled", "timed_out"]);
311
469
  function RunListPage({ initialData }) {
312
470
  const { LinkComponent, basePath } = useNavigation();
471
+ const { toast: toast2 } = useToast();
313
472
  const [page, setPage] = useState(1);
314
473
  const [pageSize, setPageSize] = useState(20);
315
474
  const [sourceFilter, setSourceFilter] = useState(null);
475
+ const prevStatusesRef = useRef(/* @__PURE__ */ new Map());
476
+ const [activeRunsExist, setActiveRunsExist] = useState(
477
+ () => initialData?.data?.some((r) => ACTIVE_STATUSES2.has(r.status)) ?? false
478
+ );
316
479
  const cacheKey = `runs-${page}-${pageSize}-${sourceFilter || "all"}`;
317
480
  const { data, error, isLoading } = useApi(
318
481
  cacheKey,
@@ -323,8 +486,29 @@ function RunListPage({ initialData }) {
323
486
  ...sourceFilter ? { triggered_by: sourceFilter } : {}
324
487
  });
325
488
  },
326
- initialData ? { fallbackData: initialData } : void 0
489
+ {
490
+ ...initialData ? { fallbackData: initialData } : {},
491
+ refreshInterval: activeRunsExist ? 5e3 : 0
492
+ }
327
493
  );
494
+ useEffect(() => {
495
+ if (!data?.data) return;
496
+ const prev = prevStatusesRef.current;
497
+ const next = /* @__PURE__ */ new Map();
498
+ for (const run of data.data) {
499
+ next.set(run.id, run.status);
500
+ const oldStatus = prev.get(run.id);
501
+ if (oldStatus && ACTIVE_STATUSES2.has(oldStatus) && TERMINAL_STATUSES.has(run.status)) {
502
+ toast2({
503
+ title: `Run ${run.status}`,
504
+ description: run.agent_name,
505
+ variant: run.status === "completed" ? "success" : "destructive"
506
+ });
507
+ }
508
+ }
509
+ prevStatusesRef.current = next;
510
+ setActiveRunsExist(data.data.some((r) => ACTIVE_STATUSES2.has(r.status)));
511
+ }, [data, toast2]);
328
512
  const handleSourceChange = useCallback((e) => {
329
513
  const value = e.target.value;
330
514
  setSourceFilter(VALID_SOURCES.includes(value) ? value : null);
@@ -505,17 +689,51 @@ function buildConversation(events) {
505
689
  }
506
690
  return items;
507
691
  }
508
- function TranscriptViewer({ transcript, prompt }) {
692
+ function TranscriptViewer({ transcript, prompt, isStreaming = false }) {
509
693
  const conversation = useMemo(() => buildConversation(transcript), [transcript]);
694
+ const scrollContainerRef = useRef(null);
695
+ const sentinelRef = useRef(null);
696
+ const userHasScrolledUpRef = useRef(false);
697
+ const [userHasScrolledUp, setUserHasScrolledUp] = useState(false);
698
+ const handleScroll = useCallback(() => {
699
+ const el = scrollContainerRef.current;
700
+ if (!el) return;
701
+ const atBottom = el.scrollHeight - el.scrollTop - el.clientHeight < 50;
702
+ if (atBottom) {
703
+ userHasScrolledUpRef.current = false;
704
+ setUserHasScrolledUp(false);
705
+ } else {
706
+ userHasScrolledUpRef.current = true;
707
+ setUserHasScrolledUp(true);
708
+ }
709
+ }, []);
710
+ useEffect(() => {
711
+ if (isStreaming && !userHasScrolledUpRef.current) {
712
+ sentinelRef.current?.scrollIntoView({ behavior: "smooth" });
713
+ }
714
+ }, [transcript.length, isStreaming]);
510
715
  return /* @__PURE__ */ jsxs(Card, { children: [
511
716
  /* @__PURE__ */ jsx(CardHeader, { children: /* @__PURE__ */ jsx(CardTitle, { className: "text-base", children: "Transcript" }) }),
512
- /* @__PURE__ */ jsxs(CardContent, { className: "space-y-3", children: [
513
- prompt && /* @__PURE__ */ jsxs("div", { className: "rounded-md border border-border bg-muted/20 px-4 py-3", children: [
514
- /* @__PURE__ */ jsx("div", { className: "text-xs font-medium text-muted-foreground mb-1", children: "Prompt" }),
515
- /* @__PURE__ */ jsx("pre", { className: "text-xs font-mono whitespace-pre-wrap", children: prompt })
516
- ] }),
517
- transcript.length === 0 ? /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: "No transcript available" }) : /* @__PURE__ */ jsx(ConversationView, { items: conversation })
518
- ] })
717
+ /* @__PURE__ */ jsx(CardContent, { className: "p-0", children: /* @__PURE__ */ jsxs(
718
+ "div",
719
+ {
720
+ ref: scrollContainerRef,
721
+ onScroll: isStreaming ? handleScroll : void 0,
722
+ className: "space-y-3 overflow-y-auto px-6 pb-6",
723
+ children: [
724
+ prompt && /* @__PURE__ */ jsxs("div", { className: "rounded-md border border-border bg-muted/20 px-4 py-3", children: [
725
+ /* @__PURE__ */ jsx("div", { className: "text-xs font-medium text-muted-foreground mb-1", children: "Prompt" }),
726
+ /* @__PURE__ */ jsx("pre", { className: "text-xs font-mono whitespace-pre-wrap", children: prompt })
727
+ ] }),
728
+ transcript.length === 0 ? /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: "No transcript available" }) : /* @__PURE__ */ jsx(ConversationView, { items: conversation }),
729
+ isStreaming && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 px-4 py-2 text-xs text-muted-foreground", children: [
730
+ /* @__PURE__ */ jsx("span", { className: "h-2 w-2 rounded-full bg-blue-400 animate-pulse" }),
731
+ "Streaming..."
732
+ ] }),
733
+ /* @__PURE__ */ jsx("div", { ref: sentinelRef })
734
+ ]
735
+ }
736
+ ) })
519
737
  ] });
520
738
  }
521
739
  function ConversationView({ items }) {
@@ -669,6 +887,7 @@ function ErrorItem({ item }) {
669
887
  }
670
888
  function RunDetailPage({ runId, initialData, initialTranscript }) {
671
889
  const { mutate } = useSWRConfig();
890
+ const { toast: toast2 } = useToast();
672
891
  const { data: run, error, isLoading } = useApi(
673
892
  `run-${runId}`,
674
893
  (client) => client.runs.get(runId),
@@ -679,6 +898,20 @@ function RunDetailPage({ runId, initialData, initialTranscript }) {
679
898
  (client) => client.runs.transcriptArray(runId),
680
899
  initialTranscript ? { fallbackData: initialTranscript } : void 0
681
900
  );
901
+ const isActive = run?.status === "running" || run?.status === "pending";
902
+ const { events, isStreaming, terminalEvent, streamingText } = useRunStream(
903
+ runId,
904
+ run?.status ?? ""
905
+ );
906
+ useEffect(() => {
907
+ if (!terminalEvent) return;
908
+ toast2({
909
+ title: terminalEvent.type === "result" ? "Run completed" : "Run failed",
910
+ variant: terminalEvent.type === "result" ? "success" : "destructive"
911
+ });
912
+ mutate(`run-${runId}`);
913
+ mutate(`transcript-${runId}`);
914
+ }, [terminalEvent, toast2, mutate, runId]);
682
915
  if (error) {
683
916
  return /* @__PURE__ */ jsx("div", { className: "flex items-center justify-center min-h-[40vh]", children: /* @__PURE__ */ jsxs("p", { className: "text-destructive", children: [
684
917
  "Failed to load run: ",
@@ -711,16 +944,26 @@ function RunDetailPage({ runId, initialData, initialTranscript }) {
711
944
  ] }),
712
945
  /* @__PURE__ */ jsx(MetricCard, { label: "Cost", children: /* @__PURE__ */ jsxs("span", { className: "font-mono", children: [
713
946
  "$",
714
- run.cost_usd != null ? run.cost_usd.toFixed(4) : "\u2014"
947
+ (() => {
948
+ const cost = terminalEvent?.cost_usd ?? run.cost_usd;
949
+ return cost != null ? Number(cost).toFixed(4) : "\u2014";
950
+ })()
715
951
  ] }) }),
716
- /* @__PURE__ */ jsx(MetricCard, { label: "Turns", children: run.num_turns }),
717
- /* @__PURE__ */ jsx(MetricCard, { label: "Duration", children: run.duration_ms > 0 ? `${(run.duration_ms / 1e3).toFixed(1)}s` : "\u2014" }),
952
+ /* @__PURE__ */ jsx(MetricCard, { label: "Turns", children: terminalEvent?.num_turns ?? run.num_turns }),
953
+ /* @__PURE__ */ jsx(MetricCard, { label: "Duration", children: (() => {
954
+ const ms = terminalEvent?.duration_ms ?? run.duration_ms;
955
+ return ms > 0 ? `${(ms / 1e3).toFixed(1)}s` : "\u2014";
956
+ })() }),
718
957
  /* @__PURE__ */ jsxs(MetricCard, { label: "Tokens", children: [
719
- (run.total_input_tokens + run.total_output_tokens).toLocaleString(),
958
+ (() => {
959
+ const inTok = terminalEvent?.total_input_tokens ?? run.total_input_tokens;
960
+ const outTok = terminalEvent?.total_output_tokens ?? run.total_output_tokens;
961
+ return (inTok + outTok).toLocaleString();
962
+ })(),
720
963
  /* @__PURE__ */ jsxs("p", { className: "text-xs text-muted-foreground mt-0.5 font-normal", children: [
721
- run.total_input_tokens.toLocaleString(),
964
+ (terminalEvent?.total_input_tokens ?? run.total_input_tokens).toLocaleString(),
722
965
  " in / ",
723
- run.total_output_tokens.toLocaleString(),
966
+ (terminalEvent?.total_output_tokens ?? run.total_output_tokens).toLocaleString(),
724
967
  " out"
725
968
  ] })
726
969
  ] })
@@ -732,7 +975,18 @@ function RunDetailPage({ runId, initialData, initialTranscript }) {
732
975
  run.error_messages.map((msg, i) => /* @__PURE__ */ jsx("pre", { className: "whitespace-pre-wrap text-sm text-destructive font-mono bg-destructive/10 rounded-md p-3", children: msg }, i))
733
976
  ] })
734
977
  ] }),
735
- /* @__PURE__ */ jsx(TranscriptViewer, { transcript: transcript || [], prompt: run.prompt }),
978
+ /* @__PURE__ */ jsx(
979
+ TranscriptViewer,
980
+ {
981
+ transcript: isActive && isStreaming ? events : transcript || [],
982
+ prompt: run.prompt,
983
+ isStreaming: isActive && isStreaming
984
+ }
985
+ ),
986
+ isActive && streamingText && /* @__PURE__ */ jsx("div", { className: "rounded-lg border bg-muted/30 p-4", children: /* @__PURE__ */ jsxs("pre", { className: "whitespace-pre-wrap text-sm font-mono", children: [
987
+ streamingText,
988
+ /* @__PURE__ */ jsx("span", { className: "inline-block w-2 h-4 ml-0.5 bg-foreground/70 animate-pulse align-text-bottom" })
989
+ ] }) }),
736
990
  /* @__PURE__ */ jsx(Card, { children: /* @__PURE__ */ jsxs("details", { children: [
737
991
  /* @__PURE__ */ jsxs("summary", { className: "flex items-center justify-between px-6 py-4 cursor-pointer list-none hover:bg-muted/30 transition-colors rounded-xl", children: [
738
992
  /* @__PURE__ */ jsx("span", { className: "text-base font-semibold", children: "Metadata" }),
@@ -3338,7 +3592,8 @@ function FileTreeEditor2({
3338
3592
  addFolderLabel = "Folder",
3339
3593
  newFileTemplate = { filename: "SKILL.md", content: "---\nname: New Skill\ndescription: Describe when this skill should be triggered\n---\n\n# Instructions\n\nDescribe what this skill does...\n" },
3340
3594
  savedVersion,
3341
- fixedStructure = false
3595
+ fixedStructure = false,
3596
+ headerActions
3342
3597
  }) {
3343
3598
  const [files, setFiles] = useState(initialFiles);
3344
3599
  const [selectedPath, setSelectedPath] = useState(
@@ -3529,7 +3784,10 @@ function FileTreeEditor2({
3529
3784
  isDirty && !readOnly && /* @__PURE__ */ jsx(Badge, { variant: "destructive", className: "text-xs", children: "Unsaved changes" }),
3530
3785
  readOnly && /* @__PURE__ */ jsx(Badge, { variant: "secondary", className: "text-xs", children: "Read-only" })
3531
3786
  ] }),
3532
- !readOnly && !hideSave && /* @__PURE__ */ jsx(Button, { onClick: handleSave, disabled: saving || !isDirty, size: "sm", children: saving ? "Saving..." : saveLabel })
3787
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
3788
+ headerActions,
3789
+ !readOnly && !hideSave && /* @__PURE__ */ jsx(Button, { onClick: handleSave, disabled: saving || !isDirty, size: "sm", children: saving ? "Saving..." : saveLabel })
3790
+ ] })
3533
3791
  ] }),
3534
3792
  /* @__PURE__ */ jsxs("div", { className: "flex gap-4 min-h-[500px]", children: [
3535
3793
  /* @__PURE__ */ jsxs("div", { className: "w-64 shrink-0 border border-border rounded-md overflow-hidden", children: [
@@ -3815,7 +4073,6 @@ function AgentSkillManager({ agentId, initialSkills, onSaved }) {
3815
4073
  onSaved?.();
3816
4074
  }, [agentId, client, onSaved]);
3817
4075
  return /* @__PURE__ */ jsxs("div", { children: [
3818
- /* @__PURE__ */ jsx("div", { className: "flex items-center justify-end mb-4", children: /* @__PURE__ */ jsx(Button, { size: "sm", variant: "outline", onClick: () => setImportOpen(true), children: "Import from skills.sh" }) }),
3819
4076
  /* @__PURE__ */ jsx(
3820
4077
  FileTreeEditor2,
3821
4078
  {
@@ -3827,7 +4084,8 @@ function AgentSkillManager({ agentId, initialSkills, onSaved }) {
3827
4084
  newFileTemplate: {
3828
4085
  filename: "SKILL.md",
3829
4086
  content: "---\nname: New Skill\ndescription: Describe when this skill should be triggered\n---\n\n# Instructions\n\nDescribe what this skill does...\n"
3830
- }
4087
+ },
4088
+ headerActions: /* @__PURE__ */ jsx(Button, { size: "sm", variant: "outline", onClick: () => setImportOpen(true), children: "Import from skills.sh" })
3831
4089
  }
3832
4090
  ),
3833
4091
  /* @__PURE__ */ jsx(
@@ -4689,7 +4947,7 @@ function renderEvent(event, idx) {
4689
4947
  /* @__PURE__ */ jsx(CollapsibleJson, { data: event, maxHeight: "8rem" })
4690
4948
  ] }, idx);
4691
4949
  }
4692
- var TERMINAL_STATUSES = /* @__PURE__ */ new Set(["completed", "failed", "cancelled", "timed_out"]);
4950
+ var TERMINAL_STATUSES2 = /* @__PURE__ */ new Set(["completed", "failed", "cancelled", "timed_out"]);
4693
4951
  function PlaygroundPage({ agentId }) {
4694
4952
  const client = useAgentPlaneClient();
4695
4953
  const { LinkComponent, basePath } = useNavigation();
@@ -4731,7 +4989,7 @@ function PlaygroundPage({ agentId }) {
4731
4989
  if (abortRef.current?.signal.aborted) break;
4732
4990
  try {
4733
4991
  const run = await client.runs.get(runId);
4734
- if (TERMINAL_STATUSES.has(run.status)) {
4992
+ if (TERMINAL_STATUSES2.has(run.status)) {
4735
4993
  try {
4736
4994
  const transcriptEvents = await client.runs.transcriptArray(runId);
4737
4995
  if (transcriptEvents.length > 0) {
@@ -4967,5 +5225,121 @@ function PlaygroundPage({ agentId }) {
4967
5225
  ] })
4968
5226
  ] });
4969
5227
  }
5228
+ var ToastProvider = ToastPrimitives.Provider;
5229
+ var ToastViewport = React4.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
5230
+ ToastPrimitives.Viewport,
5231
+ {
5232
+ ref,
5233
+ className: cn(
5234
+ "fixed top-0 right-0 z-[100] flex max-h-screen w-full flex-col-reverse gap-2 p-4 sm:flex-col sm:max-w-[420px]",
5235
+ className
5236
+ ),
5237
+ ...props
5238
+ }
5239
+ ));
5240
+ ToastViewport.displayName = ToastPrimitives.Viewport.displayName;
5241
+ var toastVariants = cva(
5242
+ "group pointer-events-auto relative flex w-full items-center justify-between gap-4 overflow-hidden rounded-lg border p-4 shadow-lg transition-all data-[swipe=cancel]:translate-x-0 data-[swipe=end]:translate-x-[var(--radix-toast-swipe-end-x)] data-[swipe=move]:translate-x-[var(--radix-toast-swipe-move-x)] data-[swipe=move]:transition-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[swipe=end]:animate-out data-[state=closed]:fade-out-80 data-[state=closed]:slide-out-to-right-full data-[state=open]:slide-in-from-top-full data-[state=open]:sm:slide-in-from-right-full",
5243
+ {
5244
+ variants: {
5245
+ variant: {
5246
+ default: "bg-zinc-800 border-zinc-700 text-zinc-100",
5247
+ success: "bg-green-950 border-green-900 text-green-400",
5248
+ destructive: "bg-red-950 border-red-900 text-red-400"
5249
+ }
5250
+ },
5251
+ defaultVariants: {
5252
+ variant: "default"
5253
+ }
5254
+ }
5255
+ );
5256
+ var Toast = React4.forwardRef(({ className, variant, ...props }, ref) => /* @__PURE__ */ jsx(
5257
+ ToastPrimitives.Root,
5258
+ {
5259
+ ref,
5260
+ className: cn(toastVariants({ variant }), className),
5261
+ ...props
5262
+ }
5263
+ ));
5264
+ Toast.displayName = ToastPrimitives.Root.displayName;
5265
+ var ToastAction = React4.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
5266
+ ToastPrimitives.Action,
5267
+ {
5268
+ ref,
5269
+ className: cn(
5270
+ "inline-flex h-8 shrink-0 items-center justify-center rounded-md border border-zinc-600 bg-transparent px-3 text-sm font-medium transition-colors hover:bg-zinc-700 focus:outline-none focus:ring-1 focus:ring-zinc-500 disabled:pointer-events-none disabled:opacity-50",
5271
+ "group-[.destructive]:border-red-800 group-[.destructive]:hover:border-red-700 group-[.destructive]:hover:bg-red-900 group-[.destructive]:focus:ring-red-800",
5272
+ "group-[.success]:border-green-800 group-[.success]:hover:border-green-700 group-[.success]:hover:bg-green-900 group-[.success]:focus:ring-green-800",
5273
+ className
5274
+ ),
5275
+ ...props
5276
+ }
5277
+ ));
5278
+ ToastAction.displayName = ToastPrimitives.Action.displayName;
5279
+ var ToastClose = React4.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
5280
+ ToastPrimitives.Close,
5281
+ {
5282
+ ref,
5283
+ className: cn(
5284
+ "absolute right-1 top-1 rounded-md p-1 text-zinc-400 opacity-0 transition-opacity hover:text-zinc-100 focus:opacity-100 focus:outline-none group-hover:opacity-100",
5285
+ "group-[.destructive]:text-red-400 group-[.destructive]:hover:text-red-300",
5286
+ "group-[.success]:text-green-400 group-[.success]:hover:text-green-300",
5287
+ className
5288
+ ),
5289
+ "toast-close": "",
5290
+ ...props,
5291
+ children: /* @__PURE__ */ jsxs(
5292
+ "svg",
5293
+ {
5294
+ xmlns: "http://www.w3.org/2000/svg",
5295
+ width: "16",
5296
+ height: "16",
5297
+ viewBox: "0 0 24 24",
5298
+ fill: "none",
5299
+ stroke: "currentColor",
5300
+ strokeWidth: "2",
5301
+ strokeLinecap: "round",
5302
+ strokeLinejoin: "round",
5303
+ children: [
5304
+ /* @__PURE__ */ jsx("path", { d: "M18 6 6 18" }),
5305
+ /* @__PURE__ */ jsx("path", { d: "m6 6 12 12" })
5306
+ ]
5307
+ }
5308
+ )
5309
+ }
5310
+ ));
5311
+ ToastClose.displayName = ToastPrimitives.Close.displayName;
5312
+ var ToastTitle = React4.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
5313
+ ToastPrimitives.Title,
5314
+ {
5315
+ ref,
5316
+ className: cn("text-sm font-semibold [&+div]:text-xs", className),
5317
+ ...props
5318
+ }
5319
+ ));
5320
+ ToastTitle.displayName = ToastPrimitives.Title.displayName;
5321
+ var ToastDescription = React4.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
5322
+ ToastPrimitives.Description,
5323
+ {
5324
+ ref,
5325
+ className: cn("text-sm opacity-90", className),
5326
+ ...props
5327
+ }
5328
+ ));
5329
+ ToastDescription.displayName = ToastPrimitives.Description.displayName;
5330
+ function Toaster() {
5331
+ const { toasts } = useToast();
5332
+ return /* @__PURE__ */ jsxs(ToastProvider, { children: [
5333
+ toasts.map(({ id, title, description, action, ...props }) => /* @__PURE__ */ jsxs(Toast, { ...props, children: [
5334
+ /* @__PURE__ */ jsxs("div", { className: "grid gap-1", children: [
5335
+ title && /* @__PURE__ */ jsx(ToastTitle, { children: title }),
5336
+ description && /* @__PURE__ */ jsx(ToastDescription, { children: description })
5337
+ ] }),
5338
+ action,
5339
+ /* @__PURE__ */ jsx(ToastClose, {})
5340
+ ] }, id)),
5341
+ /* @__PURE__ */ jsx(ToastViewport, {})
5342
+ ] });
5343
+ }
4970
5344
 
4971
- export { AdminTable, AdminTableHead, AdminTableRow, AgentA2aInfo, AgentConnectorsManager, AgentDetailPage, AgentEditForm, AgentListPage, AgentPluginManager, AgentRuns, AgentScheduleForm, AgentSkillManager, ConfirmDialog, CopyButton, DashboardPage, DetailPageHeader, EmptyRow, FormError, LocalDate, McpServerListPage, MetricCard, ModelSelector, PaginationBar, PlaygroundPage, PluginDetailPage, PluginMarketplaceDetailPage, PluginMarketplaceListPage, RunDetailPage, RunListPage, RunSourceBadge, RunStatusBadge, SectionHeader, Select, SettingsPage, Tabs, Textarea, Th, ToolkitMultiselect, TranscriptViewer, parsePaginationParams };
5345
+ export { AdminTable, AdminTableHead, AdminTableRow, AgentA2aInfo, AgentConnectorsManager, AgentDetailPage, AgentEditForm, AgentListPage, AgentPluginManager, AgentRuns, AgentScheduleForm, AgentSkillManager, ConfirmDialog, CopyButton, DashboardPage, DetailPageHeader, EmptyRow, FormError, LocalDate, McpServerListPage, MetricCard, ModelSelector, PaginationBar, PlaygroundPage, PluginDetailPage, PluginMarketplaceDetailPage, PluginMarketplaceListPage, RunDetailPage, RunListPage, RunSourceBadge, RunStatusBadge, SectionHeader, Select, SettingsPage, Tabs, Textarea, Th, Toast, ToastAction, ToastClose, ToastDescription, ToastProvider, ToastTitle, ToastViewport, Toaster, ToolkitMultiselect, TranscriptViewer, parsePaginationParams, toast, toastVariants, useRunStream, useToast };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@getcatalystiq/agent-plane-ui",
3
- "version": "0.1.29",
3
+ "version": "0.1.31",
4
4
  "description": "Embeddable React component library for AgentPlane",
5
5
  "type": "module",
6
6
  "exports": {
@@ -92,6 +92,7 @@
92
92
  },
93
93
  "dependencies": {
94
94
  "@radix-ui/react-popover": "^1.0.0",
95
+ "@radix-ui/react-toast": "^1.2.15",
95
96
  "class-variance-authority": "^0.7.0",
96
97
  "clsx": "^2.0.0",
97
98
  "cmdk": "^1.0.0",