@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
@@ -1,21 +1,41 @@
1
- import { useActionMutation } from "@agent-native/core/client";
1
+ import { useEffect, useState, type FormEvent } from "react";
2
+ import { useActionMutation, useActionQuery } from "@agent-native/core/client";
2
3
  import {
3
4
  IconArrowUpRight,
5
+ IconChevronDown,
6
+ IconChevronRight,
4
7
  IconClockHour4,
5
8
  IconDots,
9
+ IconEdit,
6
10
  IconEye,
7
11
  IconEyeOff,
12
+ IconFileText,
13
+ IconWorld,
8
14
  IconTrash,
9
15
  } from "@tabler/icons-react";
10
16
  import { toast } from "sonner";
11
17
  import { AppKeysPopover } from "@/components/app-keys-popover";
18
+ import { AppResourceEffectiveStack } from "@/components/workspace-resource-effective-stack";
12
19
  import { Badge } from "@/components/ui/badge";
20
+ import { Button } from "@/components/ui/button";
21
+ import {
22
+ Dialog,
23
+ DialogContent,
24
+ DialogDescription,
25
+ DialogFooter,
26
+ DialogHeader,
27
+ DialogTitle,
28
+ DialogTrigger,
29
+ } from "@/components/ui/dialog";
13
30
  import {
14
31
  DropdownMenu,
15
32
  DropdownMenuContent,
16
33
  DropdownMenuItem,
17
34
  DropdownMenuTrigger,
18
35
  } from "@/components/ui/dropdown-menu";
36
+ import { Input } from "@/components/ui/input";
37
+ import { Label } from "@/components/ui/label";
38
+ import { Textarea } from "@/components/ui/textarea";
19
39
  import { cn } from "@/lib/utils";
20
40
  import {
21
41
  isPendingBuilderHref,
@@ -34,6 +54,18 @@ export function WorkspaceAppCard({
34
54
  const openInNewTab = isPendingBuilderHref(app);
35
55
  const isPending = app.status === "pending";
36
56
  const isArchived = !!app.archived;
57
+ const audience = app.audience ?? "internal";
58
+ const [editOpen, setEditOpen] = useState(false);
59
+ const [draftName, setDraftName] = useState(app.name);
60
+ const [draftDescription, setDraftDescription] = useState(
61
+ app.description || "",
62
+ );
63
+
64
+ useEffect(() => {
65
+ if (editOpen) return;
66
+ setDraftName(app.name);
67
+ setDraftDescription(app.description || "");
68
+ }, [app.description, app.name, editOpen]);
37
69
 
38
70
  const archive = useActionMutation("archive-workspace-app", {
39
71
  onError: (err) =>
@@ -47,6 +79,14 @@ export function WorkspaceAppCard({
47
79
  onError: (err) =>
48
80
  toast.error(`Could not remove ${app.name}: ${stringifyError(err)}`),
49
81
  });
82
+ const updateMetadata = useActionMutation("update-workspace-app-metadata", {
83
+ onSuccess: () => {
84
+ toast.success(`Updated ${draftName.trim() || app.name}`);
85
+ setEditOpen(false);
86
+ },
87
+ onError: (err) =>
88
+ toast.error(`Could not update ${app.name}: ${stringifyError(err)}`),
89
+ });
50
90
 
51
91
  const handleArchive = () => {
52
92
  archive.mutate({ appId: app.id });
@@ -60,6 +100,19 @@ export function WorkspaceAppCard({
60
100
  removePending.mutate({ appId: app.id });
61
101
  toast.success(`Removed pending ${app.name}`);
62
102
  };
103
+ const handleMetadataSubmit = (event: FormEvent<HTMLFormElement>) => {
104
+ event.preventDefault();
105
+ const name = draftName.trim();
106
+ if (!name) {
107
+ toast.error("App name is required.");
108
+ return;
109
+ }
110
+ updateMetadata.mutate({
111
+ appId: app.id,
112
+ name,
113
+ description: draftDescription.trim(),
114
+ });
115
+ };
63
116
 
64
117
  return (
65
118
  <div
@@ -101,6 +154,12 @@ export function WorkspaceAppCard({
101
154
  Hidden
102
155
  </Badge>
103
156
  ) : null}
157
+ {audience === "public" ? (
158
+ <Badge variant="outline" className="shrink-0 gap-1">
159
+ <IconWorld size={12} />
160
+ Public
161
+ </Badge>
162
+ ) : null}
104
163
  </div>
105
164
  <p className="mt-1 truncate font-mono text-xs text-muted-foreground">
106
165
  {app.path}
@@ -117,6 +176,11 @@ export function WorkspaceAppCard({
117
176
  ) : null}
118
177
  </div>
119
178
  <div className="flex shrink-0 items-center gap-1">
179
+ {!isPending && !isArchived ? (
180
+ <div className="pointer-events-auto">
181
+ <AppResourcesDialog app={app} />
182
+ </div>
183
+ ) : null}
120
184
  {!isPending && !isArchived ? (
121
185
  <div className="pointer-events-auto">
122
186
  <AppKeysPopover appId={app.id} appName={app.name} />
@@ -135,6 +199,15 @@ export function WorkspaceAppCard({
135
199
  </button>
136
200
  </DropdownMenuTrigger>
137
201
  <DropdownMenuContent align="end" className="w-44">
202
+ <DropdownMenuItem
203
+ onSelect={(event) => {
204
+ event.preventDefault();
205
+ setEditOpen(true);
206
+ }}
207
+ >
208
+ <IconEdit size={14} className="mr-2" />
209
+ Edit details
210
+ </DropdownMenuItem>
138
211
  {isPending ? (
139
212
  <DropdownMenuItem
140
213
  onSelect={handleRemovePending}
@@ -165,10 +238,204 @@ export function WorkspaceAppCard({
165
238
  ) : null}
166
239
  </div>
167
240
  </div>
241
+ <Dialog open={editOpen} onOpenChange={setEditOpen}>
242
+ <DialogContent>
243
+ <DialogHeader>
244
+ <DialogTitle>Edit app details</DialogTitle>
245
+ </DialogHeader>
246
+ <form className="space-y-4" onSubmit={handleMetadataSubmit}>
247
+ <div className="space-y-2">
248
+ <Label htmlFor={`app-name-${app.id}`}>Name</Label>
249
+ <Input
250
+ id={`app-name-${app.id}`}
251
+ value={draftName}
252
+ maxLength={120}
253
+ onChange={(event) => setDraftName(event.target.value)}
254
+ />
255
+ </div>
256
+ <div className="space-y-2">
257
+ <Label htmlFor={`app-description-${app.id}`}>Description</Label>
258
+ <Textarea
259
+ id={`app-description-${app.id}`}
260
+ value={draftDescription}
261
+ maxLength={500}
262
+ rows={4}
263
+ onChange={(event) => setDraftDescription(event.target.value)}
264
+ />
265
+ </div>
266
+ <DialogFooter>
267
+ <Button
268
+ type="button"
269
+ variant="outline"
270
+ onClick={() => setEditOpen(false)}
271
+ >
272
+ Cancel
273
+ </Button>
274
+ <Button type="submit" disabled={updateMetadata.isPending}>
275
+ {updateMetadata.isPending ? "Saving..." : "Save"}
276
+ </Button>
277
+ </DialogFooter>
278
+ </form>
279
+ </DialogContent>
280
+ </Dialog>
168
281
  </div>
169
282
  );
170
283
  }
171
284
 
285
+ function AppResourcesDialog({ app }: { app: WorkspaceAppSummary }) {
286
+ const [open, setOpen] = useState(false);
287
+ const [inspectedResourceId, setInspectedResourceId] = useState<string | null>(
288
+ null,
289
+ );
290
+ const { data, isLoading } = useActionQuery(
291
+ "list-workspace-resources-for-app",
292
+ { appId: app.id },
293
+ { enabled: open },
294
+ );
295
+
296
+ const resources = ((data as any)?.resources ?? []) as any[];
297
+ const counts = (data as any)?.counts;
298
+
299
+ return (
300
+ <Dialog
301
+ open={open}
302
+ onOpenChange={(nextOpen) => {
303
+ setOpen(nextOpen);
304
+ if (!nextOpen) setInspectedResourceId(null);
305
+ }}
306
+ >
307
+ <DialogTrigger asChild>
308
+ <Button
309
+ type="button"
310
+ variant="ghost"
311
+ size="sm"
312
+ className="h-7 px-2 text-xs"
313
+ onClick={(e) => e.stopPropagation()}
314
+ >
315
+ <IconFileText size={14} className="mr-1" />
316
+ Context
317
+ </Button>
318
+ </DialogTrigger>
319
+ <DialogContent className="max-w-2xl">
320
+ <DialogHeader>
321
+ <DialogTitle>{app.name} workspace resources</DialogTitle>
322
+ <DialogDescription>
323
+ Workspace-level resources are inherited at runtime. App shared and
324
+ personal resources can override them locally.
325
+ </DialogDescription>
326
+ </DialogHeader>
327
+ <div className="space-y-4">
328
+ <div className="rounded-lg border bg-muted/30 px-3 py-2 text-xs leading-relaxed text-muted-foreground">
329
+ All-app resources live once at workspace scope and are read by each
330
+ app agent when it builds context. Nothing is copied into this app.
331
+ </div>
332
+
333
+ <div className="flex flex-wrap items-center gap-2">
334
+ <Badge variant="secondary">{counts?.total ?? 0} total</Badge>
335
+ <Badge variant="outline">
336
+ {counts?.workspace ?? counts?.global ?? 0} workspace
337
+ </Badge>
338
+ <Badge variant="outline">{counts?.granted ?? 0} granted</Badge>
339
+ <Badge variant="outline">
340
+ {counts?.autoLoaded ?? 0} auto-loaded
341
+ </Badge>
342
+ </div>
343
+
344
+ {isLoading ? (
345
+ <div className="space-y-2">
346
+ <div className="h-14 rounded-lg border bg-muted/30" />
347
+ <div className="h-14 rounded-lg border bg-muted/30" />
348
+ <div className="h-14 rounded-lg border bg-muted/30" />
349
+ </div>
350
+ ) : resources.length === 0 ? (
351
+ <div className="rounded-lg border border-dashed px-4 py-8 text-center text-sm text-muted-foreground">
352
+ No workspace or granted resources are visible to this app yet.
353
+ </div>
354
+ ) : (
355
+ <div className="max-h-[420px] space-y-2 overflow-y-auto pr-1">
356
+ {resources.map((resource) => {
357
+ const inspected = inspectedResourceId === resource.id;
358
+ return (
359
+ <div
360
+ key={resource.id}
361
+ className="rounded-lg border px-3 py-3"
362
+ >
363
+ <div className="flex items-start justify-between gap-3">
364
+ <div className="min-w-0">
365
+ <div className="flex flex-wrap items-center gap-2">
366
+ <span className="text-sm font-medium text-foreground">
367
+ {resource.name}
368
+ </span>
369
+ <Badge variant="secondary">{resource.kind}</Badge>
370
+ <Badge variant="outline">
371
+ {resource.source === "workspace"
372
+ ? "All apps"
373
+ : "Granted"}
374
+ </Badge>
375
+ {resource.autoLoaded ? (
376
+ <Badge variant="outline">Auto-loaded</Badge>
377
+ ) : null}
378
+ </div>
379
+ <div className="mt-1 truncate font-mono text-xs text-muted-foreground">
380
+ {resource.path}
381
+ </div>
382
+ </div>
383
+ <div className="flex shrink-0 flex-col items-end gap-2">
384
+ {resource.source === "grant" ? (
385
+ <div className="text-right text-[11px] text-muted-foreground">
386
+ Selected grant
387
+ </div>
388
+ ) : null}
389
+ <Button
390
+ type="button"
391
+ variant="ghost"
392
+ size="sm"
393
+ className="h-7 px-2 text-xs"
394
+ onClick={(event) => {
395
+ event.stopPropagation();
396
+ setInspectedResourceId(
397
+ inspected ? null : resource.id,
398
+ );
399
+ }}
400
+ >
401
+ {inspected ? (
402
+ <IconChevronDown size={14} className="mr-1" />
403
+ ) : (
404
+ <IconChevronRight size={14} className="mr-1" />
405
+ )}
406
+ Stack
407
+ </Button>
408
+ </div>
409
+ </div>
410
+
411
+ {resource.description ? (
412
+ <p className="mt-2 line-clamp-2 text-xs text-muted-foreground">
413
+ {resource.description}
414
+ </p>
415
+ ) : null}
416
+
417
+ {inspected ? (
418
+ <AppResourceEffectiveStack
419
+ appId={app.id}
420
+ resource={resource}
421
+ />
422
+ ) : null}
423
+ </div>
424
+ );
425
+ })}
426
+ </div>
427
+ )}
428
+ </div>
429
+ <DialogFooter>
430
+ <Button type="button" onClick={() => setOpen(false)}>
431
+ Done
432
+ </Button>
433
+ </DialogFooter>
434
+ </DialogContent>
435
+ </Dialog>
436
+ );
437
+ }
438
+
172
439
  function stringifyError(err: unknown): string {
173
440
  if (err instanceof Error) return err.message;
174
441
  return String(err);
@@ -0,0 +1,125 @@
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
+ AppResourceEffectiveStack,
7
+ appAvailabilityLabel,
8
+ appLayerState,
9
+ } from "./workspace-resource-effective-stack";
10
+
11
+ const queryState = vi.hoisted(() => ({
12
+ result: { data: null as any, isLoading: false },
13
+ calls: [] as any[],
14
+ }));
15
+
16
+ vi.mock("@agent-native/core/client", () => ({
17
+ useActionQuery: (...args: any[]) => {
18
+ queryState.calls.push(args);
19
+ return queryState.result;
20
+ },
21
+ }));
22
+
23
+ describe("AppResourceEffectiveStack", () => {
24
+ let container: HTMLDivElement;
25
+ let root: Root;
26
+
27
+ beforeEach(() => {
28
+ vi.stubGlobal("IS_REACT_ACT_ENVIRONMENT", true);
29
+ queryState.calls = [];
30
+ queryState.result = { data: null, isLoading: false };
31
+ container = document.createElement("div");
32
+ document.body.appendChild(container);
33
+ root = createRoot(container);
34
+ });
35
+
36
+ afterEach(() => {
37
+ act(() => root.unmount());
38
+ container.remove();
39
+ vi.unstubAllGlobals();
40
+ });
41
+
42
+ it("renders the effective layer stack and winning override", () => {
43
+ queryState.result = {
44
+ isLoading: false,
45
+ data: {
46
+ availability: "all-apps",
47
+ effectiveResource: {
48
+ owner: "person@example.test",
49
+ path: "context/brand.md",
50
+ },
51
+ layers: [
52
+ {
53
+ scope: "workspace",
54
+ label: "Workspace default",
55
+ owner: "__workspace__",
56
+ resource: {
57
+ path: "context/brand.md",
58
+ updatedAt: 1,
59
+ },
60
+ exists: true,
61
+ effective: false,
62
+ overridden: true,
63
+ },
64
+ {
65
+ scope: "shared",
66
+ label: "Organization/app override",
67
+ owner: "__shared__",
68
+ resource: null,
69
+ exists: false,
70
+ effective: false,
71
+ overridden: false,
72
+ },
73
+ {
74
+ scope: "personal",
75
+ label: "Personal override",
76
+ owner: "person@example.test",
77
+ resource: {
78
+ path: "context/brand.md",
79
+ updatedAt: 2,
80
+ },
81
+ exists: true,
82
+ effective: true,
83
+ overridden: false,
84
+ },
85
+ ],
86
+ },
87
+ };
88
+
89
+ act(() => {
90
+ root.render(
91
+ <AppResourceEffectiveStack
92
+ appId="analytics"
93
+ resource={{ id: "resource_1", path: "context/brand.md" }}
94
+ />,
95
+ );
96
+ });
97
+
98
+ expect(queryState.calls[0]).toEqual([
99
+ "get-workspace-resource-effective-context",
100
+ { resourceId: "resource_1", appId: "analytics" },
101
+ { enabled: true },
102
+ ]);
103
+ expect(container.textContent).toContain("Effective context stack");
104
+ expect(container.textContent).toContain("Inherited by all apps");
105
+ expect(container.textContent).toContain("Workspace default");
106
+ expect(container.textContent).toContain("Organization/app override");
107
+ expect(container.textContent).toContain("Personal override");
108
+ expect(container.textContent).toContain("Overridden");
109
+ expect(container.textContent).toContain("Wins");
110
+ expect(container.textContent).toContain("No file at this layer");
111
+ expect(container.textContent).toContain(
112
+ "person@example.test/context/brand.md",
113
+ );
114
+ });
115
+
116
+ it("keeps availability and layer-state labels stable", () => {
117
+ expect(appAvailabilityLabel("selected-granted")).toBe(
118
+ "Granted to this app",
119
+ );
120
+ expect(appAvailabilityLabel("selected-not-granted")).toBe("Not granted");
121
+ expect(appLayerState({ effective: true }).label).toBe("Wins");
122
+ expect(appLayerState({ overridden: true }).label).toBe("Overridden");
123
+ expect(appLayerState({}).label).toBe("Missing");
124
+ });
125
+ });
@@ -0,0 +1,141 @@
1
+ import { useActionQuery } from "@agent-native/core/client";
2
+ import { Badge } from "@/components/ui/badge";
3
+ import { cn } from "@/lib/utils";
4
+
5
+ export function appAvailabilityLabel(value?: string) {
6
+ switch (value) {
7
+ case "all-apps":
8
+ return "Inherited by all apps";
9
+ case "selected-granted":
10
+ return "Granted to this app";
11
+ case "selected-not-granted":
12
+ return "Not granted";
13
+ case "selected-no-app":
14
+ return "Select app";
15
+ case "path-not-managed":
16
+ return "Not managed";
17
+ default:
18
+ return "Checking";
19
+ }
20
+ }
21
+
22
+ export function appLayerState(layer: any): {
23
+ label: string;
24
+ className: string;
25
+ } {
26
+ if (layer.effective) {
27
+ return {
28
+ label: "Wins",
29
+ className: "border-green-500/30 bg-green-500/10 text-green-700",
30
+ };
31
+ }
32
+ if (layer.overridden) {
33
+ return {
34
+ label: "Overridden",
35
+ className: "border-amber-500/30 bg-amber-500/10 text-amber-700",
36
+ };
37
+ }
38
+ return {
39
+ label: "Missing",
40
+ className: "text-muted-foreground",
41
+ };
42
+ }
43
+
44
+ export function formatResourceTimestamp(value?: number | null): string {
45
+ if (!value) return "not present";
46
+ return new Date(value).toLocaleString();
47
+ }
48
+
49
+ export function AppResourceEffectiveStack({
50
+ appId,
51
+ resource,
52
+ }: {
53
+ appId: string;
54
+ resource: any;
55
+ }) {
56
+ const { data: context, isLoading } = useActionQuery(
57
+ "get-workspace-resource-effective-context",
58
+ { resourceId: resource.id, appId },
59
+ { enabled: !!resource.id },
60
+ );
61
+ const layers = ((context as any)?.layers ?? []) as any[];
62
+ const active = (context as any)?.effectiveResource;
63
+ const availability = (context as any)?.availability;
64
+
65
+ if (isLoading && !context) {
66
+ return (
67
+ <div className="mt-3 rounded-lg border bg-muted/20 p-3">
68
+ <div className="h-3 w-44 animate-pulse rounded bg-muted-foreground/10" />
69
+ <div className="mt-3 grid gap-2 sm:grid-cols-3">
70
+ <div className="h-20 animate-pulse rounded-md bg-muted-foreground/10" />
71
+ <div className="h-20 animate-pulse rounded-md bg-muted-foreground/10" />
72
+ <div className="h-20 animate-pulse rounded-md bg-muted-foreground/10" />
73
+ </div>
74
+ </div>
75
+ );
76
+ }
77
+
78
+ return (
79
+ <div className="mt-3 rounded-lg border bg-muted/20 p-3">
80
+ <div className="flex flex-wrap items-start justify-between gap-2">
81
+ <div className="min-w-0">
82
+ <div className="text-xs font-semibold uppercase text-muted-foreground">
83
+ Effective context stack
84
+ </div>
85
+ <div className="mt-1 truncate font-mono text-[11px] text-muted-foreground">
86
+ {resource.path}
87
+ </div>
88
+ </div>
89
+ <Badge variant="outline">{appAvailabilityLabel(availability)}</Badge>
90
+ </div>
91
+
92
+ <div className="mt-3 grid gap-2 sm:grid-cols-3">
93
+ {layers.map((layer) => {
94
+ const state = appLayerState(layer);
95
+ return (
96
+ <div
97
+ key={layer.scope}
98
+ className={cn("rounded-md border bg-background/70 p-2", {
99
+ "border-green-500/30 bg-green-500/10": layer.effective,
100
+ })}
101
+ >
102
+ <div className="flex items-start justify-between gap-2">
103
+ <span className="text-xs font-medium text-foreground">
104
+ {layer.label}
105
+ </span>
106
+ <Badge variant="outline" className={state.className}>
107
+ {state.label}
108
+ </Badge>
109
+ </div>
110
+ <div className="mt-1 truncate font-mono text-[10px] text-muted-foreground">
111
+ {layer.owner}
112
+ </div>
113
+ {layer.resource ? (
114
+ <div className="mt-2 text-[11px] text-muted-foreground">
115
+ Updated {formatResourceTimestamp(layer.resource.updatedAt)}
116
+ </div>
117
+ ) : (
118
+ <div className="mt-2 text-[11px] text-muted-foreground">
119
+ No file at this layer
120
+ </div>
121
+ )}
122
+ </div>
123
+ );
124
+ })}
125
+ </div>
126
+
127
+ <div className="mt-3 rounded-md bg-background/70 px-3 py-2 text-xs text-muted-foreground">
128
+ {active ? (
129
+ <>
130
+ Winning layer:{" "}
131
+ <span className="font-mono text-foreground">
132
+ {active.owner}/{active.path}
133
+ </span>
134
+ </>
135
+ ) : (
136
+ "No active resource exists for this path yet."
137
+ )}
138
+ </div>
139
+ </div>
140
+ );
141
+ }