@agent-native/dispatch 0.6.1 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (146) hide show
  1. package/README.md +1 -1
  2. package/dist/actions/create-pylon-ticket.d.ts +3 -0
  3. package/dist/actions/create-pylon-ticket.d.ts.map +1 -0
  4. package/dist/actions/create-pylon-ticket.js +94 -0
  5. package/dist/actions/create-pylon-ticket.js.map +1 -0
  6. package/dist/actions/create-vault-grant.js +1 -1
  7. package/dist/actions/create-vault-grant.js.map +1 -1
  8. package/dist/actions/create-vault-secret.d.ts.map +1 -1
  9. package/dist/actions/create-vault-secret.js +4 -3
  10. package/dist/actions/create-vault-secret.js.map +1 -1
  11. package/dist/actions/get-vault-access-settings.d.ts +3 -0
  12. package/dist/actions/get-vault-access-settings.d.ts.map +1 -0
  13. package/dist/actions/get-vault-access-settings.js +10 -0
  14. package/dist/actions/get-vault-access-settings.js.map +1 -0
  15. package/dist/actions/grant-vault-secrets-to-app.js +1 -1
  16. package/dist/actions/grant-vault-secrets-to-app.js.map +1 -1
  17. package/dist/actions/index.d.ts.map +1 -1
  18. package/dist/actions/index.js +8 -0
  19. package/dist/actions/index.js.map +1 -1
  20. package/dist/actions/list-integrations-catalog.js +1 -1
  21. package/dist/actions/list-integrations-catalog.js.map +1 -1
  22. package/dist/actions/list-vault-grants.js +1 -1
  23. package/dist/actions/list-vault-grants.js.map +1 -1
  24. package/dist/actions/list-workspace-apps.d.ts.map +1 -1
  25. package/dist/actions/list-workspace-apps.js +5 -1
  26. package/dist/actions/list-workspace-apps.js.map +1 -1
  27. package/dist/actions/set-vault-access-settings.d.ts +3 -0
  28. package/dist/actions/set-vault-access-settings.d.ts.map +1 -0
  29. package/dist/actions/set-vault-access-settings.js +13 -0
  30. package/dist/actions/set-vault-access-settings.js.map +1 -0
  31. package/dist/actions/start-workspace-app-creation.d.ts.map +1 -1
  32. package/dist/actions/start-workspace-app-creation.js +6 -0
  33. package/dist/actions/start-workspace-app-creation.js.map +1 -1
  34. package/dist/actions/sync-vault-to-app.js +1 -1
  35. package/dist/actions/sync-vault-to-app.js.map +1 -1
  36. package/dist/actions/update-workspace-app-metadata.d.ts +3 -0
  37. package/dist/actions/update-workspace-app-metadata.d.ts.map +1 -0
  38. package/dist/actions/update-workspace-app-metadata.js +30 -0
  39. package/dist/actions/update-workspace-app-metadata.js.map +1 -0
  40. package/dist/actions/view-screen.d.ts.map +1 -1
  41. package/dist/actions/view-screen.js +4 -2
  42. package/dist/actions/view-screen.js.map +1 -1
  43. package/dist/components/app-keys-popover.js +16 -5
  44. package/dist/components/app-keys-popover.js.map +1 -1
  45. package/dist/components/create-app-popover.d.ts.map +1 -1
  46. package/dist/components/create-app-popover.js +38 -14
  47. package/dist/components/create-app-popover.js.map +1 -1
  48. package/dist/components/dispatch-shell.d.ts +4 -4
  49. package/dist/components/dispatch-shell.d.ts.map +1 -1
  50. package/dist/components/dispatch-shell.js +6 -6
  51. package/dist/components/dispatch-shell.js.map +1 -1
  52. package/dist/components/layout/Layout.d.ts.map +1 -1
  53. package/dist/components/layout/Layout.js +10 -3
  54. package/dist/components/layout/Layout.js.map +1 -1
  55. package/dist/components/messaging-setup-panel.d.ts.map +1 -1
  56. package/dist/components/messaging-setup-panel.js +2 -2
  57. package/dist/components/messaging-setup-panel.js.map +1 -1
  58. package/dist/components/workspace-app-card.d.ts.map +1 -1
  59. package/dist/components/workspace-app-card.js +41 -2
  60. package/dist/components/workspace-app-card.js.map +1 -1
  61. package/dist/hooks/use-navigation-state.js +12 -5
  62. package/dist/hooks/use-navigation-state.js.map +1 -1
  63. package/dist/lib/catch-all-target.d.ts +2 -0
  64. package/dist/lib/catch-all-target.d.ts.map +1 -0
  65. package/dist/lib/catch-all-target.js +95 -0
  66. package/dist/lib/catch-all-target.js.map +1 -0
  67. package/dist/lib/workspace-apps.d.ts +9 -0
  68. package/dist/lib/workspace-apps.d.ts.map +1 -1
  69. package/dist/lib/workspace-apps.js.map +1 -1
  70. package/dist/routes/pages/$appId.d.ts +2 -2
  71. package/dist/routes/pages/$appId.d.ts.map +1 -1
  72. package/dist/routes/pages/$appId.js +17 -8
  73. package/dist/routes/pages/$appId.js.map +1 -1
  74. package/dist/routes/pages/integrations.d.ts.map +1 -1
  75. package/dist/routes/pages/integrations.js +20 -15
  76. package/dist/routes/pages/integrations.js.map +1 -1
  77. package/dist/routes/pages/new-app.js +1 -1
  78. package/dist/routes/pages/new-app.js.map +1 -1
  79. package/dist/routes/pages/overview.d.ts.map +1 -1
  80. package/dist/routes/pages/overview.js +5 -1
  81. package/dist/routes/pages/overview.js.map +1 -1
  82. package/dist/routes/pages/vault.d.ts.map +1 -1
  83. package/dist/routes/pages/vault.js +23 -5
  84. package/dist/routes/pages/vault.js.map +1 -1
  85. package/dist/server/lib/app-creation-store.d.ts +13 -0
  86. package/dist/server/lib/app-creation-store.d.ts.map +1 -1
  87. package/dist/server/lib/app-creation-store.js +295 -9
  88. package/dist/server/lib/app-creation-store.js.map +1 -1
  89. package/dist/server/lib/env-config.d.ts.map +1 -1
  90. package/dist/server/lib/env-config.js +5 -0
  91. package/dist/server/lib/env-config.js.map +1 -1
  92. package/dist/server/lib/onboarding-steps.d.ts +12 -0
  93. package/dist/server/lib/onboarding-steps.d.ts.map +1 -0
  94. package/dist/server/lib/onboarding-steps.js +47 -0
  95. package/dist/server/lib/onboarding-steps.js.map +1 -0
  96. package/dist/server/lib/vault-store.d.ts +55 -0
  97. package/dist/server/lib/vault-store.d.ts.map +1 -1
  98. package/dist/server/lib/vault-store.js +210 -41
  99. package/dist/server/lib/vault-store.js.map +1 -1
  100. package/dist/server/plugins/agent-chat.d.ts.map +1 -1
  101. package/dist/server/plugins/agent-chat.js +2 -1
  102. package/dist/server/plugins/agent-chat.js.map +1 -1
  103. package/dist/server/plugins/core-routes.d.ts.map +1 -1
  104. package/dist/server/plugins/core-routes.js +4 -0
  105. package/dist/server/plugins/core-routes.js.map +1 -1
  106. package/dist/server/plugins/integrations.js +2 -2
  107. package/dist/server/plugins/integrations.js.map +1 -1
  108. package/package.json +13 -11
  109. package/src/actions/create-pylon-ticket.ts +109 -0
  110. package/src/actions/create-vault-grant.ts +1 -1
  111. package/src/actions/create-vault-secret.ts +4 -3
  112. package/src/actions/get-vault-access-settings.ts +11 -0
  113. package/src/actions/grant-vault-secrets-to-app.ts +1 -1
  114. package/src/actions/index.ts +8 -0
  115. package/src/actions/list-integrations-catalog.ts +1 -1
  116. package/src/actions/list-vault-grants.ts +1 -1
  117. package/src/actions/list-workspace-apps.ts +5 -1
  118. package/src/actions/set-vault-access-settings.ts +16 -0
  119. package/src/actions/start-workspace-app-creation.ts +8 -0
  120. package/src/actions/sync-vault-to-app.ts +1 -1
  121. package/src/actions/update-workspace-app-metadata.ts +32 -0
  122. package/src/actions/view-screen.ts +4 -1
  123. package/src/components/app-keys-popover.tsx +23 -7
  124. package/src/components/create-app-popover.tsx +47 -14
  125. package/src/components/dispatch-shell.tsx +16 -15
  126. package/src/components/layout/Layout.tsx +11 -5
  127. package/src/components/messaging-setup-panel.tsx +54 -39
  128. package/src/components/workspace-app-card.tsx +102 -0
  129. package/src/hooks/use-navigation-state.ts +10 -4
  130. package/src/lib/catch-all-target.spec.ts +218 -0
  131. package/src/lib/catch-all-target.ts +99 -0
  132. package/src/lib/workspace-apps.ts +9 -0
  133. package/src/routes/pages/$appId.tsx +21 -8
  134. package/src/routes/pages/integrations.tsx +57 -18
  135. package/src/routes/pages/new-app.tsx +1 -1
  136. package/src/routes/pages/overview.tsx +11 -3
  137. package/src/routes/pages/vault.tsx +76 -9
  138. package/src/server/lib/app-creation-store.spec.ts +61 -2
  139. package/src/server/lib/app-creation-store.ts +386 -11
  140. package/src/server/lib/env-config.ts +5 -0
  141. package/src/server/lib/onboarding-steps.ts +49 -0
  142. package/src/server/lib/vault-store.spec.ts +69 -0
  143. package/src/server/lib/vault-store.ts +266 -49
  144. package/src/server/plugins/agent-chat.ts +2 -1
  145. package/src/server/plugins/core-routes.ts +5 -0
  146. package/src/server/plugins/integrations.ts +2 -2
@@ -1,3 +1,11 @@
1
+ import { type SecretScope } from "@agent-native/core/secrets";
2
+ import { schema } from "../../db/index.js";
3
+ export type VaultAccessMode = "all-apps" | "manual";
4
+ export interface VaultAccessSettings {
5
+ mode: VaultAccessMode;
6
+ scope: "org" | "user";
7
+ scopeId: string;
8
+ }
1
9
  /**
2
10
  * Caller-supplied access context for vault operations.
3
11
  *
@@ -17,6 +25,10 @@ export interface VaultCtx {
17
25
  * leaked rows across tenants when a misconfigured environment skipped auth.
18
26
  */
19
27
  export declare function requireVaultCtx(): VaultCtx;
28
+ export declare function getVaultAccessSettings(): Promise<VaultAccessSettings>;
29
+ export declare function setVaultAccessSettings(input: {
30
+ mode: VaultAccessMode;
31
+ }): Promise<VaultAccessSettings>;
20
32
  export declare function recordVaultAudit(input: {
21
33
  action: string;
22
34
  secretId?: string | null;
@@ -149,6 +161,12 @@ export declare function createGrant(secretId: string, appId: string, ctx?: Vault
149
161
  }>;
150
162
  export declare function grantSecretsToApp(secretIds: string[], appId: string, ctx?: VaultCtx): Promise<{
151
163
  appId: string;
164
+ accessMode: "all-apps";
165
+ created: any[];
166
+ skipped: string[];
167
+ } | {
168
+ appId: string;
169
+ accessMode: "manual";
152
170
  created: any[];
153
171
  skipped: string[];
154
172
  }>;
@@ -164,10 +182,43 @@ export declare function revokeGrant(grantId: string, ctx?: VaultCtx): Promise<{
164
182
  createdAt: number;
165
183
  updatedAt: number;
166
184
  }>;
185
+ type VaultSecretRow = typeof schema.vaultSecrets.$inferSelect;
186
+ export declare function credentialStoreScopeForVaultCtx(ctx: VaultCtx): {
187
+ scope: Extract<SecretScope, "org" | "workspace">;
188
+ scopeId: string;
189
+ };
190
+ export declare function syncSecretsToCredentialStore(secrets: VaultSecretRow[], ctx: VaultCtx): Promise<{
191
+ keys: string[];
192
+ scope: Extract<SecretScope, "org" | "workspace">;
193
+ scopeId: string;
194
+ }>;
167
195
  export declare function syncGrantsToApp(appId: string, ctx?: VaultCtx): Promise<{
168
196
  appId: string;
197
+ accessMode: VaultAccessMode;
198
+ synced: number;
199
+ keys: any[];
200
+ credentialStore?: undefined;
201
+ envVars?: undefined;
202
+ } | {
203
+ appId: string;
204
+ accessMode: VaultAccessMode;
169
205
  synced: number;
170
206
  keys: string[];
207
+ credentialStore: {
208
+ scope: "org" | "workspace";
209
+ scopeId: string;
210
+ synced: number;
211
+ };
212
+ envVars: {
213
+ status: "synced";
214
+ keys: string[];
215
+ } | {
216
+ status: "skipped";
217
+ reason: string;
218
+ } | {
219
+ status: "failed";
220
+ reason: string;
221
+ };
171
222
  }>;
172
223
  export declare function listRequests(filter?: {
173
224
  status?: string;
@@ -259,12 +310,16 @@ export interface AppIntegrations {
259
310
  url: string;
260
311
  color: string;
261
312
  integrations: IntegrationEntry[];
313
+ vaultAccessMode: VaultAccessMode;
262
314
  reachable: boolean;
263
315
  }
264
316
  export declare function listIntegrationsCatalog(): Promise<AppIntegrations[]>;
265
317
  export declare function listVaultOverview(): Promise<{
318
+ accessMode: VaultAccessMode;
266
319
  secretCount: number;
267
320
  activeGrantCount: number;
321
+ manualGrantCount: number;
268
322
  pendingRequestCount: number;
269
323
  }>;
324
+ export {};
270
325
  //# sourceMappingURL=vault-store.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"vault-store.d.ts","sourceRoot":"","sources":["../../../src/server/lib/vault-store.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"vault-store.d.ts","sourceRoot":"","sources":["../../../src/server/lib/vault-store.ts"],"names":[],"mappings":"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"}
@@ -1,8 +1,11 @@
1
1
  import crypto from "node:crypto";
2
2
  import { and, desc, eq, isNull, or } from "drizzle-orm";
3
3
  import { discoverAgents } from "@agent-native/core/server/agent-discovery";
4
+ import { writeAppSecret } from "@agent-native/core/secrets";
5
+ import { getOrgSetting, getUserSetting, putOrgSetting, putUserSetting, } from "@agent-native/core/settings";
4
6
  import { getDb, schema } from "../../db/index.js";
5
7
  import { currentOwnerEmail, currentOrgId, recordAudit, } from "./dispatch-store.js";
8
+ const VAULT_ACCESS_SETTINGS_KEY = "dispatch-vault-access-settings";
6
9
  /**
7
10
  * Build a VaultCtx from the current request. Throws if the request is
8
11
  * unauthenticated — the previous behavior of falling back to "local@localhost"
@@ -17,7 +20,10 @@ export function requireVaultCtx() {
17
20
  }
18
21
  /** WHERE clause that limits a vault row to the caller's ownership scope. */
19
22
  function ctxScope(table, ctx) {
20
- return or(eq(table.ownerEmail, ctx.ownerEmail), ctx.orgId ? eq(table.orgId, ctx.orgId) : isNull(table.orgId));
23
+ if (!ctx.orgId) {
24
+ return and(eq(table.ownerEmail, ctx.ownerEmail), isNull(table.orgId));
25
+ }
26
+ return or(eq(table.ownerEmail, ctx.ownerEmail), eq(table.orgId, ctx.orgId));
21
27
  }
22
28
  /** Build a ctx that scopes to a specific row's owner/org (used when a
23
29
  * request approver acts on behalf of the original requester so the
@@ -34,9 +40,50 @@ function now() {
34
40
  function safeJson(value) {
35
41
  return JSON.stringify(value ?? null);
36
42
  }
37
- function orgFilter(table) {
43
+ function scopedFilter(table) {
44
+ return ctxScope(table, requireVaultCtx());
45
+ }
46
+ function normalizeCredentialKey(value) {
47
+ return value.trim();
48
+ }
49
+ function vaultAccessScope() {
38
50
  const orgId = currentOrgId();
39
- return and(eq(table.ownerEmail, currentOwnerEmail()), orgId ? eq(table.orgId, orgId) : isNull(table.orgId));
51
+ if (orgId)
52
+ return { scope: "org", scopeId: orgId };
53
+ return { scope: "user", scopeId: currentOwnerEmail() };
54
+ }
55
+ function parseVaultAccessMode(value) {
56
+ return value === "manual" ? "manual" : "all-apps";
57
+ }
58
+ export async function getVaultAccessSettings() {
59
+ const scope = vaultAccessScope();
60
+ const raw = scope.scope === "org"
61
+ ? await getOrgSetting(scope.scopeId, VAULT_ACCESS_SETTINGS_KEY)
62
+ : await getUserSetting(scope.scopeId, VAULT_ACCESS_SETTINGS_KEY);
63
+ return {
64
+ ...scope,
65
+ mode: parseVaultAccessMode(raw?.mode),
66
+ };
67
+ }
68
+ export async function setVaultAccessSettings(input) {
69
+ const scope = vaultAccessScope();
70
+ const next = { mode: parseVaultAccessMode(input.mode) };
71
+ if (scope.scope === "org") {
72
+ await putOrgSetting(scope.scopeId, VAULT_ACCESS_SETTINGS_KEY, next);
73
+ }
74
+ else {
75
+ await putUserSetting(scope.scopeId, VAULT_ACCESS_SETTINGS_KEY, next);
76
+ }
77
+ await recordAudit({
78
+ action: "vault.access-settings.updated",
79
+ targetType: "vault-settings",
80
+ targetId: VAULT_ACCESS_SETTINGS_KEY,
81
+ summary: next.mode === "all-apps"
82
+ ? "Set vault access to all workspace apps"
83
+ : "Set vault access to manual per-app grants",
84
+ metadata: next,
85
+ });
86
+ return getVaultAccessSettings();
40
87
  }
41
88
  // ─── Vault Audit ──────────────────────────────────────────────────
42
89
  export async function recordVaultAudit(input) {
@@ -59,7 +106,7 @@ export async function listVaultAudit(limit = 50) {
59
106
  return db
60
107
  .select()
61
108
  .from(schema.vaultAuditLog)
62
- .where(orgFilter(schema.vaultAuditLog))
109
+ .where(scopedFilter(schema.vaultAuditLog))
63
110
  .orderBy(desc(schema.vaultAuditLog.createdAt))
64
111
  .limit(limit);
65
112
  }
@@ -69,7 +116,7 @@ export async function listSecrets() {
69
116
  return db
70
117
  .select()
71
118
  .from(schema.vaultSecrets)
72
- .where(orgFilter(schema.vaultSecrets))
119
+ .where(scopedFilter(schema.vaultSecrets))
73
120
  .orderBy(desc(schema.vaultSecrets.updatedAt));
74
121
  }
75
122
  export async function getSecret(secretId, ctx) {
@@ -84,6 +131,41 @@ export async function getSecret(secretId, ctx) {
84
131
  export async function createSecret(input, ctx = requireVaultCtx()) {
85
132
  const db = getDb();
86
133
  const timestamp = now();
134
+ const credentialKey = normalizeCredentialKey(input.credentialKey);
135
+ if (!credentialKey)
136
+ throw new Error("Credential key is required");
137
+ const existing = await db
138
+ .select()
139
+ .from(schema.vaultSecrets)
140
+ .where(and(eq(schema.vaultSecrets.credentialKey, credentialKey), ctxScope(schema.vaultSecrets, ctx)))
141
+ .orderBy(desc(schema.vaultSecrets.updatedAt))
142
+ .limit(1);
143
+ if (existing[0]) {
144
+ await db
145
+ .update(schema.vaultSecrets)
146
+ .set({
147
+ name: input.name,
148
+ credentialKey,
149
+ value: input.value,
150
+ provider: input.provider || null,
151
+ description: input.description || null,
152
+ updatedAt: timestamp,
153
+ })
154
+ .where(and(eq(schema.vaultSecrets.id, existing[0].id), ctxScope(schema.vaultSecrets, ctx)));
155
+ await recordVaultAudit({
156
+ action: "secret.updated",
157
+ secretId: existing[0].id,
158
+ summary: `Updated secret "${input.name}" (${credentialKey})`,
159
+ metadata: { credentialKey, provider: input.provider },
160
+ });
161
+ await recordAudit({
162
+ action: "vault.secret.updated",
163
+ targetType: "vault-secret",
164
+ targetId: existing[0].id,
165
+ summary: `Updated vault secret "${input.name}" (${credentialKey})`,
166
+ });
167
+ return getSecret(existing[0].id, ctx);
168
+ }
87
169
  const secretId = id();
88
170
  const actor = ctx.ownerEmail;
89
171
  await db.insert(schema.vaultSecrets).values({
@@ -91,7 +173,7 @@ export async function createSecret(input, ctx = requireVaultCtx()) {
91
173
  ownerEmail: actor,
92
174
  orgId: ctx.orgId,
93
175
  name: input.name,
94
- credentialKey: input.credentialKey,
176
+ credentialKey,
95
177
  value: input.value,
96
178
  provider: input.provider || null,
97
179
  description: input.description || null,
@@ -102,14 +184,14 @@ export async function createSecret(input, ctx = requireVaultCtx()) {
102
184
  await recordVaultAudit({
103
185
  action: "secret.created",
104
186
  secretId,
105
- summary: `Created secret "${input.name}" (${input.credentialKey})`,
106
- metadata: { credentialKey: input.credentialKey, provider: input.provider },
187
+ summary: `Created secret "${input.name}" (${credentialKey})`,
188
+ metadata: { credentialKey, provider: input.provider },
107
189
  });
108
190
  await recordAudit({
109
191
  action: "vault.secret.created",
110
192
  targetType: "vault-secret",
111
193
  targetId: secretId,
112
- summary: `Created vault secret "${input.name}" (${input.credentialKey})`,
194
+ summary: `Created vault secret "${input.name}" (${credentialKey})`,
113
195
  });
114
196
  return getSecret(secretId, ctx);
115
197
  }
@@ -160,7 +242,7 @@ export async function deleteSecret(secretId, ctx = requireVaultCtx()) {
160
242
  // ─── Grants ──────────────────────────────────────────────────────
161
243
  export async function listGrants(filter) {
162
244
  const db = getDb();
163
- const conditions = [orgFilter(schema.vaultGrants)];
245
+ const conditions = [scopedFilter(schema.vaultGrants)];
164
246
  if (filter?.secretId) {
165
247
  conditions.push(eq(schema.vaultGrants.secretId, filter.secretId));
166
248
  }
@@ -218,7 +300,16 @@ export async function createGrant(secretId, appId, ctx = requireVaultCtx()) {
218
300
  return getGrant(grantId);
219
301
  }
220
302
  export async function grantSecretsToApp(secretIds, appId, ctx = requireVaultCtx()) {
303
+ const access = await getVaultAccessSettings();
221
304
  const uniqueSecretIds = Array.from(new Set(secretIds));
305
+ if (access.mode === "all-apps") {
306
+ return {
307
+ appId,
308
+ accessMode: access.mode,
309
+ created: [],
310
+ skipped: uniqueSecretIds,
311
+ };
312
+ }
222
313
  const existingActive = (await listGrants({ appId })).filter((grant) => grant.status === "active");
223
314
  const existingSecretIds = new Set(existingActive.map((grant) => grant.secretId));
224
315
  const created = [];
@@ -234,7 +325,7 @@ export async function grantSecretsToApp(secretIds, appId, ctx = requireVaultCtx(
234
325
  existingSecretIds.add(secretId);
235
326
  }
236
327
  }
237
- return { appId, created, skipped };
328
+ return { appId, accessMode: access.mode, created, skipped };
238
329
  }
239
330
  export async function revokeGrant(grantId, ctx = requireVaultCtx()) {
240
331
  const db = getDb();
@@ -261,43 +352,92 @@ export async function revokeGrant(grantId, ctx = requireVaultCtx()) {
261
352
  });
262
353
  return getGrant(grantId, ctx);
263
354
  }
355
+ export function credentialStoreScopeForVaultCtx(ctx) {
356
+ if (ctx.orgId)
357
+ return { scope: "org", scopeId: ctx.orgId };
358
+ return { scope: "workspace", scopeId: `solo:${ctx.ownerEmail}` };
359
+ }
360
+ export async function syncSecretsToCredentialStore(secrets, ctx) {
361
+ const target = credentialStoreScopeForVaultCtx(ctx);
362
+ const syncedKeys = [];
363
+ for (const secret of secrets) {
364
+ if (!secret.credentialKey || !secret.value)
365
+ continue;
366
+ await writeAppSecret({
367
+ key: secret.credentialKey,
368
+ value: secret.value,
369
+ scope: target.scope,
370
+ scopeId: target.scopeId,
371
+ description: `Synced from Dispatch vault: ${secret.name}`,
372
+ });
373
+ syncedKeys.push(secret.credentialKey);
374
+ }
375
+ return { ...target, keys: syncedKeys };
376
+ }
264
377
  // ─── Sync ──────────────────────────────────────────────────────
265
378
  export async function syncGrantsToApp(appId, ctx = requireVaultCtx()) {
266
379
  const db = getDb();
380
+ const access = await getVaultAccessSettings();
267
381
  const agents = await discoverAgents("dispatch");
268
382
  const agent = agents.find((a) => a.id === appId);
269
383
  if (!agent)
270
384
  throw new Error(`App "${appId}" not found in agent registry`);
271
- const grants = await listGrants({ appId });
272
- const activeGrants = grants.filter((g) => g.status === "active");
273
- if (activeGrants.length === 0) {
274
- return { appId, synced: 0, keys: [] };
385
+ const secretsToSync = [];
386
+ const activeGrants = access.mode === "manual"
387
+ ? (await listGrants({ appId })).filter((g) => g.status === "active")
388
+ : [];
389
+ if (access.mode === "all-apps") {
390
+ const secrets = await listSecrets();
391
+ for (const secret of secrets) {
392
+ secretsToSync.push(secret);
393
+ }
275
394
  }
276
- // Resolve secret values for each grant
277
- const vars = [];
278
- for (const grant of activeGrants) {
279
- const secret = await getSecret(grant.secretId, ctx);
280
- if (secret) {
281
- vars.push({ key: secret.credentialKey, value: secret.value });
395
+ else {
396
+ for (const grant of activeGrants) {
397
+ const secret = await getSecret(grant.secretId, ctx);
398
+ if (secret) {
399
+ secretsToSync.push(secret);
400
+ }
282
401
  }
283
402
  }
284
- if (vars.length === 0) {
285
- return { appId, synced: 0, keys: [] };
403
+ if (secretsToSync.length === 0) {
404
+ return { appId, accessMode: access.mode, synced: 0, keys: [] };
286
405
  }
287
- // Push to the app's env-vars endpoint
288
- const res = await fetch(`${agent.url}/_agent-native/env-vars`, {
289
- method: "POST",
290
- headers: { "Content-Type": "application/json" },
291
- body: JSON.stringify({ vars }),
292
- });
293
- if (!res.ok) {
294
- const err = await res.text().catch(() => "Unknown error");
295
- throw new Error(`Failed to sync to ${appId}: ${err}`);
406
+ const credentialStoreSync = await syncSecretsToCredentialStore(secretsToSync, ctx);
407
+ const vars = secretsToSync.map((secret) => ({
408
+ key: secret.credentialKey,
409
+ value: secret.value,
410
+ }));
411
+ let envVarSync;
412
+ // Best-effort push to the app's env-vars endpoint for local/dev apps that
413
+ // still read process.env directly. Production/shared-DB apps intentionally
414
+ // reject env writes; the encrypted app_secrets sync above is the canonical
415
+ // path for request-scoped credentials.
416
+ try {
417
+ const res = await fetch(`${agent.url}/_agent-native/env-vars`, {
418
+ method: "POST",
419
+ headers: { "Content-Type": "application/json" },
420
+ body: JSON.stringify({ vars }),
421
+ });
422
+ if (res.ok) {
423
+ const result = await res.json();
424
+ envVarSync = { status: "synced", keys: result.saved || [] };
425
+ }
426
+ else {
427
+ const err = await res.text().catch(() => "Unknown error");
428
+ envVarSync = { status: "skipped", reason: err };
429
+ }
296
430
  }
297
- const result = await res.json();
298
- const syncedKeys = result.saved || [];
431
+ catch (err) {
432
+ envVarSync = {
433
+ status: "failed",
434
+ reason: err instanceof Error ? err.message : String(err),
435
+ };
436
+ }
437
+ const syncedKeys = credentialStoreSync.keys;
299
438
  const timestamp = now();
300
- // Update syncedAt on grants that were successfully pushed
439
+ // Update syncedAt on grants that were successfully pushed to the shared
440
+ // credential store. All-apps mode has no explicit grant rows to update.
301
441
  for (const grant of activeGrants) {
302
442
  const secret = await getSecret(grant.secretId, ctx);
303
443
  if (secret && syncedKeys.includes(secret.credentialKey)) {
@@ -311,14 +451,33 @@ export async function syncGrantsToApp(appId, ctx = requireVaultCtx()) {
311
451
  action: "secret.synced",
312
452
  appId,
313
453
  summary: `Synced ${syncedKeys.length} secret(s) to ${appId}: ${syncedKeys.join(", ")}`,
314
- metadata: { syncedKeys },
454
+ metadata: {
455
+ syncedKeys,
456
+ accessMode: access.mode,
457
+ credentialStore: {
458
+ scope: credentialStoreSync.scope,
459
+ scopeId: credentialStoreSync.scopeId,
460
+ },
461
+ envVars: envVarSync,
462
+ },
315
463
  });
316
- return { appId, synced: syncedKeys.length, keys: syncedKeys };
464
+ return {
465
+ appId,
466
+ accessMode: access.mode,
467
+ synced: syncedKeys.length,
468
+ keys: syncedKeys,
469
+ credentialStore: {
470
+ scope: credentialStoreSync.scope,
471
+ scopeId: credentialStoreSync.scopeId,
472
+ synced: credentialStoreSync.keys.length,
473
+ },
474
+ envVars: envVarSync,
475
+ };
317
476
  }
318
477
  // ─── Requests ──────────────────────────────────────────────────────
319
478
  export async function listRequests(filter) {
320
479
  const db = getDb();
321
- const conditions = [orgFilter(schema.vaultRequests)];
480
+ const conditions = [scopedFilter(schema.vaultRequests)];
322
481
  if (filter?.status) {
323
482
  conditions.push(eq(schema.vaultRequests.status, filter.status));
324
483
  }
@@ -441,6 +600,7 @@ export async function denyRequest(requestId, reason, ctx = requireVaultCtx()) {
441
600
  return getRequest(requestId, ctx);
442
601
  }
443
602
  export async function listIntegrationsCatalog() {
603
+ const access = await getVaultAccessSettings();
444
604
  const agents = await discoverAgents("dispatch");
445
605
  const grants = await listGrants();
446
606
  const secrets = await listSecrets();
@@ -458,6 +618,7 @@ export async function listIntegrationsCatalog() {
458
618
  url: agent.url,
459
619
  color: agent.color,
460
620
  integrations: [],
621
+ vaultAccessMode: access.mode,
461
622
  reachable: false,
462
623
  });
463
624
  continue;
@@ -472,7 +633,9 @@ export async function listIntegrationsCatalog() {
472
633
  label: env.label,
473
634
  required: env.required,
474
635
  configured: env.configured,
475
- vaultGranted: !!matchingSecret && grantedSecretIds.has(matchingSecret.id),
636
+ vaultGranted: !!matchingSecret &&
637
+ (access.mode === "all-apps" ||
638
+ grantedSecretIds.has(matchingSecret.id)),
476
639
  vaultSecretId: matchingSecret?.id,
477
640
  };
478
641
  });
@@ -482,6 +645,7 @@ export async function listIntegrationsCatalog() {
482
645
  url: agent.url,
483
646
  color: agent.color,
484
647
  integrations,
648
+ vaultAccessMode: access.mode,
485
649
  reachable: true,
486
650
  });
487
651
  }
@@ -492,6 +656,7 @@ export async function listIntegrationsCatalog() {
492
656
  url: agent.url,
493
657
  color: agent.color,
494
658
  integrations: [],
659
+ vaultAccessMode: access.mode,
495
660
  reachable: false,
496
661
  });
497
662
  }
@@ -500,14 +665,18 @@ export async function listIntegrationsCatalog() {
500
665
  }
501
666
  // ─── Vault Overview (for dashboard) ──────────────────────────────
502
667
  export async function listVaultOverview() {
503
- const [secrets, grants, requests] = await Promise.all([
668
+ const [secrets, grants, requests, access] = await Promise.all([
504
669
  listSecrets(),
505
670
  listGrants(),
506
671
  listRequests(),
672
+ getVaultAccessSettings(),
507
673
  ]);
674
+ const manualGrantCount = grants.filter((g) => g.status === "active").length;
508
675
  return {
676
+ accessMode: access.mode,
509
677
  secretCount: secrets.length,
510
- activeGrantCount: grants.filter((g) => g.status === "active").length,
678
+ activeGrantCount: access.mode === "all-apps" ? secrets.length : manualGrantCount,
679
+ manualGrantCount,
511
680
  pendingRequestCount: requests.filter((r) => r.status === "pending").length,
512
681
  };
513
682
  }