@opengeni/contracts 0.26.1 → 0.28.1
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/dist/artifacts.d.ts +303 -0
- package/dist/{chunk-ESXP7QLV.js → chunk-3Q5FLMOD.js} +2907 -2679
- package/dist/chunk-3Q5FLMOD.js.map +1 -0
- package/dist/{chunk-3B3XEYMN.js → chunk-KGL5BVGF.js} +3 -1
- package/dist/chunk-KGL5BVGF.js.map +1 -0
- package/dist/google-drive.js +2 -2
- package/dist/index.d.ts +215 -8
- package/dist/index.js +54 -2
- package/dist/slack-bot-scopes.d.ts +1 -1
- package/dist/slack-bot-scopes.js +1 -1
- package/package.json +1 -1
- package/src/artifacts.ts +171 -0
- package/src/index.ts +163 -9
- package/src/slack-bot-scopes.ts +2 -0
- package/dist/chunk-3B3XEYMN.js.map +0 -1
- package/dist/chunk-ESXP7QLV.js.map +0 -1
package/dist/index.js
CHANGED
|
@@ -75,6 +75,7 @@ import {
|
|
|
75
75
|
CreateSocialConnectionRequest,
|
|
76
76
|
CreateSocialPostRequest,
|
|
77
77
|
CreateVariableSetRequest,
|
|
78
|
+
CreateWorkspaceArtifactRequest,
|
|
78
79
|
CreateWorkspaceEnvironmentRequest,
|
|
79
80
|
CreateWorkspaceInstructionPolicyDraftRequest,
|
|
80
81
|
CreateWorkspaceRequest,
|
|
@@ -311,6 +312,7 @@ import {
|
|
|
311
312
|
PtyOpenResponse,
|
|
312
313
|
PtyResizeRequest,
|
|
313
314
|
PtyWriteRequest,
|
|
315
|
+
PublishWorkspaceArtifactVersionRequest,
|
|
314
316
|
RETAINED_OUTPUT_DEFAULT_PAGE_BYTES,
|
|
315
317
|
RETAINED_OUTPUT_MAX_PAGE_BYTES,
|
|
316
318
|
RETAINED_OUTPUT_RECEIPT_MAX_BYTES,
|
|
@@ -348,6 +350,7 @@ import {
|
|
|
348
350
|
RigSetupAppendPayload,
|
|
349
351
|
RigVerificationHealth,
|
|
350
352
|
RigVersion,
|
|
353
|
+
RollbackWorkspaceArtifactRequest,
|
|
351
354
|
RollbackWorkspaceInstructionPolicyRequest,
|
|
352
355
|
SESSION_AUTHORIZATION_LIST_SCOPE_MAX_IDS,
|
|
353
356
|
SESSION_EFFECTIVE_TOOL_POLICY_ID_LIMIT,
|
|
@@ -440,6 +443,8 @@ import {
|
|
|
440
443
|
SetWorkspaceEnvironmentVariableRequest,
|
|
441
444
|
SocialConnection,
|
|
442
445
|
SocialConnectionStatus,
|
|
446
|
+
SocialOAuthProviderId,
|
|
447
|
+
SocialOAuthStartRequest,
|
|
443
448
|
SocialPost,
|
|
444
449
|
SocialProvider,
|
|
445
450
|
StaticUsageLimits,
|
|
@@ -510,6 +515,12 @@ import {
|
|
|
510
515
|
ViewerHolder,
|
|
511
516
|
VoiceInputErrorCode,
|
|
512
517
|
WORKSPACE_ARCHIVE_DESCRIPTOR_VERSION,
|
|
518
|
+
WORKSPACE_ARTIFACT_CURSOR_MAX_CHARS,
|
|
519
|
+
WORKSPACE_ARTIFACT_DESCRIPTION_MAX_CHARS,
|
|
520
|
+
WORKSPACE_ARTIFACT_HTML_MAX_UTF8_BYTES,
|
|
521
|
+
WORKSPACE_ARTIFACT_LIST_DEFAULT,
|
|
522
|
+
WORKSPACE_ARTIFACT_LIST_MAX,
|
|
523
|
+
WORKSPACE_ARTIFACT_TITLE_MAX_CHARS,
|
|
513
524
|
WORKSPACE_CONTROL_ACTOR_MAX_BYTES,
|
|
514
525
|
WORKSPACE_CONTROL_EVENT_MAX_BYTES,
|
|
515
526
|
WORKSPACE_CONTROL_REASON_MAX_BYTES,
|
|
@@ -525,6 +536,18 @@ import {
|
|
|
525
536
|
WORKSPACE_STATE_MEMORY_SAMPLE_LIMIT,
|
|
526
537
|
WORKSPACE_STATE_TOPIC_MAX_CHARS,
|
|
527
538
|
Workspace,
|
|
539
|
+
WorkspaceArtifact,
|
|
540
|
+
WorkspaceArtifactContentResponse,
|
|
541
|
+
WorkspaceArtifactDetailResponse,
|
|
542
|
+
WorkspaceArtifactEvent,
|
|
543
|
+
WorkspaceArtifactEventType,
|
|
544
|
+
WorkspaceArtifactHtml,
|
|
545
|
+
WorkspaceArtifactListQuery,
|
|
546
|
+
WorkspaceArtifactListResponse,
|
|
547
|
+
WorkspaceArtifactMutationResponse,
|
|
548
|
+
WorkspaceArtifactSlug,
|
|
549
|
+
WorkspaceArtifactStatus,
|
|
550
|
+
WorkspaceArtifactVersion,
|
|
528
551
|
WorkspaceCaptureDegradedReason,
|
|
529
552
|
WorkspaceCaptureFile,
|
|
530
553
|
WorkspaceCaptureManifest,
|
|
@@ -599,6 +622,7 @@ import {
|
|
|
599
622
|
capabilityCatalogItemIsTrustedForExposure,
|
|
600
623
|
compactSessionEventResult,
|
|
601
624
|
compareCodexFleetCanonicalStringsV1,
|
|
625
|
+
comparePersonalSlackCanonicalConnections,
|
|
602
626
|
createCodexFleetReplayRecordV1,
|
|
603
627
|
createSecretRedactor,
|
|
604
628
|
decodeNativeSnapshotRef,
|
|
@@ -620,6 +644,7 @@ import {
|
|
|
620
644
|
normalizePreferenceRegistryStableKey,
|
|
621
645
|
normalizeRepositorySubpath,
|
|
622
646
|
normalizeResourceMountPath,
|
|
647
|
+
normalizeWorkspaceArtifactSlug,
|
|
623
648
|
normalizeWorkspaceInstructionPolicyRoleKey,
|
|
624
649
|
parseWorkspaceArchiveDescriptor,
|
|
625
650
|
prefixedMcpToolName,
|
|
@@ -642,6 +667,7 @@ import {
|
|
|
642
667
|
resourceMountPathCollisionKey,
|
|
643
668
|
retainedArtifactReferenceFromFile,
|
|
644
669
|
retainedOutputUnavailable,
|
|
670
|
+
selectCanonicalPersonalSlackConnection,
|
|
645
671
|
sessionEventJsonBytes,
|
|
646
672
|
sessionEventLatestClassToSemanticClass,
|
|
647
673
|
sessionEventMediaPreview,
|
|
@@ -662,14 +688,14 @@ import {
|
|
|
662
688
|
verifyRelayToken,
|
|
663
689
|
verifyStreamToken,
|
|
664
690
|
workspaceControlUtf8Bytes
|
|
665
|
-
} from "./chunk-
|
|
691
|
+
} from "./chunk-3Q5FLMOD.js";
|
|
666
692
|
import {
|
|
667
693
|
OPENGENI_SLACK_BOT_FORBIDDEN_SCOPES,
|
|
668
694
|
OPENGENI_SLACK_BOT_REQUIRED_SCOPES,
|
|
669
695
|
OPENGENI_SLACK_BOT_SAFE_OPTIONAL_SCOPES,
|
|
670
696
|
areOpenGeniSlackBotScopesAccepted,
|
|
671
697
|
evaluateOpenGeniSlackBotScopes
|
|
672
|
-
} from "./chunk-
|
|
698
|
+
} from "./chunk-KGL5BVGF.js";
|
|
673
699
|
export {
|
|
674
700
|
AccessContext,
|
|
675
701
|
AccessGrant,
|
|
@@ -747,6 +773,7 @@ export {
|
|
|
747
773
|
CreateSocialConnectionRequest,
|
|
748
774
|
CreateSocialPostRequest,
|
|
749
775
|
CreateVariableSetRequest,
|
|
776
|
+
CreateWorkspaceArtifactRequest,
|
|
750
777
|
CreateWorkspaceEnvironmentRequest,
|
|
751
778
|
CreateWorkspaceInstructionPolicyDraftRequest,
|
|
752
779
|
CreateWorkspaceRequest,
|
|
@@ -986,6 +1013,7 @@ export {
|
|
|
986
1013
|
PtyOpenResponse,
|
|
987
1014
|
PtyResizeRequest,
|
|
988
1015
|
PtyWriteRequest,
|
|
1016
|
+
PublishWorkspaceArtifactVersionRequest,
|
|
989
1017
|
RETAINED_OUTPUT_DEFAULT_PAGE_BYTES,
|
|
990
1018
|
RETAINED_OUTPUT_MAX_PAGE_BYTES,
|
|
991
1019
|
RETAINED_OUTPUT_RECEIPT_MAX_BYTES,
|
|
@@ -1023,6 +1051,7 @@ export {
|
|
|
1023
1051
|
RigSetupAppendPayload,
|
|
1024
1052
|
RigVerificationHealth,
|
|
1025
1053
|
RigVersion,
|
|
1054
|
+
RollbackWorkspaceArtifactRequest,
|
|
1026
1055
|
RollbackWorkspaceInstructionPolicyRequest,
|
|
1027
1056
|
SESSION_AUTHORIZATION_LIST_SCOPE_MAX_IDS,
|
|
1028
1057
|
SESSION_EFFECTIVE_TOOL_POLICY_ID_LIMIT,
|
|
@@ -1115,6 +1144,8 @@ export {
|
|
|
1115
1144
|
SetWorkspaceEnvironmentVariableRequest,
|
|
1116
1145
|
SocialConnection,
|
|
1117
1146
|
SocialConnectionStatus,
|
|
1147
|
+
SocialOAuthProviderId,
|
|
1148
|
+
SocialOAuthStartRequest,
|
|
1118
1149
|
SocialPost,
|
|
1119
1150
|
SocialProvider,
|
|
1120
1151
|
StaticUsageLimits,
|
|
@@ -1185,6 +1216,12 @@ export {
|
|
|
1185
1216
|
ViewerHolder,
|
|
1186
1217
|
VoiceInputErrorCode,
|
|
1187
1218
|
WORKSPACE_ARCHIVE_DESCRIPTOR_VERSION,
|
|
1219
|
+
WORKSPACE_ARTIFACT_CURSOR_MAX_CHARS,
|
|
1220
|
+
WORKSPACE_ARTIFACT_DESCRIPTION_MAX_CHARS,
|
|
1221
|
+
WORKSPACE_ARTIFACT_HTML_MAX_UTF8_BYTES,
|
|
1222
|
+
WORKSPACE_ARTIFACT_LIST_DEFAULT,
|
|
1223
|
+
WORKSPACE_ARTIFACT_LIST_MAX,
|
|
1224
|
+
WORKSPACE_ARTIFACT_TITLE_MAX_CHARS,
|
|
1188
1225
|
WORKSPACE_CONTROL_ACTOR_MAX_BYTES,
|
|
1189
1226
|
WORKSPACE_CONTROL_EVENT_MAX_BYTES,
|
|
1190
1227
|
WORKSPACE_CONTROL_REASON_MAX_BYTES,
|
|
@@ -1200,6 +1237,18 @@ export {
|
|
|
1200
1237
|
WORKSPACE_STATE_MEMORY_SAMPLE_LIMIT,
|
|
1201
1238
|
WORKSPACE_STATE_TOPIC_MAX_CHARS,
|
|
1202
1239
|
Workspace,
|
|
1240
|
+
WorkspaceArtifact,
|
|
1241
|
+
WorkspaceArtifactContentResponse,
|
|
1242
|
+
WorkspaceArtifactDetailResponse,
|
|
1243
|
+
WorkspaceArtifactEvent,
|
|
1244
|
+
WorkspaceArtifactEventType,
|
|
1245
|
+
WorkspaceArtifactHtml,
|
|
1246
|
+
WorkspaceArtifactListQuery,
|
|
1247
|
+
WorkspaceArtifactListResponse,
|
|
1248
|
+
WorkspaceArtifactMutationResponse,
|
|
1249
|
+
WorkspaceArtifactSlug,
|
|
1250
|
+
WorkspaceArtifactStatus,
|
|
1251
|
+
WorkspaceArtifactVersion,
|
|
1203
1252
|
WorkspaceCaptureDegradedReason,
|
|
1204
1253
|
WorkspaceCaptureFile,
|
|
1205
1254
|
WorkspaceCaptureManifest,
|
|
@@ -1275,6 +1324,7 @@ export {
|
|
|
1275
1324
|
capabilityCatalogItemIsTrustedForExposure,
|
|
1276
1325
|
compactSessionEventResult,
|
|
1277
1326
|
compareCodexFleetCanonicalStringsV1,
|
|
1327
|
+
comparePersonalSlackCanonicalConnections,
|
|
1278
1328
|
createCodexFleetReplayRecordV1,
|
|
1279
1329
|
createSecretRedactor,
|
|
1280
1330
|
decodeNativeSnapshotRef,
|
|
@@ -1297,6 +1347,7 @@ export {
|
|
|
1297
1347
|
normalizePreferenceRegistryStableKey,
|
|
1298
1348
|
normalizeRepositorySubpath,
|
|
1299
1349
|
normalizeResourceMountPath,
|
|
1350
|
+
normalizeWorkspaceArtifactSlug,
|
|
1300
1351
|
normalizeWorkspaceInstructionPolicyRoleKey,
|
|
1301
1352
|
parseWorkspaceArchiveDescriptor,
|
|
1302
1353
|
prefixedMcpToolName,
|
|
@@ -1319,6 +1370,7 @@ export {
|
|
|
1319
1370
|
resourceMountPathCollisionKey,
|
|
1320
1371
|
retainedArtifactReferenceFromFile,
|
|
1321
1372
|
retainedOutputUnavailable,
|
|
1373
|
+
selectCanonicalPersonalSlackConnection,
|
|
1322
1374
|
sessionEventJsonBytes,
|
|
1323
1375
|
sessionEventLatestClassToSemanticClass,
|
|
1324
1376
|
sessionEventMediaPreview,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export declare const OPENGENI_SLACK_BOT_REQUIRED_SCOPES: readonly ["canvases:read", "channels:history", "channels:read", "chat:write", "files:read", "groups:history", "groups:read", "im:history", "im:read", "im:write", "mpim:history", "mpim:read", "users:read"];
|
|
1
|
+
export declare const OPENGENI_SLACK_BOT_REQUIRED_SCOPES: readonly ["app_mentions:read", "canvases:read", "channels:history", "channels:read", "chat:write", "commands", "files:read", "groups:history", "groups:read", "im:history", "im:read", "im:write", "mpim:history", "mpim:read", "users:read"];
|
|
2
2
|
/**
|
|
3
3
|
* Optional bot grants that remain inside the shipped bot's read/identity
|
|
4
4
|
* boundary. Every other unrequired scope fails closed, including unknown future
|
package/dist/slack-bot-scopes.js
CHANGED
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
OPENGENI_SLACK_BOT_SAFE_OPTIONAL_SCOPES,
|
|
5
5
|
areOpenGeniSlackBotScopesAccepted,
|
|
6
6
|
evaluateOpenGeniSlackBotScopes
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-KGL5BVGF.js";
|
|
8
8
|
export {
|
|
9
9
|
OPENGENI_SLACK_BOT_FORBIDDEN_SCOPES,
|
|
10
10
|
OPENGENI_SLACK_BOT_REQUIRED_SCOPES,
|
package/package.json
CHANGED
package/src/artifacts.ts
ADDED
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
|
|
3
|
+
export const WORKSPACE_ARTIFACT_HTML_MAX_UTF8_BYTES = 512 * 1024;
|
|
4
|
+
export const WORKSPACE_ARTIFACT_TITLE_MAX_CHARS = 120;
|
|
5
|
+
export const WORKSPACE_ARTIFACT_DESCRIPTION_MAX_CHARS = 2_000;
|
|
6
|
+
export const WORKSPACE_ARTIFACT_LIST_MAX = 100;
|
|
7
|
+
export const WORKSPACE_ARTIFACT_LIST_DEFAULT = 50;
|
|
8
|
+
export const WORKSPACE_ARTIFACT_CURSOR_MAX_CHARS = 512;
|
|
9
|
+
|
|
10
|
+
const encoder = new TextEncoder();
|
|
11
|
+
const sha256 = z.string().regex(/^[0-9a-f]{64}$/);
|
|
12
|
+
|
|
13
|
+
export const WorkspaceArtifactSlug = z
|
|
14
|
+
.string()
|
|
15
|
+
.trim()
|
|
16
|
+
.min(1)
|
|
17
|
+
.max(96)
|
|
18
|
+
.regex(/^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/);
|
|
19
|
+
export type WorkspaceArtifactSlug = z.infer<typeof WorkspaceArtifactSlug>;
|
|
20
|
+
|
|
21
|
+
export const WorkspaceArtifactStatus = z.enum(["active", "archived"]);
|
|
22
|
+
export type WorkspaceArtifactStatus = z.infer<typeof WorkspaceArtifactStatus>;
|
|
23
|
+
|
|
24
|
+
export const WorkspaceArtifactVersion = z.object({
|
|
25
|
+
id: z.string().uuid(),
|
|
26
|
+
accountId: z.string().uuid(),
|
|
27
|
+
workspaceId: z.string().uuid(),
|
|
28
|
+
artifactId: z.string().uuid(),
|
|
29
|
+
revision: z.number().int().positive(),
|
|
30
|
+
contentType: z.literal("text/html"),
|
|
31
|
+
contentSha256: sha256,
|
|
32
|
+
sizeBytes: z.number().int().positive().max(WORKSPACE_ARTIFACT_HTML_MAX_UTF8_BYTES),
|
|
33
|
+
sourceSessionId: z.string().uuid().nullable(),
|
|
34
|
+
sourceTurnId: z.string().uuid().nullable(),
|
|
35
|
+
sourceAttemptId: z.string().uuid().nullable(),
|
|
36
|
+
sourceExecutionGeneration: z.number().int().positive().nullable(),
|
|
37
|
+
createdBySubjectId: z.string().min(1).max(1024),
|
|
38
|
+
createdAt: z.string().datetime({ offset: true }),
|
|
39
|
+
});
|
|
40
|
+
export type WorkspaceArtifactVersion = z.infer<typeof WorkspaceArtifactVersion>;
|
|
41
|
+
|
|
42
|
+
export const WorkspaceArtifact = z.object({
|
|
43
|
+
id: z.string().uuid(),
|
|
44
|
+
accountId: z.string().uuid(),
|
|
45
|
+
workspaceId: z.string().uuid(),
|
|
46
|
+
slug: WorkspaceArtifactSlug,
|
|
47
|
+
title: z.string().trim().min(1).max(WORKSPACE_ARTIFACT_TITLE_MAX_CHARS),
|
|
48
|
+
description: z.string().max(WORKSPACE_ARTIFACT_DESCRIPTION_MAX_CHARS).nullable(),
|
|
49
|
+
status: WorkspaceArtifactStatus,
|
|
50
|
+
currentVersion: WorkspaceArtifactVersion.nullable(),
|
|
51
|
+
createdBySubjectId: z.string().min(1).max(1024),
|
|
52
|
+
createdAt: z.string().datetime({ offset: true }),
|
|
53
|
+
updatedAt: z.string().datetime({ offset: true }),
|
|
54
|
+
});
|
|
55
|
+
export type WorkspaceArtifact = z.infer<typeof WorkspaceArtifact>;
|
|
56
|
+
|
|
57
|
+
export const WorkspaceArtifactEventType = z.enum(["published", "rolled_back"]);
|
|
58
|
+
export type WorkspaceArtifactEventType = z.infer<typeof WorkspaceArtifactEventType>;
|
|
59
|
+
|
|
60
|
+
export const WorkspaceArtifactEvent = z.object({
|
|
61
|
+
id: z.string().uuid(),
|
|
62
|
+
accountId: z.string().uuid(),
|
|
63
|
+
workspaceId: z.string().uuid(),
|
|
64
|
+
artifactId: z.string().uuid(),
|
|
65
|
+
type: WorkspaceArtifactEventType,
|
|
66
|
+
fromVersionId: z.string().uuid().nullable(),
|
|
67
|
+
toVersionId: z.string().uuid(),
|
|
68
|
+
sourceSessionId: z.string().uuid().nullable(),
|
|
69
|
+
sourceTurnId: z.string().uuid().nullable(),
|
|
70
|
+
sourceAttemptId: z.string().uuid().nullable(),
|
|
71
|
+
sourceExecutionGeneration: z.number().int().positive().nullable(),
|
|
72
|
+
actorSubjectId: z.string().min(1).max(1024),
|
|
73
|
+
reason: z.string().min(1).max(4096),
|
|
74
|
+
createdAt: z.string().datetime({ offset: true }),
|
|
75
|
+
});
|
|
76
|
+
export type WorkspaceArtifactEvent = z.infer<typeof WorkspaceArtifactEvent>;
|
|
77
|
+
|
|
78
|
+
export const WorkspaceArtifactListQuery = z.object({
|
|
79
|
+
limit: z.coerce
|
|
80
|
+
.number()
|
|
81
|
+
.int()
|
|
82
|
+
.positive()
|
|
83
|
+
.max(WORKSPACE_ARTIFACT_LIST_MAX)
|
|
84
|
+
.default(WORKSPACE_ARTIFACT_LIST_DEFAULT),
|
|
85
|
+
cursor: z.string().min(1).max(WORKSPACE_ARTIFACT_CURSOR_MAX_CHARS).optional(),
|
|
86
|
+
});
|
|
87
|
+
export type WorkspaceArtifactListQuery = z.infer<typeof WorkspaceArtifactListQuery>;
|
|
88
|
+
|
|
89
|
+
export const WorkspaceArtifactListResponse = z.object({
|
|
90
|
+
artifacts: z.array(WorkspaceArtifact).max(WORKSPACE_ARTIFACT_LIST_MAX),
|
|
91
|
+
nextCursor: z.string().max(WORKSPACE_ARTIFACT_CURSOR_MAX_CHARS).nullable(),
|
|
92
|
+
truncated: z.boolean(),
|
|
93
|
+
});
|
|
94
|
+
export type WorkspaceArtifactListResponse = z.infer<typeof WorkspaceArtifactListResponse>;
|
|
95
|
+
|
|
96
|
+
export const WorkspaceArtifactDetailResponse = z.object({
|
|
97
|
+
artifact: WorkspaceArtifact,
|
|
98
|
+
versions: z.array(WorkspaceArtifactVersion).max(WORKSPACE_ARTIFACT_LIST_MAX),
|
|
99
|
+
events: z.array(WorkspaceArtifactEvent).max(WORKSPACE_ARTIFACT_LIST_MAX),
|
|
100
|
+
versionsTruncated: z.boolean(),
|
|
101
|
+
eventsTruncated: z.boolean(),
|
|
102
|
+
});
|
|
103
|
+
export type WorkspaceArtifactDetailResponse = z.infer<typeof WorkspaceArtifactDetailResponse>;
|
|
104
|
+
|
|
105
|
+
export const WorkspaceArtifactHtml = z
|
|
106
|
+
.string()
|
|
107
|
+
.min(1)
|
|
108
|
+
.max(WORKSPACE_ARTIFACT_HTML_MAX_UTF8_BYTES)
|
|
109
|
+
.superRefine((value, ctx) => {
|
|
110
|
+
if (encoder.encode(value).byteLength > WORKSPACE_ARTIFACT_HTML_MAX_UTF8_BYTES) {
|
|
111
|
+
ctx.addIssue({
|
|
112
|
+
code: "custom",
|
|
113
|
+
message: `artifact HTML exceeds ${WORKSPACE_ARTIFACT_HTML_MAX_UTF8_BYTES} UTF-8 bytes`,
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
export const CreateWorkspaceArtifactRequest = z.object({
|
|
119
|
+
slug: WorkspaceArtifactSlug.optional(),
|
|
120
|
+
title: z.string().trim().min(1).max(WORKSPACE_ARTIFACT_TITLE_MAX_CHARS),
|
|
121
|
+
description: z.string().max(WORKSPACE_ARTIFACT_DESCRIPTION_MAX_CHARS).nullable().optional(),
|
|
122
|
+
html: WorkspaceArtifactHtml,
|
|
123
|
+
idempotencyKey: z.string().trim().min(1).max(200),
|
|
124
|
+
});
|
|
125
|
+
export type CreateWorkspaceArtifactRequest = z.infer<typeof CreateWorkspaceArtifactRequest>;
|
|
126
|
+
|
|
127
|
+
export const PublishWorkspaceArtifactVersionRequest = z.object({
|
|
128
|
+
title: z.string().trim().min(1).max(WORKSPACE_ARTIFACT_TITLE_MAX_CHARS).optional(),
|
|
129
|
+
description: z.string().max(WORKSPACE_ARTIFACT_DESCRIPTION_MAX_CHARS).nullable().optional(),
|
|
130
|
+
html: WorkspaceArtifactHtml,
|
|
131
|
+
expectedCurrentVersionId: z.string().uuid(),
|
|
132
|
+
idempotencyKey: z.string().trim().min(1).max(200),
|
|
133
|
+
});
|
|
134
|
+
export type PublishWorkspaceArtifactVersionRequest = z.infer<
|
|
135
|
+
typeof PublishWorkspaceArtifactVersionRequest
|
|
136
|
+
>;
|
|
137
|
+
|
|
138
|
+
export const RollbackWorkspaceArtifactRequest = z.object({
|
|
139
|
+
versionId: z.string().uuid(),
|
|
140
|
+
expectedCurrentVersionId: z.string().uuid(),
|
|
141
|
+
reason: z.string().trim().min(1).max(4096),
|
|
142
|
+
idempotencyKey: z.string().trim().min(1).max(200),
|
|
143
|
+
});
|
|
144
|
+
export type RollbackWorkspaceArtifactRequest = z.infer<typeof RollbackWorkspaceArtifactRequest>;
|
|
145
|
+
|
|
146
|
+
export const WorkspaceArtifactMutationResponse = z.object({
|
|
147
|
+
artifact: WorkspaceArtifact,
|
|
148
|
+
version: WorkspaceArtifactVersion,
|
|
149
|
+
event: WorkspaceArtifactEvent,
|
|
150
|
+
replayed: z.boolean(),
|
|
151
|
+
});
|
|
152
|
+
export type WorkspaceArtifactMutationResponse = z.infer<typeof WorkspaceArtifactMutationResponse>;
|
|
153
|
+
|
|
154
|
+
export const WorkspaceArtifactContentResponse = z.object({
|
|
155
|
+
artifactId: z.string().uuid(),
|
|
156
|
+
versionId: z.string().uuid(),
|
|
157
|
+
contentType: z.literal("text/html"),
|
|
158
|
+
contentSha256: sha256,
|
|
159
|
+
html: WorkspaceArtifactHtml,
|
|
160
|
+
});
|
|
161
|
+
export type WorkspaceArtifactContentResponse = z.infer<typeof WorkspaceArtifactContentResponse>;
|
|
162
|
+
|
|
163
|
+
export function normalizeWorkspaceArtifactSlug(value: string): string {
|
|
164
|
+
return value
|
|
165
|
+
.normalize("NFKD")
|
|
166
|
+
.toLowerCase()
|
|
167
|
+
.replace(/[^a-z0-9]+/g, "-")
|
|
168
|
+
.replace(/^-+|-+$/g, "")
|
|
169
|
+
.slice(0, 96)
|
|
170
|
+
.replace(/-+$/g, "");
|
|
171
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -8,6 +8,31 @@ import {
|
|
|
8
8
|
|
|
9
9
|
export * from "./slack-bot-scopes";
|
|
10
10
|
|
|
11
|
+
export {
|
|
12
|
+
CreateWorkspaceArtifactRequest,
|
|
13
|
+
PublishWorkspaceArtifactVersionRequest,
|
|
14
|
+
RollbackWorkspaceArtifactRequest,
|
|
15
|
+
WorkspaceArtifact,
|
|
16
|
+
WorkspaceArtifactContentResponse,
|
|
17
|
+
WorkspaceArtifactDetailResponse,
|
|
18
|
+
WorkspaceArtifactEvent,
|
|
19
|
+
WorkspaceArtifactEventType,
|
|
20
|
+
WorkspaceArtifactHtml,
|
|
21
|
+
WorkspaceArtifactListQuery,
|
|
22
|
+
WorkspaceArtifactListResponse,
|
|
23
|
+
WorkspaceArtifactMutationResponse,
|
|
24
|
+
WorkspaceArtifactSlug,
|
|
25
|
+
WorkspaceArtifactStatus,
|
|
26
|
+
WorkspaceArtifactVersion,
|
|
27
|
+
WORKSPACE_ARTIFACT_CURSOR_MAX_CHARS,
|
|
28
|
+
WORKSPACE_ARTIFACT_DESCRIPTION_MAX_CHARS,
|
|
29
|
+
WORKSPACE_ARTIFACT_HTML_MAX_UTF8_BYTES,
|
|
30
|
+
WORKSPACE_ARTIFACT_LIST_DEFAULT,
|
|
31
|
+
WORKSPACE_ARTIFACT_LIST_MAX,
|
|
32
|
+
WORKSPACE_ARTIFACT_TITLE_MAX_CHARS,
|
|
33
|
+
normalizeWorkspaceArtifactSlug,
|
|
34
|
+
} from "./artifacts";
|
|
35
|
+
|
|
11
36
|
export {
|
|
12
37
|
SESSION_EVENT_PAYLOAD_MAX_BYTES,
|
|
13
38
|
approximateSessionEventTokens,
|
|
@@ -626,6 +651,10 @@ export const Permission = z.enum([
|
|
|
626
651
|
// super-wildcard over both.
|
|
627
652
|
"rigs:use",
|
|
628
653
|
"rigs:manage",
|
|
654
|
+
// Workspace-published HTML artifacts. Read permits listing/source retrieval;
|
|
655
|
+
// publish permits create, version publication, and rollback.
|
|
656
|
+
"artifacts:read",
|
|
657
|
+
"artifacts:publish",
|
|
629
658
|
]);
|
|
630
659
|
export type Permission = z.infer<typeof Permission>;
|
|
631
660
|
|
|
@@ -647,10 +676,16 @@ export const DEFAULT_FIRST_PARTY_MCP_PERMISSIONS = [
|
|
|
647
676
|
"sessions:read",
|
|
648
677
|
"sessions:create",
|
|
649
678
|
"sessions:control",
|
|
679
|
+
// Read-only connection discovery lets the selected first-party connector
|
|
680
|
+
// tools resolve an already-installed workspace principal. Credentials stay
|
|
681
|
+
// inside the broker and remain subject to each tool's own authorization.
|
|
682
|
+
"connections:read",
|
|
650
683
|
"variable-sets:use",
|
|
651
684
|
"variable-sets:manage",
|
|
652
685
|
"rigs:use",
|
|
653
686
|
"github:use",
|
|
687
|
+
"artifacts:read",
|
|
688
|
+
"artifacts:publish",
|
|
654
689
|
] as const satisfies readonly Permission[];
|
|
655
690
|
|
|
656
691
|
/**
|
|
@@ -701,6 +736,11 @@ export const FIRST_PARTY_MCP_TOOL_NAMES = [
|
|
|
701
736
|
"social_connections_list",
|
|
702
737
|
"social_posts_recent",
|
|
703
738
|
"social_daily_analysis_context",
|
|
739
|
+
"social_search_live",
|
|
740
|
+
"social_mentions_live",
|
|
741
|
+
"social_thread_fetch",
|
|
742
|
+
"social_posts_sync",
|
|
743
|
+
"social_post_reply",
|
|
704
744
|
"scheduled_tasks_list",
|
|
705
745
|
"scheduled_tasks_get",
|
|
706
746
|
"scheduled_tasks_create",
|
|
@@ -719,17 +759,23 @@ export const FIRST_PARTY_MCP_TOOL_NAMES = [
|
|
|
719
759
|
"slack_bot_file_content",
|
|
720
760
|
"slack_bot_post_message",
|
|
721
761
|
"slack_bot_delete_message",
|
|
762
|
+
"artifacts_list",
|
|
763
|
+
"artifacts_get_source",
|
|
764
|
+
"artifacts_create",
|
|
765
|
+
"artifacts_publish",
|
|
766
|
+
"artifacts_rollback",
|
|
722
767
|
] as const;
|
|
723
768
|
export const FirstPartyMcpToolName = z.enum(FIRST_PARTY_MCP_TOOL_NAMES);
|
|
724
769
|
export type FirstPartyMcpToolName = z.infer<typeof FirstPartyMcpToolName>;
|
|
725
770
|
|
|
726
771
|
/**
|
|
727
|
-
*
|
|
728
|
-
*
|
|
729
|
-
*
|
|
772
|
+
* Connector-wide tools are explicit-only. Ordinary session omission selects
|
|
773
|
+
* the non-connector catalog, while an explicit session policy may still select
|
|
774
|
+
* any catalogued connector tool and remains independently permission-gated.
|
|
730
775
|
*/
|
|
731
|
-
export const DEFAULT_FIRST_PARTY_MCP_TOOLS =
|
|
732
|
-
|
|
776
|
+
export const DEFAULT_FIRST_PARTY_MCP_TOOLS = FIRST_PARTY_MCP_TOOL_NAMES.filter(
|
|
777
|
+
(name) => !name.startsWith("social_") && !name.startsWith("slack_bot_"),
|
|
778
|
+
) satisfies readonly FirstPartyMcpToolName[];
|
|
733
779
|
|
|
734
780
|
export function prefixedMcpToolName(registryId: string, toolName: string): string {
|
|
735
781
|
return `${registryId}__${toolName}`;
|
|
@@ -5149,6 +5195,7 @@ export type EnablePackRequest = z.infer<typeof EnablePackRequest>;
|
|
|
5149
5195
|
|
|
5150
5196
|
export const SocialProvider = z.enum([
|
|
5151
5197
|
"x",
|
|
5198
|
+
"reddit",
|
|
5152
5199
|
"linkedin",
|
|
5153
5200
|
"instagram",
|
|
5154
5201
|
"facebook",
|
|
@@ -5221,6 +5268,19 @@ export const CreateSocialPostRequest = z.object({
|
|
|
5221
5268
|
});
|
|
5222
5269
|
export type CreateSocialPostRequest = z.infer<typeof CreateSocialPostRequest>;
|
|
5223
5270
|
|
|
5271
|
+
// Social OAuth is first-party (X / Reddit REST APIs), distinct from the MCP
|
|
5272
|
+
// integrations OAuth flow: these providers have no MCP resource metadata, so
|
|
5273
|
+
// endpoints are pinned per provider and tokens live in social_connections.
|
|
5274
|
+
export const SocialOAuthProviderId = z.enum(["x", "reddit"]);
|
|
5275
|
+
export type SocialOAuthProviderId = z.infer<typeof SocialOAuthProviderId>;
|
|
5276
|
+
|
|
5277
|
+
export const SocialOAuthStartRequest = z.object({
|
|
5278
|
+
provider: SocialOAuthProviderId,
|
|
5279
|
+
scopes: z.array(z.string().min(1)).optional(),
|
|
5280
|
+
returnPath: z.string().optional(),
|
|
5281
|
+
});
|
|
5282
|
+
export type SocialOAuthStartRequest = z.infer<typeof SocialOAuthStartRequest>;
|
|
5283
|
+
|
|
5224
5284
|
export const ConnectionKind = z.enum(["oauth2", "api_key", "app_install", "delegated"]);
|
|
5225
5285
|
export type ConnectionKind = z.infer<typeof ConnectionKind>;
|
|
5226
5286
|
|
|
@@ -5270,6 +5330,70 @@ export const ConnectionMetadata = z.object({
|
|
|
5270
5330
|
});
|
|
5271
5331
|
export type ConnectionMetadata = z.infer<typeof ConnectionMetadata>;
|
|
5272
5332
|
|
|
5333
|
+
type PersonalSlackCanonicalConnection = Pick<
|
|
5334
|
+
ConnectionMetadata,
|
|
5335
|
+
"id" | "status" | "createdAt" | "updatedAt"
|
|
5336
|
+
>;
|
|
5337
|
+
|
|
5338
|
+
const PERSONAL_SLACK_CONNECTION_STATUS_RANK = {
|
|
5339
|
+
active: 0,
|
|
5340
|
+
needs_reauth: 1,
|
|
5341
|
+
error: 2,
|
|
5342
|
+
revoked: 3,
|
|
5343
|
+
} as const satisfies Record<ConnectionStatus, number>;
|
|
5344
|
+
|
|
5345
|
+
/**
|
|
5346
|
+
* Canonical ordering for duplicate subject-owned Personal Slack rows.
|
|
5347
|
+
*
|
|
5348
|
+
* PostgreSQL broker lookup mirrors this exact sequence: usable status first,
|
|
5349
|
+
* then newest update, newest creation, and immutable UUID descending.
|
|
5350
|
+
*/
|
|
5351
|
+
export function comparePersonalSlackCanonicalConnections(
|
|
5352
|
+
left: PersonalSlackCanonicalConnection,
|
|
5353
|
+
right: PersonalSlackCanonicalConnection,
|
|
5354
|
+
): number {
|
|
5355
|
+
const statusDelta =
|
|
5356
|
+
PERSONAL_SLACK_CONNECTION_STATUS_RANK[left.status] -
|
|
5357
|
+
PERSONAL_SLACK_CONNECTION_STATUS_RANK[right.status];
|
|
5358
|
+
if (statusDelta !== 0) return statusDelta;
|
|
5359
|
+
|
|
5360
|
+
const updatedAtDelta = compareDescending(
|
|
5361
|
+
canonicalConnectionTimestamp(left.updatedAt),
|
|
5362
|
+
canonicalConnectionTimestamp(right.updatedAt),
|
|
5363
|
+
);
|
|
5364
|
+
if (updatedAtDelta !== 0) return updatedAtDelta;
|
|
5365
|
+
|
|
5366
|
+
const createdAtDelta = compareDescending(
|
|
5367
|
+
canonicalConnectionTimestamp(left.createdAt),
|
|
5368
|
+
canonicalConnectionTimestamp(right.createdAt),
|
|
5369
|
+
);
|
|
5370
|
+
if (createdAtDelta !== 0) return createdAtDelta;
|
|
5371
|
+
|
|
5372
|
+
return compareDescending(left.id, right.id);
|
|
5373
|
+
}
|
|
5374
|
+
|
|
5375
|
+
export function selectCanonicalPersonalSlackConnection<T extends PersonalSlackCanonicalConnection>(
|
|
5376
|
+
connections: readonly T[],
|
|
5377
|
+
): T | null {
|
|
5378
|
+
let selected: T | null = null;
|
|
5379
|
+
for (const connection of connections) {
|
|
5380
|
+
if (!selected || comparePersonalSlackCanonicalConnections(connection, selected) < 0) {
|
|
5381
|
+
selected = connection;
|
|
5382
|
+
}
|
|
5383
|
+
}
|
|
5384
|
+
return selected;
|
|
5385
|
+
}
|
|
5386
|
+
|
|
5387
|
+
function canonicalConnectionTimestamp(value: string): number {
|
|
5388
|
+
const timestamp = Date.parse(value);
|
|
5389
|
+
return Number.isFinite(timestamp) ? timestamp : Number.NEGATIVE_INFINITY;
|
|
5390
|
+
}
|
|
5391
|
+
|
|
5392
|
+
function compareDescending(left: number | string, right: number | string): number {
|
|
5393
|
+
if (left === right) return 0;
|
|
5394
|
+
return left > right ? -1 : 1;
|
|
5395
|
+
}
|
|
5396
|
+
|
|
5273
5397
|
export const ConnectionCredentialBundle = z.record(z.string(), z.unknown());
|
|
5274
5398
|
export type ConnectionCredentialBundle = z.infer<typeof ConnectionCredentialBundle>;
|
|
5275
5399
|
|
|
@@ -5610,8 +5734,8 @@ export const Session = z.object({
|
|
|
5610
5734
|
// Non-default first-party MCP token permissions (manager-style sessions);
|
|
5611
5735
|
// null means the fixed worker default set.
|
|
5612
5736
|
firstPartyMcpPermissions: z.array(Permission).nullable(),
|
|
5613
|
-
// Exact model-visible OpenGeni selection.
|
|
5614
|
-
//
|
|
5737
|
+
// Exact model-visible OpenGeni selection. The default omits connector-wide
|
|
5738
|
+
// tools; [] intentionally selects none.
|
|
5615
5739
|
firstPartyMcpTools: z.array(FirstPartyMcpToolName),
|
|
5616
5740
|
// Per-session third-party MCP servers, metadata only. Credential values are
|
|
5617
5741
|
// write-only and never appear here.
|
|
@@ -7912,7 +8036,8 @@ export const CreateSessionRequest = withVariableSetIdAlias({
|
|
|
7912
8036
|
// rejected; creation never silently expands a child beyond that set.
|
|
7913
8037
|
firstPartyMcpPermissions: z.array(Permission).optional(),
|
|
7914
8038
|
// Exact model-visible selection from the broad first-party OpenGeni MCP
|
|
7915
|
-
// catalog. Omission selects the
|
|
8039
|
+
// catalog. Omission selects the safe non-connector default; [] intentionally
|
|
8040
|
+
// exposes none.
|
|
7916
8041
|
// This does not grant authority: every registered tool is permission-gated.
|
|
7917
8042
|
firstPartyMcpTools: z.array(FirstPartyMcpToolName).optional(),
|
|
7918
8043
|
// Third-party MCP servers attached only to this session. For an agent-created
|
|
@@ -9248,7 +9373,7 @@ export type WorkspaceModelCatalogResponse = z.infer<typeof WorkspaceModelCatalog
|
|
|
9248
9373
|
* that rollout boundary. Mutating clients send this value in
|
|
9249
9374
|
* `x-opengeni-api-contract`; the API rejects any other value before routing.
|
|
9250
9375
|
*/
|
|
9251
|
-
export const OPENGENI_API_CONTRACT_REVISION = "2026-07-
|
|
9376
|
+
export const OPENGENI_API_CONTRACT_REVISION = "2026-07-workspace-artifacts-v1" as const;
|
|
9252
9377
|
export const OPENGENI_API_CONTRACT_HEADER = "x-opengeni-api-contract" as const;
|
|
9253
9378
|
/** Bounded request/response identifier shared by browser, ingress, and API diagnostics. */
|
|
9254
9379
|
export const OPENGENI_CORRELATION_HEADER = "x-opengeni-correlation-id" as const;
|
|
@@ -9290,6 +9415,35 @@ export const ClientConfig = /* @__PURE__ */ defineModelContractSchema(() =>
|
|
|
9290
9415
|
}),
|
|
9291
9416
|
productAccessMode: ProductAccessMode,
|
|
9292
9417
|
auth: ClientAuthConfig.default({ mode: "none" }),
|
|
9418
|
+
analytics: z
|
|
9419
|
+
.object({
|
|
9420
|
+
consentRequired: z.boolean(),
|
|
9421
|
+
providers: z.object({
|
|
9422
|
+
reo: z
|
|
9423
|
+
.object({
|
|
9424
|
+
clientId: z
|
|
9425
|
+
.string()
|
|
9426
|
+
.max(128)
|
|
9427
|
+
.regex(/^[A-Za-z0-9_-]+$/u),
|
|
9428
|
+
})
|
|
9429
|
+
.optional(),
|
|
9430
|
+
posthog: z
|
|
9431
|
+
.object({
|
|
9432
|
+
projectKey: z.string().min(1).max(256),
|
|
9433
|
+
host: z.string().url().max(2_048),
|
|
9434
|
+
})
|
|
9435
|
+
.optional(),
|
|
9436
|
+
ga4: z
|
|
9437
|
+
.object({
|
|
9438
|
+
measurementId: z
|
|
9439
|
+
.string()
|
|
9440
|
+
.max(32)
|
|
9441
|
+
.regex(/^G-[A-Z0-9]+$/u),
|
|
9442
|
+
})
|
|
9443
|
+
.optional(),
|
|
9444
|
+
}),
|
|
9445
|
+
})
|
|
9446
|
+
.default({ consentRequired: true, providers: {} }),
|
|
9293
9447
|
// Server-wide hint: does this deployment support Channel-A structured services
|
|
9294
9448
|
// at all (P4.4). Per-session availability is negotiated on /stream-capabilities
|
|
9295
9449
|
// (it depends on the session's pinned backend); this is the coarse on/off the
|
package/src/slack-bot-scopes.ts
CHANGED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/slack-bot-scopes.ts"],"sourcesContent":["export const OPENGENI_SLACK_BOT_REQUIRED_SCOPES = [\n \"canvases:read\",\n \"channels:history\",\n \"channels:read\",\n \"chat:write\",\n \"files:read\",\n \"groups:history\",\n \"groups:read\",\n \"im:history\",\n \"im:read\",\n \"im:write\",\n \"mpim:history\",\n \"mpim:read\",\n \"users:read\",\n] as const;\n\n/**\n * Optional bot grants that remain inside the shipped bot's read/identity\n * boundary. Every other unrequired scope fails closed, including unknown future\n * Slack scopes, so verification, core routing, and UI eligibility cannot drift.\n */\nexport const OPENGENI_SLACK_BOT_SAFE_OPTIONAL_SCOPES = [\"team:read\"] as const;\n\n/** @deprecated Use evaluateOpenGeniSlackBotScopes; an allowlist is the policy. */\nexport const OPENGENI_SLACK_BOT_FORBIDDEN_SCOPES = [\"channels:join\", \"chat:write.public\"] as const;\n\nexport type OpenGeniSlackBotScopePolicy = {\n accepted: boolean;\n missingRequired: string[];\n unsupported: string[];\n};\n\nfunction isOpenGeniSlackBotScopeAllowed(scope: string): boolean {\n return (\n (OPENGENI_SLACK_BOT_REQUIRED_SCOPES as readonly string[]).includes(scope) ||\n (OPENGENI_SLACK_BOT_SAFE_OPTIONAL_SCOPES as readonly string[]).includes(scope)\n );\n}\n\nexport function areOpenGeniSlackBotScopesAccepted(grantedScopes: readonly string[]): boolean {\n return (\n OPENGENI_SLACK_BOT_REQUIRED_SCOPES.every((scope) => grantedScopes.includes(scope)) &&\n grantedScopes.every(isOpenGeniSlackBotScopeAllowed)\n );\n}\n\nexport function evaluateOpenGeniSlackBotScopes(\n grantedScopes: readonly string[],\n): OpenGeniSlackBotScopePolicy {\n const granted = new Set(grantedScopes);\n const missingRequired = OPENGENI_SLACK_BOT_REQUIRED_SCOPES.filter((scope) => !granted.has(scope));\n const unsupported = [...granted].filter((scope) => !isOpenGeniSlackBotScopeAllowed(scope)).sort();\n return {\n accepted: areOpenGeniSlackBotScopesAccepted(grantedScopes),\n missingRequired,\n unsupported,\n };\n}\n"],"mappings":";AAAO,IAAM,qCAAqC;AAAA,EAChD;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAOO,IAAM,0CAA0C,CAAC,WAAW;AAG5D,IAAM,sCAAsC,CAAC,iBAAiB,mBAAmB;AAQxF,SAAS,+BAA+B,OAAwB;AAC9D,SACG,mCAAyD,SAAS,KAAK,KACvE,wCAA8D,SAAS,KAAK;AAEjF;AAEO,SAAS,kCAAkC,eAA2C;AAC3F,SACE,mCAAmC,MAAM,CAAC,UAAU,cAAc,SAAS,KAAK,CAAC,KACjF,cAAc,MAAM,8BAA8B;AAEtD;AAEO,SAAS,+BACd,eAC6B;AAC7B,QAAM,UAAU,IAAI,IAAI,aAAa;AACrC,QAAM,kBAAkB,mCAAmC,OAAO,CAAC,UAAU,CAAC,QAAQ,IAAI,KAAK,CAAC;AAChG,QAAM,cAAc,CAAC,GAAG,OAAO,EAAE,OAAO,CAAC,UAAU,CAAC,+BAA+B,KAAK,CAAC,EAAE,KAAK;AAChG,SAAO;AAAA,IACL,UAAU,kCAAkC,aAAa;AAAA,IACzD;AAAA,IACA;AAAA,EACF;AACF;","names":[]}
|