@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/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-ESXP7QLV.js";
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-3B3XEYMN.js";
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
@@ -4,7 +4,7 @@ import {
4
4
  OPENGENI_SLACK_BOT_SAFE_OPTIONAL_SCOPES,
5
5
  areOpenGeniSlackBotScopesAccepted,
6
6
  evaluateOpenGeniSlackBotScopes
7
- } from "./chunk-3B3XEYMN.js";
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@opengeni/contracts",
3
- "version": "0.26.1",
3
+ "version": "0.28.1",
4
4
  "description": "Shared zod schemas and wire-contract types for the OpenGeni API.",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -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
- * Every catalogued OpenGeni tool is selected by default. Registration-time
728
- * authorization remains the independent access boundary; an explicit session
729
- * policy may narrow this model-visible set.
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
- FIRST_PARTY_MCP_TOOL_NAMES satisfies readonly FirstPartyMcpToolName[];
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. All catalogued tools are selected
5614
- // by default; [] intentionally selects none.
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 full catalog; [] intentionally exposes none.
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-turn-instructions-v1" as const;
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
@@ -1,8 +1,10 @@
1
1
  export const OPENGENI_SLACK_BOT_REQUIRED_SCOPES = [
2
+ "app_mentions:read",
2
3
  "canvases:read",
3
4
  "channels:history",
4
5
  "channels:read",
5
6
  "chat:write",
7
+ "commands",
6
8
  "files:read",
7
9
  "groups:history",
8
10
  "groups:read",
@@ -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":[]}