@anchrd/colab-sdk 0.1.21 → 0.1.23

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.
@@ -0,0 +1,241 @@
1
+ import { z } from "zod";
2
+ import { idSchema } from "../ids/ids.js";
3
+ import { Limit } from "../list-input.js";
4
+ import { MachineId } from "../machines/machines.js";
5
+ import { UserId } from "../users/users.js";
6
+ // A person's own MCP servers (E144, #802, Einstellungen › MCPs): connected from the catalog below or
7
+ // as their own, used by their personal Operators (E143) directly from the run's container (E80);
8
+ // Colab passes nothing through (E2). `operator_mcp_*`, always the caller's own, admin mode or not.
9
+ //
10
+ // ⚠️ The sign-in goes in and never comes out: no answer carries it, and no field of an answer is
11
+ // called `key`, `secret`, `token` or `password` (`/mcp` would strike it). Its field in the inputs is
12
+ // `value`; a header's name is no secret and is answered.
13
+ export const McpId = idSchema("mcp").describe("The MCP's id, `mcp_…`, as operator_mcp_list names it.");
14
+ // How Colab signs in at the MCP server: OAuth in the person's browser, a bearer token, one header with
15
+ // a value, or nothing.
16
+ export const McpAuth = z.enum(["oauth", "bearer", "header", "none"]);
17
+ // `running` ("Läuft"): the last check listed its tools. `expired` ("Anmeldung abgelaufen"): the
18
+ // server refused the sign-in (an OAuth sign-in that no longer refreshes, a token it no longer takes);
19
+ // "Neu anmelden" helps. `unreachable`: the server did not answer as an MCP server. `pending`: an
20
+ // OAuth sign-in was started and is not finished; its address is `authorizeUrl`.
21
+ export const McpState = z.enum(["running", "expired", "unreachable", "pending"]);
22
+ // The prepared MCPs (Einstellungen › MCPs › Katalog). Their addresses and sign-ins are data here, the
23
+ // UI reads them and names each by its `id` in its messages. `signIn` is who the person signs in with
24
+ // ("angemeldet mit Google"). ⚠️ The addresses are the providers' remote MCP servers as published in
25
+ // October 2026; each is proven only on the stage with a real account (#35), locally none answers.
26
+ export const mcpCatalog = [
27
+ {
28
+ id: "gmail",
29
+ name: "Gmail",
30
+ url: "https://gmailmcp.googleapis.com/mcp/v1",
31
+ auth: "oauth",
32
+ signIn: "Google",
33
+ color: "#c5221f",
34
+ initials: "G",
35
+ },
36
+ {
37
+ id: "calendar",
38
+ name: "Google Calendar",
39
+ url: "https://calendarmcp.googleapis.com/mcp/v1",
40
+ auth: "oauth",
41
+ signIn: "Google",
42
+ color: "#1a73e8",
43
+ initials: "K",
44
+ },
45
+ {
46
+ id: "drive",
47
+ name: "Google Drive",
48
+ url: "https://drivemcp.googleapis.com/mcp/v1",
49
+ auth: "oauth",
50
+ signIn: "Google",
51
+ color: "#188038",
52
+ initials: "D",
53
+ },
54
+ {
55
+ id: "slack",
56
+ name: "Slack",
57
+ url: "https://mcp.slack.com/mcp",
58
+ auth: "oauth",
59
+ signIn: "Slack",
60
+ color: "#4a154b",
61
+ initials: "Sl",
62
+ },
63
+ {
64
+ id: "teams",
65
+ name: "Microsoft Teams",
66
+ url: "https://agent365.svc.cloud.microsoft/agents/servers/mcp_TeamsServer",
67
+ auth: "oauth",
68
+ signIn: "Microsoft",
69
+ color: "#5059c9",
70
+ initials: "T",
71
+ },
72
+ {
73
+ id: "outlook",
74
+ name: "Outlook",
75
+ url: "https://agent365.svc.cloud.microsoft/agents/servers/mcp_MailTools",
76
+ auth: "oauth",
77
+ signIn: "Microsoft",
78
+ color: "#0f6cbd",
79
+ initials: "O",
80
+ },
81
+ {
82
+ id: "hubspot",
83
+ name: "HubSpot",
84
+ url: "https://mcp.hubspot.com",
85
+ auth: "oauth",
86
+ signIn: "HubSpot",
87
+ color: "#c2410c",
88
+ initials: "H",
89
+ },
90
+ {
91
+ id: "notion",
92
+ name: "Notion",
93
+ url: "https://mcp.notion.com/mcp",
94
+ auth: "oauth",
95
+ signIn: "Notion",
96
+ color: "#111111",
97
+ initials: "N",
98
+ },
99
+ ];
100
+ export const McpCatalogId = z.enum(mcpCatalog.map((entry) => entry.id));
101
+ const McpName = z.string().trim().min(1).max(64);
102
+ // https, and on this computer also http://localhost (E57), like a service's MCP address.
103
+ const McpUrl = z
104
+ .url({ protocol: /^https?$/ })
105
+ .max(2000)
106
+ .refine((value) => {
107
+ const url = new URL(value);
108
+ // A name and password in the address would be answered with it; a sign-in goes in `value`.
109
+ if (url.username || url.password)
110
+ return false;
111
+ return (url.protocol === "https:" || ["localhost", "127.0.0.1", "[::1]"].includes(url.hostname));
112
+ }, {
113
+ message: "An MCP address starts with https:// (on this computer also http://localhost) and holds no name or password.",
114
+ });
115
+ // A header's name as HTTP takes it; `authorization` is the bearer token's, `host` the request's own.
116
+ const HeaderName = z
117
+ .string()
118
+ .trim()
119
+ .regex(/^[A-Za-z0-9!#$%&'*+.^_`|~-]{1,64}$/, "A header's name holds letters, digits and - only.")
120
+ .refine((name) => !["host", "content-length", "content-type"].includes(name.toLowerCase()), {
121
+ message: "This header is the request's own.",
122
+ });
123
+ // The bearer token or the header's value as pasted; never answered.
124
+ const McpValue = z.string().trim().min(1).max(8000);
125
+ export const McpListInput = z.strictObject({
126
+ cursor: McpId.optional(),
127
+ limit: Limit.optional(),
128
+ });
129
+ export const McpGetInput = z.strictObject({ mcpId: McpId });
130
+ // "Verbinden": a catalog entry by its id, or one's own with name, address and sign-in. A bearer token
131
+ // and a header take `value`, a header its `headerName` too. The connection is checked at once
132
+ // (`tools/list`); a check that fails saves nothing. OAuth saves the MCP as `pending` with the address
133
+ // the person signs in at (`authorizeUrl`).
134
+ export const McpCreateInput = z
135
+ .strictObject({
136
+ catalogId: McpCatalogId.optional().describe("A prepared MCP of the catalog (gmail, calendar, drive, slack, teams, outlook, hubspot, notion). Leave name, url and auth out then."),
137
+ name: McpName.optional(),
138
+ url: McpUrl.optional(),
139
+ auth: McpAuth.optional(),
140
+ headerName: HeaderName.optional(),
141
+ value: McpValue.optional().describe("The bearer token or the header's value. Stored sealed for you alone and never shown again."),
142
+ })
143
+ .refine((input) => input.catalogId !== undefined
144
+ ? input.name === undefined &&
145
+ input.url === undefined &&
146
+ input.auth === undefined &&
147
+ input.headerName === undefined &&
148
+ input.value === undefined
149
+ : input.name !== undefined && input.url !== undefined && input.auth !== undefined, { message: "Name either catalogId, or name, url and auth of your own MCP." })
150
+ .refine((input) => input.auth === "bearer"
151
+ ? input.value !== undefined && input.headerName === undefined
152
+ : input.auth === "header"
153
+ ? input.value !== undefined && input.headerName !== undefined
154
+ : input.value === undefined && input.headerName === undefined, {
155
+ message: "bearer takes value, header takes headerName and value, oauth and none take neither.",
156
+ });
157
+ // The switches of its tools, a new name, a new sign-in ("Neu anmelden": a new `value` for a bearer
158
+ // token or a header, `signIn: true` for OAuth, which answers a new `authorizeUrl`).
159
+ export const McpUpdateInput = z
160
+ .strictObject({
161
+ mcpId: McpId,
162
+ name: McpName.optional(),
163
+ tools: z
164
+ .record(z.string().min(1).max(128), z.boolean())
165
+ .optional()
166
+ .describe("Tool names to switch on (true) or off (false). An Operator never sees a tool that is off."),
167
+ value: McpValue.optional(),
168
+ signIn: z.literal(true).optional(),
169
+ })
170
+ .refine((input) => input.name !== undefined ||
171
+ input.tools !== undefined ||
172
+ input.value !== undefined ||
173
+ input.signIn !== undefined, { message: "Name a field to change: name, tools, value or signIn." });
174
+ // Checks the connection again (`tools/list`): its state, and the tools the server has now. A new tool
175
+ // that writes comes switched off.
176
+ export const McpTestInput = z.strictObject({ mcpId: McpId });
177
+ // "Trennen": the sign-in is deleted at once and without archive, and no Operator reaches it any more.
178
+ export const McpRevokeInput = z.strictObject({ mcpId: McpId });
179
+ export const McpCallListInput = z.strictObject({
180
+ mcpId: McpId,
181
+ cursor: idSchema("call").optional(),
182
+ limit: Limit.optional(),
183
+ });
184
+ // A tool of the server as its last check listed it: whether it writes (by the server's own
185
+ // `readOnlyHint`; without one it counts as writing) and whether it is switched on.
186
+ export const McpTool = z.object({
187
+ name: z.string(),
188
+ description: z.string(),
189
+ writes: z.boolean(),
190
+ enabled: z.boolean(),
191
+ });
192
+ export const Mcp = z.object({
193
+ mcpId: McpId,
194
+ // The catalog entry it came from; null for one's own.
195
+ catalogId: McpCatalogId.nullable(),
196
+ name: z.string(),
197
+ url: z.string(),
198
+ auth: McpAuth,
199
+ // Only for the sign-in by header: its name, never its value.
200
+ headerName: z.string().nullable(),
201
+ state: McpState,
202
+ // While `pending`: where the person signs in, in their browser. Null otherwise.
203
+ authorizeUrl: z.string().nullable(),
204
+ // Why the last check did not pass; null when it did.
205
+ problem: z.string().nullable(),
206
+ tools: z.array(McpTool),
207
+ // The person's Operators that may use it (their detail under "MCPs"), deleted ones left out.
208
+ machineIds: z.array(MachineId),
209
+ checkedAt: z.iso.datetime().nullable(),
210
+ createdAt: z.iso.datetime(),
211
+ createdBy: UserId.nullable(),
212
+ updatedAt: z.iso.datetime(),
213
+ });
214
+ export const McpList = z.object({ items: z.array(Mcp), nextCursor: McpId.nullable() });
215
+ // The protocol of an MCP (its tab Protokoll): what its person did with it and every call of an
216
+ // Operator through it, newest first. `call` names the tool; `blocked` is a call of a tool that is off,
217
+ // refused before it reached the server.
218
+ export const McpCallAction = z.enum([
219
+ "connect",
220
+ "signin",
221
+ "update",
222
+ "test",
223
+ "expire",
224
+ "revoke",
225
+ "call",
226
+ "blocked",
227
+ ]);
228
+ export const McpCall = z.object({
229
+ callId: idSchema("call"),
230
+ action: McpCallAction,
231
+ tool: z.string().nullable(),
232
+ // The Operator that called; null for what its person did.
233
+ machineId: MachineId.nullable(),
234
+ // The server's HTTP status for a call; null for the rest.
235
+ status: z.int().nullable(),
236
+ createdAt: z.iso.datetime(),
237
+ });
238
+ export const McpCallList = z.object({
239
+ items: z.array(McpCall),
240
+ nextCursor: idSchema("call").nullable(),
241
+ });
@@ -7,7 +7,7 @@ export declare const SecretFields: {
7
7
  secret: z.ZodOptional<z.ZodLiteral<true>>;
8
8
  locked: z.ZodOptional<z.ZodBoolean>;
9
9
  };
10
- export declare const nodeKinds: readonly ["folder", "document", "table", "board", "task", "file", "gadget"];
10
+ export declare const nodeKinds: readonly ["folder", "document", "table", "board", "task", "file", "gadget", "goal", "skill"];
11
11
  export declare const NodeKind: z.ZodEnum<{
12
12
  file: "file";
13
13
  folder: "folder";
@@ -16,6 +16,8 @@ export declare const NodeKind: z.ZodEnum<{
16
16
  board: "board";
17
17
  task: "task";
18
18
  gadget: "gadget";
19
+ goal: "goal";
20
+ skill: "skill";
19
21
  }>;
20
22
  export type NodeKind = z.infer<typeof NodeKind>;
21
23
  export declare const responsibleKinds: readonly ["document", "table", "file"];
@@ -97,6 +99,8 @@ export declare const NodeListItem: z.ZodObject<{
97
99
  board: "board";
98
100
  task: "task";
99
101
  gadget: "gadget";
102
+ goal: "goal";
103
+ skill: "skill";
100
104
  }>;
101
105
  name: z.ZodString;
102
106
  hidden: z.ZodBoolean;
@@ -166,6 +170,8 @@ export declare const NodeList: z.ZodObject<{
166
170
  board: "board";
167
171
  task: "task";
168
172
  gadget: "gadget";
173
+ goal: "goal";
174
+ skill: "skill";
169
175
  }>;
170
176
  name: z.ZodString;
171
177
  hidden: z.ZodBoolean;
@@ -260,6 +266,8 @@ export declare const NodeHit: z.ZodObject<{
260
266
  board: "board";
261
267
  task: "task";
262
268
  gadget: "gadget";
269
+ goal: "goal";
270
+ skill: "skill";
263
271
  }>;
264
272
  name: z.ZodString;
265
273
  path: z.ZodObject<{
@@ -330,6 +338,8 @@ export declare const NodeSearch: z.ZodObject<{
330
338
  board: "board";
331
339
  task: "task";
332
340
  gadget: "gadget";
341
+ goal: "goal";
342
+ skill: "skill";
333
343
  }>;
334
344
  name: z.ZodString;
335
345
  path: z.ZodObject<{
@@ -459,6 +469,8 @@ export declare const NodeDetail: z.ZodObject<{
459
469
  board: "board";
460
470
  task: "task";
461
471
  gadget: "gadget";
472
+ goal: "goal";
473
+ skill: "skill";
462
474
  }>;
463
475
  name: z.ZodString;
464
476
  hidden: z.ZodBoolean;
@@ -35,6 +35,10 @@ export const nodeKinds = [
35
35
  "file",
36
36
  // #642, E118: a small application with files, a draft and published versions.
37
37
  "gadget",
38
+ // #813, E139: what is to be reached by when; its Operator plans every run itself.
39
+ "goal",
40
+ // #817, E140: how something is done well, with its result, trigger and tests.
41
+ "skill",
38
42
  ];
39
43
  export const NodeKind = z.enum(nodeKinds);
40
44
  // Only these kinds have a responsible person (E32): the one who answers for the content's validity.
@@ -73,7 +77,7 @@ export const NodeListInput = z.strictObject({
73
77
  section: NodeSection.optional().describe("List a section of the tree instead of a folder: own (what lies in your own root folder), shared (the tops of everything others let you reach) or users (every other person's root folder, only for an admin in admin mode)."),
74
78
  query: NodeQuery.optional(),
75
79
  includeHidden: Flag.optional().describe("Also list nodes whose name starts with a dot. Leaving it out hides them."),
76
- sort: NodeSort.optional().describe("The order: name (default, A to Z), updated (most recently changed first), kind, or status (the type of the column the validation ticket stands in: backlog, open, progress, done, discarded, blocked, archive, then nodes without a ticket)."),
80
+ sort: NodeSort.optional().describe("The order: name (default, A to Z), updated (most recently changed first), kind, or status (the type of the column the validation ticket stands in, New read as backlog: backlog, open, progress, done, discarded, blocked, archive, then nodes without a ticket)."),
77
81
  foldersFirst: Flag.optional().describe("Put folders before everything else, each group in the chosen order."),
78
82
  cursor: z
79
83
  .string()
@@ -121,8 +125,8 @@ export const NodeListItem = z.object({
121
125
  sharedWith: z.number().int(),
122
126
  // When it went into the archive; null for a node that is not archived.
123
127
  archivedAt: z.iso.datetime().nullable(),
124
- // The validation status (#47): the type of the column its ticket stands in; null for a kind that is
125
- // not validated.
128
+ // The validation status (#47): the type of the column its ticket stands in, a ticket in New read as
129
+ // `backlog` (unchecked, #814); null for a kind that is not validated.
126
130
  status: ColumnType.nullable(),
127
131
  // A board that is a system part with a lock (#52: the tree draws the lock and no ⋯); null for
128
132
  // every other node.