@opengeni/api-router 0.12.7 → 0.12.12
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-SD5GJTZ4.js → chunk-5TULDPWX.js} +356 -84
- package/dist/chunk-5TULDPWX.js.map +1 -0
- package/dist/index.js +1 -1
- package/package.json +10 -10
- package/src/app.ts +8 -0
- package/src/github-access.ts +1 -0
- package/src/mcp/server.ts +26 -39
- package/src/routes/github.ts +325 -20
- package/src/routes/sessions.ts +12 -23
- package/src/routes/workspace-capture.ts +108 -8
- package/dist/chunk-SD5GJTZ4.js.map +0 -1
|
@@ -421,6 +421,7 @@ async function listWorkspaceGitHubInstallationBindings(deps, workspaceId) {
|
|
|
421
421
|
),
|
|
422
422
|
repositoryScope: installation.repositoryScope,
|
|
423
423
|
repositoryCount: installation.repositoryIds.length,
|
|
424
|
+
configureUrl: null,
|
|
424
425
|
createdAt: installation.createdAt,
|
|
425
426
|
updatedAt: installation.updatedAt
|
|
426
427
|
}));
|
|
@@ -3732,7 +3733,7 @@ function registerRigTools(server, deps, grant, can, sessionId, json) {
|
|
|
3732
3733
|
);
|
|
3733
3734
|
}
|
|
3734
3735
|
}
|
|
3735
|
-
function exactAgentCommandContext(grant, callerSessionId) {
|
|
3736
|
+
function exactAgentCommandContext(grant, callerSessionId, authorizationSurface) {
|
|
3736
3737
|
const turnId = grant.metadata?.["turnId"];
|
|
3737
3738
|
const attemptId = grant.metadata?.["attemptId"];
|
|
3738
3739
|
const executionGeneration = grant.metadata?.["executionGeneration"];
|
|
@@ -3746,7 +3747,8 @@ function exactAgentCommandContext(grant, callerSessionId) {
|
|
|
3746
3747
|
callerSessionId,
|
|
3747
3748
|
callerTurnId: turnId,
|
|
3748
3749
|
callerAttemptId: attemptId,
|
|
3749
|
-
callerExecutionGeneration: executionGeneration
|
|
3750
|
+
callerExecutionGeneration: executionGeneration,
|
|
3751
|
+
...authorizationSurface ? { authorizationSurface } : {}
|
|
3750
3752
|
};
|
|
3751
3753
|
}
|
|
3752
3754
|
function registerWorkspaceOrchestrationTools(server, deps, grant, can, callerSessionId, toolspaceMode, json) {
|
|
@@ -4064,7 +4066,6 @@ function registerWorkspaceOrchestrationTools(server, deps, grant, can, callerSes
|
|
|
4064
4066
|
targetSessionId,
|
|
4065
4067
|
{
|
|
4066
4068
|
text,
|
|
4067
|
-
toolsProvided: false,
|
|
4068
4069
|
delivery: "send",
|
|
4069
4070
|
origin: "operator",
|
|
4070
4071
|
clientEventId: idempotencyKey,
|
|
@@ -4087,16 +4088,10 @@ function registerWorkspaceOrchestrationTools(server, deps, grant, can, callerSes
|
|
|
4087
4088
|
}
|
|
4088
4089
|
},
|
|
4089
4090
|
async ({ sessionId, idempotencyKey, reason }) => {
|
|
4090
|
-
const authorization = await authorizeFirstPartySession(
|
|
4091
|
-
deps,
|
|
4092
|
-
grant,
|
|
4093
|
-
sessionId,
|
|
4094
|
-
"session.control"
|
|
4095
|
-
);
|
|
4096
4091
|
if (callerSessionId !== null) {
|
|
4097
4092
|
const controlled2 = await controlAgentSessionWorkstream(
|
|
4098
4093
|
deps,
|
|
4099
|
-
exactAgentCommandContext(grant, callerSessionId),
|
|
4094
|
+
exactAgentCommandContext(grant, callerSessionId, "first_party_mcp"),
|
|
4100
4095
|
{
|
|
4101
4096
|
targetSessionId: sessionId,
|
|
4102
4097
|
action: "pause",
|
|
@@ -4109,7 +4104,7 @@ function registerWorkspaceOrchestrationTools(server, deps, grant, can, callerSes
|
|
|
4109
4104
|
effectiveControl: projectEffectiveControlForRelatedAccess(
|
|
4110
4105
|
serializeEffectiveSessionControl(controlled2.control),
|
|
4111
4106
|
sessionId,
|
|
4112
|
-
authorization?.relatedSessionAccess ?? "root"
|
|
4107
|
+
controlled2.authorization?.relatedSessionAccess ?? "root"
|
|
4113
4108
|
),
|
|
4114
4109
|
interruptionCount: controlled2.interruptionCount,
|
|
4115
4110
|
replay: controlled2.replay
|
|
@@ -4121,7 +4116,8 @@ function registerWorkspaceOrchestrationTools(server, deps, grant, can, callerSes
|
|
|
4121
4116
|
accountId: grant.accountId,
|
|
4122
4117
|
workspaceId: grant.workspaceId,
|
|
4123
4118
|
sessionId,
|
|
4124
|
-
subjectId: grant.subjectId
|
|
4119
|
+
subjectId: grant.subjectId,
|
|
4120
|
+
authorizationSurface: "first_party_mcp"
|
|
4125
4121
|
},
|
|
4126
4122
|
{
|
|
4127
4123
|
action: "pause",
|
|
@@ -4129,14 +4125,7 @@ function registerWorkspaceOrchestrationTools(server, deps, grant, can, callerSes
|
|
|
4129
4125
|
...reason ? { reason } : {}
|
|
4130
4126
|
}
|
|
4131
4127
|
);
|
|
4132
|
-
return json(
|
|
4133
|
-
...controlled,
|
|
4134
|
-
effectiveControl: projectEffectiveControlForRelatedAccess(
|
|
4135
|
-
controlled.effectiveControl,
|
|
4136
|
-
sessionId,
|
|
4137
|
-
authorization?.relatedSessionAccess ?? "root"
|
|
4138
|
-
)
|
|
4139
|
-
});
|
|
4128
|
+
return json(controlled);
|
|
4140
4129
|
}
|
|
4141
4130
|
);
|
|
4142
4131
|
server.registerTool(
|
|
@@ -4150,16 +4139,10 @@ function registerWorkspaceOrchestrationTools(server, deps, grant, can, callerSes
|
|
|
4150
4139
|
}
|
|
4151
4140
|
},
|
|
4152
4141
|
async ({ sessionId, idempotencyKey, reason }) => {
|
|
4153
|
-
const authorization = await authorizeFirstPartySession(
|
|
4154
|
-
deps,
|
|
4155
|
-
grant,
|
|
4156
|
-
sessionId,
|
|
4157
|
-
"session.control"
|
|
4158
|
-
);
|
|
4159
4142
|
if (callerSessionId !== null) {
|
|
4160
4143
|
const controlled2 = await controlAgentSessionWorkstream(
|
|
4161
4144
|
deps,
|
|
4162
|
-
exactAgentCommandContext(grant, callerSessionId),
|
|
4145
|
+
exactAgentCommandContext(grant, callerSessionId, "first_party_mcp"),
|
|
4163
4146
|
{
|
|
4164
4147
|
targetSessionId: sessionId,
|
|
4165
4148
|
action: "resume",
|
|
@@ -4172,7 +4155,7 @@ function registerWorkspaceOrchestrationTools(server, deps, grant, can, callerSes
|
|
|
4172
4155
|
effectiveControl: projectEffectiveControlForRelatedAccess(
|
|
4173
4156
|
serializeEffectiveSessionControl(controlled2.control),
|
|
4174
4157
|
sessionId,
|
|
4175
|
-
authorization?.relatedSessionAccess ?? "root"
|
|
4158
|
+
controlled2.authorization?.relatedSessionAccess ?? "root"
|
|
4176
4159
|
),
|
|
4177
4160
|
interruptionCount: controlled2.interruptionCount,
|
|
4178
4161
|
replay: controlled2.replay
|
|
@@ -4184,7 +4167,8 @@ function registerWorkspaceOrchestrationTools(server, deps, grant, can, callerSes
|
|
|
4184
4167
|
accountId: grant.accountId,
|
|
4185
4168
|
workspaceId: grant.workspaceId,
|
|
4186
4169
|
sessionId,
|
|
4187
|
-
subjectId: grant.subjectId
|
|
4170
|
+
subjectId: grant.subjectId,
|
|
4171
|
+
authorizationSurface: "first_party_mcp"
|
|
4188
4172
|
},
|
|
4189
4173
|
{
|
|
4190
4174
|
action: "resume",
|
|
@@ -4192,14 +4176,7 @@ function registerWorkspaceOrchestrationTools(server, deps, grant, can, callerSes
|
|
|
4192
4176
|
...reason ? { reason } : {}
|
|
4193
4177
|
}
|
|
4194
4178
|
);
|
|
4195
|
-
return json(
|
|
4196
|
-
...controlled,
|
|
4197
|
-
effectiveControl: projectEffectiveControlForRelatedAccess(
|
|
4198
|
-
controlled.effectiveControl,
|
|
4199
|
-
sessionId,
|
|
4200
|
-
authorization?.relatedSessionAccess ?? "root"
|
|
4201
|
-
)
|
|
4202
|
-
});
|
|
4179
|
+
return json(controlled);
|
|
4203
4180
|
}
|
|
4204
4181
|
);
|
|
4205
4182
|
if (callerSessionId !== null) {
|
|
@@ -4214,10 +4191,9 @@ function registerWorkspaceOrchestrationTools(server, deps, grant, can, callerSes
|
|
|
4214
4191
|
}
|
|
4215
4192
|
},
|
|
4216
4193
|
async ({ sessionId, instruction, idempotencyKey }) => {
|
|
4217
|
-
await authorizeFirstPartySession(deps, grant, sessionId, "session.steer");
|
|
4218
4194
|
const result = await steerAgentSession(
|
|
4219
4195
|
deps,
|
|
4220
|
-
exactAgentCommandContext(grant, callerSessionId),
|
|
4196
|
+
exactAgentCommandContext(grant, callerSessionId, "first_party_mcp"),
|
|
4221
4197
|
{ targetSessionId: sessionId, instruction, idempotencyKey }
|
|
4222
4198
|
);
|
|
4223
4199
|
return json({
|
|
@@ -4391,14 +4367,16 @@ function registerGitHubConnectTool(server, deps, grant, options, json) {
|
|
|
4391
4367
|
const { settings } = deps;
|
|
4392
4368
|
const missing = githubAppMissingSettings(settings);
|
|
4393
4369
|
const slug = settings.githubAppSlug?.trim() || null;
|
|
4370
|
+
const setupMode = settings.productAccessMode === "managed" ? "platform" : "operator";
|
|
4394
4371
|
if (missing.length > 0 || !slug) {
|
|
4395
4372
|
return json({
|
|
4396
4373
|
configured: false,
|
|
4397
4374
|
status: "disabled",
|
|
4398
|
-
|
|
4375
|
+
setupMode,
|
|
4376
|
+
appSlug: setupMode === "operator" ? slug : null,
|
|
4399
4377
|
installUrl: null,
|
|
4400
4378
|
linkUrl: null,
|
|
4401
|
-
missing
|
|
4379
|
+
missing: setupMode === "operator" ? missing : []
|
|
4402
4380
|
});
|
|
4403
4381
|
}
|
|
4404
4382
|
const installations = await listWorkspaceGitHubInstallationBindings(deps, grant.workspaceId);
|
|
@@ -4411,13 +4389,18 @@ function registerGitHubConnectTool(server, deps, grant, options, json) {
|
|
|
4411
4389
|
...githubBrowserGrantClaims(settings, grant)
|
|
4412
4390
|
}) : null;
|
|
4413
4391
|
const connectUrl = state ? `${baseUrl}/v1/workspaces/${grant.workspaceId}/github/connect?state=${encodeURIComponent(state)}` : null;
|
|
4392
|
+
const installationViews = installations.map((installation) => ({
|
|
4393
|
+
...installation,
|
|
4394
|
+
configureUrl: state && baseUrl ? `${baseUrl}/v1/workspaces/${grant.workspaceId}/github/installations/${installation.installationId}/configure?state=${encodeURIComponent(state)}` : null
|
|
4395
|
+
}));
|
|
4414
4396
|
return json({
|
|
4415
4397
|
configured: true,
|
|
4416
4398
|
status,
|
|
4417
|
-
|
|
4399
|
+
setupMode,
|
|
4400
|
+
appSlug: setupMode === "operator" ? slug : null,
|
|
4418
4401
|
installUrl: connectUrl,
|
|
4419
4402
|
linkUrl: connectUrl,
|
|
4420
|
-
installations,
|
|
4403
|
+
installations: installationViews,
|
|
4421
4404
|
missing: []
|
|
4422
4405
|
});
|
|
4423
4406
|
}
|
|
@@ -11812,6 +11795,7 @@ import {
|
|
|
11812
11795
|
buildGitHubAppManifest,
|
|
11813
11796
|
convertGitHubAppManifest,
|
|
11814
11797
|
createSignedState as createSignedState5,
|
|
11798
|
+
discoverGitHubInstallationBindingCandidates,
|
|
11815
11799
|
envLinesFromGitHubManifestConversion,
|
|
11816
11800
|
GitHubAppApiError,
|
|
11817
11801
|
GitHubAppConfigurationError as GitHubAppConfigurationError2,
|
|
@@ -11839,6 +11823,7 @@ function registerGitHubRoutes(app, deps) {
|
|
|
11839
11823
|
const slug = settings.githubAppSlug?.trim() || null;
|
|
11840
11824
|
const installations = missing.length === 0 ? await listWorkspaceGitHubInstallationBindings(deps, grant.workspaceId) : [];
|
|
11841
11825
|
const status = githubBindingStatus(missing.length === 0, installations);
|
|
11826
|
+
const setupMode = settings.productAccessMode === "managed" ? "platform" : "operator";
|
|
11842
11827
|
const canManage = hasPermission8(grant.permissions, "github:manage");
|
|
11843
11828
|
const connectState = missing.length === 0 && slug && canManage ? createSignedState5(githubStateSecret, {
|
|
11844
11829
|
accountId: grant.accountId,
|
|
@@ -11847,16 +11832,21 @@ function registerGitHubRoutes(app, deps) {
|
|
|
11847
11832
|
...githubBrowserGrantClaims(settings, grant)
|
|
11848
11833
|
}) : null;
|
|
11849
11834
|
const connectUrl = connectState ? `${openGeniBaseUrl(settings, c)}/v1/workspaces/${grant.workspaceId}/github/connect?state=${encodeURIComponent(connectState)}` : null;
|
|
11835
|
+
const installationViews = installations.map((installation) => ({
|
|
11836
|
+
...installation,
|
|
11837
|
+
configureUrl: connectState ? `${openGeniBaseUrl(settings, c)}/v1/workspaces/${grant.workspaceId}/github/installations/${installation.installationId}/configure?state=${encodeURIComponent(connectState)}` : null
|
|
11838
|
+
}));
|
|
11850
11839
|
return c.json({
|
|
11851
11840
|
configured: missing.length === 0,
|
|
11852
11841
|
status,
|
|
11853
|
-
|
|
11854
|
-
|
|
11855
|
-
|
|
11842
|
+
setupMode,
|
|
11843
|
+
appId: setupMode === "operator" ? settings.githubAppId ?? null : null,
|
|
11844
|
+
clientId: setupMode === "operator" ? settings.githubClientId ?? null : null,
|
|
11845
|
+
appSlug: setupMode === "operator" ? slug : null,
|
|
11856
11846
|
installUrl: connectUrl,
|
|
11857
11847
|
linkUrl: connectUrl,
|
|
11858
|
-
installations,
|
|
11859
|
-
missing
|
|
11848
|
+
installations: installationViews,
|
|
11849
|
+
missing: setupMode === "operator" ? missing : []
|
|
11860
11850
|
});
|
|
11861
11851
|
});
|
|
11862
11852
|
app.get("/v1/workspaces/:workspaceId/github/connect", async (c) => {
|
|
@@ -11869,8 +11859,8 @@ function registerGitHubRoutes(app, deps) {
|
|
|
11869
11859
|
if (!statePayload || statePayload.intent !== "installation_authority" || statePayload.workspaceId !== workspaceId || typeof statePayload.accountId !== "string" || !isFreshGitHubBindingState(statePayload)) {
|
|
11870
11860
|
throw new HTTPException17(400, { message: "invalid or expired GitHub installation state" });
|
|
11871
11861
|
}
|
|
11872
|
-
const
|
|
11873
|
-
if (!
|
|
11862
|
+
const clientId = settings.githubClientId?.trim();
|
|
11863
|
+
if (!clientId || githubAppMissingSettings2(settings).length > 0) {
|
|
11874
11864
|
throw new HTTPException17(409, {
|
|
11875
11865
|
message: JSON.stringify({
|
|
11876
11866
|
message: "GitHub App is not configured",
|
|
@@ -11878,9 +11868,19 @@ function registerGitHubRoutes(app, deps) {
|
|
|
11878
11868
|
})
|
|
11879
11869
|
});
|
|
11880
11870
|
}
|
|
11881
|
-
|
|
11871
|
+
const discoveryState = createSignedState5(githubStateSecret, {
|
|
11872
|
+
accountId: statePayload.accountId,
|
|
11873
|
+
workspaceId,
|
|
11874
|
+
intent: "installation_authority_discovery",
|
|
11875
|
+
...continuedGitHubBrowserGrantClaims(statePayload)
|
|
11876
|
+
});
|
|
11877
|
+
setGitHubStateCookie(c, deps, discoveryState);
|
|
11882
11878
|
return c.redirect(
|
|
11883
|
-
|
|
11879
|
+
githubOAuthAuthorizeUrl({
|
|
11880
|
+
clientId,
|
|
11881
|
+
state: discoveryState,
|
|
11882
|
+
redirectUri: `${openGeniBaseUrl(settings, c)}/v1/github/oauth/callback`
|
|
11883
|
+
})
|
|
11884
11884
|
);
|
|
11885
11885
|
});
|
|
11886
11886
|
app.get("/v1/workspaces/:workspaceId/github/repositories", async (c) => {
|
|
@@ -11932,7 +11932,46 @@ function registerGitHubRoutes(app, deps) {
|
|
|
11932
11932
|
}
|
|
11933
11933
|
return c.body(null, 204);
|
|
11934
11934
|
});
|
|
11935
|
+
app.get(
|
|
11936
|
+
"/v1/workspaces/:workspaceId/github/installations/:installationId/configure",
|
|
11937
|
+
async (c) => {
|
|
11938
|
+
const workspaceId = c.req.param("workspaceId");
|
|
11939
|
+
const installationId = parsePositiveInteger(c.req.param("installationId"));
|
|
11940
|
+
const state = c.req.query("state");
|
|
11941
|
+
if (installationId === null || !state) {
|
|
11942
|
+
throw new HTTPException17(400, { message: "invalid GitHub installation configuration" });
|
|
11943
|
+
}
|
|
11944
|
+
const statePayload = readSignedState4(state, githubStateSecret);
|
|
11945
|
+
if (!statePayload || statePayload.intent !== "installation_authority" || statePayload.workspaceId !== workspaceId || typeof statePayload.accountId !== "string" || !isFreshGitHubBindingState(statePayload)) {
|
|
11946
|
+
throw new HTTPException17(400, {
|
|
11947
|
+
message: "invalid or expired GitHub installation configuration state"
|
|
11948
|
+
});
|
|
11949
|
+
}
|
|
11950
|
+
const grant = await requireGitHubManageGrant(c, deps, workspaceId, statePayload);
|
|
11951
|
+
if (grant.accountId !== statePayload.accountId) {
|
|
11952
|
+
throw new HTTPException17(403, {
|
|
11953
|
+
message: "GitHub installation state does not match this workspace"
|
|
11954
|
+
});
|
|
11955
|
+
}
|
|
11956
|
+
const installation = (await listWorkspaceGitHubInstallationBindings(deps, grant.workspaceId)).find((candidate) => candidate.installationId === installationId);
|
|
11957
|
+
if (!installation) {
|
|
11958
|
+
throw new HTTPException17(404, { message: "GitHub installation binding not found" });
|
|
11959
|
+
}
|
|
11960
|
+
const configureState = createSignedState5(githubStateSecret, {
|
|
11961
|
+
accountId: grant.accountId,
|
|
11962
|
+
workspaceId: grant.workspaceId,
|
|
11963
|
+
expectedInstallationId: installationId,
|
|
11964
|
+
intent: "installation_authority_install",
|
|
11965
|
+
...continuedGitHubBrowserGrantClaims(statePayload)
|
|
11966
|
+
});
|
|
11967
|
+
setGitHubStateCookie(c, deps, configureState);
|
|
11968
|
+
const configureUrl = githubInstallationSettingsUrl(installation);
|
|
11969
|
+
configureUrl.searchParams.set("state", configureState);
|
|
11970
|
+
return c.redirect(configureUrl.toString());
|
|
11971
|
+
}
|
|
11972
|
+
);
|
|
11935
11973
|
app.post("/v1/workspaces/:workspaceId/github/app-manifest", async (c) => {
|
|
11974
|
+
assertOperatorGitHubAppSetup(settings);
|
|
11936
11975
|
const workspaceId = c.req.param("workspaceId");
|
|
11937
11976
|
const grant = await requireAccessGrant10(c, deps, workspaceId, "github:manage");
|
|
11938
11977
|
const payload = GitHubAppManifestCreate.parse(await c.req.json());
|
|
@@ -11961,6 +12000,7 @@ function registerGitHubRoutes(app, deps) {
|
|
|
11961
12000
|
});
|
|
11962
12001
|
});
|
|
11963
12002
|
app.get("/v1/github/app-manifest/callback", async (c) => {
|
|
12003
|
+
assertOperatorGitHubAppSetup(settings);
|
|
11964
12004
|
const code = c.req.query("code");
|
|
11965
12005
|
const state = c.req.query("state");
|
|
11966
12006
|
if (!code) {
|
|
@@ -11980,12 +12020,15 @@ function registerGitHubRoutes(app, deps) {
|
|
|
11980
12020
|
}
|
|
11981
12021
|
});
|
|
11982
12022
|
const handleGitHubInstallCallback = async (c) => {
|
|
11983
|
-
const state = c.req.query("state")
|
|
12023
|
+
const state = c.req.query("state") ?? allCookieValues(c, githubStateCookie).find((candidate) => {
|
|
12024
|
+
const payload = readSignedState4(candidate, githubStateSecret);
|
|
12025
|
+
return payload?.intent === "installation_authority_install" && isFreshGitHubBindingState(payload);
|
|
12026
|
+
});
|
|
11984
12027
|
if (!state) {
|
|
11985
12028
|
throw new HTTPException17(400, { message: "missing GitHub installation state" });
|
|
11986
12029
|
}
|
|
11987
12030
|
const statePayload = readSignedState4(state, githubStateSecret);
|
|
11988
|
-
if (!statePayload || statePayload.intent !== "
|
|
12031
|
+
if (!statePayload || statePayload.intent !== "installation_authority_install" || typeof statePayload.accountId !== "string" || typeof statePayload.workspaceId !== "string" || !isFreshGitHubBindingState(statePayload)) {
|
|
11989
12032
|
throw new HTTPException17(400, { message: "invalid or expired GitHub installation state" });
|
|
11990
12033
|
}
|
|
11991
12034
|
requireGitHubStateCookie(c, state);
|
|
@@ -12006,6 +12049,11 @@ function registerGitHubRoutes(app, deps) {
|
|
|
12006
12049
|
if (installationId === null) {
|
|
12007
12050
|
throw new HTTPException17(400, { message: "missing or invalid GitHub installation_id" });
|
|
12008
12051
|
}
|
|
12052
|
+
if (statePayload.expectedInstallationId !== void 0 && statePayload.expectedInstallationId !== installationId) {
|
|
12053
|
+
throw new HTTPException17(409, {
|
|
12054
|
+
message: "GitHub returned a different installation than the one being configured"
|
|
12055
|
+
});
|
|
12056
|
+
}
|
|
12009
12057
|
const clientId = settings.githubClientId?.trim();
|
|
12010
12058
|
if (!clientId) {
|
|
12011
12059
|
throw new HTTPException17(409, {
|
|
@@ -12043,7 +12091,62 @@ function registerGitHubRoutes(app, deps) {
|
|
|
12043
12091
|
throw new HTTPException17(400, { message: "missing GitHub OAuth state" });
|
|
12044
12092
|
}
|
|
12045
12093
|
const statePayload = readSignedState4(state, githubStateSecret);
|
|
12046
|
-
if (!statePayload ||
|
|
12094
|
+
if (!statePayload || typeof statePayload.accountId !== "string" || typeof statePayload.workspaceId !== "string" || !isFreshGitHubBindingState(statePayload)) {
|
|
12095
|
+
throw new HTTPException17(400, { message: "invalid or expired GitHub OAuth state" });
|
|
12096
|
+
}
|
|
12097
|
+
if (statePayload.intent === "installation_authority_discovery") {
|
|
12098
|
+
requireGitHubStateCookie(c, state);
|
|
12099
|
+
const grant2 = await requireGitHubManageGrant(c, deps, statePayload.workspaceId, statePayload);
|
|
12100
|
+
if (grant2.accountId !== statePayload.accountId) {
|
|
12101
|
+
throw new HTTPException17(403, {
|
|
12102
|
+
message: "GitHub OAuth state does not match this workspace"
|
|
12103
|
+
});
|
|
12104
|
+
}
|
|
12105
|
+
let candidates;
|
|
12106
|
+
try {
|
|
12107
|
+
candidates = deps.githubAppApi?.discoverInstallationBindingCandidates ? await deps.githubAppApi.discoverInstallationBindingCandidates({ code }) : deps.githubAppApi ? null : await discoverGitHubInstallationBindingCandidates(settings, { code });
|
|
12108
|
+
} catch (error) {
|
|
12109
|
+
throw githubAuthorityHttpError(error);
|
|
12110
|
+
}
|
|
12111
|
+
if (!candidates) {
|
|
12112
|
+
throw new HTTPException17(409, {
|
|
12113
|
+
message: "The configured GitHub provider cannot discover owner-authorized installations"
|
|
12114
|
+
});
|
|
12115
|
+
}
|
|
12116
|
+
if (!isConsistentGitHubBindingCandidates(candidates)) {
|
|
12117
|
+
throw new HTTPException17(409, {
|
|
12118
|
+
message: "GitHub installation discovery proof is stale or invalid"
|
|
12119
|
+
});
|
|
12120
|
+
}
|
|
12121
|
+
const selectionState = createSignedState5(githubStateSecret, {
|
|
12122
|
+
accountId: grant2.accountId,
|
|
12123
|
+
workspaceId: grant2.workspaceId,
|
|
12124
|
+
intent: "installation_authority_selection",
|
|
12125
|
+
allowedInstallationIds: candidates.map(({ installation }) => installation.installationId),
|
|
12126
|
+
...continuedGitHubBrowserGrantClaims(statePayload)
|
|
12127
|
+
});
|
|
12128
|
+
if (candidates.length === 0) {
|
|
12129
|
+
return redirectToGitHubInstallation(c, deps, selectionState);
|
|
12130
|
+
}
|
|
12131
|
+
if (candidates.length === 1) {
|
|
12132
|
+
return redirectToExactGitHubAuthorization(
|
|
12133
|
+
c,
|
|
12134
|
+
deps,
|
|
12135
|
+
selectionState,
|
|
12136
|
+
candidates[0].installation.installationId
|
|
12137
|
+
);
|
|
12138
|
+
}
|
|
12139
|
+
setGitHubStateCookie(c, deps, selectionState);
|
|
12140
|
+
return c.html(
|
|
12141
|
+
githubInstallationChooserHtml(
|
|
12142
|
+
candidates,
|
|
12143
|
+
selectionState,
|
|
12144
|
+
grant2.workspaceId,
|
|
12145
|
+
openGeniBaseUrl(settings, c)
|
|
12146
|
+
)
|
|
12147
|
+
);
|
|
12148
|
+
}
|
|
12149
|
+
if (statePayload.intent !== "installation_authority_oauth") {
|
|
12047
12150
|
throw new HTTPException17(400, { message: "invalid or expired GitHub OAuth state" });
|
|
12048
12151
|
}
|
|
12049
12152
|
const installationId = parsePositiveInteger(String(statePayload.installationId ?? ""));
|
|
@@ -12114,6 +12217,41 @@ function registerGitHubRoutes(app, deps) {
|
|
|
12114
12217
|
)
|
|
12115
12218
|
);
|
|
12116
12219
|
});
|
|
12220
|
+
app.post("/v1/workspaces/:workspaceId/github/installations/select", async (c) => {
|
|
12221
|
+
const workspaceId = c.req.param("workspaceId");
|
|
12222
|
+
const form = new URLSearchParams(await c.req.text());
|
|
12223
|
+
const state = form.get("state");
|
|
12224
|
+
if (!state) {
|
|
12225
|
+
throw new HTTPException17(400, { message: "missing GitHub installation selection state" });
|
|
12226
|
+
}
|
|
12227
|
+
const statePayload = readSignedState4(state, githubStateSecret);
|
|
12228
|
+
if (!statePayload || statePayload.intent !== "installation_authority_selection" || typeof statePayload.accountId !== "string" || statePayload.accountId.length === 0 || statePayload.workspaceId !== workspaceId || !isFreshGitHubBindingState(statePayload)) {
|
|
12229
|
+
throw new HTTPException17(400, {
|
|
12230
|
+
message: "invalid or expired GitHub installation selection state"
|
|
12231
|
+
});
|
|
12232
|
+
}
|
|
12233
|
+
requireGitHubStateCookie(c, state);
|
|
12234
|
+
const grant = await requireGitHubManageGrant(c, deps, workspaceId, statePayload);
|
|
12235
|
+
if (grant.accountId !== statePayload.accountId) {
|
|
12236
|
+
throw new HTTPException17(403, {
|
|
12237
|
+
message: "GitHub installation state does not match this workspace"
|
|
12238
|
+
});
|
|
12239
|
+
}
|
|
12240
|
+
const selected = form.get("installation_id");
|
|
12241
|
+
if (selected === "new") {
|
|
12242
|
+
return redirectToGitHubInstallation(c, deps, state);
|
|
12243
|
+
}
|
|
12244
|
+
const installationId = parsePositiveInteger(selected);
|
|
12245
|
+
if (installationId === null) {
|
|
12246
|
+
throw new HTTPException17(400, { message: "invalid GitHub installation selection" });
|
|
12247
|
+
}
|
|
12248
|
+
if (!Array.isArray(statePayload.allowedInstallationIds) || !statePayload.allowedInstallationIds.includes(installationId)) {
|
|
12249
|
+
throw new HTTPException17(403, {
|
|
12250
|
+
message: "GitHub installation was not in the owner-authorized selection"
|
|
12251
|
+
});
|
|
12252
|
+
}
|
|
12253
|
+
return redirectToExactGitHubAuthorization(c, deps, state, installationId);
|
|
12254
|
+
});
|
|
12117
12255
|
app.post("/v1/workspaces/:workspaceId/github/installations", async (c) => {
|
|
12118
12256
|
const workspaceId = c.req.param("workspaceId");
|
|
12119
12257
|
const form = new URLSearchParams(await c.req.text());
|
|
@@ -12125,11 +12263,62 @@ function registerGitHubRoutes(app, deps) {
|
|
|
12125
12263
|
if (!statePayload || typeof statePayload.accountId !== "string" || statePayload.accountId.length === 0 || statePayload.workspaceId !== workspaceId) {
|
|
12126
12264
|
throw new HTTPException17(400, { message: "invalid or expired GitHub OAuth state" });
|
|
12127
12265
|
}
|
|
12128
|
-
throw
|
|
12266
|
+
throw new HTTPException17(410, { message: legacyInstallationChooserDisabledMessage });
|
|
12267
|
+
});
|
|
12268
|
+
}
|
|
12269
|
+
function assertOperatorGitHubAppSetup(settings) {
|
|
12270
|
+
if (settings.productAccessMode === "managed") {
|
|
12271
|
+
throw new HTTPException17(404, {
|
|
12272
|
+
message: "GitHub App creation is unavailable in platform-managed deployments"
|
|
12273
|
+
});
|
|
12274
|
+
}
|
|
12275
|
+
}
|
|
12276
|
+
function redirectToGitHubInstallation(c, deps, sourceState) {
|
|
12277
|
+
const payload = readSignedState4(sourceState, deps.githubStateSecret);
|
|
12278
|
+
const slug = deps.settings.githubAppSlug?.trim();
|
|
12279
|
+
if (!payload || typeof payload.accountId !== "string" || typeof payload.workspaceId !== "string" || !slug) {
|
|
12280
|
+
throw new HTTPException17(409, { message: "GitHub App installation is unavailable" });
|
|
12281
|
+
}
|
|
12282
|
+
const installState = createSignedState5(deps.githubStateSecret, {
|
|
12283
|
+
accountId: payload.accountId,
|
|
12284
|
+
workspaceId: payload.workspaceId,
|
|
12285
|
+
intent: "installation_authority_install",
|
|
12286
|
+
...continuedGitHubBrowserGrantClaims(payload)
|
|
12129
12287
|
});
|
|
12288
|
+
setGitHubStateCookie(c, deps, installState);
|
|
12289
|
+
return c.redirect(
|
|
12290
|
+
`https://github.com/apps/${encodeURIComponent(slug)}/installations/new?state=${encodeURIComponent(installState)}`
|
|
12291
|
+
);
|
|
12130
12292
|
}
|
|
12131
|
-
function
|
|
12132
|
-
|
|
12293
|
+
function githubInstallationSettingsUrl(installation) {
|
|
12294
|
+
if (installation.accountType === "Organization" && installation.accountLogin) {
|
|
12295
|
+
return new URL(
|
|
12296
|
+
`https://github.com/organizations/${encodeURIComponent(installation.accountLogin)}/settings/installations/${installation.installationId}`
|
|
12297
|
+
);
|
|
12298
|
+
}
|
|
12299
|
+
return new URL(`https://github.com/settings/installations/${installation.installationId}`);
|
|
12300
|
+
}
|
|
12301
|
+
function redirectToExactGitHubAuthorization(c, deps, sourceState, installationId) {
|
|
12302
|
+
const payload = readSignedState4(sourceState, deps.githubStateSecret);
|
|
12303
|
+
const clientId = deps.settings.githubClientId?.trim();
|
|
12304
|
+
if (!payload || typeof payload.accountId !== "string" || typeof payload.workspaceId !== "string" || !clientId) {
|
|
12305
|
+
throw new HTTPException17(409, { message: "GitHub user authorization is unavailable" });
|
|
12306
|
+
}
|
|
12307
|
+
const oauthState = createSignedState5(deps.githubStateSecret, {
|
|
12308
|
+
accountId: payload.accountId,
|
|
12309
|
+
workspaceId: payload.workspaceId,
|
|
12310
|
+
installationId,
|
|
12311
|
+
intent: "installation_authority_oauth",
|
|
12312
|
+
...continuedGitHubBrowserGrantClaims(payload)
|
|
12313
|
+
});
|
|
12314
|
+
setGitHubStateCookie(c, deps, oauthState);
|
|
12315
|
+
return c.redirect(
|
|
12316
|
+
githubOAuthAuthorizeUrl({
|
|
12317
|
+
clientId,
|
|
12318
|
+
state: oauthState,
|
|
12319
|
+
redirectUri: `${openGeniBaseUrl(deps.settings, c)}/v1/github/oauth/callback`
|
|
12320
|
+
})
|
|
12321
|
+
);
|
|
12133
12322
|
}
|
|
12134
12323
|
function setGitHubStateCookie(c, deps, state) {
|
|
12135
12324
|
setCookie(c, githubStateCookie, state, {
|
|
@@ -12206,9 +12395,30 @@ function githubSuccessHtml(envLines) {
|
|
|
12206
12395
|
function githubSetupSuccessHtml(account, returnUrl) {
|
|
12207
12396
|
return `<!doctype html><html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>GitHub App Connected</title><style>body{font-family:system-ui,sans-serif;margin:0;min-height:100vh;display:grid;place-items:center;background:#0b0b0d;color:#f4f4f5}main{width:min(640px,calc(100vw - 32px));border:1px solid #27272a;border-radius:8px;padding:28px;background:#111114}h1{margin:0 0 10px;font-size:24px;line-height:1.2}p{margin:0 0 18px;color:#d4d4d8}.button{display:inline-flex;align-items:center;justify-content:center;min-height:36px;border-radius:6px;border:1px solid #3f3f46;padding:0 12px;background:#f4f4f5;color:#09090b;font:600 14px system-ui,sans-serif;text-decoration:none}</style></head><body><main><h1>GitHub App connected</h1><p>${escapeHtml2(account)} is now available to this OpenGeni workspace through an explicit repository allowlist.</p><a class="button" href="${escapeHtml2(returnUrl)}">Back to OpenGeni</a></main></body></html>`;
|
|
12208
12397
|
}
|
|
12398
|
+
function githubInstallationChooserHtml(candidates, state, workspaceId, baseUrl) {
|
|
12399
|
+
const action = `${baseUrl}/v1/workspaces/${encodeURIComponent(workspaceId)}/github/installations/select`;
|
|
12400
|
+
const options = candidates.map(({ installation, authorityKind }) => {
|
|
12401
|
+
const account = escapeHtml2(
|
|
12402
|
+
installation.accountLogin ?? `installation ${installation.installationId}`
|
|
12403
|
+
);
|
|
12404
|
+
const label = authorityKind === "personal_owner" ? "Personal account" : "Organization owner";
|
|
12405
|
+
return `<label class="option"><input type="radio" name="installation_id" value="${installation.installationId}" required><span><strong>${account}</strong><small>${label}</small></span></label>`;
|
|
12406
|
+
}).join("");
|
|
12407
|
+
return `<!doctype html><html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>Choose GitHub installation</title><style>body{font-family:system-ui,sans-serif;margin:0;min-height:100vh;display:grid;place-items:center;background:#0b0b0d;color:#f4f4f5}main{width:min(640px,calc(100vw - 32px));border:1px solid #27272a;border-radius:12px;padding:28px;background:#111114}h1{margin:0 0 10px;font-size:24px}p{margin:0 0 18px;color:#d4d4d8}.options{display:grid;gap:8px;margin-bottom:18px}.option{display:flex;align-items:center;gap:12px;border:1px solid #3f3f46;border-radius:8px;padding:12px;cursor:pointer}.option span{display:grid;gap:2px}.option small{color:#a1a1aa}button{min-height:38px;border-radius:7px;border:1px solid #3f3f46;padding:0 14px;background:#f4f4f5;color:#09090b;font:600 14px system-ui,sans-serif;cursor:pointer}.secondary{margin-left:8px;background:transparent;color:#f4f4f5}</style></head><body><main><h1>Choose a GitHub account</h1><p>Only installations where GitHub proved you are the personal owner or an active organization owner are shown.</p><form method="post" action="${escapeHtml2(action)}"><input type="hidden" name="state" value="${escapeHtml2(state)}"><div class="options">${options}</div><button type="submit">Connect selected</button><button class="secondary" type="submit" name="installation_id" value="new" formnovalidate>Install on another account</button></form></main></body></html>`;
|
|
12408
|
+
}
|
|
12209
12409
|
function githubSetupPendingHtml() {
|
|
12210
12410
|
return `<!doctype html><html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>GitHub App Requested</title><style>body{font-family:system-ui,sans-serif;margin:0;min-height:100vh;display:grid;place-items:center;background:#0b0b0d;color:#f4f4f5}main{width:min(640px,calc(100vw - 32px));border:1px solid #27272a;border-radius:8px;padding:28px;background:#111114}h1{margin:0 0 10px;font-size:24px;line-height:1.2}p{margin:0;color:#d4d4d8}</style></head><body><main><h1>GitHub App request sent</h1><p>A GitHub organization owner must approve the installation. OpenGeni has not created a workspace binding.</p></main></body></html>`;
|
|
12211
12411
|
}
|
|
12412
|
+
function isConsistentGitHubBindingCandidates(candidates) {
|
|
12413
|
+
const ids = /* @__PURE__ */ new Set();
|
|
12414
|
+
return candidates.every(({ installation, authorityKind }) => {
|
|
12415
|
+
if (!Number.isSafeInteger(installation.installationId) || installation.installationId <= 0 || !Number.isSafeInteger(installation.accountId) || installation.accountId <= 0 || !installation.accountLogin?.trim() || installation.suspended || ids.has(installation.installationId)) {
|
|
12416
|
+
return false;
|
|
12417
|
+
}
|
|
12418
|
+
ids.add(installation.installationId);
|
|
12419
|
+
return authorityKind === "personal_owner" ? installation.accountType === "User" : installation.accountType === "Organization";
|
|
12420
|
+
});
|
|
12421
|
+
}
|
|
12212
12422
|
function parsePositiveInteger(value) {
|
|
12213
12423
|
if (!value || !/^\d+$/.test(value)) {
|
|
12214
12424
|
return null;
|
|
@@ -12910,6 +13120,7 @@ import {
|
|
|
12910
13120
|
SessionContextBusyError,
|
|
12911
13121
|
HumanInputResponseValidationError,
|
|
12912
13122
|
latestWorkspaceCapture,
|
|
13123
|
+
sessionLatestWorkspaceCapture,
|
|
12913
13124
|
workspaceCaptureAtRevision
|
|
12914
13125
|
} from "@opengeni/db";
|
|
12915
13126
|
import {
|
|
@@ -13720,11 +13931,69 @@ import { HTTPException as HTTPException21 } from "hono/http-exception";
|
|
|
13720
13931
|
var CAPTURE_INLINE_MANIFEST_MAX_BYTES = 2 * 1024 * 1024;
|
|
13721
13932
|
var CAPTURE_INLINE_FILE_MAX_BYTES = 256 * 1024;
|
|
13722
13933
|
var CAPTURE_SIGNED_URL_TTL_SECONDS = 300;
|
|
13934
|
+
var WorkspaceCaptureManifestCache = class {
|
|
13935
|
+
constructor(maxEntries = 64, maxBytes = 16 * 1024 * 1024) {
|
|
13936
|
+
this.maxEntries = maxEntries;
|
|
13937
|
+
this.maxBytes = maxBytes;
|
|
13938
|
+
}
|
|
13939
|
+
#entries = /* @__PURE__ */ new Map();
|
|
13940
|
+
#retainedBytes = 0;
|
|
13941
|
+
get(row) {
|
|
13942
|
+
const key = row.manifestKey;
|
|
13943
|
+
if (!key) return null;
|
|
13944
|
+
const entry = this.#entries.get(key);
|
|
13945
|
+
if (!entry || entry.identity !== manifestIdentity(row)) return null;
|
|
13946
|
+
this.#entries.delete(key);
|
|
13947
|
+
this.#entries.set(key, entry);
|
|
13948
|
+
return entry;
|
|
13949
|
+
}
|
|
13950
|
+
getInlineResponse(row) {
|
|
13951
|
+
const key = row.manifestKey;
|
|
13952
|
+
if (!key) return null;
|
|
13953
|
+
const entry = this.#entries.get(key);
|
|
13954
|
+
if (!entry || entry.identity !== manifestIdentity(row) || !entry.inlineResponse) return null;
|
|
13955
|
+
this.#entries.delete(key);
|
|
13956
|
+
this.#entries.set(key, entry);
|
|
13957
|
+
return entry.inlineResponse;
|
|
13958
|
+
}
|
|
13959
|
+
setInlineResponse(row, response) {
|
|
13960
|
+
const key = row.manifestKey;
|
|
13961
|
+
if (!key) return;
|
|
13962
|
+
const entry = this.#entries.get(key);
|
|
13963
|
+
if (!entry || entry.identity !== manifestIdentity(row)) return;
|
|
13964
|
+
entry.inlineResponse = response;
|
|
13965
|
+
}
|
|
13966
|
+
set(row, loaded) {
|
|
13967
|
+
const key = row.manifestKey;
|
|
13968
|
+
if (!key || this.maxEntries <= 0 || this.maxBytes <= 0 || loaded.byteLength > CAPTURE_INLINE_MANIFEST_MAX_BYTES || loaded.byteLength > this.maxBytes) {
|
|
13969
|
+
return;
|
|
13970
|
+
}
|
|
13971
|
+
const previous = this.#entries.get(key);
|
|
13972
|
+
if (previous) {
|
|
13973
|
+
this.#retainedBytes -= previous.byteLength;
|
|
13974
|
+
this.#entries.delete(key);
|
|
13975
|
+
}
|
|
13976
|
+
this.#entries.set(key, { ...loaded, identity: manifestIdentity(row) });
|
|
13977
|
+
this.#retainedBytes += loaded.byteLength;
|
|
13978
|
+
while (this.#entries.size > this.maxEntries || this.#retainedBytes > this.maxBytes) {
|
|
13979
|
+
const oldestKey = this.#entries.keys().next().value;
|
|
13980
|
+
if (oldestKey === void 0) break;
|
|
13981
|
+
const oldest = this.#entries.get(oldestKey);
|
|
13982
|
+
this.#entries.delete(oldestKey);
|
|
13983
|
+
if (oldest) this.#retainedBytes -= oldest.byteLength;
|
|
13984
|
+
}
|
|
13985
|
+
}
|
|
13986
|
+
};
|
|
13987
|
+
function manifestIdentity(row) {
|
|
13988
|
+
return `${row.sessionId}\0${row.turnId}\0${row.revision}\0${row.leaseEpoch}\0${row.capturedAt}`;
|
|
13989
|
+
}
|
|
13723
13990
|
function signedUrl(signed) {
|
|
13724
13991
|
return { url: signed.url, expiresAt: signed.expiresAt.toISOString() };
|
|
13725
13992
|
}
|
|
13726
|
-
async function loadManifest(row, storage) {
|
|
13993
|
+
async function loadManifest(row, storage, cache) {
|
|
13727
13994
|
if (!row.manifestKey) return null;
|
|
13995
|
+
const cached = cache?.get(row);
|
|
13996
|
+
if (cached) return cached;
|
|
13728
13997
|
const stats = WorkspaceCaptureStats.safeParse(row.stats);
|
|
13729
13998
|
if (!stats.success) {
|
|
13730
13999
|
console.warn(
|
|
@@ -13759,9 +14028,11 @@ async function loadManifest(row, storage) {
|
|
|
13759
14028
|
);
|
|
13760
14029
|
return null;
|
|
13761
14030
|
}
|
|
13762
|
-
|
|
14031
|
+
const loaded = { manifest, byteLength: blob.bytes.byteLength, stats: servedStats };
|
|
14032
|
+
cache?.set(row, loaded);
|
|
14033
|
+
return loaded;
|
|
13763
14034
|
}
|
|
13764
|
-
async function serveWorkspaceCapture(row, storage) {
|
|
14035
|
+
async function serveWorkspaceCapture(row, storage, cache) {
|
|
13765
14036
|
if (!row) {
|
|
13766
14037
|
return { available: false };
|
|
13767
14038
|
}
|
|
@@ -13780,7 +14051,9 @@ async function serveWorkspaceCapture(row, storage) {
|
|
|
13780
14051
|
});
|
|
13781
14052
|
}
|
|
13782
14053
|
if (row.state !== "available" || !row.manifestKey) return { available: false };
|
|
13783
|
-
const
|
|
14054
|
+
const cachedResponse = cache?.getInlineResponse(row);
|
|
14055
|
+
if (cachedResponse) return cachedResponse;
|
|
14056
|
+
const loaded = await loadManifest(row, storage, cache);
|
|
13784
14057
|
if (!loaded) return { available: false };
|
|
13785
14058
|
const meta = {
|
|
13786
14059
|
available: true,
|
|
@@ -13792,11 +14065,16 @@ async function serveWorkspaceCapture(row, storage) {
|
|
|
13792
14065
|
stats: loaded.stats
|
|
13793
14066
|
};
|
|
13794
14067
|
if (loaded.byteLength <= CAPTURE_INLINE_MANIFEST_MAX_BYTES) {
|
|
13795
|
-
|
|
14068
|
+
const response = GetWorkspaceCaptureResponse.parse({
|
|
13796
14069
|
...meta,
|
|
13797
14070
|
manifest: loaded.manifest,
|
|
13798
14071
|
manifestUrl: null
|
|
13799
14072
|
});
|
|
14073
|
+
if (!response.available) {
|
|
14074
|
+
throw new Error("validated inline capture response lost its available discriminator");
|
|
14075
|
+
}
|
|
14076
|
+
cache?.setInlineResponse(row, response);
|
|
14077
|
+
return response;
|
|
13800
14078
|
}
|
|
13801
14079
|
const signed = await storage.createGetUrl({
|
|
13802
14080
|
key: row.manifestKey,
|
|
@@ -13868,6 +14146,7 @@ async function serveWorkspaceCaptureFile(row, path, storage) {
|
|
|
13868
14146
|
// src/routes/sessions.ts
|
|
13869
14147
|
function registerSessionRoutes(app, deps) {
|
|
13870
14148
|
const { settings, db, bus, workflowClient, objectStorage } = deps;
|
|
14149
|
+
const workspaceCaptureManifestCache = new WorkspaceCaptureManifestCache();
|
|
13871
14150
|
const ptyIdentity = (pty) => ({
|
|
13872
14151
|
leaseId: pty.leaseId,
|
|
13873
14152
|
sandboxGroupId: pty.sandboxGroupId,
|
|
@@ -14831,8 +15110,6 @@ function registerSessionRoutes(app, deps) {
|
|
|
14831
15110
|
text: payload.text,
|
|
14832
15111
|
turnInstructions: payload.turnInstructions ?? null,
|
|
14833
15112
|
resources: payload.resources,
|
|
14834
|
-
tools: payload.tools,
|
|
14835
|
-
toolsProvided: userMessagePayloadHasOwnProperty({ payload: raw }, "tools"),
|
|
14836
15113
|
model: payload.model ?? null,
|
|
14837
15114
|
reasoningEffort: payload.reasoningEffort ?? null,
|
|
14838
15115
|
mcpCredentialUpdates: payload.mcpCredentialUpdates ?? [],
|
|
@@ -14867,8 +15144,6 @@ function registerSessionRoutes(app, deps) {
|
|
|
14867
15144
|
text: event.payload.text,
|
|
14868
15145
|
turnInstructions: event.payload.turnInstructions ?? null,
|
|
14869
15146
|
resources: event.payload.resources ?? [],
|
|
14870
|
-
tools: event.payload.tools ?? [],
|
|
14871
|
-
toolsProvided: userMessagePayloadHasOwnProperty(rawEvent, "tools"),
|
|
14872
15147
|
model: event.payload.model ?? null,
|
|
14873
15148
|
reasoningEffort: event.payload.reasoningEffort ?? null,
|
|
14874
15149
|
mcpCredentialUpdates: event.payload.mcpCredentialUpdates ?? [],
|
|
@@ -15465,15 +15740,16 @@ function registerSessionRoutes(app, deps) {
|
|
|
15465
15740
|
const workspaceId = c.req.param("workspaceId") ?? "";
|
|
15466
15741
|
await requireAccessGrant14(c, deps, workspaceId, "files:read");
|
|
15467
15742
|
const sessionId = c.req.param("sessionId") ?? "";
|
|
15468
|
-
const
|
|
15469
|
-
if (!
|
|
15743
|
+
const lookup = await sessionLatestWorkspaceCapture(db, workspaceId, sessionId);
|
|
15744
|
+
if (!lookup.sessionExists) {
|
|
15470
15745
|
throw new HTTPException22(404, { message: "session not found" });
|
|
15471
15746
|
}
|
|
15472
15747
|
if (!objectStorage) {
|
|
15473
15748
|
return c.json({ available: false });
|
|
15474
15749
|
}
|
|
15475
|
-
|
|
15476
|
-
|
|
15750
|
+
return c.json(
|
|
15751
|
+
await serveWorkspaceCapture(lookup.capture, objectStorage, workspaceCaptureManifestCache)
|
|
15752
|
+
);
|
|
15477
15753
|
});
|
|
15478
15754
|
app.get("/v1/workspaces/:workspaceId/sessions/:sessionId/workspace/capture/file", async (c) => {
|
|
15479
15755
|
const workspaceId = c.req.param("workspaceId") ?? "";
|
|
@@ -15897,18 +16173,6 @@ function optionalEventSequence(raw) {
|
|
|
15897
16173
|
}
|
|
15898
16174
|
return Math.floor(sequence);
|
|
15899
16175
|
}
|
|
15900
|
-
function hasOwnProperty(value, key) {
|
|
15901
|
-
return Boolean(
|
|
15902
|
-
value && typeof value === "object" && Object.prototype.hasOwnProperty.call(value, key)
|
|
15903
|
-
);
|
|
15904
|
-
}
|
|
15905
|
-
function userMessagePayloadHasOwnProperty(value, key) {
|
|
15906
|
-
if (!value || typeof value !== "object") {
|
|
15907
|
-
return false;
|
|
15908
|
-
}
|
|
15909
|
-
const payload = value.payload;
|
|
15910
|
-
return hasOwnProperty(payload, key);
|
|
15911
|
-
}
|
|
15912
16176
|
function sessionCreateErrorResponse(c, error) {
|
|
15913
16177
|
if (error instanceof SessionSpawnDeniedError2) {
|
|
15914
16178
|
return c.json(
|
|
@@ -17624,6 +17888,14 @@ var routeLabelPatterns = [
|
|
|
17624
17888
|
pattern: /^\/v1\/workspaces\/[^/]+\/github\/connect$/,
|
|
17625
17889
|
label: "/v1/workspaces/:workspaceId/github/connect"
|
|
17626
17890
|
},
|
|
17891
|
+
{
|
|
17892
|
+
pattern: /^\/v1\/workspaces\/[^/]+\/github\/installations\/select$/,
|
|
17893
|
+
label: "/v1/workspaces/:workspaceId/github/installations/select"
|
|
17894
|
+
},
|
|
17895
|
+
{
|
|
17896
|
+
pattern: /^\/v1\/workspaces\/[^/]+\/github\/installations\/[^/]+\/configure$/,
|
|
17897
|
+
label: "/v1/workspaces/:workspaceId/github/installations/:installationId/configure"
|
|
17898
|
+
},
|
|
17627
17899
|
{
|
|
17628
17900
|
pattern: /^\/v1\/workspaces\/[^/]+\/github\/installations$/,
|
|
17629
17901
|
label: "/v1/workspaces/:workspaceId/github/installations"
|
|
@@ -17805,4 +18077,4 @@ export {
|
|
|
17805
18077
|
withDefaultEnabledCapabilityMcpTools,
|
|
17806
18078
|
workflowIdForSession2 as workflowIdForSession
|
|
17807
18079
|
};
|
|
17808
|
-
//# sourceMappingURL=chunk-
|
|
18080
|
+
//# sourceMappingURL=chunk-5TULDPWX.js.map
|