@agent-native/dispatch 0.5.1 → 0.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/dist/components/app-keys-popover.d.ts.map +1 -1
  2. package/dist/components/app-keys-popover.js +2 -1
  3. package/dist/components/app-keys-popover.js.map +1 -1
  4. package/dist/components/create-app-popover.js +1 -1
  5. package/dist/components/create-app-popover.js.map +1 -1
  6. package/dist/components/layout/Layout.js +3 -3
  7. package/dist/components/layout/Layout.js.map +1 -1
  8. package/dist/routes/index.d.ts.map +1 -1
  9. package/dist/routes/index.js +5 -0
  10. package/dist/routes/index.js.map +1 -1
  11. package/dist/routes/pages/$appId.d.ts +8 -0
  12. package/dist/routes/pages/$appId.d.ts.map +1 -0
  13. package/dist/routes/pages/$appId.js +91 -0
  14. package/dist/routes/pages/$appId.js.map +1 -0
  15. package/dist/routes/pages/approval.d.ts.map +1 -1
  16. package/dist/routes/pages/approval.js +2 -1
  17. package/dist/routes/pages/approval.js.map +1 -1
  18. package/dist/routes/pages/apps.$appId.d.ts.map +1 -1
  19. package/dist/routes/pages/apps.$appId.js +2 -1
  20. package/dist/routes/pages/apps.$appId.js.map +1 -1
  21. package/dist/routes/pages/integrations.d.ts +1 -1
  22. package/dist/routes/pages/integrations.d.ts.map +1 -1
  23. package/dist/routes/pages/integrations.js +131 -30
  24. package/dist/routes/pages/integrations.js.map +1 -1
  25. package/dist/routes/pages/overview.d.ts.map +1 -1
  26. package/dist/routes/pages/overview.js +10 -1
  27. package/dist/routes/pages/overview.js.map +1 -1
  28. package/dist/routes/pages/vault.d.ts.map +1 -1
  29. package/dist/routes/pages/vault.js +4 -3
  30. package/dist/routes/pages/vault.js.map +1 -1
  31. package/dist/routes/pages/workspace.d.ts.map +1 -1
  32. package/dist/routes/pages/workspace.js +5 -3
  33. package/dist/routes/pages/workspace.js.map +1 -1
  34. package/dist/server/plugins/integrations.js +1 -1
  35. package/dist/server/plugins/integrations.js.map +1 -1
  36. package/package.json +2 -2
  37. package/src/components/app-keys-popover.tsx +15 -1
  38. package/src/components/create-app-popover.tsx +1 -1
  39. package/src/components/layout/Layout.tsx +3 -3
  40. package/src/routes/index.ts +5 -0
  41. package/src/routes/pages/$appId.tsx +178 -0
  42. package/src/routes/pages/approval.tsx +33 -3
  43. package/src/routes/pages/apps.$appId.tsx +6 -1
  44. package/src/routes/pages/integrations.tsx +348 -215
  45. package/src/routes/pages/overview.tsx +58 -26
  46. package/src/routes/pages/vault.tsx +25 -12
  47. package/src/routes/pages/workspace.tsx +21 -3
  48. package/src/server/plugins/integrations.ts +1 -1
@@ -131,6 +131,60 @@ function AppCardSkeleton() {
131
131
  );
132
132
  }
133
133
 
134
+ interface RecentAuditEvent {
135
+ id: string;
136
+ summary: string;
137
+ actor: string;
138
+ createdAt: string;
139
+ }
140
+
141
+ function RecentActivityList({
142
+ isLoading,
143
+ events,
144
+ }: {
145
+ isLoading: boolean;
146
+ events: RecentAuditEvent[];
147
+ }) {
148
+ if (isLoading && events.length === 0) {
149
+ return (
150
+ <div className="mt-4 space-y-3">
151
+ {Array.from({ length: 3 }).map((_, index) => (
152
+ <div
153
+ key={index}
154
+ className="rounded-xl border bg-muted/30 px-4 py-3 space-y-2"
155
+ >
156
+ <Skeleton className="h-4 w-3/5" />
157
+ <Skeleton className="h-3 w-2/5" />
158
+ </div>
159
+ ))}
160
+ </div>
161
+ );
162
+ }
163
+ if (events.length === 0) {
164
+ return (
165
+ <div className="mt-4 space-y-3">
166
+ <div className="rounded-xl border border-dashed px-4 py-6 text-sm text-muted-foreground">
167
+ No activity yet.
168
+ </div>
169
+ </div>
170
+ );
171
+ }
172
+ return (
173
+ <div className="mt-4 space-y-3">
174
+ {events.map((event) => (
175
+ <div key={event.id} className="rounded-xl border bg-muted/30 px-4 py-3">
176
+ <div className="text-sm font-medium text-foreground">
177
+ {event.summary}
178
+ </div>
179
+ <div className="mt-1 text-xs text-muted-foreground">
180
+ {event.actor} · {new Date(event.createdAt).toLocaleString()}
181
+ </div>
182
+ </div>
183
+ ))}
184
+ </div>
185
+ );
186
+ }
187
+
134
188
  function WorkspaceAppsSection({
135
189
  apps,
136
190
  isLoading,
@@ -625,33 +679,11 @@ export default function OverviewRoute() {
625
679
  <h2 className="text-lg font-semibold text-foreground">
626
680
  Recent activity
627
681
  </h2>
628
- {isLoading && (
629
- <span className="text-xs text-muted-foreground">
630
- Loading...
631
- </span>
632
- )}
633
- </div>
634
- <div className="mt-4 space-y-3">
635
- {(data?.recentAudit || []).map((event) => (
636
- <div
637
- key={event.id}
638
- className="rounded-xl border bg-muted/30 px-4 py-3"
639
- >
640
- <div className="text-sm font-medium text-foreground">
641
- {event.summary}
642
- </div>
643
- <div className="mt-1 text-xs text-muted-foreground">
644
- {event.actor} ·{" "}
645
- {new Date(event.createdAt).toLocaleString()}
646
- </div>
647
- </div>
648
- ))}
649
- {!isLoading && (data?.recentAudit?.length || 0) === 0 && (
650
- <div className="rounded-xl border border-dashed px-4 py-6 text-sm text-muted-foreground">
651
- No activity yet.
652
- </div>
653
- )}
654
682
  </div>
683
+ <RecentActivityList
684
+ isLoading={isLoading}
685
+ events={data?.recentAudit ?? []}
686
+ />
655
687
  </section>
656
688
 
657
689
  <section className="rounded-2xl border bg-card p-5">
@@ -46,6 +46,7 @@ import {
46
46
  } from "@/components/ui/select";
47
47
  import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
48
48
  import { Textarea } from "@/components/ui/textarea";
49
+ import { Skeleton } from "@/components/ui/skeleton";
49
50
 
50
51
  const PROVIDERS = [
51
52
  "google",
@@ -549,22 +550,34 @@ export default function VaultRoute() {
549
550
  <div className="flex items-center justify-between">
550
551
  <div className="flex items-center gap-2 text-sm text-muted-foreground">
551
552
  <IconKey size={16} />
552
- <span>
553
- {secretsLoading
554
- ? "Loading..."
555
- : `${secrets?.length || 0} secret${(secrets?.length || 0) !== 1 ? "s" : ""}`}
556
- </span>
553
+ {secretsLoading ? (
554
+ <Skeleton className="h-4 w-20" />
555
+ ) : (
556
+ <span>
557
+ {`${secrets?.length || 0} secret${(secrets?.length || 0) !== 1 ? "s" : ""}`}
558
+ </span>
559
+ )}
557
560
  </div>
558
561
  <AddSecretDialog />
559
562
  </div>
560
563
 
561
- {(secrets || []).map((secret: any) => (
562
- <SecretRow
563
- key={secret.id}
564
- secret={secret}
565
- grants={grantsBySecret[secret.id] || []}
566
- />
567
- ))}
564
+ {secretsLoading && (secrets ?? []).length === 0
565
+ ? Array.from({ length: 3 }).map((_, index) => (
566
+ <div
567
+ key={index}
568
+ className="rounded-2xl border bg-card px-5 py-4 space-y-2"
569
+ >
570
+ <Skeleton className="h-4 w-1/3" />
571
+ <Skeleton className="h-3 w-2/3" />
572
+ </div>
573
+ ))
574
+ : (secrets || []).map((secret: any) => (
575
+ <SecretRow
576
+ key={secret.id}
577
+ secret={secret}
578
+ grants={grantsBySecret[secret.id] || []}
579
+ />
580
+ ))}
568
581
 
569
582
  {!secretsLoading && (secrets?.length || 0) === 0 && (
570
583
  <div className="rounded-2xl border border-dashed px-6 py-12 text-center">
@@ -47,6 +47,7 @@ import {
47
47
  } from "@/components/ui/select";
48
48
  import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
49
49
  import { Textarea } from "@/components/ui/textarea";
50
+ import { Skeleton } from "@/components/ui/skeleton";
50
51
 
51
52
  export function meta() {
52
53
  return [{ title: "Workspace Resources — Dispatch" }];
@@ -528,6 +529,21 @@ export default function WorkspaceRoute() {
528
529
  items: any[];
529
530
  emptyText: string;
530
531
  }) {
532
+ if (isLoading && (resources ?? []).length === 0) {
533
+ return (
534
+ <div className="space-y-3">
535
+ {Array.from({ length: 3 }).map((_, index) => (
536
+ <div
537
+ key={index}
538
+ className="rounded-2xl border bg-card px-5 py-4 space-y-2"
539
+ >
540
+ <Skeleton className="h-4 w-1/3" />
541
+ <Skeleton className="h-3 w-2/3" />
542
+ </div>
543
+ ))}
544
+ </div>
545
+ );
546
+ }
531
547
  if (items.length === 0) {
532
548
  return (
533
549
  <div className="rounded-2xl border border-dashed px-6 py-12 text-center text-sm text-muted-foreground">
@@ -555,9 +571,11 @@ export default function WorkspaceRoute() {
555
571
  >
556
572
  <div className="flex items-center justify-between">
557
573
  <div className="text-sm text-muted-foreground">
558
- {isLoading
559
- ? "Loading..."
560
- : `${resources?.length || 0} resource${(resources?.length || 0) !== 1 ? "s" : ""}`}
574
+ {isLoading ? (
575
+ <Skeleton className="h-4 w-24" />
576
+ ) : (
577
+ `${resources?.length || 0} resource${(resources?.length || 0) !== 1 ? "s" : ""}`
578
+ )}
561
579
  </div>
562
580
  <div className="flex gap-2">
563
581
  <Button
@@ -23,7 +23,7 @@ When a user asks for something:
23
23
  - Exception: if the downstream agent reports a missing model/provider credential, do not name exact env vars, Vault keys, tokens, or secrets. Say the target app needs an LLM connection and recommend connecting Builder/managed LLM for that app; keep bring-your-own provider keys as a secondary option only if the user asks.
24
24
  - If the user asks to create, build, make, scaffold, or generate an "agent" from Dispatch chat or by tagging @agent-native in Slack, email, or Telegram, first classify the ask. If it is a simple Dispatch-native behavior like a reminder, digest, monitor, routing rule, saved instruction, or recurring workflow, create or update the recurring job/resource/destination in Dispatch. If it is a robust unique product or teammate that needs its own UI, data model, actions, integrations, or domain workflow, treat it as a new workspace app and call start-workspace-app-creation.
25
25
  - If a new-app prompt asks for access to Mail, Calendar, Analytics, or similar first-party app data/agents, keep using the existing hosted/connected app and A2A path. Do not ask Builder to scaffold those apps as children of the new app unless the user explicitly asks for a customized fork/copy.
26
- - If the user explicitly asks for a new app or workspace app, call start-workspace-app-creation with their prompt. Do not satisfy a new-app request by adding a route, page, component, or file inside apps/starter or another existing app unless the user explicitly asks to modify that existing app. If the request is too vague to classify, ask one concise follow-up. If the action returns mode "builder", reply with the Builder branch URL; Builder is responsible for creating the separate workspace app under apps/<app-id>, mounting it at /<app-id>, ensuring apps/<app-id>/package.json exists so Dispatch discovers it, using relative /<app-id> links instead of hardcoded localhost/dev ports, and preserving APP_BASE_PATH/VITE_APP_BASE_PATH via appBasePath() in the React Router client entry. There is no separate workspace app registry to edit. If it returns mode "local-agent", tell the user it is ready for the local code agent and include the returned app path/prompt summary. If it returns mode "coming-soon" or "builder-unavailable", explain the missing Builder setup and ask them to connect/configure Builder.
26
+ - If the user explicitly asks for a new app or workspace app, call start-workspace-app-creation with their prompt. Do not satisfy a new-app request by adding a route, page, component, or file inside apps/starter or another existing app unless the user explicitly asks to modify that existing app. If the request is too vague to classify, ask one concise follow-up. If the action returns mode "builder", reply with the Builder branch URL; Builder is responsible for creating the separate workspace app under apps/<app-id>, mounting it at /<app-id>, ensuring apps/<app-id>/package.json exists so Dispatch discovers it, using relative /<app-id> links instead of hardcoded localhost/dev ports, and preserving APP_BASE_PATH/VITE_APP_BASE_PATH via appBasePath() in the React Router client entry. The new app lives at the workspace root /<app-id>, NOT under /dispatch/<app-id>, /apps/<app-id>, or any other Dispatch tab — when telling the user where to find it, link to /<app-id> only. There is no separate workspace app registry to edit. If it returns mode "local-agent", tell the user it is ready for the local code agent and include the returned app path/prompt summary. If it returns mode "coming-soon" or "builder-unavailable", explain the missing Builder setup and ask them to connect/configure Builder.
27
27
  - For digests, reminders, or saved behavior, prefer recurring jobs, resources, or destinations over chat replies.
28
28
  - Keep responses concise and operational — messaging platforms have character limits.
29
29
  - Use markdown sparingly (bold and lists are fine, avoid complex formatting).