@opengeni/api-router 4.0.0 → 4.1.0-canary.35916963870001
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-E7TZFJ65.js → chunk-PHQ7C36N.js} +983 -597
- package/dist/{chunk-E7TZFJ65.js.map → chunk-PHQ7C36N.js.map} +1 -1
- package/dist/index.js +1 -1
- package/dist/integrations/github-lens-connect.d.ts +1 -1
- package/dist/integrations/oauth-client.d.ts +1 -1
- package/dist/integrations/slack-bot.d.ts +8 -0
- package/dist/integrations/slack-interactions.d.ts +1 -1
- package/dist/mcp/child-read-evidence.d.ts +9 -0
- package/dist/mcp/documents.d.ts +2 -0
- package/dist/mcp/first-party-tool-permissions.d.ts +3 -0
- package/dist/mcp/session-wait.d.ts +2 -0
- package/dist/routes/codex.d.ts +2 -1
- package/package.json +19 -19
- package/src/integrations/oauth-client.ts +68 -5
- package/src/integrations/slack-bot.ts +32 -3
- package/src/integrations/slack-interactions.ts +79 -8
- package/src/mcp/child-read-evidence.ts +19 -0
- package/src/mcp/documents.ts +9 -2
- package/src/mcp/first-party-tool-permissions.ts +1 -0
- package/src/mcp/knowledge-entries.ts +15 -2
- package/src/mcp/server.ts +226 -103
- package/src/mcp/session-wait.ts +17 -0
- package/src/routes/browser-sessions.ts +42 -0
- package/src/routes/codex.ts +19 -12
- package/src/routes/computer-sessions.ts +18 -1
- package/src/routes/documents.ts +1 -0
- package/src/routes/knowledge.ts +19 -0
- package/src/routes/managed-onboarding.ts +3 -0
- package/src/routes/organization-memberships.ts +3 -0
- package/src/routes/skill-content.ts +21 -5
- package/src/sandbox/channel-a.ts +8 -0
- package/src/sandbox/machines.ts +9 -8
- package/src/sandbox/viewer.ts +16 -3
- package/src/sandbox-file-artifacts.ts +15 -1
- package/src/site-uploads.ts +19 -4
- package/src/workspace-tool-gateway.ts +1 -0
|
@@ -267,6 +267,7 @@ var FIRST_PARTY_TOOL_AUTHORIZATION = {
|
|
|
267
267
|
run_on: { sessionRequired: true, allOf: ["sessions:control"] },
|
|
268
268
|
sandbox_provision: { sessionRequired: true, allOf: ["sessions:control"] },
|
|
269
269
|
connected_machine_remove: { allOf: ["enrollments:manage"] },
|
|
270
|
+
connected_machine_enroll_token: { allOf: ["enrollments:manage"] },
|
|
270
271
|
rig_list: { allOf: ["rigs:use"] },
|
|
271
272
|
rig_get: { allOf: ["rigs:use"] },
|
|
272
273
|
rig_propose_change: { allOf: ["rigs:use"] },
|
|
@@ -649,8 +650,8 @@ import { SiteSessionPathError, OrganizationIntegrationDeniedError as Organizatio
|
|
|
649
650
|
|
|
650
651
|
// src/routes/model-connection-access.ts
|
|
651
652
|
import {
|
|
652
|
-
configuredModels as
|
|
653
|
-
withCodexCatalogProvider,
|
|
653
|
+
configuredModels as configuredModels3,
|
|
654
|
+
withCodexCatalogProvider as withCodexCatalogProvider2,
|
|
654
655
|
withXaiSubscriptionCatalogProvider as withXaiSubscriptionCatalogProvider2,
|
|
655
656
|
withOrganizationGatewayCatalogProvider,
|
|
656
657
|
withOrganizationOpenRouterCatalogProvider
|
|
@@ -673,14 +674,17 @@ import { HTTPException as HTTPException4 } from "hono/http-exception";
|
|
|
673
674
|
import { z as z5 } from "zod";
|
|
674
675
|
|
|
675
676
|
// src/routes/codex.ts
|
|
676
|
-
import {
|
|
677
|
+
import {
|
|
678
|
+
environmentsEncryptionKeyBytes,
|
|
679
|
+
configuredModels,
|
|
680
|
+
getSettings,
|
|
681
|
+
withCodexCatalogProvider
|
|
682
|
+
} from "@opengeni/config";
|
|
677
683
|
import {
|
|
678
684
|
accessTokenExpiry,
|
|
679
685
|
buildCodexUsageWindowFromCache,
|
|
680
686
|
CODEX_CLIENT_VERSION,
|
|
681
|
-
CODEX_FALLBACK_MODEL_SLUGS,
|
|
682
687
|
CODEX_FIVE_HOUR_WINDOW_SECONDS,
|
|
683
|
-
CODEX_MODEL_ID_PREFIX,
|
|
684
688
|
CODEX_PROVIDER_ID,
|
|
685
689
|
CODEX_WEEKLY_WINDOW_SECONDS,
|
|
686
690
|
CodexDeviceError,
|
|
@@ -741,7 +745,8 @@ import {
|
|
|
741
745
|
getManagedSession,
|
|
742
746
|
hasPermission as hasPermission2,
|
|
743
747
|
requireAccessGrant as requireAccessGrant2,
|
|
744
|
-
requireCanonicalLocalAccountAdministrator
|
|
748
|
+
requireCanonicalLocalAccountAdministrator,
|
|
749
|
+
resolveCatalogSettings
|
|
745
750
|
} from "@opengeni/core";
|
|
746
751
|
import { HTTPException as HTTPException2 } from "hono/http-exception";
|
|
747
752
|
import * as z3 from "zod/v4";
|
|
@@ -863,10 +868,10 @@ function codexWorkerReadiness(input) {
|
|
|
863
868
|
function codexUsageJson(payload) {
|
|
864
869
|
return { status: payload.status, usage: payload };
|
|
865
870
|
}
|
|
866
|
-
function codexModelsForPicker() {
|
|
867
|
-
return
|
|
868
|
-
id:
|
|
869
|
-
label:
|
|
871
|
+
function codexModelsForPicker(settings = getSettings()) {
|
|
872
|
+
return configuredModels(withCodexCatalogProvider(settings)).filter((model) => model.providerId === CODEX_PROVIDER_ID).map((model) => ({
|
|
873
|
+
id: model.id,
|
|
874
|
+
label: model.label,
|
|
870
875
|
provider: CODEX_PROVIDER_ID,
|
|
871
876
|
providerLabel: CODEX_PROVIDER_LABEL,
|
|
872
877
|
api: "responses"
|
|
@@ -1687,7 +1692,7 @@ function registerCodexRoutes(app, deps) {
|
|
|
1687
1692
|
now: /* @__PURE__ */ new Date()
|
|
1688
1693
|
});
|
|
1689
1694
|
let valid = false;
|
|
1690
|
-
const models = codexModelsForPicker();
|
|
1695
|
+
const models = codexModelsForPicker((await resolveCatalogSettings(db, settings)).settings);
|
|
1691
1696
|
let catalogError = null;
|
|
1692
1697
|
try {
|
|
1693
1698
|
const cred = status?.credentialId ? await loadCodexCredentialForRun(db, settings, workspaceId, status.credentialId) : null;
|
|
@@ -2471,7 +2476,7 @@ import {
|
|
|
2471
2476
|
updateOrganizationXaiRotation
|
|
2472
2477
|
} from "@opengeni/db";
|
|
2473
2478
|
import {
|
|
2474
|
-
configuredModels,
|
|
2479
|
+
configuredModels as configuredModels2,
|
|
2475
2480
|
environmentsEncryptionKeyBytes as environmentsEncryptionKeyBytes2,
|
|
2476
2481
|
withXaiSubscriptionCatalogProvider
|
|
2477
2482
|
} from "@opengeni/config";
|
|
@@ -3184,7 +3189,7 @@ function registerSuperGrokRoutes(app, deps) {
|
|
|
3184
3189
|
valid = false;
|
|
3185
3190
|
}
|
|
3186
3191
|
const catalogSettings = valid ? (await deps.resolveCatalogSettings()).settings : null;
|
|
3187
|
-
const catalog = catalogSettings ?
|
|
3192
|
+
const catalog = catalogSettings ? configuredModels2(withXaiSubscriptionCatalogProvider(catalogSettings)).filter(
|
|
3188
3193
|
(model) => model.credentialSource.kind === "connected_subscription" && model.credentialSource.provider === "xai"
|
|
3189
3194
|
).map(projectClientModel) : [];
|
|
3190
3195
|
return c.json({
|
|
@@ -3426,7 +3431,7 @@ function registerModelConnectionAccessRoutes(app, deps) {
|
|
|
3426
3431
|
accountId: connection.accountId,
|
|
3427
3432
|
workspaceId: connection.workspaceId
|
|
3428
3433
|
})).settings;
|
|
3429
|
-
settings =
|
|
3434
|
+
settings = withCodexCatalogProvider2(withXaiSubscriptionCatalogProvider2(settings));
|
|
3430
3435
|
let workspaces = [];
|
|
3431
3436
|
if (connection.workspaceId === null) {
|
|
3432
3437
|
const actor = {
|
|
@@ -3448,7 +3453,7 @@ function registerModelConnectionAccessRoutes(app, deps) {
|
|
|
3448
3453
|
ModelConnectionAccessResponse.parse({
|
|
3449
3454
|
policy,
|
|
3450
3455
|
workspaces,
|
|
3451
|
-
models:
|
|
3456
|
+
models: configuredModels3(settings).filter((model) => model.id.startsWith(modelPrefix(connection))).map(({ id, label }) => ({ id, label })),
|
|
3452
3457
|
personalWorkspacesSupported: connection.workspaceId === null && (connection.kind === "codex" || connection.kind === "supergrok")
|
|
3453
3458
|
})
|
|
3454
3459
|
);
|
|
@@ -3482,10 +3487,10 @@ import {
|
|
|
3482
3487
|
canonicalizeConfiguredModelId as canonicalizeConfiguredModelId2,
|
|
3483
3488
|
configuredAllowedModels,
|
|
3484
3489
|
configuredAllowedReasoningEfforts,
|
|
3485
|
-
configuredModels as
|
|
3490
|
+
configuredModels as configuredModels4,
|
|
3486
3491
|
resolveFirstPartyMcpToolPolicy as resolveFirstPartyMcpToolPolicy2,
|
|
3487
3492
|
resolveVoiceInputProviderRegistry as resolveVoiceInputProviderRegistry2,
|
|
3488
|
-
withCodexCatalogProvider as
|
|
3493
|
+
withCodexCatalogProvider as withCodexCatalogProvider3,
|
|
3489
3494
|
withXaiSubscriptionCatalogProvider as withXaiSubscriptionCatalogProvider3
|
|
3490
3495
|
} from "@opengeni/config";
|
|
3491
3496
|
import {
|
|
@@ -3600,7 +3605,7 @@ import {
|
|
|
3600
3605
|
requireAccessGrantAuthorization as requireAccessGrantAuthorization36,
|
|
3601
3606
|
requirePermission as requirePermission9,
|
|
3602
3607
|
releaseManagedAuthRequestActorLease,
|
|
3603
|
-
resolveCatalogSettings,
|
|
3608
|
+
resolveCatalogSettings as resolveCatalogSettings2,
|
|
3604
3609
|
resolveWorkspaceCatalogSettings as resolveWorkspaceCatalogSettings10,
|
|
3605
3610
|
validateManagedAuthRequestActorLease,
|
|
3606
3611
|
requireSessionAuthorization as requireSessionAuthorization16,
|
|
@@ -5889,7 +5894,296 @@ import {
|
|
|
5889
5894
|
deleteChannel,
|
|
5890
5895
|
setSessionChannel
|
|
5891
5896
|
} from "@opengeni/db";
|
|
5892
|
-
import { createHash as
|
|
5897
|
+
import { createHash as createHash12, randomUUID as randomUUID3 } from "crypto";
|
|
5898
|
+
|
|
5899
|
+
// src/sandbox/enrollment.ts
|
|
5900
|
+
import { randomBytes } from "crypto";
|
|
5901
|
+
import {
|
|
5902
|
+
resolveEnrollmentSigningSecret,
|
|
5903
|
+
resolveRelayTokenSecret
|
|
5904
|
+
} from "@opengeni/config";
|
|
5905
|
+
import {
|
|
5906
|
+
DeviceEnrollmentState,
|
|
5907
|
+
signEnrollmentBearer,
|
|
5908
|
+
signEnrollToken,
|
|
5909
|
+
signRelayToken,
|
|
5910
|
+
verifyEnrollToken
|
|
5911
|
+
} from "@opengeni/contracts";
|
|
5912
|
+
import {
|
|
5913
|
+
approveDeviceEnrollmentRequest,
|
|
5914
|
+
consumeDeviceEnrollmentRequest,
|
|
5915
|
+
createDeviceEnrollmentRequest,
|
|
5916
|
+
denyDeviceEnrollmentRequest,
|
|
5917
|
+
finalizeEnrollmentByToken,
|
|
5918
|
+
getDeviceEnrollmentRequestByDeviceCode,
|
|
5919
|
+
getEnrollment,
|
|
5920
|
+
getPendingDeviceEnrollmentRequestByUserCode,
|
|
5921
|
+
getPendingDeviceEnrollmentRequestByUserCodeGlobal
|
|
5922
|
+
} from "@opengeni/db";
|
|
5923
|
+
import { relayDialBaseFromSettings } from "@opengeni/core";
|
|
5924
|
+
var DEVICE_CODE_TTL_SECONDS = 600;
|
|
5925
|
+
var DEVICE_POLL_INTERVAL_SECONDS = 5;
|
|
5926
|
+
var ENROLLMENT_BEARER_TTL_SECONDS = 30 * 24 * 3600;
|
|
5927
|
+
var RELAY_TOKEN_TTL_SECONDS = 30 * 24 * 3600;
|
|
5928
|
+
var ENROLL_TOKEN_TTL_SECONDS = 3600;
|
|
5929
|
+
function mintDeviceCode() {
|
|
5930
|
+
return randomBytes(32).toString("base64url");
|
|
5931
|
+
}
|
|
5932
|
+
var USER_CODE_ALPHABET = "ABCDEFGHJKLMNPQRSTUVWXYZ23456789";
|
|
5933
|
+
function mintUserCode() {
|
|
5934
|
+
const bytes = randomBytes(8);
|
|
5935
|
+
let out = "";
|
|
5936
|
+
for (let i = 0; i < 8; i += 1) {
|
|
5937
|
+
out += USER_CODE_ALPHABET[bytes[i] % USER_CODE_ALPHABET.length];
|
|
5938
|
+
}
|
|
5939
|
+
return `${out.slice(0, 4)}-${out.slice(4, 8)}`;
|
|
5940
|
+
}
|
|
5941
|
+
async function startDeviceEnrollment(services, input) {
|
|
5942
|
+
const { db } = services;
|
|
5943
|
+
const expiresAt = new Date(Date.now() + DEVICE_CODE_TTL_SECONDS * 1e3);
|
|
5944
|
+
let request;
|
|
5945
|
+
let lastError;
|
|
5946
|
+
for (let attempt = 0; attempt < 5 && !request; attempt += 1) {
|
|
5947
|
+
const deviceCode = mintDeviceCode();
|
|
5948
|
+
const userCode = mintUserCode();
|
|
5949
|
+
try {
|
|
5950
|
+
request = await createDeviceEnrollmentRequest(db, {
|
|
5951
|
+
accountId: input.accountId,
|
|
5952
|
+
workspaceId: input.workspaceId,
|
|
5953
|
+
deviceCode,
|
|
5954
|
+
userCode,
|
|
5955
|
+
pubkey: input.publicKey,
|
|
5956
|
+
os: input.os,
|
|
5957
|
+
arch: input.arch,
|
|
5958
|
+
machineName: input.machineName ?? null,
|
|
5959
|
+
requestedExposure: "whole-machine",
|
|
5960
|
+
canOfferDisplay: input.canOfferDisplay,
|
|
5961
|
+
requestsScreenControl: input.requestsScreenControl,
|
|
5962
|
+
expiresAt
|
|
5963
|
+
});
|
|
5964
|
+
} catch (error) {
|
|
5965
|
+
lastError = error;
|
|
5966
|
+
}
|
|
5967
|
+
}
|
|
5968
|
+
if (!request) {
|
|
5969
|
+
throw lastError instanceof Error ? lastError : new Error("failed to start device enrollment");
|
|
5970
|
+
}
|
|
5971
|
+
const base = input.verificationOrigin.replace(/\/+$/, "");
|
|
5972
|
+
const verificationUri = `${base}/device`;
|
|
5973
|
+
const verificationUriComplete = `${verificationUri}?user_code=${encodeURIComponent(request.userCode)}`;
|
|
5974
|
+
return {
|
|
5975
|
+
deviceCode: request.deviceCode,
|
|
5976
|
+
userCode: request.userCode,
|
|
5977
|
+
verificationUri,
|
|
5978
|
+
verificationUriComplete,
|
|
5979
|
+
intervalSeconds: DEVICE_POLL_INTERVAL_SECONDS,
|
|
5980
|
+
expiresInSeconds: DEVICE_CODE_TTL_SECONDS
|
|
5981
|
+
};
|
|
5982
|
+
}
|
|
5983
|
+
async function approveDeviceEnrollment(services, input) {
|
|
5984
|
+
const { db } = services;
|
|
5985
|
+
const pending = await getPendingDeviceEnrollmentRequestByUserCode(
|
|
5986
|
+
db,
|
|
5987
|
+
input.workspaceId,
|
|
5988
|
+
input.userCode
|
|
5989
|
+
);
|
|
5990
|
+
if (!pending) {
|
|
5991
|
+
return null;
|
|
5992
|
+
}
|
|
5993
|
+
const sandboxName = (pending.machineName?.trim() || `${pending.os} machine`).slice(0, 256);
|
|
5994
|
+
const result = await approveDeviceEnrollmentRequest(db, {
|
|
5995
|
+
accountId: input.accountId,
|
|
5996
|
+
workspaceId: input.workspaceId,
|
|
5997
|
+
...input.scope ? { scope: input.scope } : {},
|
|
5998
|
+
allowOrganization: input.allowOrganization === true,
|
|
5999
|
+
requestId: pending.id,
|
|
6000
|
+
allowScreenControl: input.allowScreenControl,
|
|
6001
|
+
approvedBySubjectId: input.approvedBySubjectId,
|
|
6002
|
+
approvedBySubjectLabel: input.approvedBySubjectLabel ?? null,
|
|
6003
|
+
sandboxName
|
|
6004
|
+
});
|
|
6005
|
+
if (!result.approved || !result.enrollment || !result.sandbox) {
|
|
6006
|
+
return null;
|
|
6007
|
+
}
|
|
6008
|
+
return {
|
|
6009
|
+
enrollmentId: result.enrollment.id,
|
|
6010
|
+
sandboxId: result.sandbox.id,
|
|
6011
|
+
allowScreenControl: result.enrollment.allowScreenControl
|
|
6012
|
+
};
|
|
6013
|
+
}
|
|
6014
|
+
async function lookupDeviceEnrollment(services, input) {
|
|
6015
|
+
const { db } = services;
|
|
6016
|
+
return await getPendingDeviceEnrollmentRequestByUserCodeGlobal(db, input.userCode);
|
|
6017
|
+
}
|
|
6018
|
+
function toLookupResponse(record6) {
|
|
6019
|
+
return {
|
|
6020
|
+
workspaceId: record6.workspaceId,
|
|
6021
|
+
userCode: record6.userCode,
|
|
6022
|
+
machine: {
|
|
6023
|
+
machineName: record6.machineName,
|
|
6024
|
+
os: record6.os,
|
|
6025
|
+
arch: record6.arch,
|
|
6026
|
+
canOfferDisplay: record6.canOfferDisplay,
|
|
6027
|
+
requestsScreenControl: record6.requestsScreenControl
|
|
6028
|
+
},
|
|
6029
|
+
expiresAt: record6.expiresAt
|
|
6030
|
+
};
|
|
6031
|
+
}
|
|
6032
|
+
async function denyDeviceEnrollment(services, input) {
|
|
6033
|
+
const { db } = services;
|
|
6034
|
+
const pending = await getPendingDeviceEnrollmentRequestByUserCode(
|
|
6035
|
+
db,
|
|
6036
|
+
input.workspaceId,
|
|
6037
|
+
input.userCode
|
|
6038
|
+
);
|
|
6039
|
+
if (!pending) {
|
|
6040
|
+
return { denied: false };
|
|
6041
|
+
}
|
|
6042
|
+
return await denyDeviceEnrollmentRequest(db, {
|
|
6043
|
+
accountId: input.accountId,
|
|
6044
|
+
workspaceId: input.workspaceId,
|
|
6045
|
+
requestId: pending.id
|
|
6046
|
+
});
|
|
6047
|
+
}
|
|
6048
|
+
async function mintEnrollToken(services, input) {
|
|
6049
|
+
const { settings } = services;
|
|
6050
|
+
const secret = resolveEnrollmentSigningSecret(settings);
|
|
6051
|
+
if (!secret) {
|
|
6052
|
+
return null;
|
|
6053
|
+
}
|
|
6054
|
+
const nowSeconds = Math.floor(Date.now() / 1e3);
|
|
6055
|
+
const exp = nowSeconds + ENROLL_TOKEN_TTL_SECONDS;
|
|
6056
|
+
const token = await signEnrollToken(secret, {
|
|
6057
|
+
typ: "enroll",
|
|
6058
|
+
workspaceId: input.workspaceId,
|
|
6059
|
+
accountId: input.accountId,
|
|
6060
|
+
allowScreenControl: input.allowScreenControl,
|
|
6061
|
+
iat: nowSeconds,
|
|
6062
|
+
exp
|
|
6063
|
+
});
|
|
6064
|
+
return {
|
|
6065
|
+
token,
|
|
6066
|
+
expiresAt: new Date(exp * 1e3).toISOString(),
|
|
6067
|
+
expiresInSeconds: ENROLL_TOKEN_TTL_SECONDS
|
|
6068
|
+
};
|
|
6069
|
+
}
|
|
6070
|
+
async function exchangeEnrollToken(services, input) {
|
|
6071
|
+
const { db, settings } = services;
|
|
6072
|
+
const secret = resolveEnrollmentSigningSecret(settings);
|
|
6073
|
+
if (!secret) {
|
|
6074
|
+
return { ok: false, reason: "disabled" };
|
|
6075
|
+
}
|
|
6076
|
+
const claims = await verifyEnrollToken(secret, input.token);
|
|
6077
|
+
if (!claims) {
|
|
6078
|
+
return { ok: false, reason: "invalid" };
|
|
6079
|
+
}
|
|
6080
|
+
const sandboxName = (input.machineName?.trim() || `${input.os} machine`).slice(0, 256);
|
|
6081
|
+
const { enrollment } = await finalizeEnrollmentByToken(db, {
|
|
6082
|
+
accountId: claims.accountId,
|
|
6083
|
+
workspaceId: claims.workspaceId,
|
|
6084
|
+
pubkey: input.publicKey,
|
|
6085
|
+
hasDisplay: input.canOfferDisplay,
|
|
6086
|
+
// The token's allowScreenControl is the AUTHORITATIVE consent (NOT the agent's
|
|
6087
|
+
// requestsScreenControl) — it was baked in at mint by the authorizing user.
|
|
6088
|
+
allowScreenControl: claims.allowScreenControl,
|
|
6089
|
+
os: input.os,
|
|
6090
|
+
arch: input.arch,
|
|
6091
|
+
sandboxName
|
|
6092
|
+
});
|
|
6093
|
+
const credentials = await buildEnrollmentCredentials(services, {
|
|
6094
|
+
secret,
|
|
6095
|
+
workspaceId: claims.workspaceId,
|
|
6096
|
+
agentId: enrollment.id,
|
|
6097
|
+
credentialGeneration: enrollment.credentialGeneration,
|
|
6098
|
+
consentedScreenControl: enrollment.allowScreenControl
|
|
6099
|
+
});
|
|
6100
|
+
return { ok: true, credentials };
|
|
6101
|
+
}
|
|
6102
|
+
async function pollDeviceEnrollment(services, input) {
|
|
6103
|
+
const { db, settings } = services;
|
|
6104
|
+
const request = await getDeviceEnrollmentRequestByDeviceCode(db, input.deviceCode);
|
|
6105
|
+
if (!request) {
|
|
6106
|
+
return { state: "expired" };
|
|
6107
|
+
}
|
|
6108
|
+
if (request.status === "denied") {
|
|
6109
|
+
return { state: "denied" };
|
|
6110
|
+
}
|
|
6111
|
+
if (request.status === "pending") {
|
|
6112
|
+
if (new Date(request.expiresAt).getTime() <= Date.now()) {
|
|
6113
|
+
return { state: "expired" };
|
|
6114
|
+
}
|
|
6115
|
+
return { state: "pending" };
|
|
6116
|
+
}
|
|
6117
|
+
if (!request.enrollmentId) {
|
|
6118
|
+
return { state: "expired" };
|
|
6119
|
+
}
|
|
6120
|
+
const secret = resolveEnrollmentSigningSecret(settings);
|
|
6121
|
+
if (!secret) {
|
|
6122
|
+
return { state: "disabled" };
|
|
6123
|
+
}
|
|
6124
|
+
const enrollment = await getEnrollment(db, request.workspaceId, request.enrollmentId);
|
|
6125
|
+
if (!enrollment || enrollment.status !== "active") {
|
|
6126
|
+
return { state: "denied" };
|
|
6127
|
+
}
|
|
6128
|
+
const credentials = await buildEnrollmentCredentials(services, {
|
|
6129
|
+
secret,
|
|
6130
|
+
workspaceId: request.workspaceId,
|
|
6131
|
+
agentId: enrollment.id,
|
|
6132
|
+
credentialGeneration: enrollment.credentialGeneration,
|
|
6133
|
+
consentedScreenControl: enrollment.allowScreenControl
|
|
6134
|
+
});
|
|
6135
|
+
if (request.status === "approved") {
|
|
6136
|
+
await consumeDeviceEnrollmentRequest(db, {
|
|
6137
|
+
accountId: request.accountId,
|
|
6138
|
+
workspaceId: request.workspaceId,
|
|
6139
|
+
requestId: request.id
|
|
6140
|
+
});
|
|
6141
|
+
}
|
|
6142
|
+
return { state: DeviceEnrollmentState.enum.authorized, credentials };
|
|
6143
|
+
}
|
|
6144
|
+
async function buildEnrollmentCredentials(services, input) {
|
|
6145
|
+
const { settings } = services;
|
|
6146
|
+
const subjectPrefix = `agent.${input.workspaceId}.${input.agentId}`;
|
|
6147
|
+
const nowSeconds = Math.floor(Date.now() / 1e3);
|
|
6148
|
+
const exp = nowSeconds + ENROLLMENT_BEARER_TTL_SECONDS;
|
|
6149
|
+
const bearer = await signEnrollmentBearer(input.secret, {
|
|
6150
|
+
workspaceId: input.workspaceId,
|
|
6151
|
+
agentId: input.agentId,
|
|
6152
|
+
enrollmentId: input.agentId,
|
|
6153
|
+
credentialGeneration: input.credentialGeneration,
|
|
6154
|
+
subjectPrefix,
|
|
6155
|
+
exp
|
|
6156
|
+
});
|
|
6157
|
+
const natsUrls = settings.selfhostedNatsUrl ? [settings.selfhostedNatsUrl] : [];
|
|
6158
|
+
const relayTokenSecret = resolveRelayTokenSecret(settings);
|
|
6159
|
+
const relayToken = relayTokenSecret ? await signRelayToken(relayTokenSecret, {
|
|
6160
|
+
workspaceId: input.workspaceId,
|
|
6161
|
+
agentId: input.agentId,
|
|
6162
|
+
exp: nowSeconds + RELAY_TOKEN_TTL_SECONDS
|
|
6163
|
+
}) : "";
|
|
6164
|
+
return {
|
|
6165
|
+
agentId: input.agentId,
|
|
6166
|
+
workspaceId: input.workspaceId,
|
|
6167
|
+
bearer,
|
|
6168
|
+
subjectPrefix,
|
|
6169
|
+
natsUrls,
|
|
6170
|
+
// Hand the agent the canonical `/stream` dial base, NOT the raw configured URL.
|
|
6171
|
+
// The agent's relay producer appends only its routing query and assumes the base
|
|
6172
|
+
// already carries the relay's `/stream` route; a path-less base 400s the dial and
|
|
6173
|
+
// makes the terminal/desktop streams unreachable.
|
|
6174
|
+
relayUrl: relayDialBaseFromSettings(settings),
|
|
6175
|
+
relayToken,
|
|
6176
|
+
// M-AUTH closes the placeholder: there is NO per-machine NATS Account creds
|
|
6177
|
+
// file. The agent presents the BEARER as the NATS connect auth-token; the
|
|
6178
|
+
// server's auth-callout responder validates it and mints a workspace-scoped
|
|
6179
|
+
// user JWT. We echo the bearer here so a consumer reading this (vestigial) field
|
|
6180
|
+
// as the connect credential still works — the value IS the bearer.
|
|
6181
|
+
natsAccountCreds: bearer,
|
|
6182
|
+
updatePublicKey: settings.agentUpdatePublicKey ?? "",
|
|
6183
|
+
consentedWholeMachine: true,
|
|
6184
|
+
consentedScreenControl: input.consentedScreenControl
|
|
6185
|
+
};
|
|
6186
|
+
}
|
|
5893
6187
|
|
|
5894
6188
|
// src/mcp/capability-account-readiness.ts
|
|
5895
6189
|
function capabilityAccountReadiness(availableRoutes, bindings) {
|
|
@@ -5905,6 +6199,7 @@ function capabilityAccountReadiness(availableRoutes, bindings) {
|
|
|
5905
6199
|
|
|
5906
6200
|
// src/site-uploads.ts
|
|
5907
6201
|
import { WorkspaceArtifactSourceBundle as WorkspaceArtifactSourceBundle2 } from "@opengeni/contracts";
|
|
6202
|
+
import { retryWhileMissing as retryWhileMissing2 } from "@opengeni/storage";
|
|
5908
6203
|
import {
|
|
5909
6204
|
createWorkspaceArtifactUpload,
|
|
5910
6205
|
getWorkspaceArtifactUpload,
|
|
@@ -6017,7 +6312,12 @@ async function validateSiteSource(storage, key, sizeBytes) {
|
|
|
6017
6312
|
"Editable source JSON must be at most 64 MiB. Exclude dependencies and build output; HTML has a separate storage limit."
|
|
6018
6313
|
);
|
|
6019
6314
|
}
|
|
6020
|
-
const content = await storage.getObjectBytes(key);
|
|
6315
|
+
const content = await retryWhileMissing2(() => storage.getObjectBytes(key));
|
|
6316
|
+
if (!content) {
|
|
6317
|
+
throw new WorkspaceArtifactOperationError(
|
|
6318
|
+
"Site source is not available yet. Retry publication with the same upload."
|
|
6319
|
+
);
|
|
6320
|
+
}
|
|
6021
6321
|
try {
|
|
6022
6322
|
WorkspaceArtifactSourceBundle2.parse(
|
|
6023
6323
|
JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(content.bytes))
|
|
@@ -6110,13 +6410,20 @@ async function freeze(storage, from, to, contentType, optional = false) {
|
|
|
6110
6410
|
}
|
|
6111
6411
|
decoder2.decode();
|
|
6112
6412
|
}
|
|
6113
|
-
await storage.putObjectStreamIfAbsent({
|
|
6413
|
+
const created = await storage.putObjectStreamIfAbsent({
|
|
6114
6414
|
key: to,
|
|
6115
6415
|
contentType,
|
|
6116
6416
|
byteSize: head.ContentLength,
|
|
6117
6417
|
chunks: chunks()
|
|
6118
6418
|
});
|
|
6119
|
-
|
|
6419
|
+
if (created) return head.ContentLength;
|
|
6420
|
+
const stored = await retryWhileMissing2(() => storage.headObject(to));
|
|
6421
|
+
if (!stored || stored.ContentLength === void 0) {
|
|
6422
|
+
throw new WorkspaceArtifactOperationError(
|
|
6423
|
+
"Frozen Site upload is unavailable. Retry publication with the same upload."
|
|
6424
|
+
);
|
|
6425
|
+
}
|
|
6426
|
+
return stored.ContentLength;
|
|
6120
6427
|
}
|
|
6121
6428
|
async function prepareWorkspaceArtifactPublication(deps, grant, input) {
|
|
6122
6429
|
const storage = deps.objectStorage;
|
|
@@ -7291,7 +7598,14 @@ function registerKnowledgeEntryTools(server, deps, grant, sessionId) {
|
|
|
7291
7598
|
inputSchema: KnowledgeSavePreparationRequest.shape
|
|
7292
7599
|
},
|
|
7293
7600
|
(input) => run(
|
|
7294
|
-
(context) => prepareKnowledgeSave(
|
|
7601
|
+
(context) => prepareKnowledgeSave(
|
|
7602
|
+
deps.db,
|
|
7603
|
+
context,
|
|
7604
|
+
input,
|
|
7605
|
+
() => deps.getDocumentServices().embedder,
|
|
7606
|
+
void 0,
|
|
7607
|
+
deps.settings
|
|
7608
|
+
)
|
|
7295
7609
|
)
|
|
7296
7610
|
);
|
|
7297
7611
|
server.registerTool(
|
|
@@ -7306,7 +7620,13 @@ function registerKnowledgeEntryTools(server, deps, grant, sessionId) {
|
|
|
7306
7620
|
}).extend({ view: z8.enum(["published", "needs_review"]).default("published") }).shape
|
|
7307
7621
|
},
|
|
7308
7622
|
(input) => run(
|
|
7309
|
-
(context) => searchKnowledgeEntries(
|
|
7623
|
+
(context) => searchKnowledgeEntries(
|
|
7624
|
+
deps.db,
|
|
7625
|
+
context,
|
|
7626
|
+
input,
|
|
7627
|
+
() => deps.getDocumentServices().embedder,
|
|
7628
|
+
deps.settings
|
|
7629
|
+
)
|
|
7310
7630
|
)
|
|
7311
7631
|
);
|
|
7312
7632
|
server.registerTool(
|
|
@@ -7700,7 +8020,7 @@ import {
|
|
|
7700
8020
|
recordSandboxFilePublication,
|
|
7701
8021
|
withSessionRlsActorContext as withSessionRlsActorContext5
|
|
7702
8022
|
} from "@opengeni/db";
|
|
7703
|
-
import { retryWhileMissing as
|
|
8023
|
+
import { retryWhileMissing as retryWhileMissing4 } from "@opengeni/storage";
|
|
7704
8024
|
import { HTTPException as HTTPException12 } from "hono/http-exception";
|
|
7705
8025
|
|
|
7706
8026
|
// src/sandbox/channel-a.ts
|
|
@@ -7709,6 +8029,7 @@ import {
|
|
|
7709
8029
|
hasGitCredentialRepositorySelection,
|
|
7710
8030
|
hasGitHubRepositorySelection,
|
|
7711
8031
|
sandboxLifecycleTransitionWaitMs,
|
|
8032
|
+
sandboxWarmRateMicrosPerSecond,
|
|
7712
8033
|
stableSandboxEnvironmentForRun
|
|
7713
8034
|
} from "@opengeni/config";
|
|
7714
8035
|
import { githubAppBotIdentity } from "@opengeni/github";
|
|
@@ -7727,6 +8048,7 @@ import {
|
|
|
7727
8048
|
SandboxImageConflictError,
|
|
7728
8049
|
SandboxProviderReadLockUnavailableError,
|
|
7729
8050
|
SandboxRigConflictError,
|
|
8051
|
+
SandboxPaidComputeAdmissionError,
|
|
7730
8052
|
withSandboxProviderReadLock
|
|
7731
8053
|
} from "@opengeni/db";
|
|
7732
8054
|
import { appendAndPublishEvents } from "@opengeni/events";
|
|
@@ -8546,6 +8868,10 @@ async function withChannelAOperation(services, ctx, readOnly, fn) {
|
|
|
8546
8868
|
holderId,
|
|
8547
8869
|
subjectId: session.id,
|
|
8548
8870
|
backend: session.sandboxBackend,
|
|
8871
|
+
warmBilling: {
|
|
8872
|
+
mode: settings.sandboxWarmBillingMode,
|
|
8873
|
+
rateMicrosPerSecond: sandboxWarmRateMicrosPerSecond(settings, session.sandboxBackend)
|
|
8874
|
+
},
|
|
8549
8875
|
os: session.sandboxOs,
|
|
8550
8876
|
image: sandboxRuntime.image,
|
|
8551
8877
|
rigVersionId: session.rigVersionId,
|
|
@@ -8846,6 +9172,8 @@ async function withChannelAOperation(services, ctx, readOnly, fn) {
|
|
|
8846
9172
|
}
|
|
8847
9173
|
function mapChannelAError(error, waitSignal) {
|
|
8848
9174
|
if (error instanceof HTTPException6) return error;
|
|
9175
|
+
if (error instanceof SandboxPaidComputeAdmissionError)
|
|
9176
|
+
return new HTTPException6(402, { message: error.message, cause: error });
|
|
8849
9177
|
if (isChannelARequestCancellation(error, waitSignal))
|
|
8850
9178
|
return new HTTPException6(499, {
|
|
8851
9179
|
message: "request cancelled",
|
|
@@ -9059,7 +9387,7 @@ import {
|
|
|
9059
9387
|
SessionAuthorizationUnavailableError as SessionAuthorizationUnavailableError3
|
|
9060
9388
|
} from "@opengeni/core";
|
|
9061
9389
|
import { recordWorkspaceUsage, requireLimit } from "@opengeni/core";
|
|
9062
|
-
import { retryWhileMissing as
|
|
9390
|
+
import { retryWhileMissing as retryWhileMissing3 } from "@opengeni/storage";
|
|
9063
9391
|
import { WebStandardStreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/webStandardStreamableHttp.js";
|
|
9064
9392
|
|
|
9065
9393
|
// src/mcp/files.ts
|
|
@@ -9161,7 +9489,7 @@ function buildFilesMcpServer(deps, authority) {
|
|
|
9161
9489
|
}
|
|
9162
9490
|
|
|
9163
9491
|
// src/mcp-oauth.ts
|
|
9164
|
-
import { createHash as createHash2, randomBytes as
|
|
9492
|
+
import { createHash as createHash2, randomBytes as randomBytes3 } from "crypto";
|
|
9165
9493
|
import {
|
|
9166
9494
|
MCP_OAUTH_ACCESS_TOKEN_TTL_SECONDS,
|
|
9167
9495
|
MCP_OAUTH_AUTHORIZATION_CODE_TTL_SECONDS,
|
|
@@ -9219,7 +9547,7 @@ function normalizedAddress(value) {
|
|
|
9219
9547
|
|
|
9220
9548
|
// src/workspace-tool-gateway.ts
|
|
9221
9549
|
import { knowledgeContextForGateway } from "@opengeni/core";
|
|
9222
|
-
import { createHash, randomBytes } from "crypto";
|
|
9550
|
+
import { createHash, randomBytes as randomBytes2 } from "crypto";
|
|
9223
9551
|
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
|
9224
9552
|
import { InMemoryTransport } from "@modelcontextprotocol/sdk/inMemory.js";
|
|
9225
9553
|
import { withSiteSessionOrigin } from "@opengeni/core";
|
|
@@ -9324,7 +9652,13 @@ function buildDocumentsMcpServer(db, accountId, workspaceId, documentServices, o
|
|
|
9324
9652
|
{
|
|
9325
9653
|
type: "text",
|
|
9326
9654
|
text: JSON.stringify(
|
|
9327
|
-
await searchKnowledgeEntries2(
|
|
9655
|
+
await searchKnowledgeEntries2(
|
|
9656
|
+
db,
|
|
9657
|
+
context,
|
|
9658
|
+
input,
|
|
9659
|
+
() => documentServices.embedder,
|
|
9660
|
+
options.settings
|
|
9661
|
+
)
|
|
9328
9662
|
)
|
|
9329
9663
|
}
|
|
9330
9664
|
]
|
|
@@ -9610,7 +9944,8 @@ async function prepareWorkspaceToolGatewayForGrantInternal(routeDeps, grant, all
|
|
|
9610
9944
|
grant.workspaceId,
|
|
9611
9945
|
routeDeps.getDocumentServices(),
|
|
9612
9946
|
{
|
|
9613
|
-
knowledge: await knowledgeContextForGateway(routeDeps, grant)
|
|
9947
|
+
knowledge: await knowledgeContextForGateway(routeDeps, grant),
|
|
9948
|
+
settings: gatewaySettings
|
|
9614
9949
|
}
|
|
9615
9950
|
)
|
|
9616
9951
|
)
|
|
@@ -9869,7 +10204,7 @@ async function approveWorkspaceToolGatewayCall(prepared, grant, db, input, issue
|
|
|
9869
10204
|
operation: "approval",
|
|
9870
10205
|
source: preparedCall.entry.source
|
|
9871
10206
|
});
|
|
9872
|
-
const approvalToken = `ogta_${
|
|
10207
|
+
const approvalToken = `ogta_${randomBytes2(32).toString("base64url")}`;
|
|
9873
10208
|
const expiresAt = new Date(Date.now() + 5 * 6e4);
|
|
9874
10209
|
try {
|
|
9875
10210
|
await prepared.reauthorize?.();
|
|
@@ -10501,7 +10836,7 @@ function pkceChallenge(verifier) {
|
|
|
10501
10836
|
return createHash2("sha256").update(verifier, "ascii").digest("base64url");
|
|
10502
10837
|
}
|
|
10503
10838
|
function opaque(prefix) {
|
|
10504
|
-
return `${prefix}${
|
|
10839
|
+
return `${prefix}${randomBytes3(32).toString("base64url")}`;
|
|
10505
10840
|
}
|
|
10506
10841
|
function tokenHash(value) {
|
|
10507
10842
|
return createHash2("sha256").update(value, "utf8").digest("hex");
|
|
@@ -10954,7 +11289,7 @@ function registerFileRoutes(app, deps) {
|
|
|
10954
11289
|
const file2 = await rejectAndCleanObject(409, "file upload has expired", "expired");
|
|
10955
11290
|
return c.json(CompleteFileUploadResponse.parse({ file: file2 }));
|
|
10956
11291
|
}
|
|
10957
|
-
const head = await
|
|
11292
|
+
const head = await retryWhileMissing3(async () => {
|
|
10958
11293
|
if (!await objectStorage.fileExists(upload.file)) return null;
|
|
10959
11294
|
return await objectStorage.headFile(upload.file);
|
|
10960
11295
|
});
|
|
@@ -11086,7 +11421,7 @@ function registerFileRoutes(app, deps) {
|
|
|
11086
11421
|
throw new HTTPException11(409, { message: `generated video is ${retained.file.status}` });
|
|
11087
11422
|
}
|
|
11088
11423
|
const file = generatedVideoFileAsset(retained.file);
|
|
11089
|
-
const videoPresent = await
|
|
11424
|
+
const videoPresent = await retryWhileMissing3(
|
|
11090
11425
|
async () => await objectStorage.fileExists(file) ? true : null
|
|
11091
11426
|
);
|
|
11092
11427
|
if (!videoPresent) {
|
|
@@ -11196,7 +11531,7 @@ function registerFileRoutes(app, deps) {
|
|
|
11196
11531
|
if (file.status !== "ready") {
|
|
11197
11532
|
throw new HTTPException11(409, { message: `file is ${file.status}` });
|
|
11198
11533
|
}
|
|
11199
|
-
const present = await
|
|
11534
|
+
const present = await retryWhileMissing3(
|
|
11200
11535
|
async () => await objectStorage.fileExists(file) ? true : null
|
|
11201
11536
|
);
|
|
11202
11537
|
if (!present) {
|
|
@@ -11270,7 +11605,7 @@ async function serveRetainedArtifactContent(c, objectStorage, artifactId2, file,
|
|
|
11270
11605
|
...range.contentRange ? { "Content-Range": range.contentRange } : {}
|
|
11271
11606
|
};
|
|
11272
11607
|
if (range.kind === "empty") {
|
|
11273
|
-
const present = await
|
|
11608
|
+
const present = await retryWhileMissing3(
|
|
11274
11609
|
async () => await objectStorage.fileExists(file) ? true : null
|
|
11275
11610
|
);
|
|
11276
11611
|
if (!present) {
|
|
@@ -11278,7 +11613,7 @@ async function serveRetainedArtifactContent(c, objectStorage, artifactId2, file,
|
|
|
11278
11613
|
}
|
|
11279
11614
|
return c.body(null, 200, headers);
|
|
11280
11615
|
}
|
|
11281
|
-
const bytes = await
|
|
11616
|
+
const bytes = await retryWhileMissing3(
|
|
11282
11617
|
async () => objectStorage.getFileRange(file, {
|
|
11283
11618
|
start: range.start,
|
|
11284
11619
|
end: range.end
|
|
@@ -11674,6 +12009,14 @@ function sandboxFileContentType(filename) {
|
|
|
11674
12009
|
".jpg": "image/jpeg",
|
|
11675
12010
|
".json": "application/json",
|
|
11676
12011
|
".md": "text/markdown",
|
|
12012
|
+
".mp4": "video/mp4",
|
|
12013
|
+
".webm": "video/webm",
|
|
12014
|
+
".ogv": "video/ogg",
|
|
12015
|
+
".mp3": "audio/mpeg",
|
|
12016
|
+
".m4a": "audio/mp4",
|
|
12017
|
+
".ogg": "audio/ogg",
|
|
12018
|
+
".wav": "audio/wav",
|
|
12019
|
+
".flac": "audio/flac",
|
|
11677
12020
|
".pdf": "application/pdf",
|
|
11678
12021
|
".png": "image/png",
|
|
11679
12022
|
".pptx": "application/vnd.openxmlformats-officedocument.presentationml.presentation",
|
|
@@ -11685,7 +12028,9 @@ function sandboxFileContentType(filename) {
|
|
|
11685
12028
|
}[extension] ?? "application/octet-stream";
|
|
11686
12029
|
}
|
|
11687
12030
|
function sandboxArtifactIdentity(input) {
|
|
11688
|
-
const digest2 = createHash3("sha256").update(
|
|
12031
|
+
const digest2 = createHash3("sha256").update(
|
|
12032
|
+
/^(audio|video)\//.test(sandboxFileContentType(input.path)) ? "opengeni-sandbox-media-artifact-v1\0" : "opengeni-sandbox-file-artifact-v1\0"
|
|
12033
|
+
).update(input.workspaceId).update("\0").update(input.sessionId).update("\0").update(input.path).update("\0").update(input.sha256).digest("hex");
|
|
11689
12034
|
return {
|
|
11690
12035
|
fileId: uuidFromDigest(digest2, 0),
|
|
11691
12036
|
uploadId: uuidFromDigest(digest2, 16)
|
|
@@ -11704,7 +12049,7 @@ function assertSandboxArtifactFile(file, expected) {
|
|
|
11704
12049
|
}
|
|
11705
12050
|
}
|
|
11706
12051
|
async function assertVisibleSandboxArtifact(storage, file) {
|
|
11707
|
-
const head = await
|
|
12052
|
+
const head = await retryWhileMissing4(async () => await storage.headObject(file.objectKey));
|
|
11708
12053
|
assertStoredSandboxArtifact(head, file);
|
|
11709
12054
|
}
|
|
11710
12055
|
function assertStoredSandboxArtifact(head, file) {
|
|
@@ -11834,9 +12179,11 @@ import {
|
|
|
11834
12179
|
getGlobalCatalogOAuthProfile,
|
|
11835
12180
|
listConnectionsMetadata,
|
|
11836
12181
|
loadIntegrationOAuthClient,
|
|
12182
|
+
loadIntegrationOAuthPendingState,
|
|
11837
12183
|
normalizeBearerScheme,
|
|
11838
12184
|
replaceIntegrationOAuthClientIfCurrent,
|
|
11839
12185
|
storeIntegrationOAuthClient,
|
|
12186
|
+
storeIntegrationOAuthPendingState,
|
|
11840
12187
|
updateConnection,
|
|
11841
12188
|
withDatabaseStatementTimeout
|
|
11842
12189
|
} from "@opengeni/db";
|
|
@@ -11854,7 +12201,7 @@ import {
|
|
|
11854
12201
|
validateHttpUrl
|
|
11855
12202
|
} from "@opengeni/network";
|
|
11856
12203
|
import { Buffer as Buffer2 } from "buffer";
|
|
11857
|
-
import { createHash as createHash4, randomBytes as
|
|
12204
|
+
import { createHash as createHash4, randomBytes as randomBytes4, randomUUID } from "crypto";
|
|
11858
12205
|
import { HTTPException as HTTPException17 } from "hono/http-exception";
|
|
11859
12206
|
|
|
11860
12207
|
// src/connection-ownership.ts
|
|
@@ -12406,7 +12753,7 @@ async function startMcpOAuthWithinDeadline(deps, context, deadline) {
|
|
|
12406
12753
|
)
|
|
12407
12754
|
);
|
|
12408
12755
|
const key = requireEnvironmentEncryption(settings);
|
|
12409
|
-
const
|
|
12756
|
+
const fullState = createSignedState3(requireIntegrationsStateSecret(settings), {
|
|
12410
12757
|
...context.integrationKey ? { integrationKey: context.integrationKey } : {},
|
|
12411
12758
|
...context.connectAttemptId ? { connectAttemptId: context.connectAttemptId } : {},
|
|
12412
12759
|
accountId: context.accountId,
|
|
@@ -12448,6 +12795,30 @@ async function startMcpOAuthWithinDeadline(deps, context, deadline) {
|
|
|
12448
12795
|
returnPath,
|
|
12449
12796
|
...existing ? { connectionId: existing.id, connectionVersion: existing.version } : {}
|
|
12450
12797
|
});
|
|
12798
|
+
const expiresAt = new Date(Date.now() + oauthStateTtlMs);
|
|
12799
|
+
let state = fullState;
|
|
12800
|
+
if (settings.integrationsOauthShortStateEnabled) {
|
|
12801
|
+
const stateId = randomUUID();
|
|
12802
|
+
state = createSignedState3(requireIntegrationsStateSecret(settings), {
|
|
12803
|
+
kind: "mcp_oauth_reference",
|
|
12804
|
+
id: stateId,
|
|
12805
|
+
accountId: context.accountId,
|
|
12806
|
+
workspaceId: context.workspaceId
|
|
12807
|
+
});
|
|
12808
|
+
if (state.length > 512) {
|
|
12809
|
+
throw new Error("MCP OAuth reference state exceeded its provider-safe length");
|
|
12810
|
+
}
|
|
12811
|
+
await deadline.run(
|
|
12812
|
+
"state_persist",
|
|
12813
|
+
async () => storeIntegrationOAuthPendingState(db, {
|
|
12814
|
+
id: stateId,
|
|
12815
|
+
accountId: context.accountId,
|
|
12816
|
+
workspaceId: context.workspaceId,
|
|
12817
|
+
stateEncrypted: encryptEnvironmentValue3(key, fullState),
|
|
12818
|
+
expiresAt
|
|
12819
|
+
})
|
|
12820
|
+
);
|
|
12821
|
+
}
|
|
12451
12822
|
const authorizationUrl = buildAuthorizationUrl({
|
|
12452
12823
|
endpoint: discovery.as.authorizationEndpoint,
|
|
12453
12824
|
settings,
|
|
@@ -12463,7 +12834,7 @@ async function startMcpOAuthWithinDeadline(deps, context, deadline) {
|
|
|
12463
12834
|
return OAuthStartResponse.parse({
|
|
12464
12835
|
state,
|
|
12465
12836
|
authorizationUrl,
|
|
12466
|
-
expiresAt:
|
|
12837
|
+
expiresAt: expiresAt.toISOString()
|
|
12467
12838
|
});
|
|
12468
12839
|
}
|
|
12469
12840
|
function assertOAuthStartProfile(settings, payload, mcpUrl, profile) {
|
|
@@ -12519,7 +12890,7 @@ async function completeMcpOAuthCallbackWithinDeadline(deps, input, deadline) {
|
|
|
12519
12890
|
};
|
|
12520
12891
|
}
|
|
12521
12892
|
try {
|
|
12522
|
-
state =
|
|
12893
|
+
state = await resolveMcpOAuthState(db, settings, input.state, deadline);
|
|
12523
12894
|
integrationKey = state.integrationKey ?? "custom:mcp";
|
|
12524
12895
|
if (state.connectAttemptId) {
|
|
12525
12896
|
const stored = await getConnectAttempt2(db, state, state.connectAttemptId);
|
|
@@ -13297,6 +13668,33 @@ function buildAuthorizationUrl(input) {
|
|
|
13297
13668
|
}
|
|
13298
13669
|
return url.toString();
|
|
13299
13670
|
}
|
|
13671
|
+
async function resolveMcpOAuthState(db, settings, state, deadline) {
|
|
13672
|
+
const reference = readSignedState4(state, requireIntegrationsStateSecret(settings));
|
|
13673
|
+
if (reference?.kind !== "mcp_oauth_reference") {
|
|
13674
|
+
return readOAuthState(state, settings);
|
|
13675
|
+
}
|
|
13676
|
+
const accountId = requiredString(reference.accountId, "state.accountId");
|
|
13677
|
+
const workspaceId = requiredString(reference.workspaceId, "state.workspaceId");
|
|
13678
|
+
const id = requiredString(reference.id, "state.id");
|
|
13679
|
+
if (!/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/.test(id)) {
|
|
13680
|
+
throw new HTTPException17(400, { message: "invalid OAuth state reference" });
|
|
13681
|
+
}
|
|
13682
|
+
const encrypted = await runCallbackDatabaseStage(
|
|
13683
|
+
deadline,
|
|
13684
|
+
"state_verify",
|
|
13685
|
+
db,
|
|
13686
|
+
(scopedDb) => loadIntegrationOAuthPendingState(scopedDb, { accountId, workspaceId, id })
|
|
13687
|
+
);
|
|
13688
|
+
if (!encrypted) {
|
|
13689
|
+
throw new HTTPException17(400, { message: "invalid or expired OAuth state" });
|
|
13690
|
+
}
|
|
13691
|
+
const fullState = decryptEnvironmentValue2(requireEnvironmentEncryption(settings), encrypted);
|
|
13692
|
+
const resolved = readOAuthState(fullState, settings);
|
|
13693
|
+
if (resolved.accountId !== accountId || resolved.workspaceId !== workspaceId) {
|
|
13694
|
+
throw new HTTPException17(400, { message: "OAuth state reference mismatch" });
|
|
13695
|
+
}
|
|
13696
|
+
return resolved;
|
|
13697
|
+
}
|
|
13300
13698
|
function readOAuthState(state, settings) {
|
|
13301
13699
|
const payload = readSignedState4(state, requireIntegrationsStateSecret(settings));
|
|
13302
13700
|
if (!payload) {
|
|
@@ -13633,6 +14031,8 @@ function oauthStartStageLabel(stage) {
|
|
|
13633
14031
|
return "authorization-server discovery";
|
|
13634
14032
|
case "client_registration":
|
|
13635
14033
|
return "OAuth client registration";
|
|
14034
|
+
case "state_persist":
|
|
14035
|
+
return "OAuth state persistence";
|
|
13636
14036
|
}
|
|
13637
14037
|
}
|
|
13638
14038
|
function logOAuthVerificationWarning(observability, error, _state) {
|
|
@@ -13920,7 +14320,7 @@ function pkceChallenge2(verifier) {
|
|
|
13920
14320
|
return createHash4("sha256").update(verifier).digest("base64url");
|
|
13921
14321
|
}
|
|
13922
14322
|
function randomPkceVerifier() {
|
|
13923
|
-
return
|
|
14323
|
+
return randomBytes4(32).toString("base64url");
|
|
13924
14324
|
}
|
|
13925
14325
|
function uniqueStrings(values) {
|
|
13926
14326
|
return [...new Set(values.map((value) => value.trim()).filter(Boolean))];
|
|
@@ -13964,7 +14364,7 @@ import {
|
|
|
13964
14364
|
import { createSignedState as createSignedState4, readSignedState as readSignedState5 } from "@opengeni/github";
|
|
13965
14365
|
import { OAUTH_MAX_RESPONSE_BYTES as OAUTH_MAX_RESPONSE_BYTES3, pinnedFetch as pinnedFetch2, readResponseJsonBounded as readResponseJsonBounded2 } from "@opengeni/network";
|
|
13966
14366
|
import { Buffer as Buffer3 } from "buffer";
|
|
13967
|
-
import { createHash as createHash5, randomBytes as
|
|
14367
|
+
import { createHash as createHash5, randomBytes as randomBytes5 } from "crypto";
|
|
13968
14368
|
import { HTTPException as HTTPException18 } from "hono/http-exception";
|
|
13969
14369
|
var SOCIAL_USER_AGENT = "opengeni:social-connector:v0.1.0 (self-hosted)";
|
|
13970
14370
|
var SOCIAL_TIMEOUT_MS = 1e4;
|
|
@@ -14033,7 +14433,7 @@ async function startSocialOAuth(deps, context) {
|
|
|
14033
14433
|
const redirectUri = socialOAuthRedirectUri(settings, context.requestUrl);
|
|
14034
14434
|
const returnPath = safeReturnPath2(context.payload.returnPath ?? "/integrations");
|
|
14035
14435
|
const scopes = uniqueScopes(context.payload.scopes) ?? provider.defaultScopes;
|
|
14036
|
-
const verifier = provider.pkce ?
|
|
14436
|
+
const verifier = provider.pkce ? randomBytes5(32).toString("base64url") : null;
|
|
14037
14437
|
const key = requireEnvironmentEncryption2(settings);
|
|
14038
14438
|
const state = createSignedState4(requireIntegrationsStateSecret(settings), {
|
|
14039
14439
|
kind: "social_oauth",
|
|
@@ -15772,6 +16172,21 @@ function boundRigDetailMcp(rig, versionsPage, changesPage, maxBytes = RIG_DETAIL
|
|
|
15772
16172
|
return result;
|
|
15773
16173
|
}
|
|
15774
16174
|
|
|
16175
|
+
// src/mcp/child-read-evidence.ts
|
|
16176
|
+
function completeChildReadSequences(page) {
|
|
16177
|
+
if (!page.sourceExact || !["conversation", "results"].includes(page.view)) return [];
|
|
16178
|
+
return page.events.filter((event) => {
|
|
16179
|
+
if (event.sourceOmitted) return false;
|
|
16180
|
+
if (event.fragment === void 0) return true;
|
|
16181
|
+
if (!event.fragment || typeof event.fragment !== "object") return false;
|
|
16182
|
+
const fragment = event.fragment;
|
|
16183
|
+
return fragment.offset === 0 && fragment.complete === true;
|
|
16184
|
+
}).map((event) => event.sequence);
|
|
16185
|
+
}
|
|
16186
|
+
|
|
16187
|
+
// src/mcp/server.ts
|
|
16188
|
+
import { acknowledgeConsumedChildEvents } from "@opengeni/db";
|
|
16189
|
+
|
|
15775
16190
|
// src/mcp/session-wait.ts
|
|
15776
16191
|
import {
|
|
15777
16192
|
SESSION_EVENT_SEMANTIC_CLASS_TYPES,
|
|
@@ -16069,6 +16484,7 @@ function summarizeSessionWaitEvent(event, textChars = SUMMARY_TEXT_TIERS[0]) {
|
|
|
16069
16484
|
} else if (typeof compact.result === "string" && compact.result !== compact.text) {
|
|
16070
16485
|
summary.result = clampSummaryString(compact.result, textChars);
|
|
16071
16486
|
}
|
|
16487
|
+
summary.contentComplete = ["turn.completed", "agent.message.completed"].includes(event.type) && !compact.truncation.truncated && text === compact.text && JSON.stringify(failure) === JSON.stringify(compact.failure) && (compact.output === null || compact.output === compact.text || JSON.stringify(compact.output) === JSON.stringify(summary.result)) && (compact.result === null || compact.result === void 0 || compact.result === compact.text || JSON.stringify(summary.result) === JSON.stringify(compact.result));
|
|
16072
16488
|
return summary;
|
|
16073
16489
|
}
|
|
16074
16490
|
function prettyJsonBytes2(value) {
|
|
@@ -16100,6 +16516,7 @@ function boundSessionWaitResult(input, maxBytes = SESSION_EVENT_MCP_MAX_BYTES) {
|
|
|
16100
16516
|
...target,
|
|
16101
16517
|
events: target.events.map((event) => ({
|
|
16102
16518
|
...event,
|
|
16519
|
+
contentComplete: false,
|
|
16103
16520
|
text: event.text === null ? null : clampSummaryString(event.text, textChars),
|
|
16104
16521
|
...typeof event.result === "string" ? { result: clampSummaryString(event.result, textChars) } : {}
|
|
16105
16522
|
}))
|
|
@@ -16705,6 +17122,7 @@ import {
|
|
|
16705
17122
|
hasGitHubRepositorySelection as hasGitHubRepositorySelection2,
|
|
16706
17123
|
resolveStreamTokenSecret,
|
|
16707
17124
|
sandboxLifecycleTransitionWaitMs as sandboxLifecycleTransitionWaitMs2,
|
|
17125
|
+
sandboxWarmRateMicrosPerSecond as sandboxWarmRateMicrosPerSecond2,
|
|
16708
17126
|
stableSandboxEnvironmentForRun as stableSandboxEnvironmentForRun2
|
|
16709
17127
|
} from "@opengeni/config";
|
|
16710
17128
|
import { githubAppBotIdentity as githubAppBotIdentity2 } from "@opengeni/github";
|
|
@@ -16714,7 +17132,7 @@ import {
|
|
|
16714
17132
|
getSandbox as getSandbox2,
|
|
16715
17133
|
getScheduledScopedRigVersionMetadata as getScheduledScopedRigVersionMetadata2,
|
|
16716
17134
|
getSandboxSessionEnvelope as getSandboxSessionEnvelope2,
|
|
16717
|
-
|
|
17135
|
+
heartbeatLeaseHolderStatus,
|
|
16718
17136
|
loadWorkspaceEnvironmentForRun as loadWorkspaceEnvironmentForRun2,
|
|
16719
17137
|
markSandboxProviderReady,
|
|
16720
17138
|
markWarmLeaseInstanceLost as markWarmLeaseInstanceLost2,
|
|
@@ -16724,6 +17142,7 @@ import {
|
|
|
16724
17142
|
releaseLeaseHolder as releaseLeaseHolder2,
|
|
16725
17143
|
SandboxLeaseSupersededError as SandboxLeaseSupersededError2,
|
|
16726
17144
|
SandboxViewerAdmissionBlockedError,
|
|
17145
|
+
SandboxPaidComputeAdmissionError as SandboxPaidComputeAdmissionError2,
|
|
16727
17146
|
getSessionAuthorityEpoch,
|
|
16728
17147
|
namedSubjectHasLiveWorkspaceAuthority
|
|
16729
17148
|
} from "@opengeni/db";
|
|
@@ -16853,6 +17272,10 @@ async function attachViewer(services, input) {
|
|
|
16853
17272
|
...attachSubjectId ? { viewerSubjectId: attachSubjectId } : {},
|
|
16854
17273
|
...attachAuthorityEpoch !== null ? { viewerAuthorityEpoch: attachAuthorityEpoch } : {},
|
|
16855
17274
|
backend: session.sandboxBackend,
|
|
17275
|
+
warmBilling: {
|
|
17276
|
+
mode: settings.sandboxWarmBillingMode,
|
|
17277
|
+
rateMicrosPerSecond: sandboxWarmRateMicrosPerSecond2(settings, session.sandboxBackend)
|
|
17278
|
+
},
|
|
16856
17279
|
os: session.sandboxOs,
|
|
16857
17280
|
image: sandboxRuntime.image,
|
|
16858
17281
|
rigVersionId: session.rigVersionId,
|
|
@@ -16862,6 +17285,9 @@ async function attachViewer(services, input) {
|
|
|
16862
17285
|
...input.waitSignal ? { waitSignal: input.waitSignal } : {}
|
|
16863
17286
|
});
|
|
16864
17287
|
} catch (error) {
|
|
17288
|
+
if (error instanceof SandboxPaidComputeAdmissionError2) {
|
|
17289
|
+
throw new HTTPException19(402, { message: error.message, cause: error });
|
|
17290
|
+
}
|
|
16865
17291
|
if (error instanceof SandboxViewerAdmissionBlockedError) {
|
|
16866
17292
|
throw new HTTPException19(error.reason === "balance" ? 402 : 429, {
|
|
16867
17293
|
message: error.reason === "balance" ? "insufficient OpenGeni credits for an idle sandbox viewer" : "workspace sandbox warm allowance exhausted",
|
|
@@ -17048,16 +17474,17 @@ async function ensureSessionGroupReady(services, input) {
|
|
|
17048
17474
|
throw lastError ?? new Error("sandbox readiness could not be established");
|
|
17049
17475
|
}
|
|
17050
17476
|
async function heartbeatViewer(services, input) {
|
|
17051
|
-
const
|
|
17477
|
+
const status = await heartbeatLeaseHolderStatus(services.db, {
|
|
17052
17478
|
accountId: input.accountId,
|
|
17053
17479
|
workspaceId: input.workspaceId,
|
|
17054
17480
|
sandboxGroupId: input.sandboxGroupId,
|
|
17055
17481
|
kind: "viewer",
|
|
17056
17482
|
holderId: input.viewerId,
|
|
17057
17483
|
leaseTtlMs: services.settings.sandboxLeaseTtlMs,
|
|
17058
|
-
expectedEpoch: input.expectedEpoch
|
|
17484
|
+
expectedEpoch: input.expectedEpoch,
|
|
17485
|
+
billingMode: services.settings.sandboxWarmBillingMode
|
|
17059
17486
|
});
|
|
17060
|
-
if (!
|
|
17487
|
+
if (!status.leaseExtended) return status.holderAlive && status.fence === "funding";
|
|
17061
17488
|
const lease = await readLease2(services.db, input.workspaceId, input.sandboxGroupId);
|
|
17062
17489
|
if (lease?.liveness === "warm" && lease.leaseEpoch === input.expectedEpoch && lease.instanceId) {
|
|
17063
17490
|
await renewSandboxProviderExpiration({
|
|
@@ -17543,7 +17970,7 @@ function viewerIdAsUuid(rawViewerId) {
|
|
|
17543
17970
|
}
|
|
17544
17971
|
|
|
17545
17972
|
// src/integrations/slack-bot.ts
|
|
17546
|
-
import { createHmac as createHmac3, timingSafeEqual as timingSafeEqual2 } from "crypto";
|
|
17973
|
+
import { createHash as createHash7, createHmac as createHmac3, timingSafeEqual as timingSafeEqual2 } from "crypto";
|
|
17547
17974
|
import { environmentsEncryptionKeyBytes as environmentsEncryptionKeyBytes3 } from "@opengeni/config";
|
|
17548
17975
|
import {
|
|
17549
17976
|
OPENGENI_SLACK_BOT_CREDENTIAL_LABEL,
|
|
@@ -18228,6 +18655,7 @@ var OpenGeniSlackBotClient = class {
|
|
|
18228
18655
|
const targetKind = input.userId ? "user" : "channel";
|
|
18229
18656
|
const targetId = input.userId ?? input.channelId;
|
|
18230
18657
|
const blocks = validateSlackMessageBlocks(input.blocks);
|
|
18658
|
+
const wireBlocks = slackMessageWireBlocks(blocks);
|
|
18231
18659
|
const requestDigest = this.postRequestDigest({
|
|
18232
18660
|
operationId: input.operationId,
|
|
18233
18661
|
targetKind,
|
|
@@ -18309,7 +18737,7 @@ var OpenGeniSlackBotClient = class {
|
|
|
18309
18737
|
const posted = await this.call(headers, "chat.postMessage", {
|
|
18310
18738
|
channel: channelId,
|
|
18311
18739
|
text: input.text,
|
|
18312
|
-
...
|
|
18740
|
+
...wireBlocks ? { blocks: JSON.stringify(wireBlocks) } : {},
|
|
18313
18741
|
client_msg_id: input.operationId,
|
|
18314
18742
|
unfurl_links: "false",
|
|
18315
18743
|
unfurl_media: "false",
|
|
@@ -18367,6 +18795,7 @@ var OpenGeniSlackBotClient = class {
|
|
|
18367
18795
|
let providerCallStarted = false;
|
|
18368
18796
|
const blocks = validateSlackMessageBlocks(input.blocks);
|
|
18369
18797
|
try {
|
|
18798
|
+
const wireBlocks = slackMessageWireBlocks(blocks);
|
|
18370
18799
|
const headers = await this.headersFor(operation);
|
|
18371
18800
|
await this.requireMemberChannel(headers, input.channelId);
|
|
18372
18801
|
const requestDigest = this.updateRequestDigest({ ...input, ...blocks ? { blocks } : {} });
|
|
@@ -18405,7 +18834,7 @@ var OpenGeniSlackBotClient = class {
|
|
|
18405
18834
|
channel: input.channelId,
|
|
18406
18835
|
ts: input.timestamp,
|
|
18407
18836
|
text: input.text,
|
|
18408
|
-
...
|
|
18837
|
+
...wireBlocks ? { blocks: JSON.stringify(wireBlocks) } : {}
|
|
18409
18838
|
});
|
|
18410
18839
|
const slackChannelId = requiredSlackString(updated.channel, "channel");
|
|
18411
18840
|
const slackMessageTimestamp = requiredSlackString(updated.ts, "ts");
|
|
@@ -19713,6 +20142,20 @@ function nextSlackFilesListPage(payload, requested, returnedFileCount) {
|
|
|
19713
20142
|
}
|
|
19714
20143
|
return nextPage;
|
|
19715
20144
|
}
|
|
20145
|
+
function slackMessageWireBlocks(blocks) {
|
|
20146
|
+
if (!blocks) return void 0;
|
|
20147
|
+
const wire = blocks.flatMap((block, index) => {
|
|
20148
|
+
if (block.type !== "actions" || new Set(block.elements.map((e) => e.action_id)).size === block.elements.length)
|
|
20149
|
+
return [block];
|
|
20150
|
+
const id = createHash7("sha256").update(`${index}:${block.block_id}`).digest("hex").slice(0, 24);
|
|
20151
|
+
return block.elements.map((element, position2) => ({
|
|
20152
|
+
type: "actions",
|
|
20153
|
+
block_id: `opengeni_wire_${id}_${position2}`,
|
|
20154
|
+
elements: [element]
|
|
20155
|
+
}));
|
|
20156
|
+
});
|
|
20157
|
+
return validateSlackMessageBlocks(wire);
|
|
20158
|
+
}
|
|
19716
20159
|
function validateSlackMessageBlocks(blocks) {
|
|
19717
20160
|
if (blocks === void 0) return void 0;
|
|
19718
20161
|
if (blocks.length < 1 || blocks.length > MAX_SLACK_BLOCKS) {
|
|
@@ -19778,7 +20221,7 @@ function slackMutationOutcomeMayBeAmbiguous(error) {
|
|
|
19778
20221
|
|
|
19779
20222
|
// src/integrations/fiken.ts
|
|
19780
20223
|
import { withOrganizationIntegrationAcquisition as withOrganizationIntegrationAcquisition3 } from "@opengeni/db/organization-integration-policy";
|
|
19781
|
-
import { createHash as
|
|
20224
|
+
import { createHash as createHash8 } from "crypto";
|
|
19782
20225
|
import { ExternalActorContinuation as ExternalActorContinuation3 } from "@opengeni/contracts/external-identities";
|
|
19783
20226
|
import { requireConnectOwnerAuthority as requireConnectOwnerAuthority2 } from "@opengeni/core";
|
|
19784
20227
|
import {
|
|
@@ -20599,7 +21042,7 @@ async function completeFikenOAuthCallback(deps, input) {
|
|
|
20599
21042
|
operation = {
|
|
20600
21043
|
attemptId: state.connectAttemptId,
|
|
20601
21044
|
operationId: `oauth:${state.nonce}`,
|
|
20602
|
-
inputDigest:
|
|
21045
|
+
inputDigest: createHash8("sha256").update(input.state).digest("hex")
|
|
20603
21046
|
};
|
|
20604
21047
|
const claim = await claimOAuthAcquisition(
|
|
20605
21048
|
deps.db,
|
|
@@ -20906,7 +21349,7 @@ import {
|
|
|
20906
21349
|
knowledgeSourceAgentConfig,
|
|
20907
21350
|
assertOrganizationIntegrationAllowed as assertOrganizationIntegrationAllowed2
|
|
20908
21351
|
} from "@opengeni/contracts";
|
|
20909
|
-
import { createHash as
|
|
21352
|
+
import { createHash as createHash9 } from "crypto";
|
|
20910
21353
|
import { ExternalActorContinuation as ExternalActorContinuation4 } from "@opengeni/contracts/external-identities";
|
|
20911
21354
|
import {
|
|
20912
21355
|
ATLASSIAN_CREDENTIAL_LABEL,
|
|
@@ -21032,7 +21475,7 @@ async function completeAtlassianOAuthCallback(deps, input) {
|
|
|
21032
21475
|
operation = {
|
|
21033
21476
|
attemptId: state.connectAttemptId,
|
|
21034
21477
|
operationId: `oauth:${state.nonce}`,
|
|
21035
|
-
inputDigest:
|
|
21478
|
+
inputDigest: createHash9("sha256").update(input.state).digest("hex")
|
|
21036
21479
|
};
|
|
21037
21480
|
const claim = await claimOAuthAcquisition(
|
|
21038
21481
|
deps.db,
|
|
@@ -22466,7 +22909,7 @@ function adfText(value) {
|
|
|
22466
22909
|
import { AtlassianConnectionMetadata as AtlassianConnectionMetadata2 } from "@opengeni/contracts/atlassian";
|
|
22467
22910
|
|
|
22468
22911
|
// src/mcp/editable-artifacts.ts
|
|
22469
|
-
import { createHash as
|
|
22912
|
+
import { createHash as createHash10 } from "crypto";
|
|
22470
22913
|
import {
|
|
22471
22914
|
editableArtifactClientTransactionId as editableArtifactClientTransactionId2,
|
|
22472
22915
|
editableArtifactId as editableArtifactId2
|
|
@@ -22889,7 +23332,7 @@ function registerEditableArtifactAgentTools(input) {
|
|
|
22889
23332
|
}
|
|
22890
23333
|
function artifactAttemptContext(grant, sessionId, toolName, extra) {
|
|
22891
23334
|
const operationId = trustedOperationId(extra);
|
|
22892
|
-
const digest2 =
|
|
23335
|
+
const digest2 = createHash10("sha256").update("opengeni:editable-artifact-agent-call:v1\0", "utf8").update(grant.accountId, "utf8").update("\0", "utf8").update(grant.workspaceId, "utf8").update("\0", "utf8").update(sessionId, "utf8").update("\0", "utf8").update(String(grant.metadata?.["turnId"] ?? ""), "utf8").update("\0", "utf8").update(String(grant.metadata?.["attemptId"] ?? ""), "utf8").update("\0", "utf8").update(String(grant.metadata?.["executionGeneration"] ?? ""), "utf8").update("\0", "utf8").update(toolName, "utf8").update("\0", "utf8").update(operationId, "utf8").digest("hex");
|
|
22893
23336
|
const replicaId = digest2.slice(0, 16) === "0".repeat(16) ? `1${digest2.slice(1, 16)}` : digest2.slice(0, 16);
|
|
22894
23337
|
const actor = editableArtifactActorForGrant(grant, replicaId);
|
|
22895
23338
|
if (actor.kind !== "agent" || actor.sessionId !== sessionId) {
|
|
@@ -23095,7 +23538,7 @@ import {
|
|
|
23095
23538
|
knowledgeSourceAgentConfig as knowledgeSourceAgentConfig2,
|
|
23096
23539
|
assertOrganizationIntegrationAllowed as assertOrganizationIntegrationAllowed3
|
|
23097
23540
|
} from "@opengeni/contracts";
|
|
23098
|
-
import { createHash as
|
|
23541
|
+
import { createHash as createHash11, randomBytes as randomBytes6 } from "crypto";
|
|
23099
23542
|
import { ExternalActorContinuation as ExternalActorContinuation5 } from "@opengeni/contracts/external-identities";
|
|
23100
23543
|
import {
|
|
23101
23544
|
configuredGoogleDriveSyncLimits,
|
|
@@ -23216,7 +23659,7 @@ async function startGoogleDriveOAuth(deps, input) {
|
|
|
23216
23659
|
requireGoogleDriveConnection(existing, input.subjectId);
|
|
23217
23660
|
}
|
|
23218
23661
|
const key = requireEnvironmentEncryption5(deps.settings);
|
|
23219
|
-
const verifier =
|
|
23662
|
+
const verifier = randomBytes6(48).toString("base64url");
|
|
23220
23663
|
const redirectUri = requireGoogleDriveOAuthCallbackUrl(deps.settings);
|
|
23221
23664
|
const state = createSignedState7(requireIntegrationsStateSecret(deps.settings), {
|
|
23222
23665
|
accountId: input.accountId,
|
|
@@ -23262,7 +23705,7 @@ async function startGoogleDriveOAuth(deps, input) {
|
|
|
23262
23705
|
authorizationUrl.searchParams.set("code_challenge_method", "S256");
|
|
23263
23706
|
authorizationUrl.searchParams.set(
|
|
23264
23707
|
"code_challenge",
|
|
23265
|
-
|
|
23708
|
+
createHash11("sha256").update(verifier).digest("base64url")
|
|
23266
23709
|
);
|
|
23267
23710
|
return GoogleDriveOAuthStartResponse.parse({
|
|
23268
23711
|
authorizationUrl: authorizationUrl.toString(),
|
|
@@ -23286,7 +23729,7 @@ async function completeGoogleDriveOAuthCallback(deps, input) {
|
|
|
23286
23729
|
operation = {
|
|
23287
23730
|
attemptId: state.connectAttemptId,
|
|
23288
23731
|
operationId: `oauth:${state.nonce}`,
|
|
23289
|
-
inputDigest:
|
|
23732
|
+
inputDigest: createHash11("sha256").update(input.state).digest("hex")
|
|
23290
23733
|
};
|
|
23291
23734
|
const claim = await claimOAuthAcquisition(
|
|
23292
23735
|
deps.db,
|
|
@@ -25206,7 +25649,7 @@ function uniqueStrings3(values) {
|
|
|
25206
25649
|
}
|
|
25207
25650
|
|
|
25208
25651
|
// src/temporal-schedule-cleanup.ts
|
|
25209
|
-
import { randomUUID } from "crypto";
|
|
25652
|
+
import { randomUUID as randomUUID2 } from "crypto";
|
|
25210
25653
|
import {
|
|
25211
25654
|
claimTemporalScheduleCleanups,
|
|
25212
25655
|
completeTemporalScheduleConnectorCleanup,
|
|
@@ -25278,7 +25721,7 @@ async function processTemporalScheduleCleanupClaims(deps, claims) {
|
|
|
25278
25721
|
}
|
|
25279
25722
|
async function drainTemporalScheduleCleanupOutbox(deps) {
|
|
25280
25723
|
const claims = await claimTemporalScheduleCleanups(deps.db, {
|
|
25281
|
-
claimId:
|
|
25724
|
+
claimId: randomUUID2(),
|
|
25282
25725
|
limit: CLEANUP_BATCH_SIZE,
|
|
25283
25726
|
claimSeconds: CLEANUP_CLAIM_SECONDS
|
|
25284
25727
|
});
|
|
@@ -26627,7 +27070,7 @@ function registerSandboxFileArtifactTool(server, deps, grant, sessionId, json) {
|
|
|
26627
27070
|
server.registerTool(
|
|
26628
27071
|
"sandbox_file_publish",
|
|
26629
27072
|
{
|
|
26630
|
-
description: "Publish one exact file from this session's /workspace into durable workspace storage. Use this before presenting a ZIP, CSV, JSON, Markdown, HTML, PDF, Office file, or other sandbox output as downloadable.
|
|
27073
|
+
description: "Publish one exact file from this session's /workspace into durable workspace storage. Use this before presenting a video, ZIP, CSV, JSON, Markdown, HTML, PDF, Office file, or other sandbox output as downloadable. Present the returned artifact.artifactId as [Open file](artifact:<artifactId>), or  for inline image/video/audio/PDF previews. Replace <artifactId> with the exact returned ID and use a descriptive label. Never expose a sandbox: URL as the durable result.",
|
|
26631
27074
|
inputSchema: {
|
|
26632
27075
|
path: z43.string().min(1).max(4096)
|
|
26633
27076
|
}
|
|
@@ -27369,7 +27812,7 @@ function registerGoalTools(server, deps, grant, sessionId, json) {
|
|
|
27369
27812
|
async ({ reason, timeoutSeconds, idempotencyKey }) => {
|
|
27370
27813
|
await authorizeFirstPartySession(deps, grant, sessionId, "session.control");
|
|
27371
27814
|
const context = exactAgentCommandContext(grant, sessionId);
|
|
27372
|
-
const operationKey = idempotencyKey ?? `wait-for-input:${context.callerTurnId}:${
|
|
27815
|
+
const operationKey = idempotencyKey ?? `wait-for-input:${context.callerTurnId}:${createHash12("sha256").update(JSON.stringify({ reason, timeoutSeconds })).digest("hex").slice(0, 32)}`;
|
|
27373
27816
|
const { events, operationId, replay, deadlineAt } = await waitForSessionInputWithEvent(
|
|
27374
27817
|
deps.db,
|
|
27375
27818
|
grant.workspaceId,
|
|
@@ -27610,7 +28053,7 @@ function registerWorkspaceArtifactTools(server, deps, grant, sessionId, json) {
|
|
|
27610
28053
|
return {
|
|
27611
28054
|
accountId: grant.accountId,
|
|
27612
28055
|
workspaceId: grant.workspaceId,
|
|
27613
|
-
operationKey: `attempt:${
|
|
28056
|
+
operationKey: `attempt:${createHash12("sha256").update(`${claims.sessionId}:${claims.turnId}:${idempotencyKey}`).digest("hex")}`,
|
|
27614
28057
|
actorSubjectId: grant.subjectId,
|
|
27615
28058
|
sourceSessionId: claims.sessionId,
|
|
27616
28059
|
sourceTurnId: claims.turnId,
|
|
@@ -28300,7 +28743,7 @@ function registerFleetTools(server, deps, grant, sessionId, json) {
|
|
|
28300
28743
|
server.registerTool(
|
|
28301
28744
|
"sandbox_provision",
|
|
28302
28745
|
{
|
|
28303
|
-
description: "Provision a new sandbox for the fleet. kind=selfhosted returns device-flow
|
|
28746
|
+
description: "Provision a new sandbox for the fleet. kind=selfhosted returns interactive device-flow instructions for a human to approve. For authorized headless enrollment, use connected_machine_enroll_token when available instead. kind=modal creates a named Modal sandbox record, but it is NOT yet attachable as a swap target: routing a session onto a second Modal box is not supported yet, so sandbox_swap to its id is rejected. Use the session's own box (the default) or attach a Connected Machine instead.",
|
|
28304
28747
|
inputSchema: {
|
|
28305
28748
|
kind: z43.enum(["selfhosted", "modal"]),
|
|
28306
28749
|
name: z43.string().min(1).max(120).optional()
|
|
@@ -28315,10 +28758,38 @@ function registerFleetTools(server, deps, grant, sessionId, json) {
|
|
|
28315
28758
|
);
|
|
28316
28759
|
}
|
|
28317
28760
|
function registerConnectedMachineTools(server, deps, grant, sessionId, json) {
|
|
28761
|
+
server.registerTool(
|
|
28762
|
+
"connected_machine_enroll_token",
|
|
28763
|
+
{
|
|
28764
|
+
description: "Create a short-lived Connected Machine enrollment token for this workspace using existing enrollments:manage authority. Returns the token, expiry and Unix/PowerShell install commands. Run the appropriate command on the intended machine through an already-authorized execution path, then verify it with sandboxes_list. No separate device approval is required. Screen control is optional and defaults off. The token grants whole-machine access on enrollment; do not put it in public code or unrelated logs. Existing machine connections are preserved.",
|
|
28765
|
+
inputSchema: { allowScreenControl: z43.boolean().optional() }
|
|
28766
|
+
},
|
|
28767
|
+
async ({ allowScreenControl }) => {
|
|
28768
|
+
if (sessionId) {
|
|
28769
|
+
await authorizeFirstPartySession(deps, grant, sessionId, "session.first_party_mcp.call");
|
|
28770
|
+
}
|
|
28771
|
+
const minted = await mintEnrollToken(deps, {
|
|
28772
|
+
accountId: grant.accountId,
|
|
28773
|
+
workspaceId: grant.workspaceId,
|
|
28774
|
+
allowScreenControl: allowScreenControl ?? false
|
|
28775
|
+
});
|
|
28776
|
+
if (!minted) throw new Error("enrollment credential plane is not configured");
|
|
28777
|
+
const base = (deps.settings.publicBaseUrl ?? "https://app.opengeni.ai").replace(/\/+$/, "");
|
|
28778
|
+
const unixQuote = (value) => `'${value.replaceAll("'", "'\\''")}'`;
|
|
28779
|
+
const windowsQuote = (value) => `'${value.replaceAll("'", "''")}'`;
|
|
28780
|
+
return json({
|
|
28781
|
+
...minted,
|
|
28782
|
+
workspaceId: grant.workspaceId,
|
|
28783
|
+
allowScreenControl: allowScreenControl ?? false,
|
|
28784
|
+
installCommandUnix: `curl -fsSL ${unixQuote(`${base}/install.sh`)} | OPENGENI_API_URL=${unixQuote(base)} OPENGENI_ENROLL_TOKEN=${unixQuote(minted.token)} sh`,
|
|
28785
|
+
installCommandWindows: `$env:OPENGENI_API_URL=${windowsQuote(base)}; $env:OPENGENI_ENROLL_TOKEN=${windowsQuote(minted.token)}; irm ${windowsQuote(`${base}/install.ps1`)} | iex`
|
|
28786
|
+
});
|
|
28787
|
+
}
|
|
28788
|
+
);
|
|
28318
28789
|
server.registerTool(
|
|
28319
28790
|
"connected_machine_remove",
|
|
28320
28791
|
{
|
|
28321
|
-
description: "Remove one enrolled self-hosted machine while it is offline. Access is revoked, future heartbeat/reconnect credentials are rejected, and session, route, lease, archive, and audit history is retained. Idle dependent sessions are detached atomically; machine-home sessions become compute-less (backend none) until another sandbox is selected. Active turns, live leases, and recovery work remain fail-closed blockers whose typed outcome explains what must settle before retrying. Pass the enrollmentId from the Machines surface, never a Modal sandbox id. Reconnecting later requires
|
|
28792
|
+
description: "Remove one enrolled self-hosted machine while it is offline. Access is revoked, future heartbeat/reconnect credentials are rejected, and session, route, lease, archive, and audit history is retained. Idle dependent sessions are detached atomically; machine-home sessions become compute-less (backend none) until another sandbox is selected. Active turns, live leases, and recovery work remain fail-closed blockers whose typed outcome explains what must settle before retrying. Pass the enrollmentId from the Machines surface, never a Modal sandbox id. Reconnecting later requires fresh enrollment through device approval or an authorized enrollment token.",
|
|
28322
28793
|
inputSchema: {
|
|
28323
28794
|
enrollmentId: z43.string().uuid(),
|
|
28324
28795
|
expectedUpdatedAt: z43.string().datetime({ offset: true }).optional(),
|
|
@@ -28343,7 +28814,7 @@ function registerConnectedMachineTools(server, deps, grant, sessionId, json) {
|
|
|
28343
28814
|
accountId: grant.accountId,
|
|
28344
28815
|
workspaceId: enrollment.workspaceId,
|
|
28345
28816
|
enrollmentId,
|
|
28346
|
-
operationKey: idempotencyKey?.trim() ||
|
|
28817
|
+
operationKey: idempotencyKey?.trim() || randomUUID3(),
|
|
28347
28818
|
...expectedUpdatedAt ? { expectedUpdatedAt } : {},
|
|
28348
28819
|
subjectId: resourceGrant.subjectId
|
|
28349
28820
|
});
|
|
@@ -28671,6 +29142,18 @@ function exactAgentCommandContext(grant, callerSessionId, authorizationSurface)
|
|
|
28671
29142
|
};
|
|
28672
29143
|
}
|
|
28673
29144
|
function registerWorkspaceOrchestrationTools(server, deps, grant, can, callerSessionId, sessionCreateVisible, json) {
|
|
29145
|
+
const acknowledgeReads = async (children) => {
|
|
29146
|
+
if (!callerSessionId || !exactAgentAttemptClaims(grant) || !children.some((child) => child.sequences.length > 0))
|
|
29147
|
+
return;
|
|
29148
|
+
const actor = await requireLiveAgentAttemptAuthorization4(deps.db, grant, callerSessionId);
|
|
29149
|
+
if (!actor.initiatingHumanSubjectId) return;
|
|
29150
|
+
await acknowledgeConsumedChildEvents(deps.db, {
|
|
29151
|
+
workspaceId: grant.workspaceId,
|
|
29152
|
+
sessionId: callerSessionId,
|
|
29153
|
+
subjectId: actor.initiatingHumanSubjectId,
|
|
29154
|
+
children
|
|
29155
|
+
});
|
|
29156
|
+
};
|
|
28674
29157
|
if (can("sessions:read")) {
|
|
28675
29158
|
server.registerTool(
|
|
28676
29159
|
"sessions_list",
|
|
@@ -28965,29 +29448,29 @@ function registerWorkspaceOrchestrationTools(server, deps, grant, can, callerSes
|
|
|
28965
29448
|
if (view !== "debug" && !auditRequested) {
|
|
28966
29449
|
const { readSessionEventView } = await import("./session-event-view-MU3HMNV3.js");
|
|
28967
29450
|
const { listSessionEventSlices } = await import("@opengeni/db/session-event-slices");
|
|
28968
|
-
|
|
28969
|
-
|
|
28970
|
-
|
|
28971
|
-
|
|
28972
|
-
|
|
28973
|
-
|
|
28974
|
-
|
|
28975
|
-
|
|
28976
|
-
|
|
28977
|
-
|
|
28978
|
-
|
|
28979
|
-
|
|
28980
|
-
|
|
28981
|
-
|
|
28982
|
-
|
|
28983
|
-
|
|
28984
|
-
|
|
28985
|
-
|
|
28986
|
-
|
|
28987
|
-
(legacyOptions) => listSessionEventPage(deps.db, grant.workspaceId, sessionId, legacyOptions)
|
|
28988
|
-
)
|
|
29451
|
+
const page2 = await readSessionEventView(
|
|
29452
|
+
{
|
|
29453
|
+
sessionId,
|
|
29454
|
+
view,
|
|
29455
|
+
cursor,
|
|
29456
|
+
callId,
|
|
29457
|
+
includeArguments,
|
|
29458
|
+
includeOutput,
|
|
29459
|
+
after,
|
|
29460
|
+
before,
|
|
29461
|
+
direction: requestedDirection,
|
|
29462
|
+
limit
|
|
29463
|
+
},
|
|
29464
|
+
(options) => listSessionEventSlices(
|
|
29465
|
+
deps.db,
|
|
29466
|
+
grant.workspaceId,
|
|
29467
|
+
sessionId,
|
|
29468
|
+
options,
|
|
29469
|
+
(legacyOptions) => listSessionEventPage(deps.db, grant.workspaceId, sessionId, legacyOptions)
|
|
28989
29470
|
)
|
|
28990
29471
|
);
|
|
29472
|
+
await acknowledgeReads([{ sessionId, sequences: completeChildReadSequences(page2) }]);
|
|
29473
|
+
return json(page2);
|
|
28991
29474
|
}
|
|
28992
29475
|
if (cursor !== void 0 || callId !== void 0 || includeArguments !== void 0 || includeOutput !== void 0) {
|
|
28993
29476
|
throw new Error("cursor/callId/includeArguments/includeOutput require a non-debug view");
|
|
@@ -29017,31 +29500,37 @@ function registerWorkspaceOrchestrationTools(server, deps, grant, can, callerSes
|
|
|
29017
29500
|
});
|
|
29018
29501
|
if (requestedResultMode === "compact") {
|
|
29019
29502
|
const event = dbPage.events[0];
|
|
29020
|
-
|
|
29021
|
-
|
|
29022
|
-
|
|
29023
|
-
|
|
29024
|
-
|
|
29025
|
-
|
|
29026
|
-
|
|
29027
|
-
|
|
29028
|
-
|
|
29029
|
-
|
|
29030
|
-
|
|
29031
|
-
|
|
29503
|
+
const result = event ? boundSessionEventCompactResult(
|
|
29504
|
+
compactSessionEventResult2(
|
|
29505
|
+
event,
|
|
29506
|
+
latestClass,
|
|
29507
|
+
dbPage.coveredSequence ?? {
|
|
29508
|
+
first: event.sequence,
|
|
29509
|
+
last: event.sequence
|
|
29510
|
+
}
|
|
29511
|
+
)
|
|
29512
|
+
) : null;
|
|
29513
|
+
if (result && ["turn.completed", "agent.message.completed"].includes(result.type) && !result.truncation.truncated && dbPage.fullPayloadsExact) {
|
|
29514
|
+
await acknowledgeReads([{ sessionId, sequences: [result.sequence] }]);
|
|
29515
|
+
}
|
|
29516
|
+
return json(result);
|
|
29032
29517
|
}
|
|
29033
|
-
|
|
29034
|
-
|
|
29035
|
-
|
|
29036
|
-
|
|
29037
|
-
|
|
29038
|
-
|
|
29039
|
-
|
|
29040
|
-
|
|
29041
|
-
|
|
29042
|
-
|
|
29043
|
-
|
|
29044
|
-
|
|
29518
|
+
const page = boundSessionEventMcpPage({
|
|
29519
|
+
events: dbPage.events,
|
|
29520
|
+
mode,
|
|
29521
|
+
payloadMode,
|
|
29522
|
+
direction,
|
|
29523
|
+
sourceHasMore: dbPage.hasMore,
|
|
29524
|
+
sourceTruncatedBy: dbPage.truncatedBy,
|
|
29525
|
+
after: after ?? 0,
|
|
29526
|
+
before: before ?? null
|
|
29527
|
+
});
|
|
29528
|
+
if (payloadMode === "full" && dbPage.fullPayloadsExact && !page.truncation?.reasons.includes("model_payload")) {
|
|
29529
|
+
await acknowledgeReads([
|
|
29530
|
+
{ sessionId, sequences: page.events.map((event) => event.sequence) }
|
|
29531
|
+
]);
|
|
29532
|
+
}
|
|
29533
|
+
return json(page);
|
|
29045
29534
|
}
|
|
29046
29535
|
);
|
|
29047
29536
|
server.registerTool(
|
|
@@ -29077,45 +29566,52 @@ function registerWorkspaceOrchestrationTools(server, deps, grant, can, callerSes
|
|
|
29077
29566
|
const targetEventTypes = waitFor === "completion" ? SESSION_WAIT_COMPLETION_EVENT_TYPES : SESSION_WAIT_EVENT_TYPES;
|
|
29078
29567
|
const signal = extra?.signal;
|
|
29079
29568
|
const workspaceId = grant.workspaceId;
|
|
29080
|
-
|
|
29081
|
-
|
|
29082
|
-
|
|
29083
|
-
|
|
29084
|
-
|
|
29085
|
-
|
|
29086
|
-
|
|
29087
|
-
|
|
29088
|
-
|
|
29089
|
-
|
|
29090
|
-
|
|
29091
|
-
|
|
29092
|
-
|
|
29093
|
-
|
|
29094
|
-
|
|
29095
|
-
|
|
29096
|
-
|
|
29097
|
-
|
|
29098
|
-
|
|
29099
|
-
|
|
29100
|
-
|
|
29101
|
-
|
|
29102
|
-
|
|
29103
|
-
|
|
29104
|
-
|
|
29105
|
-
|
|
29106
|
-
|
|
29107
|
-
|
|
29108
|
-
|
|
29109
|
-
|
|
29110
|
-
|
|
29111
|
-
|
|
29112
|
-
|
|
29113
|
-
|
|
29114
|
-
|
|
29115
|
-
|
|
29116
|
-
|
|
29117
|
-
|
|
29118
|
-
|
|
29569
|
+
const incompleteWaitEvents = /* @__PURE__ */ new Set();
|
|
29570
|
+
const result = await waitForSessionChanges({
|
|
29571
|
+
targets,
|
|
29572
|
+
ownSessionId,
|
|
29573
|
+
maxWaitMs: (maxWaitSeconds ?? SESSION_WAIT_DEFAULT_SECONDS) * 1e3,
|
|
29574
|
+
targetEventTypes,
|
|
29575
|
+
targetEventMatches: waitFor === "completion" ? sessionWaitCompletionEventMatches : void 0,
|
|
29576
|
+
signal,
|
|
29577
|
+
source: {
|
|
29578
|
+
reauthorizeTargets: async (sessionIds) => {
|
|
29579
|
+
for (const targetSessionId of sessionIds) {
|
|
29580
|
+
await authorizeFirstPartySession(
|
|
29581
|
+
deps,
|
|
29582
|
+
grant,
|
|
29583
|
+
targetSessionId,
|
|
29584
|
+
"session.events.read"
|
|
29585
|
+
);
|
|
29586
|
+
}
|
|
29587
|
+
},
|
|
29588
|
+
readTargetEvents: async (target) => {
|
|
29589
|
+
const page = await listSessionEventPage(deps.db, workspaceId, target.sessionId, {
|
|
29590
|
+
after: target.afterSequence,
|
|
29591
|
+
direction: "after",
|
|
29592
|
+
limit: SESSION_WAIT_EVENTS_PER_TARGET,
|
|
29593
|
+
payloadMode: "full",
|
|
29594
|
+
includeTypes: targetEventTypes,
|
|
29595
|
+
maxBytes: SESSION_EVENT_MCP_MAX_BYTES * 4
|
|
29596
|
+
});
|
|
29597
|
+
if (!page.fullPayloadsExact) {
|
|
29598
|
+
for (const event of page.events) incompleteWaitEvents.add(event.id);
|
|
29599
|
+
}
|
|
29600
|
+
return { events: page.events, hasMore: page.hasMore };
|
|
29601
|
+
},
|
|
29602
|
+
readOwnPendingUpdateKinds: ownSessionId === null ? null : async () => (await listOutstandingSessionSystemUpdates(deps.db, workspaceId, ownSessionId)).map((update) => update.kind),
|
|
29603
|
+
subscribe: (targetSessionId, onEvents) => deps.bus.subscribe(workspaceId, targetSessionId, onEvents)
|
|
29604
|
+
}
|
|
29605
|
+
});
|
|
29606
|
+
if (!result.aborted && !result.truncated) {
|
|
29607
|
+
await acknowledgeReads(
|
|
29608
|
+
result.changed.map((target) => ({
|
|
29609
|
+
sessionId: target.sessionId,
|
|
29610
|
+
sequences: target.events.filter((event) => event.contentComplete && !incompleteWaitEvents.has(event.id)).map((event) => event.sequence)
|
|
29611
|
+
}))
|
|
29612
|
+
);
|
|
29613
|
+
}
|
|
29614
|
+
return json(result);
|
|
29119
29615
|
}
|
|
29120
29616
|
);
|
|
29121
29617
|
if (callerSessionId !== null) {
|
|
@@ -29985,9 +30481,12 @@ function registerCapabilityDiscoveryTools(server, deps, grant, sessionId, json)
|
|
|
29985
30481
|
};
|
|
29986
30482
|
const setupProjections = async (items) => {
|
|
29987
30483
|
const availableServerIds = /* @__PURE__ */ new Set();
|
|
30484
|
+
const availableFirstPartyTools = /* @__PURE__ */ new Set();
|
|
29988
30485
|
const acceptedServerIds = /* @__PURE__ */ new Set();
|
|
29989
30486
|
let accountSelectionKnown = false;
|
|
29990
|
-
if (items.some(
|
|
30487
|
+
if (items.some(
|
|
30488
|
+
(item) => item.enabled && (item.connectionRef || item.surfaceType === "first_party_fiken")
|
|
30489
|
+
)) {
|
|
29991
30490
|
const claims = exactAgentCommandContext(grant, sessionId);
|
|
29992
30491
|
const attemptCatalog = await getAttemptToolCatalog2(deps.db, {
|
|
29993
30492
|
accountId: grant.accountId,
|
|
@@ -29995,7 +30494,11 @@ function registerCapabilityDiscoveryTools(server, deps, grant, sessionId, json)
|
|
|
29995
30494
|
attemptId: claims.callerAttemptId
|
|
29996
30495
|
});
|
|
29997
30496
|
if (attemptCatalog?.sessionId === sessionId && attemptCatalog.turnId === claims.callerTurnId && attemptCatalog.executionGeneration === claims.callerExecutionGeneration) {
|
|
29998
|
-
for (const entry2 of attemptCatalog.entries)
|
|
30497
|
+
for (const entry2 of attemptCatalog.entries) {
|
|
30498
|
+
availableServerIds.add(entry2.identity.serverId);
|
|
30499
|
+
if (entry2.identity.serverId === "opengeni")
|
|
30500
|
+
availableFirstPartyTools.add(entry2.identity.toolName);
|
|
30501
|
+
}
|
|
29999
30502
|
const bindings = await getSessionTurnMcpAccountBindings(
|
|
30000
30503
|
deps.db,
|
|
30001
30504
|
grant.workspaceId,
|
|
@@ -30016,7 +30519,9 @@ function registerCapabilityDiscoveryTools(server, deps, grant, sessionId, json)
|
|
|
30016
30519
|
item,
|
|
30017
30520
|
availableServerIds,
|
|
30018
30521
|
acceptedServerIds,
|
|
30019
|
-
accountSelectionKnown
|
|
30522
|
+
accountSelectionKnown,
|
|
30523
|
+
availableFirstPartyTools,
|
|
30524
|
+
new Set(grant.metadata?.firstPartyMcpTools ?? [])
|
|
30020
30525
|
)
|
|
30021
30526
|
)
|
|
30022
30527
|
);
|
|
@@ -30135,7 +30640,38 @@ function registerCapabilityDiscoveryTools(server, deps, grant, sessionId, json)
|
|
|
30135
30640
|
}
|
|
30136
30641
|
);
|
|
30137
30642
|
}
|
|
30138
|
-
async function capabilitySetupProjection(deps, workspaceId, item, availableServerIds, acceptedServerIds, accountSelectionKnown) {
|
|
30643
|
+
async function capabilitySetupProjection(deps, workspaceId, item, availableServerIds, acceptedServerIds, accountSelectionKnown, availableFirstPartyTools, selectedFirstPartyTools) {
|
|
30644
|
+
if (item.surfaceType === "first_party_fiken") {
|
|
30645
|
+
if (!item.enabled || item.metadata.connectionStatus !== "active") {
|
|
30646
|
+
return {
|
|
30647
|
+
status: "authorization_required",
|
|
30648
|
+
action: "connect",
|
|
30649
|
+
detail: item.metadata.connectionStatus === "needs_reauth" ? "The workspace Fiken connection needs reconnection." : "Connect Fiken through the protected setup form."
|
|
30650
|
+
};
|
|
30651
|
+
}
|
|
30652
|
+
const selected = FIRST_PARTY_MCP_TOOL_NAMES2.filter(
|
|
30653
|
+
(name) => name.startsWith("fiken_") && selectedFirstPartyTools.has(name)
|
|
30654
|
+
);
|
|
30655
|
+
if (selected.length === 0) {
|
|
30656
|
+
return {
|
|
30657
|
+
status: "authorization_required",
|
|
30658
|
+
action: "enable",
|
|
30659
|
+
detail: "Fiken is connected, but its tools are not selected for this conversation. Ask the user to add its tools through the setup card, then send a new message."
|
|
30660
|
+
};
|
|
30661
|
+
}
|
|
30662
|
+
if (selected.some((name) => availableFirstPartyTools.has(name))) {
|
|
30663
|
+
return {
|
|
30664
|
+
status: "ready",
|
|
30665
|
+
action: null,
|
|
30666
|
+
detail: "Fiken is connected and has tools available in this turn."
|
|
30667
|
+
};
|
|
30668
|
+
}
|
|
30669
|
+
return {
|
|
30670
|
+
status: "unavailable",
|
|
30671
|
+
action: null,
|
|
30672
|
+
detail: "Fiken is connected, but its selected tools are unavailable in this execution. Check tool permissions and setup before retrying; reconnection is not required by this status."
|
|
30673
|
+
};
|
|
30674
|
+
}
|
|
30139
30675
|
if (item.id === "api:github-app" || item.surfaceType === "first_party_github") {
|
|
30140
30676
|
const missing = githubAppMissingSettings(deps.settings);
|
|
30141
30677
|
if (missing.length > 0) {
|
|
@@ -60552,7 +61088,7 @@ function registerOrganizationIntegrationPolicyRoutes(app, deps) {
|
|
|
60552
61088
|
}
|
|
60553
61089
|
|
|
60554
61090
|
// src/routes/connections.ts
|
|
60555
|
-
import { createHash as
|
|
61091
|
+
import { createHash as createHash15, createHmac as createHmac4 } from "crypto";
|
|
60556
61092
|
import {
|
|
60557
61093
|
createConnectionIdempotently,
|
|
60558
61094
|
getConnectionCreationResult,
|
|
@@ -60721,7 +61257,7 @@ import { HTTPException as HTTPException35 } from "hono/http-exception";
|
|
|
60721
61257
|
// src/integrations/provider-oauth.ts
|
|
60722
61258
|
import { withOrganizationIntegrationAcquisition as withOrganizationIntegrationAcquisition6 } from "@opengeni/db/organization-integration-policy";
|
|
60723
61259
|
import { Buffer as Buffer4 } from "buffer";
|
|
60724
|
-
import { createHash as
|
|
61260
|
+
import { createHash as createHash13, randomBytes as randomBytes7 } from "crypto";
|
|
60725
61261
|
import {
|
|
60726
61262
|
integrationDefinitionProviderDomain as integrationDefinitionProviderDomain2,
|
|
60727
61263
|
integrationDefinitionById
|
|
@@ -60804,7 +61340,7 @@ async function startApiIntegrationProviderOAuth(deps, input) {
|
|
|
60804
61340
|
...definition.authentication.scopes
|
|
60805
61341
|
]);
|
|
60806
61342
|
const client = providerClientForDefinition(deps.settings, definition);
|
|
60807
|
-
const verifier =
|
|
61343
|
+
const verifier = randomBytes7(48).toString("base64url");
|
|
60808
61344
|
const key = requireEnvironmentEncryption8(deps.settings);
|
|
60809
61345
|
const baseUrl = integrationBaseUrl(deps.settings.publicBaseUrl, input.requestUrl);
|
|
60810
61346
|
const redirectUri = `${baseUrl}${providerOAuthCallbackPath(definition)}`;
|
|
@@ -60849,7 +61385,7 @@ async function startApiIntegrationProviderOAuth(deps, input) {
|
|
|
60849
61385
|
authorizationUrl.searchParams.set("code_challenge_method", "S256");
|
|
60850
61386
|
authorizationUrl.searchParams.set(
|
|
60851
61387
|
"code_challenge",
|
|
60852
|
-
|
|
61388
|
+
createHash13("sha256").update(verifier).digest("base64url")
|
|
60853
61389
|
);
|
|
60854
61390
|
authorizationUrl.searchParams.set("prompt", "select_account");
|
|
60855
61391
|
if (definition.provider.id === "google") {
|
|
@@ -60879,7 +61415,7 @@ async function completeApiIntegrationProviderOAuth(deps, input) {
|
|
|
60879
61415
|
connectOperation = {
|
|
60880
61416
|
attemptId: state.connectAttemptId,
|
|
60881
61417
|
operationId: `oauth:${state.nonce}`,
|
|
60882
|
-
inputDigest:
|
|
61418
|
+
inputDigest: createHash13("sha256").update(input.state).digest("hex")
|
|
60883
61419
|
};
|
|
60884
61420
|
const claim = await claimOAuthAcquisition(
|
|
60885
61421
|
deps.db,
|
|
@@ -61172,7 +61708,7 @@ function providerClientKeys(definition) {
|
|
|
61172
61708
|
]);
|
|
61173
61709
|
}
|
|
61174
61710
|
function providerDefinitionFingerprint(definition) {
|
|
61175
|
-
return
|
|
61711
|
+
return createHash13("sha256").update(
|
|
61176
61712
|
JSON.stringify({
|
|
61177
61713
|
id: definition.id,
|
|
61178
61714
|
provider: definition.provider,
|
|
@@ -61425,7 +61961,7 @@ function numberValue4(value) {
|
|
|
61425
61961
|
|
|
61426
61962
|
// src/integrations/personal-github.ts
|
|
61427
61963
|
import { withOrganizationIntegrationAcquisition as withOrganizationIntegrationAcquisition7 } from "@opengeni/db/organization-integration-policy";
|
|
61428
|
-
import { createHash as
|
|
61964
|
+
import { createHash as createHash14, randomBytes as randomBytes8, randomUUID as randomUUID4 } from "crypto";
|
|
61429
61965
|
import { ExternalActorContinuation as ExternalActorContinuation8 } from "@opengeni/contracts/external-identities";
|
|
61430
61966
|
import { personalGitHubOAuthCallbackUrl } from "@opengeni/config";
|
|
61431
61967
|
import {
|
|
@@ -61472,7 +62008,7 @@ var PersonalGitHubCallbackError = class extends Error {
|
|
|
61472
62008
|
}
|
|
61473
62009
|
};
|
|
61474
62010
|
function personalGitHubClientMarker(clientId) {
|
|
61475
|
-
return
|
|
62011
|
+
return createHash14("sha256").update(clientId).digest("hex").slice(0, 32);
|
|
61476
62012
|
}
|
|
61477
62013
|
function requirePersonalGitHubOAuthSettings(settings) {
|
|
61478
62014
|
if (!settings.githubPersonalOauthEnabled) {
|
|
@@ -61555,7 +62091,7 @@ async function startPersonalGitHubOAuth(deps, input) {
|
|
|
61555
62091
|
});
|
|
61556
62092
|
}
|
|
61557
62093
|
const key = requireEnvironmentEncryption9(deps.settings);
|
|
61558
|
-
const verifier =
|
|
62094
|
+
const verifier = randomBytes8(48).toString("base64url");
|
|
61559
62095
|
const returnPath = personalGitHubReturnPath(input.workspaceId, input.returnPath);
|
|
61560
62096
|
const state = createSignedState11(requireIntegrationsStateSecret(deps.settings), {
|
|
61561
62097
|
accountId: grant.accountId,
|
|
@@ -61584,7 +62120,7 @@ async function startPersonalGitHubOAuth(deps, input) {
|
|
|
61584
62120
|
authorizationUrl.searchParams.set("state", state);
|
|
61585
62121
|
authorizationUrl.searchParams.set(
|
|
61586
62122
|
"code_challenge",
|
|
61587
|
-
|
|
62123
|
+
createHash14("sha256").update(verifier).digest("base64url")
|
|
61588
62124
|
);
|
|
61589
62125
|
authorizationUrl.searchParams.set("code_challenge_method", "S256");
|
|
61590
62126
|
return PersonalGitHubOAuthStartResponse.parse({
|
|
@@ -61608,7 +62144,7 @@ async function completePersonalGitHubOAuthCallback(deps, input) {
|
|
|
61608
62144
|
operation = {
|
|
61609
62145
|
attemptId: state.connectAttemptId,
|
|
61610
62146
|
operationId: `oauth:${state.nonce}`,
|
|
61611
|
-
inputDigest:
|
|
62147
|
+
inputDigest: createHash14("sha256").update(input.state).digest("hex")
|
|
61612
62148
|
};
|
|
61613
62149
|
const claim = await claimOAuthAcquisition(
|
|
61614
62150
|
deps.db,
|
|
@@ -61710,7 +62246,7 @@ async function completePersonalGitHubOAuthCallback(deps, input) {
|
|
|
61710
62246
|
githubLogin: identity2.login,
|
|
61711
62247
|
oauthEnvironment: oauth.oauthEnvironment,
|
|
61712
62248
|
oauthClientMarker: oauth.oauthClientMarker,
|
|
61713
|
-
credentialBindingId: requestedMetadata?.credentialBindingId ??
|
|
62249
|
+
credentialBindingId: requestedMetadata?.credentialBindingId ?? randomUUID4(),
|
|
61714
62250
|
connectedAt: requestedMetadata?.connectedAt ?? now,
|
|
61715
62251
|
lastVerifiedAt: now,
|
|
61716
62252
|
disconnectedAt: null,
|
|
@@ -62255,7 +62791,7 @@ function registerConnectionRoutes(app, deps) {
|
|
|
62255
62791
|
operation = {
|
|
62256
62792
|
attemptId: state.connectAttemptId,
|
|
62257
62793
|
operationId: `oauth:${state.nonce}`,
|
|
62258
|
-
inputDigest:
|
|
62794
|
+
inputDigest: createHash15("sha256").update(c.req.query("state")).digest("hex")
|
|
62259
62795
|
};
|
|
62260
62796
|
const callbackState = state;
|
|
62261
62797
|
const callbackOperation = operation;
|
|
@@ -62414,7 +62950,7 @@ function registerConnectionRoutes(app, deps) {
|
|
|
62414
62950
|
accountId: state.accountId,
|
|
62415
62951
|
workspaceId: state.workspaceId,
|
|
62416
62952
|
subjectId: state.subjectId,
|
|
62417
|
-
callbackDigest:
|
|
62953
|
+
callbackDigest: createHash15("sha256").update(state.nonce).digest("hex"),
|
|
62418
62954
|
installMode: state.connectionId ? "reinstall" : "connect",
|
|
62419
62955
|
...failure
|
|
62420
62956
|
});
|
|
@@ -63445,7 +63981,7 @@ function slackBotCredentialBundle(token) {
|
|
|
63445
63981
|
}
|
|
63446
63982
|
|
|
63447
63983
|
// src/routes/connect.ts
|
|
63448
|
-
import { createHash as
|
|
63984
|
+
import { createHash as createHash18, createHmac as createHmac5, randomUUID as randomUUID5 } from "crypto";
|
|
63449
63985
|
import { HTTPException as HTTPException39 } from "hono/http-exception";
|
|
63450
63986
|
import { getConnectBeginReplay } from "@opengeni/db/connect-attempts";
|
|
63451
63987
|
import {
|
|
@@ -63496,7 +64032,7 @@ import {
|
|
|
63496
64032
|
} from "@opengeni/core";
|
|
63497
64033
|
|
|
63498
64034
|
// src/integrations/github-app-connect.ts
|
|
63499
|
-
import { createHash as
|
|
64035
|
+
import { createHash as createHash16 } from "crypto";
|
|
63500
64036
|
import { z as z19 } from "zod";
|
|
63501
64037
|
import { HTTPException as HTTPException37 } from "hono/http-exception";
|
|
63502
64038
|
import {
|
|
@@ -63705,7 +64241,7 @@ async function completeGitHubAppConnect(deps, input) {
|
|
|
63705
64241
|
const operation = {
|
|
63706
64242
|
attemptId: state.connectAttemptId,
|
|
63707
64243
|
operationId: `github:${state.nonce}`,
|
|
63708
|
-
inputDigest:
|
|
64244
|
+
inputDigest: createHash16("sha256").update(input.state).digest("hex"),
|
|
63709
64245
|
authorize
|
|
63710
64246
|
};
|
|
63711
64247
|
const claim = await claimOAuthAcquisition(
|
|
@@ -63956,7 +64492,7 @@ import {
|
|
|
63956
64492
|
import { HTTPException as HTTPException38 } from "hono/http-exception";
|
|
63957
64493
|
|
|
63958
64494
|
// src/integrations/api-integrations.ts
|
|
63959
|
-
import { createHash as
|
|
64495
|
+
import { createHash as createHash17 } from "crypto";
|
|
63960
64496
|
import {
|
|
63961
64497
|
compileGraphqlRevision,
|
|
63962
64498
|
compileOpenApiRevision,
|
|
@@ -64175,7 +64711,7 @@ function resolvedPreview(input) {
|
|
|
64175
64711
|
};
|
|
64176
64712
|
}
|
|
64177
64713
|
function integrationInstallationIdentity(protocol, label, locator2) {
|
|
64178
|
-
const hash =
|
|
64714
|
+
const hash = createHash17("sha256").update(`${protocol}\0${locator2}`).digest("hex").slice(0, 12);
|
|
64179
64715
|
const slug = label.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 48) || "integration";
|
|
64180
64716
|
return {
|
|
64181
64717
|
sourceDerivedDefinitionId: `${slug}-${hash}`,
|
|
@@ -65000,7 +65536,7 @@ function registerConnectRoutes(app, deps) {
|
|
|
65000
65536
|
attemptId: before.id,
|
|
65001
65537
|
expectedRevision: input.expectedRevision,
|
|
65002
65538
|
operationId: input.idempotencyKey,
|
|
65003
|
-
inputDigest:
|
|
65539
|
+
inputDigest: createHash18("sha256").update(stableJson4(input)).digest("hex"),
|
|
65004
65540
|
authorize: (tx, _attempt, origin) => requireConnectOwnerAuthority(tx, scope, "capabilities:manage", origin),
|
|
65005
65541
|
execute: async (attempt) => {
|
|
65006
65542
|
if (attempt.state !== "credential_input")
|
|
@@ -65042,7 +65578,7 @@ function registerConnectRoutes(app, deps) {
|
|
|
65042
65578
|
attemptId: before.id,
|
|
65043
65579
|
expectedRevision: input.expectedRevision,
|
|
65044
65580
|
operationId: input.idempotencyKey,
|
|
65045
|
-
inputDigest:
|
|
65581
|
+
inputDigest: createHash18("sha256").update(stableJson4(input)).digest("hex"),
|
|
65046
65582
|
authorize: async (tx, _attempt, origin) => {
|
|
65047
65583
|
await requireConnectOwnerAuthority(tx, scope, installationPermission, origin);
|
|
65048
65584
|
if (before.providerId === "github-lens") {
|
|
@@ -65068,7 +65604,7 @@ function registerConnectRoutes(app, deps) {
|
|
|
65068
65604
|
attemptId: before.id,
|
|
65069
65605
|
expectedRevision: input.expectedRevision,
|
|
65070
65606
|
operationId: input.idempotencyKey,
|
|
65071
|
-
inputDigest:
|
|
65607
|
+
inputDigest: createHash18("sha256").update(stableJson4(input)).digest("hex"),
|
|
65072
65608
|
authorize: (tx, _attempt, origin) => requireConnectOwnerAuthority(tx, scope, "connections:write", origin),
|
|
65073
65609
|
execute: async (attempt) => {
|
|
65074
65610
|
if (attempt.state !== "credential_input")
|
|
@@ -65367,7 +65903,7 @@ function registerConnectRoutes(app, deps) {
|
|
|
65367
65903
|
attemptId: c.req.param("attemptId"),
|
|
65368
65904
|
expectedRevision: input.expectedRevision,
|
|
65369
65905
|
operationId: input.idempotencyKey,
|
|
65370
|
-
inputDigest:
|
|
65906
|
+
inputDigest: createHash18("sha256").update(stableJson4(input)).digest("hex"),
|
|
65371
65907
|
authorize: (tx, _attempt, origin) => requireConnectOwnerAuthority(tx, scope, permission, origin),
|
|
65372
65908
|
execute: async (attempt) => {
|
|
65373
65909
|
if (!attempt.source && (!attempt.credentialsCommitted || !attempt.account) || !["connected_but_incomplete", "preview"].includes(attempt.state))
|
|
@@ -65475,7 +66011,7 @@ function registerConnectRoutes(app, deps) {
|
|
|
65475
66011
|
attemptId: c.req.param("attemptId"),
|
|
65476
66012
|
expectedRevision: input.expectedRevision,
|
|
65477
66013
|
operationId: input.idempotencyKey,
|
|
65478
|
-
inputDigest:
|
|
66014
|
+
inputDigest: createHash18("sha256").update(stableJson4({ ...input, action: "cancel" })).digest("hex"),
|
|
65479
66015
|
purpose: "cancellation",
|
|
65480
66016
|
authorize: async (tx, attempt, origin) => {
|
|
65481
66017
|
const permission = attempt.providerId === "mcp-install" ? "capabilities:manage" : ["x", "reddit"].includes(attempt.providerId) ? attempt.ownership === "workspace" ? "workspace:admin" : "workspace:read" : attempt.providerId === "github-app" ? "github:manage" : attempt.providerId === "github-lens" ? "workspace:admin" : "connections:write";
|
|
@@ -65540,7 +66076,7 @@ function registerConnectRoutes(app, deps) {
|
|
|
65540
66076
|
await requireConnectOwnerAuthority(actorTx, scope, setupPermission);
|
|
65541
66077
|
const replay2 = await getConnectBeginReplay(actorTx, scope, {
|
|
65542
66078
|
idempotencyKey: input.idempotencyKey,
|
|
65543
|
-
requestDigest:
|
|
66079
|
+
requestDigest: createHash18("sha256").update(stableJson4(input)).digest("hex"),
|
|
65544
66080
|
returnUrl: input.returnUrl,
|
|
65545
66081
|
...continuation ? { externalContinuation: continuation } : {}
|
|
65546
66082
|
});
|
|
@@ -65574,7 +66110,7 @@ function registerConnectRoutes(app, deps) {
|
|
|
65574
66110
|
}
|
|
65575
66111
|
);
|
|
65576
66112
|
});
|
|
65577
|
-
const id =
|
|
66113
|
+
const id = randomUUID5();
|
|
65578
66114
|
if (input.providerId === "mcp-install") {
|
|
65579
66115
|
if (input.ownership !== "workspace" || input.reconnectAccountId || input.installationTarget)
|
|
65580
66116
|
throw new HTTPException39(422, {
|
|
@@ -65596,7 +66132,7 @@ function registerConnectRoutes(app, deps) {
|
|
|
65596
66132
|
return beginConnectAttempt(tx, scope, {
|
|
65597
66133
|
...continuation ? { externalContinuation: continuation } : {},
|
|
65598
66134
|
idempotencyKey: input.idempotencyKey,
|
|
65599
|
-
requestDigest:
|
|
66135
|
+
requestDigest: createHash18("sha256").update(stableJson4(input)).digest("hex"),
|
|
65600
66136
|
returnUrl: input.returnUrl,
|
|
65601
66137
|
attempt: {
|
|
65602
66138
|
id,
|
|
@@ -65654,7 +66190,7 @@ function registerConnectRoutes(app, deps) {
|
|
|
65654
66190
|
return beginConnectAttempt(tx, scope, {
|
|
65655
66191
|
...continuation ? { externalContinuation: continuation } : {},
|
|
65656
66192
|
idempotencyKey: input.idempotencyKey,
|
|
65657
|
-
requestDigest:
|
|
66193
|
+
requestDigest: createHash18("sha256").update(stableJson4(input)).digest("hex"),
|
|
65658
66194
|
returnUrl: input.returnUrl,
|
|
65659
66195
|
attempt: {
|
|
65660
66196
|
id,
|
|
@@ -65704,7 +66240,7 @@ function registerConnectRoutes(app, deps) {
|
|
|
65704
66240
|
return beginConnectAttempt(tx, scope, {
|
|
65705
66241
|
...continuation ? { externalContinuation: continuation } : {},
|
|
65706
66242
|
idempotencyKey: input.idempotencyKey,
|
|
65707
|
-
requestDigest:
|
|
66243
|
+
requestDigest: createHash18("sha256").update(stableJson4(input)).digest("hex"),
|
|
65708
66244
|
returnUrl: input.returnUrl,
|
|
65709
66245
|
attempt: {
|
|
65710
66246
|
id,
|
|
@@ -65739,7 +66275,7 @@ function registerConnectRoutes(app, deps) {
|
|
|
65739
66275
|
return beginConnectAttempt(tx, scope, {
|
|
65740
66276
|
...continuation ? { externalContinuation: continuation } : {},
|
|
65741
66277
|
idempotencyKey: input.idempotencyKey,
|
|
65742
|
-
requestDigest:
|
|
66278
|
+
requestDigest: createHash18("sha256").update(stableJson4(input)).digest("hex"),
|
|
65743
66279
|
returnUrl: input.returnUrl,
|
|
65744
66280
|
attempt: {
|
|
65745
66281
|
id,
|
|
@@ -65820,7 +66356,7 @@ function registerConnectRoutes(app, deps) {
|
|
|
65820
66356
|
return beginConnectAttempt(tx, scope, {
|
|
65821
66357
|
...continuation ? { externalContinuation: continuation } : {},
|
|
65822
66358
|
idempotencyKey: input.idempotencyKey,
|
|
65823
|
-
requestDigest:
|
|
66359
|
+
requestDigest: createHash18("sha256").update(stableJson4(input)).digest("hex"),
|
|
65824
66360
|
returnUrl: input.returnUrl,
|
|
65825
66361
|
attempt: {
|
|
65826
66362
|
id,
|
|
@@ -65958,7 +66494,7 @@ function registerConnectRoutes(app, deps) {
|
|
|
65958
66494
|
return beginConnectAttempt(tx, scope, {
|
|
65959
66495
|
...continuation ? { externalContinuation: continuation } : {},
|
|
65960
66496
|
idempotencyKey: input.idempotencyKey,
|
|
65961
|
-
requestDigest:
|
|
66497
|
+
requestDigest: createHash18("sha256").update(stableJson4(input)).digest("hex"),
|
|
65962
66498
|
returnUrl: input.returnUrl,
|
|
65963
66499
|
attempt: {
|
|
65964
66500
|
id,
|
|
@@ -66947,7 +67483,8 @@ function registerDocumentRoutes(app, deps) {
|
|
|
66947
67483
|
deps,
|
|
66948
67484
|
await requireAccessGrantAuthorization8(c, deps, workspaceId, "documents:search"),
|
|
66949
67485
|
"documents:search"
|
|
66950
|
-
)
|
|
67486
|
+
),
|
|
67487
|
+
settings: deps.settings
|
|
66951
67488
|
}
|
|
66952
67489
|
);
|
|
66953
67490
|
await server.connect(transport);
|
|
@@ -67015,7 +67552,7 @@ function requireOrganizationDocumentAuthority(authorityKind, organizationAuthori
|
|
|
67015
67552
|
}
|
|
67016
67553
|
|
|
67017
67554
|
// src/routes/knowledge.ts
|
|
67018
|
-
import { retryWhileMissing as
|
|
67555
|
+
import { retryWhileMissing as retryWhileMissing5 } from "@opengeni/storage";
|
|
67019
67556
|
import { allowedFirstPartyMcpToolsForSession as allowedFirstPartyMcpToolsForSession3 } from "@opengeni/config";
|
|
67020
67557
|
import {
|
|
67021
67558
|
AgentLearningContext,
|
|
@@ -67034,6 +67571,8 @@ import {
|
|
|
67034
67571
|
prepareKnowledgeFile as prepareKnowledgeFile2,
|
|
67035
67572
|
prepareKnowledgeSave as prepareKnowledgeSave2,
|
|
67036
67573
|
searchKnowledgeEntries as searchKnowledgeEntries3,
|
|
67574
|
+
KnowledgeVectorFundingError,
|
|
67575
|
+
KnowledgeVectorQueryRejectedError,
|
|
67037
67576
|
hasPermission as hasPermission13,
|
|
67038
67577
|
knowledgeContextForAccess as knowledgeContextForAccess2,
|
|
67039
67578
|
requireAccessGrantAuthorization as requireAccessGrantAuthorization9,
|
|
@@ -67073,6 +67612,18 @@ var WriteSettings = ReadSettings.extend({
|
|
|
67073
67612
|
var Id = z22.uuid();
|
|
67074
67613
|
function knowledgeHttpError(error) {
|
|
67075
67614
|
if (error instanceof HTTPException42) throw error;
|
|
67615
|
+
if (error instanceof KnowledgeVectorFundingError)
|
|
67616
|
+
throw new ApiHttpError(402, {
|
|
67617
|
+
code: "payment_required",
|
|
67618
|
+
message: error.message,
|
|
67619
|
+
details: { code: error.code, keywordAvailable: true }
|
|
67620
|
+
});
|
|
67621
|
+
if (error instanceof KnowledgeVectorQueryRejectedError)
|
|
67622
|
+
throw new ApiHttpError(error.code === "quota" ? 429 : 422, {
|
|
67623
|
+
code: error.code === "quota" ? "limit_exceeded" : "validation_failed",
|
|
67624
|
+
message: error.message,
|
|
67625
|
+
details: { code: error.code, keywordAvailable: true }
|
|
67626
|
+
});
|
|
67076
67627
|
if (error instanceof z22.ZodError)
|
|
67077
67628
|
throw new HTTPException42(422, {
|
|
67078
67629
|
message: error.issues[0]?.message ?? "Invalid Knowledge request"
|
|
@@ -67155,7 +67706,7 @@ function registerKnowledgeRoutes(app, deps) {
|
|
|
67155
67706
|
if (!file) throw new HTTPException42(404, { message: "Original file unavailable" });
|
|
67156
67707
|
if (!deps.objectStorage)
|
|
67157
67708
|
throw new HTTPException42(503, { message: "File storage is unavailable" });
|
|
67158
|
-
if (!await
|
|
67709
|
+
if (!await retryWhileMissing5(
|
|
67159
67710
|
async () => await deps.objectStorage.fileExists(file) ? true : null
|
|
67160
67711
|
))
|
|
67161
67712
|
throw new HTTPException42(410, { message: "Original file bytes are unavailable" });
|
|
@@ -67204,7 +67755,9 @@ function registerKnowledgeRoutes(app, deps) {
|
|
|
67204
67755
|
deps.db,
|
|
67205
67756
|
context,
|
|
67206
67757
|
KnowledgeSavePreparationRequest2.parse(await c.req.json()),
|
|
67207
|
-
() => deps.getDocumentServices().embedder
|
|
67758
|
+
() => deps.getDocumentServices().embedder,
|
|
67759
|
+
void 0,
|
|
67760
|
+
deps.settings
|
|
67208
67761
|
)
|
|
67209
67762
|
);
|
|
67210
67763
|
})
|
|
@@ -67219,7 +67772,8 @@ function registerKnowledgeRoutes(app, deps) {
|
|
|
67219
67772
|
deps.db,
|
|
67220
67773
|
context,
|
|
67221
67774
|
KnowledgeEntryListRequest3.parse(await c.req.json()),
|
|
67222
|
-
() => deps.getDocumentServices().embedder
|
|
67775
|
+
() => deps.getDocumentServices().embedder,
|
|
67776
|
+
deps.settings
|
|
67223
67777
|
)
|
|
67224
67778
|
)
|
|
67225
67779
|
)
|
|
@@ -67266,7 +67820,8 @@ function registerKnowledgeRoutes(app, deps) {
|
|
|
67266
67820
|
...query,
|
|
67267
67821
|
...query.limit ? { limit: Number(query.limit) } : {}
|
|
67268
67822
|
}),
|
|
67269
|
-
() => deps.getDocumentServices().embedder
|
|
67823
|
+
() => deps.getDocumentServices().embedder,
|
|
67824
|
+
deps.settings
|
|
67270
67825
|
)
|
|
67271
67826
|
);
|
|
67272
67827
|
})
|
|
@@ -67432,7 +67987,7 @@ function registerKnowledgeRoutes(app, deps) {
|
|
|
67432
67987
|
}
|
|
67433
67988
|
|
|
67434
67989
|
// src/routes/enrollments.ts
|
|
67435
|
-
import { randomUUID as
|
|
67990
|
+
import { randomUUID as randomUUID6 } from "crypto";
|
|
67436
67991
|
import {
|
|
67437
67992
|
DeviceEnrollmentApproveRequest,
|
|
67438
67993
|
DeviceEnrollmentApproveResponse,
|
|
@@ -67464,297 +68019,6 @@ import {
|
|
|
67464
68019
|
requireAccessGrantAuthorization as requireAccessGrantAuthorization10,
|
|
67465
68020
|
requirePermission
|
|
67466
68021
|
} from "@opengeni/core";
|
|
67467
|
-
|
|
67468
|
-
// src/sandbox/enrollment.ts
|
|
67469
|
-
import { randomBytes as randomBytes8 } from "crypto";
|
|
67470
|
-
import {
|
|
67471
|
-
resolveEnrollmentSigningSecret,
|
|
67472
|
-
resolveRelayTokenSecret
|
|
67473
|
-
} from "@opengeni/config";
|
|
67474
|
-
import {
|
|
67475
|
-
DeviceEnrollmentState,
|
|
67476
|
-
signEnrollmentBearer,
|
|
67477
|
-
signEnrollToken,
|
|
67478
|
-
signRelayToken,
|
|
67479
|
-
verifyEnrollToken
|
|
67480
|
-
} from "@opengeni/contracts";
|
|
67481
|
-
import {
|
|
67482
|
-
approveDeviceEnrollmentRequest,
|
|
67483
|
-
consumeDeviceEnrollmentRequest,
|
|
67484
|
-
createDeviceEnrollmentRequest,
|
|
67485
|
-
denyDeviceEnrollmentRequest,
|
|
67486
|
-
finalizeEnrollmentByToken,
|
|
67487
|
-
getDeviceEnrollmentRequestByDeviceCode,
|
|
67488
|
-
getEnrollment,
|
|
67489
|
-
getPendingDeviceEnrollmentRequestByUserCode,
|
|
67490
|
-
getPendingDeviceEnrollmentRequestByUserCodeGlobal
|
|
67491
|
-
} from "@opengeni/db";
|
|
67492
|
-
import { relayDialBaseFromSettings } from "@opengeni/core";
|
|
67493
|
-
var DEVICE_CODE_TTL_SECONDS = 600;
|
|
67494
|
-
var DEVICE_POLL_INTERVAL_SECONDS = 5;
|
|
67495
|
-
var ENROLLMENT_BEARER_TTL_SECONDS = 30 * 24 * 3600;
|
|
67496
|
-
var RELAY_TOKEN_TTL_SECONDS = 30 * 24 * 3600;
|
|
67497
|
-
var ENROLL_TOKEN_TTL_SECONDS = 3600;
|
|
67498
|
-
function mintDeviceCode() {
|
|
67499
|
-
return randomBytes8(32).toString("base64url");
|
|
67500
|
-
}
|
|
67501
|
-
var USER_CODE_ALPHABET = "ABCDEFGHJKLMNPQRSTUVWXYZ23456789";
|
|
67502
|
-
function mintUserCode() {
|
|
67503
|
-
const bytes = randomBytes8(8);
|
|
67504
|
-
let out = "";
|
|
67505
|
-
for (let i = 0; i < 8; i += 1) {
|
|
67506
|
-
out += USER_CODE_ALPHABET[bytes[i] % USER_CODE_ALPHABET.length];
|
|
67507
|
-
}
|
|
67508
|
-
return `${out.slice(0, 4)}-${out.slice(4, 8)}`;
|
|
67509
|
-
}
|
|
67510
|
-
async function startDeviceEnrollment(services, input) {
|
|
67511
|
-
const { db } = services;
|
|
67512
|
-
const expiresAt = new Date(Date.now() + DEVICE_CODE_TTL_SECONDS * 1e3);
|
|
67513
|
-
let request;
|
|
67514
|
-
let lastError;
|
|
67515
|
-
for (let attempt = 0; attempt < 5 && !request; attempt += 1) {
|
|
67516
|
-
const deviceCode = mintDeviceCode();
|
|
67517
|
-
const userCode = mintUserCode();
|
|
67518
|
-
try {
|
|
67519
|
-
request = await createDeviceEnrollmentRequest(db, {
|
|
67520
|
-
accountId: input.accountId,
|
|
67521
|
-
workspaceId: input.workspaceId,
|
|
67522
|
-
deviceCode,
|
|
67523
|
-
userCode,
|
|
67524
|
-
pubkey: input.publicKey,
|
|
67525
|
-
os: input.os,
|
|
67526
|
-
arch: input.arch,
|
|
67527
|
-
machineName: input.machineName ?? null,
|
|
67528
|
-
requestedExposure: "whole-machine",
|
|
67529
|
-
canOfferDisplay: input.canOfferDisplay,
|
|
67530
|
-
requestsScreenControl: input.requestsScreenControl,
|
|
67531
|
-
expiresAt
|
|
67532
|
-
});
|
|
67533
|
-
} catch (error) {
|
|
67534
|
-
lastError = error;
|
|
67535
|
-
}
|
|
67536
|
-
}
|
|
67537
|
-
if (!request) {
|
|
67538
|
-
throw lastError instanceof Error ? lastError : new Error("failed to start device enrollment");
|
|
67539
|
-
}
|
|
67540
|
-
const base = input.verificationOrigin.replace(/\/+$/, "");
|
|
67541
|
-
const verificationUri = `${base}/device`;
|
|
67542
|
-
const verificationUriComplete = `${verificationUri}?user_code=${encodeURIComponent(request.userCode)}`;
|
|
67543
|
-
return {
|
|
67544
|
-
deviceCode: request.deviceCode,
|
|
67545
|
-
userCode: request.userCode,
|
|
67546
|
-
verificationUri,
|
|
67547
|
-
verificationUriComplete,
|
|
67548
|
-
intervalSeconds: DEVICE_POLL_INTERVAL_SECONDS,
|
|
67549
|
-
expiresInSeconds: DEVICE_CODE_TTL_SECONDS
|
|
67550
|
-
};
|
|
67551
|
-
}
|
|
67552
|
-
async function approveDeviceEnrollment(services, input) {
|
|
67553
|
-
const { db } = services;
|
|
67554
|
-
const pending = await getPendingDeviceEnrollmentRequestByUserCode(
|
|
67555
|
-
db,
|
|
67556
|
-
input.workspaceId,
|
|
67557
|
-
input.userCode
|
|
67558
|
-
);
|
|
67559
|
-
if (!pending) {
|
|
67560
|
-
return null;
|
|
67561
|
-
}
|
|
67562
|
-
const sandboxName = (pending.machineName?.trim() || `${pending.os} machine`).slice(0, 256);
|
|
67563
|
-
const result = await approveDeviceEnrollmentRequest(db, {
|
|
67564
|
-
accountId: input.accountId,
|
|
67565
|
-
workspaceId: input.workspaceId,
|
|
67566
|
-
...input.scope ? { scope: input.scope } : {},
|
|
67567
|
-
allowOrganization: input.allowOrganization === true,
|
|
67568
|
-
requestId: pending.id,
|
|
67569
|
-
allowScreenControl: input.allowScreenControl,
|
|
67570
|
-
approvedBySubjectId: input.approvedBySubjectId,
|
|
67571
|
-
approvedBySubjectLabel: input.approvedBySubjectLabel ?? null,
|
|
67572
|
-
sandboxName
|
|
67573
|
-
});
|
|
67574
|
-
if (!result.approved || !result.enrollment || !result.sandbox) {
|
|
67575
|
-
return null;
|
|
67576
|
-
}
|
|
67577
|
-
return {
|
|
67578
|
-
enrollmentId: result.enrollment.id,
|
|
67579
|
-
sandboxId: result.sandbox.id,
|
|
67580
|
-
allowScreenControl: result.enrollment.allowScreenControl
|
|
67581
|
-
};
|
|
67582
|
-
}
|
|
67583
|
-
async function lookupDeviceEnrollment(services, input) {
|
|
67584
|
-
const { db } = services;
|
|
67585
|
-
return await getPendingDeviceEnrollmentRequestByUserCodeGlobal(db, input.userCode);
|
|
67586
|
-
}
|
|
67587
|
-
function toLookupResponse(record6) {
|
|
67588
|
-
return {
|
|
67589
|
-
workspaceId: record6.workspaceId,
|
|
67590
|
-
userCode: record6.userCode,
|
|
67591
|
-
machine: {
|
|
67592
|
-
machineName: record6.machineName,
|
|
67593
|
-
os: record6.os,
|
|
67594
|
-
arch: record6.arch,
|
|
67595
|
-
canOfferDisplay: record6.canOfferDisplay,
|
|
67596
|
-
requestsScreenControl: record6.requestsScreenControl
|
|
67597
|
-
},
|
|
67598
|
-
expiresAt: record6.expiresAt
|
|
67599
|
-
};
|
|
67600
|
-
}
|
|
67601
|
-
async function denyDeviceEnrollment(services, input) {
|
|
67602
|
-
const { db } = services;
|
|
67603
|
-
const pending = await getPendingDeviceEnrollmentRequestByUserCode(
|
|
67604
|
-
db,
|
|
67605
|
-
input.workspaceId,
|
|
67606
|
-
input.userCode
|
|
67607
|
-
);
|
|
67608
|
-
if (!pending) {
|
|
67609
|
-
return { denied: false };
|
|
67610
|
-
}
|
|
67611
|
-
return await denyDeviceEnrollmentRequest(db, {
|
|
67612
|
-
accountId: input.accountId,
|
|
67613
|
-
workspaceId: input.workspaceId,
|
|
67614
|
-
requestId: pending.id
|
|
67615
|
-
});
|
|
67616
|
-
}
|
|
67617
|
-
async function mintEnrollToken(services, input) {
|
|
67618
|
-
const { settings } = services;
|
|
67619
|
-
const secret = resolveEnrollmentSigningSecret(settings);
|
|
67620
|
-
if (!secret) {
|
|
67621
|
-
return null;
|
|
67622
|
-
}
|
|
67623
|
-
const nowSeconds = Math.floor(Date.now() / 1e3);
|
|
67624
|
-
const exp = nowSeconds + ENROLL_TOKEN_TTL_SECONDS;
|
|
67625
|
-
const token = await signEnrollToken(secret, {
|
|
67626
|
-
typ: "enroll",
|
|
67627
|
-
workspaceId: input.workspaceId,
|
|
67628
|
-
accountId: input.accountId,
|
|
67629
|
-
allowScreenControl: input.allowScreenControl,
|
|
67630
|
-
iat: nowSeconds,
|
|
67631
|
-
exp
|
|
67632
|
-
});
|
|
67633
|
-
return {
|
|
67634
|
-
token,
|
|
67635
|
-
expiresAt: new Date(exp * 1e3).toISOString(),
|
|
67636
|
-
expiresInSeconds: ENROLL_TOKEN_TTL_SECONDS
|
|
67637
|
-
};
|
|
67638
|
-
}
|
|
67639
|
-
async function exchangeEnrollToken(services, input) {
|
|
67640
|
-
const { db, settings } = services;
|
|
67641
|
-
const secret = resolveEnrollmentSigningSecret(settings);
|
|
67642
|
-
if (!secret) {
|
|
67643
|
-
return { ok: false, reason: "disabled" };
|
|
67644
|
-
}
|
|
67645
|
-
const claims = await verifyEnrollToken(secret, input.token);
|
|
67646
|
-
if (!claims) {
|
|
67647
|
-
return { ok: false, reason: "invalid" };
|
|
67648
|
-
}
|
|
67649
|
-
const sandboxName = (input.machineName?.trim() || `${input.os} machine`).slice(0, 256);
|
|
67650
|
-
const { enrollment } = await finalizeEnrollmentByToken(db, {
|
|
67651
|
-
accountId: claims.accountId,
|
|
67652
|
-
workspaceId: claims.workspaceId,
|
|
67653
|
-
pubkey: input.publicKey,
|
|
67654
|
-
hasDisplay: input.canOfferDisplay,
|
|
67655
|
-
// The token's allowScreenControl is the AUTHORITATIVE consent (NOT the agent's
|
|
67656
|
-
// requestsScreenControl) — it was baked in at mint by the authorizing user.
|
|
67657
|
-
allowScreenControl: claims.allowScreenControl,
|
|
67658
|
-
os: input.os,
|
|
67659
|
-
arch: input.arch,
|
|
67660
|
-
sandboxName
|
|
67661
|
-
});
|
|
67662
|
-
const credentials = await buildEnrollmentCredentials(services, {
|
|
67663
|
-
secret,
|
|
67664
|
-
workspaceId: claims.workspaceId,
|
|
67665
|
-
agentId: enrollment.id,
|
|
67666
|
-
credentialGeneration: enrollment.credentialGeneration,
|
|
67667
|
-
consentedScreenControl: enrollment.allowScreenControl
|
|
67668
|
-
});
|
|
67669
|
-
return { ok: true, credentials };
|
|
67670
|
-
}
|
|
67671
|
-
async function pollDeviceEnrollment(services, input) {
|
|
67672
|
-
const { db, settings } = services;
|
|
67673
|
-
const request = await getDeviceEnrollmentRequestByDeviceCode(db, input.deviceCode);
|
|
67674
|
-
if (!request) {
|
|
67675
|
-
return { state: "expired" };
|
|
67676
|
-
}
|
|
67677
|
-
if (request.status === "denied") {
|
|
67678
|
-
return { state: "denied" };
|
|
67679
|
-
}
|
|
67680
|
-
if (request.status === "pending") {
|
|
67681
|
-
if (new Date(request.expiresAt).getTime() <= Date.now()) {
|
|
67682
|
-
return { state: "expired" };
|
|
67683
|
-
}
|
|
67684
|
-
return { state: "pending" };
|
|
67685
|
-
}
|
|
67686
|
-
if (!request.enrollmentId) {
|
|
67687
|
-
return { state: "expired" };
|
|
67688
|
-
}
|
|
67689
|
-
const secret = resolveEnrollmentSigningSecret(settings);
|
|
67690
|
-
if (!secret) {
|
|
67691
|
-
return { state: "disabled" };
|
|
67692
|
-
}
|
|
67693
|
-
const enrollment = await getEnrollment(db, request.workspaceId, request.enrollmentId);
|
|
67694
|
-
if (!enrollment || enrollment.status !== "active") {
|
|
67695
|
-
return { state: "denied" };
|
|
67696
|
-
}
|
|
67697
|
-
const credentials = await buildEnrollmentCredentials(services, {
|
|
67698
|
-
secret,
|
|
67699
|
-
workspaceId: request.workspaceId,
|
|
67700
|
-
agentId: enrollment.id,
|
|
67701
|
-
credentialGeneration: enrollment.credentialGeneration,
|
|
67702
|
-
consentedScreenControl: enrollment.allowScreenControl
|
|
67703
|
-
});
|
|
67704
|
-
if (request.status === "approved") {
|
|
67705
|
-
await consumeDeviceEnrollmentRequest(db, {
|
|
67706
|
-
accountId: request.accountId,
|
|
67707
|
-
workspaceId: request.workspaceId,
|
|
67708
|
-
requestId: request.id
|
|
67709
|
-
});
|
|
67710
|
-
}
|
|
67711
|
-
return { state: DeviceEnrollmentState.enum.authorized, credentials };
|
|
67712
|
-
}
|
|
67713
|
-
async function buildEnrollmentCredentials(services, input) {
|
|
67714
|
-
const { settings } = services;
|
|
67715
|
-
const subjectPrefix = `agent.${input.workspaceId}.${input.agentId}`;
|
|
67716
|
-
const nowSeconds = Math.floor(Date.now() / 1e3);
|
|
67717
|
-
const exp = nowSeconds + ENROLLMENT_BEARER_TTL_SECONDS;
|
|
67718
|
-
const bearer = await signEnrollmentBearer(input.secret, {
|
|
67719
|
-
workspaceId: input.workspaceId,
|
|
67720
|
-
agentId: input.agentId,
|
|
67721
|
-
enrollmentId: input.agentId,
|
|
67722
|
-
credentialGeneration: input.credentialGeneration,
|
|
67723
|
-
subjectPrefix,
|
|
67724
|
-
exp
|
|
67725
|
-
});
|
|
67726
|
-
const natsUrls = settings.selfhostedNatsUrl ? [settings.selfhostedNatsUrl] : [];
|
|
67727
|
-
const relayTokenSecret = resolveRelayTokenSecret(settings);
|
|
67728
|
-
const relayToken = relayTokenSecret ? await signRelayToken(relayTokenSecret, {
|
|
67729
|
-
workspaceId: input.workspaceId,
|
|
67730
|
-
agentId: input.agentId,
|
|
67731
|
-
exp: nowSeconds + RELAY_TOKEN_TTL_SECONDS
|
|
67732
|
-
}) : "";
|
|
67733
|
-
return {
|
|
67734
|
-
agentId: input.agentId,
|
|
67735
|
-
workspaceId: input.workspaceId,
|
|
67736
|
-
bearer,
|
|
67737
|
-
subjectPrefix,
|
|
67738
|
-
natsUrls,
|
|
67739
|
-
// Hand the agent the canonical `/stream` dial base, NOT the raw configured URL.
|
|
67740
|
-
// The agent's relay producer appends only its routing query and assumes the base
|
|
67741
|
-
// already carries the relay's `/stream` route; a path-less base 400s the dial and
|
|
67742
|
-
// makes the terminal/desktop streams unreachable.
|
|
67743
|
-
relayUrl: relayDialBaseFromSettings(settings),
|
|
67744
|
-
relayToken,
|
|
67745
|
-
// M-AUTH closes the placeholder: there is NO per-machine NATS Account creds
|
|
67746
|
-
// file. The agent presents the BEARER as the NATS connect auth-token; the
|
|
67747
|
-
// server's auth-callout responder validates it and mints a workspace-scoped
|
|
67748
|
-
// user JWT. We echo the bearer here so a consumer reading this (vestigial) field
|
|
67749
|
-
// as the connect credential still works — the value IS the bearer.
|
|
67750
|
-
natsAccountCreds: bearer,
|
|
67751
|
-
updatePublicKey: settings.agentUpdatePublicKey ?? "",
|
|
67752
|
-
consentedWholeMachine: true,
|
|
67753
|
-
consentedScreenControl: input.consentedScreenControl
|
|
67754
|
-
};
|
|
67755
|
-
}
|
|
67756
|
-
|
|
67757
|
-
// src/routes/enrollments.ts
|
|
67758
68022
|
function registerEnrollmentRoutes(app, deps) {
|
|
67759
68023
|
const { settings, db } = deps;
|
|
67760
68024
|
function assertSelfhostedEnabled() {
|
|
@@ -68023,7 +68287,7 @@ function registerEnrollmentRoutes(app, deps) {
|
|
|
68023
68287
|
message: "invalid machine removal request"
|
|
68024
68288
|
});
|
|
68025
68289
|
}
|
|
68026
|
-
const idempotencyKey = parsed.data.idempotencyKey?.trim() || c.req.header("idempotency-key")?.trim() ||
|
|
68290
|
+
const idempotencyKey = parsed.data.idempotencyKey?.trim() || c.req.header("idempotency-key")?.trim() || randomUUID6();
|
|
68027
68291
|
try {
|
|
68028
68292
|
const enrollmentId = c.req.param("enrollmentId");
|
|
68029
68293
|
const enrollment = (await listEnrollments2(db, grant, { status: "active" })).find(
|
|
@@ -68154,7 +68418,7 @@ import {
|
|
|
68154
68418
|
readMachineMetricsLatestForWorkspace
|
|
68155
68419
|
} from "@opengeni/db";
|
|
68156
68420
|
import { MachineView, MetricSample } from "@opengeni/contracts";
|
|
68157
|
-
import { managedSessionGroupBackend as managedSessionGroupBackend3 } from "@opengeni/core";
|
|
68421
|
+
import { managedSessionGroupBackend as managedSessionGroupBackend3, sessionGroupMachinePresentation } from "@opengeni/core";
|
|
68158
68422
|
import { selfhostedHeartbeatLiveness } from "@opengeni/runtime/sandbox";
|
|
68159
68423
|
var ACTIVE_UPDATE_STATUSES = /* @__PURE__ */ new Set([
|
|
68160
68424
|
"requested",
|
|
@@ -68291,23 +68555,24 @@ async function listMachines(services, input) {
|
|
|
68291
68555
|
if (session && groupBackend) {
|
|
68292
68556
|
const groupActive = activeSandboxId === null;
|
|
68293
68557
|
const groupLease = await readLease3(db, workspaceId, session.sandboxGroupId);
|
|
68558
|
+
const presentation = sessionGroupMachinePresentation(groupBackend);
|
|
68559
|
+
const localHost = groupBackend === "local";
|
|
68294
68560
|
machines.push(
|
|
68295
68561
|
MachineView.parse({
|
|
68296
68562
|
sandboxId: session.sandboxGroupId,
|
|
68297
68563
|
enrollmentId: null,
|
|
68298
|
-
name:
|
|
68299
|
-
kind:
|
|
68564
|
+
name: presentation.name,
|
|
68565
|
+
kind: presentation.kind,
|
|
68300
68566
|
state: "online",
|
|
68301
68567
|
active: groupActive,
|
|
68302
68568
|
isSessionGroup: true,
|
|
68303
68569
|
workspaceGeneration: groupLease?.workspaceGeneration ?? null,
|
|
68304
68570
|
archiveGeneration: groupLease?.archiveGeneration ?? null,
|
|
68305
68571
|
archiveComplete: groupLease?.archiveComplete ?? false,
|
|
68306
|
-
//
|
|
68307
|
-
|
|
68308
|
-
|
|
68309
|
-
|
|
68310
|
-
hasDisplay: false,
|
|
68572
|
+
// A local sandbox is this machine. Other managed providers run a Linux box.
|
|
68573
|
+
os: localHost ? process.platform : "linux",
|
|
68574
|
+
arch: localHost ? process.arch : "x86_64",
|
|
68575
|
+
hasDisplay: localHost,
|
|
68311
68576
|
desktopUnavailableReason: null,
|
|
68312
68577
|
allowScreenControl: false,
|
|
68313
68578
|
sharedSessionCount: 1,
|
|
@@ -70222,11 +70487,12 @@ function browserIdentityRouteError(error) {
|
|
|
70222
70487
|
}
|
|
70223
70488
|
|
|
70224
70489
|
// src/routes/browser-sessions.ts
|
|
70225
|
-
import { randomUUID as
|
|
70490
|
+
import { randomUUID as randomUUID7 } from "crypto";
|
|
70226
70491
|
import {
|
|
70227
70492
|
environmentsEncryptionKeyBytes as environmentsEncryptionKeyBytes5,
|
|
70228
70493
|
resolveFirstPartyDelegationSecret as resolveFirstPartyDelegationSecret3,
|
|
70229
|
-
resolveStreamTokenSecret as resolveStreamTokenSecret2
|
|
70494
|
+
resolveStreamTokenSecret as resolveStreamTokenSecret2,
|
|
70495
|
+
sandboxWarmRateMicrosPerSecond as sandboxWarmRateMicrosPerSecond3
|
|
70230
70496
|
} from "@opengeni/config";
|
|
70231
70497
|
import {
|
|
70232
70498
|
BROWSER_CONTROL_WEBSOCKET_BEARER_PREFIX,
|
|
@@ -70286,6 +70552,7 @@ import {
|
|
|
70286
70552
|
BrowserSessionNotFoundError,
|
|
70287
70553
|
BrowserSessionOperationConflictError,
|
|
70288
70554
|
BrowserSessionStateError as BrowserSessionStateError2,
|
|
70555
|
+
SandboxPaidComputeAdmissionError as SandboxPaidComputeAdmissionError3,
|
|
70289
70556
|
completeBrowserSessionEnd,
|
|
70290
70557
|
completeExternalAuth,
|
|
70291
70558
|
completeBrowserDownloadSave,
|
|
@@ -70374,7 +70641,7 @@ import {
|
|
|
70374
70641
|
provisionBrowserControlClient,
|
|
70375
70642
|
renewSandboxProviderExpiration as renewSandboxProviderExpiration2
|
|
70376
70643
|
} from "@opengeni/runtime/sandbox";
|
|
70377
|
-
import { retryWhileMissing as
|
|
70644
|
+
import { retryWhileMissing as retryWhileMissing6 } from "@opengeni/storage";
|
|
70378
70645
|
import { HTTPException as HTTPException51 } from "hono/http-exception";
|
|
70379
70646
|
|
|
70380
70647
|
// src/browser-controller-authority.ts
|
|
@@ -70657,7 +70924,7 @@ async function withInteractionHolderHeartbeat(deps, input, run) {
|
|
|
70657
70924
|
}
|
|
70658
70925
|
|
|
70659
70926
|
// src/browser-state-authority.ts
|
|
70660
|
-
import { createCipheriv, createDecipheriv, createHash as
|
|
70927
|
+
import { createCipheriv, createDecipheriv, createHash as createHash19, createHmac as createHmac7, randomBytes as randomBytes9 } from "crypto";
|
|
70661
70928
|
import { BROWSER_PROFILE_ARTIFACT_FORMAT } from "@opengeni/contracts";
|
|
70662
70929
|
var ROOT_KEY_BYTES = 32;
|
|
70663
70930
|
var DATA_KEY_BYTES = 32;
|
|
@@ -70721,7 +70988,7 @@ function browserStateObjectKey(workspaceIdInput, operationIdInput) {
|
|
|
70721
70988
|
return `workspaces/${workspaceId}/browser-state/revisions/${operationId}/chromium-profile.ogbs`;
|
|
70722
70989
|
}
|
|
70723
70990
|
function browserStateManifestDigest(manifest) {
|
|
70724
|
-
return
|
|
70991
|
+
return createHash19("sha256").update(canonicalJson2(manifest), "utf8").digest("hex");
|
|
70725
70992
|
}
|
|
70726
70993
|
function operationScope(input) {
|
|
70727
70994
|
const base = baseArtifactScope(input);
|
|
@@ -72013,7 +72280,7 @@ function registerBrowserSessionRoutes(app, deps) {
|
|
|
72013
72280
|
message: `browser download exceeds single PUT limit of ${objectStorage.maxSinglePutSizeBytes} bytes`
|
|
72014
72281
|
});
|
|
72015
72282
|
}
|
|
72016
|
-
const fileId =
|
|
72283
|
+
const fileId = randomUUID7();
|
|
72017
72284
|
const safeFilename = sanitizeFilename(source.download.filename);
|
|
72018
72285
|
save = await prepareBrowserDownloadSave(deps.db, {
|
|
72019
72286
|
...identity2,
|
|
@@ -72187,6 +72454,33 @@ function registerBrowserSessionRoutes(app, deps) {
|
|
|
72187
72454
|
return context.json(result);
|
|
72188
72455
|
}
|
|
72189
72456
|
);
|
|
72457
|
+
app.get(
|
|
72458
|
+
"/v1/workspaces/:workspaceId/browser-sessions/:browserSessionId/targets/:targetId/screenshot",
|
|
72459
|
+
async (context) => {
|
|
72460
|
+
const { workspaceId, grant, browserSessionId } = await browserRoutePreamble(
|
|
72461
|
+
context,
|
|
72462
|
+
"sessions:read"
|
|
72463
|
+
);
|
|
72464
|
+
const targetId = requireOpaqueParam(context, "targetId");
|
|
72465
|
+
const frame = await withActiveBrowserController(
|
|
72466
|
+
context,
|
|
72467
|
+
grant,
|
|
72468
|
+
workspaceId,
|
|
72469
|
+
browserSessionId,
|
|
72470
|
+
"session.read",
|
|
72471
|
+
"browser.read",
|
|
72472
|
+
async ({ sessionClient }) => await sessionClient.capture(targetId)
|
|
72473
|
+
);
|
|
72474
|
+
return new Response(frame.data.slice().buffer, {
|
|
72475
|
+
status: 200,
|
|
72476
|
+
headers: {
|
|
72477
|
+
"cache-control": "no-store",
|
|
72478
|
+
"content-type": frame.mediaType,
|
|
72479
|
+
"x-opengeni-browser-frame": frame.metadataHeader
|
|
72480
|
+
}
|
|
72481
|
+
});
|
|
72482
|
+
}
|
|
72483
|
+
);
|
|
72190
72484
|
app.post(
|
|
72191
72485
|
"/v1/workspaces/:workspaceId/browser-sessions/:browserSessionId/actions",
|
|
72192
72486
|
async (context) => {
|
|
@@ -72916,7 +73210,7 @@ function registerBrowserSessionRoutes(app, deps) {
|
|
|
72916
73210
|
if (!targets.some((target) => target.id === request.targetId)) {
|
|
72917
73211
|
throw new HTTPException51(404, { message: "browser target does not exist" });
|
|
72918
73212
|
}
|
|
72919
|
-
const grantId =
|
|
73213
|
+
const grantId = randomUUID7();
|
|
72920
73214
|
const expiresAt = new Date(Date.now() + request.expiresInSeconds * 1e3).toISOString();
|
|
72921
73215
|
const rootSecret = browserAuthorityRoot(deps);
|
|
72922
73216
|
const relaySecret = placement.session.openBrowserFrames ? resolveStreamTokenSecret2(deps.settings) : null;
|
|
@@ -73914,6 +74208,11 @@ function registerBrowserSessionRoutes(app, deps) {
|
|
|
73914
74208
|
const resolved = await handle.routingSession.prime();
|
|
73915
74209
|
if (expectedPlacement?.kind === "connected_machine") {
|
|
73916
74210
|
if (resolved.kind !== "selfhosted" || resolved.sandboxId !== expectedPlacement.sandboxId) {
|
|
74211
|
+
if (operation === "browser.create") {
|
|
74212
|
+
throw new HTTPException51(422, {
|
|
74213
|
+
message: "The requested Connected Machine is not this session's current placement. Move the session to that machine before creating an interaction resource."
|
|
74214
|
+
});
|
|
74215
|
+
}
|
|
73917
74216
|
return await throwBrowserSourcePlacementChanged(
|
|
73918
74217
|
grant,
|
|
73919
74218
|
sourceSession.id,
|
|
@@ -74629,6 +74928,10 @@ async function ensureInteractionHolder(deps, grant, sourceSession, browserSessio
|
|
|
74629
74928
|
holderId: interactionHolderId(browserSessionId),
|
|
74630
74929
|
subjectId: sourceSession.id,
|
|
74631
74930
|
backend: placement.lease.backend,
|
|
74931
|
+
warmBilling: {
|
|
74932
|
+
mode: deps.settings.sandboxWarmBillingMode,
|
|
74933
|
+
rateMicrosPerSecond: sandboxWarmRateMicrosPerSecond3(deps.settings, placement.lease.backend)
|
|
74934
|
+
},
|
|
74632
74935
|
os: placement.lease.os,
|
|
74633
74936
|
image: sandboxRuntime.image,
|
|
74634
74937
|
rigVersionId: sourceSession.rigVersionId,
|
|
@@ -74664,7 +74967,7 @@ async function ensureDispatchedGeneration(deps, grant, workspaceId, browserSessi
|
|
|
74664
74967
|
operationId
|
|
74665
74968
|
});
|
|
74666
74969
|
if (record6.operation?.state === "prepared") {
|
|
74667
|
-
const controllerGeneration =
|
|
74970
|
+
const controllerGeneration = randomUUID7();
|
|
74668
74971
|
try {
|
|
74669
74972
|
await dispatchBrowserSessionOperation(deps.db, {
|
|
74670
74973
|
accountId: grant.accountId,
|
|
@@ -75273,7 +75576,7 @@ async function finalizeBrowserDownloadFile(deps, grant, workspaceId, uploadId) {
|
|
|
75273
75576
|
throw new InteractionResourceStateError("Browser download file upload authority expired");
|
|
75274
75577
|
}
|
|
75275
75578
|
const pendingFile = upload.file;
|
|
75276
|
-
const head = await
|
|
75579
|
+
const head = await retryWhileMissing6(async () => {
|
|
75277
75580
|
if (!await objectStorage.fileExists(pendingFile)) return null;
|
|
75278
75581
|
return await objectStorage.headFile(pendingFile);
|
|
75279
75582
|
});
|
|
@@ -75312,6 +75615,8 @@ function browserRouteError(error) {
|
|
|
75312
75615
|
const connectedMachineError = interactionControlApiError(error, "browser");
|
|
75313
75616
|
if (connectedMachineError) return connectedMachineError;
|
|
75314
75617
|
if (error instanceof HTTPException51) return error;
|
|
75618
|
+
if (error instanceof SandboxPaidComputeAdmissionError3)
|
|
75619
|
+
return new HTTPException51(402, { message: error.message, cause: error });
|
|
75315
75620
|
if (error instanceof BrowserSessionNotFoundError) {
|
|
75316
75621
|
return new HTTPException51(404, { message: error.message, cause: error });
|
|
75317
75622
|
}
|
|
@@ -75364,8 +75669,12 @@ function isAbort(error) {
|
|
|
75364
75669
|
}
|
|
75365
75670
|
|
|
75366
75671
|
// src/routes/computer-sessions.ts
|
|
75367
|
-
import { randomUUID as
|
|
75368
|
-
import {
|
|
75672
|
+
import { randomUUID as randomUUID8 } from "crypto";
|
|
75673
|
+
import {
|
|
75674
|
+
resolveFirstPartyDelegationSecret as resolveFirstPartyDelegationSecret4,
|
|
75675
|
+
resolveStreamTokenSecret as resolveStreamTokenSecret3,
|
|
75676
|
+
sandboxWarmRateMicrosPerSecond as sandboxWarmRateMicrosPerSecond4
|
|
75677
|
+
} from "@opengeni/config";
|
|
75369
75678
|
import {
|
|
75370
75679
|
BROWSER_CONTROL_WEBSOCKET_BEARER_PREFIX as BROWSER_CONTROL_WEBSOCKET_BEARER_PREFIX2,
|
|
75371
75680
|
BROWSER_CONTROL_PORT as BROWSER_CONTROL_PORT2,
|
|
@@ -75392,6 +75701,7 @@ import {
|
|
|
75392
75701
|
ComputerSessionNotFoundError,
|
|
75393
75702
|
ComputerSessionOperationConflictError,
|
|
75394
75703
|
ComputerSessionStateError,
|
|
75704
|
+
SandboxPaidComputeAdmissionError as SandboxPaidComputeAdmissionError4,
|
|
75395
75705
|
dispatchComputerSessionOperation,
|
|
75396
75706
|
failComputerSessionOperation,
|
|
75397
75707
|
findComputerSessionControlRecordByOperation,
|
|
@@ -75888,7 +76198,7 @@ function registerComputerSessionRoutes(app, deps) {
|
|
|
75888
76198
|
retryable: false
|
|
75889
76199
|
});
|
|
75890
76200
|
}
|
|
75891
|
-
const grantId =
|
|
76201
|
+
const grantId = randomUUID8();
|
|
75892
76202
|
const expiresAt = new Date(Date.now() + request.expiresInSeconds * 1e3).toISOString();
|
|
75893
76203
|
const token = deriveComputerViewGrantToken({
|
|
75894
76204
|
rootSecret: controllerAuthorityRoot(deps),
|
|
@@ -76279,6 +76589,11 @@ function registerComputerSessionRoutes(app, deps) {
|
|
|
76279
76589
|
}
|
|
76280
76590
|
if (expectedPlacement?.kind === "connected_machine") {
|
|
76281
76591
|
if (resolved.kind !== "selfhosted" || resolved.sandboxId !== expectedPlacement.sandboxId) {
|
|
76592
|
+
if (operation === "computer.create") {
|
|
76593
|
+
throw new HTTPException52(422, {
|
|
76594
|
+
message: "The requested Connected Machine is not this session's current placement. Move the session to that machine before creating an interaction resource."
|
|
76595
|
+
});
|
|
76596
|
+
}
|
|
76282
76597
|
return await throwComputerSourcePlacementChanged(
|
|
76283
76598
|
grant,
|
|
76284
76599
|
sourceSession.id,
|
|
@@ -76565,6 +76880,10 @@ function registerComputerSessionRoutes(app, deps) {
|
|
|
76565
76880
|
holderId: interactionHolderId2(computerSessionId),
|
|
76566
76881
|
subjectId: sourceSession.id,
|
|
76567
76882
|
backend: placement.lease.backend,
|
|
76883
|
+
warmBilling: {
|
|
76884
|
+
mode: deps.settings.sandboxWarmBillingMode,
|
|
76885
|
+
rateMicrosPerSecond: sandboxWarmRateMicrosPerSecond4(deps.settings, placement.lease.backend)
|
|
76886
|
+
},
|
|
76568
76887
|
os: placement.lease.os,
|
|
76569
76888
|
image: sandboxRuntime.image,
|
|
76570
76889
|
rigVersionId: sourceSession.rigVersionId,
|
|
@@ -76599,7 +76918,7 @@ function registerComputerSessionRoutes(app, deps) {
|
|
|
76599
76918
|
operationId
|
|
76600
76919
|
});
|
|
76601
76920
|
if (record6.operation?.state === "prepared") {
|
|
76602
|
-
const controllerGeneration =
|
|
76921
|
+
const controllerGeneration = randomUUID8();
|
|
76603
76922
|
try {
|
|
76604
76923
|
await dispatchComputerSessionOperation(deps.db, {
|
|
76605
76924
|
accountId: grant.accountId,
|
|
@@ -76887,6 +77206,8 @@ function computerRouteError(error) {
|
|
|
76887
77206
|
const connectedMachineError = interactionControlApiError(error, "computer");
|
|
76888
77207
|
if (connectedMachineError) return connectedMachineError;
|
|
76889
77208
|
if (error instanceof HTTPException52) return error;
|
|
77209
|
+
if (error instanceof SandboxPaidComputeAdmissionError4)
|
|
77210
|
+
return new HTTPException52(402, { message: error.message, cause: error });
|
|
76890
77211
|
if (error instanceof ComputerSessionNotFoundError) {
|
|
76891
77212
|
return new HTTPException52(404, { message: error.message, cause: error });
|
|
76892
77213
|
}
|
|
@@ -78712,7 +79033,7 @@ import {
|
|
|
78712
79033
|
personalGitHubGitBrokerRouteId
|
|
78713
79034
|
} from "@opengeni/github";
|
|
78714
79035
|
import { readResponseTextBounded as readResponseTextBounded2 } from "@opengeni/network";
|
|
78715
|
-
import { randomUUID as
|
|
79036
|
+
import { randomUUID as randomUUID9 } from "crypto";
|
|
78716
79037
|
import JSONBig2 from "json-bigint";
|
|
78717
79038
|
var PERSONAL_GITHUB_SERVER_ID = "github:personal";
|
|
78718
79039
|
var GITHUB_API_VERSION3 = "2022-11-28";
|
|
@@ -78930,7 +79251,7 @@ async function authorizeBrokerProviderRequest(deps, authority, destinationUrl, o
|
|
|
78930
79251
|
turnId: claims.turnId,
|
|
78931
79252
|
attemptId: claims.attemptId,
|
|
78932
79253
|
executionGeneration: claims.executionGeneration,
|
|
78933
|
-
physicalRequestId:
|
|
79254
|
+
physicalRequestId: randomUUID9(),
|
|
78934
79255
|
usePhase: "credential_resolution"
|
|
78935
79256
|
}
|
|
78936
79257
|
});
|
|
@@ -78945,7 +79266,7 @@ async function authorizeBrokerProviderRequest(deps, authority, destinationUrl, o
|
|
|
78945
79266
|
turnId: claims.turnId,
|
|
78946
79267
|
attemptId: claims.attemptId,
|
|
78947
79268
|
executionGeneration: claims.executionGeneration,
|
|
78948
|
-
physicalRequestId:
|
|
79269
|
+
physicalRequestId: randomUUID9(),
|
|
78949
79270
|
usePhase: "provider_request",
|
|
78950
79271
|
serverId: PERSONAL_GITHUB_SERVER_ID,
|
|
78951
79272
|
connectionId: claims.connectionId,
|
|
@@ -83105,7 +83426,7 @@ import {
|
|
|
83105
83426
|
integrationSourceForOrganizationPolicy as integrationSourceForOrganizationPolicy2
|
|
83106
83427
|
} from "@opengeni/core";
|
|
83107
83428
|
import { withOrganizationIntegrationPolicyFence as withOrganizationIntegrationPolicyFence8 } from "@opengeni/db/organization-integration-policy";
|
|
83108
|
-
import { createHash as
|
|
83429
|
+
import { createHash as createHash20 } from "crypto";
|
|
83109
83430
|
import {
|
|
83110
83431
|
createPinnedIntegrationTransport as createPinnedIntegrationTransport3,
|
|
83111
83432
|
fetchIntegrationSourceDocument as fetchIntegrationSourceDocument2
|
|
@@ -83967,7 +84288,7 @@ function pluginFailureCode(error) {
|
|
|
83967
84288
|
return "component_install_failed";
|
|
83968
84289
|
}
|
|
83969
84290
|
function sha2562(value) {
|
|
83970
|
-
return
|
|
84291
|
+
return createHash20("sha256").update(value).digest("hex");
|
|
83971
84292
|
}
|
|
83972
84293
|
|
|
83973
84294
|
// src/routes/skills.ts
|
|
@@ -84002,14 +84323,14 @@ import {
|
|
|
84002
84323
|
SkillSourceRemovalAuthorityError as SkillSourceRemovalAuthorityError2
|
|
84003
84324
|
} from "@opengeni/db";
|
|
84004
84325
|
import { loadSkillLibrarySkill, skillLibraryRepositoryUrl } from "@opengeni/runtime/skill-library";
|
|
84005
|
-
import { createHash as
|
|
84326
|
+
import { createHash as createHash21 } from "crypto";
|
|
84006
84327
|
import { HTTPException as HTTPException67 } from "hono/http-exception";
|
|
84007
84328
|
|
|
84008
84329
|
// src/routes/skill-content.ts
|
|
84009
84330
|
import { z as z24 } from "zod";
|
|
84010
84331
|
import { HTTPException as HTTPException66 } from "hono/http-exception";
|
|
84011
|
-
import { SkillFile } from "@opengeni/contracts";
|
|
84012
|
-
import { readSkillRemovalScope } from "@opengeni/db";
|
|
84332
|
+
import { SkillFile, SKILL_MAX_FILES } from "@opengeni/contracts";
|
|
84333
|
+
import { getSessionForSubject, readSkillRemovalScope } from "@opengeni/db";
|
|
84013
84334
|
import {
|
|
84014
84335
|
approveSkill,
|
|
84015
84336
|
rejectSkill,
|
|
@@ -84375,8 +84696,8 @@ var saveRequest = z24.object({
|
|
|
84375
84696
|
expectedScopeVersion: z24.number().int().nonnegative(),
|
|
84376
84697
|
scope: scopeSchema.default("workspace"),
|
|
84377
84698
|
stableKey: z24.string().min(1).max(96),
|
|
84378
|
-
files: z24.array(SkillFile).max(
|
|
84379
|
-
deletions: z24.array(z24.string().min(1).max(512)).max(
|
|
84699
|
+
files: z24.array(SkillFile).max(SKILL_MAX_FILES),
|
|
84700
|
+
deletions: z24.array(z24.string().min(1).max(512)).max(SKILL_MAX_FILES).default([]),
|
|
84380
84701
|
reason: z24.string().min(1).max(2e3)
|
|
84381
84702
|
}).strict();
|
|
84382
84703
|
var revisionRequest = z24.object({
|
|
@@ -84405,9 +84726,20 @@ function registerSkillContentRoutes(app, deps) {
|
|
|
84405
84726
|
const grant = await requireAccessGrant27(c, deps, workspaceId, "workspace:read");
|
|
84406
84727
|
const query = z24.object({
|
|
84407
84728
|
limit: z24.coerce.number().int().min(1).max(250).default(100),
|
|
84408
|
-
cursor: z24.string().max(2048).optional()
|
|
84729
|
+
cursor: z24.string().max(2048).optional(),
|
|
84730
|
+
sessionId: z24.uuid().optional()
|
|
84409
84731
|
}).safeParse(c.req.query());
|
|
84410
84732
|
if (!query.success) throw new HTTPException66(422, { message: "Invalid Skill list query" });
|
|
84733
|
+
if (query.data.sessionId) {
|
|
84734
|
+
await requireAccessGrant27(c, deps, workspaceId, "sessions:read");
|
|
84735
|
+
const session = await getSessionForSubject(
|
|
84736
|
+
deps.db,
|
|
84737
|
+
workspaceId,
|
|
84738
|
+
query.data.sessionId,
|
|
84739
|
+
grant.subjectId
|
|
84740
|
+
);
|
|
84741
|
+
if (!session) throw new HTTPException66(404, { message: "Session not found" });
|
|
84742
|
+
}
|
|
84411
84743
|
let after;
|
|
84412
84744
|
if (query.data.cursor !== void 0) {
|
|
84413
84745
|
try {
|
|
@@ -84419,7 +84751,12 @@ function registerSkillContentRoutes(app, deps) {
|
|
|
84419
84751
|
const rows2 = await listSkills(
|
|
84420
84752
|
deps.db,
|
|
84421
84753
|
{ accountId: grant.accountId, workspaceId, subjectId: grant.subjectId },
|
|
84422
|
-
{
|
|
84754
|
+
{
|
|
84755
|
+
limit: query.data.limit + 1,
|
|
84756
|
+
metadataOnly: true,
|
|
84757
|
+
...after ? { after } : {},
|
|
84758
|
+
...query.data.sessionId ? { sessionId: query.data.sessionId } : {}
|
|
84759
|
+
}
|
|
84423
84760
|
);
|
|
84424
84761
|
const page = rows2.slice(0, query.data.limit);
|
|
84425
84762
|
const last = page.at(-1);
|
|
@@ -84626,7 +84963,7 @@ function registerSkillRoutes(app, deps, overrides = {}) {
|
|
|
84626
84963
|
path: file.path,
|
|
84627
84964
|
content: file.content,
|
|
84628
84965
|
byteSize: bytes.byteLength,
|
|
84629
|
-
contentSha256:
|
|
84966
|
+
contentSha256: createHash21("sha256").update(bytes).digest("hex")
|
|
84630
84967
|
};
|
|
84631
84968
|
});
|
|
84632
84969
|
try {
|
|
@@ -85587,7 +85924,7 @@ import {
|
|
|
85587
85924
|
readActiveSandbox as readActiveSandbox3,
|
|
85588
85925
|
deleteSessionTreeIfQuiescent,
|
|
85589
85926
|
getSessionEvent,
|
|
85590
|
-
getSessionForSubject,
|
|
85927
|
+
getSessionForSubject as getSessionForSubject2,
|
|
85591
85928
|
getSessionGoal as getSessionGoal2,
|
|
85592
85929
|
getLatestSessionModelContext,
|
|
85593
85930
|
getSessionHumanInputRequest,
|
|
@@ -87289,7 +87626,7 @@ function registerSessionRoutes(app, deps) {
|
|
|
87289
87626
|
if (!z27.string().uuid().safeParse(sessionId).success) {
|
|
87290
87627
|
throw new HTTPException72(404, { message: "session not found" });
|
|
87291
87628
|
}
|
|
87292
|
-
const session = await
|
|
87629
|
+
const session = await getSessionForSubject2(
|
|
87293
87630
|
db,
|
|
87294
87631
|
workspaceId,
|
|
87295
87632
|
sessionId,
|
|
@@ -87320,7 +87657,7 @@ function registerSessionRoutes(app, deps) {
|
|
|
87320
87657
|
if (!z27.string().uuid().safeParse(sessionId).success) {
|
|
87321
87658
|
throw new HTTPException72(404, { message: "session not found" });
|
|
87322
87659
|
}
|
|
87323
|
-
const session = await
|
|
87660
|
+
const session = await getSessionForSubject2(
|
|
87324
87661
|
db,
|
|
87325
87662
|
workspaceId,
|
|
87326
87663
|
sessionId,
|
|
@@ -88346,7 +88683,7 @@ function registerSessionRoutes(app, deps) {
|
|
|
88346
88683
|
}
|
|
88347
88684
|
throw error;
|
|
88348
88685
|
}
|
|
88349
|
-
const session = await
|
|
88686
|
+
const session = await getSessionForSubject2(
|
|
88350
88687
|
db,
|
|
88351
88688
|
workspaceId,
|
|
88352
88689
|
sessionId,
|
|
@@ -88421,7 +88758,7 @@ function registerSessionRoutes(app, deps) {
|
|
|
88421
88758
|
if (result.status === "updated") {
|
|
88422
88759
|
await publishDurableSessionEvents3(bus, workspaceId, sessionId, [result.event]);
|
|
88423
88760
|
}
|
|
88424
|
-
const session = await
|
|
88761
|
+
const session = await getSessionForSubject2(
|
|
88425
88762
|
db,
|
|
88426
88763
|
workspaceId,
|
|
88427
88764
|
sessionId,
|
|
@@ -88440,7 +88777,7 @@ function registerSessionRoutes(app, deps) {
|
|
|
88440
88777
|
await assertSessionExists(db, workspaceId, sessionId);
|
|
88441
88778
|
const payload = UpdateSessionRequest.parse(await c.req.json());
|
|
88442
88779
|
const titleUpdate = await updateSessionTitle2(deps, grant, sessionId, payload.title, "user");
|
|
88443
|
-
const session = await
|
|
88780
|
+
const session = await getSessionForSubject2(
|
|
88444
88781
|
db,
|
|
88445
88782
|
workspaceId,
|
|
88446
88783
|
sessionId,
|
|
@@ -91508,7 +91845,7 @@ import { SessionControlConflictError as SessionControlConflictError2, WorkspaceP
|
|
|
91508
91845
|
import { updateWorkspaceSettingsWithToolDefaults } from "@opengeni/db/workspace-tool-defaults";
|
|
91509
91846
|
import { WorkspacePauseTimerRequest } from "@opengeni/contracts";
|
|
91510
91847
|
import { getWorkspaceConnectionModelRestrictions } from "@opengeni/db";
|
|
91511
|
-
import { createHash as
|
|
91848
|
+
import { createHash as createHash22 } from "crypto";
|
|
91512
91849
|
import {
|
|
91513
91850
|
AddWorkspaceMemberRequest,
|
|
91514
91851
|
CreateWorkspaceRequest,
|
|
@@ -91775,7 +92112,7 @@ function projectWorkspaceOpenRouterCustomModel(model) {
|
|
|
91775
92112
|
});
|
|
91776
92113
|
}
|
|
91777
92114
|
function workspaceCustomModelRequestHash(value) {
|
|
91778
|
-
return
|
|
92115
|
+
return createHash22("sha256").update(stableJson7(value), "utf8").digest("hex");
|
|
91779
92116
|
}
|
|
91780
92117
|
function workspaceMembersResponse(members) {
|
|
91781
92118
|
return ListWorkspaceMembersResponse.parse({
|
|
@@ -92712,7 +93049,7 @@ function requireAccountPermission2(context, accountId, permission) {
|
|
|
92712
93049
|
}
|
|
92713
93050
|
|
|
92714
93051
|
// src/routes/workspace-instruction-policies.ts
|
|
92715
|
-
import { randomUUID as
|
|
93052
|
+
import { randomUUID as randomUUID10 } from "crypto";
|
|
92716
93053
|
import {
|
|
92717
93054
|
ActivateWorkspaceInstructionPolicyRequest,
|
|
92718
93055
|
CreateWorkspaceInstructionPolicyDraftRequest,
|
|
@@ -92878,7 +93215,7 @@ function registerWorkspaceInstructionPolicyRoutes(app, deps) {
|
|
|
92878
93215
|
return context.json(
|
|
92879
93216
|
WorkspaceInstructionPolicyRevision.parse(
|
|
92880
93217
|
await createWorkspaceInstructionPolicyDraft(deps.db, {
|
|
92881
|
-
operationId: request.operationId ??
|
|
93218
|
+
operationId: request.operationId ?? randomUUID10(),
|
|
92882
93219
|
accountId: grant.accountId,
|
|
92883
93220
|
workspaceId,
|
|
92884
93221
|
createdBySubjectId: grant.subjectId,
|
|
@@ -92906,7 +93243,7 @@ function registerWorkspaceInstructionPolicyRoutes(app, deps) {
|
|
|
92906
93243
|
return context.json(
|
|
92907
93244
|
WorkspaceInstructionPolicyRevision.parse(
|
|
92908
93245
|
await importLegacyWorkspaceInstructionPolicyDraft(deps.db, {
|
|
92909
|
-
operationId: request.operationId ??
|
|
93246
|
+
operationId: request.operationId ?? randomUUID10(),
|
|
92910
93247
|
accountId: grant.accountId,
|
|
92911
93248
|
workspaceId,
|
|
92912
93249
|
createdBySubjectId: grant.subjectId,
|
|
@@ -92948,7 +93285,7 @@ function registerWorkspaceInstructionPolicyRoutes(app, deps) {
|
|
|
92948
93285
|
return context.json(
|
|
92949
93286
|
WorkspaceInstructionPolicyOnboardingProposal.parse(
|
|
92950
93287
|
await createWorkspaceInstructionPolicyOnboardingProposal(deps.db, {
|
|
92951
|
-
operationId: request.operationId ??
|
|
93288
|
+
operationId: request.operationId ?? randomUUID10(),
|
|
92952
93289
|
accountId: grant.accountId,
|
|
92953
93290
|
workspaceId,
|
|
92954
93291
|
createdBySubjectId: grant.subjectId,
|
|
@@ -92998,7 +93335,7 @@ function registerWorkspaceInstructionPolicyRoutes(app, deps) {
|
|
|
92998
93335
|
return context.json(
|
|
92999
93336
|
WorkspaceInstructionPolicyActivationResponse.parse(
|
|
93000
93337
|
await rollbackWorkspaceInstructionPolicyRevision(deps.db, {
|
|
93001
|
-
operationId: request.operationId ??
|
|
93338
|
+
operationId: request.operationId ?? randomUUID10(),
|
|
93002
93339
|
accountId: grant.accountId,
|
|
93003
93340
|
workspaceId,
|
|
93004
93341
|
targetRevisionId: request.targetRevisionId,
|
|
@@ -93037,7 +93374,7 @@ function registerWorkspaceInstructionPolicyRoutes(app, deps) {
|
|
|
93037
93374
|
return context.json(
|
|
93038
93375
|
WorkspaceInstructionPolicyActivationResponse.parse(
|
|
93039
93376
|
await activateWorkspaceInstructionPolicyRevision(deps.db, {
|
|
93040
|
-
operationId: request.operationId ??
|
|
93377
|
+
operationId: request.operationId ?? randomUUID10(),
|
|
93041
93378
|
accountId: grant.accountId,
|
|
93042
93379
|
workspaceId,
|
|
93043
93380
|
revisionId: revisionId2,
|
|
@@ -93055,7 +93392,7 @@ function registerWorkspaceInstructionPolicyRoutes(app, deps) {
|
|
|
93055
93392
|
}
|
|
93056
93393
|
|
|
93057
93394
|
// src/routes/workspace-learning.ts
|
|
93058
|
-
import { randomUUID as
|
|
93395
|
+
import { randomUUID as randomUUID11 } from "crypto";
|
|
93059
93396
|
import {
|
|
93060
93397
|
UndoGovernedLearningActivationHttpRequest,
|
|
93061
93398
|
WorkspaceLearningHistoryResponse,
|
|
@@ -93178,7 +93515,7 @@ function registerWorkspaceLearningRoutes(app, deps) {
|
|
|
93178
93515
|
const undo = await undoGovernedLearningActivation(deps.db, {
|
|
93179
93516
|
caller: { workspaceId, subjectId: grant.subjectId },
|
|
93180
93517
|
request: {
|
|
93181
|
-
operationId: request.operationId ??
|
|
93518
|
+
operationId: request.operationId ?? randomUUID11(),
|
|
93182
93519
|
activationReceiptId: activationReceiptId.data
|
|
93183
93520
|
}
|
|
93184
93521
|
});
|
|
@@ -93193,7 +93530,7 @@ function registerWorkspaceLearningRoutes(app, deps) {
|
|
|
93193
93530
|
}
|
|
93194
93531
|
|
|
93195
93532
|
// src/routes/company-profile.ts
|
|
93196
|
-
import { randomUUID as
|
|
93533
|
+
import { randomUUID as randomUUID12 } from "crypto";
|
|
93197
93534
|
import {
|
|
93198
93535
|
ActivateCompanyProfileRevisionRequest,
|
|
93199
93536
|
CompanyProfileAgentPolicy,
|
|
@@ -93370,7 +93707,7 @@ function registerCompanyProfileRoutes(app, deps) {
|
|
|
93370
93707
|
return context.json(
|
|
93371
93708
|
CompanyProfileMutationResponse.parse(
|
|
93372
93709
|
await updateCompanyProfile(deps.db, {
|
|
93373
|
-
operationId: request.operationId ??
|
|
93710
|
+
operationId: request.operationId ?? randomUUID12(),
|
|
93374
93711
|
accountId: access.grant.accountId,
|
|
93375
93712
|
workspaceId,
|
|
93376
93713
|
profile: request.profile,
|
|
@@ -93422,7 +93759,7 @@ function registerCompanyProfileRoutes(app, deps) {
|
|
|
93422
93759
|
return context.json(
|
|
93423
93760
|
CompanyProfileMutationResponse.parse(
|
|
93424
93761
|
await rollbackCompanyProfileRevision(deps.db, {
|
|
93425
|
-
operationId: request.operationId ??
|
|
93762
|
+
operationId: request.operationId ?? randomUUID12(),
|
|
93426
93763
|
accountId: access.grant.accountId,
|
|
93427
93764
|
workspaceId,
|
|
93428
93765
|
targetRevisionId: request.targetRevisionId,
|
|
@@ -93469,7 +93806,7 @@ function registerCompanyProfileRoutes(app, deps) {
|
|
|
93469
93806
|
return context.json(
|
|
93470
93807
|
CompanyProfileMutationResponse.parse(
|
|
93471
93808
|
await activateCompanyProfileRevision(deps.db, {
|
|
93472
|
-
operationId: request.operationId ??
|
|
93809
|
+
operationId: request.operationId ?? randomUUID12(),
|
|
93473
93810
|
accountId: access.grant.accountId,
|
|
93474
93811
|
workspaceId,
|
|
93475
93812
|
revisionId: revisionId(context),
|
|
@@ -93488,7 +93825,7 @@ function registerCompanyProfileRoutes(app, deps) {
|
|
|
93488
93825
|
}
|
|
93489
93826
|
|
|
93490
93827
|
// src/routes/company-brain.ts
|
|
93491
|
-
import { createHash as
|
|
93828
|
+
import { createHash as createHash24 } from "crypto";
|
|
93492
93829
|
import {
|
|
93493
93830
|
COMPANY_BRAIN_INSPECTOR_CURSOR_MAX_CHARS,
|
|
93494
93831
|
COMPANY_BRAIN_INSPECTOR_DEFAULT_LIMIT,
|
|
@@ -93759,14 +94096,14 @@ function serializeCompanyBrainOkf(value) {
|
|
|
93759
94096
|
}
|
|
93760
94097
|
|
|
93761
94098
|
// src/workspace-state-projection.ts
|
|
93762
|
-
import { createHash as
|
|
94099
|
+
import { createHash as createHash23 } from "crypto";
|
|
93763
94100
|
import {
|
|
93764
94101
|
WORKSPACE_STATE_MAX_ACTIVE_POLICY_HEADS,
|
|
93765
94102
|
WORKSPACE_STATE_KNOWLEDGE_SAMPLE_LIMIT,
|
|
93766
94103
|
WorkspaceStateResponse
|
|
93767
94104
|
} from "@opengeni/contracts";
|
|
93768
94105
|
function hashIdentities(values) {
|
|
93769
|
-
return
|
|
94106
|
+
return createHash23("sha256").update(values.join("\n"), "utf8").digest("hex");
|
|
93770
94107
|
}
|
|
93771
94108
|
function policyTargetKey(value) {
|
|
93772
94109
|
return `${value.kind}:${value.scope}:${value.roleKey ?? ""}`;
|
|
@@ -93996,7 +94333,7 @@ var inspectorQuery = z32.object({
|
|
|
93996
94333
|
message: "attemptId cannot be combined with cursor"
|
|
93997
94334
|
});
|
|
93998
94335
|
function receiptCursorScope(workspaceId, subjectId) {
|
|
93999
|
-
return
|
|
94336
|
+
return createHash24("sha256").update("opengeni:company-brain-context-receipts:v1\0").update(workspaceId).update("\0").update(subjectId).digest("hex");
|
|
94000
94337
|
}
|
|
94001
94338
|
function encodeReceiptCursor(workspaceId, subjectId, cursor) {
|
|
94002
94339
|
return Buffer.from(
|
|
@@ -94212,7 +94549,7 @@ function registerCompanyBrainRoutes(app, deps) {
|
|
|
94212
94549
|
}
|
|
94213
94550
|
|
|
94214
94551
|
// src/routes/slack-task-policy.ts
|
|
94215
|
-
import { randomUUID as
|
|
94552
|
+
import { randomUUID as randomUUID13 } from "crypto";
|
|
94216
94553
|
import {
|
|
94217
94554
|
SlackTaskPolicyListResponse,
|
|
94218
94555
|
SlackTaskPolicyMutationResponse,
|
|
@@ -94295,7 +94632,7 @@ function registerSlackTaskPolicyRoutes(app, deps) {
|
|
|
94295
94632
|
return context.json(
|
|
94296
94633
|
SlackTaskPolicyMutationResponse.parse(
|
|
94297
94634
|
await updateSlackTaskPolicy(deps.db, {
|
|
94298
|
-
operationId: parsed.data.operationId ??
|
|
94635
|
+
operationId: parsed.data.operationId ?? randomUUID13(),
|
|
94299
94636
|
accountId: access.grant.accountId,
|
|
94300
94637
|
workspaceId,
|
|
94301
94638
|
policy: parsed.data.policy,
|
|
@@ -94334,7 +94671,7 @@ import {
|
|
|
94334
94671
|
import { HTTPException as HTTPException81 } from "hono/http-exception";
|
|
94335
94672
|
|
|
94336
94673
|
// src/workspace-state-export.ts
|
|
94337
|
-
import { createHash as
|
|
94674
|
+
import { createHash as createHash25 } from "crypto";
|
|
94338
94675
|
import {
|
|
94339
94676
|
WORKSPACE_STATE_EXPORT_SCHEMA_VERSION,
|
|
94340
94677
|
WorkspaceStateExportResponse
|
|
@@ -94365,7 +94702,7 @@ function createWorkspaceStateExport(state) {
|
|
|
94365
94702
|
kind: "opengeni.workspace_state.sanitized_export",
|
|
94366
94703
|
schemaVersion: WORKSPACE_STATE_EXPORT_SCHEMA_VERSION,
|
|
94367
94704
|
generatedAt: state.generatedAt,
|
|
94368
|
-
stateSha256:
|
|
94705
|
+
stateSha256: createHash25("sha256").update(canonicalState, "utf8").digest("hex"),
|
|
94369
94706
|
omissions: WORKSPACE_STATE_EXPORT_OMISSIONS,
|
|
94370
94707
|
state
|
|
94371
94708
|
});
|
|
@@ -94473,7 +94810,7 @@ function registerWorkspaceStateRoutes(app, deps) {
|
|
|
94473
94810
|
}
|
|
94474
94811
|
|
|
94475
94812
|
// src/routes/workspace-artifacts.ts
|
|
94476
|
-
import { createHash as
|
|
94813
|
+
import { createHash as createHash26 } from "crypto";
|
|
94477
94814
|
import {
|
|
94478
94815
|
CreateWorkspaceArtifactRequest,
|
|
94479
94816
|
PublishWorkspaceArtifactVersionRequest,
|
|
@@ -94565,7 +94902,7 @@ function prepareContent(deps, grant, input) {
|
|
|
94565
94902
|
}
|
|
94566
94903
|
function provenance(subjectId, idempotencyKey) {
|
|
94567
94904
|
return {
|
|
94568
|
-
operationKey: `subject:${
|
|
94905
|
+
operationKey: `subject:${createHash26("sha256").update(`${subjectId}:${idempotencyKey}`).digest("hex")}`,
|
|
94569
94906
|
actorSubjectId: subjectId,
|
|
94570
94907
|
sourceSessionId: null,
|
|
94571
94908
|
sourceTurnId: null,
|
|
@@ -94924,7 +95261,7 @@ import {
|
|
|
94924
95261
|
import { HTTPException as HTTPException84 } from "hono/http-exception";
|
|
94925
95262
|
|
|
94926
95263
|
// src/artifact-catalog-cursor.ts
|
|
94927
|
-
import { createCipheriv as createCipheriv3, createDecipheriv as createDecipheriv3, createHash as
|
|
95264
|
+
import { createCipheriv as createCipheriv3, createDecipheriv as createDecipheriv3, createHash as createHash27, randomBytes as randomBytes11 } from "crypto";
|
|
94928
95265
|
import { ArtifactCatalogKind } from "@opengeni/contracts";
|
|
94929
95266
|
import { HTTPException as HTTPException83 } from "hono/http-exception";
|
|
94930
95267
|
import { z as z34 } from "zod";
|
|
@@ -94939,8 +95276,8 @@ var Cursor = z34.object({
|
|
|
94939
95276
|
}).strict()
|
|
94940
95277
|
}).strict();
|
|
94941
95278
|
function artifactCatalogCursorCodec(secret, binding) {
|
|
94942
|
-
const key =
|
|
94943
|
-
const aad =
|
|
95279
|
+
const key = createHash27("sha256").update("opengeni:artifact-catalog:v1\0").update(secret).digest();
|
|
95280
|
+
const aad = createHash27("sha256").update(binding).digest();
|
|
94944
95281
|
return {
|
|
94945
95282
|
encode(value) {
|
|
94946
95283
|
const iv = randomBytes11(12);
|
|
@@ -95257,7 +95594,7 @@ import { requireAccessGrant as requireAccessGrant43, TranscriptionServiceError a
|
|
|
95257
95594
|
import { getWorkspace as getWorkspace6 } from "@opengeni/db";
|
|
95258
95595
|
|
|
95259
95596
|
// src/routes/transcription-recordings.ts
|
|
95260
|
-
import { createHash as
|
|
95597
|
+
import { createHash as createHash28 } from "crypto";
|
|
95261
95598
|
import {
|
|
95262
95599
|
CreateTranscriptionRecordingRequest,
|
|
95263
95600
|
FinalizeTranscriptionRecordingRequest,
|
|
@@ -95273,7 +95610,7 @@ import {
|
|
|
95273
95610
|
TRANSCRIPTION_PROVIDER_REQUEST_TIMEOUT_MILLISECONDS,
|
|
95274
95611
|
TranscriptionServiceError
|
|
95275
95612
|
} from "@opengeni/core";
|
|
95276
|
-
import { retryWhileMissing as
|
|
95613
|
+
import { retryWhileMissing as retryWhileMissing7 } from "@opengeni/storage";
|
|
95277
95614
|
import {
|
|
95278
95615
|
claimNextTranscriptionRecordingSegment,
|
|
95279
95616
|
claimTranscriptionRecordingAssembly,
|
|
@@ -95859,7 +96196,7 @@ function registerResumableTranscriptionRoutes(app, deps) {
|
|
|
95859
96196
|
attemptedProvider = claim.segment.providerId;
|
|
95860
96197
|
fallbackAllowed = claim.fallbackAllowed === true;
|
|
95861
96198
|
const segmentKey = claim.segment.objectKey;
|
|
95862
|
-
const stored = deps.objectStorage ? await
|
|
96199
|
+
const stored = deps.objectStorage ? await retryWhileMissing7(async () => deps.objectStorage.getObjectBytes(segmentKey)) : null;
|
|
95863
96200
|
if (!stored) {
|
|
95864
96201
|
throw new RecordingProcessingError("Provider segment is missing", "invalid_audio", false);
|
|
95865
96202
|
}
|
|
@@ -96018,7 +96355,7 @@ async function* verifiedChunkBytes(deps, chunks, signal) {
|
|
|
96018
96355
|
}
|
|
96019
96356
|
let stored;
|
|
96020
96357
|
try {
|
|
96021
|
-
stored = await
|
|
96358
|
+
stored = await retryWhileMissing7(
|
|
96022
96359
|
async () => deps.objectStorage.getObjectBytes(chunk.objectKey)
|
|
96023
96360
|
);
|
|
96024
96361
|
} catch {
|
|
@@ -96102,7 +96439,7 @@ function valueAsUuid(value) {
|
|
|
96102
96439
|
if (/^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(value)) {
|
|
96103
96440
|
return value;
|
|
96104
96441
|
}
|
|
96105
|
-
const hex2 =
|
|
96442
|
+
const hex2 = createHash28("sha256").update(value).digest("hex").slice(0, 32);
|
|
96106
96443
|
return `${hex2.slice(0, 8)}-${hex2.slice(8, 12)}-4${hex2.slice(13, 16)}-a${hex2.slice(17, 20)}-${hex2.slice(20, 32)}`;
|
|
96107
96444
|
}
|
|
96108
96445
|
function nonnegativeInteger(value) {
|
|
@@ -96166,7 +96503,7 @@ async function readBoundedBody(request, maxBytes) {
|
|
|
96166
96503
|
return body3;
|
|
96167
96504
|
}
|
|
96168
96505
|
function sha256Hex3(bytes) {
|
|
96169
|
-
return
|
|
96506
|
+
return createHash28("sha256").update(bytes).digest("hex");
|
|
96170
96507
|
}
|
|
96171
96508
|
|
|
96172
96509
|
// src/routes/transcriptions.ts
|
|
@@ -96457,7 +96794,7 @@ function videoGenerationFundingOptions(input) {
|
|
|
96457
96794
|
}
|
|
96458
96795
|
|
|
96459
96796
|
// src/routes/canonical-human-identities.ts
|
|
96460
|
-
import { randomUUID as
|
|
96797
|
+
import { randomUUID as randomUUID15 } from "crypto";
|
|
96461
96798
|
import {
|
|
96462
96799
|
CanonicalHumanBindingOperationRequest,
|
|
96463
96800
|
CanonicalHumanIdentityMutationResponse,
|
|
@@ -96506,7 +96843,7 @@ import { HTTPException as HTTPException88 } from "hono/http-exception";
|
|
|
96506
96843
|
import { z as z36 } from "zod";
|
|
96507
96844
|
|
|
96508
96845
|
// src/routes/managed-auth-session-sets.ts
|
|
96509
|
-
import { randomUUID as
|
|
96846
|
+
import { randomUUID as randomUUID14 } from "crypto";
|
|
96510
96847
|
import {
|
|
96511
96848
|
BeginManagedAuthLoginTransactionRequest,
|
|
96512
96849
|
BootstrapManagedAuthSessionSetRequest,
|
|
@@ -96717,7 +97054,7 @@ function registerManagedAuthSessionSetRoutes(app, deps) {
|
|
|
96717
97054
|
app.post("/v1/auth/session-set/transactions", async (context) => {
|
|
96718
97055
|
const body3 = await bodyAs(context, BeginManagedAuthLoginTransactionRequest);
|
|
96719
97056
|
const { authority, actorEpoch } = await requireMutation(context, deps, body3.expectedGeneration);
|
|
96720
|
-
const transactionId =
|
|
97057
|
+
const transactionId = randomUUID14();
|
|
96721
97058
|
const transactionSecret = managedAuthTransactionSecret(
|
|
96722
97059
|
requireSigningSecret(deps),
|
|
96723
97060
|
authority,
|
|
@@ -97938,7 +98275,7 @@ function registerCanonicalHumanIdentityRoutes(app, deps) {
|
|
|
97938
98275
|
return await mutate(context, deps, {
|
|
97939
98276
|
operationType: "link",
|
|
97940
98277
|
...request,
|
|
97941
|
-
operationId: request.operationId ??
|
|
98278
|
+
operationId: request.operationId ?? randomUUID15()
|
|
97942
98279
|
});
|
|
97943
98280
|
});
|
|
97944
98281
|
app.delete(`${base}/login-bindings/:bindingId`, async (context) => {
|
|
@@ -97956,7 +98293,7 @@ function registerCanonicalHumanIdentityRoutes(app, deps) {
|
|
|
97956
98293
|
operationType: "unlink",
|
|
97957
98294
|
bindingId: bindingId(context),
|
|
97958
98295
|
...request,
|
|
97959
|
-
operationId: request.operationId ??
|
|
98296
|
+
operationId: request.operationId ?? randomUUID15()
|
|
97960
98297
|
});
|
|
97961
98298
|
});
|
|
97962
98299
|
app.post(`${base}/login-bindings/:bindingId/recovery`, async (context) => {
|
|
@@ -97974,7 +98311,7 @@ function registerCanonicalHumanIdentityRoutes(app, deps) {
|
|
|
97974
98311
|
operationType: "begin_recovery",
|
|
97975
98312
|
bindingId: bindingId(context),
|
|
97976
98313
|
...request,
|
|
97977
|
-
operationId: request.operationId ??
|
|
98314
|
+
operationId: request.operationId ?? randomUUID15()
|
|
97978
98315
|
});
|
|
97979
98316
|
});
|
|
97980
98317
|
app.post(`${base}/login-bindings/:bindingId/recovery/complete`, async (context) => {
|
|
@@ -97989,7 +98326,7 @@ function registerCanonicalHumanIdentityRoutes(app, deps) {
|
|
|
97989
98326
|
operationType: "recover",
|
|
97990
98327
|
bindingId: bindingId(context),
|
|
97991
98328
|
...request,
|
|
97992
|
-
operationId: request.operationId ??
|
|
98329
|
+
operationId: request.operationId ?? randomUUID15(),
|
|
97993
98330
|
...managed ? { verifiedManagedRecovery: true } : {}
|
|
97994
98331
|
});
|
|
97995
98332
|
});
|
|
@@ -98195,7 +98532,8 @@ function registerOrganizationMembershipRoutes(app, deps) {
|
|
|
98195
98532
|
await createManagedOrganization(deps.db, {
|
|
98196
98533
|
subjectId,
|
|
98197
98534
|
subjectLabel: session.user.email || session.user.name,
|
|
98198
|
-
...payload
|
|
98535
|
+
...payload,
|
|
98536
|
+
trialCreditsEnabled: deps.settings.productAccessMode === "managed" && deps.settings.verifiedSignupTrialCreditsEnabled
|
|
98199
98537
|
})
|
|
98200
98538
|
),
|
|
98201
98539
|
201
|
|
@@ -99407,7 +99745,8 @@ function registerManagedOnboardingRoutes(app, deps, options = {}) {
|
|
|
99407
99745
|
actorSubjectId: `user:${session.user.id}`,
|
|
99408
99746
|
organizationName,
|
|
99409
99747
|
operationId: parsed.data.operationId,
|
|
99410
|
-
requestFingerprint
|
|
99748
|
+
requestFingerprint,
|
|
99749
|
+
trialCreditsEnabled: deps.settings.productAccessMode === "managed" && deps.settings.verifiedSignupTrialCreditsEnabled
|
|
99411
99750
|
})
|
|
99412
99751
|
)
|
|
99413
99752
|
);
|
|
@@ -100297,11 +100636,12 @@ async function exactAvailable(providers, providerId, context) {
|
|
|
100297
100636
|
}
|
|
100298
100637
|
|
|
100299
100638
|
// src/integrations/slack-interactions.ts
|
|
100300
|
-
import { createHash as
|
|
100639
|
+
import { createHash as createHash30, createHmac as createHmac10, timingSafeEqual as timingSafeEqual3 } from "crypto";
|
|
100301
100640
|
import {
|
|
100302
100641
|
approvalIdentifier,
|
|
100303
100642
|
ApproveSlackUserLinkAccessRequest,
|
|
100304
100643
|
DEFAULT_FIRST_PARTY_MCP_TOOLS,
|
|
100644
|
+
resolveWorkspaceSessionToolDefaults,
|
|
100305
100645
|
hasOpenGeniSlackReactionScope,
|
|
100306
100646
|
ListSlackUserLinkAccessRequestsResponse,
|
|
100307
100647
|
PrepareSlackUserLinkAccessRequest,
|
|
@@ -100341,6 +100681,7 @@ import {
|
|
|
100341
100681
|
getOrCreateSlackInteraction,
|
|
100342
100682
|
getLatestSessionModelForSubject,
|
|
100343
100683
|
getSession as getSession11,
|
|
100684
|
+
getSessionByCreateIdempotencyKey,
|
|
100344
100685
|
getSessionEvent as getSessionEvent2,
|
|
100345
100686
|
getSessionHumanInputRequest as getSessionHumanInputRequest2,
|
|
100346
100687
|
childRequiresActionResolutionExists,
|
|
@@ -100400,6 +100741,7 @@ import {
|
|
|
100400
100741
|
acceptSessionUserMessage as acceptSessionUserMessage2,
|
|
100401
100742
|
controlHumanSessionWorkstream as controlHumanSessionWorkstream2,
|
|
100402
100743
|
createSessionForRequest as createSessionForRequest2,
|
|
100744
|
+
getActorNewSessionDefaults,
|
|
100403
100745
|
hasPermission as hasPermission26,
|
|
100404
100746
|
requireAccessContext as requireAccessContext8,
|
|
100405
100747
|
requireAccessGrant as requireAccessGrant45,
|
|
@@ -100775,9 +101117,9 @@ function record4(value) {
|
|
|
100775
101117
|
}
|
|
100776
101118
|
|
|
100777
101119
|
// src/slack-reaction-files.ts
|
|
100778
|
-
import { createHash as
|
|
101120
|
+
import { createHash as createHash29 } from "crypto";
|
|
100779
101121
|
import { completeFileUpload as completeFileUpload5, prepareGeneratedWorkspaceFile as prepareGeneratedWorkspaceFile2 } from "@opengeni/db";
|
|
100780
|
-
import { retryWhileMissing as
|
|
101122
|
+
import { retryWhileMissing as retryWhileMissing8 } from "@opengeni/storage";
|
|
100781
101123
|
var IMPORT_IDENTITY_VERSION = "slack-reaction-image-v1";
|
|
100782
101124
|
var UPLOAD_INTENT_TTL_MS2 = 60 * 6e4;
|
|
100783
101125
|
var UUID_PATTERN2 = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/u;
|
|
@@ -100792,7 +101134,7 @@ async function importSlackReactionImage(dependencies, source, image, ordinal) {
|
|
|
100792
101134
|
if (image.bytes.byteLength < 1 || image.bytes.byteLength > 4 * 1024 * 1024) {
|
|
100793
101135
|
throw new Error("Slack reaction image size is invalid");
|
|
100794
101136
|
}
|
|
100795
|
-
const sha2563 =
|
|
101137
|
+
const sha2563 = createHash29("sha256").update(image.bytes).digest("hex");
|
|
100796
101138
|
const identity2 = slackReactionImageIdentity(source, image.fileId);
|
|
100797
101139
|
const fileId = deterministicUuid(`${identity2}:file`);
|
|
100798
101140
|
const uploadId = deterministicUuid(`${identity2}:upload`);
|
|
@@ -100877,7 +101219,7 @@ function safeSlackImageFilename(value, contentType) {
|
|
|
100877
101219
|
return `${stem}${extension}`;
|
|
100878
101220
|
}
|
|
100879
101221
|
async function assertVisibleSlackImage(storage, objectKey, image, sha2563) {
|
|
100880
|
-
const head = await
|
|
101222
|
+
const head = await retryWhileMissing8(async () => await storage.headObject(objectKey));
|
|
100881
101223
|
assertStoredSlackImage(head, image, sha2563);
|
|
100882
101224
|
}
|
|
100883
101225
|
function assertStoredSlackImage(head, image, sha2563) {
|
|
@@ -100886,7 +101228,7 @@ function assertStoredSlackImage(head, image, sha2563) {
|
|
|
100886
101228
|
}
|
|
100887
101229
|
}
|
|
100888
101230
|
function deterministicUuid(seed) {
|
|
100889
|
-
const bytes =
|
|
101231
|
+
const bytes = createHash29("sha256").update(seed, "utf8").digest().subarray(0, 16);
|
|
100890
101232
|
bytes[6] = (bytes[6] ?? 0) & 15 | 80;
|
|
100891
101233
|
bytes[8] = (bytes[8] ?? 0) & 63 | 128;
|
|
100892
101234
|
const hex2 = bytes.toString("hex");
|
|
@@ -101045,7 +101387,7 @@ function slackReactionInboxEntry(payload, bot, settings) {
|
|
|
101045
101387
|
if (!settings.enabled || !event || event.type !== "reaction_added" || item?.type !== "message" || !teamId || !eventId || !userId || userId === bot.botUserId || !reaction || reaction !== settings.emoji || !channelId || !workspaceSlackReactionChannelAllowed(settings, channelId) || !timestamp) {
|
|
101046
101388
|
return null;
|
|
101047
101389
|
}
|
|
101048
|
-
const stableReactionIdentity =
|
|
101390
|
+
const stableReactionIdentity = createHash30("sha256").update([teamId, userId, channelId, timestamp, reaction].join("\n")).digest("hex");
|
|
101049
101391
|
return {
|
|
101050
101392
|
providerEventId: eventId,
|
|
101051
101393
|
providerMessageId: `reaction:${stableReactionIdentity}`,
|
|
@@ -101235,7 +101577,7 @@ function registerSlackInteractionRoutes(app, deps) {
|
|
|
101235
101577
|
const prepared = await prepareSlackUserLinkAccessRequest(deps.db, {
|
|
101236
101578
|
accountId: installation.accountId,
|
|
101237
101579
|
workspaceId,
|
|
101238
|
-
tokenDigest:
|
|
101580
|
+
tokenDigest: createHash30("sha256").update(payload.linkToken).digest("hex"),
|
|
101239
101581
|
connectionId: link.connectionId,
|
|
101240
101582
|
slackTeamId: link.slackTeamId,
|
|
101241
101583
|
slackUserId: link.slackUserId,
|
|
@@ -101442,7 +101784,7 @@ function registerSlackInteractionRoutes(app, deps) {
|
|
|
101442
101784
|
const prepared = await prepareSlackUserLinkAccessRequest(deps.db, {
|
|
101443
101785
|
accountId: grant.accountId,
|
|
101444
101786
|
workspaceId,
|
|
101445
|
-
tokenDigest:
|
|
101787
|
+
tokenDigest: createHash30("sha256").update(linkToken).digest("hex"),
|
|
101446
101788
|
connectionId: link.connectionId,
|
|
101447
101789
|
slackTeamId: link.slackTeamId,
|
|
101448
101790
|
slackUserId: link.slackUserId,
|
|
@@ -102405,6 +102747,14 @@ async function processSlackInboxEntry(deps, entry2) {
|
|
|
102405
102747
|
);
|
|
102406
102748
|
let session;
|
|
102407
102749
|
try {
|
|
102750
|
+
const defaults = await slackNewSessionDefaults(
|
|
102751
|
+
deps,
|
|
102752
|
+
grant,
|
|
102753
|
+
interaction,
|
|
102754
|
+
`slack:${entry2.connectionId}:${entry2.providerEventId}`
|
|
102755
|
+
);
|
|
102756
|
+
const workspace = await getWorkspace7(deps.db, interaction.workspaceId);
|
|
102757
|
+
const defaultTools = defaults.firstPartyMcpTools ?? resolveWorkspaceSessionToolDefaults(workspace?.settings)?.firstPartyMcpTools;
|
|
102408
102758
|
const prepared = slackInvocationPreparedMessage(
|
|
102409
102759
|
preparedEntry,
|
|
102410
102760
|
preparedAttachments,
|
|
@@ -102415,13 +102765,14 @@ async function processSlackInboxEntry(deps, entry2) {
|
|
|
102415
102765
|
grant,
|
|
102416
102766
|
interaction.workspaceId,
|
|
102417
102767
|
{
|
|
102768
|
+
...defaults,
|
|
102418
102769
|
requestedSessionId: interaction.sessionReservationId,
|
|
102419
102770
|
initialMessage: prepared.entry.text,
|
|
102420
102771
|
...prepared.modelContext ? { modelContext: prepared.modelContext } : {},
|
|
102421
102772
|
instructions: SLACK_SESSION_INSTRUCTIONS,
|
|
102422
|
-
firstPartyMcpTools: slackTaskFirstPartyMcpTools(deps.settings),
|
|
102423
|
-
resources: preparedAttachments.resources,
|
|
102424
|
-
|
|
102773
|
+
firstPartyMcpTools: defaultTools !== void 0 ? allowedFirstPartyMcpToolsForSession4(deps.settings, defaultTools) : slackTaskFirstPartyMcpTools(deps.settings),
|
|
102774
|
+
resources: [...defaults.resources, ...preparedAttachments.resources],
|
|
102775
|
+
...!defaults.model && preferredModel ? { model: preferredModel } : {},
|
|
102425
102776
|
idempotencyKey: `slack:${entry2.connectionId}:${entry2.providerEventId}`,
|
|
102426
102777
|
clientEventId: `slack:${entry2.providerEventId}`
|
|
102427
102778
|
}
|
|
@@ -102842,19 +103193,25 @@ async function processSlackReactionInboxEntry(deps, entry2) {
|
|
|
102842
103193
|
const preparedEntry = slackReactionPreparedEntry(entry2, context, preparedTask);
|
|
102843
103194
|
let session;
|
|
102844
103195
|
try {
|
|
103196
|
+
const defaults = await slackNewSessionDefaults(
|
|
103197
|
+
deps,
|
|
103198
|
+
grant,
|
|
103199
|
+
interaction,
|
|
103200
|
+
`slack-interaction:${interaction.id}`
|
|
103201
|
+
);
|
|
102845
103202
|
session = await createSessionForRequest2(
|
|
102846
103203
|
await withCatalogSettings(deps, grant),
|
|
102847
103204
|
grant,
|
|
102848
103205
|
interaction.workspaceId,
|
|
102849
103206
|
{
|
|
103207
|
+
...defaults,
|
|
102850
103208
|
requestedSessionId: interaction.sessionReservationId,
|
|
102851
103209
|
initialMessage: preparedEntry.text,
|
|
102852
103210
|
instructions: SLACK_SESSION_INSTRUCTIONS,
|
|
102853
|
-
//
|
|
102854
|
-
//
|
|
102855
|
-
|
|
102856
|
-
|
|
102857
|
-
...preferredModel ? { model: preferredModel } : {},
|
|
103211
|
+
// Reaction context stays bounded; ordinary tools follow the same saved
|
|
103212
|
+
// selection/workspace defaults as the website, without adding Slack tools.
|
|
103213
|
+
resources: [...defaults.resources, ...preparedTask.resources],
|
|
103214
|
+
...!defaults.model && preferredModel ? { model: preferredModel } : {},
|
|
102858
103215
|
// Every reaction entry converging on this route must use the same create
|
|
102859
103216
|
// key. This closes the same-owner multi-event race while the owner check
|
|
102860
103217
|
// above prevents a different subject from winning creation authority.
|
|
@@ -102904,6 +103261,35 @@ function slackReactionPreparedEntry(entry2, context, prepared) {
|
|
|
102904
103261
|
text: slackReactionTaskText(context, prepared)
|
|
102905
103262
|
};
|
|
102906
103263
|
}
|
|
103264
|
+
async function slackNewSessionDefaults(deps, grant, interaction, createKey) {
|
|
103265
|
+
const pending = await getSessionByCreateIdempotencyKey(
|
|
103266
|
+
deps.db,
|
|
103267
|
+
interaction.workspaceId,
|
|
103268
|
+
createKey
|
|
103269
|
+
);
|
|
103270
|
+
if (!pending) return getActorNewSessionDefaults(deps, grant, interaction.workspaceId);
|
|
103271
|
+
if (pending.id !== interaction.sessionReservationId || interaction.owningSubjectId !== grant.subjectId || pending.createdBy.kind !== "subject" || pending.createdBy.subjectId !== grant.subjectId) {
|
|
103272
|
+
throw new SlackInteractionPermanentError("slack_session_create_identity_mismatch");
|
|
103273
|
+
}
|
|
103274
|
+
return {
|
|
103275
|
+
model: pending.model,
|
|
103276
|
+
reasoningEffort: pending.reasoningEffort,
|
|
103277
|
+
latencyMode: pending.latencyMode,
|
|
103278
|
+
resources: pending.resources.filter((resource) => resource.kind === "repository"),
|
|
103279
|
+
...pending.toolPolicy.mode === "explicit" ? { tools: pending.tools } : {
|
|
103280
|
+
excludedMcpServerIds: pending.toolPolicy.excludedMcpServerIds
|
|
103281
|
+
},
|
|
103282
|
+
firstPartyMcpTools: pending.firstPartyMcpTools,
|
|
103283
|
+
...pending.firstPartyMcpPermissions ? { firstPartyMcpPermissions: pending.firstPartyMcpPermissions } : {},
|
|
103284
|
+
variableSetIds: pending.variableSetIds,
|
|
103285
|
+
...pending.rigId ? { rigId: pending.rigId } : {},
|
|
103286
|
+
sandboxBackend: pending.sandboxBackend,
|
|
103287
|
+
...pending.sandboxBackend === "selfhosted" && pending.activeSandboxId ? {
|
|
103288
|
+
targetSandboxId: pending.activeSandboxId,
|
|
103289
|
+
...pending.workingDir ? { workingDir: pending.workingDir } : {}
|
|
103290
|
+
} : {}
|
|
103291
|
+
};
|
|
103292
|
+
}
|
|
102907
103293
|
async function remountSlackReactionTaskForSession(deps, workspaceId, sessionId, prepared) {
|
|
102908
103294
|
if (prepared.attachments.length === 0) return prepared;
|
|
102909
103295
|
const session = await getSession11(deps.db, workspaceId, sessionId);
|
|
@@ -104335,7 +104721,7 @@ function normalizedBlockActionInteraction(payload) {
|
|
|
104335
104721
|
if (!teamId || !userId || !channelId || !messageTs || !actionTs || !actionId || !SLACK_BLOCK_ACTION_IDS.has(actionId) || !handleId || !/^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(handleId) || !Array.isArray(payload.actions) || payload.actions.length !== 1) {
|
|
104336
104722
|
throw new HTTPException95(400, { message: "invalid Slack block action" });
|
|
104337
104723
|
}
|
|
104338
|
-
const identity2 =
|
|
104724
|
+
const identity2 = createHash30("sha256").update([teamId, userId, channelId, messageTs, actionTs, actionId, handleId].join("\n")).digest("hex");
|
|
104339
104725
|
return {
|
|
104340
104726
|
providerEventId: `block:${identity2}`,
|
|
104341
104727
|
providerMessageId: `block:${identity2}`,
|
|
@@ -104600,7 +104986,7 @@ function usesPrivateBotDm(interaction, entry2) {
|
|
|
104600
104986
|
return isDirectMessageShortcut(entry2) || interaction.visibility === "private" && entry2.triggerKind !== "dm";
|
|
104601
104987
|
}
|
|
104602
104988
|
function deterministicUuid2(value) {
|
|
104603
|
-
const bytes =
|
|
104989
|
+
const bytes = createHash30("sha256").update(value).digest().subarray(0, 16);
|
|
104604
104990
|
bytes[6] = bytes[6] & 15 | 80;
|
|
104605
104991
|
bytes[8] = bytes[8] & 63 | 128;
|
|
104606
104992
|
const hex2 = bytes.toString("hex");
|
|
@@ -104825,7 +105211,7 @@ function createAppComposition(deps) {
|
|
|
104825
105211
|
}) : deps.transcriptionSegmenter;
|
|
104826
105212
|
const routeDeps = {
|
|
104827
105213
|
...deps,
|
|
104828
|
-
resolveCatalogSettings: () =>
|
|
105214
|
+
resolveCatalogSettings: () => resolveCatalogSettings2(deps.db, deps.settings),
|
|
104829
105215
|
observability,
|
|
104830
105216
|
githubStateSecret: deps.githubStateSecret ?? deps.settings.githubAppManifestStateSecret ?? crypto.randomUUID(),
|
|
104831
105217
|
managedAuth,
|
|
@@ -105255,9 +105641,9 @@ function createAppComposition(deps) {
|
|
|
105255
105641
|
registerMcpOAuthRoutes(app, routeDeps);
|
|
105256
105642
|
app.get("/v1/config/client", async (c) => {
|
|
105257
105643
|
c.header("cache-control", "no-store");
|
|
105258
|
-
const resolvedCatalog = await
|
|
105644
|
+
const resolvedCatalog = await resolveCatalogSettings2(deps.db, deps.settings);
|
|
105259
105645
|
const baseCatalogSettings = resolvedCatalog.settings;
|
|
105260
|
-
const codexCatalogSettings = baseCatalogSettings.codexSubscriptionEnabled ?
|
|
105646
|
+
const codexCatalogSettings = baseCatalogSettings.codexSubscriptionEnabled ? withCodexCatalogProvider3(baseCatalogSettings) : baseCatalogSettings;
|
|
105261
105647
|
const catalogSettings = baseCatalogSettings.supergrokSubscriptionEnabled ? withXaiSubscriptionCatalogProvider3(codexCatalogSettings) : codexCatalogSettings;
|
|
105262
105648
|
return c.json(
|
|
105263
105649
|
ClientConfig.parse({
|
|
@@ -105270,7 +105656,7 @@ function createAppComposition(deps) {
|
|
|
105270
105656
|
// union of the built-in allow-list and every registry provider's models, in
|
|
105271
105657
|
// selection order (default model first); project each to the client-safe
|
|
105272
105658
|
// provider-blind ClientModel shape (execution topology remains server-side).
|
|
105273
|
-
models:
|
|
105659
|
+
models: configuredModels4(catalogSettings).map(projectClientModel),
|
|
105274
105660
|
defaultReasoningEffort: deps.settings.openaiReasoningEffort,
|
|
105275
105661
|
allowedReasoningEfforts: configuredAllowedReasoningEfforts(deps.settings),
|
|
105276
105662
|
defaultSandboxBackend: deps.settings.sandboxBackend,
|
|
@@ -105952,7 +106338,7 @@ function readinessChecks(deps) {
|
|
|
105952
106338
|
} else {
|
|
105953
106339
|
await deps.db.execute(dbSql`select 1`);
|
|
105954
106340
|
}
|
|
105955
|
-
await
|
|
106341
|
+
await resolveCatalogSettings2(deps.db, deps.settings);
|
|
105956
106342
|
},
|
|
105957
106343
|
nats: async () => {
|
|
105958
106344
|
requireSessionEventDurableFanoutCapability2(deps.bus);
|
|
@@ -106882,4 +107268,4 @@ export {
|
|
|
106882
107268
|
withDefaultEnabledCapabilityMcpTools,
|
|
106883
107269
|
workflowIdForSession4 as workflowIdForSession
|
|
106884
107270
|
};
|
|
106885
|
-
//# sourceMappingURL=chunk-
|
|
107271
|
+
//# sourceMappingURL=chunk-PHQ7C36N.js.map
|