@llmsafespaces/sdk 0.22.0 → 0.24.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/index.cjs +207 -8
- package/dist/index.d.cts +138 -3
- package/dist/index.d.ts +138 -3
- package/dist/index.js +207 -8
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -56,6 +56,8 @@ var NotFoundError = class extends LLMSafeSpacesError {
|
|
|
56
56
|
}
|
|
57
57
|
};
|
|
58
58
|
var ConflictError = class extends LLMSafeSpacesError {
|
|
59
|
+
/** Current workspace phase, when the 409 body carries one (upload phase gate, Epic 67 D5). */
|
|
60
|
+
phase;
|
|
59
61
|
constructor(message) {
|
|
60
62
|
super(message, 409, "CONFLICT");
|
|
61
63
|
this.name = "ConflictError";
|
|
@@ -120,6 +122,9 @@ var LLMSafeSpaces = class {
|
|
|
120
122
|
agentRoles;
|
|
121
123
|
workflows;
|
|
122
124
|
triggers;
|
|
125
|
+
mcpServers;
|
|
126
|
+
adminMcpServers;
|
|
127
|
+
orgMcpServers;
|
|
123
128
|
constructor(options) {
|
|
124
129
|
this.baseUrl = options.baseUrl.replace(/\/$/, "");
|
|
125
130
|
this.timeout = options.timeout ?? DEFAULT_TIMEOUT;
|
|
@@ -142,11 +147,15 @@ var LLMSafeSpaces = class {
|
|
|
142
147
|
this.agentRoles = new AgentRolesAPI(this);
|
|
143
148
|
this.workflows = new WorkflowsAPI(this);
|
|
144
149
|
this.triggers = new TriggersAPI(this);
|
|
150
|
+
this.mcpServers = new McpServersAPI(this);
|
|
151
|
+
this.adminMcpServers = new AdminMcpServersAPI(this);
|
|
152
|
+
this.orgMcpServers = new OrgMcpServersAPI(this);
|
|
145
153
|
}
|
|
146
154
|
/** Internal: make an authenticated request. */
|
|
147
155
|
async request(method, path, body, timeout) {
|
|
148
156
|
const url = `${this.baseUrl}/api/v1${path}`;
|
|
149
|
-
const
|
|
157
|
+
const isForm = typeof FormData !== "undefined" && body instanceof FormData;
|
|
158
|
+
const headers = isForm ? {} : { "Content-Type": "application/json" };
|
|
150
159
|
if (this.apiKey) {
|
|
151
160
|
headers["Authorization"] = `Bearer ${this.apiKey}`;
|
|
152
161
|
} else if (this.token) {
|
|
@@ -162,7 +171,7 @@ var LLMSafeSpaces = class {
|
|
|
162
171
|
res = await this.fetchFn(url, {
|
|
163
172
|
method,
|
|
164
173
|
headers,
|
|
165
|
-
body: body ? JSON.stringify(body) : void 0,
|
|
174
|
+
body: body ? isForm ? body : JSON.stringify(body) : void 0,
|
|
166
175
|
signal: controller.signal
|
|
167
176
|
});
|
|
168
177
|
} catch (e) {
|
|
@@ -186,8 +195,12 @@ var LLMSafeSpaces = class {
|
|
|
186
195
|
throw new AuthError(msg, res.status);
|
|
187
196
|
case 404:
|
|
188
197
|
throw new NotFoundError(msg);
|
|
189
|
-
case 409:
|
|
190
|
-
|
|
198
|
+
case 409: {
|
|
199
|
+
const phase = errBody.phase;
|
|
200
|
+
const conflict = new ConflictError(msg);
|
|
201
|
+
if (phase) conflict.phase = phase;
|
|
202
|
+
throw conflict;
|
|
203
|
+
}
|
|
191
204
|
case 429:
|
|
192
205
|
throw new RateLimitError(msg);
|
|
193
206
|
case 503: {
|
|
@@ -205,6 +218,52 @@ var LLMSafeSpaces = class {
|
|
|
205
218
|
if (text === "") return void 0;
|
|
206
219
|
return JSON.parse(text);
|
|
207
220
|
}
|
|
221
|
+
/**
|
|
222
|
+
* Internal: like {@link request}, but also returns the response headers
|
|
223
|
+
* (e.g. pagination cursors). Body decoding follows the same contract.
|
|
224
|
+
*/
|
|
225
|
+
async requestWithHeaders(method, path, body, timeout) {
|
|
226
|
+
const url = `${this.baseUrl}/api/v1${path}`;
|
|
227
|
+
const headers = { "Content-Type": "application/json" };
|
|
228
|
+
if (this.apiKey) {
|
|
229
|
+
headers["Authorization"] = `Bearer ${this.apiKey}`;
|
|
230
|
+
} else if (this.token) {
|
|
231
|
+
headers["Authorization"] = `Bearer ${this.token}`;
|
|
232
|
+
}
|
|
233
|
+
const controller = new AbortController();
|
|
234
|
+
const timer = setTimeout(() => controller.abort(), timeout ?? this.timeout);
|
|
235
|
+
let res;
|
|
236
|
+
try {
|
|
237
|
+
res = await this.fetchFn(url, {
|
|
238
|
+
method,
|
|
239
|
+
headers,
|
|
240
|
+
body: body ? JSON.stringify(body) : void 0,
|
|
241
|
+
signal: controller.signal
|
|
242
|
+
});
|
|
243
|
+
} catch (e) {
|
|
244
|
+
clearTimeout(timer);
|
|
245
|
+
if (e instanceof Error && e.name === "AbortError") {
|
|
246
|
+
throw new TimeoutError();
|
|
247
|
+
}
|
|
248
|
+
throw e;
|
|
249
|
+
}
|
|
250
|
+
clearTimeout(timer);
|
|
251
|
+
if (!res.ok) {
|
|
252
|
+
const errBody = await res.json().catch(() => ({ error: res.statusText }));
|
|
253
|
+
const msg = errBody.error ?? res.statusText;
|
|
254
|
+
if (res.status === 401 || res.status === 403) throw new AuthError(msg, res.status);
|
|
255
|
+
if (res.status === 404) throw new NotFoundError(msg);
|
|
256
|
+
throw new LLMSafeSpacesError(msg, res.status);
|
|
257
|
+
}
|
|
258
|
+
let data;
|
|
259
|
+
if (res.status === 204) {
|
|
260
|
+
data = void 0;
|
|
261
|
+
} else {
|
|
262
|
+
const text = await res.text();
|
|
263
|
+
data = text === "" ? void 0 : JSON.parse(text);
|
|
264
|
+
}
|
|
265
|
+
return { data, headers: res.headers };
|
|
266
|
+
}
|
|
208
267
|
async login() {
|
|
209
268
|
if (!this.credentials) throw new AuthError("No credentials configured");
|
|
210
269
|
this.loggingIn = true;
|
|
@@ -246,6 +305,18 @@ var WorkspacesAPI = class {
|
|
|
246
305
|
getStatus(id) {
|
|
247
306
|
return this.client.request("GET", `/workspaces/${id}/status`);
|
|
248
307
|
}
|
|
308
|
+
/**
|
|
309
|
+
* Uploads a file into the workspace (Epic 67): multipart POST with a
|
|
310
|
+
* single part named `file`; the file lands on the workspace PVC under
|
|
311
|
+
* /workspace/uploads/. The returned path feeds the `files` parameter of
|
|
312
|
+
* sessions.sendPromptAsync / sessions.enqueue. The workspace must be
|
|
313
|
+
* Active; a 409 rejects with ConflictError carrying `phase`.
|
|
314
|
+
*/
|
|
315
|
+
upload(id, filename, content) {
|
|
316
|
+
const form = new FormData();
|
|
317
|
+
form.append("file", typeof content === "string" ? new Blob([content]) : content, filename);
|
|
318
|
+
return this.client.request("POST", `/workspaces/${id}/uploads`, form);
|
|
319
|
+
}
|
|
249
320
|
activate(id) {
|
|
250
321
|
return this.client.request("POST", `/workspaces/${id}/activate`);
|
|
251
322
|
}
|
|
@@ -327,20 +398,44 @@ var SessionsAPI = class {
|
|
|
327
398
|
getHistory(workspaceId, sessionId) {
|
|
328
399
|
return this.client.request("GET", `/workspaces/${workspaceId}/sessions/${sessionId}/message`);
|
|
329
400
|
}
|
|
401
|
+
/**
|
|
402
|
+
* Returns one page of session history with cursor pagination.
|
|
403
|
+
* nextCursor is "" when the beginning of the session was reached
|
|
404
|
+
* (no X-Next-Cursor response header).
|
|
405
|
+
*/
|
|
406
|
+
async getHistoryPage(workspaceId, sessionId, opts) {
|
|
407
|
+
const q = new URLSearchParams();
|
|
408
|
+
if (opts?.limit && opts.limit > 0) q.set("limit", String(opts.limit));
|
|
409
|
+
if (opts?.before) q.set("before", opts.before);
|
|
410
|
+
const qs = q.toString();
|
|
411
|
+
const path = `/workspaces/${workspaceId}/sessions/${sessionId}/message${qs ? `?${qs}` : ""}`;
|
|
412
|
+
const { data, headers } = await this.client.requestWithHeaders("GET", path);
|
|
413
|
+
return { messages: data ?? [], nextCursor: headers.get("X-Next-Cursor") ?? "" };
|
|
414
|
+
}
|
|
330
415
|
abort(workspaceId, sessionId) {
|
|
331
416
|
return this.client.request("POST", `/workspaces/${workspaceId}/sessions/${sessionId}/abort`);
|
|
332
417
|
}
|
|
333
418
|
get(workspaceId, sessionId) {
|
|
334
419
|
return this.client.request("GET", `/workspaces/${workspaceId}/sessions/${sessionId}`);
|
|
335
420
|
}
|
|
336
|
-
|
|
337
|
-
|
|
421
|
+
/**
|
|
422
|
+
* Sends a prompt asynchronously (202; the reply arrives on the workspace
|
|
423
|
+
* SSE stream). Optional `files` (Epic 67) are upload-namespace paths —
|
|
424
|
+
* the API composes the v1 attachment manifest into the dispatched text.
|
|
425
|
+
*/
|
|
426
|
+
sendPromptAsync(workspaceId, sessionId, message, files) {
|
|
427
|
+
const body = { parts: [{ type: "text", text: message }] };
|
|
428
|
+
if (files && files.length > 0) body.files = files;
|
|
429
|
+
return this.client.request("POST", `/workspaces/${workspaceId}/sessions/${sessionId}/prompt`, body);
|
|
338
430
|
}
|
|
339
431
|
delete(workspaceId, sessionId) {
|
|
340
432
|
return this.client.request("DELETE", `/workspaces/${workspaceId}/sessions/${sessionId}`);
|
|
341
433
|
}
|
|
342
|
-
|
|
343
|
-
|
|
434
|
+
/** Enqueues a message for a busy session; optional `files` as in sendPromptAsync. */
|
|
435
|
+
enqueue(workspaceId, sessionId, text, files) {
|
|
436
|
+
const body = { text };
|
|
437
|
+
if (files && files.length > 0) body.files = files;
|
|
438
|
+
return this.client.request("POST", `/workspaces/${workspaceId}/sessions/${sessionId}/queue`, body);
|
|
344
439
|
}
|
|
345
440
|
/**
|
|
346
441
|
* @deprecated Under the V2 session-queue model (Epic 63), the queue is
|
|
@@ -675,6 +770,110 @@ var TriggersAPI = class {
|
|
|
675
770
|
return this.client.request("DELETE", `/me/triggers/${id}`);
|
|
676
771
|
}
|
|
677
772
|
};
|
|
773
|
+
var McpServersAPI = class {
|
|
774
|
+
constructor(client) {
|
|
775
|
+
this.client = client;
|
|
776
|
+
}
|
|
777
|
+
client;
|
|
778
|
+
list() {
|
|
779
|
+
return this.client.request("GET", "/me/mcp-servers").then((r) => Array.isArray(r) ? r : r.servers ?? []);
|
|
780
|
+
}
|
|
781
|
+
get(id) {
|
|
782
|
+
return this.client.request("GET", `/me/mcp-servers/${id}`);
|
|
783
|
+
}
|
|
784
|
+
create(req) {
|
|
785
|
+
return this.client.request("POST", "/me/mcp-servers", req);
|
|
786
|
+
}
|
|
787
|
+
update(id, req) {
|
|
788
|
+
return this.client.request("PUT", `/me/mcp-servers/${id}`, req);
|
|
789
|
+
}
|
|
790
|
+
delete(id) {
|
|
791
|
+
return this.client.request("DELETE", `/me/mcp-servers/${id}`);
|
|
792
|
+
}
|
|
793
|
+
bind(id, workspaceId) {
|
|
794
|
+
return this.client.request("POST", `/me/mcp-servers/${id}/bindings`, { workspaceId });
|
|
795
|
+
}
|
|
796
|
+
unbind(id, workspaceId) {
|
|
797
|
+
return this.client.request("DELETE", `/me/mcp-servers/${id}/bindings/${workspaceId}`);
|
|
798
|
+
}
|
|
799
|
+
createAutoApply(id, targetType, targetId) {
|
|
800
|
+
return this.client.request("POST", `/me/mcp-servers/${id}/auto-apply`, { targetType, targetId });
|
|
801
|
+
}
|
|
802
|
+
listAutoApply(id) {
|
|
803
|
+
return this.client.request("GET", `/me/mcp-servers/${id}/auto-apply`).then((r) => Array.isArray(r) ? r : r.rules ?? []);
|
|
804
|
+
}
|
|
805
|
+
};
|
|
806
|
+
var AdminMcpServersAPI = class {
|
|
807
|
+
constructor(client) {
|
|
808
|
+
this.client = client;
|
|
809
|
+
}
|
|
810
|
+
client;
|
|
811
|
+
list() {
|
|
812
|
+
return this.client.request("GET", "/admin/mcp-servers").then((r) => Array.isArray(r) ? r : r.servers ?? []);
|
|
813
|
+
}
|
|
814
|
+
get(id) {
|
|
815
|
+
return this.client.request("GET", `/admin/mcp-servers/${id}`);
|
|
816
|
+
}
|
|
817
|
+
create(req) {
|
|
818
|
+
return this.client.request("POST", "/admin/mcp-servers", req);
|
|
819
|
+
}
|
|
820
|
+
update(id, req) {
|
|
821
|
+
return this.client.request("PUT", `/admin/mcp-servers/${id}`, req);
|
|
822
|
+
}
|
|
823
|
+
delete(id) {
|
|
824
|
+
return this.client.request("DELETE", `/admin/mcp-servers/${id}`);
|
|
825
|
+
}
|
|
826
|
+
bind(id, workspaceId) {
|
|
827
|
+
return this.client.request("POST", `/admin/mcp-servers/${id}/bindings`, { workspaceId });
|
|
828
|
+
}
|
|
829
|
+
unbind(id, workspaceId) {
|
|
830
|
+
return this.client.request("DELETE", `/admin/mcp-servers/${id}/bindings/${workspaceId}`);
|
|
831
|
+
}
|
|
832
|
+
createAutoApply(id, targetType, targetId) {
|
|
833
|
+
return this.client.request("POST", `/admin/mcp-servers/${id}/auto-apply`, { targetType, targetId });
|
|
834
|
+
}
|
|
835
|
+
listAutoApply(id) {
|
|
836
|
+
return this.client.request("GET", `/admin/mcp-servers/${id}/auto-apply`).then((r) => Array.isArray(r) ? r : r.rules ?? []);
|
|
837
|
+
}
|
|
838
|
+
/** targetId omitted → removes every rule of the targetType. */
|
|
839
|
+
deleteAutoApply(id, targetType, targetId) {
|
|
840
|
+
const suffix = targetId ? `/${targetId}` : "";
|
|
841
|
+
return this.client.request("DELETE", `/admin/mcp-servers/${id}/auto-apply/${targetType}${suffix}`);
|
|
842
|
+
}
|
|
843
|
+
};
|
|
844
|
+
var OrgMcpServersAPI = class {
|
|
845
|
+
constructor(client) {
|
|
846
|
+
this.client = client;
|
|
847
|
+
}
|
|
848
|
+
client;
|
|
849
|
+
list(orgId) {
|
|
850
|
+
return this.client.request("GET", `/orgs/${orgId}/mcp-servers`).then((r) => Array.isArray(r) ? r : r.servers ?? []);
|
|
851
|
+
}
|
|
852
|
+
get(orgId, id) {
|
|
853
|
+
return this.client.request("GET", `/orgs/${orgId}/mcp-servers/${id}`);
|
|
854
|
+
}
|
|
855
|
+
create(orgId, req) {
|
|
856
|
+
return this.client.request("POST", `/orgs/${orgId}/mcp-servers`, req);
|
|
857
|
+
}
|
|
858
|
+
update(orgId, id, req) {
|
|
859
|
+
return this.client.request("PUT", `/orgs/${orgId}/mcp-servers/${id}`, req);
|
|
860
|
+
}
|
|
861
|
+
delete(orgId, id) {
|
|
862
|
+
return this.client.request("DELETE", `/orgs/${orgId}/mcp-servers/${id}`);
|
|
863
|
+
}
|
|
864
|
+
bind(orgId, id, workspaceId) {
|
|
865
|
+
return this.client.request("POST", `/orgs/${orgId}/mcp-servers/${id}/bindings`, { workspaceId });
|
|
866
|
+
}
|
|
867
|
+
unbind(orgId, id, workspaceId) {
|
|
868
|
+
return this.client.request("DELETE", `/orgs/${orgId}/mcp-servers/${id}/bindings/${workspaceId}`);
|
|
869
|
+
}
|
|
870
|
+
createAutoApply(orgId, id, targetType, targetId) {
|
|
871
|
+
return this.client.request("POST", `/orgs/${orgId}/mcp-servers/${id}/auto-apply`, { targetType, targetId });
|
|
872
|
+
}
|
|
873
|
+
listAutoApply(orgId, id) {
|
|
874
|
+
return this.client.request("GET", `/orgs/${orgId}/mcp-servers/${id}/auto-apply`).then((r) => Array.isArray(r) ? r : r.rules ?? []);
|
|
875
|
+
}
|
|
876
|
+
};
|
|
678
877
|
|
|
679
878
|
// src/types.ts
|
|
680
879
|
var SECRET_NAME_PATTERN = /^[a-z0-9._-]+$/;
|
package/dist/index.d.cts
CHANGED
|
@@ -294,6 +294,58 @@ interface QueuedMessage {
|
|
|
294
294
|
enqueued_at: string;
|
|
295
295
|
retry_count: number;
|
|
296
296
|
}
|
|
297
|
+
/**
|
|
298
|
+
* Result of a workspace file upload (Epic 67): the absolute path of the
|
|
299
|
+
* stored file on the workspace PVC (/workspace/uploads/<uuid>-<name>),
|
|
300
|
+
* its sanitized name, and the stored byte count.
|
|
301
|
+
*/
|
|
302
|
+
interface FileUpload {
|
|
303
|
+
path: string;
|
|
304
|
+
name: string;
|
|
305
|
+
size: number;
|
|
306
|
+
}
|
|
307
|
+
interface McpServer {
|
|
308
|
+
id: string;
|
|
309
|
+
name: string;
|
|
310
|
+
transport: "http" | "sse" | "stdio";
|
|
311
|
+
url?: string;
|
|
312
|
+
command?: string;
|
|
313
|
+
args?: string[];
|
|
314
|
+
timeoutMs?: number;
|
|
315
|
+
hasSecret: boolean;
|
|
316
|
+
enabled: boolean;
|
|
317
|
+
createdAt?: string;
|
|
318
|
+
updatedAt?: string;
|
|
319
|
+
}
|
|
320
|
+
interface CreateMcpServerRequest {
|
|
321
|
+
name: string;
|
|
322
|
+
transport: "http" | "sse" | "stdio";
|
|
323
|
+
url?: string;
|
|
324
|
+
command?: string;
|
|
325
|
+
args?: string[];
|
|
326
|
+
timeoutMs?: number;
|
|
327
|
+
enabled?: boolean;
|
|
328
|
+
env?: Record<string, string>;
|
|
329
|
+
headers?: Record<string, string>;
|
|
330
|
+
autoApply?: {
|
|
331
|
+
targetType: string;
|
|
332
|
+
targetId?: string;
|
|
333
|
+
};
|
|
334
|
+
}
|
|
335
|
+
interface UpdateMcpServerRequest {
|
|
336
|
+
name?: string;
|
|
337
|
+
url?: string;
|
|
338
|
+
command?: string;
|
|
339
|
+
args?: string[];
|
|
340
|
+
timeoutMs?: number;
|
|
341
|
+
enabled?: boolean;
|
|
342
|
+
env?: Record<string, string>;
|
|
343
|
+
headers?: Record<string, string>;
|
|
344
|
+
}
|
|
345
|
+
interface McpAutoApplyRule {
|
|
346
|
+
targetType: string;
|
|
347
|
+
targetId?: string;
|
|
348
|
+
}
|
|
297
349
|
|
|
298
350
|
declare class LLMSafeSpaces {
|
|
299
351
|
readonly baseUrl: string;
|
|
@@ -319,9 +371,20 @@ declare class LLMSafeSpaces {
|
|
|
319
371
|
readonly agentRoles: AgentRolesAPI;
|
|
320
372
|
readonly workflows: WorkflowsAPI;
|
|
321
373
|
readonly triggers: TriggersAPI;
|
|
374
|
+
readonly mcpServers: McpServersAPI;
|
|
375
|
+
readonly adminMcpServers: AdminMcpServersAPI;
|
|
376
|
+
readonly orgMcpServers: OrgMcpServersAPI;
|
|
322
377
|
constructor(options: ClientOptions);
|
|
323
378
|
/** Internal: make an authenticated request. */
|
|
324
379
|
request<T>(method: string, path: string, body?: unknown, timeout?: number): Promise<T>;
|
|
380
|
+
/**
|
|
381
|
+
* Internal: like {@link request}, but also returns the response headers
|
|
382
|
+
* (e.g. pagination cursors). Body decoding follows the same contract.
|
|
383
|
+
*/
|
|
384
|
+
requestWithHeaders<T>(method: string, path: string, body?: unknown, timeout?: number): Promise<{
|
|
385
|
+
data: T;
|
|
386
|
+
headers: Headers;
|
|
387
|
+
}>;
|
|
325
388
|
private login;
|
|
326
389
|
}
|
|
327
390
|
declare class WorkspacesAPI {
|
|
@@ -333,6 +396,14 @@ declare class WorkspacesAPI {
|
|
|
333
396
|
rename(id: string, name: string): Promise<void>;
|
|
334
397
|
delete(id: string): Promise<void>;
|
|
335
398
|
getStatus(id: string): Promise<WorkspaceStatusResult>;
|
|
399
|
+
/**
|
|
400
|
+
* Uploads a file into the workspace (Epic 67): multipart POST with a
|
|
401
|
+
* single part named `file`; the file lands on the workspace PVC under
|
|
402
|
+
* /workspace/uploads/. The returned path feeds the `files` parameter of
|
|
403
|
+
* sessions.sendPromptAsync / sessions.enqueue. The workspace must be
|
|
404
|
+
* Active; a 409 rejects with ConflictError carrying `phase`.
|
|
405
|
+
*/
|
|
406
|
+
upload(id: string, filename: string, content: Blob | string): Promise<FileUpload>;
|
|
336
407
|
activate(id: string): Promise<ActivateWorkspaceResponse>;
|
|
337
408
|
suspend(id: string): Promise<void>;
|
|
338
409
|
restart(id: string): Promise<void>;
|
|
@@ -378,11 +449,29 @@ declare class SessionsAPI {
|
|
|
378
449
|
sendMessage(workspaceId: string, sessionId: string, content: string): Promise<Message>;
|
|
379
450
|
/** Returns the session transcript in contract shape. */
|
|
380
451
|
getHistory(workspaceId: string, sessionId: string): Promise<Message[]>;
|
|
452
|
+
/**
|
|
453
|
+
* Returns one page of session history with cursor pagination.
|
|
454
|
+
* nextCursor is "" when the beginning of the session was reached
|
|
455
|
+
* (no X-Next-Cursor response header).
|
|
456
|
+
*/
|
|
457
|
+
getHistoryPage(workspaceId: string, sessionId: string, opts?: {
|
|
458
|
+
limit?: number;
|
|
459
|
+
before?: string;
|
|
460
|
+
}): Promise<{
|
|
461
|
+
messages: Message[];
|
|
462
|
+
nextCursor: string;
|
|
463
|
+
}>;
|
|
381
464
|
abort(workspaceId: string, sessionId: string): Promise<void>;
|
|
382
465
|
get(workspaceId: string, sessionId: string): Promise<Record<string, unknown>>;
|
|
383
|
-
|
|
466
|
+
/**
|
|
467
|
+
* Sends a prompt asynchronously (202; the reply arrives on the workspace
|
|
468
|
+
* SSE stream). Optional `files` (Epic 67) are upload-namespace paths —
|
|
469
|
+
* the API composes the v1 attachment manifest into the dispatched text.
|
|
470
|
+
*/
|
|
471
|
+
sendPromptAsync(workspaceId: string, sessionId: string, message: string, files?: string[]): Promise<void>;
|
|
384
472
|
delete(workspaceId: string, sessionId: string): Promise<void>;
|
|
385
|
-
|
|
473
|
+
/** Enqueues a message for a busy session; optional `files` as in sendPromptAsync. */
|
|
474
|
+
enqueue(workspaceId: string, sessionId: string, text: string, files?: string[]): Promise<{
|
|
386
475
|
messageID: string;
|
|
387
476
|
}>;
|
|
388
477
|
/**
|
|
@@ -640,6 +729,50 @@ declare class TriggersAPI {
|
|
|
640
729
|
}): Promise<TriggerResponse>;
|
|
641
730
|
delete(id: string): Promise<void>;
|
|
642
731
|
}
|
|
732
|
+
/** MCP servers owned by the caller (/me/mcp-servers, Epic 53). */
|
|
733
|
+
declare class McpServersAPI {
|
|
734
|
+
private readonly client;
|
|
735
|
+
constructor(client: LLMSafeSpaces);
|
|
736
|
+
list(): Promise<McpServer[]>;
|
|
737
|
+
get(id: string): Promise<McpServer>;
|
|
738
|
+
create(req: CreateMcpServerRequest): Promise<McpServer>;
|
|
739
|
+
update(id: string, req: UpdateMcpServerRequest): Promise<McpServer>;
|
|
740
|
+
delete(id: string): Promise<void>;
|
|
741
|
+
bind(id: string, workspaceId: string): Promise<void>;
|
|
742
|
+
unbind(id: string, workspaceId: string): Promise<void>;
|
|
743
|
+
createAutoApply(id: string, targetType: string, targetId?: string): Promise<void>;
|
|
744
|
+
listAutoApply(id: string): Promise<McpAutoApplyRule[]>;
|
|
745
|
+
}
|
|
746
|
+
/** Platform MCP servers (/admin/mcp-servers; admin scope). */
|
|
747
|
+
declare class AdminMcpServersAPI {
|
|
748
|
+
private readonly client;
|
|
749
|
+
constructor(client: LLMSafeSpaces);
|
|
750
|
+
list(): Promise<McpServer[]>;
|
|
751
|
+
get(id: string): Promise<McpServer>;
|
|
752
|
+
create(req: CreateMcpServerRequest): Promise<McpServer>;
|
|
753
|
+
update(id: string, req: UpdateMcpServerRequest): Promise<McpServer>;
|
|
754
|
+
delete(id: string): Promise<void>;
|
|
755
|
+
bind(id: string, workspaceId: string): Promise<void>;
|
|
756
|
+
unbind(id: string, workspaceId: string): Promise<void>;
|
|
757
|
+
createAutoApply(id: string, targetType: string, targetId?: string): Promise<void>;
|
|
758
|
+
listAutoApply(id: string): Promise<McpAutoApplyRule[]>;
|
|
759
|
+
/** targetId omitted → removes every rule of the targetType. */
|
|
760
|
+
deleteAutoApply(id: string, targetType: string, targetId?: string): Promise<void>;
|
|
761
|
+
}
|
|
762
|
+
/** Organization MCP servers (/orgs/{orgId}/mcp-servers; org-admin scope). */
|
|
763
|
+
declare class OrgMcpServersAPI {
|
|
764
|
+
private readonly client;
|
|
765
|
+
constructor(client: LLMSafeSpaces);
|
|
766
|
+
list(orgId: string): Promise<McpServer[]>;
|
|
767
|
+
get(orgId: string, id: string): Promise<McpServer>;
|
|
768
|
+
create(orgId: string, req: CreateMcpServerRequest): Promise<McpServer>;
|
|
769
|
+
update(orgId: string, id: string, req: UpdateMcpServerRequest): Promise<McpServer>;
|
|
770
|
+
delete(orgId: string, id: string): Promise<void>;
|
|
771
|
+
bind(orgId: string, id: string, workspaceId: string): Promise<void>;
|
|
772
|
+
unbind(orgId: string, id: string, workspaceId: string): Promise<void>;
|
|
773
|
+
createAutoApply(orgId: string, id: string, targetType: string, targetId?: string): Promise<void>;
|
|
774
|
+
listAutoApply(orgId: string, id: string): Promise<McpAutoApplyRule[]>;
|
|
775
|
+
}
|
|
643
776
|
|
|
644
777
|
/** Base error for all LLMSafeSpaces API errors. */
|
|
645
778
|
declare class LLMSafeSpacesError extends Error {
|
|
@@ -654,6 +787,8 @@ declare class NotFoundError extends LLMSafeSpacesError {
|
|
|
654
787
|
constructor(message: string);
|
|
655
788
|
}
|
|
656
789
|
declare class ConflictError extends LLMSafeSpacesError {
|
|
790
|
+
/** Current workspace phase, when the 409 body carries one (upload phase gate, Epic 67 D5). */
|
|
791
|
+
phase?: string;
|
|
657
792
|
constructor(message: string);
|
|
658
793
|
}
|
|
659
794
|
declare class TimeoutError extends LLMSafeSpacesError {
|
|
@@ -678,4 +813,4 @@ declare class ServiceUnavailableError extends LLMSafeSpacesError {
|
|
|
678
813
|
constructor(message?: string, reason?: string, retryAfter?: number);
|
|
679
814
|
}
|
|
680
815
|
|
|
681
|
-
export { type APIKey, type ActivateWorkspaceResponse, type ActiveSessionsResponse, AuthError, type AuthResponse, type ClientOptions, ConflictError, type Cost, type CreateProviderCredentialRequest, type CreateSecretRequest, type CreateWorkspaceRequest, type EnsureSessionResponse, type FetchFn, type FileDiff, type InputOption, type InputRequest, LLMSafeSpaces, LLMSafeSpacesError, type Message, type ModelRef, NotFoundError, type PaginationMetadata, type Part, type ProviderCredential, type QueuedMessage, RateLimitError, type RefreshWorkspaceResult, SECRET_NAME_PATTERN, type SecretResponse, ServiceUnavailableError, type SessionListItem, type TerminalTicket, TimeoutError, type ToolPart, type ToolRef, type UpdateProviderCredentialRequest, type User, type Workspace, type WorkspaceCondition, type WorkspaceListItem, type WorkspaceListResult, type WorkspaceStatusResult };
|
|
816
|
+
export { type APIKey, type ActivateWorkspaceResponse, type ActiveSessionsResponse, AuthError, type AuthResponse, type ClientOptions, ConflictError, type Cost, type CreateMcpServerRequest, type CreateProviderCredentialRequest, type CreateSecretRequest, type CreateWorkspaceRequest, type EnsureSessionResponse, type FetchFn, type FileDiff, type FileUpload, type InputOption, type InputRequest, LLMSafeSpaces, LLMSafeSpacesError, type McpAutoApplyRule, type McpServer, type Message, type ModelRef, NotFoundError, type PaginationMetadata, type Part, type ProviderCredential, type QueuedMessage, RateLimitError, type RefreshWorkspaceResult, SECRET_NAME_PATTERN, type SecretResponse, ServiceUnavailableError, type SessionListItem, type TerminalTicket, TimeoutError, type ToolPart, type ToolRef, type UpdateMcpServerRequest, type UpdateProviderCredentialRequest, type User, type Workspace, type WorkspaceCondition, type WorkspaceListItem, type WorkspaceListResult, type WorkspaceStatusResult };
|
package/dist/index.d.ts
CHANGED
|
@@ -294,6 +294,58 @@ interface QueuedMessage {
|
|
|
294
294
|
enqueued_at: string;
|
|
295
295
|
retry_count: number;
|
|
296
296
|
}
|
|
297
|
+
/**
|
|
298
|
+
* Result of a workspace file upload (Epic 67): the absolute path of the
|
|
299
|
+
* stored file on the workspace PVC (/workspace/uploads/<uuid>-<name>),
|
|
300
|
+
* its sanitized name, and the stored byte count.
|
|
301
|
+
*/
|
|
302
|
+
interface FileUpload {
|
|
303
|
+
path: string;
|
|
304
|
+
name: string;
|
|
305
|
+
size: number;
|
|
306
|
+
}
|
|
307
|
+
interface McpServer {
|
|
308
|
+
id: string;
|
|
309
|
+
name: string;
|
|
310
|
+
transport: "http" | "sse" | "stdio";
|
|
311
|
+
url?: string;
|
|
312
|
+
command?: string;
|
|
313
|
+
args?: string[];
|
|
314
|
+
timeoutMs?: number;
|
|
315
|
+
hasSecret: boolean;
|
|
316
|
+
enabled: boolean;
|
|
317
|
+
createdAt?: string;
|
|
318
|
+
updatedAt?: string;
|
|
319
|
+
}
|
|
320
|
+
interface CreateMcpServerRequest {
|
|
321
|
+
name: string;
|
|
322
|
+
transport: "http" | "sse" | "stdio";
|
|
323
|
+
url?: string;
|
|
324
|
+
command?: string;
|
|
325
|
+
args?: string[];
|
|
326
|
+
timeoutMs?: number;
|
|
327
|
+
enabled?: boolean;
|
|
328
|
+
env?: Record<string, string>;
|
|
329
|
+
headers?: Record<string, string>;
|
|
330
|
+
autoApply?: {
|
|
331
|
+
targetType: string;
|
|
332
|
+
targetId?: string;
|
|
333
|
+
};
|
|
334
|
+
}
|
|
335
|
+
interface UpdateMcpServerRequest {
|
|
336
|
+
name?: string;
|
|
337
|
+
url?: string;
|
|
338
|
+
command?: string;
|
|
339
|
+
args?: string[];
|
|
340
|
+
timeoutMs?: number;
|
|
341
|
+
enabled?: boolean;
|
|
342
|
+
env?: Record<string, string>;
|
|
343
|
+
headers?: Record<string, string>;
|
|
344
|
+
}
|
|
345
|
+
interface McpAutoApplyRule {
|
|
346
|
+
targetType: string;
|
|
347
|
+
targetId?: string;
|
|
348
|
+
}
|
|
297
349
|
|
|
298
350
|
declare class LLMSafeSpaces {
|
|
299
351
|
readonly baseUrl: string;
|
|
@@ -319,9 +371,20 @@ declare class LLMSafeSpaces {
|
|
|
319
371
|
readonly agentRoles: AgentRolesAPI;
|
|
320
372
|
readonly workflows: WorkflowsAPI;
|
|
321
373
|
readonly triggers: TriggersAPI;
|
|
374
|
+
readonly mcpServers: McpServersAPI;
|
|
375
|
+
readonly adminMcpServers: AdminMcpServersAPI;
|
|
376
|
+
readonly orgMcpServers: OrgMcpServersAPI;
|
|
322
377
|
constructor(options: ClientOptions);
|
|
323
378
|
/** Internal: make an authenticated request. */
|
|
324
379
|
request<T>(method: string, path: string, body?: unknown, timeout?: number): Promise<T>;
|
|
380
|
+
/**
|
|
381
|
+
* Internal: like {@link request}, but also returns the response headers
|
|
382
|
+
* (e.g. pagination cursors). Body decoding follows the same contract.
|
|
383
|
+
*/
|
|
384
|
+
requestWithHeaders<T>(method: string, path: string, body?: unknown, timeout?: number): Promise<{
|
|
385
|
+
data: T;
|
|
386
|
+
headers: Headers;
|
|
387
|
+
}>;
|
|
325
388
|
private login;
|
|
326
389
|
}
|
|
327
390
|
declare class WorkspacesAPI {
|
|
@@ -333,6 +396,14 @@ declare class WorkspacesAPI {
|
|
|
333
396
|
rename(id: string, name: string): Promise<void>;
|
|
334
397
|
delete(id: string): Promise<void>;
|
|
335
398
|
getStatus(id: string): Promise<WorkspaceStatusResult>;
|
|
399
|
+
/**
|
|
400
|
+
* Uploads a file into the workspace (Epic 67): multipart POST with a
|
|
401
|
+
* single part named `file`; the file lands on the workspace PVC under
|
|
402
|
+
* /workspace/uploads/. The returned path feeds the `files` parameter of
|
|
403
|
+
* sessions.sendPromptAsync / sessions.enqueue. The workspace must be
|
|
404
|
+
* Active; a 409 rejects with ConflictError carrying `phase`.
|
|
405
|
+
*/
|
|
406
|
+
upload(id: string, filename: string, content: Blob | string): Promise<FileUpload>;
|
|
336
407
|
activate(id: string): Promise<ActivateWorkspaceResponse>;
|
|
337
408
|
suspend(id: string): Promise<void>;
|
|
338
409
|
restart(id: string): Promise<void>;
|
|
@@ -378,11 +449,29 @@ declare class SessionsAPI {
|
|
|
378
449
|
sendMessage(workspaceId: string, sessionId: string, content: string): Promise<Message>;
|
|
379
450
|
/** Returns the session transcript in contract shape. */
|
|
380
451
|
getHistory(workspaceId: string, sessionId: string): Promise<Message[]>;
|
|
452
|
+
/**
|
|
453
|
+
* Returns one page of session history with cursor pagination.
|
|
454
|
+
* nextCursor is "" when the beginning of the session was reached
|
|
455
|
+
* (no X-Next-Cursor response header).
|
|
456
|
+
*/
|
|
457
|
+
getHistoryPage(workspaceId: string, sessionId: string, opts?: {
|
|
458
|
+
limit?: number;
|
|
459
|
+
before?: string;
|
|
460
|
+
}): Promise<{
|
|
461
|
+
messages: Message[];
|
|
462
|
+
nextCursor: string;
|
|
463
|
+
}>;
|
|
381
464
|
abort(workspaceId: string, sessionId: string): Promise<void>;
|
|
382
465
|
get(workspaceId: string, sessionId: string): Promise<Record<string, unknown>>;
|
|
383
|
-
|
|
466
|
+
/**
|
|
467
|
+
* Sends a prompt asynchronously (202; the reply arrives on the workspace
|
|
468
|
+
* SSE stream). Optional `files` (Epic 67) are upload-namespace paths —
|
|
469
|
+
* the API composes the v1 attachment manifest into the dispatched text.
|
|
470
|
+
*/
|
|
471
|
+
sendPromptAsync(workspaceId: string, sessionId: string, message: string, files?: string[]): Promise<void>;
|
|
384
472
|
delete(workspaceId: string, sessionId: string): Promise<void>;
|
|
385
|
-
|
|
473
|
+
/** Enqueues a message for a busy session; optional `files` as in sendPromptAsync. */
|
|
474
|
+
enqueue(workspaceId: string, sessionId: string, text: string, files?: string[]): Promise<{
|
|
386
475
|
messageID: string;
|
|
387
476
|
}>;
|
|
388
477
|
/**
|
|
@@ -640,6 +729,50 @@ declare class TriggersAPI {
|
|
|
640
729
|
}): Promise<TriggerResponse>;
|
|
641
730
|
delete(id: string): Promise<void>;
|
|
642
731
|
}
|
|
732
|
+
/** MCP servers owned by the caller (/me/mcp-servers, Epic 53). */
|
|
733
|
+
declare class McpServersAPI {
|
|
734
|
+
private readonly client;
|
|
735
|
+
constructor(client: LLMSafeSpaces);
|
|
736
|
+
list(): Promise<McpServer[]>;
|
|
737
|
+
get(id: string): Promise<McpServer>;
|
|
738
|
+
create(req: CreateMcpServerRequest): Promise<McpServer>;
|
|
739
|
+
update(id: string, req: UpdateMcpServerRequest): Promise<McpServer>;
|
|
740
|
+
delete(id: string): Promise<void>;
|
|
741
|
+
bind(id: string, workspaceId: string): Promise<void>;
|
|
742
|
+
unbind(id: string, workspaceId: string): Promise<void>;
|
|
743
|
+
createAutoApply(id: string, targetType: string, targetId?: string): Promise<void>;
|
|
744
|
+
listAutoApply(id: string): Promise<McpAutoApplyRule[]>;
|
|
745
|
+
}
|
|
746
|
+
/** Platform MCP servers (/admin/mcp-servers; admin scope). */
|
|
747
|
+
declare class AdminMcpServersAPI {
|
|
748
|
+
private readonly client;
|
|
749
|
+
constructor(client: LLMSafeSpaces);
|
|
750
|
+
list(): Promise<McpServer[]>;
|
|
751
|
+
get(id: string): Promise<McpServer>;
|
|
752
|
+
create(req: CreateMcpServerRequest): Promise<McpServer>;
|
|
753
|
+
update(id: string, req: UpdateMcpServerRequest): Promise<McpServer>;
|
|
754
|
+
delete(id: string): Promise<void>;
|
|
755
|
+
bind(id: string, workspaceId: string): Promise<void>;
|
|
756
|
+
unbind(id: string, workspaceId: string): Promise<void>;
|
|
757
|
+
createAutoApply(id: string, targetType: string, targetId?: string): Promise<void>;
|
|
758
|
+
listAutoApply(id: string): Promise<McpAutoApplyRule[]>;
|
|
759
|
+
/** targetId omitted → removes every rule of the targetType. */
|
|
760
|
+
deleteAutoApply(id: string, targetType: string, targetId?: string): Promise<void>;
|
|
761
|
+
}
|
|
762
|
+
/** Organization MCP servers (/orgs/{orgId}/mcp-servers; org-admin scope). */
|
|
763
|
+
declare class OrgMcpServersAPI {
|
|
764
|
+
private readonly client;
|
|
765
|
+
constructor(client: LLMSafeSpaces);
|
|
766
|
+
list(orgId: string): Promise<McpServer[]>;
|
|
767
|
+
get(orgId: string, id: string): Promise<McpServer>;
|
|
768
|
+
create(orgId: string, req: CreateMcpServerRequest): Promise<McpServer>;
|
|
769
|
+
update(orgId: string, id: string, req: UpdateMcpServerRequest): Promise<McpServer>;
|
|
770
|
+
delete(orgId: string, id: string): Promise<void>;
|
|
771
|
+
bind(orgId: string, id: string, workspaceId: string): Promise<void>;
|
|
772
|
+
unbind(orgId: string, id: string, workspaceId: string): Promise<void>;
|
|
773
|
+
createAutoApply(orgId: string, id: string, targetType: string, targetId?: string): Promise<void>;
|
|
774
|
+
listAutoApply(orgId: string, id: string): Promise<McpAutoApplyRule[]>;
|
|
775
|
+
}
|
|
643
776
|
|
|
644
777
|
/** Base error for all LLMSafeSpaces API errors. */
|
|
645
778
|
declare class LLMSafeSpacesError extends Error {
|
|
@@ -654,6 +787,8 @@ declare class NotFoundError extends LLMSafeSpacesError {
|
|
|
654
787
|
constructor(message: string);
|
|
655
788
|
}
|
|
656
789
|
declare class ConflictError extends LLMSafeSpacesError {
|
|
790
|
+
/** Current workspace phase, when the 409 body carries one (upload phase gate, Epic 67 D5). */
|
|
791
|
+
phase?: string;
|
|
657
792
|
constructor(message: string);
|
|
658
793
|
}
|
|
659
794
|
declare class TimeoutError extends LLMSafeSpacesError {
|
|
@@ -678,4 +813,4 @@ declare class ServiceUnavailableError extends LLMSafeSpacesError {
|
|
|
678
813
|
constructor(message?: string, reason?: string, retryAfter?: number);
|
|
679
814
|
}
|
|
680
815
|
|
|
681
|
-
export { type APIKey, type ActivateWorkspaceResponse, type ActiveSessionsResponse, AuthError, type AuthResponse, type ClientOptions, ConflictError, type Cost, type CreateProviderCredentialRequest, type CreateSecretRequest, type CreateWorkspaceRequest, type EnsureSessionResponse, type FetchFn, type FileDiff, type InputOption, type InputRequest, LLMSafeSpaces, LLMSafeSpacesError, type Message, type ModelRef, NotFoundError, type PaginationMetadata, type Part, type ProviderCredential, type QueuedMessage, RateLimitError, type RefreshWorkspaceResult, SECRET_NAME_PATTERN, type SecretResponse, ServiceUnavailableError, type SessionListItem, type TerminalTicket, TimeoutError, type ToolPart, type ToolRef, type UpdateProviderCredentialRequest, type User, type Workspace, type WorkspaceCondition, type WorkspaceListItem, type WorkspaceListResult, type WorkspaceStatusResult };
|
|
816
|
+
export { type APIKey, type ActivateWorkspaceResponse, type ActiveSessionsResponse, AuthError, type AuthResponse, type ClientOptions, ConflictError, type Cost, type CreateMcpServerRequest, type CreateProviderCredentialRequest, type CreateSecretRequest, type CreateWorkspaceRequest, type EnsureSessionResponse, type FetchFn, type FileDiff, type FileUpload, type InputOption, type InputRequest, LLMSafeSpaces, LLMSafeSpacesError, type McpAutoApplyRule, type McpServer, type Message, type ModelRef, NotFoundError, type PaginationMetadata, type Part, type ProviderCredential, type QueuedMessage, RateLimitError, type RefreshWorkspaceResult, SECRET_NAME_PATTERN, type SecretResponse, ServiceUnavailableError, type SessionListItem, type TerminalTicket, TimeoutError, type ToolPart, type ToolRef, type UpdateMcpServerRequest, type UpdateProviderCredentialRequest, type User, type Workspace, type WorkspaceCondition, type WorkspaceListItem, type WorkspaceListResult, type WorkspaceStatusResult };
|
package/dist/index.js
CHANGED
|
@@ -22,6 +22,8 @@ var NotFoundError = class extends LLMSafeSpacesError {
|
|
|
22
22
|
}
|
|
23
23
|
};
|
|
24
24
|
var ConflictError = class extends LLMSafeSpacesError {
|
|
25
|
+
/** Current workspace phase, when the 409 body carries one (upload phase gate, Epic 67 D5). */
|
|
26
|
+
phase;
|
|
25
27
|
constructor(message) {
|
|
26
28
|
super(message, 409, "CONFLICT");
|
|
27
29
|
this.name = "ConflictError";
|
|
@@ -86,6 +88,9 @@ var LLMSafeSpaces = class {
|
|
|
86
88
|
agentRoles;
|
|
87
89
|
workflows;
|
|
88
90
|
triggers;
|
|
91
|
+
mcpServers;
|
|
92
|
+
adminMcpServers;
|
|
93
|
+
orgMcpServers;
|
|
89
94
|
constructor(options) {
|
|
90
95
|
this.baseUrl = options.baseUrl.replace(/\/$/, "");
|
|
91
96
|
this.timeout = options.timeout ?? DEFAULT_TIMEOUT;
|
|
@@ -108,11 +113,15 @@ var LLMSafeSpaces = class {
|
|
|
108
113
|
this.agentRoles = new AgentRolesAPI(this);
|
|
109
114
|
this.workflows = new WorkflowsAPI(this);
|
|
110
115
|
this.triggers = new TriggersAPI(this);
|
|
116
|
+
this.mcpServers = new McpServersAPI(this);
|
|
117
|
+
this.adminMcpServers = new AdminMcpServersAPI(this);
|
|
118
|
+
this.orgMcpServers = new OrgMcpServersAPI(this);
|
|
111
119
|
}
|
|
112
120
|
/** Internal: make an authenticated request. */
|
|
113
121
|
async request(method, path, body, timeout) {
|
|
114
122
|
const url = `${this.baseUrl}/api/v1${path}`;
|
|
115
|
-
const
|
|
123
|
+
const isForm = typeof FormData !== "undefined" && body instanceof FormData;
|
|
124
|
+
const headers = isForm ? {} : { "Content-Type": "application/json" };
|
|
116
125
|
if (this.apiKey) {
|
|
117
126
|
headers["Authorization"] = `Bearer ${this.apiKey}`;
|
|
118
127
|
} else if (this.token) {
|
|
@@ -128,7 +137,7 @@ var LLMSafeSpaces = class {
|
|
|
128
137
|
res = await this.fetchFn(url, {
|
|
129
138
|
method,
|
|
130
139
|
headers,
|
|
131
|
-
body: body ? JSON.stringify(body) : void 0,
|
|
140
|
+
body: body ? isForm ? body : JSON.stringify(body) : void 0,
|
|
132
141
|
signal: controller.signal
|
|
133
142
|
});
|
|
134
143
|
} catch (e) {
|
|
@@ -152,8 +161,12 @@ var LLMSafeSpaces = class {
|
|
|
152
161
|
throw new AuthError(msg, res.status);
|
|
153
162
|
case 404:
|
|
154
163
|
throw new NotFoundError(msg);
|
|
155
|
-
case 409:
|
|
156
|
-
|
|
164
|
+
case 409: {
|
|
165
|
+
const phase = errBody.phase;
|
|
166
|
+
const conflict = new ConflictError(msg);
|
|
167
|
+
if (phase) conflict.phase = phase;
|
|
168
|
+
throw conflict;
|
|
169
|
+
}
|
|
157
170
|
case 429:
|
|
158
171
|
throw new RateLimitError(msg);
|
|
159
172
|
case 503: {
|
|
@@ -171,6 +184,52 @@ var LLMSafeSpaces = class {
|
|
|
171
184
|
if (text === "") return void 0;
|
|
172
185
|
return JSON.parse(text);
|
|
173
186
|
}
|
|
187
|
+
/**
|
|
188
|
+
* Internal: like {@link request}, but also returns the response headers
|
|
189
|
+
* (e.g. pagination cursors). Body decoding follows the same contract.
|
|
190
|
+
*/
|
|
191
|
+
async requestWithHeaders(method, path, body, timeout) {
|
|
192
|
+
const url = `${this.baseUrl}/api/v1${path}`;
|
|
193
|
+
const headers = { "Content-Type": "application/json" };
|
|
194
|
+
if (this.apiKey) {
|
|
195
|
+
headers["Authorization"] = `Bearer ${this.apiKey}`;
|
|
196
|
+
} else if (this.token) {
|
|
197
|
+
headers["Authorization"] = `Bearer ${this.token}`;
|
|
198
|
+
}
|
|
199
|
+
const controller = new AbortController();
|
|
200
|
+
const timer = setTimeout(() => controller.abort(), timeout ?? this.timeout);
|
|
201
|
+
let res;
|
|
202
|
+
try {
|
|
203
|
+
res = await this.fetchFn(url, {
|
|
204
|
+
method,
|
|
205
|
+
headers,
|
|
206
|
+
body: body ? JSON.stringify(body) : void 0,
|
|
207
|
+
signal: controller.signal
|
|
208
|
+
});
|
|
209
|
+
} catch (e) {
|
|
210
|
+
clearTimeout(timer);
|
|
211
|
+
if (e instanceof Error && e.name === "AbortError") {
|
|
212
|
+
throw new TimeoutError();
|
|
213
|
+
}
|
|
214
|
+
throw e;
|
|
215
|
+
}
|
|
216
|
+
clearTimeout(timer);
|
|
217
|
+
if (!res.ok) {
|
|
218
|
+
const errBody = await res.json().catch(() => ({ error: res.statusText }));
|
|
219
|
+
const msg = errBody.error ?? res.statusText;
|
|
220
|
+
if (res.status === 401 || res.status === 403) throw new AuthError(msg, res.status);
|
|
221
|
+
if (res.status === 404) throw new NotFoundError(msg);
|
|
222
|
+
throw new LLMSafeSpacesError(msg, res.status);
|
|
223
|
+
}
|
|
224
|
+
let data;
|
|
225
|
+
if (res.status === 204) {
|
|
226
|
+
data = void 0;
|
|
227
|
+
} else {
|
|
228
|
+
const text = await res.text();
|
|
229
|
+
data = text === "" ? void 0 : JSON.parse(text);
|
|
230
|
+
}
|
|
231
|
+
return { data, headers: res.headers };
|
|
232
|
+
}
|
|
174
233
|
async login() {
|
|
175
234
|
if (!this.credentials) throw new AuthError("No credentials configured");
|
|
176
235
|
this.loggingIn = true;
|
|
@@ -212,6 +271,18 @@ var WorkspacesAPI = class {
|
|
|
212
271
|
getStatus(id) {
|
|
213
272
|
return this.client.request("GET", `/workspaces/${id}/status`);
|
|
214
273
|
}
|
|
274
|
+
/**
|
|
275
|
+
* Uploads a file into the workspace (Epic 67): multipart POST with a
|
|
276
|
+
* single part named `file`; the file lands on the workspace PVC under
|
|
277
|
+
* /workspace/uploads/. The returned path feeds the `files` parameter of
|
|
278
|
+
* sessions.sendPromptAsync / sessions.enqueue. The workspace must be
|
|
279
|
+
* Active; a 409 rejects with ConflictError carrying `phase`.
|
|
280
|
+
*/
|
|
281
|
+
upload(id, filename, content) {
|
|
282
|
+
const form = new FormData();
|
|
283
|
+
form.append("file", typeof content === "string" ? new Blob([content]) : content, filename);
|
|
284
|
+
return this.client.request("POST", `/workspaces/${id}/uploads`, form);
|
|
285
|
+
}
|
|
215
286
|
activate(id) {
|
|
216
287
|
return this.client.request("POST", `/workspaces/${id}/activate`);
|
|
217
288
|
}
|
|
@@ -293,20 +364,44 @@ var SessionsAPI = class {
|
|
|
293
364
|
getHistory(workspaceId, sessionId) {
|
|
294
365
|
return this.client.request("GET", `/workspaces/${workspaceId}/sessions/${sessionId}/message`);
|
|
295
366
|
}
|
|
367
|
+
/**
|
|
368
|
+
* Returns one page of session history with cursor pagination.
|
|
369
|
+
* nextCursor is "" when the beginning of the session was reached
|
|
370
|
+
* (no X-Next-Cursor response header).
|
|
371
|
+
*/
|
|
372
|
+
async getHistoryPage(workspaceId, sessionId, opts) {
|
|
373
|
+
const q = new URLSearchParams();
|
|
374
|
+
if (opts?.limit && opts.limit > 0) q.set("limit", String(opts.limit));
|
|
375
|
+
if (opts?.before) q.set("before", opts.before);
|
|
376
|
+
const qs = q.toString();
|
|
377
|
+
const path = `/workspaces/${workspaceId}/sessions/${sessionId}/message${qs ? `?${qs}` : ""}`;
|
|
378
|
+
const { data, headers } = await this.client.requestWithHeaders("GET", path);
|
|
379
|
+
return { messages: data ?? [], nextCursor: headers.get("X-Next-Cursor") ?? "" };
|
|
380
|
+
}
|
|
296
381
|
abort(workspaceId, sessionId) {
|
|
297
382
|
return this.client.request("POST", `/workspaces/${workspaceId}/sessions/${sessionId}/abort`);
|
|
298
383
|
}
|
|
299
384
|
get(workspaceId, sessionId) {
|
|
300
385
|
return this.client.request("GET", `/workspaces/${workspaceId}/sessions/${sessionId}`);
|
|
301
386
|
}
|
|
302
|
-
|
|
303
|
-
|
|
387
|
+
/**
|
|
388
|
+
* Sends a prompt asynchronously (202; the reply arrives on the workspace
|
|
389
|
+
* SSE stream). Optional `files` (Epic 67) are upload-namespace paths —
|
|
390
|
+
* the API composes the v1 attachment manifest into the dispatched text.
|
|
391
|
+
*/
|
|
392
|
+
sendPromptAsync(workspaceId, sessionId, message, files) {
|
|
393
|
+
const body = { parts: [{ type: "text", text: message }] };
|
|
394
|
+
if (files && files.length > 0) body.files = files;
|
|
395
|
+
return this.client.request("POST", `/workspaces/${workspaceId}/sessions/${sessionId}/prompt`, body);
|
|
304
396
|
}
|
|
305
397
|
delete(workspaceId, sessionId) {
|
|
306
398
|
return this.client.request("DELETE", `/workspaces/${workspaceId}/sessions/${sessionId}`);
|
|
307
399
|
}
|
|
308
|
-
|
|
309
|
-
|
|
400
|
+
/** Enqueues a message for a busy session; optional `files` as in sendPromptAsync. */
|
|
401
|
+
enqueue(workspaceId, sessionId, text, files) {
|
|
402
|
+
const body = { text };
|
|
403
|
+
if (files && files.length > 0) body.files = files;
|
|
404
|
+
return this.client.request("POST", `/workspaces/${workspaceId}/sessions/${sessionId}/queue`, body);
|
|
310
405
|
}
|
|
311
406
|
/**
|
|
312
407
|
* @deprecated Under the V2 session-queue model (Epic 63), the queue is
|
|
@@ -641,6 +736,110 @@ var TriggersAPI = class {
|
|
|
641
736
|
return this.client.request("DELETE", `/me/triggers/${id}`);
|
|
642
737
|
}
|
|
643
738
|
};
|
|
739
|
+
var McpServersAPI = class {
|
|
740
|
+
constructor(client) {
|
|
741
|
+
this.client = client;
|
|
742
|
+
}
|
|
743
|
+
client;
|
|
744
|
+
list() {
|
|
745
|
+
return this.client.request("GET", "/me/mcp-servers").then((r) => Array.isArray(r) ? r : r.servers ?? []);
|
|
746
|
+
}
|
|
747
|
+
get(id) {
|
|
748
|
+
return this.client.request("GET", `/me/mcp-servers/${id}`);
|
|
749
|
+
}
|
|
750
|
+
create(req) {
|
|
751
|
+
return this.client.request("POST", "/me/mcp-servers", req);
|
|
752
|
+
}
|
|
753
|
+
update(id, req) {
|
|
754
|
+
return this.client.request("PUT", `/me/mcp-servers/${id}`, req);
|
|
755
|
+
}
|
|
756
|
+
delete(id) {
|
|
757
|
+
return this.client.request("DELETE", `/me/mcp-servers/${id}`);
|
|
758
|
+
}
|
|
759
|
+
bind(id, workspaceId) {
|
|
760
|
+
return this.client.request("POST", `/me/mcp-servers/${id}/bindings`, { workspaceId });
|
|
761
|
+
}
|
|
762
|
+
unbind(id, workspaceId) {
|
|
763
|
+
return this.client.request("DELETE", `/me/mcp-servers/${id}/bindings/${workspaceId}`);
|
|
764
|
+
}
|
|
765
|
+
createAutoApply(id, targetType, targetId) {
|
|
766
|
+
return this.client.request("POST", `/me/mcp-servers/${id}/auto-apply`, { targetType, targetId });
|
|
767
|
+
}
|
|
768
|
+
listAutoApply(id) {
|
|
769
|
+
return this.client.request("GET", `/me/mcp-servers/${id}/auto-apply`).then((r) => Array.isArray(r) ? r : r.rules ?? []);
|
|
770
|
+
}
|
|
771
|
+
};
|
|
772
|
+
var AdminMcpServersAPI = class {
|
|
773
|
+
constructor(client) {
|
|
774
|
+
this.client = client;
|
|
775
|
+
}
|
|
776
|
+
client;
|
|
777
|
+
list() {
|
|
778
|
+
return this.client.request("GET", "/admin/mcp-servers").then((r) => Array.isArray(r) ? r : r.servers ?? []);
|
|
779
|
+
}
|
|
780
|
+
get(id) {
|
|
781
|
+
return this.client.request("GET", `/admin/mcp-servers/${id}`);
|
|
782
|
+
}
|
|
783
|
+
create(req) {
|
|
784
|
+
return this.client.request("POST", "/admin/mcp-servers", req);
|
|
785
|
+
}
|
|
786
|
+
update(id, req) {
|
|
787
|
+
return this.client.request("PUT", `/admin/mcp-servers/${id}`, req);
|
|
788
|
+
}
|
|
789
|
+
delete(id) {
|
|
790
|
+
return this.client.request("DELETE", `/admin/mcp-servers/${id}`);
|
|
791
|
+
}
|
|
792
|
+
bind(id, workspaceId) {
|
|
793
|
+
return this.client.request("POST", `/admin/mcp-servers/${id}/bindings`, { workspaceId });
|
|
794
|
+
}
|
|
795
|
+
unbind(id, workspaceId) {
|
|
796
|
+
return this.client.request("DELETE", `/admin/mcp-servers/${id}/bindings/${workspaceId}`);
|
|
797
|
+
}
|
|
798
|
+
createAutoApply(id, targetType, targetId) {
|
|
799
|
+
return this.client.request("POST", `/admin/mcp-servers/${id}/auto-apply`, { targetType, targetId });
|
|
800
|
+
}
|
|
801
|
+
listAutoApply(id) {
|
|
802
|
+
return this.client.request("GET", `/admin/mcp-servers/${id}/auto-apply`).then((r) => Array.isArray(r) ? r : r.rules ?? []);
|
|
803
|
+
}
|
|
804
|
+
/** targetId omitted → removes every rule of the targetType. */
|
|
805
|
+
deleteAutoApply(id, targetType, targetId) {
|
|
806
|
+
const suffix = targetId ? `/${targetId}` : "";
|
|
807
|
+
return this.client.request("DELETE", `/admin/mcp-servers/${id}/auto-apply/${targetType}${suffix}`);
|
|
808
|
+
}
|
|
809
|
+
};
|
|
810
|
+
var OrgMcpServersAPI = class {
|
|
811
|
+
constructor(client) {
|
|
812
|
+
this.client = client;
|
|
813
|
+
}
|
|
814
|
+
client;
|
|
815
|
+
list(orgId) {
|
|
816
|
+
return this.client.request("GET", `/orgs/${orgId}/mcp-servers`).then((r) => Array.isArray(r) ? r : r.servers ?? []);
|
|
817
|
+
}
|
|
818
|
+
get(orgId, id) {
|
|
819
|
+
return this.client.request("GET", `/orgs/${orgId}/mcp-servers/${id}`);
|
|
820
|
+
}
|
|
821
|
+
create(orgId, req) {
|
|
822
|
+
return this.client.request("POST", `/orgs/${orgId}/mcp-servers`, req);
|
|
823
|
+
}
|
|
824
|
+
update(orgId, id, req) {
|
|
825
|
+
return this.client.request("PUT", `/orgs/${orgId}/mcp-servers/${id}`, req);
|
|
826
|
+
}
|
|
827
|
+
delete(orgId, id) {
|
|
828
|
+
return this.client.request("DELETE", `/orgs/${orgId}/mcp-servers/${id}`);
|
|
829
|
+
}
|
|
830
|
+
bind(orgId, id, workspaceId) {
|
|
831
|
+
return this.client.request("POST", `/orgs/${orgId}/mcp-servers/${id}/bindings`, { workspaceId });
|
|
832
|
+
}
|
|
833
|
+
unbind(orgId, id, workspaceId) {
|
|
834
|
+
return this.client.request("DELETE", `/orgs/${orgId}/mcp-servers/${id}/bindings/${workspaceId}`);
|
|
835
|
+
}
|
|
836
|
+
createAutoApply(orgId, id, targetType, targetId) {
|
|
837
|
+
return this.client.request("POST", `/orgs/${orgId}/mcp-servers/${id}/auto-apply`, { targetType, targetId });
|
|
838
|
+
}
|
|
839
|
+
listAutoApply(orgId, id) {
|
|
840
|
+
return this.client.request("GET", `/orgs/${orgId}/mcp-servers/${id}/auto-apply`).then((r) => Array.isArray(r) ? r : r.rules ?? []);
|
|
841
|
+
}
|
|
842
|
+
};
|
|
644
843
|
|
|
645
844
|
// src/types.ts
|
|
646
845
|
var SECRET_NAME_PATTERN = /^[a-z0-9._-]+$/;
|