@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
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
SettingsTabsPage,
|
|
11
11
|
useAgentSettingsTabs,
|
|
12
12
|
} from "@agent-native/core/client/settings";
|
|
13
|
+
import { IconShield } from "@tabler/icons-react";
|
|
13
14
|
import { useState } from "react";
|
|
14
15
|
import { Link } from "react-router";
|
|
15
16
|
|
|
@@ -25,6 +26,7 @@ import {
|
|
|
25
26
|
} from "../../components/ui/card";
|
|
26
27
|
import { Label } from "../../components/ui/label";
|
|
27
28
|
import { Switch } from "../../components/ui/switch";
|
|
29
|
+
import { dispatchAccessDescriptor } from "../../shared/app-roles.js";
|
|
28
30
|
|
|
29
31
|
export function meta() {
|
|
30
32
|
return [{ title: "Settings - Dispatch" }];
|
|
@@ -32,7 +34,30 @@ export function meta() {
|
|
|
32
34
|
|
|
33
35
|
export default function SettingsRoute() {
|
|
34
36
|
const t = useT();
|
|
35
|
-
const agentSettingsTabs = useAgentSettingsTabs(
|
|
37
|
+
const agentSettingsTabs = useAgentSettingsTabs({
|
|
38
|
+
usageAppId: "dispatch",
|
|
39
|
+
usageViewAllHref: "/admin/metrics",
|
|
40
|
+
organizationContent: (
|
|
41
|
+
<div className="mx-auto w-full max-w-3xl">
|
|
42
|
+
<TeamPage
|
|
43
|
+
showTitle={false}
|
|
44
|
+
appRoles={dispatchAccessDescriptor}
|
|
45
|
+
createOrgDescription="Set up a team to share dispatch destinations and approvals with your colleagues."
|
|
46
|
+
/>
|
|
47
|
+
</div>
|
|
48
|
+
),
|
|
49
|
+
});
|
|
50
|
+
const settingsTabs = [
|
|
51
|
+
...agentSettingsTabs.filter((tab) => tab.id !== "integrations"),
|
|
52
|
+
{
|
|
53
|
+
id: "admin",
|
|
54
|
+
label: t("dispatch.nav.admin", { defaultValue: "Admin" }),
|
|
55
|
+
icon: IconShield,
|
|
56
|
+
group: "Admin",
|
|
57
|
+
href: "/admin",
|
|
58
|
+
content: null,
|
|
59
|
+
},
|
|
60
|
+
];
|
|
36
61
|
const [chatFirstModeState] = useState(() => readChatFirstModeState());
|
|
37
62
|
const [chatFirstMode, setChatFirstMode] = useState(
|
|
38
63
|
() => chatFirstModeState.enabled,
|
|
@@ -68,7 +93,7 @@ export default function SettingsRoute() {
|
|
|
68
93
|
description={t("settings.description")}
|
|
69
94
|
>
|
|
70
95
|
<SettingsTabsPage
|
|
71
|
-
extraTabs={
|
|
96
|
+
extraTabs={settingsTabs}
|
|
72
97
|
general={
|
|
73
98
|
<div className="mx-auto w-full max-w-3xl space-y-6">
|
|
74
99
|
<Card>
|
|
@@ -160,14 +185,6 @@ export default function SettingsRoute() {
|
|
|
160
185
|
</Card>
|
|
161
186
|
</div>
|
|
162
187
|
}
|
|
163
|
-
team={
|
|
164
|
-
<div className="mx-auto w-full max-w-3xl">
|
|
165
|
-
<TeamPage
|
|
166
|
-
showTitle={false}
|
|
167
|
-
createOrgDescription="Set up a team to share dispatch destinations and approvals with your colleagues."
|
|
168
|
-
/>
|
|
169
|
-
</div>
|
|
170
|
-
}
|
|
171
188
|
whatsNew={
|
|
172
189
|
<div className="mx-auto w-full max-w-3xl">
|
|
173
190
|
<ChangelogSettingsCard markdown={changelog} />
|
|
@@ -520,20 +520,18 @@ function ResultCard({
|
|
|
520
520
|
selected ? "bg-accent/70" : "hover:bg-muted/50",
|
|
521
521
|
)}
|
|
522
522
|
>
|
|
523
|
-
<div className="
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
</div>
|
|
529
|
-
<Badge variant="outline" className="shrink-0">
|
|
523
|
+
<div className="truncate text-sm font-medium text-foreground">
|
|
524
|
+
{title}
|
|
525
|
+
</div>
|
|
526
|
+
<div className="mt-1 flex flex-wrap items-center gap-x-2 gap-y-1 text-[11px] text-muted-foreground">
|
|
527
|
+
<span>
|
|
530
528
|
{result.messageCount}{" "}
|
|
531
529
|
{result.messageCount === 1 ? "message" : "messages"}
|
|
532
|
-
</
|
|
533
|
-
|
|
534
|
-
<div className="mt-2 flex items-center justify-between gap-3 text-[11px] text-muted-foreground">
|
|
530
|
+
</span>
|
|
531
|
+
<span aria-hidden="true">·</span>
|
|
535
532
|
<span className="min-w-0 truncate">{result.ownerEmail}</span>
|
|
536
|
-
<span
|
|
533
|
+
<span aria-hidden="true">·</span>
|
|
534
|
+
<span>{formatRelativeDate(result.updatedAt)}</span>
|
|
537
535
|
</div>
|
|
538
536
|
</button>
|
|
539
537
|
);
|
|
@@ -1621,31 +1619,6 @@ export default function ThreadDebugRoute() {
|
|
|
1621
1619
|
</SelectContent>
|
|
1622
1620
|
</Select>
|
|
1623
1621
|
</div>
|
|
1624
|
-
<div className="mt-3 flex flex-wrap items-center gap-2 text-xs text-muted-foreground">
|
|
1625
|
-
<span className="font-medium text-foreground">
|
|
1626
|
-
{failures.length} loaded{" "}
|
|
1627
|
-
{failures.length === 1 ? "run" : "runs"}
|
|
1628
|
-
</span>
|
|
1629
|
-
<span>·</span>
|
|
1630
|
-
<span>
|
|
1631
|
-
{failuresData?.access?.scope ??
|
|
1632
|
-
t("dispatch.pages.threadDebugCurrentScope", {
|
|
1633
|
-
defaultValue: "current scope",
|
|
1634
|
-
})}
|
|
1635
|
-
</span>
|
|
1636
|
-
{failurePatterns.slice(0, 3).map((pattern) => (
|
|
1637
|
-
<Badge key={pattern.label} variant="outline">
|
|
1638
|
-
{pattern.count} {pattern.label}
|
|
1639
|
-
</Badge>
|
|
1640
|
-
))}
|
|
1641
|
-
{failuresData?.partial ? (
|
|
1642
|
-
<Badge variant="outline">
|
|
1643
|
-
{t("dispatch.pages.threadDebugPartialResults", {
|
|
1644
|
-
defaultValue: "Partial results",
|
|
1645
|
-
})}
|
|
1646
|
-
</Badge>
|
|
1647
|
-
) : null}
|
|
1648
|
-
</div>
|
|
1649
1622
|
{unavailableFailureSources.length > 0 ? (
|
|
1650
1623
|
<div className="mt-2 flex items-start gap-1.5 text-xs text-muted-foreground">
|
|
1651
1624
|
<IconAlertTriangle className="mt-0.5 size-3.5 shrink-0" />
|
|
@@ -1662,6 +1635,15 @@ export default function ThreadDebugRoute() {
|
|
|
1662
1635
|
</span>
|
|
1663
1636
|
</div>
|
|
1664
1637
|
) : null}
|
|
1638
|
+
{failuresData?.partial ? (
|
|
1639
|
+
<div className="mt-2">
|
|
1640
|
+
<Badge variant="outline">
|
|
1641
|
+
{t("dispatch.pages.threadDebugPartialResults", {
|
|
1642
|
+
defaultValue: "Partial results",
|
|
1643
|
+
})}
|
|
1644
|
+
</Badge>
|
|
1645
|
+
</div>
|
|
1646
|
+
) : null}
|
|
1665
1647
|
</section>
|
|
1666
1648
|
|
|
1667
1649
|
{failuresError ? (
|
|
@@ -829,8 +829,13 @@ export default function VaultRoute() {
|
|
|
829
829
|
|
|
830
830
|
<TabsContent value="secrets" className="mt-4 space-y-3">
|
|
831
831
|
{!accessReady ? (
|
|
832
|
-
<div className="
|
|
833
|
-
|
|
832
|
+
<div className="space-y-3">
|
|
833
|
+
{Array.from({ length: 3 }).map((_, index) => (
|
|
834
|
+
<div key={index} className="rounded-lg bg-card px-4 py-4">
|
|
835
|
+
<Skeleton className="h-4 w-1/3" />
|
|
836
|
+
<Skeleton className="mt-2 h-3 w-2/3" />
|
|
837
|
+
</div>
|
|
838
|
+
))}
|
|
834
839
|
</div>
|
|
835
840
|
) : !canManageVault ? (
|
|
836
841
|
<div className="rounded-2xl border border-dashed px-6 py-12 text-center">
|
|
@@ -67,7 +67,7 @@ import {
|
|
|
67
67
|
} from "../../components/workspace-resource-impact-preview";
|
|
68
68
|
|
|
69
69
|
export function meta() {
|
|
70
|
-
return [{ title: "
|
|
70
|
+
return [{ title: "Resources — Dispatch" }];
|
|
71
71
|
}
|
|
72
72
|
|
|
73
73
|
const KIND_CONFIG = {
|
|
@@ -600,7 +600,11 @@ function EffectiveContextPreview({ resource }: { resource: any }) {
|
|
|
600
600
|
organization/app override, then personal override.
|
|
601
601
|
</p>
|
|
602
602
|
</div>
|
|
603
|
-
|
|
603
|
+
{isLoading ? (
|
|
604
|
+
<Skeleton className="h-6 w-24 rounded-full" />
|
|
605
|
+
) : (
|
|
606
|
+
<Badge variant="outline">{availabilityLabel(availability)}</Badge>
|
|
607
|
+
)}
|
|
604
608
|
</div>
|
|
605
609
|
|
|
606
610
|
<div className="mt-3 grid gap-3 md:grid-cols-2">
|
|
@@ -881,14 +885,13 @@ function ResourceRow({ resource, grants }: { resource: any; grants: any[] }) {
|
|
|
881
885
|
);
|
|
882
886
|
}
|
|
883
887
|
|
|
884
|
-
function GlobalContextSection({
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
const presentCount = STARTER_GLOBAL_CONTEXT.length - missingPaths.length;
|
|
888
|
+
function GlobalContextSection({
|
|
889
|
+
resources,
|
|
890
|
+
isLoading,
|
|
891
|
+
}: {
|
|
892
|
+
resources: any[];
|
|
893
|
+
isLoading: boolean;
|
|
894
|
+
}) {
|
|
892
895
|
const restoreStarter = useActionMutation(
|
|
893
896
|
"restore-starter-workspace-resources",
|
|
894
897
|
{
|
|
@@ -905,6 +908,44 @@ function GlobalContextSection({ resources }: { resources: any[] }) {
|
|
|
905
908
|
},
|
|
906
909
|
);
|
|
907
910
|
|
|
911
|
+
if (isLoading && resources.length === 0) {
|
|
912
|
+
return (
|
|
913
|
+
<section className="space-y-3">
|
|
914
|
+
<div>
|
|
915
|
+
<Skeleton className="h-4 w-28" />
|
|
916
|
+
<Skeleton className="mt-2 h-3 w-full max-w-xl" />
|
|
917
|
+
<Skeleton className="mt-1.5 h-3 w-2/3 max-w-lg" />
|
|
918
|
+
</div>
|
|
919
|
+
<div className="overflow-hidden rounded-lg bg-card">
|
|
920
|
+
{Array.from({ length: STARTER_GLOBAL_CONTEXT.length }).map(
|
|
921
|
+
(_, index) => (
|
|
922
|
+
<div
|
|
923
|
+
key={index}
|
|
924
|
+
className="flex items-center gap-3 border-t px-4 py-3 first:border-t-0"
|
|
925
|
+
>
|
|
926
|
+
<Skeleton className="size-4 rounded-full" />
|
|
927
|
+
<div className="min-w-0 flex-1 space-y-1.5">
|
|
928
|
+
<Skeleton className="h-4 w-28" />
|
|
929
|
+
<Skeleton className="h-3 w-64 max-w-full" />
|
|
930
|
+
<Skeleton className="h-3 w-40 max-w-full" />
|
|
931
|
+
</div>
|
|
932
|
+
<Skeleton className="h-6 w-16 rounded-full" />
|
|
933
|
+
</div>
|
|
934
|
+
),
|
|
935
|
+
)}
|
|
936
|
+
</div>
|
|
937
|
+
</section>
|
|
938
|
+
);
|
|
939
|
+
}
|
|
940
|
+
|
|
941
|
+
const byPath = new Map(
|
|
942
|
+
resources.map((resource) => [resource.path, resource]),
|
|
943
|
+
);
|
|
944
|
+
const missingPaths = STARTER_GLOBAL_CONTEXT.filter(
|
|
945
|
+
(item) => !byPath.has(item.path),
|
|
946
|
+
).map((item) => item.path);
|
|
947
|
+
const presentCount = STARTER_GLOBAL_CONTEXT.length - missingPaths.length;
|
|
948
|
+
|
|
908
949
|
return (
|
|
909
950
|
<section className="space-y-3">
|
|
910
951
|
<div className="flex items-center justify-between gap-3">
|
|
@@ -938,35 +979,44 @@ function GlobalContextSection({ resources }: { resources: any[] }) {
|
|
|
938
979
|
</Badge>
|
|
939
980
|
</div>
|
|
940
981
|
</div>
|
|
941
|
-
<div className="
|
|
982
|
+
<div className="overflow-hidden rounded-lg bg-card">
|
|
942
983
|
{STARTER_GLOBAL_CONTEXT.map((item) => {
|
|
943
984
|
const resource = byPath.get(item.path);
|
|
944
985
|
const exists = !!resource;
|
|
945
986
|
const global = resource?.scope === "all";
|
|
946
987
|
return (
|
|
947
|
-
<div
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
</p>
|
|
988
|
+
<div
|
|
989
|
+
key={item.path}
|
|
990
|
+
className="flex flex-wrap items-center gap-3 border-t px-4 py-3 first:border-t-0"
|
|
991
|
+
>
|
|
992
|
+
{exists ? (
|
|
993
|
+
<IconCircleCheck size={16} className="shrink-0 text-primary" />
|
|
994
|
+
) : (
|
|
995
|
+
<IconAlertCircle
|
|
996
|
+
size={16}
|
|
997
|
+
className="shrink-0 text-amber-600 dark:text-amber-400"
|
|
998
|
+
/>
|
|
999
|
+
)}
|
|
1000
|
+
<div className="min-w-0 flex-1">
|
|
1001
|
+
<div className="truncate text-sm font-medium text-foreground">
|
|
1002
|
+
{item.label}
|
|
1003
|
+
</div>
|
|
1004
|
+
<div className="mt-0.5 truncate text-xs text-muted-foreground">
|
|
1005
|
+
{item.description}
|
|
1006
|
+
</div>
|
|
1007
|
+
<div className="mt-1 truncate font-mono text-[11px] text-muted-foreground/80">
|
|
1008
|
+
{item.path}
|
|
969
1009
|
</div>
|
|
1010
|
+
</div>
|
|
1011
|
+
<div className="flex items-center gap-1.5">
|
|
1012
|
+
{exists ? (
|
|
1013
|
+
<Badge variant="outline">
|
|
1014
|
+
{global ? "All apps" : "Selected"}
|
|
1015
|
+
</Badge>
|
|
1016
|
+
) : null}
|
|
1017
|
+
{resource && isAutoLoadedInstruction(resource) ? (
|
|
1018
|
+
<Badge variant="outline">Auto-loaded</Badge>
|
|
1019
|
+
) : null}
|
|
970
1020
|
{resource ? (
|
|
971
1021
|
<EditResourceDialog
|
|
972
1022
|
resource={resource}
|
|
@@ -992,24 +1042,6 @@ function GlobalContextSection({ resources }: { resources: any[] }) {
|
|
|
992
1042
|
</Button>
|
|
993
1043
|
)}
|
|
994
1044
|
</div>
|
|
995
|
-
<div className="mt-3 space-y-2">
|
|
996
|
-
<div className="truncate font-mono text-[11px] text-muted-foreground">
|
|
997
|
-
{item.path}
|
|
998
|
-
</div>
|
|
999
|
-
<div className="flex flex-wrap gap-1.5">
|
|
1000
|
-
<Badge variant={exists ? "secondary" : "outline"}>
|
|
1001
|
-
{exists ? "Present" : "Missing"}
|
|
1002
|
-
</Badge>
|
|
1003
|
-
{exists ? (
|
|
1004
|
-
<Badge variant="outline">
|
|
1005
|
-
{global ? "All apps" : "Selected"}
|
|
1006
|
-
</Badge>
|
|
1007
|
-
) : null}
|
|
1008
|
-
{resource && isAutoLoadedInstruction(resource) ? (
|
|
1009
|
-
<Badge variant="outline">Auto-loaded</Badge>
|
|
1010
|
-
) : null}
|
|
1011
|
-
</div>
|
|
1012
|
-
</div>
|
|
1013
1045
|
</div>
|
|
1014
1046
|
);
|
|
1015
1047
|
})}
|
|
@@ -1086,7 +1118,7 @@ export default function WorkspaceRoute() {
|
|
|
1086
1118
|
|
|
1087
1119
|
return (
|
|
1088
1120
|
<DispatchShell
|
|
1089
|
-
title="
|
|
1121
|
+
title="Resources"
|
|
1090
1122
|
description="Manage inherited skills, guardrail instructions, agent profiles, reference resources, and MCP servers. All-app resources are available to every app without syncing."
|
|
1091
1123
|
>
|
|
1092
1124
|
{resourcesQuery.isError || grantsQuery.isError ? (
|
|
@@ -1111,13 +1143,10 @@ export default function WorkspaceRoute() {
|
|
|
1111
1143
|
</div>
|
|
1112
1144
|
</div>
|
|
1113
1145
|
|
|
1114
|
-
{!resourcesQuery.isError ? (
|
|
1115
|
-
<GlobalContextSection resources={resources || []} />
|
|
1116
|
-
) : null}
|
|
1117
|
-
|
|
1118
1146
|
{!resourcesQuery.isError && !grantsQuery.isError ? (
|
|
1119
1147
|
<Tabs defaultValue="skills">
|
|
1120
1148
|
<TabsList>
|
|
1149
|
+
<TabsTrigger value="context">Global context</TabsTrigger>
|
|
1121
1150
|
<TabsTrigger value="skills">
|
|
1122
1151
|
Skills {skills.length > 0 && `(${skills.length})`}
|
|
1123
1152
|
</TabsTrigger>
|
|
@@ -1136,6 +1165,13 @@ export default function WorkspaceRoute() {
|
|
|
1136
1165
|
</TabsTrigger>
|
|
1137
1166
|
</TabsList>
|
|
1138
1167
|
|
|
1168
|
+
<TabsContent value="context" className="mt-4">
|
|
1169
|
+
<GlobalContextSection
|
|
1170
|
+
resources={resources || []}
|
|
1171
|
+
isLoading={isLoading}
|
|
1172
|
+
/>
|
|
1173
|
+
</TabsContent>
|
|
1174
|
+
|
|
1139
1175
|
<TabsContent value="skills" className="mt-4">
|
|
1140
1176
|
<ResourceList
|
|
1141
1177
|
items={skills}
|
package/src/server/index.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { defineAppRoles } from "@agent-native/core/org";
|
|
1
2
|
import {
|
|
2
3
|
registerPackageActions,
|
|
3
4
|
type NitroPluginDef,
|
|
@@ -5,6 +6,9 @@ import {
|
|
|
5
6
|
|
|
6
7
|
import { dispatchActions } from "../actions/index.js";
|
|
7
8
|
import type { DispatchConfig } from "../config.js";
|
|
9
|
+
import { dispatchAccessDescriptor } from "../shared/app-roles.js";
|
|
10
|
+
|
|
11
|
+
defineAppRoles(dispatchAccessDescriptor);
|
|
8
12
|
|
|
9
13
|
/**
|
|
10
14
|
* Register dispatch's package-contributed actions on import. The framework's
|
|
@@ -3,6 +3,7 @@ import { afterEach, describe, expect, it, vi } from "vitest";
|
|
|
3
3
|
|
|
4
4
|
import {
|
|
5
5
|
generateWorkspaceAppDescription,
|
|
6
|
+
getAppCreationSettings,
|
|
6
7
|
listAvailableWorkspaceTemplates,
|
|
7
8
|
listWorkspaceApps,
|
|
8
9
|
setAppCreationSettings,
|
|
@@ -46,7 +47,6 @@ const mocks = vi.hoisted(() => {
|
|
|
46
47
|
})),
|
|
47
48
|
ensureBuilderProject: vi.fn(),
|
|
48
49
|
runBuilderAgent: vi.fn(),
|
|
49
|
-
resolveBuilderBranchProjectId: vi.fn(async () => ""),
|
|
50
50
|
getBuilderBranchProjectId: vi.fn(() => ""),
|
|
51
51
|
writeAppSecret: vi.fn(async () => "secret-id"),
|
|
52
52
|
deleteAppSecret: vi.fn(async () => true),
|
|
@@ -86,8 +86,6 @@ vi.mock("@agent-native/core/server", async (importOriginal) => {
|
|
|
86
86
|
ensureBuilderProject: (...args: any[]) =>
|
|
87
87
|
mocks.ensureBuilderProject(...args),
|
|
88
88
|
runBuilderAgent: (...args: any[]) => mocks.runBuilderAgent(...args),
|
|
89
|
-
resolveBuilderBranchProjectId: (...args: any[]) =>
|
|
90
|
-
mocks.resolveBuilderBranchProjectId(...args),
|
|
91
89
|
getBuilderBranchProjectId: (...args: any[]) =>
|
|
92
90
|
mocks.getBuilderBranchProjectId(...args),
|
|
93
91
|
};
|
|
@@ -121,12 +119,50 @@ afterEach(() => {
|
|
|
121
119
|
source: null,
|
|
122
120
|
lookupFailed: false,
|
|
123
121
|
});
|
|
124
|
-
mocks.resolveBuilderBranchProjectId.mockResolvedValue("");
|
|
125
122
|
mocks.getBuilderBranchProjectId.mockReturnValue("");
|
|
126
123
|
mocks.ensureBuilderProject.mockReset();
|
|
127
124
|
globalThis.fetch = originalFetch;
|
|
128
125
|
});
|
|
129
126
|
|
|
127
|
+
describe("getAppCreationSettings", () => {
|
|
128
|
+
it("treats the Dispatch project as authoritative over the environment", async () => {
|
|
129
|
+
mocks.settings.set("dispatch-app-creation-settings:org:builder_io", {
|
|
130
|
+
builderProjectId: "dispatch-project",
|
|
131
|
+
});
|
|
132
|
+
vi.stubEnv("DISPATCH_BUILDER_PROJECT_ID", "stale-env-project");
|
|
133
|
+
|
|
134
|
+
const result = await runWithRequestContext(
|
|
135
|
+
{ userEmail: "dev@example.test", orgId: "builder_io" },
|
|
136
|
+
() => getAppCreationSettings(),
|
|
137
|
+
);
|
|
138
|
+
|
|
139
|
+
expect(result).toMatchObject({
|
|
140
|
+
builderProjectId: "dispatch-project",
|
|
141
|
+
builderProjectIdSource: "dispatch",
|
|
142
|
+
envBuilderProjectId: "stale-env-project",
|
|
143
|
+
});
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
it("treats an explicit Dispatch null as disabled over the environment", async () => {
|
|
147
|
+
mocks.settings.set("dispatch-app-creation-settings:org:builder_io", {
|
|
148
|
+
builderProjectId: null,
|
|
149
|
+
});
|
|
150
|
+
vi.stubEnv("DISPATCH_BUILDER_PROJECT_ID", "stale-env-project");
|
|
151
|
+
|
|
152
|
+
const result = await runWithRequestContext(
|
|
153
|
+
{ userEmail: "dev@example.test", orgId: "builder_io" },
|
|
154
|
+
() => getAppCreationSettings(),
|
|
155
|
+
);
|
|
156
|
+
|
|
157
|
+
expect(result).toMatchObject({
|
|
158
|
+
builderProjectId: null,
|
|
159
|
+
builderProjectIdSource: "dispatch",
|
|
160
|
+
envBuilderProjectId: "stale-env-project",
|
|
161
|
+
builderBranchingEnabled: false,
|
|
162
|
+
});
|
|
163
|
+
});
|
|
164
|
+
});
|
|
165
|
+
|
|
130
166
|
describe("listWorkspaceApps", () => {
|
|
131
167
|
function stubNoPendingContext() {
|
|
132
168
|
for (const key of [
|
|
@@ -399,9 +435,11 @@ describe("listWorkspaceApps", () => {
|
|
|
399
435
|
name: "Todo Board",
|
|
400
436
|
}),
|
|
401
437
|
),
|
|
402
|
-
).rejects.
|
|
403
|
-
|
|
404
|
-
|
|
438
|
+
).rejects.toMatchObject({
|
|
439
|
+
message:
|
|
440
|
+
"Only organization owners and admins can update app creation settings.",
|
|
441
|
+
statusCode: 403,
|
|
442
|
+
});
|
|
405
443
|
expect(
|
|
406
444
|
mocks.settings.get("workspace-app-metadata:org:org-123"),
|
|
407
445
|
).toBeUndefined();
|
|
@@ -603,12 +641,11 @@ describe("startWorkspaceAppCreation", () => {
|
|
|
603
641
|
expect(mocks.runBuilderAgent).toHaveBeenCalledWith(
|
|
604
642
|
expect.objectContaining({ projectId: "project-provisioned" }),
|
|
605
643
|
);
|
|
606
|
-
expect(mocks.
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
);
|
|
644
|
+
expect(mocks.settings.get(settingsKey)).toMatchObject({
|
|
645
|
+
builderProjectId: "project-provisioned",
|
|
646
|
+
});
|
|
647
|
+
expect(mocks.writeAppSecret).not.toHaveBeenCalled();
|
|
648
|
+
expect(mocks.deleteAppSecret).not.toHaveBeenCalled();
|
|
612
649
|
});
|
|
613
650
|
|
|
614
651
|
it("does not let an organization member persist an auto-provisioned project", async () => {
|
|
@@ -653,58 +690,68 @@ describe("setAppCreationSettings", () => {
|
|
|
653
690
|
);
|
|
654
691
|
}
|
|
655
692
|
|
|
656
|
-
it("stores the project id
|
|
693
|
+
it("stores the project id in the org-scoped Dispatch settings row", async () => {
|
|
657
694
|
await save(projectId);
|
|
658
695
|
|
|
659
|
-
expect(
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
}),
|
|
696
|
+
expect(
|
|
697
|
+
mocks.settings.get("dispatch-app-creation-settings:org:builder_io"),
|
|
698
|
+
).toEqual({ builderProjectId: projectId });
|
|
699
|
+
expect(mocks.putSetting).toHaveBeenCalledWith(
|
|
700
|
+
"dispatch-app-creation-settings:org:builder_io",
|
|
701
|
+
{ builderProjectId: projectId },
|
|
666
702
|
);
|
|
667
703
|
expect(mocks.deleteAppSecret).not.toHaveBeenCalled();
|
|
704
|
+
expect(mocks.writeAppSecret).not.toHaveBeenCalled();
|
|
668
705
|
});
|
|
669
706
|
|
|
670
|
-
it("scopes the
|
|
707
|
+
it("scopes the settings row to one organization rather than every tenant", async () => {
|
|
671
708
|
await save(projectId);
|
|
672
709
|
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
expect(
|
|
677
|
-
expect(
|
|
710
|
+
expect(mocks.putSetting.mock.calls.at(-1)?.[0]).toBe(
|
|
711
|
+
"dispatch-app-creation-settings:org:builder_io",
|
|
712
|
+
);
|
|
713
|
+
expect(mocks.putSetting.mock.calls.at(-1)?.[0]).not.toContain(":user:");
|
|
714
|
+
expect(mocks.writeAppSecret).not.toHaveBeenCalled();
|
|
678
715
|
});
|
|
679
716
|
|
|
680
|
-
it("
|
|
717
|
+
it("uses a user-scoped settings row when there is no active org", async () => {
|
|
681
718
|
await save(projectId, { userEmail: "dev@example.test" });
|
|
682
719
|
|
|
683
|
-
expect(mocks.
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
);
|
|
720
|
+
expect(mocks.settings.get(settingsKey)).toEqual({
|
|
721
|
+
builderProjectId: projectId,
|
|
722
|
+
});
|
|
723
|
+
expect(mocks.putSetting).toHaveBeenCalledWith(settingsKey, {
|
|
724
|
+
builderProjectId: projectId,
|
|
725
|
+
});
|
|
726
|
+
expect(mocks.writeAppSecret).not.toHaveBeenCalled();
|
|
689
727
|
});
|
|
690
728
|
|
|
691
|
-
it("
|
|
729
|
+
it("persists an explicit null when the project id is cleared", async () => {
|
|
692
730
|
await save(null);
|
|
693
731
|
|
|
694
|
-
expect(
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
732
|
+
expect(
|
|
733
|
+
mocks.settings.get("dispatch-app-creation-settings:org:builder_io"),
|
|
734
|
+
).toEqual({ builderProjectId: null });
|
|
735
|
+
expect(mocks.putSetting).toHaveBeenCalledWith(
|
|
736
|
+
"dispatch-app-creation-settings:org:builder_io",
|
|
737
|
+
{ builderProjectId: null },
|
|
738
|
+
);
|
|
739
|
+
expect(mocks.deleteAppSecret).not.toHaveBeenCalled();
|
|
699
740
|
expect(mocks.writeAppSecret).not.toHaveBeenCalled();
|
|
700
741
|
});
|
|
701
742
|
|
|
702
|
-
it("
|
|
743
|
+
it("never consults the project secret store when saving settings", async () => {
|
|
703
744
|
mocks.writeAppSecret.mockRejectedValueOnce(
|
|
704
745
|
new Error("credential store down"),
|
|
705
746
|
);
|
|
706
747
|
|
|
707
|
-
await expect(save(projectId)).
|
|
708
|
-
|
|
748
|
+
await expect(save(projectId)).resolves.toMatchObject({
|
|
749
|
+
builderProjectId: projectId,
|
|
750
|
+
});
|
|
751
|
+
expect(
|
|
752
|
+
mocks.settings.get("dispatch-app-creation-settings:org:builder_io"),
|
|
753
|
+
).toEqual({ builderProjectId: projectId });
|
|
754
|
+
expect(mocks.writeAppSecret).not.toHaveBeenCalled();
|
|
755
|
+
expect(mocks.deleteAppSecret).not.toHaveBeenCalled();
|
|
709
756
|
});
|
|
710
757
|
});
|