@agent-native/dispatch 0.20.2 → 0.20.4

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.
@@ -1 +1 @@
1
- {"version":3,"file":"automation-run-history-dialog.d.ts","sourceRoot":"","sources":["../../src/components/automation-run-history-dialog.tsx"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,oBAAoB,CAAC;AAqBjE,UAAU,+BAA+B;IACvC,UAAU,EAAE,sBAAsB,GAAG,IAAI,CAAC;IAC1C,IAAI,EAAE,OAAO,CAAC;IACd,YAAY,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;CACvC;AAgCD,wBAAgB,0BAA0B,CAAC,EACzC,UAAU,EACV,IAAI,EACJ,YAAY,GACb,EAAE,+BAA+B,mDAuKjC"}
1
+ {"version":3,"file":"automation-run-history-dialog.d.ts","sourceRoot":"","sources":["../../src/components/automation-run-history-dialog.tsx"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,oBAAoB,CAAC;AAqBjE,UAAU,+BAA+B;IACvC,UAAU,EAAE,sBAAsB,GAAG,IAAI,CAAC;IAC1C,IAAI,EAAE,OAAO,CAAC;IACd,YAAY,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;CACvC;AAgCD,wBAAgB,0BAA0B,CAAC,EACzC,UAAU,EACV,IAAI,EACJ,YAAY,GACb,EAAE,+BAA+B,mDAwKjC"}
@@ -42,6 +42,7 @@ export function AutomationRunHistoryDialog({ automation, open, onOpenChange, })
42
42
  const runsQuery = useActionQuery("list-automation-runs", {
43
43
  name: automation?.name ?? "",
44
44
  scope,
45
+ appId: automation?.appId ?? "dispatch",
45
46
  }, {
46
47
  enabled: open && Boolean(automation),
47
48
  staleTime: 5_000,
@@ -1 +1 @@
1
- {"version":3,"file":"automation-run-history-dialog.js","sourceRoot":"","sources":["../../src/components/automation-run-history-dialog.tsx"],"names":[],"mappings":"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","sourcesContent":["import { useActionQuery } from \"@agent-native/core/client/hooks\";\nimport {\n IconAlertTriangle,\n IconClock,\n IconExternalLink,\n IconLoader2,\n} from \"@tabler/icons-react\";\nimport { Link } from \"react-router\";\n\nimport {\n automationScopeLabel,\n automationTarget,\n} from \"../lib/automation-display\";\nimport type { DispatchAutomationItem } from \"../lib/automations\";\nimport { ActionQueryError } from \"./action-query-error\";\nimport { Badge } from \"./ui/badge\";\nimport {\n Dialog,\n DialogContent,\n DialogDescription,\n DialogHeader,\n DialogTitle,\n} from \"./ui/dialog\";\n\ninterface AutomationRun {\n id: string;\n runId: string | null;\n threadId: string | null;\n status: \"running\" | \"success\" | \"error\" | \"interrupted\";\n startedAt: number;\n finishedAt: number | null;\n error: string | null;\n}\n\ninterface AutomationRunHistoryDialogProps {\n automation: DispatchAutomationItem | null;\n open: boolean;\n onOpenChange: (open: boolean) => void;\n}\n\nfunction runStatusVariant(\n status: AutomationRun[\"status\"],\n): \"default\" | \"destructive\" | \"outline\" {\n if (status === \"error\") return \"destructive\";\n if (status === \"success\") return \"default\";\n return \"outline\";\n}\n\nfunction formatTimestamp(value: number): string {\n const date = new Date(value);\n return Number.isNaN(date.getTime()) ? \"Unknown time\" : date.toLocaleString();\n}\n\nfunction formatDuration(run: AutomationRun): string | null {\n if (!run.finishedAt) return null;\n const seconds = Math.max(\n 0,\n Math.round((run.finishedAt - run.startedAt) / 1000),\n );\n return `${seconds}s`;\n}\n\nfunction runDebugPath(run: AutomationRun): string | null {\n const params = new URLSearchParams();\n if (run.runId) params.set(\"runId\", run.runId);\n else if (run.threadId) params.set(\"threadId\", run.threadId);\n else return null;\n return `/admin/thread-debug?${params.toString()}`;\n}\n\nexport function AutomationRunHistoryDialog({\n automation,\n open,\n onOpenChange,\n}: AutomationRunHistoryDialogProps) {\n const scope =\n automation?.scope === \"organization\" ||\n automation?.owner.startsWith(\"__organization__:\") ||\n automation?.owner === \"__shared__\"\n ? \"organization\"\n : \"personal\";\n const runsQuery = useActionQuery<AutomationRun[]>(\n \"list-automation-runs\",\n {\n name: automation?.name ?? \"\",\n scope,\n },\n {\n enabled: open && Boolean(automation),\n staleTime: 5_000,\n },\n );\n const runs = runsQuery.data ?? [];\n\n return (\n <Dialog open={open} onOpenChange={onOpenChange}>\n <DialogContent className=\"max-h-[85vh] max-w-2xl overflow-y-auto\">\n <DialogHeader>\n <DialogTitle>{automation?.name ?? \"Automation details\"}</DialogTitle>\n <DialogDescription>\n {automation\n ? `${automationTarget(automation)} · ${automationScopeLabel(automation)}`\n : \"Execution history\"}\n </DialogDescription>\n </DialogHeader>\n\n {automation ? (\n <div className=\"space-y-4\">\n <div className=\"grid grid-cols-2 gap-x-4 gap-y-3 rounded-lg border bg-muted/20 p-3 text-sm\">\n <div>\n <div className=\"text-[11px] uppercase tracking-wide text-muted-foreground\">\n Status\n </div>\n <div className=\"mt-1 font-medium\">\n {automation.lastStatus ??\n (automation.enabled ? \"ready\" : \"paused\")}\n </div>\n </div>\n <div>\n <div className=\"text-[11px] uppercase tracking-wide text-muted-foreground\">\n Last check\n </div>\n <div className=\"mt-1 font-medium\">\n {automation.lastCheck\n ? formatTimestamp(new Date(automation.lastCheck).getTime())\n : \"Not recorded\"}\n </div>\n </div>\n <div>\n <div className=\"text-[11px] uppercase tracking-wide text-muted-foreground\">\n Created by\n </div>\n <div className=\"mt-1 break-words font-medium\">\n {automation.createdBy ?? \"Unknown\"}\n </div>\n </div>\n <div>\n <div className=\"text-[11px] uppercase tracking-wide text-muted-foreground\">\n Timezone\n </div>\n <div className=\"mt-1 font-medium\">\n {automation.timezone ?? \"Account default\"}\n </div>\n </div>\n </div>\n\n {automation.lastError ? (\n <div className=\"flex items-start gap-2 rounded-lg border border-destructive/30 bg-destructive/5 p-3\">\n <IconAlertTriangle className=\"mt-0.5 size-4 shrink-0 text-destructive\" />\n <div className=\"min-w-0\">\n <p className=\"text-sm font-medium text-destructive\">\n Latest scheduler result\n </p>\n <p className=\"mt-1 break-words text-sm text-muted-foreground\">\n {automation.lastError}\n </p>\n </div>\n </div>\n ) : null}\n\n <div>\n <div className=\"flex items-center justify-between gap-3\">\n <div>\n <h3 className=\"text-sm font-semibold text-foreground\">\n Past runs\n </h3>\n <p className=\"mt-1 text-xs text-muted-foreground\">\n Only executions that actually started appear here. Blocked\n or skipped scheduler checks are shown above, not as fake\n runs.\n </p>\n </div>\n {runs.length > 0 ? (\n <Badge variant=\"outline\">{runs.length} shown</Badge>\n ) : null}\n </div>\n\n <div className=\"mt-3\">\n {runsQuery.isLoading ? (\n <div className=\"flex items-center gap-2 rounded-lg border p-4 text-sm text-muted-foreground\">\n <IconLoader2 className=\"size-4 animate-spin\" />\n Loading run history...\n </div>\n ) : runsQuery.isError ? (\n <ActionQueryError\n error={runsQuery.error}\n onRetry={() => void runsQuery.refetch()}\n />\n ) : runs.length === 0 ? (\n <div className=\"rounded-lg border border-dashed p-4 text-sm text-muted-foreground\">\n This automation has not recorded an execution yet. If it is\n enabled but shows no runs, inspect the latest scheduler\n result and last check above.\n </div>\n ) : (\n <ul className=\"divide-y rounded-lg border\">\n {runs.map((run) => {\n const debugPath = runDebugPath(run);\n const duration = formatDuration(run);\n return (\n <li key={run.id} className=\"space-y-2 p-3\">\n <div className=\"flex flex-wrap items-center gap-2 text-sm\">\n <Badge variant={runStatusVariant(run.status)}>\n {run.status}\n </Badge>\n <span className=\"text-muted-foreground\">\n {formatTimestamp(run.startedAt)}\n </span>\n {duration ? (\n <span className=\"inline-flex items-center gap-1 text-xs text-muted-foreground\">\n <IconClock className=\"size-3.5\" />\n {duration}\n </span>\n ) : null}\n {debugPath ? (\n <Link\n to={debugPath}\n className=\"ml-auto inline-flex items-center gap-1 text-xs font-medium text-foreground underline-offset-4 hover:underline\"\n >\n <IconExternalLink className=\"size-3.5\" />\n Open debug\n </Link>\n ) : null}\n </div>\n {run.error ? (\n <p className=\"break-words text-sm text-destructive\">\n {run.error}\n </p>\n ) : null}\n </li>\n );\n })}\n </ul>\n )}\n </div>\n </div>\n </div>\n ) : null}\n </DialogContent>\n </Dialog>\n );\n}\n"]}
1
+ {"version":3,"file":"automation-run-history-dialog.js","sourceRoot":"","sources":["../../src/components/automation-run-history-dialog.tsx"],"names":[],"mappings":"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","sourcesContent":["import { useActionQuery } from \"@agent-native/core/client/hooks\";\nimport {\n IconAlertTriangle,\n IconClock,\n IconExternalLink,\n IconLoader2,\n} from \"@tabler/icons-react\";\nimport { Link } from \"react-router\";\n\nimport {\n automationScopeLabel,\n automationTarget,\n} from \"../lib/automation-display\";\nimport type { DispatchAutomationItem } from \"../lib/automations\";\nimport { ActionQueryError } from \"./action-query-error\";\nimport { Badge } from \"./ui/badge\";\nimport {\n Dialog,\n DialogContent,\n DialogDescription,\n DialogHeader,\n DialogTitle,\n} from \"./ui/dialog\";\n\ninterface AutomationRun {\n id: string;\n runId: string | null;\n threadId: string | null;\n status: \"running\" | \"success\" | \"error\" | \"interrupted\";\n startedAt: number;\n finishedAt: number | null;\n error: string | null;\n}\n\ninterface AutomationRunHistoryDialogProps {\n automation: DispatchAutomationItem | null;\n open: boolean;\n onOpenChange: (open: boolean) => void;\n}\n\nfunction runStatusVariant(\n status: AutomationRun[\"status\"],\n): \"default\" | \"destructive\" | \"outline\" {\n if (status === \"error\") return \"destructive\";\n if (status === \"success\") return \"default\";\n return \"outline\";\n}\n\nfunction formatTimestamp(value: number): string {\n const date = new Date(value);\n return Number.isNaN(date.getTime()) ? \"Unknown time\" : date.toLocaleString();\n}\n\nfunction formatDuration(run: AutomationRun): string | null {\n if (!run.finishedAt) return null;\n const seconds = Math.max(\n 0,\n Math.round((run.finishedAt - run.startedAt) / 1000),\n );\n return `${seconds}s`;\n}\n\nfunction runDebugPath(run: AutomationRun): string | null {\n const params = new URLSearchParams();\n if (run.runId) params.set(\"runId\", run.runId);\n else if (run.threadId) params.set(\"threadId\", run.threadId);\n else return null;\n return `/admin/thread-debug?${params.toString()}`;\n}\n\nexport function AutomationRunHistoryDialog({\n automation,\n open,\n onOpenChange,\n}: AutomationRunHistoryDialogProps) {\n const scope =\n automation?.scope === \"organization\" ||\n automation?.owner.startsWith(\"__organization__:\") ||\n automation?.owner === \"__shared__\"\n ? \"organization\"\n : \"personal\";\n const runsQuery = useActionQuery<AutomationRun[]>(\n \"list-automation-runs\",\n {\n name: automation?.name ?? \"\",\n scope,\n appId: automation?.appId ?? \"dispatch\",\n },\n {\n enabled: open && Boolean(automation),\n staleTime: 5_000,\n },\n );\n const runs = runsQuery.data ?? [];\n\n return (\n <Dialog open={open} onOpenChange={onOpenChange}>\n <DialogContent className=\"max-h-[85vh] max-w-2xl overflow-y-auto\">\n <DialogHeader>\n <DialogTitle>{automation?.name ?? \"Automation details\"}</DialogTitle>\n <DialogDescription>\n {automation\n ? `${automationTarget(automation)} · ${automationScopeLabel(automation)}`\n : \"Execution history\"}\n </DialogDescription>\n </DialogHeader>\n\n {automation ? (\n <div className=\"space-y-4\">\n <div className=\"grid grid-cols-2 gap-x-4 gap-y-3 rounded-lg border bg-muted/20 p-3 text-sm\">\n <div>\n <div className=\"text-[11px] uppercase tracking-wide text-muted-foreground\">\n Status\n </div>\n <div className=\"mt-1 font-medium\">\n {automation.lastStatus ??\n (automation.enabled ? \"ready\" : \"paused\")}\n </div>\n </div>\n <div>\n <div className=\"text-[11px] uppercase tracking-wide text-muted-foreground\">\n Last check\n </div>\n <div className=\"mt-1 font-medium\">\n {automation.lastCheck\n ? formatTimestamp(new Date(automation.lastCheck).getTime())\n : \"Not recorded\"}\n </div>\n </div>\n <div>\n <div className=\"text-[11px] uppercase tracking-wide text-muted-foreground\">\n Created by\n </div>\n <div className=\"mt-1 break-words font-medium\">\n {automation.createdBy ?? \"Unknown\"}\n </div>\n </div>\n <div>\n <div className=\"text-[11px] uppercase tracking-wide text-muted-foreground\">\n Timezone\n </div>\n <div className=\"mt-1 font-medium\">\n {automation.timezone ?? \"Account default\"}\n </div>\n </div>\n </div>\n\n {automation.lastError ? (\n <div className=\"flex items-start gap-2 rounded-lg border border-destructive/30 bg-destructive/5 p-3\">\n <IconAlertTriangle className=\"mt-0.5 size-4 shrink-0 text-destructive\" />\n <div className=\"min-w-0\">\n <p className=\"text-sm font-medium text-destructive\">\n Latest scheduler result\n </p>\n <p className=\"mt-1 break-words text-sm text-muted-foreground\">\n {automation.lastError}\n </p>\n </div>\n </div>\n ) : null}\n\n <div>\n <div className=\"flex items-center justify-between gap-3\">\n <div>\n <h3 className=\"text-sm font-semibold text-foreground\">\n Past runs\n </h3>\n <p className=\"mt-1 text-xs text-muted-foreground\">\n Only executions that actually started appear here. Blocked\n or skipped scheduler checks are shown above, not as fake\n runs.\n </p>\n </div>\n {runs.length > 0 ? (\n <Badge variant=\"outline\">{runs.length} shown</Badge>\n ) : null}\n </div>\n\n <div className=\"mt-3\">\n {runsQuery.isLoading ? (\n <div className=\"flex items-center gap-2 rounded-lg border p-4 text-sm text-muted-foreground\">\n <IconLoader2 className=\"size-4 animate-spin\" />\n Loading run history...\n </div>\n ) : runsQuery.isError ? (\n <ActionQueryError\n error={runsQuery.error}\n onRetry={() => void runsQuery.refetch()}\n />\n ) : runs.length === 0 ? (\n <div className=\"rounded-lg border border-dashed p-4 text-sm text-muted-foreground\">\n This automation has not recorded an execution yet. If it is\n enabled but shows no runs, inspect the latest scheduler\n result and last check above.\n </div>\n ) : (\n <ul className=\"divide-y rounded-lg border\">\n {runs.map((run) => {\n const debugPath = runDebugPath(run);\n const duration = formatDuration(run);\n return (\n <li key={run.id} className=\"space-y-2 p-3\">\n <div className=\"flex flex-wrap items-center gap-2 text-sm\">\n <Badge variant={runStatusVariant(run.status)}>\n {run.status}\n </Badge>\n <span className=\"text-muted-foreground\">\n {formatTimestamp(run.startedAt)}\n </span>\n {duration ? (\n <span className=\"inline-flex items-center gap-1 text-xs text-muted-foreground\">\n <IconClock className=\"size-3.5\" />\n {duration}\n </span>\n ) : null}\n {debugPath ? (\n <Link\n to={debugPath}\n className=\"ml-auto inline-flex items-center gap-1 text-xs font-medium text-foreground underline-offset-4 hover:underline\"\n >\n <IconExternalLink className=\"size-3.5\" />\n Open debug\n </Link>\n ) : null}\n </div>\n {run.error ? (\n <p className=\"break-words text-sm text-destructive\">\n {run.error}\n </p>\n ) : null}\n </li>\n );\n })}\n </ul>\n )}\n </div>\n </div>\n </div>\n ) : null}\n </DialogContent>\n </Dialog>\n );\n}\n"]}
@@ -1,6 +1,12 @@
1
1
  import type { DispatchAutomationItem } from "./automations.js";
2
2
  export type AutomationStatusTone = "default" | "success" | "warning" | "danger" | "muted";
3
3
  export declare function automationIdentity(item: Pick<DispatchAutomationItem, "owner" | "path">): string;
4
+ /**
5
+ * Dispatch is the workspace-wide surface. Keep legacy resources without an
6
+ * app owner visible in its default view while making an explicit app owner
7
+ * opt into the global filter.
8
+ */
9
+ export declare function belongsToDispatch(item: Pick<DispatchAutomationItem, "appId">): boolean;
4
10
  export declare function automationTroubleshootPath(item: Pick<DispatchAutomationItem, "name">): string;
5
11
  export declare function automationTarget(item: DispatchAutomationItem): string;
6
12
  export declare function automationScopeLabel(item: Pick<DispatchAutomationItem, "owner" | "scope">): string;
@@ -1 +1 @@
1
- {"version":3,"file":"automation-display.d.ts","sourceRoot":"","sources":["../../src/lib/automation-display.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,kBAAkB,CAAC;AAE/D,MAAM,MAAM,oBAAoB,GAC5B,SAAS,GACT,SAAS,GACT,SAAS,GACT,QAAQ,GACR,OAAO,CAAC;AAEZ,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,IAAI,CAAC,sBAAsB,EAAE,OAAO,GAAG,MAAM,CAAC,GACnD,MAAM,CAER;AAED,wBAAgB,0BAA0B,CACxC,IAAI,EAAE,IAAI,CAAC,sBAAsB,EAAE,MAAM,CAAC,GACzC,MAAM,CAGR;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,sBAAsB,GAAG,MAAM,CAKrE;AAED,wBAAgB,oBAAoB,CAClC,IAAI,EAAE,IAAI,CAAC,sBAAsB,EAAE,OAAO,GAAG,OAAO,CAAC,GACpD,MAAM,CAMR;AAED,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,CAWxE;AAED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,sBAAsB,GAAG,MAAM,CAEtE;AAED,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,sBAAsB,GAAG,MAAM,CAExE;AAED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,sBAAsB,GAAG,MAAM,CAItE;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,sBAAsB,GAAG;IAC9D,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,oBAAoB,CAAC;CAC5B,CAUA;AAED,wBAAgB,eAAe,CAC7B,WAAW,EAAE,sBAAsB,EAAE,GACpC,sBAAsB,EAAE,CAa1B"}
1
+ {"version":3,"file":"automation-display.d.ts","sourceRoot":"","sources":["../../src/lib/automation-display.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,kBAAkB,CAAC;AAE/D,MAAM,MAAM,oBAAoB,GAC5B,SAAS,GACT,SAAS,GACT,SAAS,GACT,QAAQ,GACR,OAAO,CAAC;AAEZ,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,IAAI,CAAC,sBAAsB,EAAE,OAAO,GAAG,MAAM,CAAC,GACnD,MAAM,CAER;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAC/B,IAAI,EAAE,IAAI,CAAC,sBAAsB,EAAE,OAAO,CAAC,GAC1C,OAAO,CAET;AAED,wBAAgB,0BAA0B,CACxC,IAAI,EAAE,IAAI,CAAC,sBAAsB,EAAE,MAAM,CAAC,GACzC,MAAM,CAGR;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,sBAAsB,GAAG,MAAM,CAKrE;AAED,wBAAgB,oBAAoB,CAClC,IAAI,EAAE,IAAI,CAAC,sBAAsB,EAAE,OAAO,GAAG,OAAO,CAAC,GACpD,MAAM,CAMR;AAED,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,CAWxE;AAED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,sBAAsB,GAAG,MAAM,CAEtE;AAED,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,sBAAsB,GAAG,MAAM,CAExE;AAED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,sBAAsB,GAAG,MAAM,CAItE;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,sBAAsB,GAAG;IAC9D,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,oBAAoB,CAAC;CAC5B,CAUA;AAED,wBAAgB,eAAe,CAC7B,WAAW,EAAE,sBAAsB,EAAE,GACpC,sBAAsB,EAAE,CAa1B"}
@@ -1,6 +1,14 @@
1
1
  export function automationIdentity(item) {
2
2
  return `${item.owner}:${item.path}`;
3
3
  }
4
+ /**
5
+ * Dispatch is the workspace-wide surface. Keep legacy resources without an
6
+ * app owner visible in its default view while making an explicit app owner
7
+ * opt into the global filter.
8
+ */
9
+ export function belongsToDispatch(item) {
10
+ return !item.appId || item.appId === "dispatch";
11
+ }
4
12
  export function automationTroubleshootPath(item) {
5
13
  const params = new URLSearchParams({ query: item.name });
6
14
  return `/admin/thread-debug?${params.toString()}`;
@@ -1 +1 @@
1
- {"version":3,"file":"automation-display.js","sourceRoot":"","sources":["../../src/lib/automation-display.ts"],"names":[],"mappings":"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","sourcesContent":["import type { DispatchAutomationItem } from \"./automations.js\";\n\nexport type AutomationStatusTone =\n | \"default\"\n | \"success\"\n | \"warning\"\n | \"danger\"\n | \"muted\";\n\nexport function automationIdentity(\n item: Pick<DispatchAutomationItem, \"owner\" | \"path\">,\n): string {\n return `${item.owner}:${item.path}`;\n}\n\nexport function automationTroubleshootPath(\n item: Pick<DispatchAutomationItem, \"name\">,\n): string {\n const params = new URLSearchParams({ query: item.name });\n return `/admin/thread-debug?${params.toString()}`;\n}\n\nexport function automationTarget(item: DispatchAutomationItem): string {\n if (item.triggerType === \"event\" && item.event) return item.event;\n if (item.scheduleDescription) return item.scheduleDescription;\n if (item.schedule) return item.schedule;\n return item.triggerType || \"schedule\";\n}\n\nexport function automationScopeLabel(\n item: Pick<DispatchAutomationItem, \"owner\" | \"scope\">,\n): string {\n return item.scope === \"organization\" ||\n item.owner.startsWith(\"__organization__:\") ||\n item.owner === \"__shared__\"\n ? \"Organization\"\n : \"Personal\";\n}\n\nexport function relativeRunTime(value: string | null | undefined): string {\n if (!value) return \"never\";\n const timestamp = new Date(value).getTime();\n if (!Number.isFinite(timestamp)) return \"never\";\n const diff = timestamp - Date.now();\n const abs = Math.abs(diff);\n const suffix = diff >= 0 ? \"from now\" : \"ago\";\n if (abs < 60_000) return diff >= 0 ? \"soon\" : \"now\";\n if (abs < 3_600_000) return `${Math.floor(abs / 60_000)}m ${suffix}`;\n if (abs < 86_400_000) return `${Math.floor(abs / 3_600_000)}h ${suffix}`;\n return `${Math.floor(abs / 86_400_000)}d ${suffix}`;\n}\n\nexport function automationLastRun(item: DispatchAutomationItem): string {\n return item.lastRun ? relativeRunTime(item.lastRun) : \"never\";\n}\n\nexport function automationLastCheck(item: DispatchAutomationItem): string {\n return item.lastCheck ? relativeRunTime(item.lastCheck) : \"never\";\n}\n\nexport function automationNextRun(item: DispatchAutomationItem): string {\n if (!item.enabled) return \"paused\";\n if (item.triggerType === \"event\") return \"on event\";\n return item.nextRun ? relativeRunTime(item.nextRun) : \"not scheduled\";\n}\n\nexport function automationStatus(item: DispatchAutomationItem): {\n label: string;\n tone: AutomationStatusTone;\n} {\n if (!item.enabled) return { label: \"Paused\", tone: \"muted\" };\n if (item.lastStatus === \"error\") return { label: \"Error\", tone: \"danger\" };\n if (item.lastStatus === \"running\")\n return { label: \"Running\", tone: \"warning\" };\n if (item.lastStatus === \"skipped\")\n return { label: \"Blocked\", tone: \"warning\" };\n if (item.lastStatus === \"success\")\n return { label: \"Healthy\", tone: \"success\" };\n return { label: \"Ready\", tone: \"default\" };\n}\n\nexport function sortAutomations(\n automations: DispatchAutomationItem[],\n): DispatchAutomationItem[] {\n return [...automations].sort((a, b) => {\n const aError =\n a.enabled && (a.lastStatus === \"error\" || a.lastStatus === \"skipped\")\n ? 1\n : 0;\n const bError =\n b.enabled && (b.lastStatus === \"error\" || b.lastStatus === \"skipped\")\n ? 1\n : 0;\n if (aError !== bError) return bError - aError;\n return (b.lastRun || \"\").localeCompare(a.lastRun || \"\");\n });\n}\n"]}
1
+ {"version":3,"file":"automation-display.js","sourceRoot":"","sources":["../../src/lib/automation-display.ts"],"names":[],"mappings":"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","sourcesContent":["import type { DispatchAutomationItem } from \"./automations.js\";\n\nexport type AutomationStatusTone =\n | \"default\"\n | \"success\"\n | \"warning\"\n | \"danger\"\n | \"muted\";\n\nexport function automationIdentity(\n item: Pick<DispatchAutomationItem, \"owner\" | \"path\">,\n): string {\n return `${item.owner}:${item.path}`;\n}\n\n/**\n * Dispatch is the workspace-wide surface. Keep legacy resources without an\n * app owner visible in its default view while making an explicit app owner\n * opt into the global filter.\n */\nexport function belongsToDispatch(\n item: Pick<DispatchAutomationItem, \"appId\">,\n): boolean {\n return !item.appId || item.appId === \"dispatch\";\n}\n\nexport function automationTroubleshootPath(\n item: Pick<DispatchAutomationItem, \"name\">,\n): string {\n const params = new URLSearchParams({ query: item.name });\n return `/admin/thread-debug?${params.toString()}`;\n}\n\nexport function automationTarget(item: DispatchAutomationItem): string {\n if (item.triggerType === \"event\" && item.event) return item.event;\n if (item.scheduleDescription) return item.scheduleDescription;\n if (item.schedule) return item.schedule;\n return item.triggerType || \"schedule\";\n}\n\nexport function automationScopeLabel(\n item: Pick<DispatchAutomationItem, \"owner\" | \"scope\">,\n): string {\n return item.scope === \"organization\" ||\n item.owner.startsWith(\"__organization__:\") ||\n item.owner === \"__shared__\"\n ? \"Organization\"\n : \"Personal\";\n}\n\nexport function relativeRunTime(value: string | null | undefined): string {\n if (!value) return \"never\";\n const timestamp = new Date(value).getTime();\n if (!Number.isFinite(timestamp)) return \"never\";\n const diff = timestamp - Date.now();\n const abs = Math.abs(diff);\n const suffix = diff >= 0 ? \"from now\" : \"ago\";\n if (abs < 60_000) return diff >= 0 ? \"soon\" : \"now\";\n if (abs < 3_600_000) return `${Math.floor(abs / 60_000)}m ${suffix}`;\n if (abs < 86_400_000) return `${Math.floor(abs / 3_600_000)}h ${suffix}`;\n return `${Math.floor(abs / 86_400_000)}d ${suffix}`;\n}\n\nexport function automationLastRun(item: DispatchAutomationItem): string {\n return item.lastRun ? relativeRunTime(item.lastRun) : \"never\";\n}\n\nexport function automationLastCheck(item: DispatchAutomationItem): string {\n return item.lastCheck ? relativeRunTime(item.lastCheck) : \"never\";\n}\n\nexport function automationNextRun(item: DispatchAutomationItem): string {\n if (!item.enabled) return \"paused\";\n if (item.triggerType === \"event\") return \"on event\";\n return item.nextRun ? relativeRunTime(item.nextRun) : \"not scheduled\";\n}\n\nexport function automationStatus(item: DispatchAutomationItem): {\n label: string;\n tone: AutomationStatusTone;\n} {\n if (!item.enabled) return { label: \"Paused\", tone: \"muted\" };\n if (item.lastStatus === \"error\") return { label: \"Error\", tone: \"danger\" };\n if (item.lastStatus === \"running\")\n return { label: \"Running\", tone: \"warning\" };\n if (item.lastStatus === \"skipped\")\n return { label: \"Blocked\", tone: \"warning\" };\n if (item.lastStatus === \"success\")\n return { label: \"Healthy\", tone: \"success\" };\n return { label: \"Ready\", tone: \"default\" };\n}\n\nexport function sortAutomations(\n automations: DispatchAutomationItem[],\n): DispatchAutomationItem[] {\n return [...automations].sort((a, b) => {\n const aError =\n a.enabled && (a.lastStatus === \"error\" || a.lastStatus === \"skipped\")\n ? 1\n : 0;\n const bError =\n b.enabled && (b.lastStatus === \"error\" || b.lastStatus === \"skipped\")\n ? 1\n : 0;\n if (aError !== bError) return bError - aError;\n return (b.lastRun || \"\").localeCompare(a.lastRun || \"\");\n });\n}\n"]}
@@ -3,6 +3,7 @@ export interface DispatchAutomationItem {
3
3
  name: string;
4
4
  path: string;
5
5
  owner: string;
6
+ appId?: string;
6
7
  scope?: "personal" | "organization";
7
8
  canUpdate?: boolean;
8
9
  triggerType?: "schedule" | "event" | string;
@@ -1 +1 @@
1
- {"version":3,"file":"automations.d.ts","sourceRoot":"","sources":["../../src/lib/automations.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,sBAAsB;IACrC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,UAAU,GAAG,cAAc,CAAC;IACpC,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,WAAW,CAAC,EAAE,UAAU,GAAG,OAAO,GAAG,MAAM,CAAC;IAC5C,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,iCAAiC;IAChD,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,OAAO,CAAC;CAClB;AAcD,wBAAsB,uBAAuB,IAAI,OAAO,CACtD,sBAAsB,EAAE,CACzB,CAOA;AAED,wBAAsB,4BAA4B,CAChD,KAAK,EAAE,iCAAiC,GACvC,OAAO,CAAC,sBAAsB,CAAC,CAOjC"}
1
+ {"version":3,"file":"automations.d.ts","sourceRoot":"","sources":["../../src/lib/automations.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,sBAAsB;IACrC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,UAAU,GAAG,cAAc,CAAC;IACpC,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,WAAW,CAAC,EAAE,UAAU,GAAG,OAAO,GAAG,MAAM,CAAC;IAC5C,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,iCAAiC;IAChD,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,OAAO,CAAC;CAClB;AAcD,wBAAsB,uBAAuB,IAAI,OAAO,CACtD,sBAAsB,EAAE,CACzB,CAOA;AAED,wBAAsB,4BAA4B,CAChD,KAAK,EAAE,iCAAiC,GACvC,OAAO,CAAC,sBAAsB,CAAC,CAOjC"}
@@ -1 +1 @@
1
- {"version":3,"file":"automations.js","sourceRoot":"","sources":["../../src/lib/automations.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,oCAAoC,CAAC;AAgCrE,KAAK,UAAU,sBAAsB,CAAI,QAAkB;IACzD,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC;IACrD,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;QACjB,MAAM,OAAO,GACX,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,OAAO,IAAI,IAAI;YACjD,CAAC,CAAC,MAAM,CAAE,IAA4B,CAAC,KAAK,CAAC;YAC7C,CAAC,CAAC,2BAA2B,CAAC;QAClC,MAAM,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC;IAC3B,CAAC;IACD,OAAO,IAAS,CAAC;AACnB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,uBAAuB;IAG3C,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,eAAe,CAAC,4BAA4B,CAAC,CAAC,CAAC;IAC5E,MAAM,IAAI,GAAG,MAAM,sBAAsB,CAAU,QAAQ,CAAC,CAAC;IAC7D,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;QACzB,MAAM,IAAI,KAAK,CAAC,8CAA8C,CAAC,CAAC;IAClE,CAAC;IACD,OAAO,IAAgC,CAAC;AAC1C,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,4BAA4B,CAChD,KAAwC;IAExC,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,eAAe,CAAC,4BAA4B,CAAC,EAAE;QAC1E,MAAM,EAAE,OAAO;QACf,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;QAC/C,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC;KAC5B,CAAC,CAAC;IACH,OAAO,sBAAsB,CAAyB,QAAQ,CAAC,CAAC;AAClE,CAAC","sourcesContent":["import { agentNativePath } from \"@agent-native/core/client/api-path\";\n\nexport interface DispatchAutomationItem {\n id: string;\n name: string;\n path: string;\n owner: string;\n scope?: \"personal\" | \"organization\";\n canUpdate?: boolean;\n triggerType?: \"schedule\" | \"event\" | string;\n event?: string;\n schedule?: string;\n scheduleDescription?: string;\n condition?: string;\n mode?: string;\n domain?: string;\n enabled?: boolean;\n timezone?: string;\n lastStatus?: string;\n lastRun?: string;\n lastCheck?: string;\n lastError?: string;\n nextRun?: string;\n createdBy?: string;\n}\n\nexport interface SetDispatchAutomationEnabledInput {\n owner: string;\n path: string;\n enabled: boolean;\n}\n\nasync function readAutomationResponse<T>(response: Response): Promise<T> {\n const data = await response.json().catch(() => null);\n if (!response.ok) {\n const message =\n data && typeof data === \"object\" && \"error\" in data\n ? String((data as { error?: unknown }).error)\n : \"Automation request failed\";\n throw new Error(message);\n }\n return data as T;\n}\n\nexport async function listDispatchAutomations(): Promise<\n DispatchAutomationItem[]\n> {\n const response = await fetch(agentNativePath(\"/_agent-native/automations\"));\n const rows = await readAutomationResponse<unknown>(response);\n if (!Array.isArray(rows)) {\n throw new Error(\"Automation list returned an invalid response\");\n }\n return rows as DispatchAutomationItem[];\n}\n\nexport async function setDispatchAutomationEnabled(\n input: SetDispatchAutomationEnabledInput,\n): Promise<DispatchAutomationItem> {\n const response = await fetch(agentNativePath(\"/_agent-native/automations\"), {\n method: \"PATCH\",\n headers: { \"content-type\": \"application/json\" },\n body: JSON.stringify(input),\n });\n return readAutomationResponse<DispatchAutomationItem>(response);\n}\n"]}
1
+ {"version":3,"file":"automations.js","sourceRoot":"","sources":["../../src/lib/automations.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,oCAAoC,CAAC;AAiCrE,KAAK,UAAU,sBAAsB,CAAI,QAAkB;IACzD,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC;IACrD,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;QACjB,MAAM,OAAO,GACX,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,OAAO,IAAI,IAAI;YACjD,CAAC,CAAC,MAAM,CAAE,IAA4B,CAAC,KAAK,CAAC;YAC7C,CAAC,CAAC,2BAA2B,CAAC;QAClC,MAAM,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC;IAC3B,CAAC;IACD,OAAO,IAAS,CAAC;AACnB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,uBAAuB;IAG3C,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,eAAe,CAAC,4BAA4B,CAAC,CAAC,CAAC;IAC5E,MAAM,IAAI,GAAG,MAAM,sBAAsB,CAAU,QAAQ,CAAC,CAAC;IAC7D,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;QACzB,MAAM,IAAI,KAAK,CAAC,8CAA8C,CAAC,CAAC;IAClE,CAAC;IACD,OAAO,IAAgC,CAAC;AAC1C,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,4BAA4B,CAChD,KAAwC;IAExC,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,eAAe,CAAC,4BAA4B,CAAC,EAAE;QAC1E,MAAM,EAAE,OAAO;QACf,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;QAC/C,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC;KAC5B,CAAC,CAAC;IACH,OAAO,sBAAsB,CAAyB,QAAQ,CAAC,CAAC;AAClE,CAAC","sourcesContent":["import { agentNativePath } from \"@agent-native/core/client/api-path\";\n\nexport interface DispatchAutomationItem {\n id: string;\n name: string;\n path: string;\n owner: string;\n appId?: string;\n scope?: \"personal\" | \"organization\";\n canUpdate?: boolean;\n triggerType?: \"schedule\" | \"event\" | string;\n event?: string;\n schedule?: string;\n scheduleDescription?: string;\n condition?: string;\n mode?: string;\n domain?: string;\n enabled?: boolean;\n timezone?: string;\n lastStatus?: string;\n lastRun?: string;\n lastCheck?: string;\n lastError?: string;\n nextRun?: string;\n createdBy?: string;\n}\n\nexport interface SetDispatchAutomationEnabledInput {\n owner: string;\n path: string;\n enabled: boolean;\n}\n\nasync function readAutomationResponse<T>(response: Response): Promise<T> {\n const data = await response.json().catch(() => null);\n if (!response.ok) {\n const message =\n data && typeof data === \"object\" && \"error\" in data\n ? String((data as { error?: unknown }).error)\n : \"Automation request failed\";\n throw new Error(message);\n }\n return data as T;\n}\n\nexport async function listDispatchAutomations(): Promise<\n DispatchAutomationItem[]\n> {\n const response = await fetch(agentNativePath(\"/_agent-native/automations\"));\n const rows = await readAutomationResponse<unknown>(response);\n if (!Array.isArray(rows)) {\n throw new Error(\"Automation list returned an invalid response\");\n }\n return rows as DispatchAutomationItem[];\n}\n\nexport async function setDispatchAutomationEnabled(\n input: SetDispatchAutomationEnabledInput,\n): Promise<DispatchAutomationItem> {\n const response = await fetch(agentNativePath(\"/_agent-native/automations\"), {\n method: \"PATCH\",\n headers: { \"content-type\": \"application/json\" },\n body: JSON.stringify(input),\n });\n return readAutomationResponse<DispatchAutomationItem>(response);\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"automations.d.ts","sourceRoot":"","sources":["../../../src/routes/pages/automations.tsx"],"names":[],"mappings":"AA+CA,wBAAgB,IAAI;;IAEnB;AAmID,MAAM,CAAC,OAAO,UAAU,gBAAgB,oDA+IvC"}
1
+ {"version":3,"file":"automations.d.ts","sourceRoot":"","sources":["../../../src/routes/pages/automations.tsx"],"names":[],"mappings":"AAuDA,wBAAgB,IAAI;;IAEnB;AAmID,MAAM,CAAC,OAAO,UAAU,gBAAgB,oDA8KvC"}
@@ -12,9 +12,10 @@ import { DispatchShell } from "../../components/dispatch-shell.js";
12
12
  import { Badge } from "../../components/ui/badge.js";
13
13
  import { Button } from "../../components/ui/button.js";
14
14
  import { Popover, PopoverContent, PopoverTrigger, } from "../../components/ui/popover.js";
15
+ import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "../../components/ui/select.js";
15
16
  import { Skeleton } from "../../components/ui/skeleton.js";
16
17
  import { Switch } from "../../components/ui/switch.js";
17
- import { automationIdentity, automationLastCheck, automationLastRun, automationNextRun, automationScopeLabel, automationStatus, automationTarget, automationTroubleshootPath, sortAutomations, } from "../../lib/automation-display.js";
18
+ import { automationIdentity, automationLastCheck, automationLastRun, automationNextRun, automationScopeLabel, automationStatus, automationTarget, automationTroubleshootPath, belongsToDispatch, sortAutomations, } from "../../lib/automation-display.js";
18
19
  import { listDispatchAutomations, setDispatchAutomationEnabled, } from "../../lib/automations.js";
19
20
  import { cn } from "../../lib/utils.js";
20
21
  const AUTOMATIONS_QUERY_KEY = ["dispatch-automations"];
@@ -84,20 +85,27 @@ function CreateAutomationButton() {
84
85
  return (_jsxs(Popover, { open: open, onOpenChange: setOpen, children: [_jsx(PopoverTrigger, { asChild: true, children: _jsxs(Button, { size: "sm", children: [_jsx(IconPlus, { size: 14 }), "New automation"] }) }), _jsxs(PopoverContent, { align: "end", className: "w-[min(100vw-2rem,24rem)] p-3", children: [_jsx("p", { className: "pb-2 text-sm font-semibold text-foreground", children: "New automation" }), _jsx(PromptComposer, { autoFocus: true, placeholder: "Describe what you want to automate...", draftScope: "dispatch-automations:create", onSubmit: handleSubmit }), _jsxs("select", { value: scope, onChange: (event) => setScope(event.target.value), className: "mt-2 w-full cursor-pointer rounded-md border border-input bg-background px-3 py-1.5 text-xs text-foreground", children: [_jsx("option", { value: "personal", children: "Personal" }), _jsx("option", { value: "organization", children: "Organization" })] })] })] }));
85
86
  }
86
87
  export default function AutomationsRoute() {
88
+ const [view, setView] = useState("dispatch");
87
89
  const [detailsTarget, setDetailsTarget] = useState(null);
88
90
  const automationsQuery = useAutomations();
89
91
  const toggleAutomation = useToggleAutomation();
90
92
  const automations = automationsQuery.data ?? [];
91
- const ordered = useMemo(() => sortAutomations(automations), [automations]);
92
- const enabledCount = automations.filter((item) => item.enabled).length;
93
- const errorCount = automations.filter((item) => item.enabled &&
93
+ const visibleAutomations = useMemo(() => view === "all"
94
+ ? automations
95
+ : automations.filter((item) => belongsToDispatch(item)), [automations, view]);
96
+ const ordered = useMemo(() => sortAutomations(visibleAutomations), [visibleAutomations]);
97
+ const enabledCount = visibleAutomations.filter((item) => item.enabled).length;
98
+ const errorCount = visibleAutomations.filter((item) => item.enabled &&
94
99
  (item.lastStatus === "error" || item.lastStatus === "skipped")).length;
95
100
  const pendingToggleIdentity = toggleAutomation.isPending
96
101
  ? toggleAutomation.variables
97
102
  ? automationIdentity(toggleAutomation.variables)
98
103
  : null
99
104
  : null;
100
- return (_jsxs(DispatchShell, { title: "Automations", description: "See scheduled and event-triggered jobs, inspect their checks and past runs, pause them, or ask the agent to create one.", children: [_jsxs("section", { className: "flex flex-col gap-4", children: [_jsxs("div", { className: "flex flex-wrap items-center justify-between gap-3", children: [_jsxs("div", { className: "flex min-w-0 items-center gap-2 text-sm text-muted-foreground", children: [_jsx(IconSettingsAutomation, { size: 16, className: "shrink-0" }), _jsxs("span", { children: [enabledCount, " enabled", errorCount > 0 ? ` · ${errorCount} errors` : ""] })] }), _jsx(CreateAutomationButton, {})] }), _jsx("div", { className: "divide-y rounded-lg bg-card", children: automationsQuery.isLoading && ordered.length === 0 ? (Array.from({ length: 4 }).map((_, index) => (_jsxs("div", { className: "px-4 py-3", children: [_jsx(Skeleton, { className: "h-4 w-40" }), _jsx(Skeleton, { className: "mt-2 h-3 w-28" })] }, index)))) : ordered.length > 0 ? (ordered.map((item) => {
105
+ return (_jsxs(DispatchShell, { title: "Automations", description: "See scheduled and event-triggered jobs, inspect their checks and past runs, pause them, or ask the agent to create one.", children: [_jsxs("section", { className: "flex flex-col gap-4", children: [_jsxs("div", { className: "flex flex-wrap items-center justify-between gap-3", children: [_jsxs("div", { className: "flex min-w-0 items-center gap-2 text-sm text-muted-foreground", children: [_jsx(IconSettingsAutomation, { size: 16, className: "shrink-0" }), _jsxs("span", { children: [enabledCount, " enabled", errorCount > 0 ? ` · ${errorCount} errors` : ""] })] }), _jsxs("div", { className: "flex flex-wrap items-center justify-end gap-2", children: [_jsxs(Select, { value: view, onValueChange: (value) => {
106
+ if (value === "dispatch" || value === "all")
107
+ setView(value);
108
+ }, children: [_jsx(SelectTrigger, { className: "h-8 w-[10.5rem] text-xs", "aria-label": "Automation view", children: _jsx(SelectValue, {}) }), _jsxs(SelectContent, { children: [_jsx(SelectItem, { value: "dispatch", children: "Dispatch automations" }), _jsx(SelectItem, { value: "all", children: "All apps" })] })] }), _jsx(CreateAutomationButton, {})] })] }), _jsx("div", { className: "divide-y rounded-lg bg-card", children: automationsQuery.isLoading && ordered.length === 0 ? (Array.from({ length: 4 }).map((_, index) => (_jsxs("div", { className: "px-4 py-3", children: [_jsx(Skeleton, { className: "h-4 w-40" }), _jsx(Skeleton, { className: "mt-2 h-3 w-28" })] }, index)))) : ordered.length > 0 ? (ordered.map((item) => {
101
109
  const status = automationStatus(item);
102
110
  const canUpdate = item.canUpdate !== false;
103
111
  const isToggling = pendingToggleIdentity === automationIdentity(item);
@@ -106,7 +114,9 @@ export default function AutomationsRoute() {
106
114
  path: item.path,
107
115
  enabled: checked,
108
116
  }) })] })] }, item.id));
109
- })) : (_jsx("div", { className: "px-4 py-10 text-center text-sm text-muted-foreground", children: "No automations yet. Create one here, or ask Dispatch to set up a scheduled or event-triggered job." })) })] }), _jsx(AutomationRunHistoryDialog, { automation: detailsTarget, open: detailsTarget !== null, onOpenChange: (open) => {
117
+ })) : (_jsx("div", { className: "px-4 py-10 text-center text-sm text-muted-foreground", children: view === "all"
118
+ ? "No automations yet. Create one here, or ask Dispatch to set up a scheduled or event-triggered job."
119
+ : "No Dispatch automations yet. Switch to All apps to inspect workspace automations." })) })] }), _jsx(AutomationRunHistoryDialog, { automation: detailsTarget, open: detailsTarget !== null, onOpenChange: (open) => {
110
120
  if (!open)
111
121
  setDetailsTarget(null);
112
122
  } })] }));
@@ -1 +1 @@
1
- {"version":3,"file":"automations.js","sourceRoot":"","sources":["../../../src/routes/pages/automations.tsx"],"names":[],"mappings":"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","sourcesContent":["import { sendToAgentChat } from \"@agent-native/core/client/agent-chat\";\nimport { PromptComposer } from \"@agent-native/core/client/composer\";\nimport { useChangeVersions } from \"@agent-native/core/client/hooks\";\nimport {\n IconFileSearch,\n IconListDetails,\n IconPlus,\n IconSettingsAutomation,\n} from \"@tabler/icons-react\";\nimport { useMutation, useQuery, useQueryClient } from \"@tanstack/react-query\";\nimport { useMemo, useState } from \"react\";\nimport { Link } from \"react-router\";\nimport { toast } from \"sonner\";\n\nimport { AutomationRunHistoryDialog } from \"../../components/automation-run-history-dialog\";\nimport { DispatchShell } from \"../../components/dispatch-shell\";\nimport { Badge } from \"../../components/ui/badge\";\nimport { Button } from \"../../components/ui/button\";\nimport {\n Popover,\n PopoverContent,\n PopoverTrigger,\n} from \"../../components/ui/popover\";\nimport { Skeleton } from \"../../components/ui/skeleton\";\nimport { Switch } from \"../../components/ui/switch\";\nimport {\n automationIdentity,\n automationLastCheck,\n automationLastRun,\n automationNextRun,\n automationScopeLabel,\n automationStatus,\n automationTarget,\n automationTroubleshootPath,\n sortAutomations,\n type AutomationStatusTone,\n} from \"../../lib/automation-display\";\nimport {\n listDispatchAutomations,\n setDispatchAutomationEnabled,\n type DispatchAutomationItem,\n type SetDispatchAutomationEnabledInput,\n} from \"../../lib/automations\";\nimport { cn } from \"../../lib/utils\";\n\nconst AUTOMATIONS_QUERY_KEY = [\"dispatch-automations\"] as const;\n\nexport function meta() {\n return [{ title: \"Automations — Dispatch\" }];\n}\n\nfunction StatusDot({ tone }: { tone: AutomationStatusTone }) {\n return (\n <span\n className={cn(\n \"size-2 shrink-0 rounded-full\",\n tone === \"success\" && \"bg-emerald-500\",\n tone === \"warning\" && \"bg-amber-500\",\n tone === \"danger\" && \"bg-destructive\",\n tone === \"muted\" && \"bg-muted-foreground/35\",\n tone === \"default\" && \"bg-primary\",\n )}\n />\n );\n}\n\nfunction useAutomations() {\n const version = useChangeVersions([\"action\", \"screen-refresh\"]);\n return useQuery<DispatchAutomationItem[]>({\n queryKey: [...AUTOMATIONS_QUERY_KEY, version],\n queryFn: listDispatchAutomations,\n placeholderData: (prev) => prev,\n staleTime: 5_000,\n });\n}\n\nfunction useToggleAutomation() {\n const queryClient = useQueryClient();\n\n return useMutation({\n mutationFn: setDispatchAutomationEnabled,\n onMutate: async (input: SetDispatchAutomationEnabledInput) => {\n await queryClient.cancelQueries({ queryKey: AUTOMATIONS_QUERY_KEY });\n const snapshots = queryClient.getQueriesData<DispatchAutomationItem[]>({\n queryKey: AUTOMATIONS_QUERY_KEY,\n });\n\n queryClient.setQueriesData<DispatchAutomationItem[]>(\n { queryKey: AUTOMATIONS_QUERY_KEY },\n (rows) =>\n rows?.map((item) =>\n automationIdentity(item) === automationIdentity(input)\n ? { ...item, enabled: input.enabled }\n : item,\n ),\n );\n\n return { snapshots };\n },\n onError: (err, _input, context) => {\n for (const [queryKey, data] of context?.snapshots ?? []) {\n queryClient.setQueryData(queryKey, data);\n }\n toast.error(\n `Could not update automation: ${\n err instanceof Error ? err.message : String(err)\n }`,\n );\n },\n onSuccess: (updated) => {\n queryClient.setQueriesData<DispatchAutomationItem[]>(\n { queryKey: AUTOMATIONS_QUERY_KEY },\n (rows) =>\n rows?.map((item) =>\n automationIdentity(item) === automationIdentity(updated)\n ? updated\n : item,\n ),\n );\n },\n onSettled: () => {\n void queryClient.invalidateQueries({ queryKey: AUTOMATIONS_QUERY_KEY });\n },\n });\n}\n\nfunction CreateAutomationButton() {\n const [open, setOpen] = useState(false);\n const [scope, setScope] = useState<\"personal\" | \"organization\">(\"personal\");\n\n function handleSubmit(text: string) {\n const trimmed = text.trim();\n if (!trimmed) return;\n window.dispatchEvent(\n new CustomEvent(\"agent-panel:set-mode\", {\n detail: { mode: \"chat\" },\n }),\n );\n sendToAgentChat({\n message: trimmed,\n context: `The user wants to create a new automation. Scope: ${scope}. Use manage-automations with action=define to create it. Ask clarifying questions if needed about what event to trigger on, conditions, and what actions to take.`,\n submit: true,\n newTab: true,\n });\n setOpen(false);\n }\n\n return (\n <Popover open={open} onOpenChange={setOpen}>\n <PopoverTrigger asChild>\n <Button size=\"sm\">\n <IconPlus size={14} />\n New automation\n </Button>\n </PopoverTrigger>\n <PopoverContent align=\"end\" className=\"w-[min(100vw-2rem,24rem)] p-3\">\n <p className=\"pb-2 text-sm font-semibold text-foreground\">\n New automation\n </p>\n <PromptComposer\n autoFocus\n placeholder=\"Describe what you want to automate...\"\n draftScope=\"dispatch-automations:create\"\n onSubmit={handleSubmit}\n />\n <select\n value={scope}\n onChange={(event) =>\n setScope(event.target.value as \"personal\" | \"organization\")\n }\n className=\"mt-2 w-full cursor-pointer rounded-md border border-input bg-background px-3 py-1.5 text-xs text-foreground\"\n >\n <option value=\"personal\">Personal</option>\n <option value=\"organization\">Organization</option>\n </select>\n </PopoverContent>\n </Popover>\n );\n}\n\nexport default function AutomationsRoute() {\n const [detailsTarget, setDetailsTarget] =\n useState<DispatchAutomationItem | null>(null);\n const automationsQuery = useAutomations();\n const toggleAutomation = useToggleAutomation();\n const automations = automationsQuery.data ?? [];\n const ordered = useMemo(() => sortAutomations(automations), [automations]);\n const enabledCount = automations.filter((item) => item.enabled).length;\n const errorCount = automations.filter(\n (item) =>\n item.enabled &&\n (item.lastStatus === \"error\" || item.lastStatus === \"skipped\"),\n ).length;\n const pendingToggleIdentity = toggleAutomation.isPending\n ? toggleAutomation.variables\n ? automationIdentity(toggleAutomation.variables)\n : null\n : null;\n\n return (\n <DispatchShell\n title=\"Automations\"\n description=\"See scheduled and event-triggered jobs, inspect their checks and past runs, pause them, or ask the agent to create one.\"\n >\n <section className=\"flex flex-col gap-4\">\n <div className=\"flex flex-wrap items-center justify-between gap-3\">\n <div className=\"flex min-w-0 items-center gap-2 text-sm text-muted-foreground\">\n <IconSettingsAutomation size={16} className=\"shrink-0\" />\n <span>\n {enabledCount} enabled\n {errorCount > 0 ? ` · ${errorCount} errors` : \"\"}\n </span>\n </div>\n <CreateAutomationButton />\n </div>\n\n <div className=\"divide-y rounded-lg bg-card\">\n {automationsQuery.isLoading && ordered.length === 0 ? (\n Array.from({ length: 4 }).map((_, index) => (\n <div key={index} className=\"px-4 py-3\">\n <Skeleton className=\"h-4 w-40\" />\n <Skeleton className=\"mt-2 h-3 w-28\" />\n </div>\n ))\n ) : ordered.length > 0 ? (\n ordered.map((item) => {\n const status = automationStatus(item);\n const canUpdate = item.canUpdate !== false;\n const isToggling =\n pendingToggleIdentity === automationIdentity(item);\n return (\n <div\n key={item.id}\n className=\"grid grid-cols-[minmax(0,1fr)_auto] gap-3 px-4 py-3\"\n >\n <div className=\"min-w-0\">\n <div className=\"flex min-w-0 items-center gap-2\">\n <StatusDot tone={status.tone} />\n <span className=\"truncate text-sm font-medium text-foreground\">\n {item.name}\n </span>\n </div>\n <div className=\"mt-1 truncate text-xs text-muted-foreground\">\n {automationTarget(item)}\n </div>\n <div className=\"mt-1 flex flex-wrap gap-x-3 gap-y-1 text-[11px] text-muted-foreground\">\n <span>Last {automationLastRun(item)}</span>\n <span>Next {automationNextRun(item)}</span>\n <span>{automationScopeLabel(item)}</span>\n {item.lastCheck ? (\n <span>Checked {automationLastCheck(item)}</span>\n ) : null}\n </div>\n {item.lastError ? (\n <div className=\"mt-1 flex flex-wrap items-baseline gap-x-2 gap-y-1 text-xs text-destructive\">\n <span className=\"min-w-0 break-words\">\n {item.lastError}\n </span>\n <Link\n to={automationTroubleshootPath(item)}\n className=\"inline-flex shrink-0 items-center gap-1 font-medium text-foreground underline-offset-4 hover:underline\"\n aria-label={`Troubleshoot ${item.name} in Thread Debug`}\n >\n <IconFileSearch size={13} aria-hidden=\"true\" />\n Troubleshoot in Thread Debug\n </Link>\n </div>\n ) : null}\n </div>\n <div className=\"flex flex-col items-end gap-2\">\n <div className=\"flex items-center gap-2\">\n <Badge\n variant={\n status.tone === \"danger\" ? \"destructive\" : \"outline\"\n }\n className=\"h-5\"\n >\n {status.label}\n </Badge>\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n className=\"h-7 px-2 text-xs\"\n onClick={() => setDetailsTarget(item)}\n >\n <IconListDetails size={14} />\n Details\n </Button>\n </div>\n <Switch\n checked={!!item.enabled}\n disabled={!canUpdate || isToggling}\n aria-label={`${item.enabled ? \"Disable\" : \"Enable\"} automation ${item.name}`}\n onCheckedChange={(checked) =>\n toggleAutomation.mutate({\n owner: item.owner,\n path: item.path,\n enabled: checked,\n })\n }\n />\n </div>\n </div>\n );\n })\n ) : (\n <div className=\"px-4 py-10 text-center text-sm text-muted-foreground\">\n No automations yet. Create one here, or ask Dispatch to set up a\n scheduled or event-triggered job.\n </div>\n )}\n </div>\n </section>\n <AutomationRunHistoryDialog\n automation={detailsTarget}\n open={detailsTarget !== null}\n onOpenChange={(open) => {\n if (!open) setDetailsTarget(null);\n }}\n />\n </DispatchShell>\n );\n}\n"]}
1
+ {"version":3,"file":"automations.js","sourceRoot":"","sources":["../../../src/routes/pages/automations.tsx"],"names":[],"mappings":"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","sourcesContent":["import { sendToAgentChat } from \"@agent-native/core/client/agent-chat\";\nimport { PromptComposer } from \"@agent-native/core/client/composer\";\nimport { useChangeVersions } from \"@agent-native/core/client/hooks\";\nimport {\n IconFileSearch,\n IconListDetails,\n IconPlus,\n IconSettingsAutomation,\n} from \"@tabler/icons-react\";\nimport { useMutation, useQuery, useQueryClient } from \"@tanstack/react-query\";\nimport { useMemo, useState } from \"react\";\nimport { Link } from \"react-router\";\nimport { toast } from \"sonner\";\n\nimport { AutomationRunHistoryDialog } from \"../../components/automation-run-history-dialog\";\nimport { DispatchShell } from \"../../components/dispatch-shell\";\nimport { Badge } from \"../../components/ui/badge\";\nimport { Button } from \"../../components/ui/button\";\nimport {\n Popover,\n PopoverContent,\n PopoverTrigger,\n} from \"../../components/ui/popover\";\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from \"../../components/ui/select\";\nimport { Skeleton } from \"../../components/ui/skeleton\";\nimport { Switch } from \"../../components/ui/switch\";\nimport {\n automationIdentity,\n automationLastCheck,\n automationLastRun,\n automationNextRun,\n automationScopeLabel,\n automationStatus,\n automationTarget,\n automationTroubleshootPath,\n belongsToDispatch,\n sortAutomations,\n type AutomationStatusTone,\n} from \"../../lib/automation-display\";\nimport {\n listDispatchAutomations,\n setDispatchAutomationEnabled,\n type DispatchAutomationItem,\n type SetDispatchAutomationEnabledInput,\n} from \"../../lib/automations\";\nimport { cn } from \"../../lib/utils\";\n\nconst AUTOMATIONS_QUERY_KEY = [\"dispatch-automations\"] as const;\n\nexport function meta() {\n return [{ title: \"Automations — Dispatch\" }];\n}\n\nfunction StatusDot({ tone }: { tone: AutomationStatusTone }) {\n return (\n <span\n className={cn(\n \"size-2 shrink-0 rounded-full\",\n tone === \"success\" && \"bg-emerald-500\",\n tone === \"warning\" && \"bg-amber-500\",\n tone === \"danger\" && \"bg-destructive\",\n tone === \"muted\" && \"bg-muted-foreground/35\",\n tone === \"default\" && \"bg-primary\",\n )}\n />\n );\n}\n\nfunction useAutomations() {\n const version = useChangeVersions([\"action\", \"screen-refresh\"]);\n return useQuery<DispatchAutomationItem[]>({\n queryKey: [...AUTOMATIONS_QUERY_KEY, version],\n queryFn: listDispatchAutomations,\n placeholderData: (prev) => prev,\n staleTime: 5_000,\n });\n}\n\nfunction useToggleAutomation() {\n const queryClient = useQueryClient();\n\n return useMutation({\n mutationFn: setDispatchAutomationEnabled,\n onMutate: async (input: SetDispatchAutomationEnabledInput) => {\n await queryClient.cancelQueries({ queryKey: AUTOMATIONS_QUERY_KEY });\n const snapshots = queryClient.getQueriesData<DispatchAutomationItem[]>({\n queryKey: AUTOMATIONS_QUERY_KEY,\n });\n\n queryClient.setQueriesData<DispatchAutomationItem[]>(\n { queryKey: AUTOMATIONS_QUERY_KEY },\n (rows) =>\n rows?.map((item) =>\n automationIdentity(item) === automationIdentity(input)\n ? { ...item, enabled: input.enabled }\n : item,\n ),\n );\n\n return { snapshots };\n },\n onError: (err, _input, context) => {\n for (const [queryKey, data] of context?.snapshots ?? []) {\n queryClient.setQueryData(queryKey, data);\n }\n toast.error(\n `Could not update automation: ${\n err instanceof Error ? err.message : String(err)\n }`,\n );\n },\n onSuccess: (updated) => {\n queryClient.setQueriesData<DispatchAutomationItem[]>(\n { queryKey: AUTOMATIONS_QUERY_KEY },\n (rows) =>\n rows?.map((item) =>\n automationIdentity(item) === automationIdentity(updated)\n ? updated\n : item,\n ),\n );\n },\n onSettled: () => {\n void queryClient.invalidateQueries({ queryKey: AUTOMATIONS_QUERY_KEY });\n },\n });\n}\n\nfunction CreateAutomationButton() {\n const [open, setOpen] = useState(false);\n const [scope, setScope] = useState<\"personal\" | \"organization\">(\"personal\");\n\n function handleSubmit(text: string) {\n const trimmed = text.trim();\n if (!trimmed) return;\n window.dispatchEvent(\n new CustomEvent(\"agent-panel:set-mode\", {\n detail: { mode: \"chat\" },\n }),\n );\n sendToAgentChat({\n message: trimmed,\n context: `The user wants to create a new automation. Scope: ${scope}. Use manage-automations with action=define to create it. Ask clarifying questions if needed about what event to trigger on, conditions, and what actions to take.`,\n submit: true,\n newTab: true,\n });\n setOpen(false);\n }\n\n return (\n <Popover open={open} onOpenChange={setOpen}>\n <PopoverTrigger asChild>\n <Button size=\"sm\">\n <IconPlus size={14} />\n New automation\n </Button>\n </PopoverTrigger>\n <PopoverContent align=\"end\" className=\"w-[min(100vw-2rem,24rem)] p-3\">\n <p className=\"pb-2 text-sm font-semibold text-foreground\">\n New automation\n </p>\n <PromptComposer\n autoFocus\n placeholder=\"Describe what you want to automate...\"\n draftScope=\"dispatch-automations:create\"\n onSubmit={handleSubmit}\n />\n <select\n value={scope}\n onChange={(event) =>\n setScope(event.target.value as \"personal\" | \"organization\")\n }\n className=\"mt-2 w-full cursor-pointer rounded-md border border-input bg-background px-3 py-1.5 text-xs text-foreground\"\n >\n <option value=\"personal\">Personal</option>\n <option value=\"organization\">Organization</option>\n </select>\n </PopoverContent>\n </Popover>\n );\n}\n\nexport default function AutomationsRoute() {\n const [view, setView] = useState<\"dispatch\" | \"all\">(\"dispatch\");\n const [detailsTarget, setDetailsTarget] =\n useState<DispatchAutomationItem | null>(null);\n const automationsQuery = useAutomations();\n const toggleAutomation = useToggleAutomation();\n const automations = automationsQuery.data ?? [];\n const visibleAutomations = useMemo(\n () =>\n view === \"all\"\n ? automations\n : automations.filter((item) => belongsToDispatch(item)),\n [automations, view],\n );\n const ordered = useMemo(\n () => sortAutomations(visibleAutomations),\n [visibleAutomations],\n );\n const enabledCount = visibleAutomations.filter((item) => item.enabled).length;\n const errorCount = visibleAutomations.filter(\n (item) =>\n item.enabled &&\n (item.lastStatus === \"error\" || item.lastStatus === \"skipped\"),\n ).length;\n const pendingToggleIdentity = toggleAutomation.isPending\n ? toggleAutomation.variables\n ? automationIdentity(toggleAutomation.variables)\n : null\n : null;\n\n return (\n <DispatchShell\n title=\"Automations\"\n description=\"See scheduled and event-triggered jobs, inspect their checks and past runs, pause them, or ask the agent to create one.\"\n >\n <section className=\"flex flex-col gap-4\">\n <div className=\"flex flex-wrap items-center justify-between gap-3\">\n <div className=\"flex min-w-0 items-center gap-2 text-sm text-muted-foreground\">\n <IconSettingsAutomation size={16} className=\"shrink-0\" />\n <span>\n {enabledCount} enabled\n {errorCount > 0 ? ` · ${errorCount} errors` : \"\"}\n </span>\n </div>\n <div className=\"flex flex-wrap items-center justify-end gap-2\">\n <Select\n value={view}\n onValueChange={(value) => {\n if (value === \"dispatch\" || value === \"all\") setView(value);\n }}\n >\n <SelectTrigger\n className=\"h-8 w-[10.5rem] text-xs\"\n aria-label=\"Automation view\"\n >\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"dispatch\">Dispatch automations</SelectItem>\n <SelectItem value=\"all\">All apps</SelectItem>\n </SelectContent>\n </Select>\n <CreateAutomationButton />\n </div>\n </div>\n\n <div className=\"divide-y rounded-lg bg-card\">\n {automationsQuery.isLoading && ordered.length === 0 ? (\n Array.from({ length: 4 }).map((_, index) => (\n <div key={index} className=\"px-4 py-3\">\n <Skeleton className=\"h-4 w-40\" />\n <Skeleton className=\"mt-2 h-3 w-28\" />\n </div>\n ))\n ) : ordered.length > 0 ? (\n ordered.map((item) => {\n const status = automationStatus(item);\n const canUpdate = item.canUpdate !== false;\n const isToggling =\n pendingToggleIdentity === automationIdentity(item);\n return (\n <div\n key={item.id}\n className=\"grid grid-cols-[minmax(0,1fr)_auto] gap-3 px-4 py-3\"\n >\n <div className=\"min-w-0\">\n <div className=\"flex min-w-0 items-center gap-2\">\n <StatusDot tone={status.tone} />\n <span className=\"truncate text-sm font-medium text-foreground\">\n {item.name}\n </span>\n </div>\n <div className=\"mt-1 truncate text-xs text-muted-foreground\">\n {automationTarget(item)}\n </div>\n <div className=\"mt-1 flex flex-wrap gap-x-3 gap-y-1 text-[11px] text-muted-foreground\">\n <span>Last {automationLastRun(item)}</span>\n <span>Next {automationNextRun(item)}</span>\n <span>{automationScopeLabel(item)}</span>\n {item.lastCheck ? (\n <span>Checked {automationLastCheck(item)}</span>\n ) : null}\n </div>\n {item.lastError ? (\n <div className=\"mt-1 flex flex-wrap items-baseline gap-x-2 gap-y-1 text-xs text-destructive\">\n <span className=\"min-w-0 break-words\">\n {item.lastError}\n </span>\n <Link\n to={automationTroubleshootPath(item)}\n className=\"inline-flex shrink-0 items-center gap-1 font-medium text-foreground underline-offset-4 hover:underline\"\n aria-label={`Troubleshoot ${item.name} in Thread Debug`}\n >\n <IconFileSearch size={13} aria-hidden=\"true\" />\n Troubleshoot in Thread Debug\n </Link>\n </div>\n ) : null}\n </div>\n <div className=\"flex flex-col items-end gap-2\">\n <div className=\"flex items-center gap-2\">\n <Badge\n variant={\n status.tone === \"danger\" ? \"destructive\" : \"outline\"\n }\n className=\"h-5\"\n >\n {status.label}\n </Badge>\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n className=\"h-7 px-2 text-xs\"\n onClick={() => setDetailsTarget(item)}\n >\n <IconListDetails size={14} />\n Details\n </Button>\n </div>\n <Switch\n checked={!!item.enabled}\n disabled={!canUpdate || isToggling}\n aria-label={`${item.enabled ? \"Disable\" : \"Enable\"} automation ${item.name}`}\n onCheckedChange={(checked) =>\n toggleAutomation.mutate({\n owner: item.owner,\n path: item.path,\n enabled: checked,\n })\n }\n />\n </div>\n </div>\n );\n })\n ) : (\n <div className=\"px-4 py-10 text-center text-sm text-muted-foreground\">\n {view === \"all\"\n ? \"No automations yet. Create one here, or ask Dispatch to set up a scheduled or event-triggered job.\"\n : \"No Dispatch automations yet. Switch to All apps to inspect workspace automations.\"}\n </div>\n )}\n </div>\n </section>\n <AutomationRunHistoryDialog\n automation={detailsTarget}\n open={detailsTarget !== null}\n onOpenChange={(open) => {\n if (!open) setDetailsTarget(null);\n }}\n />\n </DispatchShell>\n );\n}\n"]}
@@ -38,7 +38,7 @@ export declare function setupDispatch(config?: DispatchConfig): NitroPluginDef;
38
38
  export { default as dispatchAuthPlugin } from "./plugins/auth.js";
39
39
  export { default as dispatchIntegrationsPlugin } from "./plugins/integrations.js";
40
40
  export { default as dispatchAgentChatPlugin } from "./plugins/agent-chat.js";
41
- export { default as dispatchDbPlugin } from "./plugins/db.js";
41
+ export { default as dispatchDbPlugin, runDispatchMigrations, } from "./plugins/db.js";
42
42
  export { default as dispatchCoreRoutesPlugin } from "./plugins/core-routes.js";
43
43
  export type { DispatchConfig } from "../config.js";
44
44
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,cAAc,EACpB,MAAM,2BAA2B,CAAC;AAGnC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAsBnD,wBAAgB,iBAAiB,IAAI,cAAc,CAElD;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,wBAAgB,aAAa,CAAC,MAAM,GAAE,cAAmB,GAAG,cAAc,CAKzE;AAED,OAAO,EAAE,OAAO,IAAI,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAClE,OAAO,EAAE,OAAO,IAAI,0BAA0B,EAAE,MAAM,2BAA2B,CAAC;AAClF,OAAO,EAAE,OAAO,IAAI,uBAAuB,EAAE,MAAM,yBAAyB,CAAC;AAC7E,OAAO,EAAE,OAAO,IAAI,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAC9D,OAAO,EAAE,OAAO,IAAI,wBAAwB,EAAE,MAAM,0BAA0B,CAAC;AAE/E,YAAY,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,cAAc,EACpB,MAAM,2BAA2B,CAAC;AAGnC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAsBnD,wBAAgB,iBAAiB,IAAI,cAAc,CAElD;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,wBAAgB,aAAa,CAAC,MAAM,GAAE,cAAmB,GAAG,cAAc,CAKzE;AAED,OAAO,EAAE,OAAO,IAAI,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAClE,OAAO,EAAE,OAAO,IAAI,0BAA0B,EAAE,MAAM,2BAA2B,CAAC;AAClF,OAAO,EAAE,OAAO,IAAI,uBAAuB,EAAE,MAAM,yBAAyB,CAAC;AAC7E,OAAO,EACL,OAAO,IAAI,gBAAgB,EAC3B,qBAAqB,GACtB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,OAAO,IAAI,wBAAwB,EAAE,MAAM,0BAA0B,CAAC;AAE/E,YAAY,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC"}
@@ -63,6 +63,6 @@ export function setupDispatch(config = {}) {
63
63
  export { default as dispatchAuthPlugin } from "./plugins/auth.js";
64
64
  export { default as dispatchIntegrationsPlugin } from "./plugins/integrations.js";
65
65
  export { default as dispatchAgentChatPlugin } from "./plugins/agent-chat.js";
66
- export { default as dispatchDbPlugin } from "./plugins/db.js";
66
+ export { default as dispatchDbPlugin, runDispatchMigrations, } from "./plugins/db.js";
67
67
  export { default as dispatchCoreRoutesPlugin } from "./plugins/core-routes.js";
68
68
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,sBAAsB,GAEvB,MAAM,2BAA2B,CAAC;AAEnC,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAGtD;;;;;;;;;GASG;AACH,sBAAsB,CAAC,eAAe,CAAC,CAAC;AAExC;;;;;GAKG;AACH,IAAI,YAAY,GAAmB,EAAE,CAAC;AAEtC,MAAM,UAAU,iBAAiB;IAC/B,OAAO,YAAY,CAAC;AACtB,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,MAAM,UAAU,aAAa,CAAC,MAAM,GAAmB,EAAE;IACvD,YAAY,GAAG,MAAM,CAAC,MAAM,CAAC,EAAE,GAAG,MAAM,EAAE,CAAC,CAAC;IAC5C,OAAO,CAAC,QAAQ,EAAE,EAAE;QAClB,KAAK,QAAQ,CAAC;IAChB,CAAC,CAAC;AACJ,CAAC;AAED,OAAO,EAAE,OAAO,IAAI,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAClE,OAAO,EAAE,OAAO,IAAI,0BAA0B,EAAE,MAAM,2BAA2B,CAAC;AAClF,OAAO,EAAE,OAAO,IAAI,uBAAuB,EAAE,MAAM,yBAAyB,CAAC;AAC7E,OAAO,EAAE,OAAO,IAAI,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAC9D,OAAO,EAAE,OAAO,IAAI,wBAAwB,EAAE,MAAM,0BAA0B,CAAC","sourcesContent":["import {\n registerPackageActions,\n type NitroPluginDef,\n} from \"@agent-native/core/server\";\n\nimport { dispatchActions } from \"../actions/index.js\";\nimport type { DispatchConfig } from \"../config.js\";\n\n/**\n * Register dispatch's package-contributed actions on import. The framework's\n * `autoDiscoverActions` merges these in after the consumer's local `actions/`\n * directory, so consumers can still override any single action by dropping\n * a same-named file in their own `actions/`.\n *\n * Side-effect import — placing it at module top means `import \"@agent-native/\n * dispatch/server\"` is enough to wire up actions, even before `setupDispatch`\n * is called.\n */\nregisterPackageActions(dispatchActions);\n\n/**\n * Internal config singleton — actions and plugins read from this so the\n * consumer's `setupDispatch(config)` call configures the whole package.\n *\n * Stored as a frozen snapshot to avoid accidental mid-request mutation.\n */\nlet activeConfig: DispatchConfig = {};\n\nexport function getDispatchConfig(): DispatchConfig {\n return activeConfig;\n}\n\n/**\n * Wire dispatch into a Nitro server. Returns a Nitro plugin that stamps the\n * active config so the named-export plugins below pick it up at request time.\n *\n * Typical consumer wiring (one config-stamp plugin + four re-exported\n * plugins, each in its own `server/plugins/<name>.ts` file so Nitro\n * auto-loads them):\n *\n * ```ts\n * // server/plugins/setup-dispatch.ts\n * import { setupDispatch } from \"@agent-native/dispatch/server\";\n * export default setupDispatch({ auth: { googleOnly: true } });\n *\n * // server/plugins/auth.ts\n * export { dispatchAuthPlugin as default } from \"@agent-native/dispatch/server\";\n *\n * // server/plugins/integrations.ts\n * export { dispatchIntegrationsPlugin as default } from \"@agent-native/dispatch/server\";\n *\n * // server/plugins/agent-chat.ts\n * export { dispatchAgentChatPlugin as default } from \"@agent-native/dispatch/server\";\n *\n * // server/plugins/db.ts\n * export { dispatchDbPlugin as default } from \"@agent-native/dispatch/server\";\n *\n * // server/plugins/core-routes.ts\n * export { dispatchCoreRoutesPlugin as default } from \"@agent-native/dispatch/server\";\n * ```\n *\n * The plugins read from the same `getDispatchConfig()` singleton this\n * function stamps, so plugin module-load order does not matter — they\n * resolve config when their plugin function runs, not at import time.\n */\nexport function setupDispatch(config: DispatchConfig = {}): NitroPluginDef {\n activeConfig = Object.freeze({ ...config });\n return (nitroApp) => {\n void nitroApp;\n };\n}\n\nexport { default as dispatchAuthPlugin } from \"./plugins/auth.js\";\nexport { default as dispatchIntegrationsPlugin } from \"./plugins/integrations.js\";\nexport { default as dispatchAgentChatPlugin } from \"./plugins/agent-chat.js\";\nexport { default as dispatchDbPlugin } from \"./plugins/db.js\";\nexport { default as dispatchCoreRoutesPlugin } from \"./plugins/core-routes.js\";\n\nexport type { DispatchConfig } from \"../config.js\";\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,sBAAsB,GAEvB,MAAM,2BAA2B,CAAC;AAEnC,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAGtD;;;;;;;;;GASG;AACH,sBAAsB,CAAC,eAAe,CAAC,CAAC;AAExC;;;;;GAKG;AACH,IAAI,YAAY,GAAmB,EAAE,CAAC;AAEtC,MAAM,UAAU,iBAAiB;IAC/B,OAAO,YAAY,CAAC;AACtB,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,MAAM,UAAU,aAAa,CAAC,MAAM,GAAmB,EAAE;IACvD,YAAY,GAAG,MAAM,CAAC,MAAM,CAAC,EAAE,GAAG,MAAM,EAAE,CAAC,CAAC;IAC5C,OAAO,CAAC,QAAQ,EAAE,EAAE;QAClB,KAAK,QAAQ,CAAC;IAChB,CAAC,CAAC;AACJ,CAAC;AAED,OAAO,EAAE,OAAO,IAAI,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAClE,OAAO,EAAE,OAAO,IAAI,0BAA0B,EAAE,MAAM,2BAA2B,CAAC;AAClF,OAAO,EAAE,OAAO,IAAI,uBAAuB,EAAE,MAAM,yBAAyB,CAAC;AAC7E,OAAO,EACL,OAAO,IAAI,gBAAgB,EAC3B,qBAAqB,GACtB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,OAAO,IAAI,wBAAwB,EAAE,MAAM,0BAA0B,CAAC","sourcesContent":["import {\n registerPackageActions,\n type NitroPluginDef,\n} from \"@agent-native/core/server\";\n\nimport { dispatchActions } from \"../actions/index.js\";\nimport type { DispatchConfig } from \"../config.js\";\n\n/**\n * Register dispatch's package-contributed actions on import. The framework's\n * `autoDiscoverActions` merges these in after the consumer's local `actions/`\n * directory, so consumers can still override any single action by dropping\n * a same-named file in their own `actions/`.\n *\n * Side-effect import — placing it at module top means `import \"@agent-native/\n * dispatch/server\"` is enough to wire up actions, even before `setupDispatch`\n * is called.\n */\nregisterPackageActions(dispatchActions);\n\n/**\n * Internal config singleton — actions and plugins read from this so the\n * consumer's `setupDispatch(config)` call configures the whole package.\n *\n * Stored as a frozen snapshot to avoid accidental mid-request mutation.\n */\nlet activeConfig: DispatchConfig = {};\n\nexport function getDispatchConfig(): DispatchConfig {\n return activeConfig;\n}\n\n/**\n * Wire dispatch into a Nitro server. Returns a Nitro plugin that stamps the\n * active config so the named-export plugins below pick it up at request time.\n *\n * Typical consumer wiring (one config-stamp plugin + four re-exported\n * plugins, each in its own `server/plugins/<name>.ts` file so Nitro\n * auto-loads them):\n *\n * ```ts\n * // server/plugins/setup-dispatch.ts\n * import { setupDispatch } from \"@agent-native/dispatch/server\";\n * export default setupDispatch({ auth: { googleOnly: true } });\n *\n * // server/plugins/auth.ts\n * export { dispatchAuthPlugin as default } from \"@agent-native/dispatch/server\";\n *\n * // server/plugins/integrations.ts\n * export { dispatchIntegrationsPlugin as default } from \"@agent-native/dispatch/server\";\n *\n * // server/plugins/agent-chat.ts\n * export { dispatchAgentChatPlugin as default } from \"@agent-native/dispatch/server\";\n *\n * // server/plugins/db.ts\n * export { dispatchDbPlugin as default } from \"@agent-native/dispatch/server\";\n *\n * // server/plugins/core-routes.ts\n * export { dispatchCoreRoutesPlugin as default } from \"@agent-native/dispatch/server\";\n * ```\n *\n * The plugins read from the same `getDispatchConfig()` singleton this\n * function stamps, so plugin module-load order does not matter — they\n * resolve config when their plugin function runs, not at import time.\n */\nexport function setupDispatch(config: DispatchConfig = {}): NitroPluginDef {\n activeConfig = Object.freeze({ ...config });\n return (nitroApp) => {\n void nitroApp;\n };\n}\n\nexport { default as dispatchAuthPlugin } from \"./plugins/auth.js\";\nexport { default as dispatchIntegrationsPlugin } from \"./plugins/integrations.js\";\nexport { default as dispatchAgentChatPlugin } from \"./plugins/agent-chat.js\";\nexport {\n default as dispatchDbPlugin,\n runDispatchMigrations,\n} from \"./plugins/db.js\";\nexport { default as dispatchCoreRoutesPlugin } from \"./plugins/core-routes.js\";\n\nexport type { DispatchConfig } from \"../config.js\";\n"]}
@@ -1,3 +1,4 @@
1
+ export declare const runDispatchMigrations: (nitroApp: any) => void | Promise<void>;
1
2
  export default _default;
2
3
  /**
3
4
  * Run dispatch's own migrations first (this is what guarantees
@@ -1 +1 @@
1
- {"version":3,"file":"db.d.ts","sourceRoot":"","sources":["../../../src/server/plugins/db.ts"],"names":[],"mappings":";AASA;;;;;;GAMG;0BACmB,QAAQ,EAAE,GAAG"}
1
+ {"version":3,"file":"db.d.ts","sourceRoot":"","sources":["../../../src/server/plugins/db.ts"],"names":[],"mappings":"AAKA,eAAO,MAAM,qBAAqB,yCAEhC,CAAC;;AAEH;;;;;;GAMG;0BACmB,QAAQ,EAAE,GAAG"}
@@ -1,7 +1,7 @@
1
1
  import { runMigrations } from "@agent-native/core/db";
2
2
  import { dispatchMigrations } from "../../db/migrations.js";
3
3
  import { scheduleVaultBootResync } from "../lib/vault-boot-resync.js";
4
- const runDispatchMigrations = runMigrations(dispatchMigrations, {
4
+ export const runDispatchMigrations = runMigrations(dispatchMigrations, {
5
5
  table: "dispatch_migrations",
6
6
  });
7
7
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"db.js","sourceRoot":"","sources":["../../../src/server/plugins/db.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAEtD,OAAO,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAC5D,OAAO,EAAE,uBAAuB,EAAE,MAAM,6BAA6B,CAAC;AAEtE,MAAM,qBAAqB,GAAG,aAAa,CAAC,kBAAkB,EAAE;IAC9D,KAAK,EAAE,qBAAqB;CAC7B,CAAC,CAAC;AAEH;;;;;;GAMG;AACH,eAAe,KAAK,EAAE,QAAa,EAAE,EAAE;IACrC,MAAM,qBAAqB,CAAC,QAAQ,CAAC,CAAC;IACtC,uBAAuB,EAAE,CAAC;AAC5B,CAAC,CAAC","sourcesContent":["import { runMigrations } from \"@agent-native/core/db\";\n\nimport { dispatchMigrations } from \"../../db/migrations.js\";\nimport { scheduleVaultBootResync } from \"../lib/vault-boot-resync.js\";\n\nconst runDispatchMigrations = runMigrations(dispatchMigrations, {\n table: \"dispatch_migrations\",\n});\n\n/**\n * Run dispatch's own migrations first (this is what guarantees\n * `vault_secrets` exists), then kick off the vault boot resync. The resync\n * itself waits several more seconds before touching the DB — see\n * vault-boot-resync.ts — so this ordering is a belt-and-suspenders\n * guarantee, not a hard dependency.\n */\nexport default async (nitroApp: any) => {\n await runDispatchMigrations(nitroApp);\n scheduleVaultBootResync();\n};\n"]}
1
+ {"version":3,"file":"db.js","sourceRoot":"","sources":["../../../src/server/plugins/db.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAEtD,OAAO,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAC5D,OAAO,EAAE,uBAAuB,EAAE,MAAM,6BAA6B,CAAC;AAEtE,MAAM,CAAC,MAAM,qBAAqB,GAAG,aAAa,CAAC,kBAAkB,EAAE;IACrE,KAAK,EAAE,qBAAqB;CAC7B,CAAC,CAAC;AAEH;;;;;;GAMG;AACH,eAAe,KAAK,EAAE,QAAa,EAAE,EAAE;IACrC,MAAM,qBAAqB,CAAC,QAAQ,CAAC,CAAC;IACtC,uBAAuB,EAAE,CAAC;AAC5B,CAAC,CAAC","sourcesContent":["import { runMigrations } from \"@agent-native/core/db\";\n\nimport { dispatchMigrations } from \"../../db/migrations.js\";\nimport { scheduleVaultBootResync } from \"../lib/vault-boot-resync.js\";\n\nexport const runDispatchMigrations = runMigrations(dispatchMigrations, {\n table: \"dispatch_migrations\",\n});\n\n/**\n * Run dispatch's own migrations first (this is what guarantees\n * `vault_secrets` exists), then kick off the vault boot resync. The resync\n * itself waits several more seconds before touching the DB — see\n * vault-boot-resync.ts — so this ordering is a belt-and-suspenders\n * guarantee, not a hard dependency.\n */\nexport default async (nitroApp: any) => {\n await runDispatchMigrations(nitroApp);\n scheduleVaultBootResync();\n};\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agent-native/dispatch",
3
- "version": "0.20.2",
3
+ "version": "0.20.4",
4
4
  "description": "Dispatch — workspace control plane for agent-native apps. Vault, integrations, destinations, scheduled jobs, and cross-app delegation, shipped as a single drop-in package.",
5
5
  "homepage": "https://github.com/BuilderIO/agent-native#readme",
6
6
  "bugs": {
@@ -84,7 +84,7 @@
84
84
  "tailwind-merge": "^3.5.0",
85
85
  "vaul": "^1.1.2",
86
86
  "zod": "^4.3.6",
87
- "@agent-native/toolkit": "0.13.4"
87
+ "@agent-native/toolkit": "0.13.5"
88
88
  },
89
89
  "devDependencies": {
90
90
  "@react-router/dev": "^8.1.0",
@@ -98,7 +98,7 @@
98
98
  "typescript-7": "npm:typescript@^7.0.2",
99
99
  "vite": "8.1.0",
100
100
  "vitest": "^4.1.5",
101
- "@agent-native/core": "0.146.1"
101
+ "@agent-native/core": "0.146.4"
102
102
  },
103
103
  "peerDependencies": {
104
104
  "@agent-native/core": ">=0.8.0",
@@ -84,6 +84,7 @@ export function AutomationRunHistoryDialog({
84
84
  {
85
85
  name: automation?.name ?? "",
86
86
  scope,
87
+ appId: automation?.appId ?? "dispatch",
87
88
  },
88
89
  {
89
90
  enabled: open && Boolean(automation),
@@ -7,6 +7,7 @@ import {
7
7
  automationStatus,
8
8
  automationTarget,
9
9
  automationTroubleshootPath,
10
+ belongsToDispatch,
10
11
  sortAutomations,
11
12
  } from "./automation-display.js";
12
13
  import type { DispatchAutomationItem } from "./automations.js";
@@ -34,6 +35,12 @@ describe("automation-display", () => {
34
35
  ).toBe("/admin/thread-debug?query=coach+onboarding+reminder");
35
36
  });
36
37
 
38
+ it("keeps Dispatch-owned and legacy automations in the default view", () => {
39
+ expect(belongsToDispatch({})).toBe(true);
40
+ expect(belongsToDispatch({ appId: "dispatch" })).toBe(true);
41
+ expect(belongsToDispatch({ appId: "mail" })).toBe(false);
42
+ });
43
+
37
44
  it("prefers event names, then schedule descriptions", () => {
38
45
  expect(
39
46
  automationTarget(
@@ -13,6 +13,17 @@ export function automationIdentity(
13
13
  return `${item.owner}:${item.path}`;
14
14
  }
15
15
 
16
+ /**
17
+ * Dispatch is the workspace-wide surface. Keep legacy resources without an
18
+ * app owner visible in its default view while making an explicit app owner
19
+ * opt into the global filter.
20
+ */
21
+ export function belongsToDispatch(
22
+ item: Pick<DispatchAutomationItem, "appId">,
23
+ ): boolean {
24
+ return !item.appId || item.appId === "dispatch";
25
+ }
26
+
16
27
  export function automationTroubleshootPath(
17
28
  item: Pick<DispatchAutomationItem, "name">,
18
29
  ): string {
@@ -5,6 +5,7 @@ export interface DispatchAutomationItem {
5
5
  name: string;
6
6
  path: string;
7
7
  owner: string;
8
+ appId?: string;
8
9
  scope?: "personal" | "organization";
9
10
  canUpdate?: boolean;
10
11
  triggerType?: "schedule" | "event" | string;
@@ -21,6 +21,13 @@ import {
21
21
  PopoverContent,
22
22
  PopoverTrigger,
23
23
  } from "../../components/ui/popover";
24
+ import {
25
+ Select,
26
+ SelectContent,
27
+ SelectItem,
28
+ SelectTrigger,
29
+ SelectValue,
30
+ } from "../../components/ui/select";
24
31
  import { Skeleton } from "../../components/ui/skeleton";
25
32
  import { Switch } from "../../components/ui/switch";
26
33
  import {
@@ -32,6 +39,7 @@ import {
32
39
  automationStatus,
33
40
  automationTarget,
34
41
  automationTroubleshootPath,
42
+ belongsToDispatch,
35
43
  sortAutomations,
36
44
  type AutomationStatusTone,
37
45
  } from "../../lib/automation-display";
@@ -179,14 +187,25 @@ function CreateAutomationButton() {
179
187
  }
180
188
 
181
189
  export default function AutomationsRoute() {
190
+ const [view, setView] = useState<"dispatch" | "all">("dispatch");
182
191
  const [detailsTarget, setDetailsTarget] =
183
192
  useState<DispatchAutomationItem | null>(null);
184
193
  const automationsQuery = useAutomations();
185
194
  const toggleAutomation = useToggleAutomation();
186
195
  const automations = automationsQuery.data ?? [];
187
- const ordered = useMemo(() => sortAutomations(automations), [automations]);
188
- const enabledCount = automations.filter((item) => item.enabled).length;
189
- const errorCount = automations.filter(
196
+ const visibleAutomations = useMemo(
197
+ () =>
198
+ view === "all"
199
+ ? automations
200
+ : automations.filter((item) => belongsToDispatch(item)),
201
+ [automations, view],
202
+ );
203
+ const ordered = useMemo(
204
+ () => sortAutomations(visibleAutomations),
205
+ [visibleAutomations],
206
+ );
207
+ const enabledCount = visibleAutomations.filter((item) => item.enabled).length;
208
+ const errorCount = visibleAutomations.filter(
190
209
  (item) =>
191
210
  item.enabled &&
192
211
  (item.lastStatus === "error" || item.lastStatus === "skipped"),
@@ -211,7 +230,26 @@ export default function AutomationsRoute() {
211
230
  {errorCount > 0 ? ` · ${errorCount} errors` : ""}
212
231
  </span>
213
232
  </div>
214
- <CreateAutomationButton />
233
+ <div className="flex flex-wrap items-center justify-end gap-2">
234
+ <Select
235
+ value={view}
236
+ onValueChange={(value) => {
237
+ if (value === "dispatch" || value === "all") setView(value);
238
+ }}
239
+ >
240
+ <SelectTrigger
241
+ className="h-8 w-[10.5rem] text-xs"
242
+ aria-label="Automation view"
243
+ >
244
+ <SelectValue />
245
+ </SelectTrigger>
246
+ <SelectContent>
247
+ <SelectItem value="dispatch">Dispatch automations</SelectItem>
248
+ <SelectItem value="all">All apps</SelectItem>
249
+ </SelectContent>
250
+ </Select>
251
+ <CreateAutomationButton />
252
+ </div>
215
253
  </div>
216
254
 
217
255
  <div className="divide-y rounded-lg bg-card">
@@ -306,8 +344,9 @@ export default function AutomationsRoute() {
306
344
  })
307
345
  ) : (
308
346
  <div className="px-4 py-10 text-center text-sm text-muted-foreground">
309
- No automations yet. Create one here, or ask Dispatch to set up a
310
- scheduled or event-triggered job.
347
+ {view === "all"
348
+ ? "No automations yet. Create one here, or ask Dispatch to set up a scheduled or event-triggered job."
349
+ : "No Dispatch automations yet. Switch to All apps to inspect workspace automations."}
311
350
  </div>
312
351
  )}
313
352
  </div>
@@ -73,7 +73,10 @@ export function setupDispatch(config: DispatchConfig = {}): NitroPluginDef {
73
73
  export { default as dispatchAuthPlugin } from "./plugins/auth.js";
74
74
  export { default as dispatchIntegrationsPlugin } from "./plugins/integrations.js";
75
75
  export { default as dispatchAgentChatPlugin } from "./plugins/agent-chat.js";
76
- export { default as dispatchDbPlugin } from "./plugins/db.js";
76
+ export {
77
+ default as dispatchDbPlugin,
78
+ runDispatchMigrations,
79
+ } from "./plugins/db.js";
77
80
  export { default as dispatchCoreRoutesPlugin } from "./plugins/core-routes.js";
78
81
 
79
82
  export type { DispatchConfig } from "../config.js";
@@ -3,7 +3,7 @@ import { runMigrations } from "@agent-native/core/db";
3
3
  import { dispatchMigrations } from "../../db/migrations.js";
4
4
  import { scheduleVaultBootResync } from "../lib/vault-boot-resync.js";
5
5
 
6
- const runDispatchMigrations = runMigrations(dispatchMigrations, {
6
+ export const runDispatchMigrations = runMigrations(dispatchMigrations, {
7
7
  table: "dispatch_migrations",
8
8
  });
9
9