@agent-native/dispatch 0.40.40 → 0.40.41-beta-dispatch-embed-01a15dc9-20261027050558

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 (45) hide show
  1. package/CHANGELOG.md +42 -0
  2. package/dist/actions/create_embed_session.js +1 -0
  3. package/dist/actions/create_embed_session.js.map +1 -1
  4. package/dist/actions/delete-destination.d.ts +12 -12
  5. package/dist/actions/provider-api-register.d.ts +13 -13
  6. package/dist/components/layout/Layout.d.ts.map +1 -1
  7. package/dist/components/layout/Layout.js +8 -11
  8. package/dist/components/layout/Layout.js.map +1 -1
  9. package/dist/components/workspace-app-host.d.ts.map +1 -1
  10. package/dist/components/workspace-app-host.js +23 -10
  11. package/dist/components/workspace-app-host.js.map +1 -1
  12. package/dist/lib/workspace-apps.d.ts +2 -2
  13. package/dist/lib/workspace-apps.d.ts.map +1 -1
  14. package/dist/lib/workspace-apps.js +35 -5
  15. package/dist/lib/workspace-apps.js.map +1 -1
  16. package/dist/server/lib/app-creation-store.d.ts.map +1 -1
  17. package/dist/server/lib/app-creation-store.js +173 -48
  18. package/dist/server/lib/app-creation-store.js.map +1 -1
  19. package/dist/server/lib/community-apps.js +1 -1
  20. package/dist/server/lib/community-apps.js.map +1 -1
  21. package/dist/server/lib/mcp-gateway.d.ts +1 -0
  22. package/dist/server/lib/mcp-gateway.d.ts.map +1 -1
  23. package/dist/server/lib/mcp-gateway.js +170 -38
  24. package/dist/server/lib/mcp-gateway.js.map +1 -1
  25. package/dist/server/lib/provider-api.d.ts +2 -2
  26. package/dist/shared/workspace-app-route.d.ts +2 -0
  27. package/dist/shared/workspace-app-route.d.ts.map +1 -0
  28. package/dist/shared/workspace-app-route.js +4 -0
  29. package/dist/shared/workspace-app-route.js.map +1 -0
  30. package/package.json +4 -4
  31. package/src/actions/create_embed_session.ts +1 -0
  32. package/src/actions/index.spec.ts +3 -0
  33. package/src/components/layout/Layout.spec.tsx +39 -9
  34. package/src/components/layout/Layout.tsx +19 -40
  35. package/src/components/workspace-app-host.spec.tsx +88 -1
  36. package/src/components/workspace-app-host.tsx +30 -9
  37. package/src/lib/workspace-apps.spec.ts +64 -5
  38. package/src/lib/workspace-apps.ts +36 -6
  39. package/src/routes/pages/apps.$appId.spec.tsx +21 -3
  40. package/src/server/lib/app-creation-store.spec.ts +502 -11
  41. package/src/server/lib/app-creation-store.ts +198 -50
  42. package/src/server/lib/community-apps.ts +1 -1
  43. package/src/server/lib/mcp-gateway.spec.ts +396 -9
  44. package/src/server/lib/mcp-gateway.ts +209 -45
  45. package/src/shared/workspace-app-route.ts +3 -0
@@ -13,6 +13,7 @@ import {
13
13
  isActionContractError,
14
14
  } from "@agent-native/core/action";
15
15
  import { describeErrorWithCauses } from "@agent-native/core/agent/engine/error-detail";
16
+ import { getAppConfig } from "@agent-native/core/app-config";
16
17
  import { getDbExec } from "@agent-native/core/db";
17
18
  import { and, eq, inArray } from "@agent-native/core/db/schema";
18
19
  import {
@@ -56,6 +57,7 @@ import {
56
57
  import { resolveAccess } from "@agent-native/core/sharing";
57
58
 
58
59
  import { getDb } from "../../db/index.js";
60
+ import { workspaceAppRoute } from "../../shared/workspace-app-route.js";
59
61
  import { isWorkspaceSsoAppUrl } from "../../shared/workspace-sso.js";
60
62
  import { getDispatchDefaultOwnerEmail } from "./admin-config.js";
61
63
  import { identityKeyForIncoming } from "./dispatch-integrations.js";
@@ -155,6 +157,15 @@ class WorkspaceAppOrgRequiredError extends Error {
155
157
  }
156
158
  }
157
159
 
160
+ class WorkspaceGatewayConfigurationError extends Error {
161
+ constructor(cause?: unknown) {
162
+ super("WORKSPACE_GATEWAY_URL must be a valid absolute HTTP(S) URL.", {
163
+ cause,
164
+ });
165
+ this.name = "WorkspaceGatewayConfigurationError";
166
+ }
167
+ }
168
+
158
169
  function requireWorkspaceAppOrgId(): string {
159
170
  const orgId = currentOrgId();
160
171
  if (!orgId) throw new WorkspaceAppOrgRequiredError();
@@ -295,17 +306,22 @@ interface WorkspaceAppMetadataSettings {
295
306
  }
296
307
 
297
308
  function readJson(file: string): any {
298
- try {
299
- return JSON.parse(fs.readFileSync(file, "utf8"));
300
- } catch {
301
- return null;
302
- }
309
+ if (!fs.existsSync(file)) return null;
310
+ return JSON.parse(fs.readFileSync(file, "utf8"));
303
311
  }
304
312
 
305
313
  function findWorkspaceRoot(startDir = process.cwd()): string | null {
306
314
  let dir = path.resolve(startDir);
307
315
  for (let i = 0; i < 20; i++) {
308
- const pkg = readJson(path.join(dir, "package.json"));
316
+ let pkg: any;
317
+ try {
318
+ pkg = readJson(path.join(dir, "package.json"));
319
+ } catch (error) {
320
+ console.warn(
321
+ `[dispatch] Could not read workspace package metadata in ${dir}; continuing parent search`,
322
+ error,
323
+ );
324
+ }
309
325
  if (typeof pkg?.["agent-native"]?.workspaceCore === "string") {
310
326
  return dir;
311
327
  }
@@ -627,18 +643,87 @@ function applyWorkspaceAppMetadataOverride(
627
643
  // code belongs here; changes to authorship, content trust, or sharing require
628
644
  // an explicit auth, origin, or sandbox boundary before this invariant changes.
629
645
  function workspaceAppUrl(appPath: string): string | null {
646
+ const gateway = workspaceGatewayBaseUrl();
647
+ if (gateway) return appendWorkspaceAppPath(gateway, appPath);
648
+
630
649
  const base = resolveAppRuntimeUrl();
631
650
  if (!base) return null;
632
651
  try {
633
- return new URL(
634
- appPath,
635
- `${projectEnvironmentUrl(base).replace(/\/$/, "")}/`,
636
- ).toString();
652
+ const baseUrl = new URL(
653
+ addBasePath(projectEnvironmentUrl(base), getConfiguredAppBasePath()),
654
+ );
655
+ return appendWorkspaceAppPath(baseUrl, appPath);
637
656
  } catch {
638
657
  return null;
639
658
  }
640
659
  }
641
660
 
661
+ function appendWorkspaceAppPath(baseUrl: URL, appPath: string): string {
662
+ const parsedPath = new URL(appPath, "http://agent-native.invalid");
663
+ const basePath = baseUrl.pathname.replace(/\/+$/, "");
664
+ let appPathname = parsedPath.pathname;
665
+ if (
666
+ basePath &&
667
+ (appPathname === basePath || appPathname.startsWith(`${basePath}/`))
668
+ ) {
669
+ appPathname = appPathname.slice(basePath.length) || "/";
670
+ }
671
+ baseUrl.pathname =
672
+ `${basePath}${appPathname.startsWith("/") ? appPathname : `/${appPathname}`}` ||
673
+ "/";
674
+ baseUrl.search = parsedPath.search;
675
+ baseUrl.hash = parsedPath.hash;
676
+ return baseUrl.toString().replace(/\/$/, "");
677
+ }
678
+
679
+ function workspaceGatewayBaseUrl(): URL | null {
680
+ const configured = getAppConfig().workspace.gatewayUrl?.trim();
681
+ if (!configured) return null;
682
+ let configuredUrl: URL;
683
+ try {
684
+ configuredUrl = new URL(configured);
685
+ } catch (error) {
686
+ throw new WorkspaceGatewayConfigurationError(error);
687
+ }
688
+ if (
689
+ configuredUrl.protocol !== "http:" &&
690
+ configuredUrl.protocol !== "https:"
691
+ ) {
692
+ throw new WorkspaceGatewayConfigurationError();
693
+ }
694
+ let url: URL;
695
+ try {
696
+ url = new URL(projectEnvironmentUrl(configuredUrl.toString()));
697
+ } catch (error) {
698
+ throw new WorkspaceGatewayConfigurationError(error);
699
+ }
700
+ if (url.protocol !== "http:" && url.protocol !== "https:") {
701
+ throw new WorkspaceGatewayConfigurationError();
702
+ }
703
+ return new URL(addBasePath(url.toString(), getConfiguredAppBasePath()));
704
+ }
705
+
706
+ function workspaceGatewayAppUrl(appPath: string): string | null {
707
+ const baseUrl = workspaceGatewayBaseUrl();
708
+ if (!baseUrl) return null;
709
+ const requestOrigin = getRequestContext()?.requestOrigin;
710
+ if (requestOrigin && new URL(requestOrigin).origin === baseUrl.origin) {
711
+ return null;
712
+ }
713
+ return appendWorkspaceAppPath(baseUrl, appPath);
714
+ }
715
+
716
+ function addBasePath(urlValue: string, basePath: string): string {
717
+ if (!basePath) return urlValue;
718
+ const url = new URL(urlValue);
719
+ const pathname = url.pathname.replace(/\/+$/, "") || "/";
720
+ if (pathname === basePath || pathname.startsWith(`${basePath}/`)) {
721
+ return url.toString();
722
+ }
723
+ url.pathname = `${basePath}${pathname === "/" ? "" : pathname}` || "/";
724
+ return url.toString();
725
+ }
726
+
642
727
  function isLocalWorkspaceGateway(url: URL): boolean {
643
728
  const hostname = url.hostname.replace(/^\[|\]$/g, "").toLowerCase();
644
729
  return (
@@ -649,18 +734,50 @@ function isLocalWorkspaceGateway(url: URL): boolean {
649
734
  );
650
735
  }
651
736
 
652
- function workspaceAppLink(
653
- appPath: string,
654
- explicitUrl?: unknown,
655
- ): string | null {
737
+ function workspaceAppPagePath(appId: string, urlValue?: string): string {
738
+ const route = workspaceAppRoute(appId);
739
+ if (!urlValue) return route;
740
+ const parsed = new URL(urlValue, "https://agent-native.invalid");
741
+ return `${route}${parsed.search}${parsed.hash}`;
742
+ }
743
+
744
+ function workspaceAppLink(appId: string, explicitUrl?: unknown): string {
656
745
  const urlValue = typeof explicitUrl === "string" ? explicitUrl.trim() : "";
657
- if (!urlValue) return workspaceAppUrl(appPath);
658
- if (urlValue.startsWith("/")) return workspaceAppUrl(urlValue) ?? urlValue;
659
- try {
660
- return projectEnvironmentUrl(new URL(urlValue).toString());
661
- } catch {
662
- return urlValue;
746
+ const routePath = workspaceAppPagePath(appId, urlValue || undefined);
747
+ if (!urlValue) {
748
+ return (
749
+ workspaceGatewayAppUrl(routePath) ??
750
+ workspaceAppUrl(routePath) ??
751
+ routePath
752
+ );
663
753
  }
754
+ if (urlValue.startsWith("/")) {
755
+ return (
756
+ workspaceGatewayAppUrl(routePath) ??
757
+ workspaceAppUrl(routePath) ??
758
+ routePath
759
+ );
760
+ }
761
+ const resolved = projectEnvironmentUrl(new URL(urlValue).toString());
762
+ const gateway = workspaceGatewayBaseUrl();
763
+ if (gateway && new URL(resolved).origin === gateway.origin) {
764
+ return (
765
+ workspaceGatewayAppUrl(routePath) ??
766
+ workspaceAppUrl(routePath) ??
767
+ routePath
768
+ );
769
+ }
770
+ const runtimeBase = resolveAppRuntimeUrl();
771
+ if (runtimeBase && new URL(resolved).origin === new URL(runtimeBase).origin) {
772
+ const runtimeUrl = new URL(
773
+ addBasePath(
774
+ projectEnvironmentUrl(runtimeBase),
775
+ getConfiguredAppBasePath(),
776
+ ),
777
+ );
778
+ return appendWorkspaceAppPath(runtimeUrl, routePath);
779
+ }
780
+ return resolved;
664
781
  }
665
782
 
666
783
  function normalizeWorkspaceAppAudience(value: unknown): WorkspaceAppAudience {
@@ -821,7 +938,10 @@ function workspaceAppRouteAccessFromPackageJson(pkg: unknown): {
821
938
  };
822
939
  }
823
940
 
824
- function parseWorkspaceAppsManifest(parsed: any): WorkspaceAppSummary[] | null {
941
+ function parseWorkspaceAppsManifest(
942
+ parsed: any,
943
+ onInvalidAppUrl?: () => void,
944
+ ): WorkspaceAppSummary[] | null {
825
945
  const rawApps = Array.isArray(parsed?.apps)
826
946
  ? parsed.apps
827
947
  : Array.isArray(parsed)
@@ -840,6 +960,18 @@ function parseWorkspaceAppsManifest(parsed: any): WorkspaceAppSummary[] | null {
840
960
  });
841
961
  if (!profile) return null;
842
962
  const metadata = workspaceAppMetadataFromRecord(entry);
963
+ let url: string | null;
964
+ try {
965
+ url = workspaceAppLink(id, entry.url);
966
+ } catch (error) {
967
+ if (error instanceof WorkspaceGatewayConfigurationError) throw error;
968
+ onInvalidAppUrl?.();
969
+ console.warn(
970
+ `[dispatch] Could not resolve Workspace app ${id}; skipping app`,
971
+ error,
972
+ );
973
+ return null;
974
+ }
843
975
  return {
844
976
  id,
845
977
  name:
@@ -851,7 +983,7 @@ function parseWorkspaceAppsManifest(parsed: any): WorkspaceAppSummary[] | null {
851
983
  ...(profile.whenToUse ? { whenToUse: profile.whenToUse } : {}),
852
984
  path: pathValue,
853
985
  homePath: normalizeWorkspaceAppHomePath(entry.homePath),
854
- url: workspaceAppLink(pathValue, entry.url),
986
+ url,
855
987
  isDispatch:
856
988
  typeof entry.isDispatch === "boolean"
857
989
  ? entry.isDispatch
@@ -887,8 +1019,11 @@ function parseWorkspaceAppsGatewayResponse(
887
1019
  : parsed;
888
1020
  if (!Array.isArray(rawApps)) return null;
889
1021
  if (rawApps.length === 0) return [];
890
- const apps = parseWorkspaceAppsManifest(parsed);
891
- if (!apps || apps.length !== rawApps.length) return null;
1022
+ let invalidUrlCount = 0;
1023
+ const apps = parseWorkspaceAppsManifest(parsed, () => {
1024
+ invalidUrlCount += 1;
1025
+ });
1026
+ if (!apps || apps.length + invalidUrlCount !== rawApps.length) return null;
892
1027
  const ids = new Set(apps.map((app) => app.id.toLowerCase()));
893
1028
  return ids.size === apps.length ? apps : null;
894
1029
  }
@@ -1861,28 +1996,25 @@ function readWorkspaceAppsFromEnv(): WorkspaceAppSummary[] | null {
1861
1996
  const raw = process.env[WORKSPACE_APPS_ENV_KEY];
1862
1997
  if (!raw) return null;
1863
1998
  try {
1864
- return parseWorkspaceAppsManifest(JSON.parse(raw));
1865
- } catch {
1866
- return null;
1999
+ const apps = parseWorkspaceAppsManifest(JSON.parse(raw));
2000
+ if (apps) return apps;
2001
+ console.warn(
2002
+ `[dispatch] Could not parse Workspace app manifest from ${WORKSPACE_APPS_ENV_KEY}; skipping source`,
2003
+ );
2004
+ } catch (error) {
2005
+ if (error instanceof WorkspaceGatewayConfigurationError) throw error;
2006
+ console.warn(
2007
+ `[dispatch] Could not read Workspace app manifest from ${WORKSPACE_APPS_ENV_KEY}; skipping source`,
2008
+ );
1867
2009
  }
2010
+ return null;
1868
2011
  }
1869
2012
 
1870
2013
  async function readWorkspaceAppsFromGateway(): Promise<WorkspaceAppDiscovery | null> {
1871
- const configuredBase = process.env.WORKSPACE_GATEWAY_URL;
2014
+ const configuredBase = getAppConfig().workspace.gatewayUrl?.trim();
1872
2015
  if (!configuredBase) return null;
1873
- const base = projectEnvironmentUrl(configuredBase);
1874
-
1875
- let baseUrl: URL;
1876
- try {
1877
- baseUrl = new URL(base);
1878
- } catch {
1879
- // coercion-ok: malformed gateway configuration is an unavailable registry
1880
- // and falls back to local sources.
1881
- return null;
1882
- }
1883
- if (baseUrl.protocol !== "http:" && baseUrl.protocol !== "https:") {
1884
- return null;
1885
- }
2016
+ const baseUrl = workspaceGatewayBaseUrl();
2017
+ if (!baseUrl) return null;
1886
2018
 
1887
2019
  const requestContext = getRequestContext();
1888
2020
  const isLocalGateway = isLocalWorkspaceGateway(baseUrl);
@@ -2123,8 +2255,15 @@ function workspaceAppsManifestCandidates(): string[] {
2123
2255
  function readWorkspaceAppsFromManifestFile(): WorkspaceAppSummary[] | null {
2124
2256
  for (const file of workspaceAppsManifestCandidates()) {
2125
2257
  if (!fs.existsSync(file)) continue;
2126
- const apps = parseWorkspaceAppsManifest(readJson(file));
2127
- if (apps) return apps;
2258
+ try {
2259
+ const apps = parseWorkspaceAppsManifest(readJson(file));
2260
+ if (apps) return apps;
2261
+ } catch (error) {
2262
+ if (error instanceof WorkspaceGatewayConfigurationError) throw error;
2263
+ console.warn(
2264
+ `[dispatch] Could not read Workspace app manifest ${file}; skipping source`,
2265
+ );
2266
+ }
2128
2267
  }
2129
2268
  return null;
2130
2269
  }
@@ -2140,7 +2279,16 @@ async function readWorkspaceAppsFromFilesystem(
2140
2279
  .readdirSync(appsDir, { withFileTypes: true })
2141
2280
  .filter((entry) => entry.isDirectory() && !entry.name.startsWith("."))) {
2142
2281
  const appDir = path.join(appsDir, entry.name);
2143
- const pkg = readJson(path.join(appDir, "package.json"));
2282
+ let pkg: any;
2283
+ try {
2284
+ pkg = readJson(path.join(appDir, "package.json"));
2285
+ } catch (error) {
2286
+ console.warn(
2287
+ `[dispatch] Could not read workspace app ${entry.name}; skipping app`,
2288
+ error,
2289
+ );
2290
+ continue;
2291
+ }
2144
2292
  if (!pkg) continue;
2145
2293
  const routeAccess = workspaceAppRouteAccessFromPackageJson(pkg);
2146
2294
  const metadata = workspaceAppMetadataFromRecord(pkg);
@@ -2166,7 +2314,7 @@ async function readWorkspaceAppsFromFilesystem(
2166
2314
  homePath: normalizeWorkspaceAppHomePath(
2167
2315
  configuredHomePath ?? inferredHomePath,
2168
2316
  ),
2169
- url: workspaceAppUrl(`/${entry.name}`),
2317
+ url: workspaceAppUrl(workspaceAppRoute(entry.name)),
2170
2318
  isDispatch: entry.name === "dispatch",
2171
2319
  audience:
2172
2320
  workspaceAppAudienceFromPackageJson(pkg) ??
@@ -2639,7 +2787,7 @@ export async function scaffoldWorkspaceAppFromTemplate(input: {
2639
2787
  description: "",
2640
2788
  path: `/${appId}`,
2641
2789
  homePath: "/home",
2642
- url: workspaceAppUrl(`/${appId}`),
2790
+ url: workspaceAppUrl(workspaceAppRoute(appId)),
2643
2791
  isDispatch: false,
2644
2792
  audience: DEFAULT_WORKSPACE_APP_AUDIENCE,
2645
2793
  publicPaths: [],
@@ -3000,8 +3148,8 @@ function buildWorkspaceAppPrompt(input: {
3000
3148
  `Dispatch workspace resources selected for this app:\n${resourceList}`,
3001
3149
  `Dispatch workspace resources with scope=all are global. After the app exists, sync workspace resources to appId "${appId}" so global skills, guardrail instructions, and reference resources reach the new app even when no per-app resources were selected.`,
3002
3150
  "",
3003
- `Use the workspace app layout: create it under apps/${appId}, mount it at /${appId}, keep it on the shared workspace database/hosting model, and avoid table-name collisions by namespacing any new domain tables to the app.`,
3004
- `Important routing rule: from outside the app, link to /${appId}; inside apps/${appId}, React Router routes are app-local. Use <Link to="/review"> and navigate("/review"), not "/${appId}/review"; APP_BASE_PATH supplies the mounted prefix, and hardcoding it causes doubled URLs like /${appId}/${appId}/review.`,
3151
+ `Use the workspace app layout: create it under apps/${appId}; Dispatch mounts it at /apps/${appId}. Keep it on the shared workspace database/hosting model, and avoid table-name collisions by namespacing any new domain tables to the app.`,
3152
+ `Important routing rule: from outside the app, link to /apps/${appId}; inside apps/${appId}, React Router routes are app-local. Use <Link to="/review"> and navigate("/review"), not "/apps/${appId}/review"; APP_BASE_PATH supplies the mounted prefix, and hardcoding it causes doubled URLs.`,
3005
3153
  `Home route contract: Dispatch opens the registered app.homePath. If the main screen is app/routes/_index.tsx and there is no app/routes/home.tsx or app/routes/_app.home.tsx, set app.homePath to "/" in server/plugins/config.ts. If the app uses a /home route, keep the default "/home". Never leave the registry pointing at /home when that route does not exist.`,
3006
3154
  "Existing first-party apps are neighbors, not implementation details for this app. If the user prompt mentions Mail, Calendar, Analytics, Dispatch, or other templates, treat them as existing hosted/connected apps that this app can link to or call through A2A/default connected agents. For example, Mail, Calendar, and Analytics already exist at https://mail.agent-native.com, https://calendar.agent-native.com, and https://analytics.agent-native.com.",
3007
3155
  `Do not create wrapper apps or scaffold child apps/routes for Mail, Calendar, Analytics, etc. inside apps/${appId} just so this app can access them. If the request is a cross-app dashboard or overview, build only the new dashboard/overview app and delegate to the existing apps for domain work.`,
@@ -3020,7 +3168,7 @@ function buildWorkspaceAppPrompt(input: {
3020
3168
  "- Use Tabler Icons (@tabler/icons-react) for every icon. Never use emojis as icons.",
3021
3169
  `- Expose what the user is looking at via application_state (navigation.view, selection, etc.) so the agent has live context. Mirror the patterns in templates/mail or templates/slides.`,
3022
3170
  "- Optimistic UI for every mutation: update the React Query cache immediately, navigate immediately, run the mutation in the background, roll back on error. Don't await a server round-trip before re-rendering.",
3023
- `- Commit an agent-native.json at apps/${appId}/agent-native.json with { "version": 1, "onboarding": { "firstRun": { "development": "connect", "production": "connect-and-integrations" } } }. Keep the shared Use Builder.io / Add your own keys onboarding visible; never build a second, custom credential form or hardcode a provider key.`,
3171
+ `- Commit an agent-native.json at apps/${appId}/agent-native.json with { "version": 1, "onboarding": { "firstRun": { "development": "off", "production": "connect-and-integrations" } } }, as the first-party templates do, so local runs open straight into the app. Keep the shared Use Builder.io / Add your own keys onboarding for production; never build a second, custom credential form or hardcode a provider key.`,
3024
3172
  "- Every AI-labeled button must call sendToAgentChat with openSidebar: true — plus submit: true for one-click work, or submit: false when the user should review/edit the proposed prompt first. Keep follow-ups in that same sidebar thread; don't add a second freeform input beside the result. Never use sparkle, wand, magic, robot, or other decorative AI icons on those buttons — a message or neutral action icon, or no icon, instead.",
3025
3173
  "- Choose a named visual direction in DESIGN.md before styling the first screen and build to it. Don't inherit a sibling app's palette unbuilt.",
3026
3174
  '- Left navigation must name real domain destinations, not "Chat" as the only or default entry.',
@@ -3482,7 +3630,7 @@ export async function startWorkspaceAppCreation(input: {
3482
3630
  projectId: builderProjectId,
3483
3631
  branchName: result.branchName,
3484
3632
  url: result.url,
3485
- workspaceUrl: workspaceAppUrl(`/${built.appId}`),
3633
+ workspaceUrl: workspaceAppUrl(workspaceAppRoute(built.appId)),
3486
3634
  status: result.status,
3487
3635
  message:
3488
3636
  `Builder started a branch for /${built.appId}. Use the Builder branch URL to track creation now. ` +
@@ -79,7 +79,7 @@ export const CURATED_COMMUNITY_APP_SOURCES: readonly CuratedCommunityAppSource[]
79
79
  },
80
80
  {
81
81
  path: "actions/generate-qr-code.spec.ts",
82
- blobSha: "3459217b7252c6ee0076c68cfdb83001cc74f29e",
82
+ blobSha: "42a1a84ecb421e1e6435cc2e7fd00e2f4f2e1ea9",
83
83
  },
84
84
  {
85
85
  path: "actions/generate-qr-code.ts",