@agent-native/dispatch 0.6.1 → 0.8.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 (341) hide show
  1. package/README.md +38 -1
  2. package/dist/actions/apply-dream-proposal.d.ts +3 -0
  3. package/dist/actions/apply-dream-proposal.d.ts.map +1 -0
  4. package/dist/actions/apply-dream-proposal.js +11 -0
  5. package/dist/actions/apply-dream-proposal.js.map +1 -0
  6. package/dist/actions/create-dream-report.d.ts +3 -0
  7. package/dist/actions/create-dream-report.d.ts.map +1 -0
  8. package/dist/actions/create-dream-report.js +67 -0
  9. package/dist/actions/create-dream-report.js.map +1 -0
  10. package/dist/actions/create-pylon-ticket.d.ts +3 -0
  11. package/dist/actions/create-pylon-ticket.d.ts.map +1 -0
  12. package/dist/actions/create-pylon-ticket.js +94 -0
  13. package/dist/actions/create-pylon-ticket.js.map +1 -0
  14. package/dist/actions/create-vault-grant.js +1 -1
  15. package/dist/actions/create-vault-grant.js.map +1 -1
  16. package/dist/actions/create-vault-secret.d.ts.map +1 -1
  17. package/dist/actions/create-vault-secret.js +4 -3
  18. package/dist/actions/create-vault-secret.js.map +1 -1
  19. package/dist/actions/create-workspace-resource.js +3 -3
  20. package/dist/actions/create-workspace-resource.js.map +1 -1
  21. package/dist/actions/delete-workspace-resource.js +1 -1
  22. package/dist/actions/delete-workspace-resource.js.map +1 -1
  23. package/dist/actions/ensure-dream-job.d.ts +3 -0
  24. package/dist/actions/ensure-dream-job.d.ts.map +1 -0
  25. package/dist/actions/ensure-dream-job.js +73 -0
  26. package/dist/actions/ensure-dream-job.js.map +1 -0
  27. package/dist/actions/get-dream-settings.d.ts +3 -0
  28. package/dist/actions/get-dream-settings.d.ts.map +1 -0
  29. package/dist/actions/get-dream-settings.js +11 -0
  30. package/dist/actions/get-dream-settings.js.map +1 -0
  31. package/dist/actions/get-dream.d.ts +3 -0
  32. package/dist/actions/get-dream.d.ts.map +1 -0
  33. package/dist/actions/get-dream.js +13 -0
  34. package/dist/actions/get-dream.js.map +1 -0
  35. package/dist/actions/get-vault-access-settings.d.ts +3 -0
  36. package/dist/actions/get-vault-access-settings.d.ts.map +1 -0
  37. package/dist/actions/get-vault-access-settings.js +10 -0
  38. package/dist/actions/get-vault-access-settings.js.map +1 -0
  39. package/dist/actions/get-workspace-resource-effective-context.d.ts +3 -0
  40. package/dist/actions/get-workspace-resource-effective-context.d.ts.map +1 -0
  41. package/dist/actions/get-workspace-resource-effective-context.js +27 -0
  42. package/dist/actions/get-workspace-resource-effective-context.js.map +1 -0
  43. package/dist/actions/grant-vault-secrets-to-app.js +1 -1
  44. package/dist/actions/grant-vault-secrets-to-app.js.map +1 -1
  45. package/dist/actions/index.d.ts.map +1 -1
  46. package/dist/actions/index.js +38 -4
  47. package/dist/actions/index.js.map +1 -1
  48. package/dist/actions/list-dream-candidates.d.ts +3 -0
  49. package/dist/actions/list-dream-candidates.d.ts.map +1 -0
  50. package/dist/actions/list-dream-candidates.js +68 -0
  51. package/dist/actions/list-dream-candidates.js.map +1 -0
  52. package/dist/actions/list-dreams.d.ts +3 -0
  53. package/dist/actions/list-dreams.d.ts.map +1 -0
  54. package/dist/actions/list-dreams.js +17 -0
  55. package/dist/actions/list-dreams.js.map +1 -0
  56. package/dist/actions/list-integrations-catalog.js +1 -1
  57. package/dist/actions/list-integrations-catalog.js.map +1 -1
  58. package/dist/actions/list-vault-grants.js +1 -1
  59. package/dist/actions/list-vault-grants.js.map +1 -1
  60. package/dist/actions/list-workspace-apps.d.ts.map +1 -1
  61. package/dist/actions/list-workspace-apps.js +5 -1
  62. package/dist/actions/list-workspace-apps.js.map +1 -1
  63. package/dist/actions/list-workspace-resources-for-app.d.ts +3 -0
  64. package/dist/actions/list-workspace-resources-for-app.d.ts.map +1 -0
  65. package/dist/actions/list-workspace-resources-for-app.js +12 -0
  66. package/dist/actions/list-workspace-resources-for-app.js.map +1 -0
  67. package/dist/actions/list-workspace-resources.js +1 -1
  68. package/dist/actions/list-workspace-resources.js.map +1 -1
  69. package/dist/actions/navigate.d.ts +1 -0
  70. package/dist/actions/navigate.d.ts.map +1 -1
  71. package/dist/actions/navigate.js +2 -1
  72. package/dist/actions/navigate.js.map +1 -1
  73. package/dist/actions/preview-dream-proposal.d.ts +3 -0
  74. package/dist/actions/preview-dream-proposal.d.ts.map +1 -0
  75. package/dist/actions/preview-dream-proposal.js +13 -0
  76. package/dist/actions/preview-dream-proposal.js.map +1 -0
  77. package/dist/actions/preview-workspace-resource-change.d.ts +3 -0
  78. package/dist/actions/preview-workspace-resource-change.d.ts.map +1 -0
  79. package/dist/actions/preview-workspace-resource-change.js +24 -0
  80. package/dist/actions/preview-workspace-resource-change.js.map +1 -0
  81. package/dist/actions/reject-dream-proposal.d.ts +3 -0
  82. package/dist/actions/reject-dream-proposal.d.ts.map +1 -0
  83. package/dist/actions/reject-dream-proposal.js +12 -0
  84. package/dist/actions/reject-dream-proposal.js.map +1 -0
  85. package/dist/actions/restore-starter-workspace-resources.d.ts +3 -0
  86. package/dist/actions/restore-starter-workspace-resources.d.ts.map +1 -0
  87. package/dist/actions/restore-starter-workspace-resources.js +14 -0
  88. package/dist/actions/restore-starter-workspace-resources.js.map +1 -0
  89. package/dist/actions/send-code-agent-remote-command.d.ts +3 -0
  90. package/dist/actions/send-code-agent-remote-command.d.ts.map +1 -0
  91. package/dist/actions/send-code-agent-remote-command.js +53 -0
  92. package/dist/actions/send-code-agent-remote-command.js.map +1 -0
  93. package/dist/actions/set-dream-settings.d.ts +3 -0
  94. package/dist/actions/set-dream-settings.d.ts.map +1 -0
  95. package/dist/actions/set-dream-settings.js +41 -0
  96. package/dist/actions/set-dream-settings.js.map +1 -0
  97. package/dist/actions/set-vault-access-settings.d.ts +3 -0
  98. package/dist/actions/set-vault-access-settings.d.ts.map +1 -0
  99. package/dist/actions/set-vault-access-settings.js +13 -0
  100. package/dist/actions/set-vault-access-settings.js.map +1 -0
  101. package/dist/actions/start-workspace-app-creation.d.ts.map +1 -1
  102. package/dist/actions/start-workspace-app-creation.js +6 -0
  103. package/dist/actions/start-workspace-app-creation.js.map +1 -1
  104. package/dist/actions/sync-vault-to-app.js +1 -1
  105. package/dist/actions/sync-vault-to-app.js.map +1 -1
  106. package/dist/actions/update-workspace-app-metadata.d.ts +3 -0
  107. package/dist/actions/update-workspace-app-metadata.d.ts.map +1 -0
  108. package/dist/actions/update-workspace-app-metadata.js +30 -0
  109. package/dist/actions/update-workspace-app-metadata.js.map +1 -0
  110. package/dist/actions/update-workspace-resource.js +1 -1
  111. package/dist/actions/update-workspace-resource.js.map +1 -1
  112. package/dist/actions/view-screen.d.ts.map +1 -1
  113. package/dist/actions/view-screen.js +77 -4
  114. package/dist/actions/view-screen.js.map +1 -1
  115. package/dist/components/app-keys-popover.js +16 -5
  116. package/dist/components/app-keys-popover.js.map +1 -1
  117. package/dist/components/approval-value-block.d.ts +7 -0
  118. package/dist/components/approval-value-block.d.ts.map +1 -0
  119. package/dist/components/approval-value-block.js +22 -0
  120. package/dist/components/approval-value-block.js.map +1 -0
  121. package/dist/components/create-app-popover.d.ts.map +1 -1
  122. package/dist/components/create-app-popover.js +41 -16
  123. package/dist/components/create-app-popover.js.map +1 -1
  124. package/dist/components/dispatch-shell.d.ts +4 -4
  125. package/dist/components/dispatch-shell.d.ts.map +1 -1
  126. package/dist/components/dispatch-shell.js +6 -6
  127. package/dist/components/dispatch-shell.js.map +1 -1
  128. package/dist/components/layout/Layout.d.ts.map +1 -1
  129. package/dist/components/layout/Layout.js +18 -4
  130. package/dist/components/layout/Layout.js.map +1 -1
  131. package/dist/components/messaging-setup-panel.d.ts.map +1 -1
  132. package/dist/components/messaging-setup-panel.js +2 -2
  133. package/dist/components/messaging-setup-panel.js.map +1 -1
  134. package/dist/components/ui/chart.d.ts +1 -1
  135. package/dist/components/workspace-app-card.d.ts.map +1 -1
  136. package/dist/components/workspace-app-card.js +63 -3
  137. package/dist/components/workspace-app-card.js.map +1 -1
  138. package/dist/components/workspace-resource-effective-stack.d.ts +11 -0
  139. package/dist/components/workspace-resource-effective-stack.d.ts.map +1 -0
  140. package/dist/components/workspace-resource-effective-stack.js +59 -0
  141. package/dist/components/workspace-resource-effective-stack.js.map +1 -0
  142. package/dist/components/workspace-resource-impact-preview.d.ts +9 -0
  143. package/dist/components/workspace-resource-impact-preview.d.ts.map +1 -0
  144. package/dist/components/workspace-resource-impact-preview.js +39 -0
  145. package/dist/components/workspace-resource-impact-preview.js.map +1 -0
  146. package/dist/db/migrations.d.ts.map +1 -1
  147. package/dist/db/migrations.js +59 -0
  148. package/dist/db/migrations.js.map +1 -1
  149. package/dist/db/schema.d.ts +714 -0
  150. package/dist/db/schema.d.ts.map +1 -1
  151. package/dist/db/schema.js +44 -2
  152. package/dist/db/schema.js.map +1 -1
  153. package/dist/hooks/use-navigation-state.d.ts +3 -0
  154. package/dist/hooks/use-navigation-state.d.ts.map +1 -1
  155. package/dist/hooks/use-navigation-state.js +35 -8
  156. package/dist/hooks/use-navigation-state.js.map +1 -1
  157. package/dist/lib/catch-all-target.d.ts +2 -0
  158. package/dist/lib/catch-all-target.d.ts.map +1 -0
  159. package/dist/lib/catch-all-target.js +95 -0
  160. package/dist/lib/catch-all-target.js.map +1 -0
  161. package/dist/lib/utils.d.ts +2 -1
  162. package/dist/lib/utils.d.ts.map +1 -1
  163. package/dist/lib/utils.js +5 -1
  164. package/dist/lib/utils.js.map +1 -1
  165. package/dist/lib/workspace-apps.d.ts +9 -0
  166. package/dist/lib/workspace-apps.d.ts.map +1 -1
  167. package/dist/lib/workspace-apps.js.map +1 -1
  168. package/dist/routes/index.d.ts.map +1 -1
  169. package/dist/routes/index.js +1 -0
  170. package/dist/routes/index.js.map +1 -1
  171. package/dist/routes/pages/$appId.d.ts +2 -2
  172. package/dist/routes/pages/$appId.d.ts.map +1 -1
  173. package/dist/routes/pages/$appId.js +17 -8
  174. package/dist/routes/pages/$appId.js.map +1 -1
  175. package/dist/routes/pages/approval.d.ts.map +1 -1
  176. package/dist/routes/pages/approval.js +4 -1
  177. package/dist/routes/pages/approval.js.map +1 -1
  178. package/dist/routes/pages/approvals.js +1 -1
  179. package/dist/routes/pages/approvals.js.map +1 -1
  180. package/dist/routes/pages/dream-settings.d.ts +34 -0
  181. package/dist/routes/pages/dream-settings.d.ts.map +1 -0
  182. package/dist/routes/pages/dream-settings.js +68 -0
  183. package/dist/routes/pages/dream-settings.js.map +1 -0
  184. package/dist/routes/pages/dreams.d.ts +5 -0
  185. package/dist/routes/pages/dreams.d.ts.map +1 -0
  186. package/dist/routes/pages/dreams.js +435 -0
  187. package/dist/routes/pages/dreams.js.map +1 -0
  188. package/dist/routes/pages/integrations.d.ts.map +1 -1
  189. package/dist/routes/pages/integrations.js +20 -15
  190. package/dist/routes/pages/integrations.js.map +1 -1
  191. package/dist/routes/pages/new-app.js +1 -1
  192. package/dist/routes/pages/new-app.js.map +1 -1
  193. package/dist/routes/pages/overview.d.ts.map +1 -1
  194. package/dist/routes/pages/overview.js +5 -1
  195. package/dist/routes/pages/overview.js.map +1 -1
  196. package/dist/routes/pages/vault.d.ts.map +1 -1
  197. package/dist/routes/pages/vault.js +23 -5
  198. package/dist/routes/pages/vault.js.map +1 -1
  199. package/dist/routes/pages/workspace.d.ts.map +1 -1
  200. package/dist/routes/pages/workspace.js +187 -35
  201. package/dist/routes/pages/workspace.js.map +1 -1
  202. package/dist/server/lib/app-creation-store.d.ts +13 -0
  203. package/dist/server/lib/app-creation-store.d.ts.map +1 -1
  204. package/dist/server/lib/app-creation-store.js +298 -11
  205. package/dist/server/lib/app-creation-store.js.map +1 -1
  206. package/dist/server/lib/dispatch-integrations.d.ts +1 -1
  207. package/dist/server/lib/dispatch-integrations.d.ts.map +1 -1
  208. package/dist/server/lib/dispatch-integrations.js +9 -4
  209. package/dist/server/lib/dispatch-integrations.js.map +1 -1
  210. package/dist/server/lib/dispatch-remote-commands.d.ts +83 -0
  211. package/dist/server/lib/dispatch-remote-commands.d.ts.map +1 -0
  212. package/dist/server/lib/dispatch-remote-commands.js +256 -0
  213. package/dist/server/lib/dispatch-remote-commands.js.map +1 -0
  214. package/dist/server/lib/dispatch-store.d.ts +26 -0
  215. package/dist/server/lib/dispatch-store.d.ts.map +1 -1
  216. package/dist/server/lib/dispatch-store.js +17 -1
  217. package/dist/server/lib/dispatch-store.js.map +1 -1
  218. package/dist/server/lib/dreams-store.d.ts +398 -0
  219. package/dist/server/lib/dreams-store.d.ts.map +1 -0
  220. package/dist/server/lib/dreams-store.js +2330 -0
  221. package/dist/server/lib/dreams-store.js.map +1 -0
  222. package/dist/server/lib/env-config.d.ts.map +1 -1
  223. package/dist/server/lib/env-config.js +5 -0
  224. package/dist/server/lib/env-config.js.map +1 -1
  225. package/dist/server/lib/onboarding-steps.d.ts +12 -0
  226. package/dist/server/lib/onboarding-steps.d.ts.map +1 -0
  227. package/dist/server/lib/onboarding-steps.js +47 -0
  228. package/dist/server/lib/onboarding-steps.js.map +1 -0
  229. package/dist/server/lib/thread-debug-store.d.ts +2 -2
  230. package/dist/server/lib/vault-store.d.ts +55 -0
  231. package/dist/server/lib/vault-store.d.ts.map +1 -1
  232. package/dist/server/lib/vault-store.js +210 -41
  233. package/dist/server/lib/vault-store.js.map +1 -1
  234. package/dist/server/lib/workspace-resources-store.d.ts +181 -17
  235. package/dist/server/lib/workspace-resources-store.d.ts.map +1 -1
  236. package/dist/server/lib/workspace-resources-store.js +737 -108
  237. package/dist/server/lib/workspace-resources-store.js.map +1 -1
  238. package/dist/server/plugins/agent-chat.d.ts.map +1 -1
  239. package/dist/server/plugins/agent-chat.js +2 -1
  240. package/dist/server/plugins/agent-chat.js.map +1 -1
  241. package/dist/server/plugins/core-routes.d.ts.map +1 -1
  242. package/dist/server/plugins/core-routes.js +4 -0
  243. package/dist/server/plugins/core-routes.js.map +1 -1
  244. package/dist/server/plugins/integrations.js +2 -2
  245. package/dist/server/plugins/integrations.js.map +1 -1
  246. package/package.json +15 -11
  247. package/src/actions/apply-dream-proposal.ts +12 -0
  248. package/src/actions/create-dream-report.ts +76 -0
  249. package/src/actions/create-pylon-ticket.ts +109 -0
  250. package/src/actions/create-vault-grant.ts +1 -1
  251. package/src/actions/create-vault-secret.ts +4 -3
  252. package/src/actions/create-workspace-resource.ts +3 -3
  253. package/src/actions/delete-workspace-resource.ts +1 -1
  254. package/src/actions/ensure-dream-job.ts +76 -0
  255. package/src/actions/get-dream-settings.ts +12 -0
  256. package/src/actions/get-dream.ts +14 -0
  257. package/src/actions/get-vault-access-settings.ts +11 -0
  258. package/src/actions/get-workspace-resource-effective-context.ts +34 -0
  259. package/src/actions/grant-vault-secrets-to-app.ts +1 -1
  260. package/src/actions/index.spec.ts +26 -0
  261. package/src/actions/index.ts +39 -4
  262. package/src/actions/list-dream-candidates.ts +77 -0
  263. package/src/actions/list-dreams.ts +17 -0
  264. package/src/actions/list-integrations-catalog.ts +1 -1
  265. package/src/actions/list-vault-grants.ts +1 -1
  266. package/src/actions/list-workspace-apps.ts +5 -1
  267. package/src/actions/list-workspace-resources-for-app.ts +13 -0
  268. package/src/actions/list-workspace-resources.ts +1 -1
  269. package/src/actions/navigate.ts +2 -1
  270. package/src/actions/preview-dream-proposal.ts +14 -0
  271. package/src/actions/preview-workspace-resource-change.ts +25 -0
  272. package/src/actions/reject-dream-proposal.ts +12 -0
  273. package/src/actions/restore-starter-workspace-resources.ts +17 -0
  274. package/src/actions/send-code-agent-remote-command.ts +59 -0
  275. package/src/actions/set-dream-settings.spec.ts +81 -0
  276. package/src/actions/set-dream-settings.ts +44 -0
  277. package/src/actions/set-vault-access-settings.ts +16 -0
  278. package/src/actions/start-workspace-app-creation.ts +8 -0
  279. package/src/actions/sync-vault-to-app.ts +1 -1
  280. package/src/actions/update-workspace-app-metadata.ts +32 -0
  281. package/src/actions/update-workspace-resource.ts +1 -1
  282. package/src/actions/view-screen.ts +94 -3
  283. package/src/components/app-keys-popover.tsx +23 -7
  284. package/src/components/approval-value-block.spec.tsx +59 -0
  285. package/src/components/approval-value-block.tsx +33 -0
  286. package/src/components/create-app-popover.tsx +50 -16
  287. package/src/components/dispatch-shell.tsx +16 -15
  288. package/src/components/layout/Layout.tsx +19 -5
  289. package/src/components/messaging-setup-panel.tsx +54 -39
  290. package/src/components/workspace-app-card.tsx +268 -1
  291. package/src/components/workspace-resource-effective-stack.spec.tsx +125 -0
  292. package/src/components/workspace-resource-effective-stack.tsx +141 -0
  293. package/src/components/workspace-resource-impact-preview.spec.tsx +147 -0
  294. package/src/components/workspace-resource-impact-preview.tsx +116 -0
  295. package/src/db/migrations.ts +59 -0
  296. package/src/db/schema.ts +46 -2
  297. package/src/hooks/use-navigation-state.ts +34 -9
  298. package/src/lib/catch-all-target.spec.ts +218 -0
  299. package/src/lib/catch-all-target.ts +99 -0
  300. package/src/lib/utils.ts +6 -1
  301. package/src/lib/workspace-apps.ts +9 -0
  302. package/src/routes/index.ts +1 -0
  303. package/src/routes/pages/$appId.tsx +21 -8
  304. package/src/routes/pages/approval.tsx +14 -1
  305. package/src/routes/pages/approvals.tsx +1 -1
  306. package/src/routes/pages/dream-settings.spec.ts +130 -0
  307. package/src/routes/pages/dream-settings.ts +103 -0
  308. package/src/routes/pages/dreams.tsx +1828 -0
  309. package/src/routes/pages/integrations.tsx +57 -18
  310. package/src/routes/pages/new-app.tsx +1 -1
  311. package/src/routes/pages/overview.tsx +11 -3
  312. package/src/routes/pages/vault.tsx +76 -9
  313. package/src/routes/pages/workspace.tsx +577 -97
  314. package/src/server/lib/app-creation-store.spec.ts +61 -2
  315. package/src/server/lib/app-creation-store.ts +389 -13
  316. package/src/server/lib/dispatch-integrations.ts +10 -3
  317. package/src/server/lib/dispatch-remote-commands.spec.ts +167 -0
  318. package/src/server/lib/dispatch-remote-commands.ts +375 -0
  319. package/src/server/lib/dispatch-store.ts +37 -1
  320. package/src/server/lib/dreams-store.spec.ts +1492 -0
  321. package/src/server/lib/dreams-store.ts +3168 -0
  322. package/src/server/lib/env-config.ts +5 -0
  323. package/src/server/lib/onboarding-steps.ts +49 -0
  324. package/src/server/lib/vault-store.spec.ts +69 -0
  325. package/src/server/lib/vault-store.ts +266 -49
  326. package/src/server/lib/workspace-resource-approval-lifecycle.spec.ts +236 -0
  327. package/src/server/lib/workspace-resources-store.spec.ts +1106 -0
  328. package/src/server/lib/workspace-resources-store.ts +1001 -134
  329. package/src/server/plugins/agent-chat.ts +2 -1
  330. package/src/server/plugins/core-routes.ts +5 -0
  331. package/src/server/plugins/integrations.ts +2 -2
  332. package/dist/actions/sync-workspace-resources-to-all.d.ts +0 -3
  333. package/dist/actions/sync-workspace-resources-to-all.d.ts.map +0 -1
  334. package/dist/actions/sync-workspace-resources-to-all.js +0 -9
  335. package/dist/actions/sync-workspace-resources-to-all.js.map +0 -1
  336. package/dist/actions/sync-workspace-resources-to-app.d.ts +0 -3
  337. package/dist/actions/sync-workspace-resources-to-app.d.ts.map +0 -1
  338. package/dist/actions/sync-workspace-resources-to-app.js +0 -11
  339. package/dist/actions/sync-workspace-resources-to-app.js.map +0 -1
  340. package/src/actions/sync-workspace-resources-to-all.ts +0 -10
  341. package/src/actions/sync-workspace-resources-to-app.ts +0 -12
@@ -41,4 +41,9 @@ export const envKeys: EnvKeyConfig[] = [
41
41
  label: "WhatsApp phone number ID",
42
42
  required: false,
43
43
  },
44
+ {
45
+ key: "PYLON_API_KEY",
46
+ label: "Pylon API key",
47
+ required: false,
48
+ },
44
49
  ];
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Dispatch-specific onboarding steps.
3
+ *
4
+ * Slack/Telegram/etc. are auto-registered at order 60 by the framework when
5
+ * their env keys are declared `required: true` in `env-config.ts`. Without
6
+ * any earlier dispatch-specific step, a brand-new workspace lands on
7
+ * "Connect Slack" as the first visible to-do — which is intimidating before
8
+ * the user has even created a real app. This step nudges them at adding
9
+ * their first workspace app first.
10
+ */
11
+
12
+ import { registerOnboardingStep } from "@agent-native/core/onboarding";
13
+ import { listWorkspaceApps } from "./app-creation-store.js";
14
+
15
+ let registered = false;
16
+
17
+ export function registerDispatchOnboardingSteps(): void {
18
+ if (registered) return;
19
+ registered = true;
20
+
21
+ registerOnboardingStep({
22
+ id: "dispatch:create-first-app",
23
+ title: "Create your first app",
24
+ description:
25
+ "Add a workspace app like Mail, Calendar, or Slides — or describe a custom app from the Apps page.",
26
+ order: 5,
27
+ required: false,
28
+ methods: [
29
+ {
30
+ id: "open-apps",
31
+ kind: "link",
32
+ primary: true,
33
+ label: "Browse apps",
34
+ payload: { url: "/dispatch/apps", external: false },
35
+ },
36
+ ],
37
+ isComplete: async () => {
38
+ try {
39
+ const apps = await listWorkspaceApps({
40
+ includeAgentCards: false,
41
+ includeArchived: true,
42
+ });
43
+ return apps.some((app) => !app.isDispatch);
44
+ } catch {
45
+ return false;
46
+ }
47
+ },
48
+ });
49
+ }
@@ -0,0 +1,69 @@
1
+ import { afterEach, describe, expect, it, vi } from "vitest";
2
+
3
+ const mocks = vi.hoisted(() => ({
4
+ writeAppSecret: vi.fn(),
5
+ }));
6
+
7
+ vi.mock("@agent-native/core/secrets", () => ({
8
+ writeAppSecret: mocks.writeAppSecret,
9
+ }));
10
+
11
+ import {
12
+ credentialStoreScopeForVaultCtx,
13
+ syncSecretsToCredentialStore,
14
+ } from "./vault-store.js";
15
+
16
+ afterEach(() => {
17
+ vi.clearAllMocks();
18
+ });
19
+
20
+ describe("credentialStoreScopeForVaultCtx", () => {
21
+ it("uses org scope when vault sync runs inside an org", () => {
22
+ expect(
23
+ credentialStoreScopeForVaultCtx({
24
+ ownerEmail: "admin@example.test",
25
+ orgId: "org_123",
26
+ }),
27
+ ).toEqual({ scope: "org", scopeId: "org_123" });
28
+ });
29
+
30
+ it("uses workspace solo scope when no org is active", () => {
31
+ expect(
32
+ credentialStoreScopeForVaultCtx({
33
+ ownerEmail: "owner@example.test",
34
+ orgId: null,
35
+ }),
36
+ ).toEqual({
37
+ scope: "workspace",
38
+ scopeId: "solo:owner@example.test",
39
+ });
40
+ });
41
+ });
42
+
43
+ describe("syncSecretsToCredentialStore", () => {
44
+ it("writes vault secrets into app_secrets without returning values", async () => {
45
+ const result = await syncSecretsToCredentialStore(
46
+ [
47
+ {
48
+ name: "OpenAI API Key",
49
+ credentialKey: "OPENAI_API_KEY",
50
+ value: "sk-test-key",
51
+ } as any,
52
+ ],
53
+ { ownerEmail: "admin@example.test", orgId: "org_123" },
54
+ );
55
+
56
+ expect(mocks.writeAppSecret).toHaveBeenCalledWith({
57
+ key: "OPENAI_API_KEY",
58
+ value: "sk-test-key",
59
+ scope: "org",
60
+ scopeId: "org_123",
61
+ description: "Synced from Dispatch vault: OpenAI API Key",
62
+ });
63
+ expect(result).toEqual({
64
+ scope: "org",
65
+ scopeId: "org_123",
66
+ keys: ["OPENAI_API_KEY"],
67
+ });
68
+ });
69
+ });
@@ -1,6 +1,13 @@
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, type SecretScope } from "@agent-native/core/secrets";
5
+ import {
6
+ getOrgSetting,
7
+ getUserSetting,
8
+ putOrgSetting,
9
+ putUserSetting,
10
+ } from "@agent-native/core/settings";
4
11
  import { getDb, schema } from "../../db/index.js";
5
12
  import {
6
13
  currentOwnerEmail,
@@ -8,6 +15,16 @@ import {
8
15
  recordAudit,
9
16
  } from "./dispatch-store.js";
10
17
 
18
+ const VAULT_ACCESS_SETTINGS_KEY = "dispatch-vault-access-settings";
19
+
20
+ export type VaultAccessMode = "all-apps" | "manual";
21
+
22
+ export interface VaultAccessSettings {
23
+ mode: VaultAccessMode;
24
+ scope: "org" | "user";
25
+ scopeId: string;
26
+ }
27
+
11
28
  /**
12
29
  * Caller-supplied access context for vault operations.
13
30
  *
@@ -40,10 +57,10 @@ function ctxScope<T extends { ownerEmail: any; orgId: any }>(
40
57
  table: T,
41
58
  ctx: VaultCtx,
42
59
  ) {
43
- return or(
44
- eq(table.ownerEmail, ctx.ownerEmail),
45
- ctx.orgId ? eq(table.orgId, ctx.orgId) : isNull(table.orgId),
46
- );
60
+ if (!ctx.orgId) {
61
+ return and(eq(table.ownerEmail, ctx.ownerEmail), isNull(table.orgId));
62
+ }
63
+ return or(eq(table.ownerEmail, ctx.ownerEmail), eq(table.orgId, ctx.orgId));
47
64
  }
48
65
 
49
66
  /** Build a ctx that scopes to a specific row's owner/org (used when a
@@ -68,12 +85,57 @@ function safeJson(value: unknown) {
68
85
  return JSON.stringify(value ?? null);
69
86
  }
70
87
 
71
- function orgFilter<T extends { ownerEmail: any; orgId: any }>(table: T) {
88
+ function scopedFilter<T extends { ownerEmail: any; orgId: any }>(table: T) {
89
+ return ctxScope(table, requireVaultCtx());
90
+ }
91
+
92
+ function normalizeCredentialKey(value: string) {
93
+ return value.trim();
94
+ }
95
+
96
+ function vaultAccessScope() {
72
97
  const orgId = currentOrgId();
73
- return and(
74
- eq(table.ownerEmail, currentOwnerEmail()),
75
- orgId ? eq(table.orgId, orgId) : isNull(table.orgId),
76
- );
98
+ if (orgId) return { scope: "org" as const, scopeId: orgId };
99
+ return { scope: "user" as const, scopeId: currentOwnerEmail() };
100
+ }
101
+
102
+ function parseVaultAccessMode(value: unknown): VaultAccessMode {
103
+ return value === "manual" ? "manual" : "all-apps";
104
+ }
105
+
106
+ export async function getVaultAccessSettings(): Promise<VaultAccessSettings> {
107
+ const scope = vaultAccessScope();
108
+ const raw =
109
+ scope.scope === "org"
110
+ ? await getOrgSetting(scope.scopeId, VAULT_ACCESS_SETTINGS_KEY)
111
+ : await getUserSetting(scope.scopeId, VAULT_ACCESS_SETTINGS_KEY);
112
+ return {
113
+ ...scope,
114
+ mode: parseVaultAccessMode(raw?.mode),
115
+ };
116
+ }
117
+
118
+ export async function setVaultAccessSettings(input: {
119
+ mode: VaultAccessMode;
120
+ }): Promise<VaultAccessSettings> {
121
+ const scope = vaultAccessScope();
122
+ const next = { mode: parseVaultAccessMode(input.mode) };
123
+ if (scope.scope === "org") {
124
+ await putOrgSetting(scope.scopeId, VAULT_ACCESS_SETTINGS_KEY, next);
125
+ } else {
126
+ await putUserSetting(scope.scopeId, VAULT_ACCESS_SETTINGS_KEY, next);
127
+ }
128
+ await recordAudit({
129
+ action: "vault.access-settings.updated",
130
+ targetType: "vault-settings",
131
+ targetId: VAULT_ACCESS_SETTINGS_KEY,
132
+ summary:
133
+ next.mode === "all-apps"
134
+ ? "Set vault access to all workspace apps"
135
+ : "Set vault access to manual per-app grants",
136
+ metadata: next,
137
+ });
138
+ return getVaultAccessSettings();
77
139
  }
78
140
 
79
141
  // ─── Vault Audit ──────────────────────────────────────────────────
@@ -106,7 +168,7 @@ export async function listVaultAudit(limit = 50) {
106
168
  return db
107
169
  .select()
108
170
  .from(schema.vaultAuditLog)
109
- .where(orgFilter(schema.vaultAuditLog))
171
+ .where(scopedFilter(schema.vaultAuditLog))
110
172
  .orderBy(desc(schema.vaultAuditLog.createdAt))
111
173
  .limit(limit);
112
174
  }
@@ -118,7 +180,7 @@ export async function listSecrets() {
118
180
  return db
119
181
  .select()
120
182
  .from(schema.vaultSecrets)
121
- .where(orgFilter(schema.vaultSecrets))
183
+ .where(scopedFilter(schema.vaultSecrets))
122
184
  .orderBy(desc(schema.vaultSecrets.updatedAt));
123
185
  }
124
186
 
@@ -149,6 +211,55 @@ export async function createSecret(
149
211
  ) {
150
212
  const db = getDb();
151
213
  const timestamp = now();
214
+ const credentialKey = normalizeCredentialKey(input.credentialKey);
215
+ if (!credentialKey) throw new Error("Credential key is required");
216
+ const existing = await db
217
+ .select()
218
+ .from(schema.vaultSecrets)
219
+ .where(
220
+ and(
221
+ eq(schema.vaultSecrets.credentialKey, credentialKey),
222
+ ctxScope(schema.vaultSecrets, ctx),
223
+ ),
224
+ )
225
+ .orderBy(desc(schema.vaultSecrets.updatedAt))
226
+ .limit(1);
227
+
228
+ if (existing[0]) {
229
+ await db
230
+ .update(schema.vaultSecrets)
231
+ .set({
232
+ name: input.name,
233
+ credentialKey,
234
+ value: input.value,
235
+ provider: input.provider || null,
236
+ description: input.description || null,
237
+ updatedAt: timestamp,
238
+ })
239
+ .where(
240
+ and(
241
+ eq(schema.vaultSecrets.id, existing[0].id),
242
+ ctxScope(schema.vaultSecrets, ctx),
243
+ ),
244
+ );
245
+
246
+ await recordVaultAudit({
247
+ action: "secret.updated",
248
+ secretId: existing[0].id,
249
+ summary: `Updated secret "${input.name}" (${credentialKey})`,
250
+ metadata: { credentialKey, provider: input.provider },
251
+ });
252
+
253
+ await recordAudit({
254
+ action: "vault.secret.updated",
255
+ targetType: "vault-secret",
256
+ targetId: existing[0].id,
257
+ summary: `Updated vault secret "${input.name}" (${credentialKey})`,
258
+ });
259
+
260
+ return getSecret(existing[0].id, ctx);
261
+ }
262
+
152
263
  const secretId = id();
153
264
  const actor = ctx.ownerEmail;
154
265
 
@@ -157,7 +268,7 @@ export async function createSecret(
157
268
  ownerEmail: actor,
158
269
  orgId: ctx.orgId,
159
270
  name: input.name,
160
- credentialKey: input.credentialKey,
271
+ credentialKey,
161
272
  value: input.value,
162
273
  provider: input.provider || null,
163
274
  description: input.description || null,
@@ -169,15 +280,15 @@ export async function createSecret(
169
280
  await recordVaultAudit({
170
281
  action: "secret.created",
171
282
  secretId,
172
- summary: `Created secret "${input.name}" (${input.credentialKey})`,
173
- metadata: { credentialKey: input.credentialKey, provider: input.provider },
283
+ summary: `Created secret "${input.name}" (${credentialKey})`,
284
+ metadata: { credentialKey, provider: input.provider },
174
285
  });
175
286
 
176
287
  await recordAudit({
177
288
  action: "vault.secret.created",
178
289
  targetType: "vault-secret",
179
290
  targetId: secretId,
180
- summary: `Created vault secret "${input.name}" (${input.credentialKey})`,
291
+ summary: `Created vault secret "${input.name}" (${credentialKey})`,
181
292
  });
182
293
 
183
294
  return getSecret(secretId, ctx);
@@ -259,7 +370,7 @@ export async function listGrants(filter?: {
259
370
  appId?: string;
260
371
  }) {
261
372
  const db = getDb();
262
- const conditions = [orgFilter(schema.vaultGrants)];
373
+ const conditions = [scopedFilter(schema.vaultGrants)];
263
374
  if (filter?.secretId) {
264
375
  conditions.push(eq(schema.vaultGrants.secretId, filter.secretId) as any);
265
376
  }
@@ -340,7 +451,16 @@ export async function grantSecretsToApp(
340
451
  appId: string,
341
452
  ctx: VaultCtx = requireVaultCtx(),
342
453
  ) {
454
+ const access = await getVaultAccessSettings();
343
455
  const uniqueSecretIds = Array.from(new Set(secretIds));
456
+ if (access.mode === "all-apps") {
457
+ return {
458
+ appId,
459
+ accessMode: access.mode,
460
+ created: [],
461
+ skipped: uniqueSecretIds,
462
+ };
463
+ }
344
464
  const existingActive = (await listGrants({ appId })).filter(
345
465
  (grant) => grant.status === "active",
346
466
  );
@@ -362,7 +482,7 @@ export async function grantSecretsToApp(
362
482
  }
363
483
  }
364
484
 
365
- return { appId, created, skipped };
485
+ return { appId, accessMode: access.mode, created, skipped };
366
486
  }
367
487
 
368
488
  export async function revokeGrant(
@@ -403,6 +523,40 @@ export async function revokeGrant(
403
523
  return getGrant(grantId, ctx);
404
524
  }
405
525
 
526
+ // ─── Shared Credential Store Sync ─────────────────────────────────
527
+
528
+ type VaultSecretRow = typeof schema.vaultSecrets.$inferSelect;
529
+
530
+ export function credentialStoreScopeForVaultCtx(ctx: VaultCtx): {
531
+ scope: Extract<SecretScope, "org" | "workspace">;
532
+ scopeId: string;
533
+ } {
534
+ if (ctx.orgId) return { scope: "org", scopeId: ctx.orgId };
535
+ return { scope: "workspace", scopeId: `solo:${ctx.ownerEmail}` };
536
+ }
537
+
538
+ export async function syncSecretsToCredentialStore(
539
+ secrets: VaultSecretRow[],
540
+ ctx: VaultCtx,
541
+ ) {
542
+ const target = credentialStoreScopeForVaultCtx(ctx);
543
+ const syncedKeys: string[] = [];
544
+
545
+ for (const secret of secrets) {
546
+ if (!secret.credentialKey || !secret.value) continue;
547
+ await writeAppSecret({
548
+ key: secret.credentialKey,
549
+ value: secret.value,
550
+ scope: target.scope,
551
+ scopeId: target.scopeId,
552
+ description: `Synced from Dispatch vault: ${secret.name}`,
553
+ });
554
+ syncedKeys.push(secret.credentialKey);
555
+ }
556
+
557
+ return { ...target, keys: syncedKeys };
558
+ }
559
+
406
560
  // ─── Sync ──────────────────────────────────────────────────────
407
561
 
408
562
  export async function syncGrantsToApp(
@@ -410,46 +564,78 @@ export async function syncGrantsToApp(
410
564
  ctx: VaultCtx = requireVaultCtx(),
411
565
  ) {
412
566
  const db = getDb();
567
+ const access = await getVaultAccessSettings();
413
568
  const agents = await discoverAgents("dispatch");
414
569
  const agent = agents.find((a) => a.id === appId);
415
570
  if (!agent) throw new Error(`App "${appId}" not found in agent registry`);
416
571
 
417
- const grants = await listGrants({ appId });
418
- const activeGrants = grants.filter((g) => g.status === "active");
419
- if (activeGrants.length === 0) {
420
- return { appId, synced: 0, keys: [] };
421
- }
572
+ const secretsToSync: VaultSecretRow[] = [];
573
+ const activeGrants =
574
+ access.mode === "manual"
575
+ ? (await listGrants({ appId })).filter((g) => g.status === "active")
576
+ : [];
422
577
 
423
- // Resolve secret values for each grant
424
- const vars: Array<{ key: string; value: string }> = [];
425
- for (const grant of activeGrants) {
426
- const secret = await getSecret(grant.secretId, ctx);
427
- if (secret) {
428
- vars.push({ key: secret.credentialKey, value: secret.value });
578
+ if (access.mode === "all-apps") {
579
+ const secrets = await listSecrets();
580
+ for (const secret of secrets) {
581
+ secretsToSync.push(secret);
582
+ }
583
+ } else {
584
+ for (const grant of activeGrants) {
585
+ const secret = await getSecret(grant.secretId, ctx);
586
+ if (secret) {
587
+ secretsToSync.push(secret);
588
+ }
429
589
  }
430
590
  }
431
591
 
432
- if (vars.length === 0) {
433
- return { appId, synced: 0, keys: [] };
592
+ if (secretsToSync.length === 0) {
593
+ return { appId, accessMode: access.mode, synced: 0, keys: [] };
434
594
  }
435
595
 
436
- // Push to the app's env-vars endpoint
437
- const res = await fetch(`${agent.url}/_agent-native/env-vars`, {
438
- method: "POST",
439
- headers: { "Content-Type": "application/json" },
440
- body: JSON.stringify({ vars }),
441
- });
442
-
443
- if (!res.ok) {
444
- const err = await res.text().catch(() => "Unknown error");
445
- throw new Error(`Failed to sync to ${appId}: ${err}`);
596
+ const credentialStoreSync = await syncSecretsToCredentialStore(
597
+ secretsToSync,
598
+ ctx,
599
+ );
600
+ const vars = secretsToSync.map((secret) => ({
601
+ key: secret.credentialKey,
602
+ value: secret.value,
603
+ }));
604
+ let envVarSync:
605
+ | { status: "synced"; keys: string[] }
606
+ | { status: "skipped"; reason: string }
607
+ | { status: "failed"; reason: string };
608
+
609
+ // Best-effort push to the app's env-vars endpoint for local/dev apps that
610
+ // still read process.env directly. Production/shared-DB apps intentionally
611
+ // reject env writes; the encrypted app_secrets sync above is the canonical
612
+ // path for request-scoped credentials.
613
+ try {
614
+ const res = await fetch(`${agent.url}/_agent-native/env-vars`, {
615
+ method: "POST",
616
+ headers: { "Content-Type": "application/json" },
617
+ body: JSON.stringify({ vars }),
618
+ });
619
+
620
+ if (res.ok) {
621
+ const result = await res.json();
622
+ envVarSync = { status: "synced", keys: result.saved || [] };
623
+ } else {
624
+ const err = await res.text().catch(() => "Unknown error");
625
+ envVarSync = { status: "skipped", reason: err };
626
+ }
627
+ } catch (err) {
628
+ envVarSync = {
629
+ status: "failed",
630
+ reason: err instanceof Error ? err.message : String(err),
631
+ };
446
632
  }
447
633
 
448
- const result = await res.json();
449
- const syncedKeys: string[] = result.saved || [];
634
+ const syncedKeys = credentialStoreSync.keys;
450
635
  const timestamp = now();
451
636
 
452
- // Update syncedAt on grants that were successfully pushed
637
+ // Update syncedAt on grants that were successfully pushed to the shared
638
+ // credential store. All-apps mode has no explicit grant rows to update.
453
639
  for (const grant of activeGrants) {
454
640
  const secret = await getSecret(grant.secretId, ctx);
455
641
  if (secret && syncedKeys.includes(secret.credentialKey)) {
@@ -464,17 +650,36 @@ export async function syncGrantsToApp(
464
650
  action: "secret.synced",
465
651
  appId,
466
652
  summary: `Synced ${syncedKeys.length} secret(s) to ${appId}: ${syncedKeys.join(", ")}`,
467
- metadata: { syncedKeys },
653
+ metadata: {
654
+ syncedKeys,
655
+ accessMode: access.mode,
656
+ credentialStore: {
657
+ scope: credentialStoreSync.scope,
658
+ scopeId: credentialStoreSync.scopeId,
659
+ },
660
+ envVars: envVarSync,
661
+ },
468
662
  });
469
663
 
470
- return { appId, synced: syncedKeys.length, keys: syncedKeys };
664
+ return {
665
+ appId,
666
+ accessMode: access.mode,
667
+ synced: syncedKeys.length,
668
+ keys: syncedKeys,
669
+ credentialStore: {
670
+ scope: credentialStoreSync.scope,
671
+ scopeId: credentialStoreSync.scopeId,
672
+ synced: credentialStoreSync.keys.length,
673
+ },
674
+ envVars: envVarSync,
675
+ };
471
676
  }
472
677
 
473
678
  // ─── Requests ──────────────────────────────────────────────────────
474
679
 
475
680
  export async function listRequests(filter?: { status?: string }) {
476
681
  const db = getDb();
477
- const conditions = [orgFilter(schema.vaultRequests)];
682
+ const conditions = [scopedFilter(schema.vaultRequests)];
478
683
  if (filter?.status) {
479
684
  conditions.push(eq(schema.vaultRequests.status, filter.status) as any);
480
685
  }
@@ -671,10 +876,12 @@ export interface AppIntegrations {
671
876
  url: string;
672
877
  color: string;
673
878
  integrations: IntegrationEntry[];
879
+ vaultAccessMode: VaultAccessMode;
674
880
  reachable: boolean;
675
881
  }
676
882
 
677
883
  export async function listIntegrationsCatalog(): Promise<AppIntegrations[]> {
884
+ const access = await getVaultAccessSettings();
678
885
  const agents = await discoverAgents("dispatch");
679
886
  const grants = await listGrants();
680
887
  const secrets = await listSecrets();
@@ -695,6 +902,7 @@ export async function listIntegrationsCatalog(): Promise<AppIntegrations[]> {
695
902
  url: agent.url,
696
903
  color: agent.color,
697
904
  integrations: [],
905
+ vaultAccessMode: access.mode,
698
906
  reachable: false,
699
907
  });
700
908
  continue;
@@ -720,7 +928,9 @@ export async function listIntegrationsCatalog(): Promise<AppIntegrations[]> {
720
928
  required: env.required,
721
929
  configured: env.configured,
722
930
  vaultGranted:
723
- !!matchingSecret && grantedSecretIds.has(matchingSecret.id),
931
+ !!matchingSecret &&
932
+ (access.mode === "all-apps" ||
933
+ grantedSecretIds.has(matchingSecret.id)),
724
934
  vaultSecretId: matchingSecret?.id,
725
935
  };
726
936
  });
@@ -731,6 +941,7 @@ export async function listIntegrationsCatalog(): Promise<AppIntegrations[]> {
731
941
  url: agent.url,
732
942
  color: agent.color,
733
943
  integrations,
944
+ vaultAccessMode: access.mode,
734
945
  reachable: true,
735
946
  });
736
947
  } catch {
@@ -740,6 +951,7 @@ export async function listIntegrationsCatalog(): Promise<AppIntegrations[]> {
740
951
  url: agent.url,
741
952
  color: agent.color,
742
953
  integrations: [],
954
+ vaultAccessMode: access.mode,
743
955
  reachable: false,
744
956
  });
745
957
  }
@@ -751,15 +963,20 @@ export async function listIntegrationsCatalog(): Promise<AppIntegrations[]> {
751
963
  // ─── Vault Overview (for dashboard) ──────────────────────────────
752
964
 
753
965
  export async function listVaultOverview() {
754
- const [secrets, grants, requests] = await Promise.all([
966
+ const [secrets, grants, requests, access] = await Promise.all([
755
967
  listSecrets(),
756
968
  listGrants(),
757
969
  listRequests(),
970
+ getVaultAccessSettings(),
758
971
  ]);
972
+ const manualGrantCount = grants.filter((g) => g.status === "active").length;
759
973
 
760
974
  return {
975
+ accessMode: access.mode,
761
976
  secretCount: secrets.length,
762
- activeGrantCount: grants.filter((g) => g.status === "active").length,
977
+ activeGrantCount:
978
+ access.mode === "all-apps" ? secrets.length : manualGrantCount,
979
+ manualGrantCount,
763
980
  pendingRequestCount: requests.filter((r) => r.status === "pending").length,
764
981
  };
765
982
  }