@agent-native/dispatch 0.23.5 → 0.24.2
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/actions/list-connected-agents.d.ts +1 -0
- package/dist/actions/list-connected-agents.js +5 -1
- package/dist/actions/list-connected-agents.js.map +1 -1
- package/dist/actions/list-dispatch-usage-metrics.d.ts +2 -0
- package/dist/actions/list-dispatch-usage-metrics.js +11 -1
- package/dist/actions/list-dispatch-usage-metrics.js.map +1 -1
- package/dist/actions/provider-api-register.d.ts +12 -12
- package/dist/actions/remix-workspace-template.js +4 -3
- package/dist/actions/remix-workspace-template.js.map +1 -1
- package/dist/actions/scaffold-workspace-app.js +3 -2
- package/dist/actions/scaffold-workspace-app.js.map +1 -1
- package/dist/actions/start-workspace-app-creation.js +3 -2
- package/dist/actions/start-workspace-app-creation.js.map +1 -1
- package/dist/actions/view-screen.js +11 -1
- package/dist/actions/view-screen.js.map +1 -1
- package/dist/components/admin-navigation.d.ts.map +1 -1
- package/dist/components/admin-navigation.js +21 -5
- package/dist/components/admin-navigation.js.map +1 -1
- package/dist/components/app-icon.js +1 -1
- package/dist/components/app-icon.js.map +1 -1
- package/dist/components/app-list-row.d.ts +1 -1
- package/dist/components/app-list-row.d.ts.map +1 -1
- package/dist/components/app-list-row.js +1 -1
- package/dist/components/app-list-row.js.map +1 -1
- package/dist/components/app-open-actions.d.ts +1 -17
- package/dist/components/app-open-actions.d.ts.map +1 -1
- package/dist/components/app-open-actions.js +1 -20
- package/dist/components/app-open-actions.js.map +1 -1
- package/dist/components/app-row-settings.d.ts +6 -0
- package/dist/components/app-row-settings.d.ts.map +1 -0
- package/dist/components/app-row-settings.js +11 -0
- package/dist/components/app-row-settings.js.map +1 -0
- package/dist/components/automation-run-history-dialog.d.ts.map +1 -1
- package/dist/components/automation-run-history-dialog.js +3 -2
- package/dist/components/automation-run-history-dialog.js.map +1 -1
- package/dist/components/connected-app-card.d.ts.map +1 -1
- package/dist/components/connected-app-card.js +3 -2
- package/dist/components/connected-app-card.js.map +1 -1
- package/dist/components/create-app-popover.js +2 -2
- package/dist/components/create-app-popover.js.map +1 -1
- package/dist/components/dispatch-control-plane.d.ts.map +1 -1
- package/dist/components/dispatch-control-plane.js +23 -7
- package/dist/components/dispatch-control-plane.js.map +1 -1
- package/dist/components/dispatch-shell.d.ts.map +1 -1
- package/dist/components/dispatch-shell.js +5 -1
- package/dist/components/dispatch-shell.js.map +1 -1
- package/dist/components/docs-link.d.ts +16 -0
- package/dist/components/docs-link.d.ts.map +1 -0
- package/dist/components/docs-link.js +34 -0
- package/dist/components/docs-link.js.map +1 -0
- package/dist/components/layout/Layout.d.ts +1 -0
- package/dist/components/layout/Layout.d.ts.map +1 -1
- package/dist/components/layout/Layout.js +43 -35
- package/dist/components/layout/Layout.js.map +1 -1
- package/dist/components/messaging-setup-panel.d.ts.map +1 -1
- package/dist/components/messaging-setup-panel.js +3 -2
- package/dist/components/messaging-setup-panel.js.map +1 -1
- package/dist/components/usage-alerts-panel.d.ts +11 -0
- package/dist/components/usage-alerts-panel.d.ts.map +1 -0
- package/dist/components/usage-alerts-panel.js +125 -0
- package/dist/components/usage-alerts-panel.js.map +1 -0
- package/dist/components/workspace-app-card.d.ts +3 -1
- package/dist/components/workspace-app-card.d.ts.map +1 -1
- package/dist/components/workspace-app-card.js +70 -29
- package/dist/components/workspace-app-card.js.map +1 -1
- package/dist/components/workspace-app-search.d.ts +10 -0
- package/dist/components/workspace-app-search.d.ts.map +1 -0
- package/dist/components/workspace-app-search.js +27 -0
- package/dist/components/workspace-app-search.js.map +1 -0
- package/dist/components/workspace-resource-effective-stack.d.ts.map +1 -1
- package/dist/components/workspace-resource-effective-stack.js +3 -2
- package/dist/components/workspace-resource-effective-stack.js.map +1 -1
- package/dist/components/workspace-template-card.d.ts.map +1 -1
- package/dist/components/workspace-template-card.js +10 -15
- package/dist/components/workspace-template-card.js.map +1 -1
- package/dist/hooks/use-navigation-state.d.ts +2 -0
- package/dist/hooks/use-navigation-state.d.ts.map +1 -1
- package/dist/hooks/use-navigation-state.js +10 -0
- package/dist/hooks/use-navigation-state.js.map +1 -1
- package/dist/lib/embed-session-recovery.d.ts +3 -0
- package/dist/lib/embed-session-recovery.d.ts.map +1 -0
- package/dist/lib/embed-session-recovery.js +18 -0
- package/dist/lib/embed-session-recovery.js.map +1 -0
- package/dist/lib/other-apps.d.ts +2 -0
- package/dist/lib/other-apps.d.ts.map +1 -1
- package/dist/lib/other-apps.js.map +1 -1
- package/dist/lib/workspace-app-layout.d.ts +19 -0
- package/dist/lib/workspace-app-layout.d.ts.map +1 -0
- package/dist/lib/workspace-app-layout.js +75 -0
- package/dist/lib/workspace-app-layout.js.map +1 -0
- package/dist/lib/workspace-apps.d.ts +14 -0
- package/dist/lib/workspace-apps.d.ts.map +1 -1
- package/dist/lib/workspace-apps.js +66 -0
- package/dist/lib/workspace-apps.js.map +1 -1
- package/dist/lib/workspace-apps.test.d.ts +2 -0
- package/dist/lib/workspace-apps.test.d.ts.map +1 -0
- package/dist/lib/workspace-apps.test.js +33 -0
- package/dist/lib/workspace-apps.test.js.map +1 -0
- package/dist/routes/pages/$appId.d.ts.map +1 -1
- package/dist/routes/pages/$appId.js +4 -2
- package/dist/routes/pages/$appId.js.map +1 -1
- package/dist/routes/pages/agents.d.ts.map +1 -1
- package/dist/routes/pages/agents.js +2 -3
- package/dist/routes/pages/agents.js.map +1 -1
- package/dist/routes/pages/apps.$appId.d.ts.map +1 -1
- package/dist/routes/pages/apps.$appId.js +17 -13
- package/dist/routes/pages/apps.$appId.js.map +1 -1
- package/dist/routes/pages/apps.d.ts.map +1 -1
- package/dist/routes/pages/apps.js +31 -16
- package/dist/routes/pages/apps.js.map +1 -1
- package/dist/routes/pages/audit.d.ts.map +1 -1
- package/dist/routes/pages/audit.js +2 -1
- package/dist/routes/pages/audit.js.map +1 -1
- package/dist/routes/pages/chat.d.ts.map +1 -1
- package/dist/routes/pages/chat.js +7 -2
- package/dist/routes/pages/chat.js.map +1 -1
- package/dist/routes/pages/dreams.d.ts.map +1 -1
- package/dist/routes/pages/dreams.js +14 -18
- package/dist/routes/pages/dreams.js.map +1 -1
- package/dist/routes/pages/integrations.d.ts.map +1 -1
- package/dist/routes/pages/integrations.js +51 -14
- package/dist/routes/pages/integrations.js.map +1 -1
- package/dist/routes/pages/metrics.d.ts.map +1 -1
- package/dist/routes/pages/metrics.js +146 -17
- package/dist/routes/pages/metrics.js.map +1 -1
- package/dist/routes/pages/operations.js +1 -1
- package/dist/routes/pages/operations.js.map +1 -1
- package/dist/routes/pages/settings.d.ts.map +1 -1
- package/dist/routes/pages/settings.js +19 -2
- package/dist/routes/pages/settings.js.map +1 -1
- package/dist/routes/pages/thread-debug.d.ts.map +1 -1
- package/dist/routes/pages/thread-debug.js +5 -8
- package/dist/routes/pages/thread-debug.js.map +1 -1
- package/dist/routes/pages/vault.d.ts.map +1 -1
- package/dist/routes/pages/vault.js +1 -1
- package/dist/routes/pages/vault.js.map +1 -1
- package/dist/routes/pages/workspace.d.ts.map +1 -1
- package/dist/routes/pages/workspace.js +13 -10
- package/dist/routes/pages/workspace.js.map +1 -1
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +3 -0
- package/dist/server/index.js.map +1 -1
- package/dist/server/lib/app-creation-store.d.ts.map +1 -1
- package/dist/server/lib/app-creation-store.js +12 -52
- package/dist/server/lib/app-creation-store.js.map +1 -1
- package/dist/server/lib/usage-metrics-store.d.ts +17 -0
- package/dist/server/lib/usage-metrics-store.d.ts.map +1 -1
- package/dist/server/lib/usage-metrics-store.js +187 -30
- package/dist/server/lib/usage-metrics-store.js.map +1 -1
- package/dist/server/plugins/agent-chat.js +2 -0
- package/dist/server/plugins/agent-chat.js.map +1 -1
- package/dist/server/plugins/integrations.d.ts.map +1 -1
- package/dist/server/plugins/integrations.js +1 -0
- package/dist/server/plugins/integrations.js.map +1 -1
- package/dist/shared/app-roles.d.ts +9 -0
- package/dist/shared/app-roles.d.ts.map +1 -0
- package/dist/shared/app-roles.js +7 -0
- package/dist/shared/app-roles.js.map +1 -0
- package/package.json +4 -3
- package/src/actions/list-connected-agents.spec.ts +73 -0
- package/src/actions/list-connected-agents.ts +6 -2
- package/src/actions/list-dispatch-usage-metrics.ts +11 -1
- package/src/actions/remix-workspace-template.spec.ts +29 -0
- package/src/actions/remix-workspace-template.ts +13 -6
- package/src/actions/scaffold-workspace-app.ts +12 -5
- package/src/actions/start-workspace-app-creation.ts +8 -2
- package/src/actions/view-screen.ts +13 -1
- package/src/components/admin-navigation.tsx +57 -11
- package/src/components/app-icon.spec.tsx +34 -0
- package/src/components/app-icon.tsx +1 -1
- package/src/components/app-list-row.tsx +1 -2
- package/src/components/app-open-actions.tsx +5 -114
- package/src/components/app-row-settings.tsx +54 -0
- package/src/components/automation-run-history-dialog.tsx +8 -4
- package/src/components/connected-app-card.tsx +3 -2
- package/src/components/create-app-popover.spec.tsx +1 -1
- package/src/components/create-app-popover.tsx +2 -2
- package/src/components/dispatch-control-plane.spec.tsx +44 -3
- package/src/components/dispatch-control-plane.tsx +83 -27
- package/src/components/dispatch-shell.tsx +7 -1
- package/src/components/docs-link.tsx +52 -0
- package/src/components/layout/Layout.spec.tsx +13 -0
- package/src/components/layout/Layout.tsx +63 -32
- package/src/components/messaging-setup-panel.tsx +10 -3
- package/src/components/usage-alerts-panel.tsx +445 -0
- package/src/components/workspace-app-card.spec.tsx +130 -9
- package/src/components/workspace-app-card.tsx +128 -71
- package/src/components/workspace-app-search.tsx +96 -0
- package/src/components/workspace-resource-effective-stack.tsx +10 -5
- package/src/components/workspace-template-card.spec.tsx +53 -24
- package/src/components/workspace-template-card.tsx +16 -26
- package/src/hooks/use-navigation-state.ts +12 -0
- package/src/lib/embed-session-recovery.spec.ts +63 -0
- package/src/lib/embed-session-recovery.ts +26 -0
- package/src/lib/other-apps.ts +2 -0
- package/src/lib/workspace-app-layout.spec.ts +47 -0
- package/src/lib/workspace-app-layout.ts +121 -0
- package/src/lib/workspace-apps.test.ts +64 -0
- package/src/lib/workspace-apps.ts +82 -0
- package/src/routes/pages/$appId.tsx +3 -6
- package/src/routes/pages/agents.tsx +6 -3
- package/src/routes/pages/apps.$appId.tsx +16 -17
- package/src/routes/pages/apps.tsx +116 -62
- package/src/routes/pages/audit.tsx +28 -8
- package/src/routes/pages/chat.spec.tsx +10 -0
- package/src/routes/pages/chat.tsx +8 -0
- package/src/routes/pages/dreams.tsx +92 -142
- package/src/routes/pages/integrations.tsx +147 -68
- package/src/routes/pages/metrics.tsx +460 -102
- package/src/routes/pages/operations.tsx +2 -2
- package/src/routes/pages/settings.tsx +27 -10
- package/src/routes/pages/thread-debug.tsx +18 -36
- package/src/routes/pages/vault.tsx +7 -2
- package/src/routes/pages/workspace.tsx +92 -56
- package/src/server/index.ts +4 -0
- package/src/server/lib/app-creation-store.spec.ts +90 -43
- package/src/server/lib/app-creation-store.ts +15 -61
- package/src/server/lib/usage-metrics-store.spec.ts +117 -0
- package/src/server/lib/usage-metrics-store.ts +249 -30
- package/src/server/plugins/agent-chat.spec.ts +4 -0
- package/src/server/plugins/agent-chat.ts +2 -0
- package/src/server/plugins/integrations.ts +1 -0
- package/src/shared/app-roles.ts +8 -0
- package/src/styles/dispatch.css +9 -0
|
@@ -4,11 +4,8 @@ import {
|
|
|
4
4
|
} from "@agent-native/core/client/hooks";
|
|
5
5
|
import {
|
|
6
6
|
IconAlertTriangle,
|
|
7
|
-
IconBrain,
|
|
8
7
|
IconCalendarTime,
|
|
9
8
|
IconCheck,
|
|
10
|
-
IconCircleDashed,
|
|
11
|
-
IconClock,
|
|
12
9
|
IconDatabase,
|
|
13
10
|
IconFileDiff,
|
|
14
11
|
IconPlayerPlay,
|
|
@@ -548,32 +545,6 @@ function ProposalSkeleton() {
|
|
|
548
545
|
);
|
|
549
546
|
}
|
|
550
547
|
|
|
551
|
-
function StatTile({
|
|
552
|
-
label,
|
|
553
|
-
value,
|
|
554
|
-
icon: Icon,
|
|
555
|
-
}: {
|
|
556
|
-
label: string;
|
|
557
|
-
value: string | number;
|
|
558
|
-
icon: typeof IconBrain;
|
|
559
|
-
}) {
|
|
560
|
-
return (
|
|
561
|
-
<div className="rounded-lg bg-card px-3 py-2.5">
|
|
562
|
-
<div className="flex items-center justify-between gap-2">
|
|
563
|
-
<div className="min-w-0 flex-1">
|
|
564
|
-
<div className="truncate text-[11px] font-medium uppercase tracking-wide text-muted-foreground">
|
|
565
|
-
{label}
|
|
566
|
-
</div>
|
|
567
|
-
<div className="mt-1 text-xl font-semibold tabular-nums text-foreground">
|
|
568
|
-
{value}
|
|
569
|
-
</div>
|
|
570
|
-
</div>
|
|
571
|
-
<Icon size={18} className="shrink-0 text-muted-foreground" />
|
|
572
|
-
</div>
|
|
573
|
-
</div>
|
|
574
|
-
);
|
|
575
|
-
}
|
|
576
|
-
|
|
577
548
|
function DreamSettingsSheet({
|
|
578
549
|
open,
|
|
579
550
|
onOpenChange,
|
|
@@ -1358,10 +1329,6 @@ export default function DreamsRoute() {
|
|
|
1358
1329
|
const evidenceItems: DreamEvidence[] = detail?.evidence ?? [];
|
|
1359
1330
|
const selectedSourceHealth: DreamSourceHealth[] =
|
|
1360
1331
|
selectedDream?.sourceHealth ?? [];
|
|
1361
|
-
const pendingProposalCount = proposals.filter(
|
|
1362
|
-
(proposal) =>
|
|
1363
|
-
String(proposal.status || "pending").toLowerCase() === "pending",
|
|
1364
|
-
).length;
|
|
1365
1332
|
const appliedProposalCount = proposals.filter(
|
|
1366
1333
|
(proposal) => String(proposal.status || "").toLowerCase() === "applied",
|
|
1367
1334
|
).length;
|
|
@@ -1428,32 +1395,10 @@ export default function DreamsRoute() {
|
|
|
1428
1395
|
description="Review agent runs, propose memory improvements, and apply evidence-backed learning changes."
|
|
1429
1396
|
>
|
|
1430
1397
|
<div className="space-y-4">
|
|
1431
|
-
<div className="flex flex-
|
|
1432
|
-
<div className="
|
|
1433
|
-
<StatTile
|
|
1434
|
-
label="Dream passes"
|
|
1435
|
-
value={dreams.length}
|
|
1436
|
-
icon={IconBrain}
|
|
1437
|
-
/>
|
|
1438
|
-
<StatTile
|
|
1439
|
-
label="Pending proposals"
|
|
1440
|
-
value={pendingProposalCount}
|
|
1441
|
-
icon={IconCircleDashed}
|
|
1442
|
-
/>
|
|
1443
|
-
<StatTile
|
|
1444
|
-
label="Candidate runs"
|
|
1445
|
-
value={candidates.length}
|
|
1446
|
-
icon={IconClock}
|
|
1447
|
-
/>
|
|
1448
|
-
<StatTile
|
|
1449
|
-
label="Inspected threads"
|
|
1450
|
-
value={selectedDream ? dreamInspectedCount(selectedDream) : 0}
|
|
1451
|
-
icon={IconCheck}
|
|
1452
|
-
/>
|
|
1453
|
-
</div>
|
|
1454
|
-
<div className="flex flex-wrap items-center gap-2">
|
|
1398
|
+
<div className="flex flex-wrap items-center justify-between gap-3 border-b pb-3">
|
|
1399
|
+
<div className="flex min-w-0 flex-wrap items-center gap-x-3 gap-y-1">
|
|
1455
1400
|
{dreamSettings ? (
|
|
1456
|
-
<Badge variant="outline" className="
|
|
1401
|
+
<Badge variant="outline" className="max-w-full truncate">
|
|
1457
1402
|
{dreamSettings.enabled ? "Enabled" : "Paused"} ·{" "}
|
|
1458
1403
|
{dreamSettings.allSources
|
|
1459
1404
|
? "All sources"
|
|
@@ -1461,6 +1406,11 @@ export default function DreamsRoute() {
|
|
|
1461
1406
|
· {dreamSettings.schedule}
|
|
1462
1407
|
</Badge>
|
|
1463
1408
|
) : null}
|
|
1409
|
+
<span className="text-xs text-muted-foreground">
|
|
1410
|
+
{dreams.length} passes · {candidates.length} candidate runs
|
|
1411
|
+
</span>
|
|
1412
|
+
</div>
|
|
1413
|
+
<div className="flex flex-wrap items-center gap-2">
|
|
1464
1414
|
<DreamSettingsSheet
|
|
1465
1415
|
open={settingsOpen}
|
|
1466
1416
|
onOpenChange={handleSettingsOpenChange}
|
|
@@ -1519,8 +1469,8 @@ export default function DreamsRoute() {
|
|
|
1519
1469
|
</div>
|
|
1520
1470
|
</div>
|
|
1521
1471
|
|
|
1522
|
-
<div className="grid gap-4 lg:grid-cols-
|
|
1523
|
-
<section className="rounded-lg bg-card">
|
|
1472
|
+
<div className="grid gap-4 lg:grid-cols-[280px_minmax(0,1fr)]">
|
|
1473
|
+
<section className="min-w-0 rounded-lg bg-card">
|
|
1524
1474
|
<div className="border-b px-4 py-3">
|
|
1525
1475
|
<div className="text-sm font-semibold text-foreground">
|
|
1526
1476
|
Recent passes
|
|
@@ -1770,92 +1720,92 @@ export default function DreamsRoute() {
|
|
|
1770
1720
|
) : null}
|
|
1771
1721
|
</div>
|
|
1772
1722
|
</section>
|
|
1723
|
+
</div>
|
|
1773
1724
|
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
</div>
|
|
1725
|
+
<section className="min-w-0 rounded-lg bg-card">
|
|
1726
|
+
<div className="border-b px-4 py-3">
|
|
1727
|
+
<div>
|
|
1728
|
+
<div className="text-sm font-semibold text-foreground">
|
|
1729
|
+
Candidate runs
|
|
1730
|
+
</div>
|
|
1731
|
+
<div className="mt-1 text-xs text-muted-foreground">
|
|
1732
|
+
Grounded signals ready for review.
|
|
1783
1733
|
</div>
|
|
1784
1734
|
</div>
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
</
|
|
1807
|
-
</
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
|
|
1824
|
-
|
|
1825
|
-
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
</
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
|
|
1735
|
+
</div>
|
|
1736
|
+
<div className="max-h-[720px] overflow-auto p-3">
|
|
1737
|
+
<QueryState
|
|
1738
|
+
error={candidatesQuery.error}
|
|
1739
|
+
label="Could not load candidates"
|
|
1740
|
+
/>
|
|
1741
|
+
{candidatesQuery.isLoading ? <DreamListSkeleton /> : null}
|
|
1742
|
+
{!candidatesQuery.isLoading &&
|
|
1743
|
+
!candidatesQuery.error &&
|
|
1744
|
+
candidateSourceHealth.length > 0 ? (
|
|
1745
|
+
<div className="mb-3">
|
|
1746
|
+
<SourceHealthPanel sources={candidateSourceHealth} />
|
|
1747
|
+
</div>
|
|
1748
|
+
) : null}
|
|
1749
|
+
{!candidatesQuery.isLoading && !candidatesQuery.error ? (
|
|
1750
|
+
candidates.length > 0 ? (
|
|
1751
|
+
<Table>
|
|
1752
|
+
<TableHeader>
|
|
1753
|
+
<TableRow>
|
|
1754
|
+
<TableHead>Run</TableHead>
|
|
1755
|
+
<TableHead>Signals</TableHead>
|
|
1756
|
+
<TableHead className="w-20 text-right">Score</TableHead>
|
|
1757
|
+
</TableRow>
|
|
1758
|
+
</TableHeader>
|
|
1759
|
+
<TableBody>
|
|
1760
|
+
{candidates.map((candidate) => {
|
|
1761
|
+
const id = candidateId(candidate);
|
|
1762
|
+
const signals = candidateSignals(candidate);
|
|
1763
|
+
return (
|
|
1764
|
+
<TableRow key={id}>
|
|
1765
|
+
<TableCell className="min-w-0 py-3">
|
|
1766
|
+
<div className="max-w-[230px] truncate text-sm font-medium text-foreground">
|
|
1767
|
+
{candidateLabel(candidate)}
|
|
1768
|
+
</div>
|
|
1769
|
+
<div className="mt-1 truncate font-mono text-[11px] text-muted-foreground">
|
|
1770
|
+
{candidate.thread?.id ??
|
|
1771
|
+
candidate.threadId ??
|
|
1772
|
+
candidate.runId ??
|
|
1773
|
+
id}
|
|
1774
|
+
</div>
|
|
1775
|
+
<div className="mt-1 text-[11px] text-muted-foreground">
|
|
1776
|
+
{candidateOwner(candidate)} ·{" "}
|
|
1777
|
+
{compactDate(candidateUpdatedAt(candidate))}
|
|
1778
|
+
</div>
|
|
1779
|
+
</TableCell>
|
|
1780
|
+
<TableCell className="py-3">
|
|
1781
|
+
<div className="mt-1 flex flex-wrap gap-1">
|
|
1782
|
+
<Badge variant="outline">
|
|
1783
|
+
{candidateStatus(candidate)}
|
|
1784
|
+
</Badge>
|
|
1785
|
+
{signals.slice(0, 2).map((signal) => (
|
|
1786
|
+
<Badge key={signal} variant="secondary">
|
|
1787
|
+
{signal}
|
|
1833
1788
|
</Badge>
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
)
|
|
1855
|
-
) : null}
|
|
1856
|
-
</div>
|
|
1857
|
-
</section>
|
|
1858
|
-
</div>
|
|
1789
|
+
))}
|
|
1790
|
+
</div>
|
|
1791
|
+
</TableCell>
|
|
1792
|
+
<TableCell className="py-3 text-right text-sm tabular-nums text-muted-foreground">
|
|
1793
|
+
{candidate.score ?? "n/a"}
|
|
1794
|
+
</TableCell>
|
|
1795
|
+
</TableRow>
|
|
1796
|
+
);
|
|
1797
|
+
})}
|
|
1798
|
+
</TableBody>
|
|
1799
|
+
</Table>
|
|
1800
|
+
) : (
|
|
1801
|
+
<EmptyPanel
|
|
1802
|
+
title="No candidates"
|
|
1803
|
+
description="No recent runs matched the dream candidate heuristics."
|
|
1804
|
+
/>
|
|
1805
|
+
)
|
|
1806
|
+
) : null}
|
|
1807
|
+
</div>
|
|
1808
|
+
</section>
|
|
1859
1809
|
</div>
|
|
1860
1810
|
</DispatchShell>
|
|
1861
1811
|
);
|
|
@@ -3,12 +3,14 @@ import {
|
|
|
3
3
|
useActionQuery,
|
|
4
4
|
} from "@agent-native/core/client/hooks";
|
|
5
5
|
import {
|
|
6
|
-
|
|
6
|
+
getDefaultMcpIntegrations,
|
|
7
|
+
McpIntegrationLogo,
|
|
8
|
+
} from "@agent-native/core/client/resources";
|
|
9
|
+
import {
|
|
7
10
|
IconChevronRight,
|
|
8
|
-
IconCircleDashed,
|
|
9
|
-
IconKey,
|
|
10
11
|
IconLink,
|
|
11
12
|
IconPlugConnected,
|
|
13
|
+
IconSearch,
|
|
12
14
|
} from "@tabler/icons-react";
|
|
13
15
|
import { useQueryClient } from "@tanstack/react-query";
|
|
14
16
|
import { useMemo, useState } from "react";
|
|
@@ -17,7 +19,6 @@ import { toast } from "sonner";
|
|
|
17
19
|
|
|
18
20
|
import { ActionQueryError } from "../../components/action-query-error";
|
|
19
21
|
import { DispatchShell } from "../../components/dispatch-shell";
|
|
20
|
-
import { Badge } from "../../components/ui/badge";
|
|
21
22
|
import { Button } from "../../components/ui/button";
|
|
22
23
|
import {
|
|
23
24
|
Collapsible,
|
|
@@ -34,11 +35,7 @@ import {
|
|
|
34
35
|
} from "../../components/ui/dialog";
|
|
35
36
|
import { Input } from "../../components/ui/input";
|
|
36
37
|
import { Label } from "../../components/ui/label";
|
|
37
|
-
import {
|
|
38
|
-
Tooltip,
|
|
39
|
-
TooltipContent,
|
|
40
|
-
TooltipTrigger,
|
|
41
|
-
} from "../../components/ui/tooltip";
|
|
38
|
+
import { Skeleton } from "../../components/ui/skeleton";
|
|
42
39
|
|
|
43
40
|
export function meta() {
|
|
44
41
|
return [{ title: "Connections — Dispatch" }];
|
|
@@ -97,6 +94,38 @@ function inferProviderFromKey(key: string, label: string): string {
|
|
|
97
94
|
return "other";
|
|
98
95
|
}
|
|
99
96
|
|
|
97
|
+
const MCP_INTEGRATIONS_BY_ID = new Map(
|
|
98
|
+
getDefaultMcpIntegrations().map((integration) => [
|
|
99
|
+
integration.id,
|
|
100
|
+
integration,
|
|
101
|
+
]),
|
|
102
|
+
);
|
|
103
|
+
|
|
104
|
+
const CREDENTIAL_PROVIDER_LOGO_IDS: Record<string, string> = {
|
|
105
|
+
google: "google-workspace",
|
|
106
|
+
bigquery: "google-workspace",
|
|
107
|
+
jira: "atlassian",
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
function credentialLogo(service: Service) {
|
|
111
|
+
const providerId = inferProviderFromKey(service.key, service.label);
|
|
112
|
+
const integration = MCP_INTEGRATIONS_BY_ID.get(
|
|
113
|
+
CREDENTIAL_PROVIDER_LOGO_IDS[providerId] ?? providerId,
|
|
114
|
+
);
|
|
115
|
+
if (!integration?.logoUrl) {
|
|
116
|
+
return <IconPlugConnected className="size-4 text-muted-foreground" />;
|
|
117
|
+
}
|
|
118
|
+
return (
|
|
119
|
+
<McpIntegrationLogo
|
|
120
|
+
name={service.label}
|
|
121
|
+
logoUrl={integration.logoUrl}
|
|
122
|
+
integrationId={integration.id}
|
|
123
|
+
className="size-full rounded-md border-0 bg-transparent"
|
|
124
|
+
imageClassName="size-full p-1"
|
|
125
|
+
/>
|
|
126
|
+
);
|
|
127
|
+
}
|
|
128
|
+
|
|
100
129
|
function ConnectDialog({
|
|
101
130
|
service,
|
|
102
131
|
open,
|
|
@@ -110,6 +139,10 @@ function ConnectDialog({
|
|
|
110
139
|
}) {
|
|
111
140
|
const [value, setValue] = useState("");
|
|
112
141
|
const qc = useQueryClient();
|
|
142
|
+
const configuredApps = service.apps.filter((app) => app.configured);
|
|
143
|
+
const configuredAppNames = configuredApps
|
|
144
|
+
.map((app) => app.appName)
|
|
145
|
+
.join(", ");
|
|
113
146
|
|
|
114
147
|
const createSecret = useActionMutation("create-vault-secret", {});
|
|
115
148
|
const createGrant = useActionMutation("create-vault-grant", {});
|
|
@@ -189,12 +222,11 @@ function ConnectDialog({
|
|
|
189
222
|
<DialogHeader>
|
|
190
223
|
<DialogTitle>Connect {service.label}</DialogTitle>
|
|
191
224
|
<DialogDescription>
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
it.
|
|
225
|
+
{configuredApps.length > 0
|
|
226
|
+
? `Configured in ${configuredAppNames}. `
|
|
227
|
+
: "No app currently reports this key as configured. "}
|
|
228
|
+
Saving it creates a workspace vault entry using this exact key name.
|
|
229
|
+
Apps need the same key name to use it.
|
|
198
230
|
</DialogDescription>
|
|
199
231
|
</DialogHeader>
|
|
200
232
|
<div className="space-y-3">
|
|
@@ -240,55 +272,54 @@ function ConnectorCard({
|
|
|
240
272
|
accessMode: "all-apps" | "manual";
|
|
241
273
|
}) {
|
|
242
274
|
const [open, setOpen] = useState(false);
|
|
243
|
-
const
|
|
244
|
-
const
|
|
275
|
+
const configuredApps = service.apps.filter((app) => app.configured);
|
|
276
|
+
const vaultApps = service.apps.filter((app) => app.vaultGranted);
|
|
277
|
+
const isAvailable = configuredApps.length > 0 || vaultApps.length > 0;
|
|
278
|
+
const configuredAppNames = configuredApps
|
|
279
|
+
.map((app) => app.appName)
|
|
280
|
+
.join(", ");
|
|
281
|
+
const vaultAppNames = vaultApps.map((app) => app.appName).join(", ");
|
|
245
282
|
|
|
246
283
|
return (
|
|
247
284
|
<>
|
|
248
|
-
<
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
className="group flex flex-col items-start gap-2 rounded-2xl bg-card p-5 text-left transition-[background-color] hover:bg-card/80 cursor-pointer"
|
|
252
|
-
>
|
|
253
|
-
<div className="flex w-full items-start justify-between gap-2">
|
|
254
|
-
<div className="flex h-9 w-9 items-center justify-center rounded-xl bg-muted">
|
|
255
|
-
<IconKey size={16} className="text-muted-foreground" />
|
|
256
|
-
</div>
|
|
257
|
-
{isConnected ? (
|
|
258
|
-
<Badge
|
|
259
|
-
variant="secondary"
|
|
260
|
-
className="bg-green-500/10 text-green-700 dark:text-green-400 gap-1"
|
|
261
|
-
>
|
|
262
|
-
<IconCheck size={12} />
|
|
263
|
-
Connected
|
|
264
|
-
</Badge>
|
|
265
|
-
) : (
|
|
266
|
-
<Badge
|
|
267
|
-
variant="secondary"
|
|
268
|
-
className="bg-amber-500/10 text-amber-700 dark:text-amber-400 gap-1"
|
|
269
|
-
>
|
|
270
|
-
<IconCircleDashed size={12} />
|
|
271
|
-
Connect
|
|
272
|
-
</Badge>
|
|
273
|
-
)}
|
|
285
|
+
<article className="flex min-w-0 items-center gap-3 border-b border-border/60 py-3.5 last:border-b-0">
|
|
286
|
+
<div className="flex size-8 shrink-0 items-center justify-center rounded-md bg-muted">
|
|
287
|
+
{credentialLogo(service)}
|
|
274
288
|
</div>
|
|
275
|
-
<div className="
|
|
276
|
-
<
|
|
277
|
-
<
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
289
|
+
<div className="min-w-0 flex-1">
|
|
290
|
+
<div className="flex min-w-0 items-center gap-2">
|
|
291
|
+
<span className="truncate text-sm font-medium text-foreground">
|
|
292
|
+
{service.label}
|
|
293
|
+
</span>
|
|
294
|
+
<span
|
|
295
|
+
className={
|
|
296
|
+
isAvailable
|
|
297
|
+
? "shrink-0 text-[11px] font-medium text-emerald-600 dark:text-emerald-400"
|
|
298
|
+
: "shrink-0 text-[11px] font-medium text-muted-foreground"
|
|
299
|
+
}
|
|
300
|
+
>
|
|
301
|
+
{vaultApps.length > 0 ? "Connected" : "App key"}
|
|
302
|
+
</span>
|
|
286
303
|
</div>
|
|
304
|
+
<p className="mt-0.5 truncate font-mono text-[11px] leading-5 text-muted-foreground/80">
|
|
305
|
+
{service.key}
|
|
306
|
+
</p>
|
|
307
|
+
<p className="mt-0.5 truncate text-xs leading-5 text-muted-foreground">
|
|
308
|
+
Declared by {service.apps.length}{" "}
|
|
309
|
+
{service.apps.length === 1 ? "app" : "apps"}
|
|
310
|
+
{configuredApps.length > 0 ? ` · ${configuredAppNames}` : ""}
|
|
311
|
+
{vaultApps.length > 0 ? ` · Vault: ${vaultAppNames}` : ""}
|
|
312
|
+
</p>
|
|
287
313
|
</div>
|
|
288
|
-
<
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
314
|
+
<button
|
|
315
|
+
type="button"
|
|
316
|
+
onClick={() => setOpen(true)}
|
|
317
|
+
className="inline-flex h-8 shrink-0 items-center justify-center gap-1 rounded-md border border-border bg-background px-2.5 text-xs font-medium text-foreground transition-colors hover:bg-accent focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
|
|
318
|
+
>
|
|
319
|
+
{isAvailable ? "Manage" : "Connect"}
|
|
320
|
+
<IconChevronRight className="size-3.5 rtl:-scale-x-100" />
|
|
321
|
+
</button>
|
|
322
|
+
</article>
|
|
292
323
|
<ConnectDialog
|
|
293
324
|
service={service}
|
|
294
325
|
open={open}
|
|
@@ -326,11 +357,13 @@ function PerAppDetailRow({ app }: { app: CatalogApp }) {
|
|
|
326
357
|
export default function ConnectionsRoute() {
|
|
327
358
|
const catalogQuery = useActionQuery("list-integrations-catalog", {});
|
|
328
359
|
const accessQuery = useActionQuery("get-vault-access-settings", {});
|
|
329
|
-
const { data: catalog
|
|
360
|
+
const { data: catalog } = catalogQuery;
|
|
330
361
|
const { data: accessSettings } = accessQuery;
|
|
362
|
+
const isLoading = catalogQuery.isLoading || accessQuery.isLoading;
|
|
331
363
|
const apps = (catalog as CatalogApp[]) || [];
|
|
332
364
|
const accessMode =
|
|
333
365
|
(accessSettings as any)?.mode === "manual" ? "manual" : "all-apps";
|
|
366
|
+
const [query, setQuery] = useState("");
|
|
334
367
|
|
|
335
368
|
const services = useMemo<Service[]>(() => {
|
|
336
369
|
const map = new Map<string, Service>();
|
|
@@ -358,13 +391,26 @@ export default function ConnectionsRoute() {
|
|
|
358
391
|
);
|
|
359
392
|
}, [apps]);
|
|
360
393
|
|
|
361
|
-
const
|
|
362
|
-
|
|
394
|
+
const filteredServices = useMemo(() => {
|
|
395
|
+
const normalized = query.trim().toLowerCase();
|
|
396
|
+
if (!normalized) return services;
|
|
397
|
+
return services.filter(
|
|
398
|
+
(service) =>
|
|
399
|
+
service.label.toLowerCase().includes(normalized) ||
|
|
400
|
+
service.key.toLowerCase().includes(normalized),
|
|
401
|
+
);
|
|
402
|
+
}, [query, services]);
|
|
403
|
+
const available = filteredServices.filter(
|
|
404
|
+
(s) => !s.apps.some((a) => a.configured),
|
|
405
|
+
);
|
|
406
|
+
const connected = filteredServices.filter((s) =>
|
|
407
|
+
s.apps.some((a) => a.configured),
|
|
408
|
+
);
|
|
363
409
|
|
|
364
410
|
return (
|
|
365
411
|
<DispatchShell
|
|
366
412
|
title="Connections"
|
|
367
|
-
description="Connect
|
|
413
|
+
description="Connect workspace credentials declared by apps and manage how they are shared."
|
|
368
414
|
>
|
|
369
415
|
{catalogQuery.isError || accessQuery.isError ? (
|
|
370
416
|
<ActionQueryError
|
|
@@ -376,9 +422,40 @@ export default function ConnectionsRoute() {
|
|
|
376
422
|
/>
|
|
377
423
|
) : null}
|
|
378
424
|
|
|
425
|
+
{!catalogQuery.isError && !isLoading ? (
|
|
426
|
+
<div className="mb-5 flex items-center gap-3">
|
|
427
|
+
<div className="relative min-w-0 flex-1">
|
|
428
|
+
<IconSearch className="pointer-events-none absolute start-3 top-1/2 size-4 -translate-y-1/2 text-muted-foreground" />
|
|
429
|
+
<Input
|
|
430
|
+
value={query}
|
|
431
|
+
onChange={(event) => setQuery(event.target.value)}
|
|
432
|
+
placeholder="Search credentials"
|
|
433
|
+
aria-label="Search credentials"
|
|
434
|
+
className="h-9 ps-9"
|
|
435
|
+
/>
|
|
436
|
+
</div>
|
|
437
|
+
<span className="shrink-0 text-xs text-muted-foreground">
|
|
438
|
+
{filteredServices.length} credential
|
|
439
|
+
{filteredServices.length === 1 ? "" : "s"}
|
|
440
|
+
</span>
|
|
441
|
+
</div>
|
|
442
|
+
) : null}
|
|
443
|
+
|
|
379
444
|
{!catalogQuery.isError && isLoading && services.length === 0 && (
|
|
380
|
-
<div className="
|
|
381
|
-
|
|
445
|
+
<div className="overflow-hidden rounded-lg bg-card">
|
|
446
|
+
{Array.from({ length: 7 }).map((_, index) => (
|
|
447
|
+
<div
|
|
448
|
+
key={index}
|
|
449
|
+
className="flex items-center gap-3 border-b px-4 py-3 last:border-b-0"
|
|
450
|
+
>
|
|
451
|
+
<Skeleton className="size-8 rounded-md" />
|
|
452
|
+
<div className="min-w-0 flex-1">
|
|
453
|
+
<Skeleton className="h-4 w-40 max-w-full" />
|
|
454
|
+
<Skeleton className="mt-1.5 h-3 w-56 max-w-full" />
|
|
455
|
+
</div>
|
|
456
|
+
<Skeleton className="h-6 w-20 rounded-full" />
|
|
457
|
+
</div>
|
|
458
|
+
))}
|
|
382
459
|
</div>
|
|
383
460
|
)}
|
|
384
461
|
|
|
@@ -392,13 +469,13 @@ export default function ConnectionsRoute() {
|
|
|
392
469
|
<section>
|
|
393
470
|
<div className="mb-3 flex items-baseline justify-between">
|
|
394
471
|
<h2 className="text-sm font-medium text-foreground">
|
|
395
|
-
|
|
472
|
+
Not configured in apps
|
|
396
473
|
</h2>
|
|
397
474
|
<span className="text-xs text-muted-foreground">
|
|
398
475
|
{available.length}
|
|
399
476
|
</span>
|
|
400
477
|
</div>
|
|
401
|
-
<div className="
|
|
478
|
+
<div className="overflow-hidden rounded-lg bg-card">
|
|
402
479
|
{available.map((service) => (
|
|
403
480
|
<ConnectorCard
|
|
404
481
|
key={service.key}
|
|
@@ -413,12 +490,14 @@ export default function ConnectionsRoute() {
|
|
|
413
490
|
{connected.length > 0 && (
|
|
414
491
|
<section>
|
|
415
492
|
<div className="mb-3 mt-2 flex items-baseline justify-between">
|
|
416
|
-
<h2 className="text-sm font-medium text-foreground">
|
|
493
|
+
<h2 className="text-sm font-medium text-foreground">
|
|
494
|
+
Configured in apps
|
|
495
|
+
</h2>
|
|
417
496
|
<span className="text-xs text-muted-foreground">
|
|
418
497
|
{connected.length}
|
|
419
498
|
</span>
|
|
420
499
|
</div>
|
|
421
|
-
<div className="
|
|
500
|
+
<div className="overflow-hidden rounded-lg bg-card">
|
|
422
501
|
{connected.map((service) => (
|
|
423
502
|
<ConnectorCard
|
|
424
503
|
key={service.key}
|