@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
@@ -0,0 +1,218 @@
1
+ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
2
+
3
+ const loadWorkspaceAppsManifestMock = vi.hoisted(() => vi.fn());
4
+ const getBuiltinAgentsMock = vi.hoisted(() => vi.fn());
5
+
6
+ vi.mock("@agent-native/core/server/agent-discovery", () => ({
7
+ loadWorkspaceAppsManifest: loadWorkspaceAppsManifestMock,
8
+ getBuiltinAgents: getBuiltinAgentsMock,
9
+ }));
10
+
11
+ import { resolveCatchAllTarget } from "./catch-all-target.js";
12
+
13
+ beforeEach(() => {
14
+ vi.clearAllMocks();
15
+ });
16
+
17
+ afterEach(() => {
18
+ vi.clearAllMocks();
19
+ });
20
+
21
+ describe("resolveCatchAllTarget", () => {
22
+ it("prefers the workspace manifest entry when one matches", () => {
23
+ loadWorkspaceAppsManifestMock.mockReturnValue([
24
+ { id: "todo", name: "Todo", path: "/todo" },
25
+ ]);
26
+ getBuiltinAgentsMock.mockReturnValue([
27
+ {
28
+ id: "todo",
29
+ name: "Todo",
30
+ description: "",
31
+ url: "https://todo.example.com",
32
+ color: "#000",
33
+ },
34
+ ]);
35
+
36
+ expect(resolveCatchAllTarget("todo")).toBe("/todo");
37
+ });
38
+
39
+ it("falls back to the built-in template URL when no workspace manifest exists", () => {
40
+ loadWorkspaceAppsManifestMock.mockReturnValue(null);
41
+ getBuiltinAgentsMock.mockReturnValue([
42
+ {
43
+ id: "forms",
44
+ name: "Forms",
45
+ description: "",
46
+ url: "http://localhost:8084",
47
+ color: "#06B6D4",
48
+ },
49
+ ]);
50
+
51
+ expect(resolveCatchAllTarget("forms")).toBe("http://localhost:8084");
52
+ });
53
+
54
+ it("falls back to the built-in template URL when the workspace manifest does not include the app", () => {
55
+ loadWorkspaceAppsManifestMock.mockReturnValue([
56
+ { id: "dispatch", name: "Dispatch", path: "/dispatch" },
57
+ ]);
58
+ getBuiltinAgentsMock.mockReturnValue([
59
+ {
60
+ id: "forms",
61
+ name: "Forms",
62
+ description: "",
63
+ url: "http://localhost:8084",
64
+ color: "#06B6D4",
65
+ },
66
+ ]);
67
+
68
+ expect(resolveCatchAllTarget("forms")).toBe("http://localhost:8084");
69
+ });
70
+
71
+ it("normalizes a manifest entry without a leading slash", () => {
72
+ loadWorkspaceAppsManifestMock.mockReturnValue([
73
+ { id: "todo", name: "Todo", path: "todo" },
74
+ ]);
75
+ getBuiltinAgentsMock.mockReturnValue([]);
76
+
77
+ expect(resolveCatchAllTarget("todo")).toBe("/todo");
78
+ });
79
+
80
+ it("uses app.path when id !== path (not /${appId})", () => {
81
+ // Before the fix, an entry whose mounted path differs from its id —
82
+ // e.g. id: "forms", path: "my-forms" without a leading slash — was
83
+ // silently rewritten to `/forms` (the appId) and routed to the wrong
84
+ // app. The normalizer now keeps the manifest path and only prepends
85
+ // the missing slash.
86
+ loadWorkspaceAppsManifestMock.mockReturnValue([
87
+ { id: "forms", name: "Forms", path: "my-forms" },
88
+ ]);
89
+ getBuiltinAgentsMock.mockReturnValue([]);
90
+
91
+ expect(resolveCatchAllTarget("forms")).toBe("/my-forms");
92
+ });
93
+
94
+ it("prefers app.url when the manifest entry has an externally-hosted URL", () => {
95
+ // Workspaces can point at remote deploys. The catch-all should bounce
96
+ // to the absolute URL instead of mounting a local path that doesn't
97
+ // exist inside the gateway.
98
+ loadWorkspaceAppsManifestMock.mockReturnValue([
99
+ {
100
+ id: "forms",
101
+ name: "Forms",
102
+ path: "/forms",
103
+ url: "https://forms.example.com",
104
+ },
105
+ ]);
106
+ getBuiltinAgentsMock.mockReturnValue([]);
107
+
108
+ expect(resolveCatchAllTarget("forms")).toBe("https://forms.example.com");
109
+ });
110
+
111
+ it("ignores app.url that isn't an absolute http(s) URL and falls back to path", () => {
112
+ // Bare hostname — `new URL("forms.example.com")` throws, so the value
113
+ // is rejected and we fall through to the (validated) path. Without
114
+ // this, the catch-all would `throw redirect("forms.example.com")`
115
+ // and the browser would treat the value as a relative path inside the
116
+ // gateway, producing a broken redirect.
117
+ loadWorkspaceAppsManifestMock.mockReturnValue([
118
+ {
119
+ id: "forms",
120
+ name: "Forms",
121
+ path: "/forms",
122
+ url: "forms.example.com",
123
+ },
124
+ ]);
125
+ getBuiltinAgentsMock.mockReturnValue([]);
126
+
127
+ expect(resolveCatchAllTarget("forms")).toBe("/forms");
128
+ });
129
+
130
+ it("rejects non-http(s) URL schemes (e.g. javascript:) and falls back to path", () => {
131
+ // Defense in depth — a hostile manifest entry can't produce a
132
+ // `javascript:` redirect target. Validation enforces http(s) only.
133
+ loadWorkspaceAppsManifestMock.mockReturnValue([
134
+ {
135
+ id: "forms",
136
+ name: "Forms",
137
+ path: "/forms",
138
+ url: "javascript:alert(1)",
139
+ },
140
+ ]);
141
+ getBuiltinAgentsMock.mockReturnValue([]);
142
+
143
+ expect(resolveCatchAllTarget("forms")).toBe("/forms");
144
+ });
145
+
146
+ it("strips a trailing slash from app.url", () => {
147
+ loadWorkspaceAppsManifestMock.mockReturnValue([
148
+ {
149
+ id: "forms",
150
+ name: "Forms",
151
+ path: "/forms",
152
+ url: "https://forms.example.com/",
153
+ },
154
+ ]);
155
+ getBuiltinAgentsMock.mockReturnValue([]);
156
+
157
+ expect(resolveCatchAllTarget("forms")).toBe("https://forms.example.com");
158
+ });
159
+
160
+ it("ignores an empty/whitespace app.url and falls back to path", () => {
161
+ loadWorkspaceAppsManifestMock.mockReturnValue([
162
+ {
163
+ id: "forms",
164
+ name: "Forms",
165
+ path: "/forms",
166
+ url: " ",
167
+ },
168
+ ]);
169
+ getBuiltinAgentsMock.mockReturnValue([]);
170
+
171
+ expect(resolveCatchAllTarget("forms")).toBe("/forms");
172
+ });
173
+
174
+ it("collapses leading slashes/backslashes in app.path so `/\\evil.example` can't redirect off-origin", () => {
175
+ // Browsers normalize backslashes to forward slashes during URL
176
+ // parsing, so `throw redirect("/\\evil.example")` would resolve to
177
+ // `https://evil.example`. The regex covers both slash types.
178
+ loadWorkspaceAppsManifestMock.mockReturnValue([
179
+ { id: "forms", name: "Forms", path: "/\\evil.example" },
180
+ ]);
181
+ getBuiltinAgentsMock.mockReturnValue([]);
182
+
183
+ expect(resolveCatchAllTarget("forms")).toBe("/evil.example");
184
+ });
185
+
186
+ it("collapses leading double slashes in app.path so `//evil.example` can't redirect off-origin", () => {
187
+ // The manifest parser only checks `startsWith("/")`, so a path of
188
+ // `//evil.example` slips through. Browsers treat that as a network-
189
+ // path reference and `throw redirect("//evil.example")` would redirect
190
+ // to `https://evil.example` — the same phishing vector the `app.url`
191
+ // validator closes. Collapse the leading slashes so the redirect
192
+ // stays on the gateway.
193
+ loadWorkspaceAppsManifestMock.mockReturnValue([
194
+ { id: "forms", name: "Forms", path: "//evil.example" },
195
+ ]);
196
+ getBuiltinAgentsMock.mockReturnValue([]);
197
+
198
+ expect(resolveCatchAllTarget("forms")).toBe("/evil.example");
199
+ });
200
+
201
+ it("falls back to /${appId} when the manifest entry has neither path nor url", () => {
202
+ loadWorkspaceAppsManifestMock.mockReturnValue([
203
+ { id: "forms", name: "Forms", path: "" },
204
+ ]);
205
+ getBuiltinAgentsMock.mockReturnValue([]);
206
+
207
+ expect(resolveCatchAllTarget("forms")).toBe("/forms");
208
+ });
209
+
210
+ it("returns null when nothing matches", () => {
211
+ loadWorkspaceAppsManifestMock.mockReturnValue([
212
+ { id: "dispatch", name: "Dispatch", path: "/dispatch" },
213
+ ]);
214
+ getBuiltinAgentsMock.mockReturnValue([]);
215
+
216
+ expect(resolveCatchAllTarget("unknown-app")).toBeNull();
217
+ });
218
+ });
@@ -0,0 +1,99 @@
1
+ import {
2
+ getBuiltinAgents,
3
+ loadWorkspaceAppsManifest,
4
+ } from "@agent-native/core/server/agent-discovery";
5
+
6
+ /**
7
+ * Resolve where `/dispatch/<appId>` should bounce to when it doesn't match
8
+ * an explicit dispatch route. Used by the `$appId` catch-all route loader.
9
+ *
10
+ * Resolution order:
11
+ *
12
+ * 1. Workspace apps manifest (env, .agent-native/workspace-apps.json, or a
13
+ * filesystem scan of `apps/`).
14
+ * - `app.url` (absolute URL — externally hosted workspace app) wins if
15
+ * present.
16
+ * - Otherwise the `app.path` mounted under the workspace gateway is
17
+ * used. Path is normalized to a leading slash if missing
18
+ * (e.g. manifest entry `path: "my-forms"` → `/my-forms`), so an app
19
+ * whose mounted path differs from its id ends up at the right place
20
+ * instead of being silently rewritten to `/${appId}`.
21
+ * - Bare entry with no path / url falls back to `/${appId}`.
22
+ * 2. First-party template registry. When no workspace manifest matches
23
+ * (framework dev with each template on its own port, hosted dispatch
24
+ * with no sibling apps), return the matching template's deploy URL —
25
+ * dev URL in development (e.g. http://localhost:8084 for forms), prod
26
+ * URL in production (e.g. https://forms.agent-native.com).
27
+ *
28
+ * Returns `null` if neither lookup matches, letting the route render its
29
+ * "Page not found" pane.
30
+ */
31
+ /**
32
+ * Validate `app.url` is an absolute http(s) URL before we trust it as a
33
+ * redirect target. A bare hostname (`"forms.example.com"`) or a
34
+ * `javascript:` scheme would otherwise get returned verbatim from
35
+ * `resolveCatchAllTarget` and produce a broken redirect (or a phishing
36
+ * vector). Mirrors `normalizeWorkspaceAppUrl` in
37
+ * `packages/core/src/deploy/workspace-deploy.ts` — but inlined to avoid
38
+ * pulling the deploy CLI module into a runtime path.
39
+ */
40
+ function validatedAbsoluteUrl(value: unknown): string | undefined {
41
+ if (typeof value !== "string" || !value.trim()) return undefined;
42
+ try {
43
+ const parsed = new URL(value.trim());
44
+ if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
45
+ return undefined;
46
+ }
47
+ return parsed.toString().replace(/\/$/, "");
48
+ } catch {
49
+ return undefined;
50
+ }
51
+ }
52
+
53
+ export function resolveCatchAllTarget(appId: string): string | null {
54
+ const apps = loadWorkspaceAppsManifest();
55
+ if (apps) {
56
+ const app = apps.find((entry) => entry?.id === appId);
57
+ if (app) {
58
+ // Explicit externally-hosted URL wins. Workspaces that point at a
59
+ // remote deploy (e.g. a sibling app on Netlify) set `url` and we
60
+ // should bounce the user there rather than mounting a local path
61
+ // that doesn't exist inside the gateway. Validate the URL first —
62
+ // a bare hostname or non-http(s) scheme would produce a broken
63
+ // redirect (and a `javascript:` value would be a phishing vector).
64
+ const url = validatedAbsoluteUrl(app.url);
65
+ if (url) {
66
+ return url;
67
+ }
68
+ // Fall back to the mounted path. Normalize to leading slash so an
69
+ // entry whose path differs from its id (e.g. `id: "forms"`,
70
+ // `path: "my-forms"`) still lands on the correct gateway mount —
71
+ // not on `/${appId}`, which would silently route to the wrong app.
72
+ //
73
+ // Reject scheme-relative paths. Three variants reach this point —
74
+ // all of them get collapsed to a single leading slash so the
75
+ // redirect stays on the gateway:
76
+ //
77
+ // `//evil.example` — network-path reference, browser treats as
78
+ // absolute (https://evil.example).
79
+ // `/\evil.example` — browsers normalize backslashes to forward
80
+ // slashes during URL parsing, same result.
81
+ // `\/evil.example` — same idea, leading-backslash variant.
82
+ //
83
+ // The manifest parser only checks `startsWith("/")` for the first
84
+ // case, and even that allows `//evil…`. Defend in depth here by
85
+ // collapsing any run of leading slashes-or-backslashes to one
86
+ // forward slash. Same phishing vector that `validatedAbsoluteUrl`
87
+ // closes for `app.url`.
88
+ if (typeof app.path === "string" && app.path.trim()) {
89
+ const normalized = app.path.trim().replace(/^[/\\]+/, "/");
90
+ return normalized.startsWith("/") ? normalized : `/${normalized}`;
91
+ }
92
+ return `/${appId}`;
93
+ }
94
+ }
95
+ const builtin = getBuiltinAgents("dispatch").find(
96
+ (agent) => agent.id === appId,
97
+ );
98
+ return builtin?.url ?? null;
99
+ }
package/src/lib/utils.ts CHANGED
@@ -1 +1,6 @@
1
- export { cn } from "@agent-native/core";
1
+ import { type ClassValue, clsx } from "clsx";
2
+ import { twMerge } from "tailwind-merge";
3
+
4
+ export function cn(...inputs: ClassValue[]) {
5
+ return twMerge(clsx(inputs));
6
+ }
@@ -5,10 +5,19 @@ export interface WorkspaceAppSummary {
5
5
  path: string;
6
6
  url?: string | null;
7
7
  isDispatch?: boolean;
8
+ audience?: "internal" | "public";
9
+ publicPaths?: string[];
10
+ protectedPaths?: string[];
8
11
  status?: "ready" | "pending";
9
12
  statusLabel?: string;
10
13
  builderUrl?: string | null;
11
14
  branchName?: string | null;
15
+ createdAt?: string | null;
16
+ agentCardUrl?: string | null;
17
+ agentCardReachable?: boolean;
18
+ a2aEndpointUrl?: string | null;
19
+ agentName?: string | null;
20
+ agentSkillsCount?: number | null;
12
21
  archived?: boolean;
13
22
  }
14
23
 
@@ -46,6 +46,7 @@ export const dispatchRoutes: RouteConfig = [
46
46
  route("approval", "./pages/approval.js"),
47
47
  route("approvals", "./pages/approvals.js"),
48
48
  route("audit", "./pages/audit.js"),
49
+ route("dreams", "./pages/dreams.js"),
49
50
  route("thread-debug", "./pages/thread-debug.js"),
50
51
  route("team", "./pages/team.js"),
51
52
  route("extensions", "./pages/extensions._index.js"),
@@ -4,10 +4,10 @@ import {
4
4
  Navigate,
5
5
  redirect,
6
6
  useParams,
7
+ type ClientLoaderFunctionArgs,
7
8
  type LoaderFunctionArgs,
8
9
  } from "react-router";
9
10
  import { useActionQuery, appPath } from "@agent-native/core/client";
10
- import { loadWorkspaceAppsManifest } from "@agent-native/core/server/agent-discovery";
11
11
  import {
12
12
  IconArrowLeft,
13
13
  IconArrowUpRight,
@@ -17,6 +17,7 @@ import { DispatchShell } from "@/components/dispatch-shell";
17
17
  import { Spinner } from "@/components/ui/spinner";
18
18
  import { Badge } from "@/components/ui/badge";
19
19
  import { Button } from "@/components/ui/button";
20
+ import { resolveCatchAllTarget } from "@/lib/catch-all-target";
20
21
  import {
21
22
  workspaceAppHref,
22
23
  type WorkspaceAppSummary,
@@ -49,6 +50,14 @@ export function meta() {
49
50
  * and looks broken. This route fixes both the post-creation navigation
50
51
  * and the OAuth round-trip from a single place.
51
52
  *
53
+ * Built-in template fallback: when no workspace manifest is available
54
+ * (framework dev with each template on its own port, hosted dispatch with
55
+ * no sibling apps), redirect to the matching first-party template's deploy
56
+ * URL — `http://localhost:<devPort>` in dev, `https://<id>.agent-native.com`
57
+ * in production. Without this, a user visiting `/forms` on dispatch is
58
+ * forced to sign in (auth guard) and then lands on this route's "Page not
59
+ * found" pane after the post-login reload.
60
+ *
52
61
  * `appId === "dispatch"` short-circuit: when the segment matches Dispatch
53
62
  * itself (e.g. `/dispatch/dispatch`), we go straight to the overview rather
54
63
  * than chaining through `/dispatch` (which polled `useActionQuery` re-fired
@@ -64,19 +73,23 @@ export function loader({ params }: LoaderFunctionArgs) {
64
73
  if (!appId) return null;
65
74
  const selfTarget = dispatchSelfRedirect(appId);
66
75
  if (selfTarget) throw redirect(selfTarget);
67
- const apps = loadWorkspaceAppsManifest();
68
- if (!apps) return null;
69
- const app = apps.find((entry) => entry?.id === appId);
70
- const target =
71
- app?.path && app.path.startsWith("/") ? app.path : app ? `/${appId}` : null;
76
+ const target = resolveCatchAllTarget(appId);
72
77
  if (target) throw redirect(target);
73
78
  return null;
74
79
  }
75
80
 
76
- export function clientLoader({ params }: LoaderFunctionArgs) {
81
+ export async function clientLoader({
82
+ params,
83
+ serverLoader,
84
+ }: ClientLoaderFunctionArgs) {
77
85
  const selfTarget = dispatchSelfRedirect(params.appId);
78
86
  if (selfTarget) throw redirect(selfTarget);
79
- return null;
87
+ // Defer to the server loader so the built-in template fallback runs on
88
+ // SPA navigations too (e.g. clicking a `/<template-id>` link inside
89
+ // dispatch). Without this the client side would only check the workspace
90
+ // apps query, which never lists the static first-party templates and so
91
+ // the user would land on the "Page not found" pane.
92
+ return serverLoader();
80
93
  }
81
94
 
82
95
  export default function WorkspaceAppCatchAllRoute() {
@@ -7,6 +7,10 @@ import {
7
7
  appPath,
8
8
  } from "@agent-native/core/client";
9
9
  import { toast } from "sonner";
10
+ import {
11
+ ApprovalValueBlock,
12
+ parseApprovalValue,
13
+ } from "@/components/approval-value-block";
10
14
  import { Button } from "@/components/ui/button";
11
15
  import { Badge } from "@/components/ui/badge";
12
16
  import { Skeleton } from "@/components/ui/skeleton";
@@ -168,10 +172,12 @@ export default function ApprovalPreviewRoute() {
168
172
  }
169
173
 
170
174
  const isPending = approval.status === "pending";
175
+ const beforeValue = parseApprovalValue(approval.beforeValue);
176
+ const afterValue = parseApprovalValue(approval.afterValue);
171
177
 
172
178
  return (
173
179
  <div className="flex min-h-screen items-start justify-center bg-background p-6">
174
- <div className="w-full max-w-md space-y-4">
180
+ <div className="w-full max-w-2xl space-y-4">
175
181
  <div className="rounded-2xl border bg-card p-5">
176
182
  <div className="flex items-start gap-3">
177
183
  <div className="flex h-9 w-9 shrink-0 items-center justify-center rounded-xl border bg-muted text-foreground">
@@ -224,6 +230,13 @@ export default function ApprovalPreviewRoute() {
224
230
  )}
225
231
  </div>
226
232
 
233
+ {(beforeValue !== null || afterValue !== null) && (
234
+ <div className="mt-4 grid gap-3 md:grid-cols-2">
235
+ <ApprovalValueBlock label="Before" value={beforeValue} />
236
+ <ApprovalValueBlock label="After" value={afterValue} />
237
+ </div>
238
+ )}
239
+
227
240
  {isPending && (
228
241
  <div className="mt-4 flex gap-2">
229
242
  <Button
@@ -58,7 +58,7 @@ export default function ApprovalsRoute() {
58
58
  </div>
59
59
  <div className="mt-1 text-xs text-muted-foreground">
60
60
  {hasOrg
61
- ? "Applies to saved destinations and dispatch settings today."
61
+ ? "Applies to saved destinations, shared dream proposals, All-app workspace resources, and dispatch settings."
62
62
  : "Requires a team workspace. Set one up on the Team page."}
63
63
  </div>
64
64
  </div>
@@ -0,0 +1,130 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import {
3
+ dreamSettingsToDraft,
4
+ dreamSettingsUpdateFromDraft,
5
+ splitSourceIds,
6
+ type DreamSettingsDraft,
7
+ } from "./dream-settings.js";
8
+
9
+ function draft(
10
+ overrides: Partial<DreamSettingsDraft> = {},
11
+ ): DreamSettingsDraft {
12
+ return {
13
+ enabled: true,
14
+ schedule: "0 9 * * 1",
15
+ sourceId: "all",
16
+ sourceIdsText: "",
17
+ allSources: true,
18
+ query: "",
19
+ limit: "8",
20
+ sourceTimeoutMs: "30000",
21
+ sourceConcurrency: "2",
22
+ sourceStartStaggerMs: "250",
23
+ threadConcurrency: "3",
24
+ threadTimeoutMs: "8000",
25
+ minCandidateCount: "1",
26
+ ...overrides,
27
+ };
28
+ }
29
+
30
+ describe("dream settings payload helpers", () => {
31
+ it("normalizes persisted settings into editable draft text", () => {
32
+ expect(
33
+ dreamSettingsToDraft({
34
+ enabled: true,
35
+ schedule: "0 8 * * 2",
36
+ sourceId: "selected",
37
+ sourceIds: ["mail", "calendar"],
38
+ allSources: false,
39
+ query: "memory",
40
+ limit: 12,
41
+ sourceTimeoutMs: 45000,
42
+ sourceConcurrency: 4,
43
+ sourceStartStaggerMs: 500,
44
+ threadConcurrency: 5,
45
+ threadTimeoutMs: 9000,
46
+ minCandidateCount: 2,
47
+ }),
48
+ ).toMatchObject({
49
+ enabled: true,
50
+ schedule: "0 8 * * 2",
51
+ sourceId: "selected",
52
+ sourceIdsText: "mail\ncalendar",
53
+ allSources: false,
54
+ query: "memory",
55
+ limit: "12",
56
+ sourceTimeoutMs: "45000",
57
+ sourceConcurrency: "4",
58
+ sourceStartStaggerMs: "500",
59
+ threadConcurrency: "5",
60
+ threadTimeoutMs: "9000",
61
+ minCandidateCount: "2",
62
+ });
63
+ });
64
+
65
+ it("splits explicit source ids from commas and newlines", () => {
66
+ expect(splitSourceIds(" mail\ncalendar, analytics ,, \nbrain ")).toEqual([
67
+ "mail",
68
+ "calendar",
69
+ "analytics",
70
+ "brain",
71
+ ]);
72
+ });
73
+
74
+ it("builds a save payload that clears source ids and query", () => {
75
+ expect(
76
+ dreamSettingsUpdateFromDraft(
77
+ draft({
78
+ enabled: false,
79
+ schedule: " 0 10 * * 3 ",
80
+ sourceId: " current ",
81
+ sourceIdsText: "",
82
+ allSources: false,
83
+ query: " ",
84
+ minCandidateCount: "0",
85
+ }),
86
+ ),
87
+ ).toMatchObject({
88
+ enabled: false,
89
+ schedule: "0 10 * * 3",
90
+ sourceId: "current",
91
+ sourceIds: [],
92
+ allSources: false,
93
+ query: "",
94
+ limit: 8,
95
+ sourceTimeoutMs: 30000,
96
+ sourceConcurrency: 2,
97
+ sourceStartStaggerMs: 250,
98
+ threadConcurrency: 3,
99
+ threadTimeoutMs: 8000,
100
+ minCandidateCount: 0,
101
+ });
102
+ });
103
+
104
+ it("falls back to all source scope and omits invalid numeric edits", () => {
105
+ expect(
106
+ dreamSettingsUpdateFromDraft(
107
+ draft({
108
+ sourceId: " ",
109
+ sourceIdsText: "mail\ncalendar",
110
+ limit: "not-a-number",
111
+ threadTimeoutMs: "",
112
+ }),
113
+ ),
114
+ ).toMatchObject({
115
+ sourceId: "all",
116
+ sourceIds: ["mail", "calendar"],
117
+ allSources: true,
118
+ });
119
+ expect(
120
+ dreamSettingsUpdateFromDraft(
121
+ draft({ limit: "not-a-number", threadTimeoutMs: "" }),
122
+ ),
123
+ ).not.toHaveProperty("limit");
124
+ expect(
125
+ dreamSettingsUpdateFromDraft(
126
+ draft({ limit: "not-a-number", threadTimeoutMs: "" }),
127
+ ),
128
+ ).not.toHaveProperty("threadTimeoutMs");
129
+ });
130
+ });