@agent-native/dispatch 0.14.2 → 0.14.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.
- package/README.md +114 -122
- package/dist/actions/approve-dispatch-change.d.ts +10 -10
- package/dist/actions/list_apps.d.ts +1 -0
- package/dist/actions/list_apps.js +16 -8
- package/dist/actions/list_apps.js.map +1 -1
- package/dist/actions/provider-api-register.js +64 -2
- package/dist/actions/provider-api-register.js.map +1 -1
- package/dist/actions/reject-dispatch-change.d.ts +10 -10
- package/dist/actions/set-mcp-app-access.js +1 -4
- package/dist/actions/set-mcp-app-access.js.map +1 -1
- package/dist/components/action-query-error.d.ts +8 -0
- package/dist/components/action-query-error.d.ts.map +1 -0
- package/dist/components/action-query-error.js +10 -0
- package/dist/components/action-query-error.js.map +1 -0
- package/dist/components/app-keys-popover.d.ts +4 -0
- package/dist/components/app-keys-popover.d.ts.map +1 -1
- package/dist/components/app-keys-popover.js +26 -14
- package/dist/components/app-keys-popover.js.map +1 -1
- package/dist/components/dispatch-control-plane.d.ts.map +1 -1
- package/dist/components/dispatch-control-plane.js +31 -27
- package/dist/components/dispatch-control-plane.js.map +1 -1
- package/dist/components/index.d.ts +1 -0
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/index.js +1 -0
- package/dist/components/index.js.map +1 -1
- package/dist/components/layout/Layout.d.ts +1 -0
- package/dist/components/layout/Layout.d.ts.map +1 -1
- package/dist/components/layout/Layout.js +19 -21
- package/dist/components/layout/Layout.js.map +1 -1
- package/dist/components/ui/sheet.js +1 -1
- package/dist/components/ui/sheet.js.map +1 -1
- package/dist/components/ui/toast.js +1 -1
- package/dist/components/ui/toast.js.map +1 -1
- package/dist/components/workspace-app-card.d.ts.map +1 -1
- package/dist/components/workspace-app-card.js +8 -5
- package/dist/components/workspace-app-card.js.map +1 -1
- package/dist/components/workspace-resource-effective-stack.d.ts.map +1 -1
- package/dist/components/workspace-resource-effective-stack.js +6 -1
- package/dist/components/workspace-resource-effective-stack.js.map +1 -1
- package/dist/components/workspace-resource-impact-preview.d.ts.map +1 -1
- package/dist/components/workspace-resource-impact-preview.js +6 -1
- package/dist/components/workspace-resource-impact-preview.js.map +1 -1
- package/dist/routes/pages/$appId.d.ts.map +1 -1
- package/dist/routes/pages/$appId.js +6 -1
- package/dist/routes/pages/$appId.js.map +1 -1
- package/dist/routes/pages/agents.d.ts.map +1 -1
- package/dist/routes/pages/agents.js +5 -8
- package/dist/routes/pages/agents.js.map +1 -1
- package/dist/routes/pages/approval.d.ts.map +1 -1
- package/dist/routes/pages/approval.js +6 -1
- package/dist/routes/pages/approval.js.map +1 -1
- package/dist/routes/pages/approvals.d.ts.map +1 -1
- package/dist/routes/pages/approvals.js +8 -5
- package/dist/routes/pages/approvals.js.map +1 -1
- package/dist/routes/pages/apps.$appId.d.ts.map +1 -1
- package/dist/routes/pages/apps.$appId.js +4 -2
- package/dist/routes/pages/apps.$appId.js.map +1 -1
- package/dist/routes/pages/apps.d.ts.map +1 -1
- package/dist/routes/pages/apps.js +9 -3
- package/dist/routes/pages/apps.js.map +1 -1
- package/dist/routes/pages/audit.d.ts.map +1 -1
- package/dist/routes/pages/audit.js +4 -2
- package/dist/routes/pages/audit.js.map +1 -1
- package/dist/routes/pages/chat.d.ts.map +1 -1
- package/dist/routes/pages/chat.js +16 -2
- package/dist/routes/pages/chat.js.map +1 -1
- package/dist/routes/pages/destinations.d.ts.map +1 -1
- package/dist/routes/pages/destinations.js +5 -3
- package/dist/routes/pages/destinations.js.map +1 -1
- package/dist/routes/pages/identities.d.ts.map +1 -1
- package/dist/routes/pages/identities.js +5 -3
- package/dist/routes/pages/identities.js.map +1 -1
- package/dist/routes/pages/integrations.d.ts.map +1 -1
- package/dist/routes/pages/integrations.js +9 -3
- package/dist/routes/pages/integrations.js.map +1 -1
- package/dist/routes/pages/thread-debug.d.ts.map +1 -1
- package/dist/routes/pages/thread-debug.js +7 -6
- package/dist/routes/pages/thread-debug.js.map +1 -1
- package/dist/routes/pages/vault.d.ts.map +1 -1
- package/dist/routes/pages/vault.js +23 -7
- package/dist/routes/pages/vault.js.map +1 -1
- package/dist/routes/pages/workspace.d.ts.map +1 -1
- package/dist/routes/pages/workspace.js +9 -3
- package/dist/routes/pages/workspace.js.map +1 -1
- package/dist/server/lib/dispatch-store.d.ts +24 -21
- package/dist/server/lib/dispatch-store.d.ts.map +1 -1
- package/dist/server/lib/dispatch-store.js +59 -23
- package/dist/server/lib/dispatch-store.js.map +1 -1
- package/dist/server/lib/mcp-access-store.d.ts.map +1 -1
- package/dist/server/lib/mcp-access-store.js +30 -2
- package/dist/server/lib/mcp-access-store.js.map +1 -1
- package/dist/server/lib/vault-store.d.ts.map +1 -1
- package/dist/server/lib/vault-store.js +102 -37
- package/dist/server/lib/vault-store.js.map +1 -1
- package/dist/server/plugins/agent-chat.d.ts +1 -1
- package/package.json +2 -3
- package/src/actions/list_apps.spec.ts +52 -0
- package/src/actions/list_apps.ts +16 -8
- package/src/actions/provider-api-register.spec.ts +193 -0
- package/src/actions/provider-api-register.ts +66 -1
- package/src/actions/set-mcp-app-access.spec.ts +73 -0
- package/src/actions/set-mcp-app-access.ts +1 -5
- package/src/components/action-query-error.spec.tsx +56 -0
- package/src/components/action-query-error.tsx +32 -0
- package/src/components/app-keys-popover.spec.tsx +85 -0
- package/src/components/app-keys-popover.tsx +76 -50
- package/src/components/dispatch-control-plane.spec.tsx +106 -0
- package/src/components/dispatch-control-plane.tsx +71 -115
- package/src/components/index.ts +1 -0
- package/src/components/layout/Layout.spec.tsx +42 -2
- package/src/components/layout/Layout.tsx +22 -27
- package/src/components/ui/sheet.tsx +1 -1
- package/src/components/ui/toast.tsx +1 -1
- package/src/components/workspace-app-card.spec.tsx +80 -0
- package/src/components/workspace-app-card.tsx +36 -25
- package/src/components/workspace-resource-effective-stack.tsx +13 -1
- package/src/components/workspace-resource-impact-preview.tsx +12 -1
- package/src/routes/pages/$appId.tsx +17 -1
- package/src/routes/pages/agents.tsx +24 -11
- package/src/routes/pages/approval.tsx +16 -4
- package/src/routes/pages/approvals.tsx +108 -89
- package/src/routes/pages/apps.$appId.tsx +9 -2
- package/src/routes/pages/apps.tsx +20 -7
- package/src/routes/pages/audit.tsx +29 -20
- package/src/routes/pages/chat.spec.tsx +94 -0
- package/src/routes/pages/chat.tsx +30 -10
- package/src/routes/pages/destinations.tsx +75 -62
- package/src/routes/pages/identities.tsx +74 -63
- package/src/routes/pages/integrations.tsx +17 -10
- package/src/routes/pages/thread-debug.tsx +18 -12
- package/src/routes/pages/vault.tsx +59 -26
- package/src/routes/pages/workspace.tsx +69 -55
- package/src/server/lib/approval-fencing.spec.ts +420 -0
- package/src/server/lib/dispatch-store.ts +94 -21
- package/src/server/lib/mcp-access-store.spec.ts +116 -4
- package/src/server/lib/mcp-access-store.ts +37 -2
- package/src/server/lib/mcp-gateway.spec.ts +79 -3
- package/src/server/lib/vault-store.ts +151 -45
package/README.md
CHANGED
|
@@ -1,140 +1,132 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @agent-native/dispatch
|
|
2
|
+
|
|
3
|
+
Workspace control plane for agent-native apps — vault, integrations,
|
|
4
|
+
destinations, cross-app workspace resources, recurring "dream" report jobs,
|
|
5
|
+
and cross-app delegation, shipped as a single drop-in package.
|
|
6
|
+
|
|
7
|
+
Powers the `dispatch` template. Provides:
|
|
8
|
+
|
|
9
|
+
- **Drizzle schemas** — destinations, identity links, link tokens, approval
|
|
10
|
+
requests, audit events, dream reports/proposals, vault secrets/grants/
|
|
11
|
+
requests/audit, workspace resources/grants
|
|
12
|
+
- **Server layer** — `setupDispatch(config)` plus Nitro plugins for auth,
|
|
13
|
+
integrations, agent chat, DB, and core routes
|
|
14
|
+
- **Actions** — ~90 `defineAction` modules (vault grants/requests, workspace
|
|
15
|
+
resource grants, destinations, dream jobs, provider-api catalog/docs/
|
|
16
|
+
request, connected-agent discovery, audit/approvals, platform messaging,
|
|
17
|
+
and more) consumed as agent tools + HTTP endpoints
|
|
18
|
+
- **Routes** — a full React Router 7 `RouteConfig[]` (chat, overview, apps,
|
|
19
|
+
vault, integrations, agents, workspace, messaging, destinations,
|
|
20
|
+
identities, approvals, automations, audit, settings, dreams, extensions,
|
|
21
|
+
...) to splat into a consumer's `app/routes.ts`
|
|
22
|
+
- **React components** — `DispatchShell`, `Layout`/`NavContent`,
|
|
23
|
+
`CreateAppPopover`/`CreateAppFlow`, `AppKeysPopover`, plus a full
|
|
24
|
+
shadcn/ui-based `components/ui/*` primitive set
|
|
25
|
+
- **Styles** — `dispatch.css` Tailwind layer
|
|
26
|
+
|
|
27
|
+
## Install
|
|
2
28
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
Agent-Native is an open-source framework for rapidly building robust applications with agents at their core.
|
|
6
|
-
|
|
7
|
-
```ts
|
|
8
|
-
// One action powers every app surface: UI, agent, HTTP, MCP, A2A, and CLI.
|
|
9
|
-
export default defineAction({
|
|
10
|
-
schema: z.object({
|
|
11
|
-
emailId: z.string(),
|
|
12
|
-
body: z.string(),
|
|
13
|
-
}),
|
|
14
|
-
run: async ({ emailId, body }) => {
|
|
15
|
-
await db.insert(replies).values({ emailId, body });
|
|
16
|
-
},
|
|
17
|
-
});
|
|
29
|
+
```bash
|
|
30
|
+
pnpm add @agent-native/dispatch
|
|
18
31
|
```
|
|
19
32
|
|
|
20
|
-
-
|
|
21
|
-
|
|
22
|
-
- **[Backend agnostic](https://agent-native.com/docs/database)**: Plug in any Drizzle-supported SQL database and Nitro-compatible host.
|
|
23
|
-
- **[Toolkits](https://agent-native.com/docs/agent-native-toolkit)**: Reusable building blocks for collaboration, sharing, settings, teams, and observability.
|
|
24
|
-
|
|
25
|
-
## Don't pick between apps or agents.
|
|
26
|
-
|
|
27
|
-
Agent-native apps are both
|
|
28
|
-
|
|
29
|
-
| | SaaS Tools | Raw AI Agents | Internal Tools | Agent-Native App |
|
|
30
|
-
| ----------------- | ------------------ | ----------------------- | -------------------------- | ----------------------- |
|
|
31
|
-
| **UI** | Polished but rigid | None | Mixed quality | Full UI, fork & go |
|
|
32
|
-
| **AI** | Bolted on | Powerful | Shallowly connected | Agent-first, integrated |
|
|
33
|
-
| **Customization** | Can't | Instructions and skills | Full, but high maintenance | Agent modifies the app |
|
|
34
|
-
| **Ownership** | Rented | Somewhat yours | You own the code | You own the code |
|
|
35
|
-
|
|
36
|
-
## Try an Agent-Native app
|
|
37
|
-
|
|
38
|
-
Fork a working app and let the agent evolve it. **You can customize everything.**
|
|
39
|
-
|
|
40
|
-
<table>
|
|
41
|
-
<tr>
|
|
42
|
-
<td width="33%" align="center" valign="top">
|
|
43
|
-
|
|
44
|
-
**Clips**
|
|
45
|
-
|
|
46
|
-
<a href="https://agent-native.com/templates/clips"><img src="https://cdn.builder.io/api/v1/image/assets%2FYJIGb4i01jvw0SRdL5Bt%2F189ebd9b2f2b4f0ead3b33138d4e4c10?format=webp&width=800" alt="Clips app" width="100%" /></a>
|
|
47
|
-
|
|
48
|
-
**Agent-Native Loom**
|
|
49
|
-
|
|
50
|
-
Record your screen with auto-transcripts and captured browser debug logs, share a link, and let an agent read the transcript, see timestamped frames, and fix the bug.
|
|
51
|
-
|
|
52
|
-
</td>
|
|
53
|
-
<td width="33%" align="center" valign="top">
|
|
54
|
-
|
|
55
|
-
**Plans**
|
|
56
|
-
|
|
57
|
-
<a href="https://agent-native.com/templates/plan"><img src="https://cdn.builder.io/api/v1/image/assets%2FYJIGb4i01jvw0SRdL5Bt%2Fefc6a3ac908149fa92e2b9392c0bb372?format=webp&width=800" alt="Plans app" width="100%" /></a>
|
|
58
|
-
|
|
59
|
-
**Visual plan mode for coding agents**
|
|
60
|
-
|
|
61
|
-
Install `/visual-plan` and `/visual-recap` so your coding agent can plan before it builds and recap changes after they land. High-level code reviews with diagrams, wireframes, annotations, and review links.
|
|
62
|
-
|
|
63
|
-
</td>
|
|
64
|
-
<td width="33%" align="center" valign="top">
|
|
65
|
-
|
|
66
|
-
**Design**
|
|
67
|
-
|
|
68
|
-
<a href="https://agent-native.com/templates/design"><img src="https://cdn.builder.io/api/v1/image/assets%2FYJIGb4i01jvw0SRdL5Bt%2Fe2c86908c2fa4f119ee4aa90b4823944?format=webp&width=800" alt="Design app" width="100%" /></a>
|
|
33
|
+
Peer-depends on `@agent-native/core` (`>=0.8.0`), `react`/`react-dom`
|
|
34
|
+
(`>=19.2.7`), and `react-router` (`>=8`).
|
|
69
35
|
|
|
70
|
-
|
|
36
|
+
## Compose
|
|
71
37
|
|
|
72
|
-
|
|
38
|
+
Template's `app/routes.ts`:
|
|
73
39
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
<td width="33%" align="center" valign="top">
|
|
78
|
-
|
|
79
|
-
**Content**
|
|
80
|
-
|
|
81
|
-
<a href="https://agent-native.com/templates/content"><img src="https://cdn.builder.io/api/v1/image/assets%2FYJIGb4i01jvw0SRdL5Bt%2F89bcfc6106304bfbaf8ec8a7ccd721eb?format=webp&width=800" alt="Content app" width="100%" /></a>
|
|
82
|
-
|
|
83
|
-
**Agent-Native Notion/Obsidian**
|
|
84
|
-
|
|
85
|
-
Edit local Markdown/MDX files, generate rich interactive custom blocks, and draft, rewrite, or publish with an agent.
|
|
86
|
-
|
|
87
|
-
</td>
|
|
88
|
-
<td width="33%" align="center" valign="top">
|
|
89
|
-
|
|
90
|
-
**Analytics**
|
|
91
|
-
|
|
92
|
-
<a href="https://agent-native.com/templates/analytics"><img src="https://cdn.builder.io/api/v1/image/assets%2FYJIGb4i01jvw0SRdL5Bt%2F4933a80cc3134d7e874631f688be828a?format=webp&width=800" alt="Analytics app" width="100%" /></a>
|
|
93
|
-
|
|
94
|
-
**Agent-Native Amplitude, Fullstory**
|
|
95
|
-
|
|
96
|
-
Connect analytics data sources, prompt for real charts, and build reusable dashboards.
|
|
97
|
-
|
|
98
|
-
</td>
|
|
99
|
-
<td width="33%" align="center" valign="top">
|
|
100
|
-
|
|
101
|
-
**Chat**
|
|
40
|
+
```ts
|
|
41
|
+
import { type RouteConfig } from "@react-router/dev/routes";
|
|
42
|
+
import { dispatchRoutes } from "@agent-native/dispatch/routes";
|
|
102
43
|
|
|
103
|
-
|
|
44
|
+
export default [
|
|
45
|
+
...localRoutes, // consumer's own routes win on collision
|
|
46
|
+
...dispatchRoutes, // dispatch fills in everything else
|
|
47
|
+
] satisfies RouteConfig;
|
|
48
|
+
```
|
|
104
49
|
|
|
105
|
-
|
|
50
|
+
Template's `server/plugins/*.ts` (each export lives in its own file so Nitro
|
|
51
|
+
auto-loads it):
|
|
106
52
|
|
|
107
|
-
|
|
53
|
+
```ts
|
|
54
|
+
// server/plugins/setup-dispatch.ts
|
|
55
|
+
import { setupDispatch } from "@agent-native/dispatch/server";
|
|
56
|
+
export default setupDispatch({ auth: { googleOnly: true } });
|
|
108
57
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
</table>
|
|
58
|
+
// server/plugins/auth.ts
|
|
59
|
+
export { dispatchAuthPlugin as default } from "@agent-native/dispatch/server";
|
|
112
60
|
|
|
113
|
-
|
|
61
|
+
// server/plugins/integrations.ts
|
|
62
|
+
export { dispatchIntegrationsPlugin as default } from "@agent-native/dispatch/server";
|
|
114
63
|
|
|
115
|
-
|
|
64
|
+
// server/plugins/agent-chat.ts
|
|
65
|
+
export { dispatchAgentChatPlugin as default } from "@agent-native/dispatch/server";
|
|
116
66
|
|
|
117
|
-
|
|
67
|
+
// server/plugins/db.ts
|
|
68
|
+
export { dispatchDbPlugin as default } from "@agent-native/dispatch/server";
|
|
118
69
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
cd my-app
|
|
122
|
-
pnpm install
|
|
123
|
-
pnpm dev
|
|
70
|
+
// server/plugins/core-routes.ts
|
|
71
|
+
export { dispatchCoreRoutesPlugin as default } from "@agent-native/dispatch/server";
|
|
124
72
|
```
|
|
125
73
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
See the full [getting started docs](https://agent-native.com/docs).
|
|
129
|
-
|
|
130
|
-
## Community
|
|
74
|
+
Template's `server/db/schema.ts`:
|
|
131
75
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
Full documentation at **[agent-native.com](https://agent-native.com)**.
|
|
137
|
-
|
|
138
|
-
## License
|
|
76
|
+
```ts
|
|
77
|
+
export * from "@agent-native/dispatch/db";
|
|
78
|
+
```
|
|
139
79
|
|
|
140
|
-
|
|
80
|
+
`@agent-native/dispatch/actions` doesn't need a manual import for most
|
|
81
|
+
consumers: `import "@agent-native/dispatch/server"` (pulled in by the plugin
|
|
82
|
+
wiring above) side-effect-registers every Dispatch action via
|
|
83
|
+
`registerPackageActions`, and the framework's `autoDiscoverActions` merges
|
|
84
|
+
them in after the consumer's local `actions/` directory. Drop a same-named
|
|
85
|
+
file in the consumer's own `actions/` to override any single action.
|
|
86
|
+
|
|
87
|
+
## Exports
|
|
88
|
+
|
|
89
|
+
| Subpath | What it is |
|
|
90
|
+
| ---------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
91
|
+
| `.` | Shared config types only — `DispatchConfig`, `DispatchAuthConfig`, `DispatchIntegrationsConfig`. Import this where a type is needed without pulling in server/client code. |
|
|
92
|
+
| `./routes` | `dispatchRoutes` — a programmatic `RouteConfig[]` covering every Dispatch page (chat, overview, metrics, operations, apps, vault, integrations, agents, workspace, messaging, destinations, identities, approvals, automations, audit, settings, dreams, extensions, thread-debug, team, and a workspace-app catch-all route). |
|
|
93
|
+
| `./routes/pages/*` | Individual compiled page modules the routes above point at (e.g. `./routes/pages/vault.js`). Not normally imported directly. |
|
|
94
|
+
| `./server` | `setupDispatch(config)` plus the Nitro plugin set: `dispatchAuthPlugin`, `dispatchIntegrationsPlugin`, `dispatchAgentChatPlugin`, `dispatchDbPlugin`, `dispatchCoreRoutesPlugin`. Importing this module also side-effect-registers all Dispatch actions. |
|
|
95
|
+
| `./server/lib/thread-link-preview` | `loadThreadLinkPreview(threadId)` — server-only helper (reads request context and checks thread ownership) that builds link-preview metadata for shared thread URLs. |
|
|
96
|
+
| `./actions` | `dispatchActions` — the flat name → `ActionEntry` map of every Dispatch action (vault, workspace resources, destinations, dream jobs, provider-api catalog/docs/request, connected agents, audit, approvals, platform messaging, and more). |
|
|
97
|
+
| `./db` | `getDb()` / `db()`, the Drizzle `schema` namespace, the Dispatch table exports (`dispatchDestinations`, `dispatchIdentityLinks`, `dispatchLinkTokens`, `dispatchApprovalRequests`, `dispatchAuditEvents`, `dispatchDreams`, `dispatchDreamProposals`, `vaultSecrets`, `vaultGrants`, `vaultRequests`, `vaultAuditLog`, `workspaceResources`, `workspaceResourceGrants`), and migrations. |
|
|
98
|
+
| `./lib/thread-link-preview` | Isomorphic helpers behind the server one above — `extractThreadPreviewImageUrl`, `buildThreadLinkPreviewMeta`, and the `ThreadLinkPreview` type. Safe to import from client code. |
|
|
99
|
+
| `./components` | Escape-hatch UI pieces for custom layouts: `DispatchShell`, `Layout`/`NavContent` (plus `DispatchExtensionConfig`/`DispatchNavIcon`/`DispatchNavItem`/`DispatchNavSection` types), `CreateAppPopover`/`CreateAppFlow`, `AppKeysPopover`. Most consumers only need `dispatchRoutes` and never import from here directly. |
|
|
100
|
+
| `./components/ui/*` | The shadcn/ui primitive set Dispatch's own UI is built on (`button`, `dialog`, `dropdown-menu`, `card`, `command`, `calendar`, `chart`, ...), exported per-file so a consumer can reuse one primitive without pulling in the rest. |
|
|
101
|
+
| `./styles/dispatch.css` | Tailwind layer with Dispatch-specific styles. Import once in the consumer's global CSS entry. |
|
|
102
|
+
|
|
103
|
+
## What it's for
|
|
104
|
+
|
|
105
|
+
Dispatch is the workspace control plane sitting above individual template
|
|
106
|
+
apps:
|
|
107
|
+
|
|
108
|
+
- **Vault** — shared workspace secrets with a request → grant → audit flow,
|
|
109
|
+
scoped per app.
|
|
110
|
+
- **Workspace resources** — cross-app resources (e.g. shared instructions or
|
|
111
|
+
data) with explicit per-app grants and effective-context resolution.
|
|
112
|
+
- **Integrations & destinations** — outbound messaging channel setup (Slack,
|
|
113
|
+
Teams, Discord, Telegram, WhatsApp, email, and more) and a destinations
|
|
114
|
+
queue for delivering agent output.
|
|
115
|
+
- **Dream jobs** — a recurring background job (`ensure-dream-job`) that scans
|
|
116
|
+
agent thread-debug history across connected sources and produces pending,
|
|
117
|
+
evidence-backed proposals (`create-dream-report`, `list-dream-candidates`,
|
|
118
|
+
`apply-dream-proposal` / `reject-dream-proposal`) without an extra LLM call.
|
|
119
|
+
- **Connected agents & provider APIs** — discovery of other workspace apps
|
|
120
|
+
(`list-connected-agents`, `open_app`, `ask_app`) and a generic provider-api
|
|
121
|
+
catalog/docs/request surface for calling third-party APIs through stored
|
|
122
|
+
credentials.
|
|
123
|
+
- **Approvals & audit** — a shared approval-request/audit-event model used
|
|
124
|
+
across the above surfaces.
|
|
125
|
+
|
|
126
|
+
## Eject
|
|
127
|
+
|
|
128
|
+
There is no `agent-native.package.json` / CLI package-lifecycle wiring for
|
|
129
|
+
this package yet (unlike `@agent-native/scheduling`). To customize beyond the
|
|
130
|
+
`setupDispatch` config surface, copy the files you want to own out of
|
|
131
|
+
`node_modules/@agent-native/dispatch/src` into your own package and swap the
|
|
132
|
+
dependency manually.
|
|
@@ -1,21 +1,21 @@
|
|
|
1
1
|
declare const _default: import("@agent-native/core").ActionDefinition<{
|
|
2
2
|
id: string;
|
|
3
3
|
}, {
|
|
4
|
+
afterValue: string | null;
|
|
5
|
+
beforeValue: string | null;
|
|
6
|
+
changeType: string;
|
|
7
|
+
createdAt: number;
|
|
4
8
|
id: string;
|
|
5
|
-
ownerEmail: string;
|
|
6
9
|
orgId: string | null;
|
|
7
|
-
|
|
8
|
-
targetType: string;
|
|
9
|
-
targetId: string | null;
|
|
10
|
-
status: string;
|
|
11
|
-
summary: string;
|
|
10
|
+
ownerEmail: string;
|
|
12
11
|
payload: string;
|
|
13
|
-
beforeValue: string | null;
|
|
14
|
-
afterValue: string | null;
|
|
15
12
|
requestedBy: string;
|
|
16
|
-
reviewedBy: string | null;
|
|
17
13
|
reviewedAt: number | null;
|
|
18
|
-
|
|
14
|
+
reviewedBy: string | null;
|
|
15
|
+
status: string;
|
|
16
|
+
summary: string;
|
|
17
|
+
targetId: string | null;
|
|
18
|
+
targetType: string;
|
|
19
19
|
updatedAt: number;
|
|
20
20
|
}>;
|
|
21
21
|
export default _default;
|
|
@@ -9,17 +9,25 @@ export default defineAction({
|
|
|
9
9
|
parallelSafe: true,
|
|
10
10
|
run: async () => {
|
|
11
11
|
const apps = await listGrantedDispatchMcpApps();
|
|
12
|
+
const appSummaries = apps.map((app) => ({
|
|
13
|
+
id: app.id,
|
|
14
|
+
name: app.name,
|
|
15
|
+
description: app.description,
|
|
16
|
+
url: app.url,
|
|
17
|
+
running: true,
|
|
18
|
+
source: "dispatch-mcp-grant",
|
|
19
|
+
}));
|
|
12
20
|
return {
|
|
13
21
|
workspace: true,
|
|
14
22
|
gateway: "dispatch",
|
|
15
|
-
apps:
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
})
|
|
23
|
+
apps: appSummaries,
|
|
24
|
+
// MCP model-visible results are deliberately text-only unless a tool is
|
|
25
|
+
// app-only or opens an MCP App. Supplying a compact, valid JSON message
|
|
26
|
+
// keeps large app catalogs machine-readable instead of letting the
|
|
27
|
+
// generic text limiter cut the full result into invalid JSON.
|
|
28
|
+
message: JSON.stringify({
|
|
29
|
+
apps: appSummaries.map(({ id, name }) => ({ id, name })),
|
|
30
|
+
}),
|
|
23
31
|
};
|
|
24
32
|
},
|
|
25
33
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"list_apps.js","sourceRoot":"","sources":["../../src/actions/list_apps.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,0BAA0B,EAAE,MAAM,8BAA8B,CAAC;AAE1E,eAAe,YAAY,CAAC;IAC1B,WAAW,EACT,6LAA6L;IAC/L,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC;IACpB,IAAI,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE;IACvB,QAAQ,EAAE,IAAI;IACd,YAAY,EAAE,IAAI;IAClB,GAAG,EAAE,KAAK,IAAI,EAAE;QACd,MAAM,IAAI,GAAG,MAAM,0BAA0B,EAAE,CAAC;QAChD,
|
|
1
|
+
{"version":3,"file":"list_apps.js","sourceRoot":"","sources":["../../src/actions/list_apps.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,0BAA0B,EAAE,MAAM,8BAA8B,CAAC;AAE1E,eAAe,YAAY,CAAC;IAC1B,WAAW,EACT,6LAA6L;IAC/L,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC;IACpB,IAAI,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE;IACvB,QAAQ,EAAE,IAAI;IACd,YAAY,EAAE,IAAI;IAClB,GAAG,EAAE,KAAK,IAAI,EAAE;QACd,MAAM,IAAI,GAAG,MAAM,0BAA0B,EAAE,CAAC;QAChD,MAAM,YAAY,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;YACtC,EAAE,EAAE,GAAG,CAAC,EAAE;YACV,IAAI,EAAE,GAAG,CAAC,IAAI;YACd,WAAW,EAAE,GAAG,CAAC,WAAW;YAC5B,GAAG,EAAE,GAAG,CAAC,GAAG;YACZ,OAAO,EAAE,IAAI;YACb,MAAM,EAAE,oBAAoB;SAC7B,CAAC,CAAC,CAAC;QACJ,OAAO;YACL,SAAS,EAAE,IAAI;YACf,OAAO,EAAE,UAAU;YACnB,IAAI,EAAE,YAAY;YAClB,wEAAwE;YACxE,wEAAwE;YACxE,mEAAmE;YACnE,8DAA8D;YAC9D,OAAO,EAAE,IAAI,CAAC,SAAS,CAAC;gBACtB,IAAI,EAAE,YAAY,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;aACzD,CAAC;SACH,CAAC;IACJ,CAAC;CACF,CAAC,CAAC","sourcesContent":["import { defineAction } from \"@agent-native/core\";\nimport { z } from \"zod\";\n\nimport { listGrantedDispatchMcpApps } from \"../server/lib/mcp-gateway.js\";\n\nexport default defineAction({\n description:\n 'List the apps this Dispatch MCP gateway can route to, including \"dispatch\" itself for Dispatch-owned pages such as extensions. The result is filtered by Dispatch\\'s MCP app access policy.',\n schema: z.object({}),\n http: { method: \"GET\" },\n readOnly: true,\n parallelSafe: true,\n run: async () => {\n const apps = await listGrantedDispatchMcpApps();\n const appSummaries = apps.map((app) => ({\n id: app.id,\n name: app.name,\n description: app.description,\n url: app.url,\n running: true,\n source: \"dispatch-mcp-grant\",\n }));\n return {\n workspace: true,\n gateway: \"dispatch\",\n apps: appSummaries,\n // MCP model-visible results are deliberately text-only unless a tool is\n // app-only or opens an MCP App. Supplying a compact, valid JSON message\n // keeps large app catalogs machine-readable instead of letting the\n // generic text limiter cut the full result into invalid JSON.\n message: JSON.stringify({\n apps: appSummaries.map(({ id, name }) => ({ id, name })),\n }),\n };\n },\n});\n"]}
|
|
@@ -1,7 +1,42 @@
|
|
|
1
1
|
import { defineAction } from "@agent-native/core";
|
|
2
|
-
import {
|
|
2
|
+
import { getDbExec } from "@agent-native/core/db";
|
|
3
|
+
import { upsertCustomProvider, deleteCustomProvider, listCustomProviders, getCustomProvider, assertCanMutateCustomProviderScope, } from "@agent-native/core/provider-api";
|
|
3
4
|
import { getCredentialContext } from "@agent-native/core/server";
|
|
4
5
|
import { z } from "zod";
|
|
6
|
+
/**
|
|
7
|
+
* Resolve the caller's role in a specific org, straight from `org_members`.
|
|
8
|
+
*
|
|
9
|
+
* `getCredentialContext()` (from `@agent-native/core/server`) only exposes
|
|
10
|
+
* `{ userEmail, orgId }` — no role. `getOrgContext()` (from
|
|
11
|
+
* `@agent-native/core/org`) resolves role but requires an `H3Event`, which
|
|
12
|
+
* `defineAction` handlers are not given. This mirrors the established
|
|
13
|
+
* no-event role-lookup idiom already used for org-admin gating inside
|
|
14
|
+
* agent-callable/background code (see `isCurrentUserOrgAdmin` in
|
|
15
|
+
* `packages/core/src/jobs/tools.ts`, `getViewerOrgRole` in
|
|
16
|
+
* `packages/dispatch/src/server/lib/usage-metrics-store.ts`, and the same
|
|
17
|
+
* query in `packages/core/src/mcp/actions/service-token-access.ts`) — same
|
|
18
|
+
* SQL, same fail-closed-to-null-on-error semantics. Returns null (never an
|
|
19
|
+
* org role) on any lookup error or when the caller has no membership row in
|
|
20
|
+
* this org.
|
|
21
|
+
*/
|
|
22
|
+
async function resolveCallerOrgRole(orgId, email) {
|
|
23
|
+
if (!orgId)
|
|
24
|
+
return null;
|
|
25
|
+
try {
|
|
26
|
+
const client = getDbExec();
|
|
27
|
+
const { rows } = await client.execute({
|
|
28
|
+
sql: `SELECT role FROM org_members WHERE org_id = ? AND LOWER(email) = ? LIMIT 1`,
|
|
29
|
+
args: [orgId, email.toLowerCase()],
|
|
30
|
+
});
|
|
31
|
+
if (rows.length === 0)
|
|
32
|
+
return null;
|
|
33
|
+
const role = rows[0].role;
|
|
34
|
+
return typeof role === "string" && role ? role : null;
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
5
40
|
const AuthSchema = z.discriminatedUnion("type", [
|
|
6
41
|
z.object({
|
|
7
42
|
type: z.literal("none"),
|
|
@@ -98,6 +133,32 @@ After registration the provider appears in provider-api-catalog and can be used
|
|
|
98
133
|
throw new Error("provider-api-register requires an authenticated request context.");
|
|
99
134
|
}
|
|
100
135
|
const scopeId = scope === "org" ? (ctx.orgId ?? ctx.userEmail) : ctx.userEmail;
|
|
136
|
+
// Only upsert/delete mutate state; list/get remain readable by any org
|
|
137
|
+
// member (scoping org-scoped reads is left as a follow-up — see plan
|
|
138
|
+
// 014). Resolve the caller's role in the *target* org (`scopeId`, which
|
|
139
|
+
// for scope === "org" is exactly `ctx.orgId`) and enforce owner/admin
|
|
140
|
+
// before allowing an org-scoped write. `assertCanMutateCustomProviderScope`
|
|
141
|
+
// is the single source of truth for this check and is also enforced a
|
|
142
|
+
// second time inside `upsertCustomProvider`/`deleteCustomProvider`
|
|
143
|
+
// themselves (defense in depth) — calling it here too gives a clear,
|
|
144
|
+
// early error before any other work happens.
|
|
145
|
+
//
|
|
146
|
+
// When the caller has no active org (`ctx.orgId` is null — a solo user,
|
|
147
|
+
// or an app that hasn't wired `resolveOrgId` at all), `scopeId` above
|
|
148
|
+
// already collapsed to `ctx.userEmail`: there is no shared org resource
|
|
149
|
+
// to protect, and no *other* caller can ever address that same scopeId
|
|
150
|
+
// (every other request's fallback is scoped to *its own* email). Treat
|
|
151
|
+
// that case like sole ownership of a personal bucket — consistent with
|
|
152
|
+
// `org/context.ts`'s auto-created personal org, which also assigns the
|
|
153
|
+
// user role "owner" — rather than hard-rejecting scope: "org" (the
|
|
154
|
+
// action's own default) for every solo user or org-less app.
|
|
155
|
+
let orgRole = null;
|
|
156
|
+
if ((operation === "upsert" || operation === "delete") && scope === "org") {
|
|
157
|
+
orgRole = ctx.orgId
|
|
158
|
+
? await resolveCallerOrgRole(ctx.orgId, ctx.userEmail)
|
|
159
|
+
: "owner";
|
|
160
|
+
assertCanMutateCustomProviderScope(scope, scopeId, orgRole);
|
|
161
|
+
}
|
|
101
162
|
if (operation === "list") {
|
|
102
163
|
const providers = await listCustomProviders(scope, scopeId);
|
|
103
164
|
return {
|
|
@@ -125,7 +186,7 @@ After registration the provider appears in provider-api-catalog and can be used
|
|
|
125
186
|
if (operation === "delete") {
|
|
126
187
|
if (!id)
|
|
127
188
|
throw new Error("id is required for delete operation.");
|
|
128
|
-
const deleted = await deleteCustomProvider(scope, scopeId, id);
|
|
189
|
+
const deleted = await deleteCustomProvider(scope, scopeId, id, orgRole);
|
|
129
190
|
return { deleted, id };
|
|
130
191
|
}
|
|
131
192
|
// upsert
|
|
@@ -148,6 +209,7 @@ After registration the provider appears in provider-api-catalog and can be used
|
|
|
148
209
|
allowedHostSuffixes,
|
|
149
210
|
defaultHeaders,
|
|
150
211
|
notes,
|
|
212
|
+
orgRole,
|
|
151
213
|
});
|
|
152
214
|
return {
|
|
153
215
|
registered: true,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"provider-api-register.js","sourceRoot":"","sources":["../../src/actions/provider-api-register.ts"],"names":[],"mappings":"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","sourcesContent":["import { defineAction } from \"@agent-native/core\";\nimport {\n upsertCustomProvider,\n deleteCustomProvider,\n listCustomProviders,\n getCustomProvider,\n} from \"@agent-native/core/provider-api\";\nimport { getCredentialContext } from \"@agent-native/core/server\";\nimport { z } from \"zod\";\n\nconst AuthSchema = z.discriminatedUnion(\"type\", [\n z.object({\n type: z.literal(\"none\"),\n }),\n z.object({\n type: z.literal(\"bearer\"),\n credentialKey: z\n .string()\n .min(1)\n .describe(\n \"Name of the credential key (e.g. MY_API_TOKEN). Must already be saved via app secrets — this action never accepts secret values.\",\n ),\n }),\n z.object({\n type: z.literal(\"basic\"),\n usernameKey: z\n .string()\n .min(1)\n .describe(\"Credential key name for the username/login.\"),\n passwordKey: z\n .string()\n .min(1)\n .describe(\"Credential key name for the password/secret.\"),\n }),\n z.object({\n type: z.literal(\"api-key-header\"),\n credentialKey: z\n .string()\n .min(1)\n .describe(\"Credential key name for the API key value.\"),\n headerName: z\n .string()\n .min(1)\n .describe(\"HTTP header name to send the key in (e.g. X-Api-Key).\"),\n }),\n]);\n\nexport default defineAction({\n description: `Register or update a custom API provider so the agent can call it via provider-api-request and look up its docs via provider-api-docs.\n\nIMPORTANT — credentials:\n- This action stores only credential KEY NAMES, never secret values.\n- If the required API key is not yet saved, instruct the user to add it via app Settings → Keys, or use the create-vault-secret action, before calling this action.\n- Supported auth kinds: none, bearer, basic, api-key-header.\n google-service-account and oauth-bearer are NOT supported for custom providers.\n\nAfter registration the provider appears in provider-api-catalog and can be used with provider-api-request.`,\n schema: z.object({\n operation: z\n .enum([\"upsert\", \"delete\", \"list\", \"get\"])\n .default(\"upsert\")\n .describe(\n \"Operation: upsert (create or update), delete (remove), list (all custom providers), get (single provider).\",\n ),\n id: z\n .string()\n .min(1)\n .max(64)\n .optional()\n .describe(\n \"Provider slug (e.g. my-api). Lowercase letters, digits, hyphens only. Required for upsert/delete/get.\",\n ),\n label: z\n .string()\n .min(1)\n .max(200)\n .optional()\n .describe(\n \"Human-readable name (e.g. 'My Analytics API'). Required for upsert.\",\n ),\n baseUrl: z\n .string()\n .url()\n .optional()\n .describe(\n \"Base URL for the API (e.g. https://api.example.com/v1). Required for upsert. Must be a public https/http URL.\",\n ),\n auth: AuthSchema.optional().describe(\n \"Auth configuration. Required for upsert. Use type 'none' for public APIs.\",\n ),\n docsUrls: z\n .array(z.string().url())\n .optional()\n .describe(\"Optional list of documentation URLs for this provider.\"),\n allowedHostSuffixes: z\n .array(z.string())\n .optional()\n .describe(\n \"Optional list of additional host suffixes requests may target beyond the base URL origin (e.g. ['example.com']).\",\n ),\n defaultHeaders: z\n .record(z.string(), z.string())\n .optional()\n .describe(\n \"Optional headers to include on every request (e.g. { 'Accept': 'application/json' }).\",\n ),\n notes: z\n .string()\n .max(1000)\n .optional()\n .describe(\"Optional notes about this provider shown in the catalog.\"),\n scope: z\n .enum([\"user\", \"org\"])\n .default(\"org\")\n .describe(\n \"Whether to store the provider for the current user only ('user') or for the whole workspace ('org').\",\n ),\n }),\n http: false,\n run: async ({\n operation,\n id,\n label,\n baseUrl,\n auth,\n docsUrls,\n allowedHostSuffixes,\n defaultHeaders,\n notes,\n scope,\n }) => {\n const ctx = getCredentialContext();\n if (!ctx) {\n throw new Error(\n \"provider-api-register requires an authenticated request context.\",\n );\n }\n const scopeId =\n scope === \"org\" ? (ctx.orgId ?? ctx.userEmail) : ctx.userEmail;\n\n if (operation === \"list\") {\n const providers = await listCustomProviders(scope, scopeId);\n return {\n providers: providers.map((p) => ({\n id: p.id,\n label: p.label,\n baseUrl: p.baseUrl,\n authType: p.auth.type,\n docsUrls: p.docsUrls,\n notes: p.notes,\n updatedAt: p.updatedAt,\n })),\n count: providers.length,\n };\n }\n\n if (operation === \"get\") {\n if (!id) throw new Error(\"id is required for get operation.\");\n const provider = await getCustomProvider(scope, scopeId, id);\n if (!provider) {\n return { found: false, id };\n }\n return { found: true, provider };\n }\n\n if (operation === \"delete\") {\n if (!id) throw new Error(\"id is required for delete operation.\");\n const deleted = await deleteCustomProvider(scope, scopeId, id);\n return { deleted, id };\n }\n\n // upsert\n if (!id) throw new Error(\"id is required for upsert operation.\");\n if (!label) throw new Error(\"label is required for upsert operation.\");\n if (!baseUrl) throw new Error(\"baseUrl is required for upsert operation.\");\n if (!auth) throw new Error(\"auth is required for upsert operation.\");\n\n await upsertCustomProvider({\n scope,\n scopeId,\n id,\n label,\n baseUrl,\n auth,\n docsUrls,\n allowedHostSuffixes,\n defaultHeaders,\n notes,\n });\n\n return {\n registered: true,\n id,\n label,\n message: `Custom provider \"${id}\" registered. Use provider-api-catalog to inspect it and provider-api-request to call it.`,\n };\n },\n});\n"]}
|
|
1
|
+
{"version":3,"file":"provider-api-register.js","sourceRoot":"","sources":["../../src/actions/provider-api-register.ts"],"names":[],"mappings":"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","sourcesContent":["import { defineAction } from \"@agent-native/core\";\nimport { getDbExec } from \"@agent-native/core/db\";\nimport {\n upsertCustomProvider,\n deleteCustomProvider,\n listCustomProviders,\n getCustomProvider,\n assertCanMutateCustomProviderScope,\n} from \"@agent-native/core/provider-api\";\nimport { getCredentialContext } from \"@agent-native/core/server\";\nimport { z } from \"zod\";\n\n/**\n * Resolve the caller's role in a specific org, straight from `org_members`.\n *\n * `getCredentialContext()` (from `@agent-native/core/server`) only exposes\n * `{ userEmail, orgId }` — no role. `getOrgContext()` (from\n * `@agent-native/core/org`) resolves role but requires an `H3Event`, which\n * `defineAction` handlers are not given. This mirrors the established\n * no-event role-lookup idiom already used for org-admin gating inside\n * agent-callable/background code (see `isCurrentUserOrgAdmin` in\n * `packages/core/src/jobs/tools.ts`, `getViewerOrgRole` in\n * `packages/dispatch/src/server/lib/usage-metrics-store.ts`, and the same\n * query in `packages/core/src/mcp/actions/service-token-access.ts`) — same\n * SQL, same fail-closed-to-null-on-error semantics. Returns null (never an\n * org role) on any lookup error or when the caller has no membership row in\n * this org.\n */\nasync function resolveCallerOrgRole(\n orgId: string | null,\n email: string,\n): Promise<string | null> {\n if (!orgId) return null;\n try {\n const client = getDbExec();\n const { rows } = await client.execute({\n sql: `SELECT role FROM org_members WHERE org_id = ? AND LOWER(email) = ? LIMIT 1`,\n args: [orgId, email.toLowerCase()],\n });\n if (rows.length === 0) return null;\n const role = (rows[0] as { role?: unknown }).role;\n return typeof role === \"string\" && role ? role : null;\n } catch {\n return null;\n }\n}\n\nconst AuthSchema = z.discriminatedUnion(\"type\", [\n z.object({\n type: z.literal(\"none\"),\n }),\n z.object({\n type: z.literal(\"bearer\"),\n credentialKey: z\n .string()\n .min(1)\n .describe(\n \"Name of the credential key (e.g. MY_API_TOKEN). Must already be saved via app secrets — this action never accepts secret values.\",\n ),\n }),\n z.object({\n type: z.literal(\"basic\"),\n usernameKey: z\n .string()\n .min(1)\n .describe(\"Credential key name for the username/login.\"),\n passwordKey: z\n .string()\n .min(1)\n .describe(\"Credential key name for the password/secret.\"),\n }),\n z.object({\n type: z.literal(\"api-key-header\"),\n credentialKey: z\n .string()\n .min(1)\n .describe(\"Credential key name for the API key value.\"),\n headerName: z\n .string()\n .min(1)\n .describe(\"HTTP header name to send the key in (e.g. X-Api-Key).\"),\n }),\n]);\n\nexport default defineAction({\n description: `Register or update a custom API provider so the agent can call it via provider-api-request and look up its docs via provider-api-docs.\n\nIMPORTANT — credentials:\n- This action stores only credential KEY NAMES, never secret values.\n- If the required API key is not yet saved, instruct the user to add it via app Settings → Keys, or use the create-vault-secret action, before calling this action.\n- Supported auth kinds: none, bearer, basic, api-key-header.\n google-service-account and oauth-bearer are NOT supported for custom providers.\n\nAfter registration the provider appears in provider-api-catalog and can be used with provider-api-request.`,\n schema: z.object({\n operation: z\n .enum([\"upsert\", \"delete\", \"list\", \"get\"])\n .default(\"upsert\")\n .describe(\n \"Operation: upsert (create or update), delete (remove), list (all custom providers), get (single provider).\",\n ),\n id: z\n .string()\n .min(1)\n .max(64)\n .optional()\n .describe(\n \"Provider slug (e.g. my-api). Lowercase letters, digits, hyphens only. Required for upsert/delete/get.\",\n ),\n label: z\n .string()\n .min(1)\n .max(200)\n .optional()\n .describe(\n \"Human-readable name (e.g. 'My Analytics API'). Required for upsert.\",\n ),\n baseUrl: z\n .string()\n .url()\n .optional()\n .describe(\n \"Base URL for the API (e.g. https://api.example.com/v1). Required for upsert. Must be a public https/http URL.\",\n ),\n auth: AuthSchema.optional().describe(\n \"Auth configuration. Required for upsert. Use type 'none' for public APIs.\",\n ),\n docsUrls: z\n .array(z.string().url())\n .optional()\n .describe(\"Optional list of documentation URLs for this provider.\"),\n allowedHostSuffixes: z\n .array(z.string())\n .optional()\n .describe(\n \"Optional list of additional host suffixes requests may target beyond the base URL origin (e.g. ['example.com']).\",\n ),\n defaultHeaders: z\n .record(z.string(), z.string())\n .optional()\n .describe(\n \"Optional headers to include on every request (e.g. { 'Accept': 'application/json' }).\",\n ),\n notes: z\n .string()\n .max(1000)\n .optional()\n .describe(\"Optional notes about this provider shown in the catalog.\"),\n scope: z\n .enum([\"user\", \"org\"])\n .default(\"org\")\n .describe(\n \"Whether to store the provider for the current user only ('user') or for the whole workspace ('org').\",\n ),\n }),\n http: false,\n run: async ({\n operation,\n id,\n label,\n baseUrl,\n auth,\n docsUrls,\n allowedHostSuffixes,\n defaultHeaders,\n notes,\n scope,\n }) => {\n const ctx = getCredentialContext();\n if (!ctx) {\n throw new Error(\n \"provider-api-register requires an authenticated request context.\",\n );\n }\n const scopeId =\n scope === \"org\" ? (ctx.orgId ?? ctx.userEmail) : ctx.userEmail;\n\n // Only upsert/delete mutate state; list/get remain readable by any org\n // member (scoping org-scoped reads is left as a follow-up — see plan\n // 014). Resolve the caller's role in the *target* org (`scopeId`, which\n // for scope === \"org\" is exactly `ctx.orgId`) and enforce owner/admin\n // before allowing an org-scoped write. `assertCanMutateCustomProviderScope`\n // is the single source of truth for this check and is also enforced a\n // second time inside `upsertCustomProvider`/`deleteCustomProvider`\n // themselves (defense in depth) — calling it here too gives a clear,\n // early error before any other work happens.\n //\n // When the caller has no active org (`ctx.orgId` is null — a solo user,\n // or an app that hasn't wired `resolveOrgId` at all), `scopeId` above\n // already collapsed to `ctx.userEmail`: there is no shared org resource\n // to protect, and no *other* caller can ever address that same scopeId\n // (every other request's fallback is scoped to *its own* email). Treat\n // that case like sole ownership of a personal bucket — consistent with\n // `org/context.ts`'s auto-created personal org, which also assigns the\n // user role \"owner\" — rather than hard-rejecting scope: \"org\" (the\n // action's own default) for every solo user or org-less app.\n let orgRole: string | null = null;\n if ((operation === \"upsert\" || operation === \"delete\") && scope === \"org\") {\n orgRole = ctx.orgId\n ? await resolveCallerOrgRole(ctx.orgId, ctx.userEmail)\n : \"owner\";\n assertCanMutateCustomProviderScope(scope, scopeId, orgRole);\n }\n\n if (operation === \"list\") {\n const providers = await listCustomProviders(scope, scopeId);\n return {\n providers: providers.map((p) => ({\n id: p.id,\n label: p.label,\n baseUrl: p.baseUrl,\n authType: p.auth.type,\n docsUrls: p.docsUrls,\n notes: p.notes,\n updatedAt: p.updatedAt,\n })),\n count: providers.length,\n };\n }\n\n if (operation === \"get\") {\n if (!id) throw new Error(\"id is required for get operation.\");\n const provider = await getCustomProvider(scope, scopeId, id);\n if (!provider) {\n return { found: false, id };\n }\n return { found: true, provider };\n }\n\n if (operation === \"delete\") {\n if (!id) throw new Error(\"id is required for delete operation.\");\n const deleted = await deleteCustomProvider(scope, scopeId, id, orgRole);\n return { deleted, id };\n }\n\n // upsert\n if (!id) throw new Error(\"id is required for upsert operation.\");\n if (!label) throw new Error(\"label is required for upsert operation.\");\n if (!baseUrl) throw new Error(\"baseUrl is required for upsert operation.\");\n if (!auth) throw new Error(\"auth is required for upsert operation.\");\n\n await upsertCustomProvider({\n scope,\n scopeId,\n id,\n label,\n baseUrl,\n auth,\n docsUrls,\n allowedHostSuffixes,\n defaultHeaders,\n notes,\n orgRole,\n });\n\n return {\n registered: true,\n id,\n label,\n message: `Custom provider \"${id}\" registered. Use provider-api-catalog to inspect it and provider-api-request to call it.`,\n };\n },\n});\n"]}
|
|
@@ -2,21 +2,21 @@ declare const _default: import("@agent-native/core").ActionDefinition<{
|
|
|
2
2
|
id: string;
|
|
3
3
|
reason?: string | undefined;
|
|
4
4
|
}, {
|
|
5
|
+
afterValue: string | null;
|
|
6
|
+
beforeValue: string | null;
|
|
7
|
+
changeType: string;
|
|
8
|
+
createdAt: number;
|
|
5
9
|
id: string;
|
|
6
|
-
ownerEmail: string;
|
|
7
10
|
orgId: string | null;
|
|
8
|
-
|
|
9
|
-
targetType: string;
|
|
10
|
-
targetId: string | null;
|
|
11
|
-
status: string;
|
|
12
|
-
summary: string;
|
|
11
|
+
ownerEmail: string;
|
|
13
12
|
payload: string;
|
|
14
|
-
beforeValue: string | null;
|
|
15
|
-
afterValue: string | null;
|
|
16
13
|
requestedBy: string;
|
|
17
|
-
reviewedBy: string | null;
|
|
18
14
|
reviewedAt: number | null;
|
|
19
|
-
|
|
15
|
+
reviewedBy: string | null;
|
|
16
|
+
status: string;
|
|
17
|
+
summary: string;
|
|
18
|
+
targetId: string | null;
|
|
19
|
+
targetType: string;
|
|
20
20
|
updatedAt: number;
|
|
21
21
|
}>;
|
|
22
22
|
export default _default;
|
|
@@ -16,7 +16,7 @@ export default defineAction({
|
|
|
16
16
|
}),
|
|
17
17
|
run: async (args) => {
|
|
18
18
|
const agents = await discoverAgents("dispatch");
|
|
19
|
-
const knownIds = new Set(agents.map((agent) => agent.id));
|
|
19
|
+
const knownIds = new Set(["dispatch", ...agents.map((agent) => agent.id)]);
|
|
20
20
|
const selectedAppIds = Array.from(new Set(args.selectedAppIds
|
|
21
21
|
.map((id) => id.trim().toLowerCase())
|
|
22
22
|
.filter(Boolean)));
|
|
@@ -24,9 +24,6 @@ export default defineAction({
|
|
|
24
24
|
if (unknown.length > 0) {
|
|
25
25
|
throw new Error(`Unknown app(s): ${unknown.join(", ")}. Use list-mcp-app-access to see available app IDs.`);
|
|
26
26
|
}
|
|
27
|
-
if (args.mode === "selected-apps" && selectedAppIds.length === 0) {
|
|
28
|
-
throw new Error("selected-apps mode requires at least one app ID.");
|
|
29
|
-
}
|
|
30
27
|
await setDispatchMcpAppAccessSettings({
|
|
31
28
|
mode: args.mode,
|
|
32
29
|
selectedAppIds,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"set-mcp-app-access.js","sourceRoot":"","sources":["../../src/actions/set-mcp-app-access.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,cAAc,EAAE,MAAM,2CAA2C,CAAC;AAC3E,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,WAAW,EAAE,MAAM,iCAAiC,CAAC;AAC9D,OAAO,EAAE,+BAA+B,EAAE,MAAM,mCAAmC,CAAC;AACpF,OAAO,gBAAgB,MAAM,0BAA0B,CAAC;AAExD,MAAM,UAAU,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,UAAU,EAAE,eAAe,CAAC,CAAC,CAAC;AAEzD,eAAe,YAAY,CAAC;IAC1B,WAAW,EACT,sEAAsE;IACxE,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC;QACf,IAAI,EAAE,UAAU,CAAC,QAAQ,CACvB,6FAA6F,CAC9F;QACD,cAAc,EAAE,CAAC;aACd,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;aACjB,OAAO,CAAC,EAAE,CAAC;aACX,QAAQ,CAAC,+CAA+C,CAAC;KAC7D,CAAC;IACF,GAAG,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE;QAClB,MAAM,MAAM,GAAG,MAAM,cAAc,CAAC,UAAU,CAAC,CAAC;QAChD,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"set-mcp-app-access.js","sourceRoot":"","sources":["../../src/actions/set-mcp-app-access.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,cAAc,EAAE,MAAM,2CAA2C,CAAC;AAC3E,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,WAAW,EAAE,MAAM,iCAAiC,CAAC;AAC9D,OAAO,EAAE,+BAA+B,EAAE,MAAM,mCAAmC,CAAC;AACpF,OAAO,gBAAgB,MAAM,0BAA0B,CAAC;AAExD,MAAM,UAAU,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,UAAU,EAAE,eAAe,CAAC,CAAC,CAAC;AAEzD,eAAe,YAAY,CAAC;IAC1B,WAAW,EACT,sEAAsE;IACxE,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC;QACf,IAAI,EAAE,UAAU,CAAC,QAAQ,CACvB,6FAA6F,CAC9F;QACD,cAAc,EAAE,CAAC;aACd,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;aACjB,OAAO,CAAC,EAAE,CAAC;aACX,QAAQ,CAAC,+CAA+C,CAAC;KAC7D,CAAC;IACF,GAAG,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE;QAClB,MAAM,MAAM,GAAG,MAAM,cAAc,CAAC,UAAU,CAAC,CAAC;QAChD,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC,CAAC,UAAU,EAAE,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;QAC3E,MAAM,cAAc,GAAG,KAAK,CAAC,IAAI,CAC/B,IAAI,GAAG,CACL,IAAI,CAAC,cAAc;aAChB,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;aACpC,MAAM,CAAC,OAAO,CAAC,CACnB,CACF,CAAC;QACF,MAAM,OAAO,GAAG,cAAc,CAAC,MAAM,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;QACjE,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACvB,MAAM,IAAI,KAAK,CACb,mBAAmB,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,qDAAqD,CAC3F,CAAC;QACJ,CAAC;QACD,MAAM,+BAA+B,CAAC;YACpC,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,cAAc;SACf,CAAC,CAAC;QACH,MAAM,WAAW,CAAC;YAChB,MAAM,EAAE,oBAAoB;YAC5B,UAAU,EAAE,qBAAqB;YACjC,QAAQ,EAAE,aAAa;YACvB,OAAO,EACL,IAAI,CAAC,IAAI,KAAK,UAAU;gBACtB,CAAC,CAAC,yCAAyC;gBAC3C,CAAC,CAAC,kCAAkC,cAAc,CAAC,MAAM,kBAAkB;YAC/E,QAAQ,EAAE,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,cAAc,EAAE;SAC9C,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;QAEnB,OAAO,gBAAgB,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAClC,CAAC;CACF,CAAC,CAAC","sourcesContent":["import { defineAction } from \"@agent-native/core\";\nimport { discoverAgents } from \"@agent-native/core/server/agent-discovery\";\nimport { z } from \"zod\";\n\nimport { recordAudit } from \"../server/lib/dispatch-store.js\";\nimport { setDispatchMcpAppAccessSettings } from \"../server/lib/mcp-access-store.js\";\nimport listMcpAppAccess from \"./list-mcp-app-access.js\";\n\nconst modeSchema = z.enum([\"all-apps\", \"selected-apps\"]);\n\nexport default defineAction({\n description:\n \"Set which apps are available through Dispatch's unified MCP gateway.\",\n schema: z.object({\n mode: modeSchema.describe(\n \"Use all-apps to expose every discovered app, or selected-apps to allow only selectedAppIds.\",\n ),\n selectedAppIds: z\n .array(z.string())\n .default([])\n .describe(\"App IDs to expose when mode is selected-apps.\"),\n }),\n run: async (args) => {\n const agents = await discoverAgents(\"dispatch\");\n const knownIds = new Set([\"dispatch\", ...agents.map((agent) => agent.id)]);\n const selectedAppIds = Array.from(\n new Set(\n args.selectedAppIds\n .map((id) => id.trim().toLowerCase())\n .filter(Boolean),\n ),\n );\n const unknown = selectedAppIds.filter((id) => !knownIds.has(id));\n if (unknown.length > 0) {\n throw new Error(\n `Unknown app(s): ${unknown.join(\", \")}. Use list-mcp-app-access to see available app IDs.`,\n );\n }\n await setDispatchMcpAppAccessSettings({\n mode: args.mode,\n selectedAppIds,\n });\n await recordAudit({\n action: \"mcp-access.updated\",\n targetType: \"dispatch-mcp-access\",\n targetId: \"unified-mcp\",\n summary:\n args.mode === \"all-apps\"\n ? \"Allowed Dispatch MCP access to all apps\"\n : `Allowed Dispatch MCP access to ${selectedAppIds.length} selected app(s)`,\n metadata: { mode: args.mode, selectedAppIds },\n }).catch(() => {});\n\n return listMcpAppAccess.run({});\n },\n});\n"]}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
interface ActionQueryErrorProps {
|
|
2
|
+
error?: unknown;
|
|
3
|
+
onRetry: () => unknown;
|
|
4
|
+
className?: string;
|
|
5
|
+
}
|
|
6
|
+
export declare function ActionQueryError({ onRetry, className, }: ActionQueryErrorProps): import("node_modules/@types/react").JSX.Element;
|
|
7
|
+
export {};
|
|
8
|
+
//# sourceMappingURL=action-query-error.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"action-query-error.d.ts","sourceRoot":"","sources":["../../src/components/action-query-error.tsx"],"names":[],"mappings":"AAMA,UAAU,qBAAqB;IAC7B,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,OAAO,EAAE,MAAM,OAAO,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,wBAAgB,gBAAgB,CAAC,EAC/B,OAAO,EACP,SAAS,GACV,EAAE,qBAAqB,mDAgBvB"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useT } from "@agent-native/core/client";
|
|
3
|
+
import { IconAlertTriangle, IconRefresh } from "@tabler/icons-react";
|
|
4
|
+
import { Alert, AlertDescription, AlertTitle } from "./ui/alert.js";
|
|
5
|
+
import { Button } from "./ui/button.js";
|
|
6
|
+
export function ActionQueryError({ onRetry, className, }) {
|
|
7
|
+
const t = useT();
|
|
8
|
+
return (_jsxs(Alert, { variant: "destructive", className: className, children: [_jsx(IconAlertTriangle, { className: "size-4" }), _jsx(AlertTitle, { children: t("dispatch.pages.dataLoadFailed") }), _jsxs(AlertDescription, { className: "flex flex-wrap items-center justify-between gap-3", children: [_jsx("span", { children: t("dispatch.pages.dataLoadFailedDescription") }), _jsxs(Button, { type: "button", variant: "outline", size: "sm", onClick: onRetry, children: [_jsx(IconRefresh, { className: "size-4" }), t("dispatch.pages.tryAgain")] })] })] }));
|
|
9
|
+
}
|
|
10
|
+
//# sourceMappingURL=action-query-error.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"action-query-error.js","sourceRoot":"","sources":["../../src/components/action-query-error.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,2BAA2B,CAAC;AACjD,OAAO,EAAE,iBAAiB,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAErE,OAAO,EAAE,KAAK,EAAE,gBAAgB,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AACjE,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAQrC,MAAM,UAAU,gBAAgB,CAAC,EAC/B,OAAO,EACP,SAAS,GACa;IACtB,MAAM,CAAC,GAAG,IAAI,EAAE,CAAC;IAEjB,OAAO,CACL,MAAC,KAAK,IAAC,OAAO,EAAC,aAAa,EAAC,SAAS,EAAE,SAAS,aAC/C,KAAC,iBAAiB,IAAC,SAAS,EAAC,QAAQ,GAAG,EACxC,KAAC,UAAU,cAAE,CAAC,CAAC,+BAA+B,CAAC,GAAc,EAC7D,MAAC,gBAAgB,IAAC,SAAS,EAAC,mDAAmD,aAC7E,yBAAO,CAAC,CAAC,0CAA0C,CAAC,GAAQ,EAC5D,MAAC,MAAM,IAAC,IAAI,EAAC,QAAQ,EAAC,OAAO,EAAC,SAAS,EAAC,IAAI,EAAC,IAAI,EAAC,OAAO,EAAE,OAAO,aAChE,KAAC,WAAW,IAAC,SAAS,EAAC,QAAQ,GAAG,EACjC,CAAC,CAAC,yBAAyB,CAAC,IACtB,IACQ,IACb,CACT,CAAC;AACJ,CAAC","sourcesContent":["import { useT } from \"@agent-native/core/client\";\nimport { IconAlertTriangle, IconRefresh } from \"@tabler/icons-react\";\n\nimport { Alert, AlertDescription, AlertTitle } from \"./ui/alert\";\nimport { Button } from \"./ui/button\";\n\ninterface ActionQueryErrorProps {\n error?: unknown;\n onRetry: () => unknown;\n className?: string;\n}\n\nexport function ActionQueryError({\n onRetry,\n className,\n}: ActionQueryErrorProps) {\n const t = useT();\n\n return (\n <Alert variant=\"destructive\" className={className}>\n <IconAlertTriangle className=\"size-4\" />\n <AlertTitle>{t(\"dispatch.pages.dataLoadFailed\")}</AlertTitle>\n <AlertDescription className=\"flex flex-wrap items-center justify-between gap-3\">\n <span>{t(\"dispatch.pages.dataLoadFailedDescription\")}</span>\n <Button type=\"button\" variant=\"outline\" size=\"sm\" onClick={onRetry}>\n <IconRefresh className=\"size-4\" />\n {t(\"dispatch.pages.tryAgain\")}\n </Button>\n </AlertDescription>\n </Alert>\n );\n}\n"]}
|
|
@@ -7,5 +7,9 @@ interface AppKeysPopoverProps {
|
|
|
7
7
|
side?: "top" | "right" | "bottom" | "left";
|
|
8
8
|
}
|
|
9
9
|
export declare function AppKeysPopover({ appId, appName, trigger, align, side, }: AppKeysPopoverProps): import("node_modules/@types/react").JSX.Element;
|
|
10
|
+
export declare function AppKeysPanel({ appId, appName, }: {
|
|
11
|
+
appId: string;
|
|
12
|
+
appName: string;
|
|
13
|
+
}): import("node_modules/@types/react").JSX.Element;
|
|
10
14
|
export {};
|
|
11
15
|
//# sourceMappingURL=app-keys-popover.d.ts.map
|