@opengeni/api-router 0.12.5 → 0.12.7
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/app.js +1 -1
- package/dist/{chunk-3BHOMOSD.js → chunk-SD5GJTZ4.js} +234 -70
- package/dist/chunk-SD5GJTZ4.js.map +1 -0
- package/dist/index.js +10 -4
- package/dist/index.js.map +1 -1
- package/package.json +10 -10
- package/src/app.ts +4 -0
- package/src/index.ts +8 -3
- package/src/mcp/files.ts +77 -0
- package/src/mcp/server.ts +170 -47
- package/src/routes/files.ts +11 -0
- package/src/routes/scheduled-tasks.ts +1 -0
- package/dist/chunk-3BHOMOSD.js.map +0 -1
package/dist/app.js
CHANGED
|
@@ -21,13 +21,13 @@ import {
|
|
|
21
21
|
import { dbSql, getWorkspace as getWorkspace2 } from "@opengeni/db";
|
|
22
22
|
import { createObservability } from "@opengeni/observability";
|
|
23
23
|
import { createObjectStorage } from "@opengeni/storage";
|
|
24
|
-
import { WebStandardStreamableHTTPServerTransport as
|
|
24
|
+
import { WebStandardStreamableHTTPServerTransport as WebStandardStreamableHTTPServerTransport3 } from "@modelcontextprotocol/sdk/server/webStandardStreamableHttp.js";
|
|
25
25
|
import { Hono } from "hono";
|
|
26
26
|
import { bodyLimit } from "hono/body-limit";
|
|
27
27
|
import { cors } from "hono/cors";
|
|
28
28
|
import { HTTPException as HTTPException26 } from "hono/http-exception";
|
|
29
29
|
import {
|
|
30
|
-
hasPermission as
|
|
30
|
+
hasPermission as hasPermission10,
|
|
31
31
|
requireAccessGrant as requireAccessGrant18,
|
|
32
32
|
requirePermission,
|
|
33
33
|
requireSessionAuthorization as requireSessionAuthorization3,
|
|
@@ -291,6 +291,8 @@ import { requireLimit as requireLimit8 } from "@opengeni/core";
|
|
|
291
291
|
// src/mcp/server.ts
|
|
292
292
|
import {
|
|
293
293
|
CreateScheduledTaskRequest,
|
|
294
|
+
DEFAULT_FIRST_PARTY_MCP_TOOLS,
|
|
295
|
+
FIRST_PARTY_MCP_TOOL_NAMES,
|
|
294
296
|
defaultRepositoryMountPath,
|
|
295
297
|
SESSION_EVENT_RAW_DELTA_TYPES,
|
|
296
298
|
SessionEventLatestClass,
|
|
@@ -335,7 +337,6 @@ import {
|
|
|
335
337
|
MEMORY_CORRECT_TOOL_DESCRIPTION,
|
|
336
338
|
MEMORY_SAVE_TOOL_DESCRIPTION,
|
|
337
339
|
MEMORY_SEARCH_TOOL_DESCRIPTION,
|
|
338
|
-
requireFile,
|
|
339
340
|
requireScheduledTask,
|
|
340
341
|
requireSession,
|
|
341
342
|
saveWorkspaceMemory,
|
|
@@ -356,7 +357,9 @@ import {
|
|
|
356
357
|
GitHubAppConfigurationError,
|
|
357
358
|
githubAppMissingSettings
|
|
358
359
|
} from "@opengeni/github";
|
|
359
|
-
import {
|
|
360
|
+
import {
|
|
361
|
+
McpServer
|
|
362
|
+
} from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
360
363
|
import * as z4 from "zod/v4";
|
|
361
364
|
import {
|
|
362
365
|
hasPermission as hasPermission2,
|
|
@@ -2607,17 +2610,124 @@ function slackPostOutcomeMayBeAmbiguous(error) {
|
|
|
2607
2610
|
}
|
|
2608
2611
|
|
|
2609
2612
|
// src/mcp/server.ts
|
|
2613
|
+
var FIRST_PARTY_TOOL_AUTHORIZATION = {
|
|
2614
|
+
set_session_title: { sessionRequired: true, allOf: ["sessions:control"] },
|
|
2615
|
+
goal_set: { sessionRequired: true, allOf: ["goals:manage"] },
|
|
2616
|
+
goal_update: { sessionRequired: true, allOf: ["goals:manage"] },
|
|
2617
|
+
goal_complete: { sessionRequired: true, allOf: ["goals:manage"] },
|
|
2618
|
+
goal_pause: { sessionRequired: true, allOf: ["goals:manage"] },
|
|
2619
|
+
memory_search: { sessionRequired: true, allOf: ["documents:search"] },
|
|
2620
|
+
memory_save: { sessionRequired: true, allOf: ["documents:search"] },
|
|
2621
|
+
memory_correct: { sessionRequired: true, allOf: ["documents:search"] },
|
|
2622
|
+
sandboxes_list: { sessionRequired: true, allOf: ["sessions:read"] },
|
|
2623
|
+
sandbox_attach: { sessionRequired: true, allOf: ["sessions:control"] },
|
|
2624
|
+
sandbox_swap: { sessionRequired: true, allOf: ["sessions:control"] },
|
|
2625
|
+
run_on: { sessionRequired: true, allOf: ["sessions:control"] },
|
|
2626
|
+
sandbox_provision: { sessionRequired: true, allOf: ["sessions:control"] },
|
|
2627
|
+
rig_list: { allOf: ["rigs:use"] },
|
|
2628
|
+
rig_get: { allOf: ["rigs:use"] },
|
|
2629
|
+
rig_propose_change: { allOf: ["rigs:use"] },
|
|
2630
|
+
rig_verify: { allOf: ["rigs:use"] },
|
|
2631
|
+
rig_promote: { allOf: ["rigs:manage"] },
|
|
2632
|
+
sessions_list: { allOf: ["sessions:read"] },
|
|
2633
|
+
session_get: { allOf: ["sessions:read"] },
|
|
2634
|
+
session_events: { allOf: ["sessions:read"] },
|
|
2635
|
+
session_create: { allOf: ["sessions:create"] },
|
|
2636
|
+
session_send_message: { allOf: ["sessions:control"] },
|
|
2637
|
+
session_pause: { allOf: ["sessions:control"] },
|
|
2638
|
+
session_resume: { allOf: ["sessions:control"] },
|
|
2639
|
+
session_steer: { sessionRequired: true, allOf: ["sessions:control"] },
|
|
2640
|
+
set_other_session_title: { allOf: ["sessions:control"] },
|
|
2641
|
+
variable_set_list: { allOf: ["variable-sets:use"] },
|
|
2642
|
+
environment_list: { allOf: ["variable-sets:use"] },
|
|
2643
|
+
variable_set_set_variable: { allOf: ["variable-sets:manage"] },
|
|
2644
|
+
environment_set_variable: { allOf: ["variable-sets:manage"] },
|
|
2645
|
+
github_connect_link: { allOf: ["github:use"] },
|
|
2646
|
+
github_token: { sessionRequired: true, allOf: ["github:use"] },
|
|
2647
|
+
github_repositories_list: { allOf: ["github:use"] },
|
|
2648
|
+
social_connections_list: { allOf: ["connections:read"] },
|
|
2649
|
+
social_posts_recent: { allOf: ["connections:read"] },
|
|
2650
|
+
social_daily_analysis_context: { allOf: ["connections:read"] },
|
|
2651
|
+
scheduled_tasks_list: { anyOf: ["scheduled_tasks:manage", "scheduled_tasks:run"] },
|
|
2652
|
+
scheduled_tasks_get: { anyOf: ["scheduled_tasks:manage", "scheduled_tasks:run"] },
|
|
2653
|
+
scheduled_tasks_create: { allOf: ["scheduled_tasks:manage"] },
|
|
2654
|
+
scheduled_tasks_update: { allOf: ["scheduled_tasks:manage"] },
|
|
2655
|
+
scheduled_tasks_pause: { allOf: ["scheduled_tasks:manage"] },
|
|
2656
|
+
scheduled_tasks_resume: { allOf: ["scheduled_tasks:manage"] },
|
|
2657
|
+
scheduled_tasks_trigger: { allOf: ["scheduled_tasks:run"] },
|
|
2658
|
+
scheduled_tasks_delete: { allOf: ["scheduled_tasks:manage"] },
|
|
2659
|
+
scheduled_task_runs_list: { anyOf: ["scheduled_tasks:manage", "scheduled_tasks:run"] },
|
|
2660
|
+
slack_bot_list_channels: { allOf: ["connections:read"] },
|
|
2661
|
+
slack_bot_channel_history: { allOf: ["connections:read"] },
|
|
2662
|
+
slack_bot_list_users: { allOf: ["connections:read"] },
|
|
2663
|
+
slack_bot_post_message: { allOf: ["connections:read"] }
|
|
2664
|
+
};
|
|
2665
|
+
var FIRST_PARTY_MCP_TOOL_NAME_SET = new Set(FIRST_PARTY_MCP_TOOL_NAMES);
|
|
2666
|
+
var PolicyMcpServer = class extends McpServer {
|
|
2667
|
+
constructor(grant, sessionId, selectedTools, allowUncatalogued) {
|
|
2668
|
+
super({ name: "opengeni", version: "1.0.0" });
|
|
2669
|
+
this.grant = grant;
|
|
2670
|
+
this.sessionId = sessionId;
|
|
2671
|
+
this.selectedTools = selectedTools;
|
|
2672
|
+
this.allowUncatalogued = allowUncatalogued;
|
|
2673
|
+
}
|
|
2674
|
+
registeredToolCount = 0;
|
|
2675
|
+
registerTool(name, config, cb) {
|
|
2676
|
+
const catalogued = FIRST_PARTY_MCP_TOOL_NAME_SET.has(name);
|
|
2677
|
+
let admitted = this.allowUncatalogued && !catalogued;
|
|
2678
|
+
if (catalogued) {
|
|
2679
|
+
const toolName = name;
|
|
2680
|
+
const policy = FIRST_PARTY_TOOL_AUTHORIZATION[toolName];
|
|
2681
|
+
const authorized = (!policy.sessionRequired || this.sessionId !== null) && (policy.allOf?.every((permission) => hasPermission2(this.grant.permissions, permission)) ?? true) && (policy.anyOf?.some((permission) => hasPermission2(this.grant.permissions, permission)) ?? true);
|
|
2682
|
+
const selected = this.selectedTools === null || this.selectedTools.has(toolName);
|
|
2683
|
+
admitted = authorized && selected;
|
|
2684
|
+
}
|
|
2685
|
+
if (!admitted) {
|
|
2686
|
+
return {
|
|
2687
|
+
...config.title ? { title: config.title } : {},
|
|
2688
|
+
...config.description ? { description: config.description } : {},
|
|
2689
|
+
...config.annotations ? { annotations: config.annotations } : {},
|
|
2690
|
+
...config._meta ? { _meta: config._meta } : {},
|
|
2691
|
+
handler: cb,
|
|
2692
|
+
enabled: false,
|
|
2693
|
+
enable() {
|
|
2694
|
+
},
|
|
2695
|
+
disable() {
|
|
2696
|
+
},
|
|
2697
|
+
update() {
|
|
2698
|
+
},
|
|
2699
|
+
remove() {
|
|
2700
|
+
}
|
|
2701
|
+
};
|
|
2702
|
+
}
|
|
2703
|
+
this.registeredToolCount += 1;
|
|
2704
|
+
return super.registerTool(name, config, cb);
|
|
2705
|
+
}
|
|
2706
|
+
ensureToolsListHandler() {
|
|
2707
|
+
if (this.registeredToolCount > 0) return;
|
|
2708
|
+
super.registerTool(
|
|
2709
|
+
"__opengeni_empty_first_party_surface__",
|
|
2710
|
+
{
|
|
2711
|
+
description: "Internal disabled placeholder for an empty first-party surface.",
|
|
2712
|
+
inputSchema: z4.object({})
|
|
2713
|
+
},
|
|
2714
|
+
async () => ({
|
|
2715
|
+
content: [{ type: "text", text: '{"unavailable":true}' }]
|
|
2716
|
+
})
|
|
2717
|
+
).disable();
|
|
2718
|
+
}
|
|
2719
|
+
};
|
|
2610
2720
|
function buildOpenGeniMcpServer(deps, grant, options = {}) {
|
|
2611
|
-
const server = new McpServer({
|
|
2612
|
-
name: "opengeni",
|
|
2613
|
-
version: "1.0.0"
|
|
2614
|
-
});
|
|
2615
2721
|
const json = (value) => ({
|
|
2616
2722
|
content: [{ type: "text", text: JSON.stringify(value, null, 2) }]
|
|
2617
2723
|
});
|
|
2618
2724
|
const can = (permission) => hasPermission2(grant.permissions, permission);
|
|
2619
2725
|
const toolspaceMode = options.toolspace != null;
|
|
2620
2726
|
const sessionId = typeof grant.metadata?.["sessionId"] === "string" ? grant.metadata["sessionId"] : null;
|
|
2727
|
+
const selectedTools = sessionId !== null && !toolspaceMode ? new Set(
|
|
2728
|
+
grant.metadata?.["firstPartyMcpTools"] ?? DEFAULT_FIRST_PARTY_MCP_TOOLS
|
|
2729
|
+
) : null;
|
|
2730
|
+
const server = new PolicyMcpServer(grant, sessionId, selectedTools, toolspaceMode);
|
|
2621
2731
|
if (sessionId !== null && (!toolspaceMode || can("sessions:control"))) {
|
|
2622
2732
|
server.registerTool(
|
|
2623
2733
|
"set_session_title",
|
|
@@ -2657,44 +2767,6 @@ function buildOpenGeniMcpServer(deps, grant, options = {}) {
|
|
|
2657
2767
|
registerGitHubTokenTool(server, deps, grant, sessionId, json);
|
|
2658
2768
|
}
|
|
2659
2769
|
}
|
|
2660
|
-
if (!toolspaceMode || can("files:read")) {
|
|
2661
|
-
server.registerTool(
|
|
2662
|
-
"files_get_download_url",
|
|
2663
|
-
{
|
|
2664
|
-
description: "Create a short-lived download URL for a ready file asset.",
|
|
2665
|
-
inputSchema: { fileId: z4.string().uuid() }
|
|
2666
|
-
},
|
|
2667
|
-
async ({ fileId }) => {
|
|
2668
|
-
if (!deps.objectStorage) {
|
|
2669
|
-
throw new Error("object storage is not configured");
|
|
2670
|
-
}
|
|
2671
|
-
const file = await requireFile(deps.db, grant.workspaceId, fileId);
|
|
2672
|
-
if (file.status !== "ready") {
|
|
2673
|
-
throw new Error(`file is ${file.status}`);
|
|
2674
|
-
}
|
|
2675
|
-
const signed = await deps.objectStorage.createGetUrl({
|
|
2676
|
-
key: file.objectKey
|
|
2677
|
-
});
|
|
2678
|
-
return json({
|
|
2679
|
-
file: {
|
|
2680
|
-
id: file.id,
|
|
2681
|
-
filename: file.filename,
|
|
2682
|
-
safeFilename: file.safeFilename,
|
|
2683
|
-
contentType: file.contentType,
|
|
2684
|
-
sizeBytes: file.sizeBytes,
|
|
2685
|
-
sha256: file.sha256,
|
|
2686
|
-
status: file.status,
|
|
2687
|
-
createdAt: file.createdAt,
|
|
2688
|
-
updatedAt: file.updatedAt
|
|
2689
|
-
},
|
|
2690
|
-
downloadUrl: {
|
|
2691
|
-
url: signed.url,
|
|
2692
|
-
expiresAt: signed.expiresAt.toISOString()
|
|
2693
|
-
}
|
|
2694
|
-
});
|
|
2695
|
-
}
|
|
2696
|
-
);
|
|
2697
|
-
}
|
|
2698
2770
|
if (!toolspaceMode || can("github:use")) {
|
|
2699
2771
|
server.registerTool(
|
|
2700
2772
|
"github_repositories_list",
|
|
@@ -2985,7 +3057,8 @@ function buildOpenGeniMcpServer(deps, grant, options = {}) {
|
|
|
2985
3057
|
await deps.workflowClient.triggerScheduledTask({
|
|
2986
3058
|
task,
|
|
2987
3059
|
agentRunUsageIdempotencyKey,
|
|
2988
|
-
triggerWorkflowId
|
|
3060
|
+
triggerWorkflowId,
|
|
3061
|
+
initiator: { kind: "subject", subjectId: grant.subjectId }
|
|
2989
3062
|
});
|
|
2990
3063
|
await recordWorkspaceUsage(deps, {
|
|
2991
3064
|
accountId: grant.accountId,
|
|
@@ -3031,6 +3104,7 @@ function buildOpenGeniMcpServer(deps, grant, options = {}) {
|
|
|
3031
3104
|
);
|
|
3032
3105
|
}
|
|
3033
3106
|
registerToolspaceProxyTools(server, options.toolspace ?? null);
|
|
3107
|
+
server.ensureToolsListHandler();
|
|
3034
3108
|
return server;
|
|
3035
3109
|
}
|
|
3036
3110
|
function registerSlackBotTools(server, deps, grant, sessionId, json) {
|
|
@@ -3896,6 +3970,9 @@ function registerWorkspaceOrchestrationTools(server, deps, grant, can, callerSes
|
|
|
3896
3970
|
firstPartyMcpPermissions: z4.array(z4.string()).optional().describe(
|
|
3897
3971
|
"Optional first-party capability set for the child. Omit to inherit this session's effective permissions. An explicit set may only narrow capabilities held by this session. A goal-bearing child requires goals:manage in the resulting set; creation fails rather than adding it implicitly."
|
|
3898
3972
|
),
|
|
3973
|
+
firstPartyMcpTools: z4.array(z4.enum(FIRST_PARTY_MCP_TOOL_NAMES)).optional().describe(
|
|
3974
|
+
"Exact model-visible first-party tool selection for the child. Omit to inherit this session's effective selection. This does not grant permissions."
|
|
3975
|
+
),
|
|
3899
3976
|
// Shared-sandbox placement (addendum 05 §D). OMIT (default) to SHARE the
|
|
3900
3977
|
// creator's box — one filesystem/repo/desktop, N independent conversations;
|
|
3901
3978
|
// this is the SAFE DEFAULT. Pass "new" for a fresh isolated box (a different
|
|
@@ -3949,7 +4026,7 @@ function registerWorkspaceOrchestrationTools(server, deps, grant, can, callerSes
|
|
|
3949
4026
|
server.registerTool(
|
|
3950
4027
|
"session_send_message",
|
|
3951
4028
|
{
|
|
3952
|
-
description: "Send information to another session. From an OpenGeni worker this becomes a coalescible
|
|
4029
|
+
description: "Send information to another session. From an OpenGeni worker this becomes a canonical coalescible machine input: it appears in the target's compact incoming queue group, is durably added to model history when claimed, and remains visible in the timeline. A sessionless operator call appends one human/API prompt.",
|
|
3953
4030
|
inputSchema: {
|
|
3954
4031
|
sessionId: z4.string().uuid(),
|
|
3955
4032
|
text: z4.string().min(1),
|
|
@@ -4129,7 +4206,7 @@ function registerWorkspaceOrchestrationTools(server, deps, grant, can, callerSes
|
|
|
4129
4206
|
server.registerTool(
|
|
4130
4207
|
"session_steer",
|
|
4131
4208
|
{
|
|
4132
|
-
description: "Atomically replace another session's current direction and resume it. The
|
|
4209
|
+
description: "Atomically replace another session's current direction and resume it. The Agent Steer is a typed machine input shown in the target queue/timeline and durably retained in model history; it never impersonates a human prompt.",
|
|
4133
4210
|
inputSchema: {
|
|
4134
4211
|
sessionId: z4.string().uuid(),
|
|
4135
4212
|
instruction: z4.string().min(1),
|
|
@@ -5881,8 +5958,8 @@ function registerCatalogAssetRoutes(app, deps) {
|
|
|
5881
5958
|
if (!contentType) {
|
|
5882
5959
|
throw new HTTPException5(404, { message: "asset not found" });
|
|
5883
5960
|
}
|
|
5884
|
-
const
|
|
5885
|
-
if (!
|
|
5961
|
+
const object5 = await objectStorage.getObjectBytes(key);
|
|
5962
|
+
if (!object5) {
|
|
5886
5963
|
throw new HTTPException5(404, { message: "asset not found" });
|
|
5887
5964
|
}
|
|
5888
5965
|
const etag = etagForKey(key);
|
|
@@ -5895,7 +5972,7 @@ function registerCatalogAssetRoutes(app, deps) {
|
|
|
5895
5972
|
if (ifNoneMatchSatisfied(c.req.header("if-none-match"), etag)) {
|
|
5896
5973
|
return c.body(null, 304, headers);
|
|
5897
5974
|
}
|
|
5898
|
-
return c.body(new Uint8Array(
|
|
5975
|
+
return c.body(new Uint8Array(object5.bytes), 200, { ...headers, "Content-Type": contentType });
|
|
5899
5976
|
});
|
|
5900
5977
|
}
|
|
5901
5978
|
function catalogAssetKeyFromPath(pathname) {
|
|
@@ -8931,7 +9008,7 @@ import {
|
|
|
8931
9008
|
queueDocumentForReindex,
|
|
8932
9009
|
searchDocuments as searchDocuments2
|
|
8933
9010
|
} from "@opengeni/documents";
|
|
8934
|
-
import { WebStandardStreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/webStandardStreamableHttp.js";
|
|
9011
|
+
import { WebStandardStreamableHTTPServerTransport as WebStandardStreamableHTTPServerTransport2 } from "@modelcontextprotocol/sdk/server/webStandardStreamableHttp.js";
|
|
8935
9012
|
import { HTTPException as HTTPException11 } from "hono/http-exception";
|
|
8936
9013
|
import { requireAccessGrant as requireAccessGrant5 } from "@opengeni/core";
|
|
8937
9014
|
import { recordWorkspaceUsage as recordWorkspaceUsage3, requireLimit as requireLimit3 } from "@opengeni/core";
|
|
@@ -9162,8 +9239,90 @@ import {
|
|
|
9162
9239
|
import { HTTPException as HTTPException10 } from "hono/http-exception";
|
|
9163
9240
|
import { requireAccessGrant as requireAccessGrant4 } from "@opengeni/core";
|
|
9164
9241
|
import { recordWorkspaceUsage as recordWorkspaceUsage2, requireLimit as requireLimit2 } from "@opengeni/core";
|
|
9242
|
+
import { WebStandardStreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/webStandardStreamableHttp.js";
|
|
9243
|
+
|
|
9244
|
+
// src/mcp/files.ts
|
|
9245
|
+
import { requireFile } from "@opengeni/db";
|
|
9246
|
+
import { hasPermission as hasPermission7 } from "@opengeni/core";
|
|
9247
|
+
import { McpServer as McpServer3 } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
9248
|
+
import * as z3 from "zod/v4";
|
|
9249
|
+
function buildFilesMcpServer(deps, grant) {
|
|
9250
|
+
const server = new McpServer3({
|
|
9251
|
+
name: "opengeni-files",
|
|
9252
|
+
version: "1.0.0"
|
|
9253
|
+
});
|
|
9254
|
+
if (!hasPermission7(grant.permissions, "files:read")) {
|
|
9255
|
+
server.registerTool(
|
|
9256
|
+
"__opengeni_empty_files_surface__",
|
|
9257
|
+
{
|
|
9258
|
+
description: "Internal disabled placeholder for an unauthorized files surface.",
|
|
9259
|
+
inputSchema: z3.object({})
|
|
9260
|
+
},
|
|
9261
|
+
async () => ({
|
|
9262
|
+
content: [{ type: "text", text: '{"unavailable":true}' }]
|
|
9263
|
+
})
|
|
9264
|
+
).disable();
|
|
9265
|
+
return server;
|
|
9266
|
+
}
|
|
9267
|
+
server.registerTool(
|
|
9268
|
+
"files_get_download_url",
|
|
9269
|
+
{
|
|
9270
|
+
description: "Create a short-lived download URL for a ready file asset.",
|
|
9271
|
+
inputSchema: { fileId: z3.string().uuid() }
|
|
9272
|
+
},
|
|
9273
|
+
async ({ fileId }) => {
|
|
9274
|
+
if (!deps.objectStorage) {
|
|
9275
|
+
throw new Error("object storage is not configured");
|
|
9276
|
+
}
|
|
9277
|
+
const file = await requireFile(deps.db, grant.workspaceId, fileId);
|
|
9278
|
+
if (file.status !== "ready") {
|
|
9279
|
+
throw new Error(`file is ${file.status}`);
|
|
9280
|
+
}
|
|
9281
|
+
const signed = await deps.objectStorage.createGetUrl({ key: file.objectKey });
|
|
9282
|
+
return {
|
|
9283
|
+
content: [
|
|
9284
|
+
{
|
|
9285
|
+
type: "text",
|
|
9286
|
+
text: JSON.stringify(
|
|
9287
|
+
{
|
|
9288
|
+
file: {
|
|
9289
|
+
id: file.id,
|
|
9290
|
+
filename: file.filename,
|
|
9291
|
+
safeFilename: file.safeFilename,
|
|
9292
|
+
contentType: file.contentType,
|
|
9293
|
+
sizeBytes: file.sizeBytes,
|
|
9294
|
+
sha256: file.sha256,
|
|
9295
|
+
status: file.status,
|
|
9296
|
+
createdAt: file.createdAt,
|
|
9297
|
+
updatedAt: file.updatedAt
|
|
9298
|
+
},
|
|
9299
|
+
downloadUrl: {
|
|
9300
|
+
url: signed.url,
|
|
9301
|
+
expiresAt: signed.expiresAt.toISOString()
|
|
9302
|
+
}
|
|
9303
|
+
},
|
|
9304
|
+
null,
|
|
9305
|
+
2
|
|
9306
|
+
)
|
|
9307
|
+
}
|
|
9308
|
+
]
|
|
9309
|
+
};
|
|
9310
|
+
}
|
|
9311
|
+
);
|
|
9312
|
+
return server;
|
|
9313
|
+
}
|
|
9314
|
+
|
|
9315
|
+
// src/routes/files.ts
|
|
9165
9316
|
function registerFileRoutes(app, deps) {
|
|
9166
9317
|
const { db, objectStorage } = deps;
|
|
9318
|
+
app.all("/v1/workspaces/:workspaceId/mcp/files", async (c) => {
|
|
9319
|
+
const workspaceId = c.req.param("workspaceId");
|
|
9320
|
+
const grant = await requireAccessGrant4(c, deps, workspaceId, "files:read");
|
|
9321
|
+
const transport = new WebStandardStreamableHTTPServerTransport({ enableJsonResponse: true });
|
|
9322
|
+
const server = buildFilesMcpServer(deps, grant);
|
|
9323
|
+
await server.connect(transport);
|
|
9324
|
+
return await transport.handleRequest(c.req.raw);
|
|
9325
|
+
});
|
|
9167
9326
|
app.post("/v1/workspaces/:workspaceId/files/uploads", async (c) => {
|
|
9168
9327
|
const workspaceId = c.req.param("workspaceId");
|
|
9169
9328
|
const grant = await requireAccessGrant4(c, deps, workspaceId, "files:upload");
|
|
@@ -9972,7 +10131,7 @@ function registerDocumentRoutes(app, deps) {
|
|
|
9972
10131
|
const workspaceId = c.req.param("workspaceId");
|
|
9973
10132
|
const grant = await requireAccessGrant5(c, deps, workspaceId, "documents:search");
|
|
9974
10133
|
const sessionId = typeof grant.metadata?.sessionId === "string" ? grant.metadata.sessionId : void 0;
|
|
9975
|
-
const transport = new
|
|
10134
|
+
const transport = new WebStandardStreamableHTTPServerTransport2({ enableJsonResponse: true });
|
|
9976
10135
|
const server = buildDocumentsMcpServer(
|
|
9977
10136
|
db,
|
|
9978
10137
|
grant.accountId,
|
|
@@ -11667,7 +11826,7 @@ import {
|
|
|
11667
11826
|
} from "@opengeni/github";
|
|
11668
11827
|
import { deleteCookie, setCookie } from "hono/cookie";
|
|
11669
11828
|
import { HTTPException as HTTPException17 } from "hono/http-exception";
|
|
11670
|
-
import { hasPermission as
|
|
11829
|
+
import { hasPermission as hasPermission8, requireAccessGrant as requireAccessGrant10 } from "@opengeni/core";
|
|
11671
11830
|
var githubStateCookie = "opengeni_github_state";
|
|
11672
11831
|
var githubBindingStateMaxAgeSeconds = 10 * 60;
|
|
11673
11832
|
var legacyInstallationChooserDisabledMessage = "The legacy repository-admin GitHub installation chooser is disabled; use the GitHub owner-consent connect flow";
|
|
@@ -11680,7 +11839,7 @@ function registerGitHubRoutes(app, deps) {
|
|
|
11680
11839
|
const slug = settings.githubAppSlug?.trim() || null;
|
|
11681
11840
|
const installations = missing.length === 0 ? await listWorkspaceGitHubInstallationBindings(deps, grant.workspaceId) : [];
|
|
11682
11841
|
const status = githubBindingStatus(missing.length === 0, installations);
|
|
11683
|
-
const canManage =
|
|
11842
|
+
const canManage = hasPermission8(grant.permissions, "github:manage");
|
|
11684
11843
|
const connectState = missing.length === 0 && slug && canManage ? createSignedState5(githubStateSecret, {
|
|
11685
11844
|
accountId: grant.accountId,
|
|
11686
11845
|
workspaceId: grant.workspaceId,
|
|
@@ -12618,7 +12777,8 @@ function registerScheduledTaskRoutes(app, deps) {
|
|
|
12618
12777
|
await workflowClient.triggerScheduledTask({
|
|
12619
12778
|
task,
|
|
12620
12779
|
agentRunUsageIdempotencyKey,
|
|
12621
|
-
triggerWorkflowId
|
|
12780
|
+
triggerWorkflowId,
|
|
12781
|
+
initiator: { kind: "subject", subjectId: grant.subjectId }
|
|
12622
12782
|
});
|
|
12623
12783
|
await recordWorkspaceUsage4(deps, {
|
|
12624
12784
|
accountId: grant.accountId,
|
|
@@ -12758,7 +12918,7 @@ import {
|
|
|
12758
12918
|
coalesceSessionEventDeltas,
|
|
12759
12919
|
publishDurableSessionEvents as publishDurableSessionEvents2
|
|
12760
12920
|
} from "@opengeni/events";
|
|
12761
|
-
import { z as
|
|
12921
|
+
import { z as z5, ZodError } from "zod";
|
|
12762
12922
|
|
|
12763
12923
|
// src/sandbox/channel-a.ts
|
|
12764
12924
|
import {
|
|
@@ -13962,7 +14122,7 @@ function registerSessionRoutes(app, deps) {
|
|
|
13962
14122
|
const workspaceId = c.req.param("workspaceId");
|
|
13963
14123
|
const grant = await requireAccessGrant14(c, deps, workspaceId, "sessions:read");
|
|
13964
14124
|
const sessionId = c.req.param("sessionId");
|
|
13965
|
-
if (!
|
|
14125
|
+
if (!z5.string().uuid().safeParse(sessionId).success) {
|
|
13966
14126
|
throw new HTTPException22(404, { message: "session not found" });
|
|
13967
14127
|
}
|
|
13968
14128
|
const session = await getSessionForSubject(
|
|
@@ -13981,7 +14141,7 @@ function registerSessionRoutes(app, deps) {
|
|
|
13981
14141
|
const workspaceId = c.req.param("workspaceId");
|
|
13982
14142
|
const grant = await requireAccessGrant14(c, deps, workspaceId, "sessions:read");
|
|
13983
14143
|
const sessionId = c.req.param("sessionId");
|
|
13984
|
-
if (!
|
|
14144
|
+
if (!z5.string().uuid().safeParse(sessionId).success) {
|
|
13985
14145
|
throw new HTTPException22(404, { message: "session not found" });
|
|
13986
14146
|
}
|
|
13987
14147
|
const parsed = UpdateSessionPinRequest.safeParse(await c.req.json().catch(() => null));
|
|
@@ -15681,7 +15841,7 @@ function eventEnumList(raw, schema, name) {
|
|
|
15681
15841
|
}
|
|
15682
15842
|
function sessionListQuery(query, allowCursor = true) {
|
|
15683
15843
|
const parentSessionId = query.parentSessionId;
|
|
15684
|
-
if (parentSessionId !== void 0 && parentSessionId !== "null" && !
|
|
15844
|
+
if (parentSessionId !== void 0 && parentSessionId !== "null" && !z5.string().uuid().safeParse(parentSessionId).success) {
|
|
15685
15845
|
throw new HTTPException22(400, {
|
|
15686
15846
|
message: 'parentSessionId must be a session id or the literal "null"'
|
|
15687
15847
|
});
|
|
@@ -15837,7 +15997,7 @@ import {
|
|
|
15837
15997
|
listSocialPosts as listSocialPosts2
|
|
15838
15998
|
} from "@opengeni/db";
|
|
15839
15999
|
import { HTTPException as HTTPException23 } from "hono/http-exception";
|
|
15840
|
-
import { z as
|
|
16000
|
+
import { z as z6 } from "zod";
|
|
15841
16001
|
import { requireAccessGrant as requireAccessGrant15 } from "@opengeni/core";
|
|
15842
16002
|
function registerSocialRoutes(app, deps) {
|
|
15843
16003
|
const { db } = deps;
|
|
@@ -15927,7 +16087,7 @@ function parseConnectionIds(raw) {
|
|
|
15927
16087
|
return void 0;
|
|
15928
16088
|
}
|
|
15929
16089
|
const values = raw.split(",").map((value) => value.trim()).filter(Boolean);
|
|
15930
|
-
const parsed =
|
|
16090
|
+
const parsed = z6.array(z6.string().uuid()).safeParse(values);
|
|
15931
16091
|
if (!parsed.success) {
|
|
15932
16092
|
throw new HTTPException23(422, {
|
|
15933
16093
|
message: "connectionIds must be a comma-separated list of UUIDs"
|
|
@@ -15988,7 +16148,7 @@ import {
|
|
|
15988
16148
|
} from "@opengeni/db";
|
|
15989
16149
|
import { boundWorkspaceControlHttpPage } from "@opengeni/events";
|
|
15990
16150
|
import { HTTPException as HTTPException24 } from "hono/http-exception";
|
|
15991
|
-
import { hasPermission as
|
|
16151
|
+
import { hasPermission as hasPermission9, requireAccessContext as requireAccessContext2, requireAccessGrant as requireAccessGrant16 } from "@opengeni/core";
|
|
15992
16152
|
import { requireLimit as requireLimit7 } from "@opengeni/core";
|
|
15993
16153
|
import {
|
|
15994
16154
|
assertWorkspaceDeletable,
|
|
@@ -16235,7 +16395,7 @@ function registerWorkspaceRoutes(app, deps) {
|
|
|
16235
16395
|
const context = await requireAccessContext2(c, deps);
|
|
16236
16396
|
const readableWorkspaceIds = [
|
|
16237
16397
|
...new Set(
|
|
16238
|
-
context.workspaceGrants.filter((grant) =>
|
|
16398
|
+
context.workspaceGrants.filter((grant) => hasPermission9(grant.permissions, "workspace:read")).map((grant) => grant.workspaceId)
|
|
16239
16399
|
)
|
|
16240
16400
|
];
|
|
16241
16401
|
if (readableWorkspaceIds.length > 0) {
|
|
@@ -16524,8 +16684,8 @@ import {
|
|
|
16524
16684
|
WorkspaceInstructionPolicyNotFoundError
|
|
16525
16685
|
} from "@opengeni/db";
|
|
16526
16686
|
import { HTTPException as HTTPException25 } from "hono/http-exception";
|
|
16527
|
-
import { z as
|
|
16528
|
-
var WorkspaceInstructionPolicyRevisionId =
|
|
16687
|
+
import { z as z7 } from "zod";
|
|
16688
|
+
var WorkspaceInstructionPolicyRevisionId = z7.string().uuid();
|
|
16529
16689
|
async function parseBody(context, schema) {
|
|
16530
16690
|
const parsed = schema.safeParse(await context.req.json().catch(() => null));
|
|
16531
16691
|
if (!parsed.success) {
|
|
@@ -17025,7 +17185,7 @@ function createApp(deps) {
|
|
|
17025
17185
|
}
|
|
17026
17186
|
const workspace = await getWorkspace2(routeDeps.db, workspaceId);
|
|
17027
17187
|
const workspaceMemoryEnabled = resolveWorkspaceMemoryEnabled(workspace?.settings);
|
|
17028
|
-
const transport = new
|
|
17188
|
+
const transport = new WebStandardStreamableHTTPServerTransport3({
|
|
17029
17189
|
enableJsonResponse: true
|
|
17030
17190
|
});
|
|
17031
17191
|
const mcp = buildOpenGeniMcpServer(routeDeps, grant, {
|
|
@@ -17099,7 +17259,7 @@ function createApp(deps) {
|
|
|
17099
17259
|
}
|
|
17100
17260
|
async function requireMcpAccessGrant(c, deps, workspaceId) {
|
|
17101
17261
|
const grant = await requireAccessGrant18(c, deps, workspaceId);
|
|
17102
|
-
if (
|
|
17262
|
+
if (hasPermission10(grant.permissions, "workspace:read")) {
|
|
17103
17263
|
return grant;
|
|
17104
17264
|
}
|
|
17105
17265
|
if (isToolspaceGrant(deps.settings, grant)) {
|
|
@@ -17280,6 +17440,10 @@ var routeLabelPatterns = [
|
|
|
17280
17440
|
pattern: /^\/v1\/workspaces\/[^/]+\/mcp\/docs$/,
|
|
17281
17441
|
label: "/v1/workspaces/:workspaceId/mcp/docs"
|
|
17282
17442
|
},
|
|
17443
|
+
{
|
|
17444
|
+
pattern: /^\/v1\/workspaces\/[^/]+\/mcp\/files$/,
|
|
17445
|
+
label: "/v1/workspaces/:workspaceId/mcp/files"
|
|
17446
|
+
},
|
|
17283
17447
|
{
|
|
17284
17448
|
pattern: /^\/v1\/workspaces\/[^/]+\/default-rig$/,
|
|
17285
17449
|
label: "/v1/workspaces/:workspaceId/default-rig"
|
|
@@ -17641,4 +17805,4 @@ export {
|
|
|
17641
17805
|
withDefaultEnabledCapabilityMcpTools,
|
|
17642
17806
|
workflowIdForSession2 as workflowIdForSession
|
|
17643
17807
|
};
|
|
17644
|
-
//# sourceMappingURL=chunk-
|
|
17808
|
+
//# sourceMappingURL=chunk-SD5GJTZ4.js.map
|