@opengeni/contracts 0.22.0 → 0.26.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/checkpoint-provider-bindings.d.ts +15 -0
- package/dist/chunk-3B3XEYMN.js +43 -0
- package/dist/chunk-3B3XEYMN.js.map +1 -0
- package/dist/chunk-ESXP7QLV.js +9757 -0
- package/dist/chunk-ESXP7QLV.js.map +1 -0
- package/dist/codex-fleet-policy.d.ts +210 -0
- package/dist/event-preview.d.ts +77 -0
- package/dist/google-drive.d.ts +215 -0
- package/dist/google-drive.js +95 -0
- package/dist/google-drive.js.map +1 -0
- package/dist/index.d.ts +4584 -4641
- package/dist/index.js +771 -8316
- package/dist/index.js.map +1 -1
- package/dist/preference-registry.d.ts +914 -0
- package/dist/retained-output.d.ts +205 -0
- package/dist/sandbox-snapshots.d.ts +41 -0
- package/dist/secret-redaction.d.ts +40 -0
- package/dist/slack-bot-scopes.d.ts +16 -0
- package/dist/slack-bot-scopes.js +15 -0
- package/dist/slack-bot-scopes.js.map +1 -0
- package/dist/workspace-instruction-policies.d.ts +422 -0
- package/dist/workspace-state.d.ts +526 -0
- package/package.json +11 -3
- package/src/checkpoint-provider-bindings.ts +36 -0
- package/src/google-drive.ts +101 -0
- package/src/index.ts +486 -85
- package/src/preference-registry.ts +353 -0
- package/src/sandbox-snapshots.ts +188 -0
- package/src/slack-bot-scopes.ts +58 -0
- package/src/workspace-state.ts +223 -0
|
@@ -0,0 +1,353 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
|
|
3
|
+
export const PREFERENCE_REGISTRY_CONTENT_MAX_CHARS = 262_144;
|
|
4
|
+
export const PREFERENCE_REGISTRY_DESCRIPTOR_DESCRIPTION_MAX_CHARS = 240;
|
|
5
|
+
export const PREFERENCE_REGISTRY_DESCRIPTOR_MAX_COUNT = 64;
|
|
6
|
+
export const PREFERENCE_REGISTRY_DESCRIPTOR_MAX_UTF8_BYTES = 16_384;
|
|
7
|
+
export const PREFERENCE_REGISTRY_REASON_MAX_CHARS = 4_096;
|
|
8
|
+
export const PREFERENCE_REGISTRY_SOURCE_ID_MAX_CHARS = 512;
|
|
9
|
+
export const PREFERENCE_REGISTRY_STABLE_KEY_MAX_CHARS = 96;
|
|
10
|
+
export const PREFERENCE_REGISTRY_TITLE_MAX_CHARS = 120;
|
|
11
|
+
|
|
12
|
+
export const PreferenceRegistryScope = z.enum(["organization", "workspace", "user"]);
|
|
13
|
+
export type PreferenceRegistryScope = z.infer<typeof PreferenceRegistryScope>;
|
|
14
|
+
|
|
15
|
+
export const PreferenceRegistryStatus = z.enum([
|
|
16
|
+
"proposed",
|
|
17
|
+
"active",
|
|
18
|
+
"inactive",
|
|
19
|
+
"rejected",
|
|
20
|
+
"superseded",
|
|
21
|
+
"expired",
|
|
22
|
+
]);
|
|
23
|
+
export type PreferenceRegistryStatus = z.infer<typeof PreferenceRegistryStatus>;
|
|
24
|
+
|
|
25
|
+
export const PreferenceRegistryProvenanceSource = z.enum([
|
|
26
|
+
"human",
|
|
27
|
+
"onboarding",
|
|
28
|
+
"knowledge_proposal",
|
|
29
|
+
"imported_document",
|
|
30
|
+
"slack",
|
|
31
|
+
"meeting_transcript",
|
|
32
|
+
"call_transcript",
|
|
33
|
+
]);
|
|
34
|
+
export type PreferenceRegistryProvenanceSource = z.infer<typeof PreferenceRegistryProvenanceSource>;
|
|
35
|
+
|
|
36
|
+
export const PreferenceRegistryTrust = z.enum([
|
|
37
|
+
"untrusted_proposal",
|
|
38
|
+
"personal",
|
|
39
|
+
"workspace_managed",
|
|
40
|
+
"organization_managed",
|
|
41
|
+
]);
|
|
42
|
+
export type PreferenceRegistryTrust = z.infer<typeof PreferenceRegistryTrust>;
|
|
43
|
+
|
|
44
|
+
export const PreferenceRegistryConflictStrategy = z.enum(["override", "merge", "reject", "inform"]);
|
|
45
|
+
export type PreferenceRegistryConflictStrategy = z.infer<typeof PreferenceRegistryConflictStrategy>;
|
|
46
|
+
|
|
47
|
+
export const PreferenceRegistryEventType = z.enum([
|
|
48
|
+
"proposal_created",
|
|
49
|
+
"activated",
|
|
50
|
+
"corrected",
|
|
51
|
+
"rejected",
|
|
52
|
+
"deactivated",
|
|
53
|
+
"superseded",
|
|
54
|
+
"scope_changed",
|
|
55
|
+
]);
|
|
56
|
+
export type PreferenceRegistryEventType = z.infer<typeof PreferenceRegistryEventType>;
|
|
57
|
+
|
|
58
|
+
export const PreferenceRegistryStableKey = z
|
|
59
|
+
.string()
|
|
60
|
+
.min(1)
|
|
61
|
+
.max(PREFERENCE_REGISTRY_STABLE_KEY_MAX_CHARS)
|
|
62
|
+
.regex(/^[a-z0-9](?:[a-z0-9._-]*[a-z0-9])?$/);
|
|
63
|
+
export type PreferenceRegistryStableKey = z.infer<typeof PreferenceRegistryStableKey>;
|
|
64
|
+
|
|
65
|
+
export function normalizePreferenceRegistryStableKey(value: string): string {
|
|
66
|
+
return value.normalize("NFKC").trim().toLowerCase().replace(/\s+/gu, "-").replace(/-+/g, "-");
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const RequestStableKey = z
|
|
70
|
+
.string()
|
|
71
|
+
.transform(normalizePreferenceRegistryStableKey)
|
|
72
|
+
.pipe(PreferenceRegistryStableKey);
|
|
73
|
+
|
|
74
|
+
const hash = z.string().regex(/^[0-9a-f]{64}$/);
|
|
75
|
+
const boundedActor = z.string().trim().min(1).max(1_024);
|
|
76
|
+
const boundedReason = z.string().trim().min(1).max(PREFERENCE_REGISTRY_REASON_MAX_CHARS);
|
|
77
|
+
const descriptorText = z.string().min(1).max(PREFERENCE_REGISTRY_DESCRIPTOR_DESCRIPTION_MAX_CHARS);
|
|
78
|
+
|
|
79
|
+
export const PreferenceRegistryScopeTarget = z
|
|
80
|
+
.object({
|
|
81
|
+
scope: PreferenceRegistryScope,
|
|
82
|
+
workspaceId: z.string().uuid().nullable(),
|
|
83
|
+
subjectId: z.string().min(1).max(1_024).nullable(),
|
|
84
|
+
})
|
|
85
|
+
.superRefine((value, context) => {
|
|
86
|
+
if (
|
|
87
|
+
value.scope === "organization" &&
|
|
88
|
+
(value.workspaceId !== null || value.subjectId !== null)
|
|
89
|
+
) {
|
|
90
|
+
context.addIssue({
|
|
91
|
+
code: "custom",
|
|
92
|
+
message: "organization scope has no workspace or subject",
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
if (value.scope === "workspace" && (value.workspaceId === null || value.subjectId !== null)) {
|
|
96
|
+
context.addIssue({ code: "custom", message: "workspace scope requires only a workspace" });
|
|
97
|
+
}
|
|
98
|
+
if (value.scope === "user" && (value.workspaceId !== null || value.subjectId === null)) {
|
|
99
|
+
context.addIssue({ code: "custom", message: "user scope requires only a subject" });
|
|
100
|
+
}
|
|
101
|
+
});
|
|
102
|
+
export type PreferenceRegistryScopeTarget = z.infer<typeof PreferenceRegistryScopeTarget>;
|
|
103
|
+
|
|
104
|
+
export const PreferenceRegistryPrecedence = z.object({
|
|
105
|
+
tier: PreferenceRegistryScope,
|
|
106
|
+
rank: z.number().int().min(-1_000).max(1_000),
|
|
107
|
+
conflictStrategy: PreferenceRegistryConflictStrategy,
|
|
108
|
+
conflictsWith: z.array(PreferenceRegistryStableKey).max(32),
|
|
109
|
+
});
|
|
110
|
+
export type PreferenceRegistryPrecedence = z.infer<typeof PreferenceRegistryPrecedence>;
|
|
111
|
+
|
|
112
|
+
export const PreferenceRegistryProvenance = z.object({
|
|
113
|
+
source: PreferenceRegistryProvenanceSource,
|
|
114
|
+
sourceId: z.string().min(1).max(PREFERENCE_REGISTRY_SOURCE_ID_MAX_CHARS).nullable(),
|
|
115
|
+
trust: PreferenceRegistryTrust,
|
|
116
|
+
});
|
|
117
|
+
export type PreferenceRegistryProvenance = z.infer<typeof PreferenceRegistryProvenance>;
|
|
118
|
+
|
|
119
|
+
export const PreferenceRegistryDescriptorProvenance = z.object({
|
|
120
|
+
source: PreferenceRegistryProvenanceSource,
|
|
121
|
+
sourceIdHash: hash.nullable(),
|
|
122
|
+
trust: PreferenceRegistryTrust,
|
|
123
|
+
});
|
|
124
|
+
export type PreferenceRegistryDescriptorProvenance = z.infer<
|
|
125
|
+
typeof PreferenceRegistryDescriptorProvenance
|
|
126
|
+
>;
|
|
127
|
+
|
|
128
|
+
export const PreferenceRegistryRevisionSummary = z.object({
|
|
129
|
+
id: z.string().uuid(),
|
|
130
|
+
preferenceId: z.string().uuid(),
|
|
131
|
+
revision: z.number().int().positive(),
|
|
132
|
+
contentHash: hash,
|
|
133
|
+
title: z.string().min(1).max(PREFERENCE_REGISTRY_TITLE_MAX_CHARS),
|
|
134
|
+
description: descriptorText,
|
|
135
|
+
precedence: PreferenceRegistryPrecedence,
|
|
136
|
+
provenance: PreferenceRegistryProvenance,
|
|
137
|
+
expiresAt: z.string().datetime().nullable(),
|
|
138
|
+
correctsRevisionId: z.string().uuid().nullable(),
|
|
139
|
+
createdBySubjectId: boundedActor,
|
|
140
|
+
createdAt: z.string().datetime(),
|
|
141
|
+
});
|
|
142
|
+
export type PreferenceRegistryRevisionSummary = z.infer<typeof PreferenceRegistryRevisionSummary>;
|
|
143
|
+
|
|
144
|
+
export const PreferenceRegistryRecord = z.object({
|
|
145
|
+
id: z.string().uuid(),
|
|
146
|
+
accountId: z.string().uuid(),
|
|
147
|
+
stableKey: PreferenceRegistryStableKey,
|
|
148
|
+
target: PreferenceRegistryScopeTarget,
|
|
149
|
+
status: PreferenceRegistryStatus,
|
|
150
|
+
scopeVersion: z.number().int().positive(),
|
|
151
|
+
activationVersion: z.number().int().nonnegative(),
|
|
152
|
+
activeRevision: PreferenceRegistryRevisionSummary.nullable(),
|
|
153
|
+
supersededByPreferenceId: z.string().uuid().nullable(),
|
|
154
|
+
createdBySubjectId: boundedActor,
|
|
155
|
+
createdAt: z.string().datetime(),
|
|
156
|
+
updatedAt: z.string().datetime(),
|
|
157
|
+
});
|
|
158
|
+
export type PreferenceRegistryRecord = z.infer<typeof PreferenceRegistryRecord>;
|
|
159
|
+
|
|
160
|
+
export const PreferenceRegistryEvent = z.object({
|
|
161
|
+
id: z.string().uuid(),
|
|
162
|
+
accountId: z.string().uuid(),
|
|
163
|
+
preferenceId: z.string().uuid(),
|
|
164
|
+
type: PreferenceRegistryEventType,
|
|
165
|
+
version: z.number().int().positive(),
|
|
166
|
+
oldRevisionId: z.string().uuid().nullable(),
|
|
167
|
+
newRevisionId: z.string().uuid().nullable(),
|
|
168
|
+
oldTarget: PreferenceRegistryScopeTarget.nullable(),
|
|
169
|
+
newTarget: PreferenceRegistryScopeTarget.nullable(),
|
|
170
|
+
relatedPreferenceId: z.string().uuid().nullable(),
|
|
171
|
+
actorSubjectId: boundedActor,
|
|
172
|
+
reason: boundedReason,
|
|
173
|
+
createdAt: z.string().datetime(),
|
|
174
|
+
});
|
|
175
|
+
export type PreferenceRegistryEvent = z.infer<typeof PreferenceRegistryEvent>;
|
|
176
|
+
|
|
177
|
+
export const PreferenceRegistryDescriptor = z.object({
|
|
178
|
+
id: z.string().uuid(),
|
|
179
|
+
stableKey: PreferenceRegistryStableKey,
|
|
180
|
+
title: z.string().min(1).max(PREFERENCE_REGISTRY_TITLE_MAX_CHARS),
|
|
181
|
+
description: descriptorText,
|
|
182
|
+
scope: PreferenceRegistryScope,
|
|
183
|
+
activeVersion: z.number().int().positive(),
|
|
184
|
+
revisionId: z.string().uuid(),
|
|
185
|
+
contentHash: hash,
|
|
186
|
+
precedence: PreferenceRegistryPrecedence,
|
|
187
|
+
provenance: PreferenceRegistryDescriptorProvenance,
|
|
188
|
+
expiresAt: z.string().datetime().nullable(),
|
|
189
|
+
retrievalHandle: z.string().min(1).max(512),
|
|
190
|
+
});
|
|
191
|
+
export type PreferenceRegistryDescriptor = z.infer<typeof PreferenceRegistryDescriptor>;
|
|
192
|
+
|
|
193
|
+
export const PreferenceRegistrySnapshot = z.object({
|
|
194
|
+
id: z.string().uuid(),
|
|
195
|
+
workspaceId: z.string().uuid(),
|
|
196
|
+
sessionId: z.string().uuid(),
|
|
197
|
+
turnId: z.string().uuid(),
|
|
198
|
+
attemptId: z.string().uuid(),
|
|
199
|
+
executionGeneration: z.number().int().positive(),
|
|
200
|
+
initiatingHumanSubjectId: boundedActor,
|
|
201
|
+
descriptorHash: hash,
|
|
202
|
+
descriptors: z.array(PreferenceRegistryDescriptor).max(PREFERENCE_REGISTRY_DESCRIPTOR_MAX_COUNT),
|
|
203
|
+
truncated: z.boolean(),
|
|
204
|
+
createdAt: z.string().datetime(),
|
|
205
|
+
});
|
|
206
|
+
export type PreferenceRegistrySnapshot = z.infer<typeof PreferenceRegistrySnapshot>;
|
|
207
|
+
|
|
208
|
+
export const PreferenceRegistryFullContent = z.object({
|
|
209
|
+
descriptor: PreferenceRegistryDescriptor,
|
|
210
|
+
content: z.string().min(1).max(PREFERENCE_REGISTRY_CONTENT_MAX_CHARS),
|
|
211
|
+
});
|
|
212
|
+
export type PreferenceRegistryFullContent = z.infer<typeof PreferenceRegistryFullContent>;
|
|
213
|
+
|
|
214
|
+
const revisionInput = {
|
|
215
|
+
title: z.string().trim().min(1).max(PREFERENCE_REGISTRY_TITLE_MAX_CHARS),
|
|
216
|
+
description: z.string().trim().min(1).max(PREFERENCE_REGISTRY_DESCRIPTOR_DESCRIPTION_MAX_CHARS),
|
|
217
|
+
content: z
|
|
218
|
+
.string()
|
|
219
|
+
.min(1)
|
|
220
|
+
.max(PREFERENCE_REGISTRY_CONTENT_MAX_CHARS)
|
|
221
|
+
.refine((value) => value.trim().length > 0, "preference content must not be blank"),
|
|
222
|
+
precedenceRank: z.number().int().min(-1_000).max(1_000).default(0),
|
|
223
|
+
conflictStrategy: PreferenceRegistryConflictStrategy.default("override"),
|
|
224
|
+
conflictsWith: z.array(RequestStableKey).max(32).default([]),
|
|
225
|
+
expiresAt: z.string().datetime({ offset: true }).nullable().default(null),
|
|
226
|
+
};
|
|
227
|
+
|
|
228
|
+
const importedSources = new Set<PreferenceRegistryProvenanceSource>([
|
|
229
|
+
"knowledge_proposal",
|
|
230
|
+
"imported_document",
|
|
231
|
+
"slack",
|
|
232
|
+
"meeting_transcript",
|
|
233
|
+
"call_transcript",
|
|
234
|
+
]);
|
|
235
|
+
|
|
236
|
+
export const CreatePreferenceRegistryProposalRequest = z
|
|
237
|
+
.object({
|
|
238
|
+
stableKey: RequestStableKey,
|
|
239
|
+
scope: PreferenceRegistryScope,
|
|
240
|
+
...revisionInput,
|
|
241
|
+
provenanceSource: PreferenceRegistryProvenanceSource.default("human"),
|
|
242
|
+
provenanceSourceId: z
|
|
243
|
+
.string()
|
|
244
|
+
.min(1)
|
|
245
|
+
.max(PREFERENCE_REGISTRY_SOURCE_ID_MAX_CHARS)
|
|
246
|
+
.nullable()
|
|
247
|
+
.default(null),
|
|
248
|
+
})
|
|
249
|
+
.superRefine((value, context) => {
|
|
250
|
+
if (importedSources.has(value.provenanceSource) && value.provenanceSourceId === null) {
|
|
251
|
+
context.addIssue({
|
|
252
|
+
code: "custom",
|
|
253
|
+
path: ["provenanceSourceId"],
|
|
254
|
+
message: "imported preference proposals require a provenance source id",
|
|
255
|
+
});
|
|
256
|
+
}
|
|
257
|
+
});
|
|
258
|
+
export type CreatePreferenceRegistryProposalRequest = z.infer<
|
|
259
|
+
typeof CreatePreferenceRegistryProposalRequest
|
|
260
|
+
>;
|
|
261
|
+
|
|
262
|
+
export const ActivatePreferenceRegistryRevisionRequest = z.object({
|
|
263
|
+
revisionId: z.string().uuid(),
|
|
264
|
+
expectedCurrentRevisionId: z.string().uuid().nullable(),
|
|
265
|
+
expectedScopeVersion: z.number().int().positive(),
|
|
266
|
+
reason: boundedReason,
|
|
267
|
+
});
|
|
268
|
+
export type ActivatePreferenceRegistryRevisionRequest = z.infer<
|
|
269
|
+
typeof ActivatePreferenceRegistryRevisionRequest
|
|
270
|
+
>;
|
|
271
|
+
|
|
272
|
+
export const CorrectPreferenceRegistryRequest = z.object({
|
|
273
|
+
expectedCurrentRevisionId: z.string().uuid(),
|
|
274
|
+
expectedScopeVersion: z.number().int().positive(),
|
|
275
|
+
...revisionInput,
|
|
276
|
+
reason: boundedReason,
|
|
277
|
+
});
|
|
278
|
+
export type CorrectPreferenceRegistryRequest = z.infer<typeof CorrectPreferenceRegistryRequest>;
|
|
279
|
+
|
|
280
|
+
export const DeactivatePreferenceRegistryRequest = z.object({
|
|
281
|
+
expectedCurrentRevisionId: z.string().uuid(),
|
|
282
|
+
expectedScopeVersion: z.number().int().positive(),
|
|
283
|
+
reason: boundedReason,
|
|
284
|
+
});
|
|
285
|
+
export type DeactivatePreferenceRegistryRequest = z.infer<
|
|
286
|
+
typeof DeactivatePreferenceRegistryRequest
|
|
287
|
+
>;
|
|
288
|
+
|
|
289
|
+
export const ChangePreferenceRegistryScopeRequest = z.object({
|
|
290
|
+
scope: PreferenceRegistryScope,
|
|
291
|
+
expectedScopeVersion: z.number().int().positive(),
|
|
292
|
+
reason: boundedReason,
|
|
293
|
+
});
|
|
294
|
+
export type ChangePreferenceRegistryScopeRequest = z.infer<
|
|
295
|
+
typeof ChangePreferenceRegistryScopeRequest
|
|
296
|
+
>;
|
|
297
|
+
|
|
298
|
+
export const SupersedePreferenceRegistryRequest = z.object({
|
|
299
|
+
replacementPreferenceId: z.string().uuid(),
|
|
300
|
+
expectedCurrentRevisionId: z.string().uuid(),
|
|
301
|
+
expectedScopeVersion: z.number().int().positive(),
|
|
302
|
+
reason: boundedReason,
|
|
303
|
+
});
|
|
304
|
+
export type SupersedePreferenceRegistryRequest = z.infer<typeof SupersedePreferenceRegistryRequest>;
|
|
305
|
+
|
|
306
|
+
export const RejectPreferenceRegistryProposalRequest = z.object({
|
|
307
|
+
revisionId: z.string().uuid(),
|
|
308
|
+
expectedScopeVersion: z.number().int().positive(),
|
|
309
|
+
reason: boundedReason,
|
|
310
|
+
});
|
|
311
|
+
export type RejectPreferenceRegistryProposalRequest = z.infer<
|
|
312
|
+
typeof RejectPreferenceRegistryProposalRequest
|
|
313
|
+
>;
|
|
314
|
+
|
|
315
|
+
export const PreferenceRegistryListQuery = z.object({
|
|
316
|
+
scope: PreferenceRegistryScope.optional(),
|
|
317
|
+
status: PreferenceRegistryStatus.optional(),
|
|
318
|
+
limit: z.coerce.number().int().min(1).max(100).default(50),
|
|
319
|
+
});
|
|
320
|
+
export type PreferenceRegistryListQuery = z.infer<typeof PreferenceRegistryListQuery>;
|
|
321
|
+
|
|
322
|
+
export const PreferenceRegistryListResponse = z.object({
|
|
323
|
+
preferences: z.array(PreferenceRegistryRecord),
|
|
324
|
+
});
|
|
325
|
+
export type PreferenceRegistryListResponse = z.infer<typeof PreferenceRegistryListResponse>;
|
|
326
|
+
|
|
327
|
+
export const PreferenceRegistryDetailResponse = z.object({
|
|
328
|
+
preference: PreferenceRegistryRecord,
|
|
329
|
+
revisions: z.array(PreferenceRegistryRevisionSummary),
|
|
330
|
+
events: z.array(PreferenceRegistryEvent),
|
|
331
|
+
});
|
|
332
|
+
export type PreferenceRegistryDetailResponse = z.infer<typeof PreferenceRegistryDetailResponse>;
|
|
333
|
+
|
|
334
|
+
export const PreferenceRegistryMutationResponse = z.object({
|
|
335
|
+
preference: PreferenceRegistryRecord,
|
|
336
|
+
event: PreferenceRegistryEvent,
|
|
337
|
+
});
|
|
338
|
+
export type PreferenceRegistryMutationResponse = z.infer<typeof PreferenceRegistryMutationResponse>;
|
|
339
|
+
|
|
340
|
+
export const PreferenceRegistryConflictResponse = z.object({
|
|
341
|
+
code: z.literal("PREFERENCE_REGISTRY_CONFLICT"),
|
|
342
|
+
message: z.string(),
|
|
343
|
+
currentRevisionId: z.string().uuid().nullable(),
|
|
344
|
+
scopeVersion: z.number().int().positive().nullable(),
|
|
345
|
+
});
|
|
346
|
+
export type PreferenceRegistryConflictResponse = z.infer<typeof PreferenceRegistryConflictResponse>;
|
|
347
|
+
|
|
348
|
+
export const PreferenceRegistryFullContentRequest = z.object({
|
|
349
|
+
retrievalHandle: z.string().min(1).max(512),
|
|
350
|
+
});
|
|
351
|
+
export type PreferenceRegistryFullContentRequest = z.infer<
|
|
352
|
+
typeof PreferenceRegistryFullContentRequest
|
|
353
|
+
>;
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
export const WORKSPACE_ARCHIVE_DESCRIPTOR_VERSION = 2 as const;
|
|
2
|
+
|
|
3
|
+
export type WorkspaceTreeFingerprint = {
|
|
4
|
+
algorithm: "sha256";
|
|
5
|
+
sha256: string;
|
|
6
|
+
entryCount: number;
|
|
7
|
+
fileCount: number;
|
|
8
|
+
totalFileBytes: number;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export type TarWorkspaceArchiveDescriptor = {
|
|
12
|
+
version: 1;
|
|
13
|
+
revision: string;
|
|
14
|
+
archiveSha256: string;
|
|
15
|
+
archiveBytes: number;
|
|
16
|
+
capturedAt: string;
|
|
17
|
+
workspace: WorkspaceTreeFingerprint;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export type NativeSnapshotProvider =
|
|
21
|
+
| "e2b"
|
|
22
|
+
| "modal_snapshot_directory"
|
|
23
|
+
| "modal_snapshot_filesystem"
|
|
24
|
+
| "runloop"
|
|
25
|
+
| "vercel";
|
|
26
|
+
|
|
27
|
+
export type NativeSnapshotRef = {
|
|
28
|
+
provider: NativeSnapshotProvider;
|
|
29
|
+
snapshotId: string;
|
|
30
|
+
workspacePersistence?: string;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
export type NativeSnapshotDescriptor = {
|
|
34
|
+
version: typeof WORKSPACE_ARCHIVE_DESCRIPTOR_VERSION;
|
|
35
|
+
kind: "provider_snapshot";
|
|
36
|
+
revision: string;
|
|
37
|
+
archiveSha256: string;
|
|
38
|
+
archiveBytes: number;
|
|
39
|
+
capturedAt: string;
|
|
40
|
+
provider: NativeSnapshotProvider;
|
|
41
|
+
snapshotId: string;
|
|
42
|
+
workspacePersistence?: string;
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
export type WorkspaceArchiveDescriptor = TarWorkspaceArchiveDescriptor | NativeSnapshotDescriptor;
|
|
46
|
+
|
|
47
|
+
export const NATIVE_SNAPSHOT_PREFIXES: ReadonlyArray<{
|
|
48
|
+
provider: NativeSnapshotProvider;
|
|
49
|
+
prefix: string;
|
|
50
|
+
}> = [
|
|
51
|
+
{ provider: "e2b", prefix: "E2B_SANDBOX_SNAPSHOT_V1\n" },
|
|
52
|
+
{ provider: "modal_snapshot_directory", prefix: "MODAL_SANDBOX_DIR_SNAPSHOT_V1\n" },
|
|
53
|
+
{ provider: "modal_snapshot_filesystem", prefix: "MODAL_SANDBOX_FS_SNAPSHOT_V1\n" },
|
|
54
|
+
{ provider: "runloop", prefix: "RUNLOOP_SANDBOX_SNAPSHOT_V1\n" },
|
|
55
|
+
{ provider: "vercel", prefix: "UC_VERCEL_SNAPSHOT_V1\n" },
|
|
56
|
+
];
|
|
57
|
+
|
|
58
|
+
const SHA256 = /^[a-f0-9]{64}$/;
|
|
59
|
+
const TAR_REVISION = /^wa1:([0-9]{13}):([a-f0-9]{64})$/;
|
|
60
|
+
const NATIVE_REVISION = /^wa2:([0-9]{13}):([a-f0-9]{64})$/;
|
|
61
|
+
|
|
62
|
+
function nonnegativeInteger(value: unknown): value is number {
|
|
63
|
+
return typeof value === "number" && Number.isSafeInteger(value) && value >= 0;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function commonDescriptorFieldsValid(
|
|
67
|
+
candidate: Partial<WorkspaceArchiveDescriptor>,
|
|
68
|
+
): candidate is Partial<WorkspaceArchiveDescriptor> & {
|
|
69
|
+
revision: string;
|
|
70
|
+
archiveSha256: string;
|
|
71
|
+
archiveBytes: number;
|
|
72
|
+
capturedAt: string;
|
|
73
|
+
} {
|
|
74
|
+
return (
|
|
75
|
+
typeof candidate.revision === "string" &&
|
|
76
|
+
typeof candidate.archiveSha256 === "string" &&
|
|
77
|
+
SHA256.test(candidate.archiveSha256) &&
|
|
78
|
+
nonnegativeInteger(candidate.archiveBytes) &&
|
|
79
|
+
candidate.archiveBytes > 0 &&
|
|
80
|
+
typeof candidate.capturedAt === "string" &&
|
|
81
|
+
Number.isFinite(Date.parse(candidate.capturedAt))
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function revisionMatchesDescriptor(
|
|
86
|
+
revision: string,
|
|
87
|
+
archiveSha256: string,
|
|
88
|
+
capturedAt: string,
|
|
89
|
+
pattern: RegExp,
|
|
90
|
+
): boolean {
|
|
91
|
+
const match = revision.match(pattern);
|
|
92
|
+
return Boolean(
|
|
93
|
+
match && match[2] === archiveSha256 && Number(match[1]) === Date.parse(capturedAt),
|
|
94
|
+
);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export function parseWorkspaceArchiveDescriptor(value: unknown): WorkspaceArchiveDescriptor | null {
|
|
98
|
+
if (!value || typeof value !== "object") return null;
|
|
99
|
+
const candidate = value as Partial<WorkspaceArchiveDescriptor>;
|
|
100
|
+
if (!commonDescriptorFieldsValid(candidate)) return null;
|
|
101
|
+
|
|
102
|
+
if (candidate.version === 1) {
|
|
103
|
+
const tar = candidate as Partial<TarWorkspaceArchiveDescriptor>;
|
|
104
|
+
const workspace = tar.workspace as Partial<WorkspaceTreeFingerprint> | undefined;
|
|
105
|
+
if (
|
|
106
|
+
!revisionMatchesDescriptor(
|
|
107
|
+
candidate.revision,
|
|
108
|
+
candidate.archiveSha256,
|
|
109
|
+
candidate.capturedAt,
|
|
110
|
+
TAR_REVISION,
|
|
111
|
+
) ||
|
|
112
|
+
workspace?.algorithm !== "sha256" ||
|
|
113
|
+
typeof workspace.sha256 !== "string" ||
|
|
114
|
+
!SHA256.test(workspace.sha256) ||
|
|
115
|
+
!nonnegativeInteger(workspace.entryCount) ||
|
|
116
|
+
!nonnegativeInteger(workspace.fileCount) ||
|
|
117
|
+
!nonnegativeInteger(workspace.totalFileBytes)
|
|
118
|
+
) {
|
|
119
|
+
return null;
|
|
120
|
+
}
|
|
121
|
+
return tar as TarWorkspaceArchiveDescriptor;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
if (candidate.version === WORKSPACE_ARCHIVE_DESCRIPTOR_VERSION) {
|
|
125
|
+
const native = candidate as Partial<NativeSnapshotDescriptor>;
|
|
126
|
+
if (
|
|
127
|
+
native.kind !== "provider_snapshot" ||
|
|
128
|
+
!revisionMatchesDescriptor(
|
|
129
|
+
candidate.revision,
|
|
130
|
+
candidate.archiveSha256,
|
|
131
|
+
candidate.capturedAt,
|
|
132
|
+
NATIVE_REVISION,
|
|
133
|
+
) ||
|
|
134
|
+
!NATIVE_SNAPSHOT_PREFIXES.some((entry) => entry.provider === native.provider) ||
|
|
135
|
+
typeof native.snapshotId !== "string" ||
|
|
136
|
+
native.snapshotId.length === 0 ||
|
|
137
|
+
(native.workspacePersistence !== undefined && typeof native.workspacePersistence !== "string")
|
|
138
|
+
) {
|
|
139
|
+
return null;
|
|
140
|
+
}
|
|
141
|
+
return native as NativeSnapshotDescriptor;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
return null;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
export function decodeNativeSnapshotRef(bytes: Uint8Array): NativeSnapshotRef | null {
|
|
148
|
+
let text: string;
|
|
149
|
+
try {
|
|
150
|
+
text = new TextDecoder("utf-8", { fatal: true }).decode(bytes);
|
|
151
|
+
} catch {
|
|
152
|
+
return null;
|
|
153
|
+
}
|
|
154
|
+
for (const entry of NATIVE_SNAPSHOT_PREFIXES) {
|
|
155
|
+
if (!text.startsWith(entry.prefix)) continue;
|
|
156
|
+
try {
|
|
157
|
+
const payload = JSON.parse(text.slice(entry.prefix.length)) as {
|
|
158
|
+
snapshot_id?: unknown;
|
|
159
|
+
workspace_persistence?: unknown;
|
|
160
|
+
};
|
|
161
|
+
if (typeof payload.snapshot_id !== "string" || payload.snapshot_id.length === 0) {
|
|
162
|
+
return null;
|
|
163
|
+
}
|
|
164
|
+
if (
|
|
165
|
+
payload.workspace_persistence !== undefined &&
|
|
166
|
+
typeof payload.workspace_persistence !== "string"
|
|
167
|
+
) {
|
|
168
|
+
return null;
|
|
169
|
+
}
|
|
170
|
+
return {
|
|
171
|
+
provider: entry.provider,
|
|
172
|
+
snapshotId: payload.snapshot_id,
|
|
173
|
+
...(typeof payload.workspace_persistence === "string"
|
|
174
|
+
? { workspacePersistence: payload.workspace_persistence }
|
|
175
|
+
: {}),
|
|
176
|
+
};
|
|
177
|
+
} catch {
|
|
178
|
+
return null;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
return null;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
export function backendForNativeSnapshotProvider(provider: NativeSnapshotProvider): string {
|
|
185
|
+
return provider === "modal_snapshot_directory" || provider === "modal_snapshot_filesystem"
|
|
186
|
+
? "modal"
|
|
187
|
+
: provider;
|
|
188
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
export const OPENGENI_SLACK_BOT_REQUIRED_SCOPES = [
|
|
2
|
+
"canvases:read",
|
|
3
|
+
"channels:history",
|
|
4
|
+
"channels:read",
|
|
5
|
+
"chat:write",
|
|
6
|
+
"files:read",
|
|
7
|
+
"groups:history",
|
|
8
|
+
"groups:read",
|
|
9
|
+
"im:history",
|
|
10
|
+
"im:read",
|
|
11
|
+
"im:write",
|
|
12
|
+
"mpim:history",
|
|
13
|
+
"mpim:read",
|
|
14
|
+
"users:read",
|
|
15
|
+
] as const;
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Optional bot grants that remain inside the shipped bot's read/identity
|
|
19
|
+
* boundary. Every other unrequired scope fails closed, including unknown future
|
|
20
|
+
* Slack scopes, so verification, core routing, and UI eligibility cannot drift.
|
|
21
|
+
*/
|
|
22
|
+
export const OPENGENI_SLACK_BOT_SAFE_OPTIONAL_SCOPES = ["team:read"] as const;
|
|
23
|
+
|
|
24
|
+
/** @deprecated Use evaluateOpenGeniSlackBotScopes; an allowlist is the policy. */
|
|
25
|
+
export const OPENGENI_SLACK_BOT_FORBIDDEN_SCOPES = ["channels:join", "chat:write.public"] as const;
|
|
26
|
+
|
|
27
|
+
export type OpenGeniSlackBotScopePolicy = {
|
|
28
|
+
accepted: boolean;
|
|
29
|
+
missingRequired: string[];
|
|
30
|
+
unsupported: string[];
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
function isOpenGeniSlackBotScopeAllowed(scope: string): boolean {
|
|
34
|
+
return (
|
|
35
|
+
(OPENGENI_SLACK_BOT_REQUIRED_SCOPES as readonly string[]).includes(scope) ||
|
|
36
|
+
(OPENGENI_SLACK_BOT_SAFE_OPTIONAL_SCOPES as readonly string[]).includes(scope)
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export function areOpenGeniSlackBotScopesAccepted(grantedScopes: readonly string[]): boolean {
|
|
41
|
+
return (
|
|
42
|
+
OPENGENI_SLACK_BOT_REQUIRED_SCOPES.every((scope) => grantedScopes.includes(scope)) &&
|
|
43
|
+
grantedScopes.every(isOpenGeniSlackBotScopeAllowed)
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export function evaluateOpenGeniSlackBotScopes(
|
|
48
|
+
grantedScopes: readonly string[],
|
|
49
|
+
): OpenGeniSlackBotScopePolicy {
|
|
50
|
+
const granted = new Set(grantedScopes);
|
|
51
|
+
const missingRequired = OPENGENI_SLACK_BOT_REQUIRED_SCOPES.filter((scope) => !granted.has(scope));
|
|
52
|
+
const unsupported = [...granted].filter((scope) => !isOpenGeniSlackBotScopeAllowed(scope)).sort();
|
|
53
|
+
return {
|
|
54
|
+
accepted: areOpenGeniSlackBotScopesAccepted(grantedScopes),
|
|
55
|
+
missingRequired,
|
|
56
|
+
unsupported,
|
|
57
|
+
};
|
|
58
|
+
}
|