@agent-native/dispatch 0.40.30-nightly-20261021093329 → 0.40.30
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.
- package/CHANGELOG.md +6 -47
- package/dist/actions/connect-external-agent.d.ts.map +1 -1
- package/dist/actions/connect-external-agent.js +12 -13
- package/dist/actions/connect-external-agent.js.map +1 -1
- package/dist/actions/create-workspace-resource.d.ts +13 -13
- package/dist/actions/delete-destination.d.ts +12 -12
- package/dist/actions/delete-workspace-resource.d.ts +13 -13
- package/dist/actions/import-agent.d.ts +13 -13
- package/dist/actions/index.d.ts.map +1 -1
- package/dist/actions/index.js +8 -0
- package/dist/actions/index.js.map +1 -1
- package/dist/actions/inspect-connect-agent-card.d.ts +5 -0
- package/dist/actions/inspect-connect-agent-card.d.ts.map +1 -0
- package/dist/actions/inspect-connect-agent-card.js +15 -0
- package/dist/actions/inspect-connect-agent-card.js.map +1 -0
- package/dist/actions/install-curated-community-app.d.ts +36 -0
- package/dist/actions/install-curated-community-app.d.ts.map +1 -0
- package/dist/actions/install-curated-community-app.js +26 -0
- package/dist/actions/install-curated-community-app.js.map +1 -0
- package/dist/actions/list-connect-marketplace-apps.d.ts +3 -0
- package/dist/actions/list-connect-marketplace-apps.d.ts.map +1 -0
- package/dist/actions/list-connect-marketplace-apps.js +15 -0
- package/dist/actions/list-connect-marketplace-apps.js.map +1 -0
- package/dist/actions/list-connected-agents.d.ts +2 -0
- package/dist/actions/list-curated-community-apps.d.ts +3 -0
- package/dist/actions/list-curated-community-apps.d.ts.map +1 -0
- package/dist/actions/list-curated-community-apps.js +10 -0
- package/dist/actions/list-curated-community-apps.js.map +1 -0
- package/dist/actions/provider-api-register.d.ts +14 -14
- package/dist/actions/remix-workspace-template.d.ts +6 -0
- package/dist/actions/update-workspace-app-metadata.d.ts +1 -0
- package/dist/actions/update-workspace-app-metadata.js +26 -5
- package/dist/actions/update-workspace-app-metadata.js.map +1 -1
- package/dist/components/community-apps-section.d.ts +2 -0
- package/dist/components/community-apps-section.d.ts.map +1 -0
- package/dist/components/community-apps-section.js +90 -0
- package/dist/components/community-apps-section.js.map +1 -0
- package/dist/components/workspace-app-card.d.ts.map +1 -1
- package/dist/components/workspace-app-card.js +63 -9
- package/dist/components/workspace-app-card.js.map +1 -1
- package/dist/lib/connect-apps.d.ts +1 -2
- package/dist/lib/connect-apps.d.ts.map +1 -1
- package/dist/lib/connect-apps.js +41 -65
- package/dist/lib/connect-apps.js.map +1 -1
- package/dist/lib/workspace-apps.d.ts +1 -0
- package/dist/lib/workspace-apps.d.ts.map +1 -1
- package/dist/lib/workspace-apps.js.map +1 -1
- package/dist/routes/pages/apps.d.ts.map +1 -1
- package/dist/routes/pages/apps.js +2 -1
- package/dist/routes/pages/apps.js.map +1 -1
- package/dist/routes/pages/connect.d.ts.map +1 -1
- package/dist/routes/pages/connect.js +5 -7
- package/dist/routes/pages/connect.js.map +1 -1
- package/dist/server/index.d.ts +2 -0
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +2 -0
- package/dist/server/index.js.map +1 -1
- package/dist/server/lib/app-creation-store.d.ts +11 -1
- package/dist/server/lib/app-creation-store.d.ts.map +1 -1
- package/dist/server/lib/app-creation-store.js +258 -39
- package/dist/server/lib/app-creation-store.js.map +1 -1
- package/dist/server/lib/community-apps.d.ts +45 -0
- package/dist/server/lib/community-apps.d.ts.map +1 -0
- package/dist/server/lib/community-apps.js +267 -0
- package/dist/server/lib/community-apps.js.map +1 -0
- package/dist/server/lib/community-source.d.ts +19 -0
- package/dist/server/lib/community-source.d.ts.map +1 -0
- package/dist/server/lib/community-source.js +118 -0
- package/dist/server/lib/community-source.js.map +1 -0
- package/dist/server/lib/connect-apps.d.ts +4 -0
- package/dist/server/lib/connect-apps.d.ts.map +1 -0
- package/dist/server/lib/connect-apps.js +99 -0
- package/dist/server/lib/connect-apps.js.map +1 -0
- package/dist/server/lib/org-apps-directory-cache.d.ts +20 -0
- package/dist/server/lib/org-apps-directory-cache.d.ts.map +1 -0
- package/dist/server/lib/org-apps-directory-cache.js +44 -0
- package/dist/server/lib/org-apps-directory-cache.js.map +1 -0
- package/dist/server/plugins/integrations.js +3 -3
- package/dist/server/plugins/integrations.js.map +1 -1
- package/dist/shared/labs.d.ts +2 -0
- package/dist/shared/labs.d.ts.map +1 -0
- package/dist/shared/labs.js +8 -0
- package/dist/shared/labs.js.map +1 -0
- package/package.json +5 -4
- package/src/actions/connect-external-agent.spec.ts +101 -3
- package/src/actions/connect-external-agent.ts +12 -11
- package/src/actions/index.spec.ts +13 -0
- package/src/actions/index.ts +8 -0
- package/src/actions/inspect-connect-agent-card.ts +17 -0
- package/src/actions/install-curated-community-app.ts +32 -0
- package/src/actions/list-connect-marketplace-apps.ts +17 -0
- package/src/actions/list-curated-community-apps.ts +12 -0
- package/src/actions/update-workspace-app-metadata.spec.ts +25 -0
- package/src/actions/update-workspace-app-metadata.ts +48 -24
- package/src/components/community-apps-section.tsx +224 -0
- package/src/components/workspace-app-card.spec.tsx +226 -1
- package/src/components/workspace-app-card.tsx +115 -12
- package/src/lib/connect-apps.spec.ts +118 -66
- package/src/lib/connect-apps.ts +47 -82
- package/src/lib/workspace-apps.ts +1 -0
- package/src/routes/pages/apps.spec.tsx +201 -1
- package/src/routes/pages/apps.tsx +3 -0
- package/src/routes/pages/connect.spec.tsx +53 -6
- package/src/routes/pages/connect.tsx +14 -11
- package/src/server/index.ts +9 -0
- package/src/server/lib/app-creation-store.spec.ts +539 -11
- package/src/server/lib/app-creation-store.ts +332 -41
- package/src/server/lib/community-apps.spec.ts +367 -0
- package/src/server/lib/community-apps.ts +372 -0
- package/src/server/lib/community-source.spec.ts +151 -0
- package/src/server/lib/community-source.ts +186 -0
- package/src/server/lib/connect-apps.ts +149 -0
- package/src/server/lib/org-apps-directory-cache.spec.ts +71 -0
- package/src/server/lib/org-apps-directory-cache.ts +66 -0
- package/src/server/plugins/integrations.spec.ts +60 -0
- package/src/server/plugins/integrations.ts +3 -3
- package/src/shared/labs.ts +9 -0
|
@@ -7,9 +7,11 @@ import { canonicalA2AAudience, signA2AToken } from "@agent-native/core/a2a";
|
|
|
7
7
|
import { isActionContractError } from "@agent-native/core/action";
|
|
8
8
|
import { describeErrorWithCauses } from "@agent-native/core/agent/engine/error-detail";
|
|
9
9
|
import { getDbExec } from "@agent-native/core/db";
|
|
10
|
+
import { and, eq, inArray } from "@agent-native/core/db/schema";
|
|
10
11
|
import {
|
|
11
12
|
getOrgDomain,
|
|
12
13
|
isWorkspaceAppAccessAllowed,
|
|
14
|
+
workspaceApps,
|
|
13
15
|
} from "@agent-native/core/org";
|
|
14
16
|
import {
|
|
15
17
|
CredentialStoreUnavailableError,
|
|
@@ -39,11 +41,12 @@ import {
|
|
|
39
41
|
assertValidWorkspaceAppId,
|
|
40
42
|
connectRequiredResult,
|
|
41
43
|
normalizeWorkspaceAppHomePath,
|
|
44
|
+
parseAgentProfileMetadata,
|
|
42
45
|
type ConnectRequiredCard,
|
|
43
46
|
} from "@agent-native/core/shared";
|
|
44
47
|
import { resolveAccess } from "@agent-native/core/sharing";
|
|
45
48
|
|
|
46
|
-
import "../../db/index.js";
|
|
49
|
+
import { getDb } from "../../db/index.js";
|
|
47
50
|
import { isWorkspaceSsoAppUrl } from "../../shared/workspace-sso.js";
|
|
48
51
|
import { getDispatchDefaultOwnerEmail } from "./admin-config.js";
|
|
49
52
|
import { identityKeyForIncoming } from "./dispatch-integrations.js";
|
|
@@ -57,6 +60,7 @@ import {
|
|
|
57
60
|
projectEnvironmentUrl,
|
|
58
61
|
requestEnvironmentLane,
|
|
59
62
|
} from "./environment-lane.js";
|
|
63
|
+
import { invalidateOrgAppsDirectoryCache } from "./org-apps-directory-cache.js";
|
|
60
64
|
import { createRequest, listSecretOptions } from "./vault-store.js";
|
|
61
65
|
import { WORKSPACE_APPS_ACTION_PATH } from "./workspace-app-action-auth.js";
|
|
62
66
|
import {
|
|
@@ -69,6 +73,8 @@ const SETTINGS_KEY = "dispatch-app-creation-settings";
|
|
|
69
73
|
const DEFAULT_BUILDER_WORKSPACE_PROJECT_NAME = "Agent-Native Workspace";
|
|
70
74
|
const APP_CREATION_SETTINGS_AUTHORIZATION_MESSAGE =
|
|
71
75
|
"Only organization owners and admins can update app creation settings.";
|
|
76
|
+
const WORKSPACE_APP_METADATA_AUTHORIZATION_MESSAGE =
|
|
77
|
+
"Only organization owners and admins can update workspace app details.";
|
|
72
78
|
const APP_CREATION_SETTINGS_REQUIRED_MESSAGE =
|
|
73
79
|
"An organization owner or admin must configure the Builder workspace project before members can create apps.";
|
|
74
80
|
const WORKSPACE_APP_METADATA_SETTINGS_KEY = "workspace-app-metadata";
|
|
@@ -109,6 +115,26 @@ class AppCreationSettingsAuthorizationError extends Error {
|
|
|
109
115
|
}
|
|
110
116
|
}
|
|
111
117
|
|
|
118
|
+
class WorkspaceAppMetadataAuthorizationError extends Error {
|
|
119
|
+
statusCode = 403;
|
|
120
|
+
|
|
121
|
+
constructor() {
|
|
122
|
+
super(WORKSPACE_APP_METADATA_AUTHORIZATION_MESSAGE);
|
|
123
|
+
this.name = "WorkspaceAppMetadataAuthorizationError";
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
class AppCreationOwnerRoleUnavailableError extends Error {
|
|
128
|
+
statusCode = 503;
|
|
129
|
+
|
|
130
|
+
constructor(cause: unknown) {
|
|
131
|
+
super("Could not verify the organization role. Try again shortly.", {
|
|
132
|
+
cause,
|
|
133
|
+
});
|
|
134
|
+
this.name = "AppCreationOwnerRoleUnavailableError";
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
112
138
|
class WorkspaceAppOrgRequiredError extends Error {
|
|
113
139
|
statusCode = 400;
|
|
114
140
|
|
|
@@ -156,6 +182,8 @@ export interface WorkspaceAppSummary {
|
|
|
156
182
|
id: string;
|
|
157
183
|
name: string;
|
|
158
184
|
description: string;
|
|
185
|
+
whenToUse?: string[];
|
|
186
|
+
communitySourceId?: string;
|
|
159
187
|
path: string;
|
|
160
188
|
homePath?: string;
|
|
161
189
|
url: string | null;
|
|
@@ -233,6 +261,7 @@ interface PendingWorkspaceApp {
|
|
|
233
261
|
contextLabel: string | null;
|
|
234
262
|
audience?: WorkspaceAppAudience;
|
|
235
263
|
visibility?: WorkspaceAppVisibility;
|
|
264
|
+
communitySourceId?: string;
|
|
236
265
|
createdBy?: string | null;
|
|
237
266
|
owner?: string | null;
|
|
238
267
|
teams?: string[];
|
|
@@ -244,12 +273,14 @@ interface PendingWorkspaceApp {
|
|
|
244
273
|
interface WorkspaceAppMetadataOverride {
|
|
245
274
|
name?: string;
|
|
246
275
|
description?: string;
|
|
276
|
+
whenToUse?: string[];
|
|
247
277
|
generated?: boolean;
|
|
248
278
|
sourcePrompt?: string;
|
|
249
279
|
updatedAt?: string;
|
|
250
280
|
updatedBy?: string;
|
|
251
281
|
createdBy?: string;
|
|
252
282
|
visibility?: WorkspaceAppVisibility;
|
|
283
|
+
communitySourceId?: string;
|
|
253
284
|
}
|
|
254
285
|
|
|
255
286
|
interface WorkspaceAppMetadataSettings {
|
|
@@ -379,7 +410,7 @@ function pendingWorkspaceAppContext(): { id: string; label: string } | null {
|
|
|
379
410
|
}
|
|
380
411
|
|
|
381
412
|
async function readSettingsRecord(): Promise<Record<string, any>> {
|
|
382
|
-
const raw = await getSetting(scopedSettingsKey())
|
|
413
|
+
const raw = await getSetting(scopedSettingsKey());
|
|
383
414
|
return raw && typeof raw === "object" && !Array.isArray(raw)
|
|
384
415
|
? (raw as Record<string, any>)
|
|
385
416
|
: {};
|
|
@@ -389,6 +420,17 @@ function cleanOptionalText(value: unknown): string | undefined {
|
|
|
389
420
|
return typeof value === "string" && value.trim() ? value.trim() : undefined;
|
|
390
421
|
}
|
|
391
422
|
|
|
423
|
+
function normalizeCommunitySourceId(value: unknown): string | undefined {
|
|
424
|
+
if (
|
|
425
|
+
typeof value !== "string" ||
|
|
426
|
+
value.length > 100 ||
|
|
427
|
+
!/^community-[a-z0-9]+(?:-[a-z0-9]+)*$/i.test(value)
|
|
428
|
+
) {
|
|
429
|
+
return undefined;
|
|
430
|
+
}
|
|
431
|
+
return value.toLowerCase();
|
|
432
|
+
}
|
|
433
|
+
|
|
392
434
|
function parseWorkspaceAppMetadataSettings(
|
|
393
435
|
raw: unknown,
|
|
394
436
|
): WorkspaceAppMetadataSettings {
|
|
@@ -410,18 +452,29 @@ function parseWorkspaceAppMetadataSettings(
|
|
|
410
452
|
const override: WorkspaceAppMetadataOverride = {};
|
|
411
453
|
const name = cleanOptionalText(item.name);
|
|
412
454
|
const description = cleanOptionalText(item.description);
|
|
455
|
+
const profile = parseAgentProfileMetadata({
|
|
456
|
+
whenToUse: item.whenToUse,
|
|
457
|
+
});
|
|
413
458
|
const sourcePrompt = cleanOptionalText(item.sourcePrompt);
|
|
414
459
|
const updatedAt = cleanOptionalText(item.updatedAt);
|
|
415
460
|
const updatedBy = cleanOptionalText(item.updatedBy);
|
|
416
461
|
const createdBy = cleanOptionalText(item.createdBy);
|
|
462
|
+
const communitySourceId = normalizeCommunitySourceId(
|
|
463
|
+
item.communitySourceId,
|
|
464
|
+
);
|
|
417
465
|
|
|
418
466
|
if (name) override.name = name;
|
|
419
467
|
if (description) override.description = description;
|
|
468
|
+
if (profile?.whenToUse) override.whenToUse = profile.whenToUse;
|
|
469
|
+
else if (Array.isArray(item.whenToUse) && item.whenToUse.length === 0) {
|
|
470
|
+
override.whenToUse = [];
|
|
471
|
+
}
|
|
420
472
|
if (item.generated === true) override.generated = true;
|
|
421
473
|
if (sourcePrompt) override.sourcePrompt = sourcePrompt;
|
|
422
474
|
if (updatedAt) override.updatedAt = updatedAt;
|
|
423
475
|
if (updatedBy) override.updatedBy = updatedBy;
|
|
424
476
|
if (createdBy) override.createdBy = createdBy;
|
|
477
|
+
if (communitySourceId) override.communitySourceId = communitySourceId;
|
|
425
478
|
if (item.visibility === "private" || item.visibility === "org") {
|
|
426
479
|
override.visibility = item.visibility;
|
|
427
480
|
}
|
|
@@ -433,9 +486,7 @@ function parseWorkspaceAppMetadataSettings(
|
|
|
433
486
|
}
|
|
434
487
|
|
|
435
488
|
async function readWorkspaceAppMetadataSettings(): Promise<WorkspaceAppMetadataSettings> {
|
|
436
|
-
const raw = await getSetting(workspaceAppMetadataSettingsKey())
|
|
437
|
-
() => null,
|
|
438
|
-
);
|
|
489
|
+
const raw = await getSetting(workspaceAppMetadataSettingsKey());
|
|
439
490
|
return parseWorkspaceAppMetadataSettings(raw);
|
|
440
491
|
}
|
|
441
492
|
|
|
@@ -443,37 +494,73 @@ async function writeWorkspaceAppMetadataOverride(input: {
|
|
|
443
494
|
appId: string;
|
|
444
495
|
name?: string | null;
|
|
445
496
|
description?: string | null;
|
|
497
|
+
whenToUse?: string[] | null;
|
|
446
498
|
generated?: boolean;
|
|
447
499
|
sourcePrompt?: string | null;
|
|
448
500
|
updatedBy?: string | null;
|
|
449
501
|
createdBy?: string | null;
|
|
450
502
|
visibility?: WorkspaceAppVisibility | null;
|
|
503
|
+
communitySourceId?: string | null;
|
|
451
504
|
}): Promise<WorkspaceAppMetadataSettings> {
|
|
452
505
|
const key = workspaceAppMetadataSettingsKey();
|
|
453
|
-
const current = parseWorkspaceAppMetadataSettings(
|
|
454
|
-
await getSetting(key).catch(() => null),
|
|
455
|
-
);
|
|
506
|
+
const current = parseWorkspaceAppMetadataSettings(await getSetting(key));
|
|
456
507
|
const appId = input.appId.trim();
|
|
457
508
|
const existing = current.apps[appId] ?? {};
|
|
458
509
|
const next: WorkspaceAppMetadataOverride = {
|
|
459
510
|
...existing,
|
|
460
511
|
updatedAt: new Date().toISOString(),
|
|
461
512
|
};
|
|
513
|
+
const hasName = Object.hasOwn(input, "name") && input.name !== undefined;
|
|
514
|
+
const hasDescription =
|
|
515
|
+
Object.hasOwn(input, "description") && input.description !== undefined;
|
|
516
|
+
const hasWhenToUse =
|
|
517
|
+
Object.hasOwn(input, "whenToUse") && input.whenToUse !== undefined;
|
|
462
518
|
const name = cleanOptionalText(input.name);
|
|
463
519
|
const description = cleanOptionalText(input.description);
|
|
520
|
+
const whenToUse = input.whenToUse;
|
|
464
521
|
const sourcePrompt = cleanOptionalText(input.sourcePrompt);
|
|
465
522
|
const updatedBy = cleanOptionalText(input.updatedBy);
|
|
466
523
|
const createdBy = cleanOptionalText(input.createdBy);
|
|
524
|
+
const communitySourceId = normalizeCommunitySourceId(input.communitySourceId);
|
|
467
525
|
|
|
468
|
-
if (
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
526
|
+
if (hasName) {
|
|
527
|
+
if (name) next.name = name;
|
|
528
|
+
else delete next.name;
|
|
529
|
+
}
|
|
530
|
+
if (hasDescription) {
|
|
531
|
+
if (description) next.description = description;
|
|
532
|
+
else delete next.description;
|
|
533
|
+
}
|
|
534
|
+
if (hasWhenToUse) {
|
|
535
|
+
const examples = whenToUse ?? [];
|
|
536
|
+
const profile = parseAgentProfileMetadata({
|
|
537
|
+
description: description ?? next.description,
|
|
538
|
+
whenToUse: examples,
|
|
539
|
+
});
|
|
540
|
+
if (!profile) {
|
|
541
|
+
throw new Error(
|
|
542
|
+
"Workspace app when-to-use entries must contain up to 6 non-empty examples of 140 characters or fewer.",
|
|
543
|
+
);
|
|
544
|
+
}
|
|
545
|
+
next.whenToUse = profile.whenToUse ?? [];
|
|
546
|
+
}
|
|
547
|
+
if (description && description.length > 1000) {
|
|
548
|
+
throw new Error(
|
|
549
|
+
"Workspace app descriptions must be 1,000 characters or fewer.",
|
|
550
|
+
);
|
|
551
|
+
}
|
|
472
552
|
if (input.generated === true) next.generated = true;
|
|
473
553
|
else if (input.generated === false) delete next.generated;
|
|
474
554
|
if (sourcePrompt) next.sourcePrompt = sourcePrompt;
|
|
475
555
|
if (updatedBy) next.updatedBy = updatedBy;
|
|
476
556
|
if (createdBy) next.createdBy = createdBy;
|
|
557
|
+
if (input.communitySourceId !== undefined) {
|
|
558
|
+
if (input.communitySourceId === null || !communitySourceId) {
|
|
559
|
+
delete next.communitySourceId;
|
|
560
|
+
} else {
|
|
561
|
+
next.communitySourceId = communitySourceId;
|
|
562
|
+
}
|
|
563
|
+
}
|
|
477
564
|
if (input.visibility) next.visibility = input.visibility;
|
|
478
565
|
|
|
479
566
|
current.apps[appId] = next;
|
|
@@ -490,18 +577,30 @@ function applyWorkspaceAppMetadataOverride(
|
|
|
490
577
|
|
|
491
578
|
const name = cleanOptionalText(override.name);
|
|
492
579
|
const description = cleanOptionalText(override.description);
|
|
580
|
+
const whenToUse = override.whenToUse;
|
|
493
581
|
const generated = override.generated === true;
|
|
494
582
|
const shouldApplyName = !!name && !generated;
|
|
495
583
|
const shouldApplyDescription =
|
|
496
584
|
!!description && (!generated || !cleanOptionalText(app.description));
|
|
497
585
|
const visibility = override.visibility;
|
|
498
|
-
|
|
586
|
+
const communitySourceId = override.communitySourceId;
|
|
587
|
+
if (
|
|
588
|
+
!shouldApplyName &&
|
|
589
|
+
!shouldApplyDescription &&
|
|
590
|
+
whenToUse === undefined &&
|
|
591
|
+
!visibility &&
|
|
592
|
+
!communitySourceId
|
|
593
|
+
) {
|
|
594
|
+
return app;
|
|
595
|
+
}
|
|
499
596
|
|
|
500
597
|
return {
|
|
501
598
|
...app,
|
|
502
599
|
...(shouldApplyName ? { name } : {}),
|
|
503
600
|
...(shouldApplyDescription ? { description } : {}),
|
|
601
|
+
...(whenToUse !== undefined ? { whenToUse } : {}),
|
|
504
602
|
...(visibility ? { visibility } : {}),
|
|
603
|
+
...(communitySourceId ? { communitySourceId } : {}),
|
|
505
604
|
...(app.status === "pending" &&
|
|
506
605
|
!app.createdBy &&
|
|
507
606
|
(override.createdBy || override.updatedBy)
|
|
@@ -602,8 +701,17 @@ function normalizeWorkspaceAppTeams(value: unknown): string[] {
|
|
|
602
701
|
|
|
603
702
|
function workspaceAppMetadataFromRecord(
|
|
604
703
|
record: Record<string, any>,
|
|
605
|
-
): Pick<
|
|
704
|
+
): Pick<
|
|
705
|
+
WorkspaceAppSummary,
|
|
706
|
+
"createdAt" | "createdBy" | "owner" | "teams" | "whenToUse"
|
|
707
|
+
> {
|
|
606
708
|
const config = record["agent-native"] ?? record.agentNative;
|
|
709
|
+
const profile = parseAgentProfileMetadata({
|
|
710
|
+
whenToUse:
|
|
711
|
+
config && typeof config === "object" && !Array.isArray(config)
|
|
712
|
+
? config.whenToUse
|
|
713
|
+
: undefined,
|
|
714
|
+
});
|
|
607
715
|
const workspaceConfig =
|
|
608
716
|
config && typeof config === "object" && !Array.isArray(config)
|
|
609
717
|
? (config.workspaceApp ?? config.workspace ?? config)
|
|
@@ -651,6 +759,7 @@ function workspaceAppMetadataFromRecord(
|
|
|
651
759
|
workspaceConfig.ownerEmail,
|
|
652
760
|
),
|
|
653
761
|
teams,
|
|
762
|
+
...(profile?.whenToUse ? { whenToUse: profile.whenToUse } : {}),
|
|
654
763
|
};
|
|
655
764
|
}
|
|
656
765
|
|
|
@@ -719,6 +828,10 @@ function parseWorkspaceAppsManifest(parsed: any): WorkspaceAppSummary[] | null {
|
|
|
719
828
|
const id = typeof entry.id === "string" ? entry.id.trim() : "";
|
|
720
829
|
const pathValue = typeof entry.path === "string" ? entry.path.trim() : "";
|
|
721
830
|
if (!id || !pathValue.startsWith("/")) return null;
|
|
831
|
+
const profile = parseAgentProfileMetadata({
|
|
832
|
+
whenToUse: entry.whenToUse,
|
|
833
|
+
});
|
|
834
|
+
if (!profile) return null;
|
|
722
835
|
const metadata = workspaceAppMetadataFromRecord(entry);
|
|
723
836
|
return {
|
|
724
837
|
id,
|
|
@@ -728,6 +841,7 @@ function parseWorkspaceAppsManifest(parsed: any): WorkspaceAppSummary[] | null {
|
|
|
728
841
|
: titleCase(id),
|
|
729
842
|
description:
|
|
730
843
|
typeof entry.description === "string" ? entry.description : "",
|
|
844
|
+
...(profile.whenToUse ? { whenToUse: profile.whenToUse } : {}),
|
|
731
845
|
path: pathValue,
|
|
732
846
|
homePath: normalizeWorkspaceAppHomePath(entry.homePath),
|
|
733
847
|
url: workspaceAppLink(pathValue, entry.url),
|
|
@@ -850,6 +964,9 @@ function parsePendingWorkspaceApps(value: unknown): PendingWorkspaceApp[] {
|
|
|
850
964
|
if (!id || !pathValue.startsWith("/")) return null;
|
|
851
965
|
const now = new Date().toISOString();
|
|
852
966
|
const createdAt = cleanOptionalString(record.createdAt) ?? now;
|
|
967
|
+
const communitySourceId = normalizeCommunitySourceId(
|
|
968
|
+
record.communitySourceId,
|
|
969
|
+
);
|
|
853
970
|
return {
|
|
854
971
|
id,
|
|
855
972
|
name:
|
|
@@ -884,6 +1001,7 @@ function parsePendingWorkspaceApps(value: unknown): PendingWorkspaceApp[] {
|
|
|
884
1001
|
...(record.visibility === "private" || record.visibility === "org"
|
|
885
1002
|
? { visibility: record.visibility }
|
|
886
1003
|
: {}),
|
|
1004
|
+
...(communitySourceId ? { communitySourceId } : {}),
|
|
887
1005
|
createdAt,
|
|
888
1006
|
updatedAt:
|
|
889
1007
|
typeof record.updatedAt === "string" && record.updatedAt.trim()
|
|
@@ -987,11 +1105,13 @@ async function reservePendingWorkspaceApp(input: {
|
|
|
987
1105
|
description: string;
|
|
988
1106
|
projectId: string | null;
|
|
989
1107
|
visibility: WorkspaceAppVisibility;
|
|
1108
|
+
communitySourceId?: string;
|
|
990
1109
|
}): Promise<void> {
|
|
991
1110
|
await assertWorkspaceAppIdRegisteredFree(input.appId);
|
|
992
1111
|
const now = new Date().toISOString();
|
|
993
1112
|
const context = pendingWorkspaceAppContext();
|
|
994
1113
|
const creatorEmail = currentOwnerEmail();
|
|
1114
|
+
const communitySourceId = normalizeCommunitySourceId(input.communitySourceId);
|
|
995
1115
|
|
|
996
1116
|
await mutateSetting(scopedSettingsKey(), async (current) => {
|
|
997
1117
|
const raw =
|
|
@@ -1027,6 +1147,7 @@ async function reservePendingWorkspaceApp(input: {
|
|
|
1027
1147
|
contextId: context?.id ?? null,
|
|
1028
1148
|
contextLabel: context?.label ?? null,
|
|
1029
1149
|
visibility: input.visibility,
|
|
1150
|
+
...(communitySourceId ? { communitySourceId } : {}),
|
|
1030
1151
|
createdBy: creatorEmail,
|
|
1031
1152
|
owner: creatorEmail,
|
|
1032
1153
|
createdAt: now,
|
|
@@ -1083,6 +1204,7 @@ export async function archiveWorkspaceApp(input: {
|
|
|
1083
1204
|
const current = parseArchivedAppIds(raw.archivedAppIds);
|
|
1084
1205
|
if (!current.includes(appId)) current.push(appId);
|
|
1085
1206
|
await putSetting(scopedSettingsKey(), { ...raw, archivedAppIds: current });
|
|
1207
|
+
invalidateOrgAppsDirectoryCache();
|
|
1086
1208
|
await recordAudit({
|
|
1087
1209
|
action: "workspace-app.archived",
|
|
1088
1210
|
targetType: "workspace-app",
|
|
@@ -1102,6 +1224,7 @@ export async function unarchiveWorkspaceApp(input: {
|
|
|
1102
1224
|
(id) => id !== appId,
|
|
1103
1225
|
);
|
|
1104
1226
|
await putSetting(scopedSettingsKey(), { ...raw, archivedAppIds: current });
|
|
1227
|
+
invalidateOrgAppsDirectoryCache();
|
|
1105
1228
|
await recordAudit({
|
|
1106
1229
|
action: "workspace-app.unarchived",
|
|
1107
1230
|
targetType: "workspace-app",
|
|
@@ -1148,6 +1271,7 @@ function pendingAppToSummary(app: PendingWorkspaceApp): WorkspaceAppSummary {
|
|
|
1148
1271
|
status: "pending",
|
|
1149
1272
|
statusLabel: "Pending Builder branch",
|
|
1150
1273
|
visibility: app.visibility,
|
|
1274
|
+
communitySourceId: app.communitySourceId,
|
|
1151
1275
|
builderUrl: app.builderUrl,
|
|
1152
1276
|
branchName: app.branchName,
|
|
1153
1277
|
createdAt: app.createdAt,
|
|
@@ -1590,12 +1714,45 @@ async function filterWorkspaceAppsByAccess(
|
|
|
1590
1714
|
return apps.filter((app) => visibleIds.has(app.id));
|
|
1591
1715
|
}
|
|
1592
1716
|
|
|
1717
|
+
async function filterOrganizationVisibleWorkspaceApps(
|
|
1718
|
+
apps: WorkspaceAppSummary[],
|
|
1719
|
+
orgId: string,
|
|
1720
|
+
): Promise<WorkspaceAppSummary[]> {
|
|
1721
|
+
const readyApps = apps.filter(
|
|
1722
|
+
(app) => app.status === "ready" && !app.archived,
|
|
1723
|
+
);
|
|
1724
|
+
const visibleIds = new Set<string>();
|
|
1725
|
+
const db = getDb();
|
|
1726
|
+
|
|
1727
|
+
for (let start = 0; start < readyApps.length; start += 500) {
|
|
1728
|
+
const batch = readyApps.slice(start, start + 500);
|
|
1729
|
+
const rows = await db
|
|
1730
|
+
.select({ id: workspaceApps.id })
|
|
1731
|
+
.from(workspaceApps)
|
|
1732
|
+
.where(
|
|
1733
|
+
and(
|
|
1734
|
+
eq(workspaceApps.orgId, orgId),
|
|
1735
|
+
eq(workspaceApps.visibility, "org"),
|
|
1736
|
+
eq(workspaceApps.orgEnabled, true),
|
|
1737
|
+
inArray(
|
|
1738
|
+
workspaceApps.id,
|
|
1739
|
+
batch.map((app) => app.id),
|
|
1740
|
+
),
|
|
1741
|
+
),
|
|
1742
|
+
);
|
|
1743
|
+
for (const row of rows) visibleIds.add(row.id);
|
|
1744
|
+
}
|
|
1745
|
+
|
|
1746
|
+
return readyApps.filter((app) => visibleIds.has(app.id));
|
|
1747
|
+
}
|
|
1748
|
+
|
|
1593
1749
|
async function recordPendingWorkspaceApp(input: {
|
|
1594
1750
|
appId: string;
|
|
1595
1751
|
projectId: string | null;
|
|
1596
1752
|
description: string;
|
|
1597
1753
|
sourcePrompt: string;
|
|
1598
1754
|
visibility: WorkspaceAppVisibility;
|
|
1755
|
+
communitySourceId?: string;
|
|
1599
1756
|
branchName?: string | null;
|
|
1600
1757
|
builderUrl?: string | null;
|
|
1601
1758
|
}) {
|
|
@@ -1612,6 +1769,9 @@ async function recordPendingWorkspaceApp(input: {
|
|
|
1612
1769
|
.find(samePendingEntry);
|
|
1613
1770
|
const creatorEmail = currentOwnerEmail();
|
|
1614
1771
|
const existingOwnerEmail = existing?.createdBy ?? existing?.owner;
|
|
1772
|
+
const communitySourceId =
|
|
1773
|
+
normalizeCommunitySourceId(input.communitySourceId) ??
|
|
1774
|
+
normalizeCommunitySourceId(existing?.communitySourceId);
|
|
1615
1775
|
if (
|
|
1616
1776
|
existingOwnerEmail &&
|
|
1617
1777
|
existingOwnerEmail.trim().toLowerCase() !== creatorEmail.toLowerCase()
|
|
@@ -1633,6 +1793,7 @@ async function recordPendingWorkspaceApp(input: {
|
|
|
1633
1793
|
contextId: context?.id ?? null,
|
|
1634
1794
|
contextLabel: context?.label ?? null,
|
|
1635
1795
|
visibility: input.visibility,
|
|
1796
|
+
...(communitySourceId ? { communitySourceId } : {}),
|
|
1636
1797
|
createdBy: existing?.createdBy ?? existing?.owner ?? creatorEmail,
|
|
1637
1798
|
owner: existing?.owner ?? existing?.createdBy ?? creatorEmail,
|
|
1638
1799
|
createdAt: existing?.createdAt || now,
|
|
@@ -1650,12 +1811,14 @@ async function recordPendingWorkspaceApp(input: {
|
|
|
1650
1811
|
|
|
1651
1812
|
await writeWorkspaceAppMetadataOverride({
|
|
1652
1813
|
appId: input.appId,
|
|
1814
|
+
name: null,
|
|
1653
1815
|
description: input.description,
|
|
1654
1816
|
generated: true,
|
|
1655
1817
|
sourcePrompt: input.sourcePrompt,
|
|
1656
1818
|
updatedBy: creatorEmail,
|
|
1657
1819
|
createdBy: next.createdBy,
|
|
1658
1820
|
visibility: input.visibility,
|
|
1821
|
+
communitySourceId,
|
|
1659
1822
|
});
|
|
1660
1823
|
|
|
1661
1824
|
await recordAudit({
|
|
@@ -1989,10 +2152,15 @@ export async function updateWorkspaceAppMetadata(input: {
|
|
|
1989
2152
|
appId: string;
|
|
1990
2153
|
name?: string | null;
|
|
1991
2154
|
description?: string | null;
|
|
2155
|
+
whenToUse?: string[] | null;
|
|
1992
2156
|
}): Promise<WorkspaceAppSummary> {
|
|
1993
2157
|
const appId = input.appId.trim();
|
|
1994
2158
|
assertValidWorkspaceAppId(appId);
|
|
1995
2159
|
requireWorkspaceAppOrgId();
|
|
2160
|
+
const role = await requestOwnerRole();
|
|
2161
|
+
if (role !== "owner" && role !== "admin") {
|
|
2162
|
+
throw new WorkspaceAppMetadataAuthorizationError();
|
|
2163
|
+
}
|
|
1996
2164
|
|
|
1997
2165
|
const apps = await listWorkspaceApps({
|
|
1998
2166
|
includeAgentCards: false,
|
|
@@ -2001,27 +2169,42 @@ export async function updateWorkspaceAppMetadata(input: {
|
|
|
2001
2169
|
const app = apps.find((candidate) => candidate.id === appId);
|
|
2002
2170
|
if (!app) throw new Error(`Workspace app "${appId}" was not found.`);
|
|
2003
2171
|
|
|
2004
|
-
const
|
|
2005
|
-
const
|
|
2006
|
-
input.description
|
|
2007
|
-
|
|
2008
|
-
|
|
2009
|
-
|
|
2172
|
+
const nameProvided = Object.hasOwn(input, "name") && input.name !== undefined;
|
|
2173
|
+
const descriptionProvided =
|
|
2174
|
+
Object.hasOwn(input, "description") && input.description !== undefined;
|
|
2175
|
+
const whenToUseProvided =
|
|
2176
|
+
Object.hasOwn(input, "whenToUse") && input.whenToUse !== undefined;
|
|
2177
|
+
const name = nameProvided ? (input.name?.trim() ?? null) : app.name;
|
|
2178
|
+
const description = descriptionProvided
|
|
2179
|
+
? (input.description?.trim() ?? null)
|
|
2180
|
+
: (app.description ?? undefined);
|
|
2181
|
+
const whenToUse = whenToUseProvided ? (input.whenToUse ?? []) : app.whenToUse;
|
|
2182
|
+
const metadataOverride: Parameters<
|
|
2183
|
+
typeof writeWorkspaceAppMetadataOverride
|
|
2184
|
+
>[0] = {
|
|
2010
2185
|
appId,
|
|
2011
|
-
name,
|
|
2012
|
-
description,
|
|
2013
|
-
generated: false,
|
|
2014
2186
|
updatedBy: currentOwnerEmail(),
|
|
2187
|
+
};
|
|
2188
|
+
if (nameProvided) metadataOverride.name = input.name?.trim() ?? null;
|
|
2189
|
+
if (descriptionProvided) {
|
|
2190
|
+
metadataOverride.description = input.description?.trim() ?? null;
|
|
2191
|
+
}
|
|
2192
|
+
if (whenToUseProvided) metadataOverride.whenToUse = input.whenToUse ?? [];
|
|
2193
|
+
if (nameProvided || descriptionProvided) metadataOverride.generated = false;
|
|
2194
|
+
await writeWorkspaceAppMetadataOverride({
|
|
2195
|
+
...metadataOverride,
|
|
2015
2196
|
});
|
|
2197
|
+
invalidateOrgAppsDirectoryCache();
|
|
2016
2198
|
|
|
2017
2199
|
await recordAudit({
|
|
2018
2200
|
action: "workspace-app.metadata-updated",
|
|
2019
2201
|
targetType: "workspace-app",
|
|
2020
2202
|
targetId: appId,
|
|
2021
|
-
summary: `Updated workspace app details for ${name}`,
|
|
2203
|
+
summary: `Updated workspace app details for ${name ?? app.name}`,
|
|
2022
2204
|
metadata: {
|
|
2023
|
-
name,
|
|
2205
|
+
name: name ?? app.name,
|
|
2024
2206
|
descriptionConfigured: !!description,
|
|
2207
|
+
whenToUseCount: whenToUse?.length ?? 0,
|
|
2025
2208
|
},
|
|
2026
2209
|
});
|
|
2027
2210
|
|
|
@@ -2031,11 +2214,19 @@ export async function updateWorkspaceAppMetadata(input: {
|
|
|
2031
2214
|
includeArchived: true,
|
|
2032
2215
|
})
|
|
2033
2216
|
).find((candidate) => candidate.id === appId);
|
|
2034
|
-
return
|
|
2217
|
+
return (
|
|
2218
|
+
updated ?? {
|
|
2219
|
+
...app,
|
|
2220
|
+
name: name ?? app.name,
|
|
2221
|
+
description: description ?? app.description,
|
|
2222
|
+
whenToUse,
|
|
2223
|
+
}
|
|
2224
|
+
);
|
|
2035
2225
|
}
|
|
2036
2226
|
|
|
2037
|
-
|
|
2227
|
+
async function listWorkspaceAppsWithPrincipal(
|
|
2038
2228
|
options: ListWorkspaceAppsOptions = {},
|
|
2229
|
+
principal: "user" | "organization" = "user",
|
|
2039
2230
|
): Promise<WorkspaceAppSummary[]> {
|
|
2040
2231
|
const finalize = async (
|
|
2041
2232
|
apps: WorkspaceAppSummary[],
|
|
@@ -2048,9 +2239,14 @@ export async function listWorkspaceApps(
|
|
|
2048
2239
|
const listed = options.includeArchived
|
|
2049
2240
|
? recorded
|
|
2050
2241
|
: recorded.filter((app) => !app.archived);
|
|
2051
|
-
const
|
|
2052
|
-
|
|
2053
|
-
|
|
2242
|
+
const candidates = filterAppsByAudience(listed, options.audience);
|
|
2243
|
+
const visible =
|
|
2244
|
+
principal === "organization"
|
|
2245
|
+
? await filterOrganizationVisibleWorkspaceApps(
|
|
2246
|
+
candidates,
|
|
2247
|
+
requireWorkspaceAppOrgId(),
|
|
2248
|
+
)
|
|
2249
|
+
: await filterWorkspaceAppsByAccess(candidates);
|
|
2054
2250
|
return maybeIncludeAgentCards(visible, options);
|
|
2055
2251
|
};
|
|
2056
2252
|
let gatewayDenial: WorkspaceAppsGatewayAuthorizationError | null = null;
|
|
@@ -2117,6 +2313,22 @@ export async function listWorkspaceApps(
|
|
|
2117
2313
|
return finalize([], { persist: !unverified });
|
|
2118
2314
|
}
|
|
2119
2315
|
|
|
2316
|
+
export function listWorkspaceApps(
|
|
2317
|
+
options: ListWorkspaceAppsOptions = {},
|
|
2318
|
+
): Promise<WorkspaceAppSummary[]> {
|
|
2319
|
+
return listWorkspaceAppsWithPrincipal(options, "user");
|
|
2320
|
+
}
|
|
2321
|
+
|
|
2322
|
+
export async function listOrganizationVisibleWorkspaceApps(): Promise<
|
|
2323
|
+
WorkspaceAppSummary[]
|
|
2324
|
+
> {
|
|
2325
|
+
requireWorkspaceAppOrgId();
|
|
2326
|
+
return listWorkspaceAppsWithPrincipal(
|
|
2327
|
+
{ includeAgentCards: false, includeArchived: false, audience: "all" },
|
|
2328
|
+
"organization",
|
|
2329
|
+
);
|
|
2330
|
+
}
|
|
2331
|
+
|
|
2120
2332
|
const ADDABLE_TEMPLATES: AvailableWorkspaceTemplate[] = [
|
|
2121
2333
|
{
|
|
2122
2334
|
name: "mail",
|
|
@@ -2282,6 +2494,8 @@ export async function scaffoldWorkspaceAppFromTemplate(input: {
|
|
|
2282
2494
|
try {
|
|
2283
2495
|
await writeWorkspaceAppMetadataOverride({
|
|
2284
2496
|
appId,
|
|
2497
|
+
name: null,
|
|
2498
|
+
description: null,
|
|
2285
2499
|
updatedBy: creatorEmail,
|
|
2286
2500
|
createdBy: creatorEmail,
|
|
2287
2501
|
visibility,
|
|
@@ -2318,6 +2532,7 @@ export async function scaffoldWorkspaceAppFromTemplate(input: {
|
|
|
2318
2532
|
visibility,
|
|
2319
2533
|
},
|
|
2320
2534
|
]);
|
|
2535
|
+
invalidateOrgAppsDirectoryCache();
|
|
2321
2536
|
|
|
2322
2537
|
return { appId, template, output };
|
|
2323
2538
|
}
|
|
@@ -2512,8 +2727,8 @@ async function requestOwnerRole(): Promise<string | null> {
|
|
|
2512
2727
|
});
|
|
2513
2728
|
const role = (rows[0] as any)?.role;
|
|
2514
2729
|
return typeof role === "string" ? role : null;
|
|
2515
|
-
} catch {
|
|
2516
|
-
|
|
2730
|
+
} catch (error) {
|
|
2731
|
+
throw new AppCreationOwnerRoleUnavailableError(error);
|
|
2517
2732
|
}
|
|
2518
2733
|
}
|
|
2519
2734
|
|
|
@@ -2853,6 +3068,12 @@ export interface AppCreationLocalAgentResult {
|
|
|
2853
3068
|
appId: string;
|
|
2854
3069
|
prompt: string;
|
|
2855
3070
|
message: string;
|
|
3071
|
+
attachments?: Array<{
|
|
3072
|
+
type: "file";
|
|
3073
|
+
name: string;
|
|
3074
|
+
contentType: string;
|
|
3075
|
+
text: string;
|
|
3076
|
+
}>;
|
|
2856
3077
|
}
|
|
2857
3078
|
|
|
2858
3079
|
export interface AppCreationComingSoonResult {
|
|
@@ -2897,6 +3118,7 @@ export async function startWorkspaceAppCreation(input: {
|
|
|
2897
3118
|
secretIds?: string[];
|
|
2898
3119
|
resourceIds?: string[];
|
|
2899
3120
|
attachments?: BuilderAgentAttachment[];
|
|
3121
|
+
communitySourceId?: string;
|
|
2900
3122
|
}): Promise<StartWorkspaceAppCreationResult> {
|
|
2901
3123
|
const initial = buildWorkspaceAppPrompt({
|
|
2902
3124
|
prompt: input.prompt,
|
|
@@ -2904,6 +3126,12 @@ export async function startWorkspaceAppCreation(input: {
|
|
|
2904
3126
|
description: input.description,
|
|
2905
3127
|
template: input.template,
|
|
2906
3128
|
});
|
|
3129
|
+
if (
|
|
3130
|
+
input.communitySourceId !== undefined &&
|
|
3131
|
+
!normalizeCommunitySourceId(input.communitySourceId)
|
|
3132
|
+
) {
|
|
3133
|
+
throw new Error("Community source ids must be valid bounded identifiers.");
|
|
3134
|
+
}
|
|
2907
3135
|
assertValidWorkspaceAppId(initial.appId);
|
|
2908
3136
|
requireWorkspaceAppOrgId();
|
|
2909
3137
|
normalizeBuilderAgentAttachments(input.attachments);
|
|
@@ -2955,15 +3183,39 @@ export async function startWorkspaceAppCreation(input: {
|
|
|
2955
3183
|
generateWorkspaceAppDescription(input.prompt, built.appId);
|
|
2956
3184
|
|
|
2957
3185
|
if (isLocal) {
|
|
2958
|
-
|
|
2959
|
-
|
|
2960
|
-
|
|
2961
|
-
|
|
2962
|
-
|
|
2963
|
-
|
|
2964
|
-
|
|
2965
|
-
|
|
2966
|
-
|
|
3186
|
+
if (input.communitySourceId) {
|
|
3187
|
+
try {
|
|
3188
|
+
await reservePendingWorkspaceApp({
|
|
3189
|
+
appId: built.appId,
|
|
3190
|
+
description: appDescription,
|
|
3191
|
+
projectId: null,
|
|
3192
|
+
visibility: creationVisibility,
|
|
3193
|
+
communitySourceId: input.communitySourceId,
|
|
3194
|
+
});
|
|
3195
|
+
} catch (err) {
|
|
3196
|
+
if (err instanceof WorkspaceAppIdTakenError)
|
|
3197
|
+
return appIdTakenResult(err);
|
|
3198
|
+
throw err;
|
|
3199
|
+
}
|
|
3200
|
+
}
|
|
3201
|
+
try {
|
|
3202
|
+
await writeWorkspaceAppMetadataOverride({
|
|
3203
|
+
appId: built.appId,
|
|
3204
|
+
name: null,
|
|
3205
|
+
description: appDescription,
|
|
3206
|
+
generated: true,
|
|
3207
|
+
sourcePrompt: input.prompt,
|
|
3208
|
+
updatedBy: currentOwnerEmail(),
|
|
3209
|
+
createdBy: currentOwnerEmail(),
|
|
3210
|
+
visibility: creationVisibility,
|
|
3211
|
+
communitySourceId: input.communitySourceId,
|
|
3212
|
+
});
|
|
3213
|
+
} catch (error) {
|
|
3214
|
+
if (input.communitySourceId) {
|
|
3215
|
+
await releasePendingWorkspaceAppReservation(built.appId);
|
|
3216
|
+
}
|
|
3217
|
+
throw error;
|
|
3218
|
+
}
|
|
2967
3219
|
await requestSelectedVaultKeys({
|
|
2968
3220
|
appId: built.appId,
|
|
2969
3221
|
selectedKeys,
|
|
@@ -2976,6 +3228,22 @@ export async function startWorkspaceAppCreation(input: {
|
|
|
2976
3228
|
mode: "local-agent",
|
|
2977
3229
|
appId: built.appId,
|
|
2978
3230
|
prompt,
|
|
3231
|
+
...(input.communitySourceId && input.attachments?.length
|
|
3232
|
+
? {
|
|
3233
|
+
attachments: input.attachments.flatMap((attachment) =>
|
|
3234
|
+
attachment.type === "upload" && attachment.text !== undefined
|
|
3235
|
+
? [
|
|
3236
|
+
{
|
|
3237
|
+
type: "file" as const,
|
|
3238
|
+
name: attachment.name,
|
|
3239
|
+
contentType: attachment.contentType,
|
|
3240
|
+
text: attachment.text,
|
|
3241
|
+
},
|
|
3242
|
+
]
|
|
3243
|
+
: [],
|
|
3244
|
+
),
|
|
3245
|
+
}
|
|
3246
|
+
: {}),
|
|
2979
3247
|
message:
|
|
2980
3248
|
"Use the local code agent to create this app in the workspace, then open it from /dispatch/apps.",
|
|
2981
3249
|
};
|
|
@@ -3018,12 +3286,34 @@ export async function startWorkspaceAppCreation(input: {
|
|
|
3018
3286
|
description: appDescription,
|
|
3019
3287
|
projectId: builderProjectId,
|
|
3020
3288
|
visibility: creationVisibility,
|
|
3289
|
+
...(normalizeCommunitySourceId(input.communitySourceId)
|
|
3290
|
+
? { communitySourceId: input.communitySourceId }
|
|
3291
|
+
: {}),
|
|
3021
3292
|
});
|
|
3022
3293
|
} catch (err) {
|
|
3023
3294
|
if (err instanceof WorkspaceAppIdTakenError) return appIdTakenResult(err);
|
|
3024
3295
|
throw err;
|
|
3025
3296
|
}
|
|
3026
3297
|
|
|
3298
|
+
if (input.communitySourceId) {
|
|
3299
|
+
try {
|
|
3300
|
+
await writeWorkspaceAppMetadataOverride({
|
|
3301
|
+
appId: built.appId,
|
|
3302
|
+
communitySourceId: input.communitySourceId,
|
|
3303
|
+
});
|
|
3304
|
+
} catch (error) {
|
|
3305
|
+
try {
|
|
3306
|
+
await releasePendingWorkspaceAppReservation(built.appId);
|
|
3307
|
+
} catch (cleanupError) {
|
|
3308
|
+
console.warn(
|
|
3309
|
+
"[dispatch] failed to release pending workspace app reservation",
|
|
3310
|
+
cleanupError,
|
|
3311
|
+
);
|
|
3312
|
+
}
|
|
3313
|
+
throw error;
|
|
3314
|
+
}
|
|
3315
|
+
}
|
|
3316
|
+
|
|
3027
3317
|
let result: {
|
|
3028
3318
|
branchName: string;
|
|
3029
3319
|
url: string;
|
|
@@ -3063,6 +3353,7 @@ export async function startWorkspaceAppCreation(input: {
|
|
|
3063
3353
|
description: appDescription,
|
|
3064
3354
|
sourcePrompt: input.prompt,
|
|
3065
3355
|
visibility: creationVisibility,
|
|
3356
|
+
communitySourceId: input.communitySourceId,
|
|
3066
3357
|
branchName: result.branchName,
|
|
3067
3358
|
builderUrl: result.url,
|
|
3068
3359
|
});
|