@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
@@ -4,7 +4,7 @@ import { listWorkspaceResources } from "../server/lib/workspace-resources-store.
4
4
 
5
5
  export default defineAction({
6
6
  description:
7
- "List all workspace-wide resources (skills, instructions, agents, and knowledge packs) that can be shared across apps.",
7
+ "List all workspace-wide resources (skills, instructions, agent profiles, and reference resources) that apps inherit at runtime.",
8
8
  schema: z.object({
9
9
  kind: z
10
10
  .enum(["skill", "instruction", "agent", "knowledge"])
@@ -5,6 +5,7 @@
5
5
  *
6
6
  * Usage:
7
7
  * pnpm action navigate --view=overview
8
+ * pnpm action navigate --view=dreams
8
9
  * pnpm action navigate --view=<custom-dispatch-extension-id>
9
10
  * pnpm action navigate --path=/some/route
10
11
  *
@@ -25,7 +26,7 @@ export default defineAction({
25
26
  .string()
26
27
  .optional()
27
28
  .describe(
28
- "Named dispatch view to navigate to. Built-in views include overview, apps, metrics, new-app, vault, integrations, messaging, workspace, agents, destinations, identities, approvals, audit, thread-debug, and team. Generated Dispatch extension tabs can also use their nav item id.",
29
+ "Named dispatch view to navigate to. Built-in views include overview, apps, metrics, new-app, vault, integrations, messaging, workspace, agents, destinations, identities, approvals, audit, thread-debug, dreams, and team. Generated Dispatch extension tabs can also use their nav item id.",
29
30
  ),
30
31
  path: z.string().optional().describe("URL path to navigate to"),
31
32
  }),
@@ -0,0 +1,14 @@
1
+ import { defineAction } from "@agent-native/core";
2
+ import { z } from "zod";
3
+ import { previewDreamProposal } from "../server/lib/dreams-store.js";
4
+
5
+ export default defineAction({
6
+ description:
7
+ "Preview one Dispatch dream proposal before applying it, including target, current content, proposed content, and approval behavior.",
8
+ schema: z.object({
9
+ id: z.string().min(1).describe("Dream proposal id."),
10
+ }),
11
+ http: { method: "GET" },
12
+ readOnly: true,
13
+ run: async ({ id }) => previewDreamProposal(id),
14
+ });
@@ -0,0 +1,25 @@
1
+ import { defineAction } from "@agent-native/core";
2
+ import { z } from "zod";
3
+ import { previewWorkspaceResourceChange } from "../server/lib/workspace-resources-store.js";
4
+
5
+ export default defineAction({
6
+ description:
7
+ "Preview the impact of creating, updating, or deleting a workspace resource, including All-app reach, overrides, and whether Dispatch approval will be requested.",
8
+ schema: z.object({
9
+ operation: z
10
+ .enum(["create", "update", "delete"])
11
+ .optional()
12
+ .describe("Change operation to preview."),
13
+ resourceId: z.string().optional().describe("Existing resource id."),
14
+ path: z
15
+ .string()
16
+ .optional()
17
+ .describe("Resource path, such as context/brand.md."),
18
+ scope: z
19
+ .enum(["all", "selected"])
20
+ .optional()
21
+ .describe("Resulting resource scope after the change."),
22
+ }),
23
+ http: { method: "GET" },
24
+ run: async (args) => previewWorkspaceResourceChange(args),
25
+ });
@@ -0,0 +1,12 @@
1
+ import { defineAction } from "@agent-native/core";
2
+ import { z } from "zod";
3
+ import { rejectDreamProposal } from "../server/lib/dreams-store.js";
4
+
5
+ export default defineAction({
6
+ description: "Reject one pending Dispatch dream proposal.",
7
+ schema: z.object({
8
+ id: z.string().min(1).describe("Dream proposal id."),
9
+ reason: z.string().optional().describe("Optional rejection reason."),
10
+ }),
11
+ run: async ({ id, reason }) => rejectDreamProposal(id, reason),
12
+ });
@@ -0,0 +1,17 @@
1
+ import { defineAction } from "@agent-native/core";
2
+ import { z } from "zod";
3
+ import { restoreStarterWorkspaceResources } from "../server/lib/workspace-resources-store.js";
4
+
5
+ export default defineAction({
6
+ description:
7
+ "Restore missing starter global workspace resources such as company, brand, messaging, guardrails, and company voice. Existing resources are left unchanged.",
8
+ schema: z.object({
9
+ paths: z
10
+ .array(z.string())
11
+ .optional()
12
+ .describe(
13
+ "Optional starter resource paths to restore. Omit to restore every missing starter resource.",
14
+ ),
15
+ }),
16
+ run: async (args) => restoreStarterWorkspaceResources(args),
17
+ });
@@ -0,0 +1,59 @@
1
+ import { defineAction } from "@agent-native/core";
2
+ import { getRequestUserEmail } from "@agent-native/core/server";
3
+ import { z } from "zod";
4
+ import {
5
+ enqueueRemoteCodeCommand,
6
+ type RemoteCodeCommandEnvelope,
7
+ } from "../server/lib/dispatch-remote-commands.js";
8
+
9
+ const commandSchema = z.discriminatedUnion("type", [
10
+ z.object({ type: z.literal("create"), prompt: z.string().min(1) }),
11
+ z.object({ type: z.literal("list") }),
12
+ z.object({ type: z.literal("status"), runRef: z.string().optional() }),
13
+ z.object({
14
+ type: z.literal("continue"),
15
+ runRef: z.string().min(1),
16
+ text: z.string().min(1),
17
+ }),
18
+ z.object({ type: z.literal("approve"), approvalId: z.string().min(1) }),
19
+ z.object({ type: z.literal("deny"), approvalId: z.string().min(1) }),
20
+ z.object({ type: z.literal("stop"), runRef: z.string().min(1) }),
21
+ ]);
22
+
23
+ export default defineAction({
24
+ description:
25
+ "Route a command to the remote Agent-Native Code host through the integration relay.",
26
+ schema: z.object({
27
+ command: commandSchema,
28
+ source: z
29
+ .object({
30
+ platform: z.string().default("dispatch"),
31
+ externalThreadId: z.string().default("dispatch"),
32
+ senderId: z.string().optional(),
33
+ senderName: z.string().optional(),
34
+ messageId: z.string().optional(),
35
+ timestamp: z.number().optional(),
36
+ })
37
+ .optional(),
38
+ }),
39
+ run: async ({ command, source }) => {
40
+ const ownerEmail = getRequestUserEmail();
41
+ if (!ownerEmail) throw new Error("no authenticated user");
42
+
43
+ const envelope: RemoteCodeCommandEnvelope = {
44
+ kind: "code-agent",
45
+ ownerEmail,
46
+ command,
47
+ source: {
48
+ platform: source?.platform || "dispatch",
49
+ externalThreadId: source?.externalThreadId || "dispatch",
50
+ senderId: source?.senderId,
51
+ senderName: source?.senderName,
52
+ messageId: source?.messageId,
53
+ timestamp: source?.timestamp ?? Date.now(),
54
+ },
55
+ };
56
+
57
+ return enqueueRemoteCodeCommand(envelope);
58
+ },
59
+ });
@@ -0,0 +1,81 @@
1
+ import { beforeEach, describe, expect, it, vi } from "vitest";
2
+
3
+ const mocks = vi.hoisted(() => ({
4
+ setDreamSettings: vi.fn(),
5
+ }));
6
+
7
+ vi.mock("../server/lib/dreams-store.js", () => ({
8
+ setDreamSettings: mocks.setDreamSettings,
9
+ }));
10
+
11
+ import action from "./set-dream-settings.js";
12
+
13
+ describe("set-dream-settings action", () => {
14
+ beforeEach(() => {
15
+ vi.clearAllMocks();
16
+ mocks.setDreamSettings.mockImplementation(async (input) => ({
17
+ enabled: false,
18
+ schedule: "0 9 * * 1",
19
+ sourceId: "all",
20
+ sourceIds: [],
21
+ allSources: true,
22
+ query: null,
23
+ limit: 8,
24
+ sourceTimeoutMs: 30000,
25
+ sourceConcurrency: 2,
26
+ sourceStartStaggerMs: 250,
27
+ threadConcurrency: 3,
28
+ threadTimeoutMs: 8000,
29
+ minCandidateCount: 1,
30
+ ...input,
31
+ }));
32
+ });
33
+
34
+ it("coerces numeric fields and preserves explicit clears", async () => {
35
+ await action.run({
36
+ enabled: true,
37
+ schedule: "0 8 * * 2",
38
+ sourceId: "current",
39
+ sourceIds: [],
40
+ allSources: false,
41
+ query: "",
42
+ limit: "50",
43
+ sourceTimeoutMs: "60000",
44
+ sourceConcurrency: "8",
45
+ sourceStartStaggerMs: "5000",
46
+ threadConcurrency: "10",
47
+ threadTimeoutMs: "30000",
48
+ minCandidateCount: "0",
49
+ } as any);
50
+
51
+ expect(mocks.setDreamSettings).toHaveBeenCalledWith({
52
+ enabled: true,
53
+ schedule: "0 8 * * 2",
54
+ sourceId: "current",
55
+ sourceIds: [],
56
+ allSources: false,
57
+ query: "",
58
+ limit: 50,
59
+ sourceTimeoutMs: 60000,
60
+ sourceConcurrency: 8,
61
+ sourceStartStaggerMs: 5000,
62
+ threadConcurrency: 10,
63
+ threadTimeoutMs: 30000,
64
+ minCandidateCount: 0,
65
+ });
66
+ });
67
+
68
+ it("rejects out-of-range numeric settings before writing", async () => {
69
+ await expect(action.run({ limit: "0" } as any)).rejects.toThrow(
70
+ /Invalid action parameters/,
71
+ );
72
+ await expect(
73
+ action.run({ sourceTimeoutMs: "60001" } as any),
74
+ ).rejects.toThrow(/Invalid action parameters/);
75
+ await expect(
76
+ action.run({ threadTimeoutMs: "30001" } as any),
77
+ ).rejects.toThrow(/Invalid action parameters/);
78
+
79
+ expect(mocks.setDreamSettings).not.toHaveBeenCalled();
80
+ });
81
+ });
@@ -0,0 +1,44 @@
1
+ import { defineAction } from "@agent-native/core";
2
+ import { z } from "zod";
3
+ import { setDreamSettings } from "../server/lib/dreams-store.js";
4
+
5
+ export default defineAction({
6
+ description:
7
+ "Update recurring Dispatch dream settings without immediately running or applying a dream pass.",
8
+ schema: z.object({
9
+ enabled: z
10
+ .boolean()
11
+ .optional()
12
+ .describe("Whether recurring dreams are on."),
13
+ schedule: z
14
+ .string()
15
+ .optional()
16
+ .describe('Five-field cron schedule, for example "0 9 * * 1".'),
17
+ sourceId: z
18
+ .string()
19
+ .optional()
20
+ .describe(
21
+ "Thread debug source id. Use 'all' for every connected source.",
22
+ ),
23
+ sourceIds: z
24
+ .array(z.string().min(1))
25
+ .optional()
26
+ .describe("Optional explicit source ids to scan together."),
27
+ allSources: z.coerce
28
+ .boolean()
29
+ .optional()
30
+ .describe("Scan every connected thread-debug source."),
31
+ query: z
32
+ .string()
33
+ .optional()
34
+ .describe("Optional search term for recurring dream passes."),
35
+ limit: z.coerce.number().int().min(1).max(50).optional(),
36
+ sourceTimeoutMs: z.coerce.number().int().min(1000).max(60000).optional(),
37
+ sourceConcurrency: z.coerce.number().int().min(1).max(8).optional(),
38
+ sourceStartStaggerMs: z.coerce.number().int().min(0).max(5000).optional(),
39
+ threadConcurrency: z.coerce.number().int().min(1).max(10).optional(),
40
+ threadTimeoutMs: z.coerce.number().int().min(1000).max(30000).optional(),
41
+ minCandidateCount: z.coerce.number().int().min(0).max(50).optional(),
42
+ }),
43
+ run: async (input) => setDreamSettings(input),
44
+ });
@@ -0,0 +1,16 @@
1
+ import { defineAction } from "@agent-native/core";
2
+ import { z } from "zod";
3
+ import { setVaultAccessSettings } from "../server/lib/vault-store.js";
4
+
5
+ export default defineAction({
6
+ description:
7
+ "Set the Dispatch vault access mode. Use all-apps for the default workspace-wide mode or manual to require explicit per-app grants.",
8
+ schema: z.object({
9
+ mode: z
10
+ .enum(["all-apps", "manual"])
11
+ .describe(
12
+ "all-apps shares every vault key with every app; manual requires grants",
13
+ ),
14
+ }),
15
+ run: async (args) => setVaultAccessSettings(args),
16
+ });
@@ -23,6 +23,14 @@ export default defineAction({
23
23
  .optional()
24
24
  .nullable()
25
25
  .describe("Template to start from"),
26
+ description: z
27
+ .string()
28
+ .max(500)
29
+ .optional()
30
+ .nullable()
31
+ .describe(
32
+ "Concise AI-generated description of the app based on the user's prompt. Dispatch saves this while the app is being created.",
33
+ ),
26
34
  secretIds: z
27
35
  .array(z.string())
28
36
  .max(100)
@@ -4,7 +4,7 @@ import { syncGrantsToApp } from "../server/lib/vault-store.js";
4
4
 
5
5
  export default defineAction({
6
6
  description:
7
- "Push all granted secrets to an app by calling its env-vars endpoint. Returns the list of synced credential keys.",
7
+ "Push vault secrets to an app by calling its env-vars endpoint. In all-apps mode this syncs every vault key; in manual mode it syncs active grants.",
8
8
  schema: z.object({
9
9
  appId: z
10
10
  .string()
@@ -0,0 +1,32 @@
1
+ import { defineAction } from "@agent-native/core";
2
+ import { getWorkspaceAppIdValidationError } from "@agent-native/core/shared";
3
+ import { z } from "zod";
4
+ import { updateWorkspaceAppMetadata } from "../server/lib/app-creation-store.js";
5
+
6
+ export default defineAction({
7
+ description:
8
+ "Update the human-editable display name and description Dispatch uses for a workspace app. These details are also used as connected-agent/A2A context.",
9
+ schema: z.object({
10
+ appId: z
11
+ .string()
12
+ .max(64)
13
+ .refine((appId) => !getWorkspaceAppIdValidationError(appId), {
14
+ message:
15
+ "Use a non-reserved app id with lowercase letters, numbers, and hyphens.",
16
+ })
17
+ .describe("Workspace app id, matching the apps/<id> folder"),
18
+ name: z
19
+ .string()
20
+ .max(120)
21
+ .optional()
22
+ .nullable()
23
+ .describe("Human-readable app name"),
24
+ description: z
25
+ .string()
26
+ .max(500)
27
+ .optional()
28
+ .nullable()
29
+ .describe("Human-readable app description"),
30
+ }),
31
+ run: async (args) => updateWorkspaceAppMetadata(args),
32
+ });
@@ -4,7 +4,7 @@ import { updateWorkspaceResource } from "../server/lib/workspace-resources-store
4
4
 
5
5
  export default defineAction({
6
6
  description:
7
- "Update a workspace resource's name, description, content, or scope.",
7
+ "Update a workspace resource's name, description, content, or scope. When Dispatch approval policy is enabled, changes that affect All-app resources queue an approval request before taking effect.",
8
8
  schema: z.object({
9
9
  id: z.string().describe("Resource ID"),
10
10
  name: z.string().optional().describe("New name"),
@@ -16,16 +16,40 @@ import {
16
16
  listSecrets,
17
17
  listGrants,
18
18
  listRequests,
19
+ getVaultAccessSettings,
19
20
  } from "../server/lib/vault-store.js";
20
21
  import { listWorkspaceApps } from "../server/lib/app-creation-store.js";
21
22
  import { listDispatchUsageMetrics } from "../server/lib/usage-metrics-store.js";
22
- import { listWorkspaceResourceOptions } from "../server/lib/workspace-resources-store.js";
23
+ import {
24
+ listWorkspaceResourceOptions,
25
+ listWorkspaceResourcesForApp,
26
+ } from "../server/lib/workspace-resources-store.js";
23
27
  import {
24
28
  getAgentThreadDebug,
25
29
  listThreadDebugSources,
26
30
  searchAgentThreads,
27
31
  } from "../server/lib/thread-debug-store.js";
28
32
 
33
+ async function runLocalDispatchAction(
34
+ name: string,
35
+ args: Record<string, unknown>,
36
+ ) {
37
+ const modulePath = `./${name}.js`;
38
+ const module = (await import(/* @vite-ignore */ modulePath)) as {
39
+ default?: {
40
+ run: (args: Record<string, unknown>) => unknown | Promise<unknown>;
41
+ };
42
+ };
43
+ if (!module.default) throw new Error(`Dispatch action not found: ${name}`);
44
+ return module.default.run(stripUndefined(args));
45
+ }
46
+
47
+ function stripUndefined(args: Record<string, unknown>) {
48
+ return Object.fromEntries(
49
+ Object.entries(args).filter(([, value]) => value !== undefined),
50
+ );
51
+ }
52
+
29
53
  export default defineAction({
30
54
  description:
31
55
  "See what the user is currently looking at in the dispatch UI, including navigation state and a compact operational summary.",
@@ -56,9 +80,32 @@ export default defineAction({
56
80
  navigation?.view === "apps" ||
57
81
  navigation?.view === "new-app"
58
82
  ) {
59
- screen.workspaceApps = await listWorkspaceApps({
83
+ const workspaceApps = await listWorkspaceApps({
60
84
  includeAgentCards: true,
61
85
  });
86
+ screen.workspaceApps = workspaceApps;
87
+ if (navigation?.view === "apps") {
88
+ screen.workspaceAppResources = await Promise.all(
89
+ workspaceApps
90
+ .filter((app) => !app.isDispatch)
91
+ .slice(0, 12)
92
+ .map(async (app) => {
93
+ const result = await listWorkspaceResourcesForApp(app.id);
94
+ return {
95
+ appId: app.id,
96
+ appName: app.name,
97
+ counts: result.counts,
98
+ resources: result.resources.map((resource) => ({
99
+ name: resource.name,
100
+ path: resource.path,
101
+ kind: resource.kind,
102
+ source: resource.source,
103
+ autoLoaded: resource.autoLoaded,
104
+ })),
105
+ };
106
+ }),
107
+ );
108
+ }
62
109
  }
63
110
  if (navigation?.view === "metrics") {
64
111
  try {
@@ -78,11 +125,13 @@ export default defineAction({
78
125
  }
79
126
  }
80
127
  if (navigation?.view === "vault" || navigation?.view === "new-app") {
81
- const [secrets, grants, requests] = await Promise.all([
128
+ const [secrets, grants, requests, access] = await Promise.all([
82
129
  listSecrets(),
83
130
  listGrants(),
84
131
  listRequests({ status: "pending" }),
132
+ getVaultAccessSettings(),
85
133
  ]);
134
+ screen.vaultAccessMode = access.mode;
86
135
  screen.vaultSecrets = secrets.map((s) => ({
87
136
  id: s.id,
88
137
  name: s.name,
@@ -96,6 +145,16 @@ export default defineAction({
96
145
  }
97
146
  if (navigation?.view === "workspace" || navigation?.view === "new-app") {
98
147
  screen.workspaceResources = await listWorkspaceResourceOptions();
148
+ screen.workspaceResourceEffectiveContext = {
149
+ action: "get-workspace-resource-effective-context",
150
+ description:
151
+ "Preview workspace -> organization/app -> personal precedence for a resource path and optional app/user. All-app resources are inherited at runtime; selected resources are app-specific exceptions.",
152
+ };
153
+ screen.workspaceResourceImpactPreview = {
154
+ action: "preview-workspace-resource-change",
155
+ description:
156
+ "Preview All-app reach, overrides, and approval behavior before creating, updating, or deleting a workspace resource.",
157
+ };
99
158
  }
100
159
  if (navigation?.view === "thread-debug") {
101
160
  try {
@@ -133,6 +192,38 @@ export default defineAction({
133
192
  error instanceof Error ? error.message : String(error);
134
193
  }
135
194
  }
195
+ if (navigation?.view === "dreams") {
196
+ try {
197
+ const nav = navigation as Record<string, any>;
198
+ const [sources, candidates, dreams, settings] = await Promise.all([
199
+ listThreadDebugSources(),
200
+ runLocalDispatchAction("list-dream-candidates", {
201
+ sourceId: nav.sourceId,
202
+ ownerEmail: nav.ownerEmail,
203
+ limit: 10,
204
+ }),
205
+ runLocalDispatchAction("list-dreams", {
206
+ status: nav.status,
207
+ limit: 10,
208
+ }),
209
+ runLocalDispatchAction("get-dream-settings", {}),
210
+ ]);
211
+ screen.dreamSources = sources;
212
+ screen.dreamCandidates = candidates;
213
+ screen.latestDreams = dreams;
214
+ screen.dreamSettings = settings;
215
+
216
+ const dreamId = nav.dreamId ?? nav.id;
217
+ if (dreamId) {
218
+ screen.dreamDetail = await runLocalDispatchAction("get-dream", {
219
+ id: dreamId,
220
+ });
221
+ }
222
+ } catch (error) {
223
+ screen.dreamsError =
224
+ error instanceof Error ? error.message : String(error);
225
+ }
226
+ }
136
227
 
137
228
  if (Object.keys(screen).length === 0) {
138
229
  return "No application state found. Is the app running?";
@@ -89,6 +89,12 @@ function AppKeysPanel({ appId, appName }: { appId: string; appName: string }) {
89
89
  isLoading: grantsLoading,
90
90
  refetch: refetchGrants,
91
91
  } = useActionQuery("list-vault-grants", { appId });
92
+ const { data: accessSettings, isLoading: accessLoading } = useActionQuery(
93
+ "get-vault-access-settings",
94
+ {},
95
+ );
96
+ const accessMode =
97
+ (accessSettings as any)?.mode === "manual" ? "manual" : "all-apps";
92
98
 
93
99
  const grantBySecretId = useMemo(() => {
94
100
  const map = new Map<string, VaultGrant>();
@@ -135,11 +141,13 @@ function AppKeysPanel({ appId, appName }: { appId: string; appName: string }) {
135
141
  onError: (err) => toast.error(`Sync failed: ${String(err)}`),
136
142
  });
137
143
 
138
- const isLoading = secretsLoading || grantsLoading;
144
+ const isLoading = secretsLoading || grantsLoading || accessLoading;
139
145
  const grantedCount = grantBySecretId.size;
140
146
  const typedSecrets = secrets as VaultSecret[];
147
+ const allApps = accessMode !== "manual";
141
148
 
142
149
  const toggleSecret = (secret: VaultSecret) => {
150
+ if (allApps) return;
143
151
  if (pendingSecretIds.has(secret.id)) return;
144
152
  const existing = grantBySecretId.get(secret.id);
145
153
  markPending(secret.id, true);
@@ -159,14 +167,20 @@ function AppKeysPanel({ appId, appName }: { appId: string; appName: string }) {
159
167
  Keys for {appName}
160
168
  </p>
161
169
  <p className="text-[11px] text-muted-foreground">
162
- {grantedCount} of {typedSecrets.length} granted
170
+ {allApps
171
+ ? `${typedSecrets.length} available`
172
+ : `${grantedCount} of ${typedSecrets.length} granted`}
163
173
  </p>
164
174
  </div>
165
175
  <Button
166
176
  type="button"
167
177
  variant="outline"
168
178
  size="sm"
169
- disabled={syncMutation.isPending || grantedCount === 0}
179
+ disabled={
180
+ syncMutation.isPending ||
181
+ typedSecrets.length === 0 ||
182
+ (!allApps && grantedCount === 0)
183
+ }
170
184
  onClick={() => syncMutation.mutate({ appId })}
171
185
  className="h-7 px-2"
172
186
  >
@@ -201,17 +215,17 @@ function AppKeysPanel({ appId, appName }: { appId: string; appName: string }) {
201
215
  </p>
202
216
  ) : (
203
217
  typedSecrets.map((secret) => {
204
- const granted = grantBySecretId.has(secret.id);
218
+ const granted = allApps || grantBySecretId.has(secret.id);
205
219
  const pending = pendingSecretIds.has(secret.id);
206
220
  return (
207
221
  <button
208
222
  key={secret.id}
209
223
  type="button"
210
224
  aria-pressed={granted}
211
- disabled={pending}
225
+ disabled={pending || allApps}
212
226
  onClick={() => toggleSecret(secret)}
213
227
  className={`flex w-full items-start gap-3 rounded-md px-2.5 py-2 text-left text-sm disabled:cursor-not-allowed disabled:opacity-60 ${
214
- pending ? "" : "cursor-pointer"
228
+ pending || allApps ? "" : "cursor-pointer"
215
229
  } ${
216
230
  granted
217
231
  ? "border border-primary/45 bg-primary/5"
@@ -232,7 +246,9 @@ function AppKeysPanel({ appId, appName }: { appId: string; appName: string }) {
232
246
  {secret.credentialKey}
233
247
  </span>
234
248
  <span className="block truncate text-xs text-muted-foreground/70">
235
- {secret.provider || secret.name || "Vault secret"}
249
+ {allApps
250
+ ? "Available to this app"
251
+ : secret.provider || secret.name || "Vault secret"}
236
252
  </span>
237
253
  </span>
238
254
  </button>
@@ -0,0 +1,59 @@
1
+ // @vitest-environment happy-dom
2
+ import React, { act } from "react";
3
+ import { createRoot, type Root } from "react-dom/client";
4
+ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
5
+ import {
6
+ ApprovalValueBlock,
7
+ approvalValuePreview,
8
+ parseApprovalValue,
9
+ } from "./approval-value-block";
10
+
11
+ describe("approval value display", () => {
12
+ let container: HTMLDivElement;
13
+ let root: Root;
14
+
15
+ beforeEach(() => {
16
+ vi.stubGlobal("IS_REACT_ACT_ENVIRONMENT", true);
17
+ container = document.createElement("div");
18
+ document.body.appendChild(container);
19
+ root = createRoot(container);
20
+ });
21
+
22
+ afterEach(() => {
23
+ act(() => root.unmount());
24
+ container.remove();
25
+ vi.unstubAllGlobals();
26
+ });
27
+
28
+ it("parses serialized approval values and preserves plain strings", () => {
29
+ expect(
30
+ parseApprovalValue('{"scope":"all","path":"context/brand.md"}'),
31
+ ).toEqual({
32
+ scope: "all",
33
+ path: "context/brand.md",
34
+ });
35
+ expect(parseApprovalValue("plain text")).toBe("plain text");
36
+ expect(parseApprovalValue(null)).toBeNull();
37
+ });
38
+
39
+ it("formats before/after payloads for readable approval review", () => {
40
+ expect(approvalValuePreview(null)).toBe("None");
41
+ expect(approvalValuePreview("plain text")).toBe("plain text");
42
+ expect(approvalValuePreview({ scope: "all" })).toBe(
43
+ JSON.stringify({ scope: "all" }, null, 2),
44
+ );
45
+
46
+ act(() => {
47
+ root.render(
48
+ <ApprovalValueBlock
49
+ label="After"
50
+ value={{ path: "context/brand.md", scope: "all" }}
51
+ />,
52
+ );
53
+ });
54
+
55
+ expect(container.textContent).toContain("After");
56
+ expect(container.textContent).toContain('"path": "context/brand.md"');
57
+ expect(container.textContent).toContain('"scope": "all"');
58
+ });
59
+ });