@agent-native/dispatch 0.31.13 → 0.31.14

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 (47) hide show
  1. package/dist/actions/list-dispatch-usage-metrics.js +9 -1
  2. package/dist/actions/list-dispatch-usage-metrics.js.map +1 -1
  3. package/dist/actions/provider-api-register.d.ts +12 -12
  4. package/dist/components/other-apps-section.d.ts +5 -3
  5. package/dist/components/other-apps-section.d.ts.map +1 -1
  6. package/dist/components/other-apps-section.js +15 -3
  7. package/dist/components/other-apps-section.js.map +1 -1
  8. package/dist/components/workspace-app-host.d.ts +8 -2
  9. package/dist/components/workspace-app-host.d.ts.map +1 -1
  10. package/dist/components/workspace-app-host.js +46 -8
  11. package/dist/components/workspace-app-host.js.map +1 -1
  12. package/dist/lib/workspace-apps.d.ts +7 -0
  13. package/dist/lib/workspace-apps.d.ts.map +1 -1
  14. package/dist/lib/workspace-apps.js +65 -0
  15. package/dist/lib/workspace-apps.js.map +1 -1
  16. package/dist/routes/index.js +1 -1
  17. package/dist/routes/index.js.map +1 -1
  18. package/dist/routes/pages/apps.$appId.d.ts.map +1 -1
  19. package/dist/routes/pages/apps.$appId.js +15 -4
  20. package/dist/routes/pages/apps.$appId.js.map +1 -1
  21. package/dist/routes/pages/apps.d.ts.map +1 -1
  22. package/dist/routes/pages/apps.js +16 -4
  23. package/dist/routes/pages/apps.js.map +1 -1
  24. package/dist/server/lib/usage-metrics-store.d.ts +20 -0
  25. package/dist/server/lib/usage-metrics-store.d.ts.map +1 -1
  26. package/dist/server/lib/usage-metrics-store.js +86 -32
  27. package/dist/server/lib/usage-metrics-store.js.map +1 -1
  28. package/dist/server/plugins/agent-chat.js +3 -0
  29. package/dist/server/plugins/agent-chat.js.map +1 -1
  30. package/package.json +3 -3
  31. package/src/actions/index.spec.ts +17 -0
  32. package/src/actions/list-dispatch-usage-metrics.ts +9 -1
  33. package/src/components/other-apps-section.spec.ts +49 -0
  34. package/src/components/other-apps-section.tsx +31 -6
  35. package/src/components/workspace-app-host.spec.tsx +98 -0
  36. package/src/components/workspace-app-host.tsx +70 -4
  37. package/src/lib/workspace-apps.spec.ts +40 -0
  38. package/src/lib/workspace-apps.ts +80 -0
  39. package/src/routes/index.spec.ts +10 -0
  40. package/src/routes/index.ts +1 -1
  41. package/src/routes/pages/apps.$appId.spec.tsx +50 -1
  42. package/src/routes/pages/apps.$appId.tsx +26 -3
  43. package/src/routes/pages/apps.tsx +42 -26
  44. package/src/server/lib/usage-metrics-store.spec.ts +132 -1
  45. package/src/server/lib/usage-metrics-store.ts +173 -65
  46. package/src/server/plugins/agent-chat.spec.ts +2 -0
  47. package/src/server/plugins/agent-chat.ts +3 -0
@@ -2,7 +2,7 @@ import { defineAction } from "@agent-native/core";
2
2
  import { z } from "zod";
3
3
  import { listDispatchUsageMetrics } from "../server/lib/usage-metrics-store.js";
4
4
  export default defineAction({
5
- description: "Get personal or workspace LLM usage, spend or Builder.io credit spend, app attribution, prompt previews, and recent activity metrics for Dispatch.",
5
+ description: "Get personal or workspace LLM usage, spend or Builder.io credit spend, app attribution, prompt previews, and recent activity metrics for Dispatch. Workspace results also include monthlyByUser credit rows and workspaceAppCreationsByUserMonth rows from the shared token_usage and Dispatch audit tables.",
6
6
  schema: z.object({
7
7
  sinceDays: z.coerce
8
8
  .number()
@@ -23,6 +23,14 @@ export default defineAction({
23
23
  .describe("Optional workspace member email to filter all usage to."),
24
24
  }),
25
25
  http: { method: "GET" },
26
+ readOnly: true,
27
+ parallelSafe: true,
28
+ publicAgent: {
29
+ expose: true,
30
+ readOnly: true,
31
+ requiresAuth: true,
32
+ isConsequential: false,
33
+ },
26
34
  run: async (args) => listDispatchUsageMetrics(args),
27
35
  });
28
36
  //# sourceMappingURL=list-dispatch-usage-metrics.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"list-dispatch-usage-metrics.js","sourceRoot":"","sources":["../../src/actions/list-dispatch-usage-metrics.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,wBAAwB,EAAE,MAAM,sCAAsC,CAAC;AAEhF,eAAe,YAAY,CAAC;IAC1B,WAAW,EACT,oJAAoJ;IACtJ,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC;QACf,SAAS,EAAE,CAAC,CAAC,MAAM;aAChB,MAAM,EAAE;aACR,GAAG,EAAE;aACL,GAAG,CAAC,CAAC,CAAC;aACN,GAAG,CAAC,GAAG,CAAC;aACR,OAAO,CAAC,EAAE,CAAC;aACX,QAAQ,CAAC,0CAA0C,CAAC;QACvD,KAAK,EAAE,CAAC;aACL,IAAI,CAAC,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC;aACzB,OAAO,CAAC,WAAW,CAAC;aACpB,QAAQ,CAAC,yDAAyD,CAAC;QACtE,SAAS,EAAE,CAAC;aACT,MAAM,EAAE;aACR,IAAI,EAAE;aACN,GAAG,CAAC,CAAC,CAAC;aACN,QAAQ,EAAE;aACV,QAAQ,CAAC,yDAAyD,CAAC;KACvE,CAAC;IACF,IAAI,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE;IACvB,GAAG,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE,CAAC,wBAAwB,CAAC,IAAI,CAAC;CACpD,CAAC,CAAC","sourcesContent":["import { defineAction } from \"@agent-native/core\";\nimport { z } from \"zod\";\n\nimport { listDispatchUsageMetrics } from \"../server/lib/usage-metrics-store.js\";\n\nexport default defineAction({\n description:\n \"Get personal or workspace LLM usage, spend or Builder.io credit spend, app attribution, prompt previews, and recent activity metrics for Dispatch.\",\n schema: z.object({\n sinceDays: z.coerce\n .number()\n .int()\n .min(1)\n .max(365)\n .default(30)\n .describe(\"Lookback window in days. Defaults to 30.\"),\n scope: z\n .enum([\"me\", \"workspace\"])\n .default(\"workspace\")\n .describe(\"Whether to inspect your account or the whole workspace.\"),\n userEmail: z\n .string()\n .trim()\n .min(1)\n .optional()\n .describe(\"Optional workspace member email to filter all usage to.\"),\n }),\n http: { method: \"GET\" },\n run: async (args) => listDispatchUsageMetrics(args),\n});\n"]}
1
+ {"version":3,"file":"list-dispatch-usage-metrics.js","sourceRoot":"","sources":["../../src/actions/list-dispatch-usage-metrics.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,wBAAwB,EAAE,MAAM,sCAAsC,CAAC;AAEhF,eAAe,YAAY,CAAC;IAC1B,WAAW,EACT,8SAA8S;IAChT,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC;QACf,SAAS,EAAE,CAAC,CAAC,MAAM;aAChB,MAAM,EAAE;aACR,GAAG,EAAE;aACL,GAAG,CAAC,CAAC,CAAC;aACN,GAAG,CAAC,GAAG,CAAC;aACR,OAAO,CAAC,EAAE,CAAC;aACX,QAAQ,CAAC,0CAA0C,CAAC;QACvD,KAAK,EAAE,CAAC;aACL,IAAI,CAAC,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC;aACzB,OAAO,CAAC,WAAW,CAAC;aACpB,QAAQ,CAAC,yDAAyD,CAAC;QACtE,SAAS,EAAE,CAAC;aACT,MAAM,EAAE;aACR,IAAI,EAAE;aACN,GAAG,CAAC,CAAC,CAAC;aACN,QAAQ,EAAE;aACV,QAAQ,CAAC,yDAAyD,CAAC;KACvE,CAAC;IACF,IAAI,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE;IACvB,QAAQ,EAAE,IAAI;IACd,YAAY,EAAE,IAAI;IAClB,WAAW,EAAE;QACX,MAAM,EAAE,IAAI;QACZ,QAAQ,EAAE,IAAI;QACd,YAAY,EAAE,IAAI;QAClB,eAAe,EAAE,KAAK;KACvB;IACD,GAAG,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE,CAAC,wBAAwB,CAAC,IAAI,CAAC;CACpD,CAAC,CAAC","sourcesContent":["import { defineAction } from \"@agent-native/core\";\nimport { z } from \"zod\";\n\nimport { listDispatchUsageMetrics } from \"../server/lib/usage-metrics-store.js\";\n\nexport default defineAction({\n description:\n \"Get personal or workspace LLM usage, spend or Builder.io credit spend, app attribution, prompt previews, and recent activity metrics for Dispatch. Workspace results also include monthlyByUser credit rows and workspaceAppCreationsByUserMonth rows from the shared token_usage and Dispatch audit tables.\",\n schema: z.object({\n sinceDays: z.coerce\n .number()\n .int()\n .min(1)\n .max(365)\n .default(30)\n .describe(\"Lookback window in days. Defaults to 30.\"),\n scope: z\n .enum([\"me\", \"workspace\"])\n .default(\"workspace\")\n .describe(\"Whether to inspect your account or the whole workspace.\"),\n userEmail: z\n .string()\n .trim()\n .min(1)\n .optional()\n .describe(\"Optional workspace member email to filter all usage to.\"),\n }),\n http: { method: \"GET\" },\n readOnly: true,\n parallelSafe: true,\n publicAgent: {\n expose: true,\n readOnly: true,\n requiresAuth: true,\n isConsequential: false,\n },\n run: async (args) => listDispatchUsageMetrics(args),\n});\n"]}
@@ -47,9 +47,9 @@ declare const _default: import("node_modules/@agent-native/core/dist").ActionDef
47
47
  notes?: string | undefined;
48
48
  scope?: "org" | "user" | undefined;
49
49
  }, {
50
- deleted?: undefined;
51
- found?: undefined;
52
50
  id?: undefined;
51
+ provider?: undefined;
52
+ deleted?: undefined;
53
53
  providers: {
54
54
  id: string;
55
55
  label: string;
@@ -60,46 +60,46 @@ declare const _default: import("node_modules/@agent-native/core/dist").ActionDef
60
60
  updatedAt: number;
61
61
  }[];
62
62
  count: number;
63
- provider?: undefined;
63
+ found?: undefined;
64
64
  registered?: undefined;
65
65
  label?: undefined;
66
66
  message?: undefined;
67
67
  } | {
68
- deleted?: undefined;
69
68
  id?: undefined;
70
- providers?: undefined;
71
69
  count?: undefined;
70
+ deleted?: undefined;
71
+ providers?: undefined;
72
72
  found: boolean;
73
73
  provider: import("node_modules/@agent-native/core/dist/provider-api").CustomProviderConfig;
74
74
  registered?: undefined;
75
75
  label?: undefined;
76
76
  message?: undefined;
77
77
  } | {
78
- deleted?: undefined;
79
- providers?: undefined;
80
78
  count?: undefined;
81
79
  provider?: undefined;
80
+ deleted?: undefined;
81
+ providers?: undefined;
82
82
  found: boolean;
83
83
  id: string;
84
84
  registered?: undefined;
85
85
  label?: undefined;
86
86
  message?: undefined;
87
87
  } | {
88
- found?: undefined;
89
- providers?: undefined;
90
88
  count?: undefined;
91
89
  provider?: undefined;
90
+ providers?: undefined;
91
+ found?: undefined;
92
92
  deleted: boolean;
93
93
  id: string;
94
94
  registered?: undefined;
95
95
  label?: undefined;
96
96
  message?: undefined;
97
97
  } | {
98
- deleted?: undefined;
99
- found?: undefined;
100
- providers?: undefined;
101
98
  count?: undefined;
102
99
  provider?: undefined;
100
+ deleted?: undefined;
101
+ providers?: undefined;
102
+ found?: undefined;
103
103
  registered: boolean;
104
104
  id: string;
105
105
  label: string;
@@ -1,19 +1,21 @@
1
1
  import { type ConnectedAppSummary } from "../lib/other-apps.js";
2
2
  import type { WorkspaceAppId } from "../lib/other-apps.js";
3
3
  import { type CuratedWorkspaceTemplate, type CuratedWorkspaceTemplatesResult, type WorkspaceTemplateLabels } from "./workspace-template-card.js";
4
- type OtherAppEntry = {
4
+ export type OtherAppEntry = {
5
5
  kind: "template";
6
6
  template: CuratedWorkspaceTemplate;
7
7
  } | {
8
8
  kind: "connected";
9
9
  app: ConnectedAppSummary;
10
10
  };
11
+ export declare function otherAppEntryMatchesQuery(entry: OtherAppEntry, query: string): boolean;
12
+ export declare function filterOtherAppEntries(entries: OtherAppEntry[], query: string): OtherAppEntry[];
11
13
  export declare function mergeOtherAppEntries({ templates, connectedApps, workspaceApps, }: {
12
14
  templates?: CuratedWorkspaceTemplatesResult;
13
15
  connectedApps: ConnectedAppSummary[];
14
16
  workspaceApps: WorkspaceAppId[];
15
17
  }): OtherAppEntry[];
16
- export declare function OtherAppsSection({ templates, connectedApps, workspaceApps, templatesLoading, connectedAppsLoading, templatesError, connectedAppsError, onRetryTemplates, onRetryConnectedApps, templateLabels, onRemixSuccess, heading, embeddedInList, className, }: {
18
+ export declare function OtherAppsSection({ templates, connectedApps, workspaceApps, templatesLoading, connectedAppsLoading, templatesError, connectedAppsError, onRetryTemplates, onRetryConnectedApps, templateLabels, onRemixSuccess, query, heading, embeddedInList, className, }: {
17
19
  templates?: CuratedWorkspaceTemplatesResult;
18
20
  connectedApps?: ConnectedAppSummary[];
19
21
  workspaceApps: WorkspaceAppId[];
@@ -25,9 +27,9 @@ export declare function OtherAppsSection({ templates, connectedApps, workspaceAp
25
27
  onRetryConnectedApps?: () => void;
26
28
  templateLabels?: Partial<WorkspaceTemplateLabels>;
27
29
  onRemixSuccess?: (result: unknown, template: CuratedWorkspaceTemplate) => void;
30
+ query?: string;
28
31
  heading?: string | null;
29
32
  embeddedInList?: boolean;
30
33
  className?: string;
31
34
  }): import("node_modules/@types/react").JSX.Element | null;
32
- export {};
33
35
  //# sourceMappingURL=other-apps-section.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"other-apps-section.d.ts","sourceRoot":"","sources":["../../src/components/other-apps-section.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAmB,KAAK,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAC9E,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAWxD,OAAO,EAEL,KAAK,wBAAwB,EAC7B,KAAK,+BAA+B,EACpC,KAAK,uBAAuB,EAC7B,MAAM,2BAA2B,CAAC;AAEnC,KAAK,aAAa,GACd;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,QAAQ,EAAE,wBAAwB,CAAA;CAAE,GACxD;IAAE,IAAI,EAAE,WAAW,CAAC;IAAC,GAAG,EAAE,mBAAmB,CAAA;CAAE,CAAC;AAepD,wBAAgB,oBAAoB,CAAC,EACnC,SAAS,EACT,aAAa,EACb,aAAa,GACd,EAAE;IACD,SAAS,CAAC,EAAE,+BAA+B,CAAC;IAC5C,aAAa,EAAE,mBAAmB,EAAE,CAAC;IACrC,aAAa,EAAE,cAAc,EAAE,CAAC;CACjC,GAAG,aAAa,EAAE,CA4BlB;AAED,wBAAgB,gBAAgB,CAAC,EAC/B,SAAS,EACT,aAAkB,EAClB,aAAa,EACb,gBAAwB,EACxB,oBAA4B,EAC5B,cAAc,EACd,kBAAkB,EAClB,gBAAgB,EAChB,oBAAoB,EACpB,cAAc,EACd,cAAc,EACd,OAAsB,EACtB,cAAsB,EACtB,SAAS,GACV,EAAE;IACD,SAAS,CAAC,EAAE,+BAA+B,CAAC;IAC5C,aAAa,CAAC,EAAE,mBAAmB,EAAE,CAAC;IACtC,aAAa,EAAE,cAAc,EAAE,CAAC;IAChC,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,cAAc,CAAC,EAAE,KAAK,GAAG,IAAI,CAAC;IAC9B,kBAAkB,CAAC,EAAE,KAAK,GAAG,IAAI,CAAC;IAClC,gBAAgB,CAAC,EAAE,MAAM,IAAI,CAAC;IAC9B,oBAAoB,CAAC,EAAE,MAAM,IAAI,CAAC;IAClC,cAAc,CAAC,EAAE,OAAO,CAAC,uBAAuB,CAAC,CAAC;IAClD,cAAc,CAAC,EAAE,CACf,MAAM,EAAE,OAAO,EACf,QAAQ,EAAE,wBAAwB,KAC/B,IAAI,CAAC;IACV,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,0DAyEA"}
1
+ {"version":3,"file":"other-apps-section.d.ts","sourceRoot":"","sources":["../../src/components/other-apps-section.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAmB,KAAK,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAC9E,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAWxD,OAAO,EAEL,KAAK,wBAAwB,EAC7B,KAAK,+BAA+B,EACpC,KAAK,uBAAuB,EAC7B,MAAM,2BAA2B,CAAC;AAEnC,MAAM,MAAM,aAAa,GACrB;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,QAAQ,EAAE,wBAAwB,CAAA;CAAE,GACxD;IAAE,IAAI,EAAE,WAAW,CAAC;IAAC,GAAG,EAAE,mBAAmB,CAAA;CAAE,CAAC;AAepD,wBAAgB,yBAAyB,CACvC,KAAK,EAAE,aAAa,EACpB,KAAK,EAAE,MAAM,GACZ,OAAO,CAQT;AAED,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,aAAa,EAAE,EACxB,KAAK,EAAE,MAAM,GACZ,aAAa,EAAE,CAEjB;AAED,wBAAgB,oBAAoB,CAAC,EACnC,SAAS,EACT,aAAa,EACb,aAAa,GACd,EAAE;IACD,SAAS,CAAC,EAAE,+BAA+B,CAAC;IAC5C,aAAa,EAAE,mBAAmB,EAAE,CAAC;IACrC,aAAa,EAAE,cAAc,EAAE,CAAC;CACjC,GAAG,aAAa,EAAE,CA4BlB;AAED,wBAAgB,gBAAgB,CAAC,EAC/B,SAAS,EACT,aAAkB,EAClB,aAAa,EACb,gBAAwB,EACxB,oBAA4B,EAC5B,cAAc,EACd,kBAAkB,EAClB,gBAAgB,EAChB,oBAAoB,EACpB,cAAc,EACd,cAAc,EACd,KAAU,EACV,OAAsB,EACtB,cAAsB,EACtB,SAAS,GACV,EAAE;IACD,SAAS,CAAC,EAAE,+BAA+B,CAAC;IAC5C,aAAa,CAAC,EAAE,mBAAmB,EAAE,CAAC;IACtC,aAAa,EAAE,cAAc,EAAE,CAAC;IAChC,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,cAAc,CAAC,EAAE,KAAK,GAAG,IAAI,CAAC;IAC9B,kBAAkB,CAAC,EAAE,KAAK,GAAG,IAAI,CAAC;IAClC,gBAAgB,CAAC,EAAE,MAAM,IAAI,CAAC;IAC9B,oBAAoB,CAAC,EAAE,MAAM,IAAI,CAAC;IAClC,cAAc,CAAC,EAAE,OAAO,CAAC,uBAAuB,CAAC,CAAC;IAClD,cAAc,CAAC,EAAE,CACf,MAAM,EAAE,OAAO,EACf,QAAQ,EAAE,wBAAwB,KAC/B,IAAI,CAAC;IACV,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,0DA4EA"}
@@ -18,6 +18,18 @@ function getTemplateItems(result) {
18
18
  return [];
19
19
  return Array.isArray(result) ? result : result.templates;
20
20
  }
21
+ export function otherAppEntryMatchesQuery(entry, query) {
22
+ const normalizedQuery = query.trim().toLowerCase();
23
+ if (!normalizedQuery)
24
+ return true;
25
+ const searchable = entry.kind === "template"
26
+ ? `${entry.template.name} ${entry.template.description ?? ""}`
27
+ : `${entry.app.name} ${entry.app.description ?? ""}`;
28
+ return searchable.toLowerCase().includes(normalizedQuery);
29
+ }
30
+ export function filterOtherAppEntries(entries, query) {
31
+ return entries.filter((entry) => otherAppEntryMatchesQuery(entry, query));
32
+ }
21
33
  export function mergeOtherAppEntries({ templates, connectedApps, workspaceApps, }) {
22
34
  const workspaceAppIds = new Set(workspaceApps.map((app) => app.id.trim().toLowerCase()));
23
35
  const seen = new Set();
@@ -41,13 +53,13 @@ export function mergeOtherAppEntries({ templates, connectedApps, workspaceApps,
41
53
  }
42
54
  return entries;
43
55
  }
44
- export function OtherAppsSection({ templates, connectedApps = [], workspaceApps, templatesLoading = false, connectedAppsLoading = false, templatesError, connectedAppsError, onRetryTemplates, onRetryConnectedApps, templateLabels, onRemixSuccess, heading = "Other apps", embeddedInList = false, className, }) {
56
+ export function OtherAppsSection({ templates, connectedApps = [], workspaceApps, templatesLoading = false, connectedAppsLoading = false, templatesError, connectedAppsError, onRetryTemplates, onRetryConnectedApps, templateLabels, onRemixSuccess, query = "", heading = "Other apps", embeddedInList = false, className, }) {
45
57
  const t = useT();
46
- const entries = mergeOtherAppEntries({
58
+ const entries = filterOtherAppEntries(mergeOtherAppEntries({
47
59
  templates,
48
60
  connectedApps,
49
61
  workspaceApps,
50
- });
62
+ }), query);
51
63
  const isLoading = templatesLoading || connectedAppsLoading;
52
64
  const hasError = Boolean(templatesError || connectedAppsError);
53
65
  if (!isLoading && !hasError && entries.length === 0)
@@ -1 +1 @@
1
- {"version":3,"file":"other-apps-section.js","sourceRoot":"","sources":["../../src/components/other-apps-section.tsx"],"names":[],"mappings":"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","sourcesContent":["import { useT } from \"@agent-native/core/client/i18n\";\n\nimport { filterOtherApps, type ConnectedAppSummary } from \"../lib/other-apps\";\nimport type { WorkspaceAppId } from \"../lib/other-apps\";\nimport { cn } from \"../lib/utils\";\nimport { isDefaultWorkspaceAppHiddenId } from \"../lib/workspace-apps\";\nimport { ActionQueryError } from \"./action-query-error\";\nimport {\n APP_LIST_GRID_CLASS,\n APP_LIST_GRID_ROW_CLASS,\n AppList,\n} from \"./app-list-row\";\nimport { ConnectedAppCard } from \"./connected-app-card\";\nimport { Skeleton } from \"./ui/skeleton\";\nimport {\n WorkspaceTemplateCard,\n type CuratedWorkspaceTemplate,\n type CuratedWorkspaceTemplatesResult,\n type WorkspaceTemplateLabels,\n} from \"./workspace-template-card\";\n\ntype OtherAppEntry =\n | { kind: \"template\"; template: CuratedWorkspaceTemplate }\n | { kind: \"connected\"; app: ConnectedAppSummary };\n\nfunction templateKey(template: CuratedWorkspaceTemplate): string {\n return (template.templateId || template.id || template.appId || template.name)\n .trim()\n .toLowerCase();\n}\n\nfunction getTemplateItems(\n result: CuratedWorkspaceTemplatesResult | undefined,\n): CuratedWorkspaceTemplate[] {\n if (!result) return [];\n return Array.isArray(result) ? result : result.templates;\n}\n\nexport function mergeOtherAppEntries({\n templates,\n connectedApps,\n workspaceApps,\n}: {\n templates?: CuratedWorkspaceTemplatesResult;\n connectedApps: ConnectedAppSummary[];\n workspaceApps: WorkspaceAppId[];\n}): OtherAppEntry[] {\n const workspaceAppIds = new Set(\n workspaceApps.map((app) => app.id.trim().toLowerCase()),\n );\n const seen = new Set<string>();\n const entries: OtherAppEntry[] = [];\n\n for (const template of getTemplateItems(templates)) {\n const id = templateKey(template);\n if (\n !id ||\n isDefaultWorkspaceAppHiddenId(id) ||\n template.installed ||\n workspaceAppIds.has(id)\n )\n continue;\n seen.add(id);\n entries.push({ kind: \"template\", template });\n }\n\n for (const app of filterOtherApps(connectedApps, workspaceApps)) {\n const id = app.id.trim().toLowerCase();\n if (seen.has(id)) continue;\n seen.add(id);\n entries.push({ kind: \"connected\", app });\n }\n\n return entries;\n}\n\nexport function OtherAppsSection({\n templates,\n connectedApps = [],\n workspaceApps,\n templatesLoading = false,\n connectedAppsLoading = false,\n templatesError,\n connectedAppsError,\n onRetryTemplates,\n onRetryConnectedApps,\n templateLabels,\n onRemixSuccess,\n heading = \"Other apps\",\n embeddedInList = false,\n className,\n}: {\n templates?: CuratedWorkspaceTemplatesResult;\n connectedApps?: ConnectedAppSummary[];\n workspaceApps: WorkspaceAppId[];\n templatesLoading?: boolean;\n connectedAppsLoading?: boolean;\n templatesError?: Error | null;\n connectedAppsError?: Error | null;\n onRetryTemplates?: () => void;\n onRetryConnectedApps?: () => void;\n templateLabels?: Partial<WorkspaceTemplateLabels>;\n onRemixSuccess?: (\n result: unknown,\n template: CuratedWorkspaceTemplate,\n ) => void;\n heading?: string | null;\n embeddedInList?: boolean;\n className?: string;\n}) {\n const t = useT();\n const entries = mergeOtherAppEntries({\n templates,\n connectedApps,\n workspaceApps,\n });\n const isLoading = templatesLoading || connectedAppsLoading;\n const hasError = Boolean(templatesError || connectedAppsError);\n\n if (!isLoading && !hasError && entries.length === 0) return null;\n\n const entryCards = entries.map((entry) =>\n entry.kind === \"template\" ? (\n <WorkspaceTemplateCard\n key={`template:${templateKey(entry.template)}`}\n template={entry.template}\n labels={templateLabels}\n catalog\n className={APP_LIST_GRID_ROW_CLASS}\n onRemixSuccess={onRemixSuccess}\n />\n ) : (\n <ConnectedAppCard\n key={`connected:${entry.app.id}`}\n app={entry.app}\n className={APP_LIST_GRID_ROW_CLASS}\n />\n ),\n );\n\n const content = (\n <>\n {heading ? (\n <div className=\"flex min-w-0 items-center\">\n <h2 className=\"truncate text-sm font-semibold text-foreground\">\n {t(\"dispatch.pages.otherApps\", { defaultValue: heading })}\n </h2>\n </div>\n ) : null}\n\n {templatesError ? (\n <ActionQueryError\n error={templatesError}\n onRetry={() => onRetryTemplates?.()}\n />\n ) : null}\n {connectedAppsError ? (\n <ActionQueryError\n error={connectedAppsError}\n onRetry={() => onRetryConnectedApps?.()}\n />\n ) : null}\n\n {isLoading && entries.length === 0 ? (\n embeddedInList ? (\n <OtherAppsSkeletonRows />\n ) : (\n <OtherAppsSkeletonList />\n )\n ) : entries.length > 0 ? (\n embeddedInList ? (\n entryCards\n ) : (\n <AppList className={APP_LIST_GRID_CLASS}>{entryCards}</AppList>\n )\n ) : null}\n </>\n );\n\n if (embeddedInList) return content;\n\n return <section className={cn(\"space-y-3\", className)}>{content}</section>;\n}\n\nfunction OtherAppsSkeletonList() {\n return (\n <AppList className={APP_LIST_GRID_CLASS}>\n {Array.from({ length: 4 }).map((_, index) => (\n <div\n key={index}\n className={cn(\n \"flex min-w-0 items-center gap-3 border-b px-4 py-3.5 last:border-b-0\",\n APP_LIST_GRID_ROW_CLASS,\n )}\n >\n <Skeleton className=\"size-8 shrink-0 rounded-xl\" />\n <div className=\"min-w-0 flex-1 space-y-2\">\n <Skeleton className=\"h-4 w-32\" />\n <Skeleton className=\"h-3 w-2/3\" />\n </div>\n <Skeleton className=\"h-9 w-24 shrink-0 rounded-md\" />\n </div>\n ))}\n </AppList>\n );\n}\n\nfunction OtherAppsSkeletonRows() {\n return (\n <>\n {Array.from({ length: 4 }).map((_, index) => (\n <div\n key={index}\n className={cn(\n \"flex min-w-0 items-center gap-3 border-b px-4 py-3.5 last:border-b-0\",\n APP_LIST_GRID_ROW_CLASS,\n )}\n >\n <Skeleton className=\"size-8 shrink-0 rounded-xl\" />\n <div className=\"min-w-0 flex-1 space-y-2\">\n <Skeleton className=\"h-4 w-32\" />\n <Skeleton className=\"h-3 w-2/3\" />\n </div>\n <Skeleton className=\"h-9 w-24 shrink-0 rounded-md\" />\n </div>\n ))}\n </>\n );\n}\n"]}
1
+ {"version":3,"file":"other-apps-section.js","sourceRoot":"","sources":["../../src/components/other-apps-section.tsx"],"names":[],"mappings":"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","sourcesContent":["import { useT } from \"@agent-native/core/client/i18n\";\n\nimport { filterOtherApps, type ConnectedAppSummary } from \"../lib/other-apps\";\nimport type { WorkspaceAppId } from \"../lib/other-apps\";\nimport { cn } from \"../lib/utils\";\nimport { isDefaultWorkspaceAppHiddenId } from \"../lib/workspace-apps\";\nimport { ActionQueryError } from \"./action-query-error\";\nimport {\n APP_LIST_GRID_CLASS,\n APP_LIST_GRID_ROW_CLASS,\n AppList,\n} from \"./app-list-row\";\nimport { ConnectedAppCard } from \"./connected-app-card\";\nimport { Skeleton } from \"./ui/skeleton\";\nimport {\n WorkspaceTemplateCard,\n type CuratedWorkspaceTemplate,\n type CuratedWorkspaceTemplatesResult,\n type WorkspaceTemplateLabels,\n} from \"./workspace-template-card\";\n\nexport type OtherAppEntry =\n | { kind: \"template\"; template: CuratedWorkspaceTemplate }\n | { kind: \"connected\"; app: ConnectedAppSummary };\n\nfunction templateKey(template: CuratedWorkspaceTemplate): string {\n return (template.templateId || template.id || template.appId || template.name)\n .trim()\n .toLowerCase();\n}\n\nfunction getTemplateItems(\n result: CuratedWorkspaceTemplatesResult | undefined,\n): CuratedWorkspaceTemplate[] {\n if (!result) return [];\n return Array.isArray(result) ? result : result.templates;\n}\n\nexport function otherAppEntryMatchesQuery(\n entry: OtherAppEntry,\n query: string,\n): boolean {\n const normalizedQuery = query.trim().toLowerCase();\n if (!normalizedQuery) return true;\n const searchable =\n entry.kind === \"template\"\n ? `${entry.template.name} ${entry.template.description ?? \"\"}`\n : `${entry.app.name} ${entry.app.description ?? \"\"}`;\n return searchable.toLowerCase().includes(normalizedQuery);\n}\n\nexport function filterOtherAppEntries(\n entries: OtherAppEntry[],\n query: string,\n): OtherAppEntry[] {\n return entries.filter((entry) => otherAppEntryMatchesQuery(entry, query));\n}\n\nexport function mergeOtherAppEntries({\n templates,\n connectedApps,\n workspaceApps,\n}: {\n templates?: CuratedWorkspaceTemplatesResult;\n connectedApps: ConnectedAppSummary[];\n workspaceApps: WorkspaceAppId[];\n}): OtherAppEntry[] {\n const workspaceAppIds = new Set(\n workspaceApps.map((app) => app.id.trim().toLowerCase()),\n );\n const seen = new Set<string>();\n const entries: OtherAppEntry[] = [];\n\n for (const template of getTemplateItems(templates)) {\n const id = templateKey(template);\n if (\n !id ||\n isDefaultWorkspaceAppHiddenId(id) ||\n template.installed ||\n workspaceAppIds.has(id)\n )\n continue;\n seen.add(id);\n entries.push({ kind: \"template\", template });\n }\n\n for (const app of filterOtherApps(connectedApps, workspaceApps)) {\n const id = app.id.trim().toLowerCase();\n if (seen.has(id)) continue;\n seen.add(id);\n entries.push({ kind: \"connected\", app });\n }\n\n return entries;\n}\n\nexport function OtherAppsSection({\n templates,\n connectedApps = [],\n workspaceApps,\n templatesLoading = false,\n connectedAppsLoading = false,\n templatesError,\n connectedAppsError,\n onRetryTemplates,\n onRetryConnectedApps,\n templateLabels,\n onRemixSuccess,\n query = \"\",\n heading = \"Other apps\",\n embeddedInList = false,\n className,\n}: {\n templates?: CuratedWorkspaceTemplatesResult;\n connectedApps?: ConnectedAppSummary[];\n workspaceApps: WorkspaceAppId[];\n templatesLoading?: boolean;\n connectedAppsLoading?: boolean;\n templatesError?: Error | null;\n connectedAppsError?: Error | null;\n onRetryTemplates?: () => void;\n onRetryConnectedApps?: () => void;\n templateLabels?: Partial<WorkspaceTemplateLabels>;\n onRemixSuccess?: (\n result: unknown,\n template: CuratedWorkspaceTemplate,\n ) => void;\n query?: string;\n heading?: string | null;\n embeddedInList?: boolean;\n className?: string;\n}) {\n const t = useT();\n const entries = filterOtherAppEntries(\n mergeOtherAppEntries({\n templates,\n connectedApps,\n workspaceApps,\n }),\n query,\n );\n const isLoading = templatesLoading || connectedAppsLoading;\n const hasError = Boolean(templatesError || connectedAppsError);\n\n if (!isLoading && !hasError && entries.length === 0) return null;\n\n const entryCards = entries.map((entry) =>\n entry.kind === \"template\" ? (\n <WorkspaceTemplateCard\n key={`template:${templateKey(entry.template)}`}\n template={entry.template}\n labels={templateLabels}\n catalog\n className={APP_LIST_GRID_ROW_CLASS}\n onRemixSuccess={onRemixSuccess}\n />\n ) : (\n <ConnectedAppCard\n key={`connected:${entry.app.id}`}\n app={entry.app}\n className={APP_LIST_GRID_ROW_CLASS}\n />\n ),\n );\n\n const content = (\n <>\n {heading ? (\n <div className=\"flex min-w-0 items-center\">\n <h2 className=\"truncate text-sm font-semibold text-foreground\">\n {t(\"dispatch.pages.otherApps\", { defaultValue: heading })}\n </h2>\n </div>\n ) : null}\n\n {templatesError ? (\n <ActionQueryError\n error={templatesError}\n onRetry={() => onRetryTemplates?.()}\n />\n ) : null}\n {connectedAppsError ? (\n <ActionQueryError\n error={connectedAppsError}\n onRetry={() => onRetryConnectedApps?.()}\n />\n ) : null}\n\n {isLoading && entries.length === 0 ? (\n embeddedInList ? (\n <OtherAppsSkeletonRows />\n ) : (\n <OtherAppsSkeletonList />\n )\n ) : entries.length > 0 ? (\n embeddedInList ? (\n entryCards\n ) : (\n <AppList className={APP_LIST_GRID_CLASS}>{entryCards}</AppList>\n )\n ) : null}\n </>\n );\n\n if (embeddedInList) return content;\n\n return <section className={cn(\"space-y-3\", className)}>{content}</section>;\n}\n\nfunction OtherAppsSkeletonList() {\n return (\n <AppList className={APP_LIST_GRID_CLASS}>\n {Array.from({ length: 4 }).map((_, index) => (\n <div\n key={index}\n className={cn(\n \"flex min-w-0 items-center gap-3 border-b px-4 py-3.5 last:border-b-0\",\n APP_LIST_GRID_ROW_CLASS,\n )}\n >\n <Skeleton className=\"size-8 shrink-0 rounded-xl\" />\n <div className=\"min-w-0 flex-1 space-y-2\">\n <Skeleton className=\"h-4 w-32\" />\n <Skeleton className=\"h-3 w-2/3\" />\n </div>\n <Skeleton className=\"h-9 w-24 shrink-0 rounded-md\" />\n </div>\n ))}\n </AppList>\n );\n}\n\nfunction OtherAppsSkeletonRows() {\n return (\n <>\n {Array.from({ length: 4 }).map((_, index) => (\n <div\n key={index}\n className={cn(\n \"flex min-w-0 items-center gap-3 border-b px-4 py-3.5 last:border-b-0\",\n APP_LIST_GRID_ROW_CLASS,\n )}\n >\n <Skeleton className=\"size-8 shrink-0 rounded-xl\" />\n <div className=\"min-w-0 flex-1 space-y-2\">\n <Skeleton className=\"h-4 w-32\" />\n <Skeleton className=\"h-3 w-2/3\" />\n </div>\n <Skeleton className=\"h-9 w-24 shrink-0 rounded-md\" />\n </div>\n ))}\n </>\n );\n}\n"]}
@@ -34,14 +34,20 @@ interface WorkspaceAppFrameProps {
34
34
  navigateToTopWindow?: (href: string) => boolean | void;
35
35
  /** Chat-first app tabs use their own route while standalone hosts use app metadata. */
36
36
  embedPath?: string;
37
+ /** Standalone Dispatch routes seed the iframe once from their initial suffix. */
38
+ initialPath?: string;
39
+ /** Standalone Dispatch hosts mirror child route changes into the shell URL. */
40
+ onChildRouteChange?: (path: string) => void;
37
41
  /** Chat-first app surfaces own the parent chat rail around the iframe. */
38
42
  chatSidebar?: boolean;
39
43
  copy?: ChatFirstCopy;
40
44
  }
41
- export declare function WorkspaceAppFrame({ app, navigateToTopWindow, embedPath, chatSidebar, copy, }: WorkspaceAppFrameProps): import("node_modules/@types/react").JSX.Element;
42
- export declare function WorkspaceAppHost({ appId, navigateToTopWindow, }: {
45
+ export declare function WorkspaceAppFrame({ app, navigateToTopWindow, embedPath, initialPath, onChildRouteChange, chatSidebar, copy, }: WorkspaceAppFrameProps): import("node_modules/@types/react").JSX.Element;
46
+ export declare function WorkspaceAppHost({ appId, navigateToTopWindow, initialPath, onChildRouteChange, }: {
43
47
  appId?: string;
44
48
  navigateToTopWindow?: (href: string) => boolean | void;
49
+ initialPath?: string;
50
+ onChildRouteChange?: (path: string) => void;
45
51
  }): import("node_modules/@types/react").JSX.Element;
46
52
  export declare function WorkspaceAppKeepAlive({ activeAppId, }: {
47
53
  activeAppId: string | null;
@@ -1 +1 @@
1
- {"version":3,"file":"workspace-app-host.d.ts","sourceRoot":"","sources":["../../src/components/workspace-app-host.tsx"],"names":[],"mappings":"AAEA,OAAO,EAGL,KAAK,aAAa,EACnB,MAAM,sCAAsC,CAAC;AAc9C,OAAO,EAML,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AA0Bf,UAAU,iBAAiB;IACzB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,SAAS,CAAC;CACnB;AAqBD,wBAAgB,+BAA+B,CAC7C,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,MAAM,GACX,iBAAiB,CAEnB;AAkED,MAAM,WAAW,yBAAyB;IACxC,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,SAAS,CAAC;IACpB,IAAI,CAAC,EAAE,aAAa,CAAC;IACrB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,mBAAmB,CAAC,EAAE,MAAM,IAAI,CAAC;CAClC;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,EACnC,KAAK,EACL,OAAO,EACP,QAAQ,EACR,IAA2B,EAC3B,aAAa,EACb,mBAAmB,GACpB,EAAE,yBAAyB,mDAkE3B;AAED,MAAM,WAAW,oBAAoB;IACnC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACrB;AAED,UAAU,sBAAsB;IAC9B,GAAG,EAAE,oBAAoB,CAAC;IAC1B,mBAAmB,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,GAAG,IAAI,CAAC;IACvD,uFAAuF;IACvF,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,0EAA0E;IAC1E,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,IAAI,CAAC,EAAE,aAAa,CAAC;CACtB;AAED,wBAAgB,iBAAiB,CAAC,EAChC,GAAG,EACH,mBAA4C,EAC5C,SAAS,EACT,WAAmB,EACnB,IAA2B,GAC5B,EAAE,sBAAsB,mDAuPxB;AAED,wBAAgB,gBAAgB,CAAC,EAC/B,KAAK,EACL,mBAA4C,GAC7C,EAAE;IACD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,mBAAmB,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,GAAG,IAAI,CAAC;CACxD,mDA6LA;AAID,wBAAgB,qBAAqB,CAAC,EACpC,WAAW,GACZ,EAAE;IACD,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B,mDAwCA"}
1
+ {"version":3,"file":"workspace-app-host.d.ts","sourceRoot":"","sources":["../../src/components/workspace-app-host.tsx"],"names":[],"mappings":"AAEA,OAAO,EAGL,KAAK,aAAa,EACnB,MAAM,sCAAsC,CAAC;AAe9C,OAAO,EAML,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AA2Bf,UAAU,iBAAiB;IACzB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,SAAS,CAAC;CACnB;AAqBD,wBAAgB,+BAA+B,CAC7C,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,MAAM,GACX,iBAAiB,CAEnB;AAkED,MAAM,WAAW,yBAAyB;IACxC,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,SAAS,CAAC;IACpB,IAAI,CAAC,EAAE,aAAa,CAAC;IACrB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,mBAAmB,CAAC,EAAE,MAAM,IAAI,CAAC;CAClC;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,EACnC,KAAK,EACL,OAAO,EACP,QAAQ,EACR,IAA2B,EAC3B,aAAa,EACb,mBAAmB,GACpB,EAAE,yBAAyB,mDAkE3B;AAED,MAAM,WAAW,oBAAoB;IACnC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACrB;AAED,UAAU,sBAAsB;IAC9B,GAAG,EAAE,oBAAoB,CAAC;IAC1B,mBAAmB,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,GAAG,IAAI,CAAC;IACvD,uFAAuF;IACvF,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,iFAAiF;IACjF,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,+EAA+E;IAC/E,kBAAkB,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAC5C,0EAA0E;IAC1E,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,IAAI,CAAC,EAAE,aAAa,CAAC;CACtB;AAED,wBAAgB,iBAAiB,CAAC,EAChC,GAAG,EACH,mBAA4C,EAC5C,SAAS,EACT,WAAW,EACX,kBAAkB,EAClB,WAAmB,EACnB,IAA2B,GAC5B,EAAE,sBAAsB,mDA2SxB;AAED,wBAAgB,gBAAgB,CAAC,EAC/B,KAAK,EACL,mBAA4C,EAC5C,WAAW,EACX,kBAAkB,GACnB,EAAE;IACD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,mBAAmB,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,GAAG,IAAI,CAAC;IACvD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,kBAAkB,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CAC7C,mDA+LA;AAID,wBAAgB,qBAAqB,CAAC,EACpC,WAAW,GACZ,EAAE;IACD,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B,mDAwCA"}
@@ -5,13 +5,14 @@ import { ChatFirstAppPane, defaultChatFirstCopy, } from "@agent-native/core/clie
5
5
  import { useFeatureFlag } from "@agent-native/core/client/feature-flags";
6
6
  import { useActionMutation, useActionQuery, } from "@agent-native/core/client/hooks";
7
7
  import { useT } from "@agent-native/core/client/i18n";
8
+ import { AGENT_NATIVE_WORKSPACE_APP_ROUTE_MESSAGE_TYPE } from "@agent-native/core/client/navigation";
8
9
  import { withBuilderUtmTrackingParams } from "@agent-native/core/shared/builder-link-tracking";
9
10
  import { IconAlertTriangle, IconArrowLeft, IconClockHour4, } from "@tabler/icons-react";
10
11
  import { useTheme } from "next-themes";
11
12
  import { useCallback, useEffect, useMemo, useRef, useState, } from "react";
12
13
  import { Link } from "react-router";
13
14
  import { isEmbedSessionExpiredMessage } from "../lib/embed-session-recovery.js";
14
- import { mergeChatFirstWorkspaceApps, isWorkspaceSsoApp, navigateToWorkspaceApp, shouldOpenWorkspaceAppInTopWindow, workspaceAppDirectHref, workspaceAppEmbedTarget, workspaceAppHref, } from "../lib/workspace-apps.js";
15
+ import { mergeChatFirstWorkspaceApps, isWorkspaceSsoApp, navigateToWorkspaceApp, shouldOpenWorkspaceAppInTopWindow, workspaceAppRouteForChildPath, workspaceAppDirectHref, workspaceAppEmbedTarget, workspaceAppHref, } from "../lib/workspace-apps.js";
15
16
  import { DISPATCH_WORKSPACE_SSO_FLAG } from "../shared/feature-flags.js";
16
17
  import { workspaceAppChatProxyPath } from "../shared/workspace-app-chat.js";
17
18
  import { ActionQueryError } from "./action-query-error.js";
@@ -113,7 +114,7 @@ export function WorkspaceAppChatRail({ appId, appName, children, copy = defaultC
113
114
  // rather than a copy maintained inside Dispatch.
114
115
  apiUrl: appChat.apiUrl, agentChatSurface: "app", showTabBar: true, suppressInlineOpenApp: true, dynamicSuggestions: false, suggestions: [], emptyStateText: `Ask about ${appName}`, ...(agentPageHref ? { agentPageHref } : {}), ...(onFullscreenRequest ? { onFullscreenRequest } : {}), children: children }));
115
116
  }
116
- export function WorkspaceAppFrame({ app, navigateToTopWindow = navigateToWorkspaceApp, embedPath, chatSidebar = false, copy = defaultChatFirstCopy, }) {
117
+ export function WorkspaceAppFrame({ app, navigateToTopWindow = navigateToWorkspaceApp, embedPath, initialPath, onChildRouteChange, chatSidebar = false, copy = defaultChatFirstCopy, }) {
117
118
  const { resolvedTheme } = useTheme();
118
119
  const theme = resolvedTheme === "dark" || resolvedTheme === "light"
119
120
  ? resolvedTheme
@@ -153,19 +154,25 @@ export function WorkspaceAppFrame({ app, navigateToTopWindow = navigateToWorkspa
153
154
  if (embedPath !== undefined) {
154
155
  return workspaceAppDirectHref({ path: app.path, url: app.url }, embedPath);
155
156
  }
157
+ if (initialPath !== undefined) {
158
+ return workspaceAppDirectHref({ path: app.path, url: app.url }, initialPath);
159
+ }
156
160
  const target = workspaceAppEmbedTarget({
157
161
  path: app.path ?? "",
158
162
  url: app.url,
159
163
  });
160
164
  return target.url ?? target.path ?? null;
161
- }, [app.path, app.url, embedPath]);
165
+ }, [app.path, app.url, embedPath, initialPath]);
162
166
  const openInTopWindow = shouldOpenWorkspaceAppInTopWindow();
163
- const topWindowSsoAttemptKey = `${app.id}\u0000${app.path ?? ""}\u0000${app.url ?? ""}\u0000${embedPath ?? ""}\u0000${embedAttempt}`;
167
+ const topWindowSsoAttemptKey = `${app.id}\u0000${app.path ?? ""}\u0000${app.url ?? ""}\u0000${embedPath ?? ""}\u0000${initialPath ?? ""}\u0000${embedAttempt}`;
164
168
  const topWindowSsoAttemptedRef = useRef(null);
165
169
  const embedInput = useMemo(() => {
166
170
  if (embedPath !== undefined) {
167
171
  return buildChatFirstEmbedSessionInput(app.id, embedPath);
168
172
  }
173
+ if (initialPath !== undefined) {
174
+ return buildChatFirstEmbedSessionInput(app.id, initialPath);
175
+ }
169
176
  if (!appHref)
170
177
  return null;
171
178
  return {
@@ -173,7 +180,7 @@ export function WorkspaceAppFrame({ app, navigateToTopWindow = navigateToWorkspa
173
180
  ...workspaceAppEmbedTarget({ path: app.path ?? "", url: app.url }),
174
181
  chrome: "minimal",
175
182
  };
176
- }, [app.id, app.path, app.url, appHref, embedPath]);
183
+ }, [app.id, app.path, app.url, appHref, embedPath, initialPath]);
177
184
  useEffect(() => {
178
185
  if (openInTopWindow && useWorkspaceSso && embedInput) {
179
186
  setTopWindowNavigationFailed(false);
@@ -258,7 +265,7 @@ export function WorkspaceAppFrame({ app, navigateToTopWindow = navigateToWorkspa
258
265
  return;
259
266
  }
260
267
  setIsDirectFallback(true);
261
- setEmbedUrl(workspaceAppDirectHref({ path: app.path ?? "", url: app.url }, embedPath ?? "/"));
268
+ setEmbedUrl(workspaceAppDirectHref({ path: app.path ?? "", url: app.url }, initialPath ?? embedPath ?? "/"));
262
269
  setEmbedError(error);
263
270
  });
264
271
  return () => {
@@ -272,6 +279,7 @@ export function WorkspaceAppFrame({ app, navigateToTopWindow = navigateToWorkspa
272
279
  createWorkspaceSsoEmbedSession.mutateAsync,
273
280
  embedInput,
274
281
  embedPath,
282
+ initialPath,
275
283
  embedAttempt,
276
284
  openInTopWindow,
277
285
  navigateToTopWindow,
@@ -289,6 +297,36 @@ export function WorkspaceAppFrame({ app, navigateToTopWindow = navigateToWorkspa
289
297
  window.addEventListener("message", handleEmbedSessionExpired);
290
298
  return () => window.removeEventListener("message", handleEmbedSessionExpired);
291
299
  }, [embedUrl]);
300
+ useEffect(() => {
301
+ if (!onChildRouteChange || !embedUrl)
302
+ return;
303
+ const frame = embedFrameRef.current;
304
+ if (!frame)
305
+ return;
306
+ let expectedOrigin;
307
+ try {
308
+ expectedOrigin = new URL(embedUrl, window.location.href).origin;
309
+ }
310
+ catch {
311
+ return;
312
+ }
313
+ const handleWorkspaceAppRoute = (event) => {
314
+ if (event.source !== frame.contentWindow ||
315
+ event.origin !== expectedOrigin) {
316
+ return;
317
+ }
318
+ const message = event.data;
319
+ if (message?.type !== AGENT_NATIVE_WORKSPACE_APP_ROUTE_MESSAGE_TYPE ||
320
+ typeof message.path !== "string") {
321
+ return;
322
+ }
323
+ const route = workspaceAppRouteForChildPath({ id: app.id, path: app.path ?? "", url: app.url }, message.path);
324
+ if (route)
325
+ onChildRouteChange(route);
326
+ };
327
+ window.addEventListener("message", handleWorkspaceAppRoute);
328
+ return () => window.removeEventListener("message", handleWorkspaceAppRoute);
329
+ }, [app.id, app.path, app.url, embedUrl, onChildRouteChange]);
292
330
  useEffect(() => {
293
331
  postThemeToFrame();
294
332
  }, [embedUrl, postThemeToFrame]);
@@ -303,7 +341,7 @@ export function WorkspaceAppFrame({ app, navigateToTopWindow = navigateToWorkspa
303
341
  return appPane;
304
342
  return (_jsx(WorkspaceAppChatRail, { appId: app.id, appName: app.name, copy: copy, children: appPane }));
305
343
  }
306
- export function WorkspaceAppHost({ appId, navigateToTopWindow = navigateToWorkspaceApp, }) {
344
+ export function WorkspaceAppHost({ appId, navigateToTopWindow = navigateToWorkspaceApp, initialPath, onChildRouteChange, }) {
307
345
  const t = useT();
308
346
  const workspaceAppsQuery = useActionQuery("list-workspace-apps", { includeAgentCards: false, includeArchived: true });
309
347
  const workspaceApps = useMemo(() => mergeChatFirstWorkspaceApps(workspaceAppsQuery.data), [workspaceAppsQuery.data]);
@@ -365,7 +403,7 @@ export function WorkspaceAppHost({ appId, navigateToTopWindow = navigateToWorksp
365
403
  defaultValue: "Open in Builder",
366
404
  }) }) })) : null] })] }) }));
367
405
  }
368
- return (_jsx("div", { "data-dispatch-workspace-app-host": true, className: "flex h-full min-h-0 flex-col bg-background", children: _jsx("div", { className: "min-h-0 flex-1 bg-muted/20", children: _jsx(WorkspaceAppFrame, { app: app, navigateToTopWindow: navigateToTopWindow }) }) }));
406
+ return (_jsx("div", { "data-dispatch-workspace-app-host": true, className: "flex h-full min-h-0 flex-col bg-background", children: _jsx("div", { className: "min-h-0 flex-1 bg-muted/20", children: _jsx(WorkspaceAppFrame, { app: app, navigateToTopWindow: navigateToTopWindow, initialPath: initialPath, onChildRouteChange: onChildRouteChange }) }) }));
369
407
  }
370
408
  const MAX_KEEP_ALIVE_APPS = 3;
371
409
  export function WorkspaceAppKeepAlive({ activeAppId, }) {