@opengeni/contracts 0.26.1 → 0.27.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/artifacts.d.ts +303 -0
- package/dist/{chunk-3B3XEYMN.js → chunk-KGL5BVGF.js} +3 -1
- package/dist/chunk-KGL5BVGF.js.map +1 -0
- package/dist/{chunk-ESXP7QLV.js → chunk-S4F2GZPD.js} +2827 -2675
- package/dist/chunk-S4F2GZPD.js.map +1 -0
- package/dist/google-drive.js +2 -2
- package/dist/index.d.ts +110 -5
- package/dist/index.js +46 -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 +37 -1
- 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/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
|
|
|
@@ -651,6 +680,8 @@ export const DEFAULT_FIRST_PARTY_MCP_PERMISSIONS = [
|
|
|
651
680
|
"variable-sets:manage",
|
|
652
681
|
"rigs:use",
|
|
653
682
|
"github:use",
|
|
683
|
+
"artifacts:read",
|
|
684
|
+
"artifacts:publish",
|
|
654
685
|
] as const satisfies readonly Permission[];
|
|
655
686
|
|
|
656
687
|
/**
|
|
@@ -719,6 +750,11 @@ export const FIRST_PARTY_MCP_TOOL_NAMES = [
|
|
|
719
750
|
"slack_bot_file_content",
|
|
720
751
|
"slack_bot_post_message",
|
|
721
752
|
"slack_bot_delete_message",
|
|
753
|
+
"artifacts_list",
|
|
754
|
+
"artifacts_get_source",
|
|
755
|
+
"artifacts_create",
|
|
756
|
+
"artifacts_publish",
|
|
757
|
+
"artifacts_rollback",
|
|
722
758
|
] as const;
|
|
723
759
|
export const FirstPartyMcpToolName = z.enum(FIRST_PARTY_MCP_TOOL_NAMES);
|
|
724
760
|
export type FirstPartyMcpToolName = z.infer<typeof FirstPartyMcpToolName>;
|
|
@@ -9248,7 +9284,7 @@ export type WorkspaceModelCatalogResponse = z.infer<typeof WorkspaceModelCatalog
|
|
|
9248
9284
|
* that rollout boundary. Mutating clients send this value in
|
|
9249
9285
|
* `x-opengeni-api-contract`; the API rejects any other value before routing.
|
|
9250
9286
|
*/
|
|
9251
|
-
export const OPENGENI_API_CONTRACT_REVISION = "2026-07-
|
|
9287
|
+
export const OPENGENI_API_CONTRACT_REVISION = "2026-07-workspace-artifacts-v1" as const;
|
|
9252
9288
|
export const OPENGENI_API_CONTRACT_HEADER = "x-opengeni-api-contract" as const;
|
|
9253
9289
|
/** Bounded request/response identifier shared by browser, ingress, and API diagnostics. */
|
|
9254
9290
|
export const OPENGENI_CORRELATION_HEADER = "x-opengeni-correlation-id" as const;
|
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":[]}
|