@agent-native/dispatch 0.6.0 → 0.7.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 (159) hide show
  1. package/README.md +1 -1
  2. package/dist/actions/create-pylon-ticket.d.ts +3 -0
  3. package/dist/actions/create-pylon-ticket.d.ts.map +1 -0
  4. package/dist/actions/create-pylon-ticket.js +94 -0
  5. package/dist/actions/create-pylon-ticket.js.map +1 -0
  6. package/dist/actions/create-vault-grant.js +1 -1
  7. package/dist/actions/create-vault-grant.js.map +1 -1
  8. package/dist/actions/create-vault-secret.d.ts.map +1 -1
  9. package/dist/actions/create-vault-secret.js +4 -3
  10. package/dist/actions/create-vault-secret.js.map +1 -1
  11. package/dist/actions/get-vault-access-settings.d.ts +3 -0
  12. package/dist/actions/get-vault-access-settings.d.ts.map +1 -0
  13. package/dist/actions/get-vault-access-settings.js +10 -0
  14. package/dist/actions/get-vault-access-settings.js.map +1 -0
  15. package/dist/actions/grant-vault-secrets-to-app.js +1 -1
  16. package/dist/actions/grant-vault-secrets-to-app.js.map +1 -1
  17. package/dist/actions/index.d.ts.map +1 -1
  18. package/dist/actions/index.js +8 -0
  19. package/dist/actions/index.js.map +1 -1
  20. package/dist/actions/list-integrations-catalog.js +1 -1
  21. package/dist/actions/list-integrations-catalog.js.map +1 -1
  22. package/dist/actions/list-vault-grants.js +1 -1
  23. package/dist/actions/list-vault-grants.js.map +1 -1
  24. package/dist/actions/list-workspace-apps.d.ts.map +1 -1
  25. package/dist/actions/list-workspace-apps.js +5 -1
  26. package/dist/actions/list-workspace-apps.js.map +1 -1
  27. package/dist/actions/set-vault-access-settings.d.ts +3 -0
  28. package/dist/actions/set-vault-access-settings.d.ts.map +1 -0
  29. package/dist/actions/set-vault-access-settings.js +13 -0
  30. package/dist/actions/set-vault-access-settings.js.map +1 -0
  31. package/dist/actions/start-workspace-app-creation.d.ts.map +1 -1
  32. package/dist/actions/start-workspace-app-creation.js +6 -0
  33. package/dist/actions/start-workspace-app-creation.js.map +1 -1
  34. package/dist/actions/sync-vault-to-app.js +1 -1
  35. package/dist/actions/sync-vault-to-app.js.map +1 -1
  36. package/dist/actions/update-workspace-app-metadata.d.ts +3 -0
  37. package/dist/actions/update-workspace-app-metadata.d.ts.map +1 -0
  38. package/dist/actions/update-workspace-app-metadata.js +30 -0
  39. package/dist/actions/update-workspace-app-metadata.js.map +1 -0
  40. package/dist/actions/view-screen.d.ts.map +1 -1
  41. package/dist/actions/view-screen.js +4 -2
  42. package/dist/actions/view-screen.js.map +1 -1
  43. package/dist/components/app-keys-popover.d.ts.map +1 -1
  44. package/dist/components/app-keys-popover.js +17 -5
  45. package/dist/components/app-keys-popover.js.map +1 -1
  46. package/dist/components/create-app-popover.d.ts.map +1 -1
  47. package/dist/components/create-app-popover.js +38 -14
  48. package/dist/components/create-app-popover.js.map +1 -1
  49. package/dist/components/dispatch-shell.d.ts +4 -4
  50. package/dist/components/dispatch-shell.d.ts.map +1 -1
  51. package/dist/components/dispatch-shell.js +6 -6
  52. package/dist/components/dispatch-shell.js.map +1 -1
  53. package/dist/components/layout/Layout.d.ts.map +1 -1
  54. package/dist/components/layout/Layout.js +10 -3
  55. package/dist/components/layout/Layout.js.map +1 -1
  56. package/dist/components/messaging-setup-panel.d.ts.map +1 -1
  57. package/dist/components/messaging-setup-panel.js +2 -2
  58. package/dist/components/messaging-setup-panel.js.map +1 -1
  59. package/dist/components/workspace-app-card.d.ts.map +1 -1
  60. package/dist/components/workspace-app-card.js +41 -2
  61. package/dist/components/workspace-app-card.js.map +1 -1
  62. package/dist/hooks/use-navigation-state.js +12 -5
  63. package/dist/hooks/use-navigation-state.js.map +1 -1
  64. package/dist/lib/catch-all-target.d.ts +2 -0
  65. package/dist/lib/catch-all-target.d.ts.map +1 -0
  66. package/dist/lib/catch-all-target.js +95 -0
  67. package/dist/lib/catch-all-target.js.map +1 -0
  68. package/dist/lib/workspace-apps.d.ts +9 -0
  69. package/dist/lib/workspace-apps.d.ts.map +1 -1
  70. package/dist/lib/workspace-apps.js.map +1 -1
  71. package/dist/routes/pages/$appId.d.ts +2 -24
  72. package/dist/routes/pages/$appId.d.ts.map +1 -1
  73. package/dist/routes/pages/$appId.js +42 -8
  74. package/dist/routes/pages/$appId.js.map +1 -1
  75. package/dist/routes/pages/approval.d.ts.map +1 -1
  76. package/dist/routes/pages/approval.js +2 -1
  77. package/dist/routes/pages/approval.js.map +1 -1
  78. package/dist/routes/pages/apps.$appId.d.ts.map +1 -1
  79. package/dist/routes/pages/apps.$appId.js +2 -1
  80. package/dist/routes/pages/apps.$appId.js.map +1 -1
  81. package/dist/routes/pages/integrations.d.ts.map +1 -1
  82. package/dist/routes/pages/integrations.js +20 -15
  83. package/dist/routes/pages/integrations.js.map +1 -1
  84. package/dist/routes/pages/new-app.js +1 -1
  85. package/dist/routes/pages/new-app.js.map +1 -1
  86. package/dist/routes/pages/overview.d.ts.map +1 -1
  87. package/dist/routes/pages/overview.js +14 -1
  88. package/dist/routes/pages/overview.js.map +1 -1
  89. package/dist/routes/pages/vault.d.ts.map +1 -1
  90. package/dist/routes/pages/vault.js +25 -6
  91. package/dist/routes/pages/vault.js.map +1 -1
  92. package/dist/routes/pages/workspace.d.ts.map +1 -1
  93. package/dist/routes/pages/workspace.js +5 -3
  94. package/dist/routes/pages/workspace.js.map +1 -1
  95. package/dist/server/lib/app-creation-store.d.ts +13 -0
  96. package/dist/server/lib/app-creation-store.d.ts.map +1 -1
  97. package/dist/server/lib/app-creation-store.js +295 -9
  98. package/dist/server/lib/app-creation-store.js.map +1 -1
  99. package/dist/server/lib/env-config.d.ts.map +1 -1
  100. package/dist/server/lib/env-config.js +5 -0
  101. package/dist/server/lib/env-config.js.map +1 -1
  102. package/dist/server/lib/onboarding-steps.d.ts +12 -0
  103. package/dist/server/lib/onboarding-steps.d.ts.map +1 -0
  104. package/dist/server/lib/onboarding-steps.js +47 -0
  105. package/dist/server/lib/onboarding-steps.js.map +1 -0
  106. package/dist/server/lib/vault-store.d.ts +55 -0
  107. package/dist/server/lib/vault-store.d.ts.map +1 -1
  108. package/dist/server/lib/vault-store.js +210 -41
  109. package/dist/server/lib/vault-store.js.map +1 -1
  110. package/dist/server/plugins/agent-chat.d.ts.map +1 -1
  111. package/dist/server/plugins/agent-chat.js +2 -1
  112. package/dist/server/plugins/agent-chat.js.map +1 -1
  113. package/dist/server/plugins/core-routes.d.ts.map +1 -1
  114. package/dist/server/plugins/core-routes.js +4 -0
  115. package/dist/server/plugins/core-routes.js.map +1 -1
  116. package/dist/server/plugins/integrations.js +2 -2
  117. package/dist/server/plugins/integrations.js.map +1 -1
  118. package/package.json +13 -11
  119. package/src/actions/create-pylon-ticket.ts +109 -0
  120. package/src/actions/create-vault-grant.ts +1 -1
  121. package/src/actions/create-vault-secret.ts +4 -3
  122. package/src/actions/get-vault-access-settings.ts +11 -0
  123. package/src/actions/grant-vault-secrets-to-app.ts +1 -1
  124. package/src/actions/index.ts +8 -0
  125. package/src/actions/list-integrations-catalog.ts +1 -1
  126. package/src/actions/list-vault-grants.ts +1 -1
  127. package/src/actions/list-workspace-apps.ts +5 -1
  128. package/src/actions/set-vault-access-settings.ts +16 -0
  129. package/src/actions/start-workspace-app-creation.ts +8 -0
  130. package/src/actions/sync-vault-to-app.ts +1 -1
  131. package/src/actions/update-workspace-app-metadata.ts +32 -0
  132. package/src/actions/view-screen.ts +4 -1
  133. package/src/components/app-keys-popover.tsx +38 -8
  134. package/src/components/create-app-popover.tsx +47 -14
  135. package/src/components/dispatch-shell.tsx +16 -15
  136. package/src/components/layout/Layout.tsx +11 -5
  137. package/src/components/messaging-setup-panel.tsx +54 -39
  138. package/src/components/workspace-app-card.tsx +102 -0
  139. package/src/hooks/use-navigation-state.ts +10 -4
  140. package/src/lib/catch-all-target.spec.ts +218 -0
  141. package/src/lib/catch-all-target.ts +99 -0
  142. package/src/lib/workspace-apps.ts +9 -0
  143. package/src/routes/pages/$appId.tsx +45 -7
  144. package/src/routes/pages/approval.tsx +33 -3
  145. package/src/routes/pages/apps.$appId.tsx +6 -1
  146. package/src/routes/pages/integrations.tsx +57 -18
  147. package/src/routes/pages/new-app.tsx +1 -1
  148. package/src/routes/pages/overview.tsx +69 -29
  149. package/src/routes/pages/vault.tsx +101 -21
  150. package/src/routes/pages/workspace.tsx +21 -3
  151. package/src/server/lib/app-creation-store.spec.ts +61 -2
  152. package/src/server/lib/app-creation-store.ts +386 -11
  153. package/src/server/lib/env-config.ts +5 -0
  154. package/src/server/lib/onboarding-steps.ts +49 -0
  155. package/src/server/lib/vault-store.spec.ts +69 -0
  156. package/src/server/lib/vault-store.ts +266 -49
  157. package/src/server/plugins/agent-chat.ts +2 -1
  158. package/src/server/plugins/core-routes.ts +5 -0
  159. package/src/server/plugins/integrations.ts +2 -2
@@ -1,3 +1,4 @@
1
+ type WorkspaceAppAudience = "internal" | "public";
1
2
  export interface WorkspaceAppSummary {
2
3
  id: string;
3
4
  name: string;
@@ -5,6 +6,9 @@ export interface WorkspaceAppSummary {
5
6
  path: string;
6
7
  url: string | null;
7
8
  isDispatch: boolean;
9
+ audience: WorkspaceAppAudience;
10
+ publicPaths: string[];
11
+ protectedPaths: string[];
8
12
  status?: "ready" | "pending";
9
13
  statusLabel?: string;
10
14
  builderUrl?: string | null;
@@ -25,6 +29,7 @@ export interface ListWorkspaceAppsOptions {
25
29
  * when rendering the "Hidden apps" expander.
26
30
  */
27
31
  includeArchived?: boolean;
32
+ audience?: WorkspaceAppAudience | "all";
28
33
  }
29
34
  export interface AvailableWorkspaceTemplate {
30
35
  name: string;
@@ -52,6 +57,7 @@ export interface WorkspaceInfo {
52
57
  /** Number of apps currently scaffolded under apps/. */
53
58
  appCount: number;
54
59
  }
60
+ export declare function generateWorkspaceAppDescription(prompt: string, appId: string): string;
55
61
  export declare function archiveWorkspaceApp(input: {
56
62
  appId: string;
57
63
  }): Promise<{
@@ -75,6 +81,11 @@ export declare function getEnvBuilderProjectId(): string | null;
75
81
  * "starter" / "dispatch" with no parent context).
76
82
  */
77
83
  export declare function getWorkspaceInfo(): WorkspaceInfo;
84
+ export declare function updateWorkspaceAppMetadata(input: {
85
+ appId: string;
86
+ name?: string | null;
87
+ description?: string | null;
88
+ }): Promise<WorkspaceAppSummary>;
78
89
  export declare function listWorkspaceApps(options?: ListWorkspaceAppsOptions): Promise<WorkspaceAppSummary[]>;
79
90
  export declare function listAvailableWorkspaceTemplates(): Promise<AvailableWorkspaceTemplate[]>;
80
91
  export declare function scaffoldWorkspaceAppFromTemplate(input: {
@@ -92,6 +103,7 @@ export declare function setAppCreationSettings(input: {
92
103
  export declare function startWorkspaceAppCreation(input: {
93
104
  prompt: string;
94
105
  appId?: string | null;
106
+ description?: string | null;
95
107
  template?: string | null;
96
108
  secretIds?: string[];
97
109
  resourceIds?: string[];
@@ -140,4 +152,5 @@ export declare function startWorkspaceAppCreation(input: {
140
152
  message: string;
141
153
  prompt?: undefined;
142
154
  }>;
155
+ export {};
143
156
  //# sourceMappingURL=app-creation-store.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"app-creation-store.d.ts","sourceRoot":"","sources":["../../../src/server/lib/app-creation-store.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"app-creation-store.d.ts","sourceRoot":"","sources":["../../../src/server/lib/app-creation-store.ts"],"names":[],"mappings":"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"}
@@ -3,14 +3,15 @@ import fs from "node:fs";
3
3
  import path from "node:path";
4
4
  import { fileURLToPath } from "node:url";
5
5
  import { getSetting, putSetting } from "@agent-native/core/settings";
6
+ import { assertValidWorkspaceAppId } from "@agent-native/core/shared";
6
7
  import { getBuilderBranchProjectId, getRequestContext, isIntegrationCallerRequest, resolveBuilderBranchProjectId, resolveBuilderCredentials, runBuilderAgent, } from "@agent-native/core/server";
7
8
  import { getDbExec } from "@agent-native/core/db";
8
- import { assertValidWorkspaceAppId } from "@agent-native/core/shared";
9
9
  import { currentOrgId, currentOwnerEmail, recordAudit, resolveLinkedOwner, } from "./dispatch-store.js";
10
10
  import { identityKeyForIncoming } from "./dispatch-integrations.js";
11
11
  import { createRequest, listSecrets } from "./vault-store.js";
12
12
  import { grantWorkspaceResourcesToApp, listWorkspaceResourceOptions, } from "./workspace-resources-store.js";
13
13
  const SETTINGS_KEY = "dispatch-app-creation-settings";
14
+ const WORKSPACE_APP_METADATA_SETTINGS_KEY = "workspace-app-metadata";
14
15
  const WORKSPACE_APPS_ENV_KEY = "AGENT_NATIVE_WORKSPACE_APPS_JSON";
15
16
  const WORKSPACE_APPS_MANIFEST_FILE = "workspace-apps.json";
16
17
  const WORKSPACE_APPS_GATEWAY_PATH = "/_workspace/apps";
@@ -18,6 +19,7 @@ const WORKSPACE_APPS_GATEWAY_TIMEOUT_MS = 1_000;
18
19
  const MAX_PENDING_APPS = 50;
19
20
  const AGENT_CARD_PATH = "/.well-known/agent-card.json";
20
21
  const AGENT_CARD_FETCH_TIMEOUT_MS = 1_500;
22
+ const DEFAULT_WORKSPACE_APP_AUDIENCE = "internal";
21
23
  function readJson(file) {
22
24
  try {
23
25
  return JSON.parse(fs.readFileSync(file, "utf8"));
@@ -47,18 +49,145 @@ function titleCase(value) {
47
49
  .map((part) => part.charAt(0).toUpperCase() + part.slice(1))
48
50
  .join(" ");
49
51
  }
52
+ function normalizeWhitespace(value) {
53
+ return value.replace(/\s+/g, " ").trim();
54
+ }
55
+ function ensureSentence(value) {
56
+ if (!value)
57
+ return value;
58
+ const capitalized = value.charAt(0).toUpperCase() + value.slice(1);
59
+ return /[.!?]$/.test(capitalized) ? capitalized : `${capitalized}.`;
60
+ }
61
+ function clipSentence(value, max = 180) {
62
+ if (value.length <= max)
63
+ return value;
64
+ const clipped = value
65
+ .slice(0, max - 1)
66
+ .replace(/\s+\S*$/, "")
67
+ .trim();
68
+ return `${clipped || value.slice(0, max - 1).trim()}…`;
69
+ }
70
+ export function generateWorkspaceAppDescription(prompt, appId) {
71
+ const cleaned = normalizeWhitespace(prompt)
72
+ .replace(/^(please\s+)?(build|create|make|generate|scaffold)\s+(me\s+|us\s+)?/i, "")
73
+ .replace(/^(an?\s+)?(workspace\s+)?(agent-native\s+)?(app|tool)\s+(that|to|for)\s+/i, "")
74
+ .replace(/^(an?\s+)?(dashboard|workspace|agent)\s+(that|to|for)\s+/i, "");
75
+ if (!cleaned)
76
+ return `Workspace app for ${titleCase(appId)}.`;
77
+ return clipSentence(ensureSentence(cleaned));
78
+ }
50
79
  function scopedSettingsKey() {
51
80
  const orgId = currentOrgId();
52
81
  if (orgId)
53
82
  return `${SETTINGS_KEY}:org:${orgId}`;
54
83
  return `${SETTINGS_KEY}:user:${currentOwnerEmail()}`;
55
84
  }
85
+ function workspaceAppMetadataSettingsKey() {
86
+ const orgId = currentOrgId();
87
+ if (orgId)
88
+ return `${WORKSPACE_APP_METADATA_SETTINGS_KEY}:org:${orgId}`;
89
+ return `${WORKSPACE_APP_METADATA_SETTINGS_KEY}:user:${currentOwnerEmail()}`;
90
+ }
56
91
  async function readSettingsRecord() {
57
92
  const raw = await getSetting(scopedSettingsKey()).catch(() => null);
58
93
  return raw && typeof raw === "object" && !Array.isArray(raw)
59
94
  ? raw
60
95
  : {};
61
96
  }
97
+ function cleanOptionalText(value) {
98
+ return typeof value === "string" && value.trim() ? value.trim() : undefined;
99
+ }
100
+ function parseWorkspaceAppMetadataSettings(raw) {
101
+ const record = raw && typeof raw === "object" && !Array.isArray(raw)
102
+ ? raw
103
+ : {};
104
+ const rawApps = record.apps &&
105
+ typeof record.apps === "object" &&
106
+ !Array.isArray(record.apps)
107
+ ? record.apps
108
+ : {};
109
+ const apps = {};
110
+ for (const [id, value] of Object.entries(rawApps)) {
111
+ if (!id.trim() || !value || typeof value !== "object")
112
+ continue;
113
+ const item = value;
114
+ const override = {};
115
+ const name = cleanOptionalText(item.name);
116
+ const description = cleanOptionalText(item.description);
117
+ const sourcePrompt = cleanOptionalText(item.sourcePrompt);
118
+ const updatedAt = cleanOptionalText(item.updatedAt);
119
+ const updatedBy = cleanOptionalText(item.updatedBy);
120
+ if (name)
121
+ override.name = name;
122
+ if (description)
123
+ override.description = description;
124
+ if (item.generated === true)
125
+ override.generated = true;
126
+ if (sourcePrompt)
127
+ override.sourcePrompt = sourcePrompt;
128
+ if (updatedAt)
129
+ override.updatedAt = updatedAt;
130
+ if (updatedBy)
131
+ override.updatedBy = updatedBy;
132
+ if (Object.keys(override).length > 0)
133
+ apps[id.trim()] = override;
134
+ }
135
+ return { apps };
136
+ }
137
+ async function readWorkspaceAppMetadataSettings() {
138
+ const raw = await getSetting(workspaceAppMetadataSettingsKey()).catch(() => null);
139
+ return parseWorkspaceAppMetadataSettings(raw);
140
+ }
141
+ async function writeWorkspaceAppMetadataOverride(input) {
142
+ const key = workspaceAppMetadataSettingsKey();
143
+ const current = parseWorkspaceAppMetadataSettings(await getSetting(key).catch(() => null));
144
+ const appId = input.appId.trim();
145
+ const existing = current.apps[appId] ?? {};
146
+ const next = {
147
+ ...existing,
148
+ updatedAt: new Date().toISOString(),
149
+ };
150
+ const name = cleanOptionalText(input.name);
151
+ const description = cleanOptionalText(input.description);
152
+ const sourcePrompt = cleanOptionalText(input.sourcePrompt);
153
+ const updatedBy = cleanOptionalText(input.updatedBy);
154
+ if (name)
155
+ next.name = name;
156
+ else
157
+ delete next.name;
158
+ if (description)
159
+ next.description = description;
160
+ else
161
+ delete next.description;
162
+ if (input.generated === true)
163
+ next.generated = true;
164
+ else if (input.generated === false)
165
+ delete next.generated;
166
+ if (sourcePrompt)
167
+ next.sourcePrompt = sourcePrompt;
168
+ if (updatedBy)
169
+ next.updatedBy = updatedBy;
170
+ current.apps[appId] = next;
171
+ await putSetting(key, { apps: current.apps });
172
+ return current;
173
+ }
174
+ function applyWorkspaceAppMetadataOverride(app, settings) {
175
+ const override = settings.apps[app.id];
176
+ if (!override)
177
+ return app;
178
+ const name = cleanOptionalText(override.name);
179
+ const description = cleanOptionalText(override.description);
180
+ const generated = override.generated === true;
181
+ const shouldApplyName = !!name && !generated;
182
+ const shouldApplyDescription = !!description && (!generated || !cleanOptionalText(app.description));
183
+ if (!shouldApplyName && !shouldApplyDescription)
184
+ return app;
185
+ return {
186
+ ...app,
187
+ ...(shouldApplyName ? { name } : {}),
188
+ ...(shouldApplyDescription ? { description } : {}),
189
+ };
190
+ }
62
191
  function workspaceAppUrl(appPath) {
63
192
  const base = process.env.WORKSPACE_GATEWAY_URL ||
64
193
  process.env.APP_URL ||
@@ -88,6 +217,71 @@ function workspaceAppLink(appPath, explicitUrl) {
88
217
  return urlValue;
89
218
  }
90
219
  }
220
+ function normalizeWorkspaceAppAudience(value) {
221
+ return value === "public" ? "public" : DEFAULT_WORKSPACE_APP_AUDIENCE;
222
+ }
223
+ function normalizeWorkspaceAppPathList(value) {
224
+ let rawPaths = [];
225
+ if (Array.isArray(value)) {
226
+ rawPaths = value;
227
+ }
228
+ else if (typeof value === "string") {
229
+ const trimmed = value.trim();
230
+ if (!trimmed)
231
+ return [];
232
+ try {
233
+ const parsed = JSON.parse(trimmed);
234
+ rawPaths = Array.isArray(parsed) ? parsed : [trimmed];
235
+ }
236
+ catch {
237
+ rawPaths = trimmed.split(",");
238
+ }
239
+ }
240
+ const paths = rawPaths
241
+ .map((entry) => (typeof entry === "string" ? entry.trim() : ""))
242
+ .filter((entry) => entry.startsWith("/"))
243
+ .map((entry) => entry.length > 1 && entry.endsWith("/") ? entry.slice(0, -1) : entry);
244
+ return Array.from(new Set(paths));
245
+ }
246
+ function workspaceAppAudienceFromPackageJson(pkg) {
247
+ if (!pkg || typeof pkg !== "object" || Array.isArray(pkg))
248
+ return undefined;
249
+ const record = pkg;
250
+ const config = record["agent-native"] ?? record.agentNative;
251
+ const nested = config && typeof config === "object" && !Array.isArray(config)
252
+ ? config
253
+ : {};
254
+ const raw = nested.workspaceApp?.audience ??
255
+ nested.workspace?.audience ??
256
+ nested.audience ??
257
+ record.workspaceAppAudience;
258
+ if (raw === undefined)
259
+ return undefined;
260
+ return normalizeWorkspaceAppAudience(raw);
261
+ }
262
+ function workspaceAppRouteAccessFromPackageJson(pkg) {
263
+ if (!pkg || typeof pkg !== "object" || Array.isArray(pkg)) {
264
+ return { publicPaths: [], protectedPaths: [] };
265
+ }
266
+ const record = pkg;
267
+ const config = record["agent-native"] ?? record.agentNative;
268
+ const nested = config && typeof config === "object" && !Array.isArray(config)
269
+ ? config
270
+ : {};
271
+ return {
272
+ publicPaths: normalizeWorkspaceAppPathList(nested.workspaceApp?.publicPaths ??
273
+ nested.workspaceApp?.publicPagePaths ??
274
+ nested.workspace?.publicPaths ??
275
+ nested.publicPaths ??
276
+ record.workspaceAppPublicPaths),
277
+ protectedPaths: normalizeWorkspaceAppPathList(nested.workspaceApp?.protectedPaths ??
278
+ nested.workspaceApp?.privatePaths ??
279
+ nested.workspaceApp?.authRequiredPaths ??
280
+ nested.workspace?.protectedPaths ??
281
+ nested.protectedPaths ??
282
+ record.workspaceAppProtectedPaths),
283
+ };
284
+ }
91
285
  function parseWorkspaceAppsManifest(parsed) {
92
286
  const rawApps = Array.isArray(parsed?.apps)
93
287
  ? parsed.apps
@@ -115,6 +309,11 @@ function parseWorkspaceAppsManifest(parsed) {
115
309
  isDispatch: typeof entry.isDispatch === "boolean"
116
310
  ? entry.isDispatch
117
311
  : id === "dispatch",
312
+ audience: entry.audience === undefined
313
+ ? DEFAULT_WORKSPACE_APP_AUDIENCE
314
+ : normalizeWorkspaceAppAudience(entry.audience),
315
+ publicPaths: normalizeWorkspaceAppPathList(entry.publicPaths),
316
+ protectedPaths: normalizeWorkspaceAppPathList(entry.protectedPaths),
118
317
  status: "ready",
119
318
  };
120
319
  })
@@ -164,6 +363,9 @@ function parsePendingWorkspaceApps(value) {
164
363
  projectId: typeof record.projectId === "string" && record.projectId.trim()
165
364
  ? record.projectId.trim()
166
365
  : null,
366
+ ...(record.audience === undefined
367
+ ? {}
368
+ : { audience: normalizeWorkspaceAppAudience(record.audience) }),
167
369
  createdAt: typeof record.createdAt === "string" && record.createdAt.trim()
168
370
  ? record.createdAt.trim()
169
371
  : now,
@@ -250,6 +452,9 @@ function pendingAppToSummary(app) {
250
452
  path: app.path,
251
453
  url: app.builderUrl,
252
454
  isDispatch: false,
455
+ audience: app.audience ?? DEFAULT_WORKSPACE_APP_AUDIENCE,
456
+ publicPaths: [],
457
+ protectedPaths: [],
253
458
  status: "pending",
254
459
  statusLabel: "Building in Builder",
255
460
  builderUrl: app.builderUrl,
@@ -363,7 +568,8 @@ async function recordPendingWorkspaceApp(input) {
363
568
  const next = {
364
569
  id: input.appId,
365
570
  name: titleCase(input.appId),
366
- description: "Builder is creating this app. The workspace path becomes live after the branch is merged and deployed.",
571
+ description: input.description ||
572
+ "Builder is creating this app. The workspace path becomes live after the branch is merged and deployed.",
367
573
  path: `/${input.appId}`,
368
574
  builderUrl: input.builderUrl?.trim() || null,
369
575
  branchName: input.branchName?.trim() || null,
@@ -378,6 +584,13 @@ async function recordPendingWorkspaceApp(input) {
378
584
  ...pendingApps.filter((app) => app.id !== input.appId),
379
585
  ].slice(0, MAX_PENDING_APPS),
380
586
  });
587
+ await writeWorkspaceAppMetadataOverride({
588
+ appId: input.appId,
589
+ description: input.description,
590
+ generated: true,
591
+ sourcePrompt: input.sourcePrompt,
592
+ updatedBy: currentOwnerEmail(),
593
+ });
381
594
  await recordAudit({
382
595
  action: "workspace-app.pending",
383
596
  targetType: "workspace-app",
@@ -457,12 +670,13 @@ function readWorkspaceAppsFromFilesystem(workspaceRoot) {
457
670
  return null;
458
671
  const apps = fs
459
672
  .readdirSync(appsDir, { withFileTypes: true })
460
- .filter((entry) => entry.isDirectory())
673
+ .filter((entry) => entry.isDirectory() && !entry.name.startsWith("."))
461
674
  .map((entry) => {
462
675
  const appDir = path.join(appsDir, entry.name);
463
676
  const pkg = readJson(path.join(appDir, "package.json"));
464
677
  if (!pkg)
465
678
  return null;
679
+ const routeAccess = workspaceAppRouteAccessFromPackageJson(pkg);
466
680
  return {
467
681
  id: entry.name,
468
682
  name: pkg.displayName || titleCase(entry.name),
@@ -470,6 +684,10 @@ function readWorkspaceAppsFromFilesystem(workspaceRoot) {
470
684
  path: `/${entry.name}`,
471
685
  url: workspaceAppUrl(`/${entry.name}`),
472
686
  isDispatch: entry.name === "dispatch",
687
+ audience: workspaceAppAudienceFromPackageJson(pkg) ??
688
+ DEFAULT_WORKSPACE_APP_AUDIENCE,
689
+ publicPaths: routeAccess.publicPaths,
690
+ protectedPaths: routeAccess.protectedPaths,
473
691
  status: "ready",
474
692
  };
475
693
  })
@@ -524,15 +742,69 @@ export function getWorkspaceInfo() {
524
742
  };
525
743
  }
526
744
  async function applyArchivedAndPending(apps, options) {
527
- const [withPending, archivedIds] = await Promise.all([
745
+ const [withPending, archivedIds, metadataSettings] = await Promise.all([
528
746
  appendPendingWorkspaceApps(apps),
529
747
  listArchivedAppIds(),
748
+ readWorkspaceAppMetadataSettings(),
530
749
  ]);
531
750
  const archivedSet = new Set(archivedIds);
532
- const annotated = withPending.map((app) => archivedSet.has(app.id) ? { ...app, archived: true } : app);
751
+ const annotated = withPending.map((app) => {
752
+ const withMetadata = applyWorkspaceAppMetadataOverride(app, metadataSettings);
753
+ return archivedSet.has(app.id)
754
+ ? { ...withMetadata, archived: true }
755
+ : withMetadata;
756
+ });
533
757
  return options.includeArchived
534
- ? annotated
535
- : annotated.filter((app) => !app.archived);
758
+ ? filterAppsByAudience(annotated, options.audience)
759
+ : filterAppsByAudience(annotated.filter((app) => !app.archived), options.audience);
760
+ }
761
+ function filterAppsByAudience(apps, audience) {
762
+ if (!audience || audience === "all")
763
+ return apps;
764
+ return apps.filter((app) => (app.audience ?? DEFAULT_WORKSPACE_APP_AUDIENCE) ===
765
+ normalizeWorkspaceAppAudience(audience));
766
+ }
767
+ export async function updateWorkspaceAppMetadata(input) {
768
+ await assertCanManageAppCreationSettings();
769
+ const appId = input.appId.trim();
770
+ assertValidWorkspaceAppId(appId);
771
+ const apps = await listWorkspaceApps({
772
+ includeAgentCards: false,
773
+ includeArchived: true,
774
+ });
775
+ const app = apps.find((candidate) => candidate.id === appId);
776
+ if (!app)
777
+ throw new Error(`Workspace app "${appId}" was not found.`);
778
+ // Treat undefined/null as "field omitted, leave existing value alone"; an
779
+ // explicit empty string clears the override (the app reverts to its
780
+ // built-in name / no description). Without this, a partial update that
781
+ // only touches one field silently wipes the other.
782
+ const name = input.name == null ? app.name : input.name.trim();
783
+ const description = input.description == null
784
+ ? (app.description ?? undefined)
785
+ : input.description.trim();
786
+ await writeWorkspaceAppMetadataOverride({
787
+ appId,
788
+ name,
789
+ description,
790
+ generated: false,
791
+ updatedBy: currentOwnerEmail(),
792
+ });
793
+ await recordAudit({
794
+ action: "workspace-app.metadata-updated",
795
+ targetType: "workspace-app",
796
+ targetId: appId,
797
+ summary: `Updated workspace app details for ${name}`,
798
+ metadata: {
799
+ name,
800
+ descriptionConfigured: !!description,
801
+ },
802
+ });
803
+ const updated = (await listWorkspaceApps({
804
+ includeAgentCards: false,
805
+ includeArchived: true,
806
+ })).find((candidate) => candidate.id === appId);
807
+ return updated ?? { ...app, name, description };
536
808
  }
537
809
  export async function listWorkspaceApps(options = {}) {
538
810
  const gatewayApps = await readWorkspaceAppsFromGateway();
@@ -559,6 +831,9 @@ export async function listWorkspaceApps(options = {}) {
559
831
  path: "/dispatch",
560
832
  url: workspaceAppUrl("/dispatch"),
561
833
  isDispatch: true,
834
+ audience: DEFAULT_WORKSPACE_APP_AUDIENCE,
835
+ publicPaths: [],
836
+ protectedPaths: [],
562
837
  status: "ready",
563
838
  },
564
839
  ], options), options);
@@ -913,6 +1188,8 @@ function buildWorkspaceAppPrompt(input) {
913
1188
  const appId = slugify(input.appId || "") ||
914
1189
  slugify(input.prompt.replace(/\b(build|create|make|an?|the|app|tool)\b/gi, " ")) ||
915
1190
  "new-app";
1191
+ const appDescription = input.description?.trim() ||
1192
+ generateWorkspaceAppDescription(input.prompt, appId);
916
1193
  const selectedKeys = input.selectedKeys || [];
917
1194
  const selectedResources = input.selectedResources || [];
918
1195
  const resourceList = selectedResources.length
@@ -926,6 +1203,7 @@ function buildWorkspaceAppPrompt(input) {
926
1203
  "Create a new agent-native app in this workspace.",
927
1204
  "",
928
1205
  `App name: ${appId}`,
1206
+ `App description: ${appDescription}`,
929
1207
  `Template to start from: ${input.template || "starter"}`,
930
1208
  `User prompt: ${input.prompt.trim()}`,
931
1209
  "If the user mentions a product or company such as Granola, Loom, Superhuman, Linear, or Notion, treat it as product inspiration unless they explicitly ask to connect to that service. Do not invent or require third-party API keys like GRANOLA_API_KEY just because a product is named.",
@@ -956,11 +1234,13 @@ function buildWorkspaceAppPrompt(input) {
956
1234
  "",
957
1235
  "Branch readiness requirements before handing off:",
958
1236
  "- The CLI auto-fills package.json name and displayName from the app id; only edit the description / scripts / dependencies if the app actually needs more than the template provides.",
1237
+ `- Save a concise, human-readable app description in apps/${appId}/package.json "description" so Dispatch, A2A discovery, and connected agents can describe what this app does. Use the description above or improve it based on the prompt.`,
959
1238
  "- Do not add or update workspace-apps.json or .agent-native/workspace-apps.json unless the app needs an explicit external URL override; the root deploy generates the workspace app registry from apps/* and deploy metadata.",
960
1239
  "- Update pnpm-lock.yaml when adding or changing dependencies so Netlify can install the branch reliably.",
961
1240
  "- Update the app manifest/package/deploy metadata needed by the existing workspace deployment model; do not leave the branch relying only on uncommitted local state.",
962
- "- Verify the app's agent card/A2A metadata is ready so Dispatch can discover and delegate to the app after deployment.",
963
- "- Include a final verification note covering the registry entry, manifest/deploy metadata, and agent-card readiness.",
1241
+ "- Verify the app's agent card/A2A metadata is ready so Dispatch can discover and delegate to the app after deployment. Every sibling workspace app should be usable over A2A by default through call-agent.",
1242
+ "- Give the app agent context that sibling workspace apps are available over A2A with names and descriptions from the workspace app registry; do not hardcode a stale app list.",
1243
+ "- Include a final verification note covering the registry entry, manifest/deploy metadata, relative same-origin routing, and agent-card readiness.",
964
1244
  `When it is ready, start or update the workspace dev server and navigate the user to /${appId}.`,
965
1245
  ].join("\n"),
966
1246
  };
@@ -990,6 +1270,7 @@ export async function startWorkspaceAppCreation(input) {
990
1270
  const initial = buildWorkspaceAppPrompt({
991
1271
  prompt: input.prompt,
992
1272
  appId: input.appId,
1273
+ description: input.description,
993
1274
  template: input.template,
994
1275
  });
995
1276
  assertValidWorkspaceAppId(initial.appId);
@@ -1013,11 +1294,14 @@ export async function startWorkspaceAppCreation(input) {
1013
1294
  const built = buildWorkspaceAppPrompt({
1014
1295
  prompt: input.prompt,
1015
1296
  appId: input.appId,
1297
+ description: input.description,
1016
1298
  template: input.template,
1017
1299
  selectedKeys,
1018
1300
  selectedResources,
1019
1301
  });
1020
1302
  const prompt = built.prompt;
1303
+ const appDescription = input.description?.trim() ||
1304
+ generateWorkspaceAppDescription(input.prompt, built.appId);
1021
1305
  if (isLocal) {
1022
1306
  await requestSelectedVaultKeys({
1023
1307
  appId: built.appId,
@@ -1070,6 +1354,8 @@ export async function startWorkspaceAppCreation(input) {
1070
1354
  await recordPendingWorkspaceApp({
1071
1355
  appId: built.appId,
1072
1356
  projectId: settings.builderProjectId,
1357
+ description: appDescription,
1358
+ sourcePrompt: input.prompt,
1073
1359
  branchName: result.branchName,
1074
1360
  builderUrl: result.url,
1075
1361
  });