@opengeni/api-router 4.1.0 → 4.1.2
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-24C5LPNE.js → chunk-2SSU5KWV.js} +715 -279
- package/dist/{chunk-24C5LPNE.js.map → chunk-2SSU5KWV.js.map} +1 -1
- package/dist/index.js +1 -1
- package/dist/integrations/github-lens-connect.d.ts +1 -1
- package/dist/integrations/slack-interactions.d.ts +1 -1
- package/dist/mcp/documents.d.ts +2 -0
- package/dist/mcp/first-party-tool-permissions.d.ts +8 -0
- package/dist/routes/browser-sessions.d.ts +3 -0
- package/dist/routes/github-browser-pages.d.ts +5 -0
- package/dist/routes/insights.d.ts +26 -0
- package/dist/sandbox-file-artifacts.d.ts +17 -1
- package/package.json +15 -15
- package/src/mcp/documents.ts +9 -2
- package/src/mcp/first-party-tool-permissions.ts +2 -0
- package/src/mcp/knowledge-entries.ts +15 -2
- package/src/mcp/server.ts +51 -2
- package/src/routes/browser-sessions.ts +140 -0
- package/src/routes/computer-sessions.ts +18 -1
- package/src/routes/documents.ts +1 -0
- package/src/routes/files.ts +4 -0
- package/src/routes/github-browser-pages.ts +102 -0
- package/src/routes/github.ts +6 -47
- package/src/routes/insights.ts +70 -6
- 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/sessions.ts +89 -0
- package/src/sandbox/channel-a.ts +8 -0
- package/src/sandbox/viewer.ts +16 -3
- package/src/sandbox-file-artifacts.ts +37 -26
- package/src/workspace-tool-gateway.ts +1 -0
|
@@ -294,6 +294,8 @@ var FIRST_PARTY_TOOL_AUTHORIZATION = {
|
|
|
294
294
|
browser_open: { sessionRequired: true, allOf: ["sessions:control"] },
|
|
295
295
|
browser_tabs: { sessionRequired: true, allOf: ["sessions:control"] },
|
|
296
296
|
browser_observe: { sessionRequired: true, allOf: ["sessions:read"] },
|
|
297
|
+
browser_read: { sessionRequired: true, allOf: ["sessions:read"] },
|
|
298
|
+
browser_screenshot: { sessionRequired: true, allOf: ["sessions:read"] },
|
|
297
299
|
browser_act: { sessionRequired: true, allOf: ["sessions:control"] },
|
|
298
300
|
browser_clipboard: { sessionRequired: true, allOf: ["sessions:read"] },
|
|
299
301
|
browser_debug: { sessionRequired: true, allOf: ["sessions:read"] },
|
|
@@ -4600,6 +4602,9 @@ var Name = class {
|
|
|
4600
4602
|
return new SQL([this]);
|
|
4601
4603
|
}
|
|
4602
4604
|
};
|
|
4605
|
+
function isDriverValueEncoder(value) {
|
|
4606
|
+
return typeof value === "object" && value !== null && "mapToDriverValue" in value && typeof value.mapToDriverValue === "function";
|
|
4607
|
+
}
|
|
4603
4608
|
var noopDecoder = {
|
|
4604
4609
|
mapFromDriverValue: (value) => value
|
|
4605
4610
|
};
|
|
@@ -4732,6 +4737,33 @@ Subquery.prototype.getSQL = function() {
|
|
|
4732
4737
|
return new SQL([this]);
|
|
4733
4738
|
};
|
|
4734
4739
|
|
|
4740
|
+
// ../../node_modules/.bun/drizzle-orm@0.45.2+1d2c014f134ec9f4/node_modules/drizzle-orm/sql/expressions/conditions.js
|
|
4741
|
+
function bindIfParam(value, column) {
|
|
4742
|
+
if (isDriverValueEncoder(column) && !isSQLWrapper(value) && !is(value, Param) && !is(value, Placeholder) && !is(value, Column) && !is(value, Table) && !is(value, View)) {
|
|
4743
|
+
return new Param(value, column);
|
|
4744
|
+
}
|
|
4745
|
+
return value;
|
|
4746
|
+
}
|
|
4747
|
+
var eq = (left, right) => {
|
|
4748
|
+
return sql`${left} = ${bindIfParam(right, left)}`;
|
|
4749
|
+
};
|
|
4750
|
+
function and(...unfilteredConditions) {
|
|
4751
|
+
const conditions = unfilteredConditions.filter(
|
|
4752
|
+
(c) => c !== void 0
|
|
4753
|
+
);
|
|
4754
|
+
if (conditions.length === 0) {
|
|
4755
|
+
return void 0;
|
|
4756
|
+
}
|
|
4757
|
+
if (conditions.length === 1) {
|
|
4758
|
+
return new SQL(conditions);
|
|
4759
|
+
}
|
|
4760
|
+
return new SQL([
|
|
4761
|
+
new StringChunk("("),
|
|
4762
|
+
sql.join(conditions, new StringChunk(" and ")),
|
|
4763
|
+
new StringChunk(")")
|
|
4764
|
+
]);
|
|
4765
|
+
}
|
|
4766
|
+
|
|
4735
4767
|
// src/auth/managed-auth.ts
|
|
4736
4768
|
import { Pool } from "pg";
|
|
4737
4769
|
|
|
@@ -7598,7 +7630,14 @@ function registerKnowledgeEntryTools(server, deps, grant, sessionId) {
|
|
|
7598
7630
|
inputSchema: KnowledgeSavePreparationRequest.shape
|
|
7599
7631
|
},
|
|
7600
7632
|
(input) => run(
|
|
7601
|
-
(context) => prepareKnowledgeSave(
|
|
7633
|
+
(context) => prepareKnowledgeSave(
|
|
7634
|
+
deps.db,
|
|
7635
|
+
context,
|
|
7636
|
+
input,
|
|
7637
|
+
() => deps.getDocumentServices().embedder,
|
|
7638
|
+
void 0,
|
|
7639
|
+
deps.settings
|
|
7640
|
+
)
|
|
7602
7641
|
)
|
|
7603
7642
|
);
|
|
7604
7643
|
server.registerTool(
|
|
@@ -7613,7 +7652,13 @@ function registerKnowledgeEntryTools(server, deps, grant, sessionId) {
|
|
|
7613
7652
|
}).extend({ view: z8.enum(["published", "needs_review"]).default("published") }).shape
|
|
7614
7653
|
},
|
|
7615
7654
|
(input) => run(
|
|
7616
|
-
(context) => searchKnowledgeEntries(
|
|
7655
|
+
(context) => searchKnowledgeEntries(
|
|
7656
|
+
deps.db,
|
|
7657
|
+
context,
|
|
7658
|
+
input,
|
|
7659
|
+
() => deps.getDocumentServices().embedder,
|
|
7660
|
+
deps.settings
|
|
7661
|
+
)
|
|
7617
7662
|
)
|
|
7618
7663
|
);
|
|
7619
7664
|
server.registerTool(
|
|
@@ -7901,26 +7946,26 @@ async function listWorkspaceGitHubRepositoryBranches(deps, input, services = wor
|
|
|
7901
7946
|
])) {
|
|
7902
7947
|
throw new GitHubRepositoryBranchAuthorityError("changed");
|
|
7903
7948
|
}
|
|
7904
|
-
const
|
|
7949
|
+
const page2 = await services.listProviderBranches(deps, {
|
|
7905
7950
|
installationId: input.installationId,
|
|
7906
7951
|
repositoryId: input.repositoryId,
|
|
7907
7952
|
page: input.query.cursor,
|
|
7908
7953
|
limit: input.query.limit
|
|
7909
7954
|
});
|
|
7910
|
-
if (!
|
|
7955
|
+
if (!page2) {
|
|
7911
7956
|
throw new GitHubAppApiError(
|
|
7912
7957
|
"The configured GitHub provider cannot list exact repository branches"
|
|
7913
7958
|
);
|
|
7914
7959
|
}
|
|
7915
|
-
if (
|
|
7960
|
+
if (page2.installationId !== input.installationId || page2.repositoryId !== input.repositoryId || page2.branches.length > input.query.limit || page2.nextPage !== null && page2.nextPage !== input.query.cursor + 1 || page2.branches.length < input.query.limit && page2.nextPage !== null) {
|
|
7916
7961
|
throw new GitHubAppApiError("GitHub returned an invalid repository branches page");
|
|
7917
7962
|
}
|
|
7918
7963
|
const response = GitHubRepositoryBranchesResponseSchema.safeParse({
|
|
7919
|
-
branches:
|
|
7964
|
+
branches: page2.branches.map((name) => ({
|
|
7920
7965
|
name,
|
|
7921
|
-
isDefault: name ===
|
|
7966
|
+
isDefault: name === page2.defaultBranch
|
|
7922
7967
|
})),
|
|
7923
|
-
nextCursor:
|
|
7968
|
+
nextCursor: page2.nextPage
|
|
7924
7969
|
});
|
|
7925
7970
|
if (!response.success) {
|
|
7926
7971
|
throw new GitHubAppApiError("GitHub returned an invalid repository branches page");
|
|
@@ -8009,6 +8054,11 @@ import {
|
|
|
8009
8054
|
} from "@opengeni/db";
|
|
8010
8055
|
import { retryWhileMissing as retryWhileMissing4 } from "@opengeni/storage";
|
|
8011
8056
|
import { HTTPException as HTTPException12 } from "hono/http-exception";
|
|
8057
|
+
import {
|
|
8058
|
+
isConnectedMachineAbsolutePath,
|
|
8059
|
+
relativeConnectedMachinePath,
|
|
8060
|
+
resolveConnectedMachinePath
|
|
8061
|
+
} from "@opengeni/runtime/sandbox";
|
|
8012
8062
|
|
|
8013
8063
|
// src/sandbox/channel-a.ts
|
|
8014
8064
|
import {
|
|
@@ -8016,6 +8066,7 @@ import {
|
|
|
8016
8066
|
hasGitCredentialRepositorySelection,
|
|
8017
8067
|
hasGitHubRepositorySelection,
|
|
8018
8068
|
sandboxLifecycleTransitionWaitMs,
|
|
8069
|
+
sandboxWarmRateMicrosPerSecond,
|
|
8019
8070
|
stableSandboxEnvironmentForRun
|
|
8020
8071
|
} from "@opengeni/config";
|
|
8021
8072
|
import { githubAppBotIdentity } from "@opengeni/github";
|
|
@@ -8034,6 +8085,7 @@ import {
|
|
|
8034
8085
|
SandboxImageConflictError,
|
|
8035
8086
|
SandboxProviderReadLockUnavailableError,
|
|
8036
8087
|
SandboxRigConflictError,
|
|
8088
|
+
SandboxPaidComputeAdmissionError,
|
|
8037
8089
|
withSandboxProviderReadLock
|
|
8038
8090
|
} from "@opengeni/db";
|
|
8039
8091
|
import { appendAndPublishEvents } from "@opengeni/events";
|
|
@@ -8853,6 +8905,10 @@ async function withChannelAOperation(services, ctx, readOnly, fn) {
|
|
|
8853
8905
|
holderId,
|
|
8854
8906
|
subjectId: session.id,
|
|
8855
8907
|
backend: session.sandboxBackend,
|
|
8908
|
+
warmBilling: {
|
|
8909
|
+
mode: settings.sandboxWarmBillingMode,
|
|
8910
|
+
rateMicrosPerSecond: sandboxWarmRateMicrosPerSecond(settings, session.sandboxBackend)
|
|
8911
|
+
},
|
|
8856
8912
|
os: session.sandboxOs,
|
|
8857
8913
|
image: sandboxRuntime.image,
|
|
8858
8914
|
rigVersionId: session.rigVersionId,
|
|
@@ -9153,6 +9209,8 @@ async function withChannelAOperation(services, ctx, readOnly, fn) {
|
|
|
9153
9209
|
}
|
|
9154
9210
|
function mapChannelAError(error, waitSignal) {
|
|
9155
9211
|
if (error instanceof HTTPException6) return error;
|
|
9212
|
+
if (error instanceof SandboxPaidComputeAdmissionError)
|
|
9213
|
+
return new HTTPException6(402, { message: error.message, cause: error });
|
|
9156
9214
|
if (isChannelARequestCancellation(error, waitSignal))
|
|
9157
9215
|
return new HTTPException6(499, {
|
|
9158
9216
|
message: "request cancelled",
|
|
@@ -9335,6 +9393,7 @@ import {
|
|
|
9335
9393
|
retainedGeneratedImageReferenceFromFile,
|
|
9336
9394
|
retainedGeneratedVideoReferenceFromFile,
|
|
9337
9395
|
retainedScreenshotReferenceFromFile,
|
|
9396
|
+
retainedSessionScreenshotKindFromObjectKey,
|
|
9338
9397
|
VideoArtifactPlaybackSource,
|
|
9339
9398
|
resolveRetainedOutputRange
|
|
9340
9399
|
} from "@opengeni/contracts";
|
|
@@ -9631,7 +9690,13 @@ function buildDocumentsMcpServer(db, accountId, workspaceId, documentServices, o
|
|
|
9631
9690
|
{
|
|
9632
9691
|
type: "text",
|
|
9633
9692
|
text: JSON.stringify(
|
|
9634
|
-
await searchKnowledgeEntries2(
|
|
9693
|
+
await searchKnowledgeEntries2(
|
|
9694
|
+
db,
|
|
9695
|
+
context,
|
|
9696
|
+
input,
|
|
9697
|
+
() => documentServices.embedder,
|
|
9698
|
+
options.settings
|
|
9699
|
+
)
|
|
9635
9700
|
)
|
|
9636
9701
|
}
|
|
9637
9702
|
]
|
|
@@ -9917,7 +9982,8 @@ async function prepareWorkspaceToolGatewayForGrantInternal(routeDeps, grant, all
|
|
|
9917
9982
|
grant.workspaceId,
|
|
9918
9983
|
routeDeps.getDocumentServices(),
|
|
9919
9984
|
{
|
|
9920
|
-
knowledge: await knowledgeContextForGateway(routeDeps, grant)
|
|
9985
|
+
knowledge: await knowledgeContextForGateway(routeDeps, grant),
|
|
9986
|
+
settings: gatewaySettings
|
|
9921
9987
|
}
|
|
9922
9988
|
)
|
|
9923
9989
|
)
|
|
@@ -11718,12 +11784,15 @@ function retainedGeneratedImageMetadata(artifact) {
|
|
|
11718
11784
|
}
|
|
11719
11785
|
function retainedScreenshotMetadata(artifact) {
|
|
11720
11786
|
if (artifact.status === "ready" && artifact.sessionId && artifact.retentionExpiresAt.getTime() > Date.now()) {
|
|
11787
|
+
const kind = retainedSessionScreenshotKindFromObjectKey(artifact.file.objectKey);
|
|
11788
|
+
if (!kind) return retainedArtifactUnavailable(artifact.artifactId, "invalid_content");
|
|
11721
11789
|
const reference = retainedScreenshotReferenceFromFile({
|
|
11722
11790
|
...artifact.file,
|
|
11723
11791
|
sessionId: artifact.sessionId,
|
|
11724
11792
|
width: artifact.width,
|
|
11725
11793
|
height: artifact.height,
|
|
11726
|
-
expiresAt: artifact.retentionExpiresAt.toISOString()
|
|
11794
|
+
expiresAt: artifact.retentionExpiresAt.toISOString(),
|
|
11795
|
+
kind
|
|
11727
11796
|
});
|
|
11728
11797
|
if (reference) return reference;
|
|
11729
11798
|
}
|
|
@@ -11798,13 +11867,12 @@ async function publishSandboxFileArtifactInScope(deps, input) {
|
|
|
11798
11867
|
message: "object storage cannot verify immutable artifact files"
|
|
11799
11868
|
});
|
|
11800
11869
|
}
|
|
11801
|
-
const path = sandboxArtifactRelativePath(input.path);
|
|
11802
11870
|
const maxArtifactBytes = Math.min(SANDBOX_FILE_ARTIFACT_MAX_BYTES, storage.maxSinglePutSizeBytes);
|
|
11803
11871
|
if (maxArtifactBytes < 1) {
|
|
11804
11872
|
throw new HTTPException12(503, { message: "object storage cannot accept artifact files" });
|
|
11805
11873
|
}
|
|
11806
11874
|
const readLimit = Math.min(25 * 1024 * 1024, maxArtifactBytes + FILE_READ_SENTINEL_BYTES);
|
|
11807
|
-
const read = await withChannelARead(
|
|
11875
|
+
const { path, sandboxPath, read } = await withChannelARead(
|
|
11808
11876
|
{
|
|
11809
11877
|
db: deps.db,
|
|
11810
11878
|
settings: deps.settings,
|
|
@@ -11819,7 +11887,7 @@ async function publishSandboxFileArtifactInScope(deps, input) {
|
|
|
11819
11887
|
...input.signal ? { waitSignal: input.signal } : {},
|
|
11820
11888
|
operation: "artifact.publish"
|
|
11821
11889
|
},
|
|
11822
|
-
({ service }) => service.
|
|
11890
|
+
({ service }) => readSandboxArtifactFile(service, input.path, readLimit)
|
|
11823
11891
|
);
|
|
11824
11892
|
if (read.truncated || read.sizeBytes > maxArtifactBytes) {
|
|
11825
11893
|
throw new HTTPException12(413, {
|
|
@@ -11929,42 +11997,46 @@ async function publishSandboxFileArtifactInScope(deps, input) {
|
|
|
11929
11997
|
});
|
|
11930
11998
|
return SandboxFileArtifactReceipt.parse({
|
|
11931
11999
|
type: "sandbox_file",
|
|
11932
|
-
sandboxPath
|
|
12000
|
+
sandboxPath,
|
|
11933
12001
|
filename,
|
|
11934
12002
|
artifact
|
|
11935
12003
|
});
|
|
11936
12004
|
}
|
|
11937
|
-
function
|
|
12005
|
+
async function readSandboxArtifactFile(service, value, maxBytes) {
|
|
12006
|
+
const root2 = service.capabilities().FileSystem.root;
|
|
12007
|
+
const path = sandboxArtifactRelativePath(value, root2);
|
|
12008
|
+
const sandboxPath = resolveConnectedMachinePath(root2, path);
|
|
12009
|
+
const read = await service.fsRead({ path, encoding: "base64", maxBytes });
|
|
12010
|
+
return { path, sandboxPath, read };
|
|
12011
|
+
}
|
|
12012
|
+
function sandboxArtifactRelativePath(value, workspaceRoot = "/workspace") {
|
|
11938
12013
|
let path = value.trim();
|
|
11939
12014
|
if (path.startsWith("sandbox:")) {
|
|
11940
12015
|
path = path.slice("sandbox:".length);
|
|
11941
12016
|
}
|
|
11942
|
-
if (path
|
|
12017
|
+
if (!path || /[\\/]$/.test(path)) {
|
|
11943
12018
|
throw new HTTPException12(400, { message: "sandbox artifact path must name a file" });
|
|
11944
12019
|
}
|
|
11945
|
-
|
|
11946
|
-
|
|
11947
|
-
|
|
12020
|
+
let absolute;
|
|
12021
|
+
let relative;
|
|
12022
|
+
try {
|
|
12023
|
+
if (!isConnectedMachineAbsolutePath(workspaceRoot)) throw new Error("Missing workspace root");
|
|
12024
|
+
absolute = resolveConnectedMachinePath(workspaceRoot, path);
|
|
12025
|
+
relative = relativeConnectedMachinePath(workspaceRoot, absolute);
|
|
12026
|
+
} catch {
|
|
11948
12027
|
throw new HTTPException12(400, {
|
|
11949
|
-
message: "sandbox artifact path
|
|
12028
|
+
message: "sandbox artifact path is invalid for this workspace"
|
|
11950
12029
|
});
|
|
11951
12030
|
}
|
|
11952
|
-
if (!
|
|
11953
|
-
throw new HTTPException12(400, { message: "sandbox artifact path must name a file" });
|
|
11954
|
-
}
|
|
11955
|
-
if (path.includes("\0")) {
|
|
11956
|
-
throw new HTTPException12(400, { message: "sandbox artifact path is invalid" });
|
|
11957
|
-
}
|
|
11958
|
-
const normalized = posix.normalize(path);
|
|
11959
|
-
if (normalized === "." || normalized === ".." || normalized.startsWith("../") || normalized.endsWith("/")) {
|
|
12031
|
+
if (!relative) {
|
|
11960
12032
|
throw new HTTPException12(400, {
|
|
11961
|
-
message: "sandbox artifact path must
|
|
12033
|
+
message: "sandbox artifact path must name a file inside the active workspace root"
|
|
11962
12034
|
});
|
|
11963
12035
|
}
|
|
11964
|
-
if (
|
|
12036
|
+
if (absolute.length > SANDBOX_ARTIFACT_ABSOLUTE_PATH_MAX_CHARS) {
|
|
11965
12037
|
throw new HTTPException12(400, { message: "sandbox artifact path is too long" });
|
|
11966
12038
|
}
|
|
11967
|
-
return
|
|
12039
|
+
return relative;
|
|
11968
12040
|
}
|
|
11969
12041
|
function sandboxArtifactSafeFilename(filename) {
|
|
11970
12042
|
return sanitizeFilename(filename).slice(0, SANDBOX_ARTIFACT_SAFE_FILENAME_MAX_CHARS);
|
|
@@ -15624,16 +15696,16 @@ function capEventPayload(event, perFieldChars) {
|
|
|
15624
15696
|
function prettyJsonBytes(value) {
|
|
15625
15697
|
return Buffer.byteLength(JSON.stringify(value, null, 2), "utf8");
|
|
15626
15698
|
}
|
|
15627
|
-
function setMeasuredBytes(
|
|
15628
|
-
let measured =
|
|
15699
|
+
function setMeasuredBytes(page2) {
|
|
15700
|
+
let measured = page2.bytes;
|
|
15629
15701
|
for (let attempt = 0; attempt < 8; attempt += 1) {
|
|
15630
|
-
|
|
15631
|
-
const next = prettyJsonBytes(
|
|
15702
|
+
page2.bytes = measured;
|
|
15703
|
+
const next = prettyJsonBytes(page2);
|
|
15632
15704
|
if (next === measured) return next;
|
|
15633
15705
|
measured = next;
|
|
15634
15706
|
}
|
|
15635
|
-
|
|
15636
|
-
return prettyJsonBytes(
|
|
15707
|
+
page2.bytes = measured;
|
|
15708
|
+
return prettyJsonBytes(page2);
|
|
15637
15709
|
}
|
|
15638
15710
|
function boundSessionEventMcpPage(input) {
|
|
15639
15711
|
const maxBytes = Math.max(8 * 1024, input.maxBytes ?? SESSION_EVENT_MCP_MAX_BYTES);
|
|
@@ -15655,7 +15727,7 @@ function boundSessionEventMcpPage(input) {
|
|
|
15655
15727
|
if (modelRowsDropped) reasons.push("model_bytes");
|
|
15656
15728
|
const nextAfter = input.direction === "after" ? last ?? input.after : null;
|
|
15657
15729
|
const nextBefore = input.direction === "before" ? first ?? input.before : null;
|
|
15658
|
-
const
|
|
15730
|
+
const page3 = {
|
|
15659
15731
|
mode: input.mode,
|
|
15660
15732
|
payloadMode: input.payloadMode,
|
|
15661
15733
|
direction: input.direction,
|
|
@@ -15675,20 +15747,20 @@ function boundSessionEventMcpPage(input) {
|
|
|
15675
15747
|
bytes: 0,
|
|
15676
15748
|
maxBytes
|
|
15677
15749
|
};
|
|
15678
|
-
setMeasuredBytes(
|
|
15679
|
-
return
|
|
15750
|
+
setMeasuredBytes(page3);
|
|
15751
|
+
return page3;
|
|
15680
15752
|
};
|
|
15681
|
-
let
|
|
15682
|
-
while (
|
|
15753
|
+
let page2 = build();
|
|
15754
|
+
while (page2.bytes > maxBytes && events.length > 0) {
|
|
15683
15755
|
if (input.direction === "before") events.shift();
|
|
15684
15756
|
else events.pop();
|
|
15685
15757
|
modelRowsDropped = true;
|
|
15686
|
-
|
|
15758
|
+
page2 = build();
|
|
15687
15759
|
}
|
|
15688
|
-
if (
|
|
15760
|
+
if (page2.bytes > maxBytes) {
|
|
15689
15761
|
throw new RangeError(`Session-event MCP metadata exceeds its ${maxBytes}-byte envelope`);
|
|
15690
15762
|
}
|
|
15691
|
-
return
|
|
15763
|
+
return page2;
|
|
15692
15764
|
}
|
|
15693
15765
|
function modelStringProjection(value, maxBytes) {
|
|
15694
15766
|
const originalBytes = Buffer.byteLength(value, "utf8");
|
|
@@ -16145,9 +16217,9 @@ function boundRigDetailMcp(rig, versionsPage, changesPage, maxBytes = RIG_DETAIL
|
|
|
16145
16217
|
}
|
|
16146
16218
|
|
|
16147
16219
|
// src/mcp/child-read-evidence.ts
|
|
16148
|
-
function completeChildReadSequences(
|
|
16149
|
-
if (!
|
|
16150
|
-
return
|
|
16220
|
+
function completeChildReadSequences(page2) {
|
|
16221
|
+
if (!page2.sourceExact || !["conversation", "results"].includes(page2.view)) return [];
|
|
16222
|
+
return page2.events.filter((event) => {
|
|
16151
16223
|
if (event.sourceOmitted) return false;
|
|
16152
16224
|
if (event.fragment === void 0) return true;
|
|
16153
16225
|
if (!event.fragment || typeof event.fragment !== "object") return false;
|
|
@@ -17042,7 +17114,7 @@ function boundScheduledTaskMcpPage(input) {
|
|
|
17042
17114
|
const rowsDroppedForBytes = droppedTasks.length > 0;
|
|
17043
17115
|
const hasMore = input.sourceHasMore || rowsDroppedForBytes;
|
|
17044
17116
|
const nextOffset = hasMore && input.tasks.length > 0 ? input.offset + input.tasks.length : null;
|
|
17045
|
-
const
|
|
17117
|
+
const page3 = {
|
|
17046
17118
|
tasks: summaries,
|
|
17047
17119
|
page: {
|
|
17048
17120
|
limit: input.limit,
|
|
@@ -17070,20 +17142,20 @@ function boundScheduledTaskMcpPage(input) {
|
|
|
17070
17142
|
}
|
|
17071
17143
|
};
|
|
17072
17144
|
settleMeasuredBytes(
|
|
17073
|
-
|
|
17074
|
-
() =>
|
|
17145
|
+
page3,
|
|
17146
|
+
() => page3.projection.bytes,
|
|
17075
17147
|
(bytes) => {
|
|
17076
|
-
|
|
17148
|
+
page3.projection.bytes = bytes;
|
|
17077
17149
|
}
|
|
17078
17150
|
);
|
|
17079
|
-
return
|
|
17151
|
+
return page3;
|
|
17080
17152
|
};
|
|
17081
|
-
let
|
|
17082
|
-
while (
|
|
17153
|
+
let page2 = build();
|
|
17154
|
+
while (page2.projection.bytes > maxBytes && summaries.length > 0) {
|
|
17083
17155
|
summaries = summaries.slice(0, -1);
|
|
17084
|
-
|
|
17156
|
+
page2 = build();
|
|
17085
17157
|
}
|
|
17086
|
-
return
|
|
17158
|
+
return page2;
|
|
17087
17159
|
}
|
|
17088
17160
|
|
|
17089
17161
|
// src/sandbox/viewer.ts
|
|
@@ -17094,6 +17166,7 @@ import {
|
|
|
17094
17166
|
hasGitHubRepositorySelection as hasGitHubRepositorySelection2,
|
|
17095
17167
|
resolveStreamTokenSecret,
|
|
17096
17168
|
sandboxLifecycleTransitionWaitMs as sandboxLifecycleTransitionWaitMs2,
|
|
17169
|
+
sandboxWarmRateMicrosPerSecond as sandboxWarmRateMicrosPerSecond2,
|
|
17097
17170
|
stableSandboxEnvironmentForRun as stableSandboxEnvironmentForRun2
|
|
17098
17171
|
} from "@opengeni/config";
|
|
17099
17172
|
import { githubAppBotIdentity as githubAppBotIdentity2 } from "@opengeni/github";
|
|
@@ -17103,7 +17176,7 @@ import {
|
|
|
17103
17176
|
getSandbox as getSandbox2,
|
|
17104
17177
|
getScheduledScopedRigVersionMetadata as getScheduledScopedRigVersionMetadata2,
|
|
17105
17178
|
getSandboxSessionEnvelope as getSandboxSessionEnvelope2,
|
|
17106
|
-
|
|
17179
|
+
heartbeatLeaseHolderStatus,
|
|
17107
17180
|
loadWorkspaceEnvironmentForRun as loadWorkspaceEnvironmentForRun2,
|
|
17108
17181
|
markSandboxProviderReady,
|
|
17109
17182
|
markWarmLeaseInstanceLost as markWarmLeaseInstanceLost2,
|
|
@@ -17113,6 +17186,7 @@ import {
|
|
|
17113
17186
|
releaseLeaseHolder as releaseLeaseHolder2,
|
|
17114
17187
|
SandboxLeaseSupersededError as SandboxLeaseSupersededError2,
|
|
17115
17188
|
SandboxViewerAdmissionBlockedError,
|
|
17189
|
+
SandboxPaidComputeAdmissionError as SandboxPaidComputeAdmissionError2,
|
|
17116
17190
|
getSessionAuthorityEpoch,
|
|
17117
17191
|
namedSubjectHasLiveWorkspaceAuthority
|
|
17118
17192
|
} from "@opengeni/db";
|
|
@@ -17242,6 +17316,10 @@ async function attachViewer(services, input) {
|
|
|
17242
17316
|
...attachSubjectId ? { viewerSubjectId: attachSubjectId } : {},
|
|
17243
17317
|
...attachAuthorityEpoch !== null ? { viewerAuthorityEpoch: attachAuthorityEpoch } : {},
|
|
17244
17318
|
backend: session.sandboxBackend,
|
|
17319
|
+
warmBilling: {
|
|
17320
|
+
mode: settings.sandboxWarmBillingMode,
|
|
17321
|
+
rateMicrosPerSecond: sandboxWarmRateMicrosPerSecond2(settings, session.sandboxBackend)
|
|
17322
|
+
},
|
|
17245
17323
|
os: session.sandboxOs,
|
|
17246
17324
|
image: sandboxRuntime.image,
|
|
17247
17325
|
rigVersionId: session.rigVersionId,
|
|
@@ -17251,6 +17329,9 @@ async function attachViewer(services, input) {
|
|
|
17251
17329
|
...input.waitSignal ? { waitSignal: input.waitSignal } : {}
|
|
17252
17330
|
});
|
|
17253
17331
|
} catch (error) {
|
|
17332
|
+
if (error instanceof SandboxPaidComputeAdmissionError2) {
|
|
17333
|
+
throw new HTTPException19(402, { message: error.message, cause: error });
|
|
17334
|
+
}
|
|
17254
17335
|
if (error instanceof SandboxViewerAdmissionBlockedError) {
|
|
17255
17336
|
throw new HTTPException19(error.reason === "balance" ? 402 : 429, {
|
|
17256
17337
|
message: error.reason === "balance" ? "insufficient OpenGeni credits for an idle sandbox viewer" : "workspace sandbox warm allowance exhausted",
|
|
@@ -17437,16 +17518,17 @@ async function ensureSessionGroupReady(services, input) {
|
|
|
17437
17518
|
throw lastError ?? new Error("sandbox readiness could not be established");
|
|
17438
17519
|
}
|
|
17439
17520
|
async function heartbeatViewer(services, input) {
|
|
17440
|
-
const
|
|
17521
|
+
const status = await heartbeatLeaseHolderStatus(services.db, {
|
|
17441
17522
|
accountId: input.accountId,
|
|
17442
17523
|
workspaceId: input.workspaceId,
|
|
17443
17524
|
sandboxGroupId: input.sandboxGroupId,
|
|
17444
17525
|
kind: "viewer",
|
|
17445
17526
|
holderId: input.viewerId,
|
|
17446
17527
|
leaseTtlMs: services.settings.sandboxLeaseTtlMs,
|
|
17447
|
-
expectedEpoch: input.expectedEpoch
|
|
17528
|
+
expectedEpoch: input.expectedEpoch,
|
|
17529
|
+
billingMode: services.settings.sandboxWarmBillingMode
|
|
17448
17530
|
});
|
|
17449
|
-
if (!
|
|
17531
|
+
if (!status.leaseExtended) return status.holderAlive && status.fence === "funding";
|
|
17450
17532
|
const lease = await readLease2(services.db, input.workspaceId, input.sandboxGroupId);
|
|
17451
17533
|
if (lease?.liveness === "warm" && lease.leaseEpoch === input.expectedEpoch && lease.instanceId) {
|
|
17452
17534
|
await renewSandboxProviderExpiration({
|
|
@@ -18326,7 +18408,7 @@ var OpenGeniSlackBotClient = class {
|
|
|
18326
18408
|
let reactedMessage = null;
|
|
18327
18409
|
const checkpointCreatedAtMs = restored?.state.createdAtMs ?? Date.now();
|
|
18328
18410
|
const firstPage = restored?.state.pageCount ?? 0;
|
|
18329
|
-
for (let
|
|
18411
|
+
for (let page2 = firstPage; page2 < MAX_REACTION_CONTEXT_PAGES; page2 += 1) {
|
|
18330
18412
|
const payload = await this.call(headers, "conversations.replies", {
|
|
18331
18413
|
channel: input.channelId,
|
|
18332
18414
|
// Slack accepts either the parent timestamp or a message timestamp from
|
|
@@ -18350,7 +18432,7 @@ var OpenGeniSlackBotClient = class {
|
|
|
18350
18432
|
throw new SlackBotProviderError("reaction_pagination_invalid");
|
|
18351
18433
|
}
|
|
18352
18434
|
seenCursors.add(nextCursor);
|
|
18353
|
-
const pageCount =
|
|
18435
|
+
const pageCount = page2 + 1;
|
|
18354
18436
|
if (pageCount >= MAX_REACTION_CONTEXT_PAGES) {
|
|
18355
18437
|
throw new SlackBotProviderError("reaction_pagination_exhausted");
|
|
18356
18438
|
}
|
|
@@ -18576,14 +18658,14 @@ var OpenGeniSlackBotClient = class {
|
|
|
18576
18658
|
if (offset > content.length) {
|
|
18577
18659
|
throw new SlackBotProviderError("invalid_file_offset");
|
|
18578
18660
|
}
|
|
18579
|
-
const
|
|
18580
|
-
const nextOffset = offset +
|
|
18661
|
+
const page2 = content.slice(offset, offset + SLACK_FILE_CONTENT_PAGE_CHARS);
|
|
18662
|
+
const nextOffset = offset + page2.length < content.length ? offset + page2.length : null;
|
|
18581
18663
|
return {
|
|
18582
18664
|
channel: info,
|
|
18583
18665
|
file,
|
|
18584
18666
|
contentType,
|
|
18585
18667
|
offset,
|
|
18586
|
-
content:
|
|
18668
|
+
content: page2,
|
|
18587
18669
|
nextOffset,
|
|
18588
18670
|
truncated: nextOffset !== null
|
|
18589
18671
|
};
|
|
@@ -18985,7 +19067,7 @@ var OpenGeniSlackBotClient = class {
|
|
|
18985
19067
|
let cursor = null;
|
|
18986
19068
|
let matchedTimestamp = null;
|
|
18987
19069
|
let exhausted = false;
|
|
18988
|
-
for (let
|
|
19070
|
+
for (let page2 = 0; page2 < MAX_SLACK_POST_RECONCILIATION_PAGES; page2 += 1) {
|
|
18989
19071
|
const payload = await this.call(headers, method, {
|
|
18990
19072
|
channel: input.channelId,
|
|
18991
19073
|
limit: String(input.threadTimestamp ? MAX_THREAD_PAGE : MAX_HISTORY_PAGE),
|
|
@@ -20092,13 +20174,13 @@ function nextSlackFilesListPage(payload, requested, returnedFileCount) {
|
|
|
20092
20174
|
}
|
|
20093
20175
|
const count = paging?.count;
|
|
20094
20176
|
const total = paging?.total;
|
|
20095
|
-
const
|
|
20177
|
+
const page2 = paging?.page;
|
|
20096
20178
|
const pages = paging?.pages;
|
|
20097
|
-
if (!positiveSafeInt(count) || !nonNegativeSafeInt(total) || !positiveSafeInt(
|
|
20179
|
+
if (!positiveSafeInt(count) || !nonNegativeSafeInt(total) || !positiveSafeInt(page2) || !nonNegativeSafeInt(pages) || count !== requested.count || page2 !== requested.page || returnedFileCount > count || pages !== (total === 0 ? 0 : Math.ceil(total / count)) || page2 > Math.max(1, pages)) {
|
|
20098
20180
|
throw new SlackBotProviderError("invalid_files_paging");
|
|
20099
20181
|
}
|
|
20100
|
-
if (
|
|
20101
|
-
const nextPage =
|
|
20182
|
+
if (page2 >= pages) return null;
|
|
20183
|
+
const nextPage = page2 + 1;
|
|
20102
20184
|
if (!positiveSafeInt(nextPage)) {
|
|
20103
20185
|
throw new SlackBotProviderError("invalid_files_paging");
|
|
20104
20186
|
}
|
|
@@ -20459,14 +20541,14 @@ var FikenClient = class {
|
|
|
20459
20541
|
resolveCredential;
|
|
20460
20542
|
expectedConnectionVersion;
|
|
20461
20543
|
async listCompanies(input = {}) {
|
|
20462
|
-
const { payload, page } = await this.request("companies.list", "GET", "/companies", {
|
|
20544
|
+
const { payload, page: page2 } = await this.request("companies.list", "GET", "/companies", {
|
|
20463
20545
|
query: pageQuery(input)
|
|
20464
20546
|
});
|
|
20465
|
-
return { companies: projectArray(payload), page };
|
|
20547
|
+
return { companies: projectArray(payload), page: page2 };
|
|
20466
20548
|
}
|
|
20467
20549
|
async listContacts(input) {
|
|
20468
20550
|
const slug = this.companySlugFor(input.companySlug);
|
|
20469
|
-
const { payload, page } = await this.request(
|
|
20551
|
+
const { payload, page: page2 } = await this.request(
|
|
20470
20552
|
"contacts.list",
|
|
20471
20553
|
"GET",
|
|
20472
20554
|
`/companies/${slug}/contacts`,
|
|
@@ -20482,7 +20564,7 @@ var FikenClient = class {
|
|
|
20482
20564
|
}
|
|
20483
20565
|
}
|
|
20484
20566
|
);
|
|
20485
|
-
return { companySlug: slug, contacts: projectArray(payload), page };
|
|
20567
|
+
return { companySlug: slug, contacts: projectArray(payload), page: page2 };
|
|
20486
20568
|
}
|
|
20487
20569
|
async createContact(input) {
|
|
20488
20570
|
const slug = this.companySlugFor(input.companySlug);
|
|
@@ -20508,7 +20590,7 @@ var FikenClient = class {
|
|
|
20508
20590
|
}
|
|
20509
20591
|
async listProducts(input) {
|
|
20510
20592
|
const slug = this.companySlugFor(input.companySlug);
|
|
20511
|
-
const { payload, page } = await this.request(
|
|
20593
|
+
const { payload, page: page2 } = await this.request(
|
|
20512
20594
|
"products.list",
|
|
20513
20595
|
"GET",
|
|
20514
20596
|
`/companies/${slug}/products`,
|
|
@@ -20520,11 +20602,11 @@ var FikenClient = class {
|
|
|
20520
20602
|
}
|
|
20521
20603
|
}
|
|
20522
20604
|
);
|
|
20523
|
-
return { companySlug: slug, products: projectArray(payload), page };
|
|
20605
|
+
return { companySlug: slug, products: projectArray(payload), page: page2 };
|
|
20524
20606
|
}
|
|
20525
20607
|
async listInvoices(input) {
|
|
20526
20608
|
const slug = this.companySlugFor(input.companySlug);
|
|
20527
|
-
const { payload, page } = await this.request(
|
|
20609
|
+
const { payload, page: page2 } = await this.request(
|
|
20528
20610
|
"invoices.list",
|
|
20529
20611
|
"GET",
|
|
20530
20612
|
`/companies/${slug}/invoices`,
|
|
@@ -20539,7 +20621,7 @@ var FikenClient = class {
|
|
|
20539
20621
|
}
|
|
20540
20622
|
}
|
|
20541
20623
|
);
|
|
20542
|
-
return { companySlug: slug, invoices: projectArray(payload), page };
|
|
20624
|
+
return { companySlug: slug, invoices: projectArray(payload), page: page2 };
|
|
20543
20625
|
}
|
|
20544
20626
|
async getInvoice(input) {
|
|
20545
20627
|
const slug = this.companySlugFor(input.companySlug);
|
|
@@ -20623,7 +20705,7 @@ var FikenClient = class {
|
|
|
20623
20705
|
}
|
|
20624
20706
|
async listBankAccounts(input) {
|
|
20625
20707
|
const slug = this.companySlugFor(input.companySlug);
|
|
20626
|
-
const { payload, page } = await this.request(
|
|
20708
|
+
const { payload, page: page2 } = await this.request(
|
|
20627
20709
|
"bank_accounts.list",
|
|
20628
20710
|
"GET",
|
|
20629
20711
|
`/companies/${slug}/bankAccounts`,
|
|
@@ -20634,11 +20716,11 @@ var FikenClient = class {
|
|
|
20634
20716
|
}
|
|
20635
20717
|
}
|
|
20636
20718
|
);
|
|
20637
|
-
return { companySlug: slug, bankAccounts: projectArray(payload), page };
|
|
20719
|
+
return { companySlug: slug, bankAccounts: projectArray(payload), page: page2 };
|
|
20638
20720
|
}
|
|
20639
20721
|
async listPurchases(input) {
|
|
20640
20722
|
const slug = this.companySlugFor(input.companySlug);
|
|
20641
|
-
const { payload, page } = await this.request(
|
|
20723
|
+
const { payload, page: page2 } = await this.request(
|
|
20642
20724
|
"purchases.list",
|
|
20643
20725
|
"GET",
|
|
20644
20726
|
`/companies/${slug}/purchases`,
|
|
@@ -20651,11 +20733,11 @@ var FikenClient = class {
|
|
|
20651
20733
|
}
|
|
20652
20734
|
}
|
|
20653
20735
|
);
|
|
20654
|
-
return { companySlug: slug, purchases: projectArray(payload), page };
|
|
20736
|
+
return { companySlug: slug, purchases: projectArray(payload), page: page2 };
|
|
20655
20737
|
}
|
|
20656
20738
|
async listSales(input) {
|
|
20657
20739
|
const slug = this.companySlugFor(input.companySlug);
|
|
20658
|
-
const { payload, page } = await this.request("sales.list", "GET", `/companies/${slug}/sales`, {
|
|
20740
|
+
const { payload, page: page2 } = await this.request("sales.list", "GET", `/companies/${slug}/sales`, {
|
|
20659
20741
|
query: {
|
|
20660
20742
|
...pageQuery(input),
|
|
20661
20743
|
...input.dateGe ? { dateGe: input.dateGe } : {},
|
|
@@ -20663,7 +20745,7 @@ var FikenClient = class {
|
|
|
20663
20745
|
...input.settled !== void 0 ? { settled: String(input.settled) } : {}
|
|
20664
20746
|
}
|
|
20665
20747
|
});
|
|
20666
|
-
return { companySlug: slug, sales: projectArray(payload), page };
|
|
20748
|
+
return { companySlug: slug, sales: projectArray(payload), page: page2 };
|
|
20667
20749
|
}
|
|
20668
20750
|
/**
|
|
20669
20751
|
* The company scope for a call: an explicit slug wins, then the connection's
|
|
@@ -20865,11 +20947,11 @@ function boundedInt2(value, max, fallback) {
|
|
|
20865
20947
|
return Math.min(value, max);
|
|
20866
20948
|
}
|
|
20867
20949
|
function pageFromHeaders(headers) {
|
|
20868
|
-
const
|
|
20950
|
+
const page2 = headerInt(headers, "fiken-api-page");
|
|
20869
20951
|
const pageSize = headerInt(headers, "fiken-api-page-size");
|
|
20870
|
-
if (
|
|
20952
|
+
if (page2 === null || pageSize === null) return null;
|
|
20871
20953
|
return {
|
|
20872
|
-
page,
|
|
20954
|
+
page: page2,
|
|
20873
20955
|
pageSize,
|
|
20874
20956
|
pageCount: headerInt(headers, "fiken-api-page-count"),
|
|
20875
20957
|
resultCount: headerInt(headers, "fiken-api-result-count")
|
|
@@ -21828,24 +21910,24 @@ async function getAtlassianLiveItem(deps, input) {
|
|
|
21828
21910
|
);
|
|
21829
21911
|
url.searchParams.set("body-format", "storage");
|
|
21830
21912
|
try {
|
|
21831
|
-
const
|
|
21913
|
+
const page2 = objectRecord(
|
|
21832
21914
|
await atlassianApiRequest(deps, { ...input, url, label: "Confluence live page" })
|
|
21833
21915
|
);
|
|
21834
21916
|
const source = sources.find(
|
|
21835
|
-
(candidate) => candidate.resourceId === optionalString(
|
|
21917
|
+
(candidate) => candidate.resourceId === optionalString(page2.spaceId)
|
|
21836
21918
|
);
|
|
21837
21919
|
if (!source) continue;
|
|
21838
21920
|
const comments = await readConfluenceLiveComments(deps, input, cloudId);
|
|
21839
|
-
const webUi = optionalString(objectRecord(
|
|
21921
|
+
const webUi = optionalString(objectRecord(page2._links).webui);
|
|
21840
21922
|
return {
|
|
21841
21923
|
kind: "confluence_page",
|
|
21842
|
-
id: requiredString2(
|
|
21843
|
-
title: requiredString2(
|
|
21924
|
+
id: requiredString2(page2.id, "page.id"),
|
|
21925
|
+
title: requiredString2(page2.title, "page.title"),
|
|
21844
21926
|
source: { id: source.id, name: source.name, siteName: source.siteName },
|
|
21845
|
-
status: optionalString(
|
|
21846
|
-
createdAt: optionalString(
|
|
21847
|
-
updatedAt: optionalString(objectRecord(
|
|
21848
|
-
content: optionalString(objectRecord(objectRecord(
|
|
21927
|
+
status: optionalString(page2.status),
|
|
21928
|
+
createdAt: optionalString(page2.createdAt),
|
|
21929
|
+
updatedAt: optionalString(objectRecord(page2.version).createdAt),
|
|
21930
|
+
content: optionalString(objectRecord(objectRecord(page2.body).storage).value) ?? "",
|
|
21849
21931
|
comments,
|
|
21850
21932
|
url: webUi ? new URL(webUi.startsWith("/wiki/") ? webUi : `/wiki${webUi}`, source.siteUrl).toString() : source.siteUrl
|
|
21851
21933
|
};
|
|
@@ -22359,7 +22441,7 @@ async function materializeSchedules(deps, input) {
|
|
|
22359
22441
|
async function browseJiraProjects(deps, input, site) {
|
|
22360
22442
|
const items = [];
|
|
22361
22443
|
let startAt = 0;
|
|
22362
|
-
for (let
|
|
22444
|
+
for (let page2 = 0; page2 < 20; page2 += 1) {
|
|
22363
22445
|
const url = new URL(
|
|
22364
22446
|
`https://api.atlassian.com/ex/jira/${encodeURIComponent(site.cloudId)}/rest/api/3/project/search`
|
|
22365
22447
|
);
|
|
@@ -22402,7 +22484,7 @@ async function browseConfluenceSpaces(deps, input, site) {
|
|
|
22402
22484
|
let url = new URL(
|
|
22403
22485
|
`https://api.atlassian.com/ex/confluence/${encodeURIComponent(site.cloudId)}/wiki/api/v2/spaces?limit=100`
|
|
22404
22486
|
);
|
|
22405
|
-
for (let
|
|
22487
|
+
for (let page2 = 0; page2 < 20; page2 += 1) {
|
|
22406
22488
|
const payload = objectRecord(
|
|
22407
22489
|
await atlassianApiRequest(deps, { ...input, url, label: "Confluence spaces" })
|
|
22408
22490
|
);
|
|
@@ -22802,7 +22884,7 @@ function cqlString(value) {
|
|
|
22802
22884
|
async function readJiraLiveComments(deps, input, cloudId) {
|
|
22803
22885
|
const comments = [];
|
|
22804
22886
|
let startAt = 0;
|
|
22805
|
-
for (let
|
|
22887
|
+
for (let page2 = 0; page2 < 20; page2 += 1) {
|
|
22806
22888
|
const url = new URL(
|
|
22807
22889
|
`https://api.atlassian.com/ex/jira/${encodeURIComponent(cloudId)}/rest/api/3/issue/${encodeURIComponent(input.id)}/comment`
|
|
22808
22890
|
);
|
|
@@ -22830,7 +22912,7 @@ async function readJiraLiveComments(deps, input, cloudId) {
|
|
|
22830
22912
|
async function readConfluenceLiveComments(deps, input, cloudId) {
|
|
22831
22913
|
const comments = [];
|
|
22832
22914
|
let cursor = null;
|
|
22833
|
-
for (let
|
|
22915
|
+
for (let page2 = 0; page2 < 20; page2 += 1) {
|
|
22834
22916
|
const url = new URL(
|
|
22835
22917
|
`https://api.atlassian.com/ex/confluence/${encodeURIComponent(cloudId)}/wiki/api/v2/pages/${encodeURIComponent(input.id)}/footer-comments`
|
|
22836
22918
|
);
|
|
@@ -27285,9 +27367,9 @@ function registerFikenTools(server, deps, grant, sessionId, json) {
|
|
|
27285
27367
|
...pageInputs
|
|
27286
27368
|
}
|
|
27287
27369
|
},
|
|
27288
|
-
async ({ connectionId, page, pageSize }) => json(
|
|
27370
|
+
async ({ connectionId, page: page2, pageSize }) => json(
|
|
27289
27371
|
await (await clientFor(connectionId)).listCompanies({
|
|
27290
|
-
...
|
|
27372
|
+
...page2 !== void 0 ? { page: page2 } : {},
|
|
27291
27373
|
...pageSize !== void 0 ? { pageSize } : {}
|
|
27292
27374
|
})
|
|
27293
27375
|
)
|
|
@@ -29223,7 +29305,7 @@ function registerWorkspaceOrchestrationTools(server, deps, grant, can, callerSes
|
|
|
29223
29305
|
if (decodedCursor && decodedCursor.updatedAfter !== (normalizedUpdatedAfter ?? null)) {
|
|
29224
29306
|
throw new Error("sessions_list cursor does not match updatedAfter");
|
|
29225
29307
|
}
|
|
29226
|
-
const
|
|
29308
|
+
const page2 = await listSessionDiscoverySummaries(deps.db, grant.workspaceId, {
|
|
29227
29309
|
limit: boundedSessionDiscoveryLimit(limit),
|
|
29228
29310
|
...decodedCursor ? { cursor: decodedCursor } : {},
|
|
29229
29311
|
includeLastMessage: includeLastMessage === true,
|
|
@@ -29243,7 +29325,7 @@ function registerWorkspaceOrchestrationTools(server, deps, grant, can, callerSes
|
|
|
29243
29325
|
subjectId: grant.subjectId,
|
|
29244
29326
|
...authorizationScope ? { authorizationScope } : {}
|
|
29245
29327
|
});
|
|
29246
|
-
const result = detail === "full" ? capSessionDiscoveryPage(
|
|
29328
|
+
const result = detail === "full" ? capSessionDiscoveryPage(page2, includeLastMessage === true) : capSessionDiscoveryCompactPage(page2, {
|
|
29247
29329
|
includeLastMessage: includeLastMessage === true,
|
|
29248
29330
|
includeRelatedWork: relatedWorkRequested
|
|
29249
29331
|
});
|
|
@@ -29409,8 +29491,8 @@ function registerWorkspaceOrchestrationTools(server, deps, grant, can, callerSes
|
|
|
29409
29491
|
}
|
|
29410
29492
|
if (view !== "debug" && !auditRequested) {
|
|
29411
29493
|
const { readSessionEventView } = await import("./session-event-view-MU3HMNV3.js");
|
|
29412
|
-
const { listSessionEventSlices } = await import("@opengeni/db/session-event-slices");
|
|
29413
|
-
const
|
|
29494
|
+
const { listSessionEventSlices: listSessionEventSlices2 } = await import("@opengeni/db/session-event-slices");
|
|
29495
|
+
const page3 = await readSessionEventView(
|
|
29414
29496
|
{
|
|
29415
29497
|
sessionId,
|
|
29416
29498
|
view,
|
|
@@ -29423,7 +29505,7 @@ function registerWorkspaceOrchestrationTools(server, deps, grant, can, callerSes
|
|
|
29423
29505
|
direction: requestedDirection,
|
|
29424
29506
|
limit
|
|
29425
29507
|
},
|
|
29426
|
-
(options) =>
|
|
29508
|
+
(options) => listSessionEventSlices2(
|
|
29427
29509
|
deps.db,
|
|
29428
29510
|
grant.workspaceId,
|
|
29429
29511
|
sessionId,
|
|
@@ -29431,8 +29513,8 @@ function registerWorkspaceOrchestrationTools(server, deps, grant, can, callerSes
|
|
|
29431
29513
|
(legacyOptions) => listSessionEventPage(deps.db, grant.workspaceId, sessionId, legacyOptions)
|
|
29432
29514
|
)
|
|
29433
29515
|
);
|
|
29434
|
-
await acknowledgeReads([{ sessionId, sequences: completeChildReadSequences(
|
|
29435
|
-
return json(
|
|
29516
|
+
await acknowledgeReads([{ sessionId, sequences: completeChildReadSequences(page3) }]);
|
|
29517
|
+
return json(page3);
|
|
29436
29518
|
}
|
|
29437
29519
|
if (cursor !== void 0 || callId !== void 0 || includeArguments !== void 0 || includeOutput !== void 0) {
|
|
29438
29520
|
throw new Error("cursor/callId/includeArguments/includeOutput require a non-debug view");
|
|
@@ -29477,7 +29559,7 @@ function registerWorkspaceOrchestrationTools(server, deps, grant, can, callerSes
|
|
|
29477
29559
|
}
|
|
29478
29560
|
return json(result);
|
|
29479
29561
|
}
|
|
29480
|
-
const
|
|
29562
|
+
const page2 = boundSessionEventMcpPage({
|
|
29481
29563
|
events: dbPage.events,
|
|
29482
29564
|
mode,
|
|
29483
29565
|
payloadMode,
|
|
@@ -29487,12 +29569,12 @@ function registerWorkspaceOrchestrationTools(server, deps, grant, can, callerSes
|
|
|
29487
29569
|
after: after ?? 0,
|
|
29488
29570
|
before: before ?? null
|
|
29489
29571
|
});
|
|
29490
|
-
if (payloadMode === "full" && dbPage.fullPayloadsExact && !
|
|
29572
|
+
if (payloadMode === "full" && dbPage.fullPayloadsExact && !page2.truncation?.reasons.includes("model_payload")) {
|
|
29491
29573
|
await acknowledgeReads([
|
|
29492
|
-
{ sessionId, sequences:
|
|
29574
|
+
{ sessionId, sequences: page2.events.map((event) => event.sequence) }
|
|
29493
29575
|
]);
|
|
29494
29576
|
}
|
|
29495
|
-
return json(
|
|
29577
|
+
return json(page2);
|
|
29496
29578
|
}
|
|
29497
29579
|
);
|
|
29498
29580
|
server.registerTool(
|
|
@@ -29548,7 +29630,7 @@ function registerWorkspaceOrchestrationTools(server, deps, grant, can, callerSes
|
|
|
29548
29630
|
}
|
|
29549
29631
|
},
|
|
29550
29632
|
readTargetEvents: async (target) => {
|
|
29551
|
-
const
|
|
29633
|
+
const page2 = await listSessionEventPage(deps.db, workspaceId, target.sessionId, {
|
|
29552
29634
|
after: target.afterSequence,
|
|
29553
29635
|
direction: "after",
|
|
29554
29636
|
limit: SESSION_WAIT_EVENTS_PER_TARGET,
|
|
@@ -29556,10 +29638,10 @@ function registerWorkspaceOrchestrationTools(server, deps, grant, can, callerSes
|
|
|
29556
29638
|
includeTypes: targetEventTypes,
|
|
29557
29639
|
maxBytes: SESSION_EVENT_MCP_MAX_BYTES * 4
|
|
29558
29640
|
});
|
|
29559
|
-
if (!
|
|
29560
|
-
for (const event of
|
|
29641
|
+
if (!page2.fullPayloadsExact) {
|
|
29642
|
+
for (const event of page2.events) incompleteWaitEvents.add(event.id);
|
|
29561
29643
|
}
|
|
29562
|
-
return { events:
|
|
29644
|
+
return { events: page2.events, hasMore: page2.hasMore };
|
|
29563
29645
|
},
|
|
29564
29646
|
readOwnPendingUpdateKinds: ownSessionId === null ? null : async () => (await listOutstandingSessionSystemUpdates(deps.db, workspaceId, ownSessionId)).map((update) => update.kind),
|
|
29565
29647
|
subscribe: (targetSessionId, onEvents) => deps.bus.subscribe(workspaceId, targetSessionId, onEvents)
|
|
@@ -30443,9 +30525,12 @@ function registerCapabilityDiscoveryTools(server, deps, grant, sessionId, json)
|
|
|
30443
30525
|
};
|
|
30444
30526
|
const setupProjections = async (items) => {
|
|
30445
30527
|
const availableServerIds = /* @__PURE__ */ new Set();
|
|
30528
|
+
const availableFirstPartyTools = /* @__PURE__ */ new Set();
|
|
30446
30529
|
const acceptedServerIds = /* @__PURE__ */ new Set();
|
|
30447
30530
|
let accountSelectionKnown = false;
|
|
30448
|
-
if (items.some(
|
|
30531
|
+
if (items.some(
|
|
30532
|
+
(item) => item.enabled && (item.connectionRef || item.surfaceType === "first_party_fiken")
|
|
30533
|
+
)) {
|
|
30449
30534
|
const claims = exactAgentCommandContext(grant, sessionId);
|
|
30450
30535
|
const attemptCatalog = await getAttemptToolCatalog2(deps.db, {
|
|
30451
30536
|
accountId: grant.accountId,
|
|
@@ -30453,7 +30538,11 @@ function registerCapabilityDiscoveryTools(server, deps, grant, sessionId, json)
|
|
|
30453
30538
|
attemptId: claims.callerAttemptId
|
|
30454
30539
|
});
|
|
30455
30540
|
if (attemptCatalog?.sessionId === sessionId && attemptCatalog.turnId === claims.callerTurnId && attemptCatalog.executionGeneration === claims.callerExecutionGeneration) {
|
|
30456
|
-
for (const entry2 of attemptCatalog.entries)
|
|
30541
|
+
for (const entry2 of attemptCatalog.entries) {
|
|
30542
|
+
availableServerIds.add(entry2.identity.serverId);
|
|
30543
|
+
if (entry2.identity.serverId === "opengeni")
|
|
30544
|
+
availableFirstPartyTools.add(entry2.identity.toolName);
|
|
30545
|
+
}
|
|
30457
30546
|
const bindings = await getSessionTurnMcpAccountBindings(
|
|
30458
30547
|
deps.db,
|
|
30459
30548
|
grant.workspaceId,
|
|
@@ -30474,7 +30563,9 @@ function registerCapabilityDiscoveryTools(server, deps, grant, sessionId, json)
|
|
|
30474
30563
|
item,
|
|
30475
30564
|
availableServerIds,
|
|
30476
30565
|
acceptedServerIds,
|
|
30477
|
-
accountSelectionKnown
|
|
30566
|
+
accountSelectionKnown,
|
|
30567
|
+
availableFirstPartyTools,
|
|
30568
|
+
new Set(grant.metadata?.firstPartyMcpTools ?? [])
|
|
30478
30569
|
)
|
|
30479
30570
|
)
|
|
30480
30571
|
);
|
|
@@ -30593,7 +30684,38 @@ function registerCapabilityDiscoveryTools(server, deps, grant, sessionId, json)
|
|
|
30593
30684
|
}
|
|
30594
30685
|
);
|
|
30595
30686
|
}
|
|
30596
|
-
async function capabilitySetupProjection(deps, workspaceId, item, availableServerIds, acceptedServerIds, accountSelectionKnown) {
|
|
30687
|
+
async function capabilitySetupProjection(deps, workspaceId, item, availableServerIds, acceptedServerIds, accountSelectionKnown, availableFirstPartyTools, selectedFirstPartyTools) {
|
|
30688
|
+
if (item.surfaceType === "first_party_fiken") {
|
|
30689
|
+
if (!item.enabled || item.metadata.connectionStatus !== "active") {
|
|
30690
|
+
return {
|
|
30691
|
+
status: "authorization_required",
|
|
30692
|
+
action: "connect",
|
|
30693
|
+
detail: item.metadata.connectionStatus === "needs_reauth" ? "The workspace Fiken connection needs reconnection." : "Connect Fiken through the protected setup form."
|
|
30694
|
+
};
|
|
30695
|
+
}
|
|
30696
|
+
const selected = FIRST_PARTY_MCP_TOOL_NAMES2.filter(
|
|
30697
|
+
(name) => name.startsWith("fiken_") && selectedFirstPartyTools.has(name)
|
|
30698
|
+
);
|
|
30699
|
+
if (selected.length === 0) {
|
|
30700
|
+
return {
|
|
30701
|
+
status: "authorization_required",
|
|
30702
|
+
action: "enable",
|
|
30703
|
+
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."
|
|
30704
|
+
};
|
|
30705
|
+
}
|
|
30706
|
+
if (selected.some((name) => availableFirstPartyTools.has(name))) {
|
|
30707
|
+
return {
|
|
30708
|
+
status: "ready",
|
|
30709
|
+
action: null,
|
|
30710
|
+
detail: "Fiken is connected and has tools available in this turn."
|
|
30711
|
+
};
|
|
30712
|
+
}
|
|
30713
|
+
return {
|
|
30714
|
+
status: "unavailable",
|
|
30715
|
+
action: null,
|
|
30716
|
+
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."
|
|
30717
|
+
};
|
|
30718
|
+
}
|
|
30597
30719
|
if (item.id === "api:github-app" || item.surfaceType === "first_party_github") {
|
|
30598
30720
|
const missing = githubAppMissingSettings(deps.settings);
|
|
30599
30721
|
if (missing.length > 0) {
|
|
@@ -30947,9 +31069,9 @@ function decodeSessionDiscoveryCursor(value) {
|
|
|
30947
31069
|
throw new Error("sessions_list cursor is invalid");
|
|
30948
31070
|
}
|
|
30949
31071
|
}
|
|
30950
|
-
function capSessionDiscoveryCompactPage(
|
|
31072
|
+
function capSessionDiscoveryCompactPage(page2, options = {}, maxBytes = SESSION_DISCOVERY_PAGE_MAX_BYTES) {
|
|
30951
31073
|
let previewBytes = 0;
|
|
30952
|
-
const projected =
|
|
31074
|
+
const projected = page2.sessions.map((session) => {
|
|
30953
31075
|
const row = {
|
|
30954
31076
|
...compactSessionMcpListRow(session, options.includeRelatedWork),
|
|
30955
31077
|
...options.includeLastMessage && session.queuedPromptCount > 0 ? { queuedPromptCount: session.queuedPromptCount } : {}
|
|
@@ -30986,24 +31108,24 @@ function capSessionDiscoveryCompactPage(page, options = {}, maxBytes = SESSION_D
|
|
|
30986
31108
|
let kept = projected;
|
|
30987
31109
|
const build = () => {
|
|
30988
31110
|
const dropped = kept.length < projected.length;
|
|
30989
|
-
const last =
|
|
31111
|
+
const last = page2.sessions[kept.length - 1];
|
|
30990
31112
|
const cursor = dropped && last ? {
|
|
30991
|
-
orderBy:
|
|
31113
|
+
orderBy: page2.orderBy,
|
|
30992
31114
|
sortRank: last.sortRank,
|
|
30993
31115
|
sortRevision: last.sortRevision,
|
|
30994
31116
|
sortAt: last.sortAt,
|
|
30995
31117
|
id: last.id,
|
|
30996
|
-
snapshotAt:
|
|
30997
|
-
snapshotRevision:
|
|
30998
|
-
updatedAfter:
|
|
30999
|
-
filterHash:
|
|
31000
|
-
...
|
|
31001
|
-
} :
|
|
31118
|
+
snapshotAt: page2.snapshotAt,
|
|
31119
|
+
snapshotRevision: page2.snapshotRevision,
|
|
31120
|
+
updatedAfter: page2.updatedAfter,
|
|
31121
|
+
filterHash: page2.filterHash,
|
|
31122
|
+
...page2.originSiteId ? { originSiteId: page2.originSiteId } : {}
|
|
31123
|
+
} : page2.nextCursor;
|
|
31002
31124
|
return {
|
|
31003
31125
|
sessions: kept,
|
|
31004
|
-
total:
|
|
31126
|
+
total: page2.total,
|
|
31005
31127
|
nextCursor: cursor ? encodeSessionDiscoveryCursor(cursor) : null,
|
|
31006
|
-
...
|
|
31128
|
+
...page2.orderBy === "updatedAt" ? { updatedThrough: page2.updatedThrough } : {},
|
|
31007
31129
|
...dropped ? {
|
|
31008
31130
|
responseTruncated: true,
|
|
31009
31131
|
truncationReason: `response exceeded ${maxBytes} bytes; continue with nextCursor`
|
|
@@ -31020,8 +31142,8 @@ function capSessionDiscoveryCompactPage(page, options = {}, maxBytes = SESSION_D
|
|
|
31020
31142
|
}
|
|
31021
31143
|
return result;
|
|
31022
31144
|
}
|
|
31023
|
-
function capSessionDiscoveryPage(
|
|
31024
|
-
const projected =
|
|
31145
|
+
function capSessionDiscoveryPage(page2, includeLastMessage) {
|
|
31146
|
+
const projected = page2.sessions.map((session) => {
|
|
31025
31147
|
const title = capSessionDiscoveryText(session.title, 200, session.titleOriginalChars);
|
|
31026
31148
|
const goal = session.goal ? capSessionDiscoveryText(
|
|
31027
31149
|
session.goal.text,
|
|
@@ -31108,29 +31230,29 @@ function capSessionDiscoveryPage(page, includeLastMessage) {
|
|
|
31108
31230
|
}).length : 0;
|
|
31109
31231
|
const lastKept = kept.at(-1);
|
|
31110
31232
|
const droppedForByteCap = kept.length < projected.length;
|
|
31111
|
-
const sourceLast = lastKept ?
|
|
31233
|
+
const sourceLast = lastKept ? page2.sessions.find((session) => session.id === lastKept.id) : void 0;
|
|
31112
31234
|
const nextCursor = droppedForByteCap ? sourceLast ? encodeSessionDiscoveryCursor({
|
|
31113
|
-
orderBy:
|
|
31235
|
+
orderBy: page2.orderBy,
|
|
31114
31236
|
sortRank: sourceLast.sortRank,
|
|
31115
31237
|
sortRevision: sourceLast.sortRevision,
|
|
31116
31238
|
sortAt: sourceLast.sortAt,
|
|
31117
31239
|
id: sourceLast.id,
|
|
31118
|
-
snapshotAt:
|
|
31119
|
-
snapshotRevision:
|
|
31120
|
-
updatedAfter:
|
|
31121
|
-
filterHash:
|
|
31122
|
-
...
|
|
31123
|
-
}) : null :
|
|
31240
|
+
snapshotAt: page2.snapshotAt,
|
|
31241
|
+
snapshotRevision: page2.snapshotRevision,
|
|
31242
|
+
updatedAfter: page2.updatedAfter,
|
|
31243
|
+
filterHash: page2.filterHash,
|
|
31244
|
+
...page2.originSiteId ? { originSiteId: page2.originSiteId } : {}
|
|
31245
|
+
}) : null : page2.nextCursor ? encodeSessionDiscoveryCursor(page2.nextCursor) : null;
|
|
31124
31246
|
const result2 = {
|
|
31125
31247
|
sessions: kept,
|
|
31126
|
-
total:
|
|
31127
|
-
hasMore:
|
|
31248
|
+
total: page2.total,
|
|
31249
|
+
hasMore: page2.hasMore || droppedForByteCap,
|
|
31128
31250
|
nextCursor,
|
|
31129
|
-
orderBy:
|
|
31130
|
-
snapshotAt:
|
|
31131
|
-
snapshotRevision:
|
|
31132
|
-
updatedAfter:
|
|
31133
|
-
updatedThrough:
|
|
31251
|
+
orderBy: page2.orderBy,
|
|
31252
|
+
snapshotAt: page2.snapshotAt,
|
|
31253
|
+
snapshotRevision: page2.snapshotRevision,
|
|
31254
|
+
updatedAfter: page2.updatedAfter,
|
|
31255
|
+
updatedThrough: page2.updatedThrough,
|
|
31134
31256
|
...includeLastMessage ? {
|
|
31135
31257
|
latestMessagePreviewBudget: {
|
|
31136
31258
|
bytes: previewBytes,
|
|
@@ -67405,7 +67527,8 @@ function registerDocumentRoutes(app, deps) {
|
|
|
67405
67527
|
deps,
|
|
67406
67528
|
await requireAccessGrantAuthorization8(c, deps, workspaceId, "documents:search"),
|
|
67407
67529
|
"documents:search"
|
|
67408
|
-
)
|
|
67530
|
+
),
|
|
67531
|
+
settings: deps.settings
|
|
67409
67532
|
}
|
|
67410
67533
|
);
|
|
67411
67534
|
await server.connect(transport);
|
|
@@ -67492,6 +67615,8 @@ import {
|
|
|
67492
67615
|
prepareKnowledgeFile as prepareKnowledgeFile2,
|
|
67493
67616
|
prepareKnowledgeSave as prepareKnowledgeSave2,
|
|
67494
67617
|
searchKnowledgeEntries as searchKnowledgeEntries3,
|
|
67618
|
+
KnowledgeVectorFundingError,
|
|
67619
|
+
KnowledgeVectorQueryRejectedError,
|
|
67495
67620
|
hasPermission as hasPermission13,
|
|
67496
67621
|
knowledgeContextForAccess as knowledgeContextForAccess2,
|
|
67497
67622
|
requireAccessGrantAuthorization as requireAccessGrantAuthorization9,
|
|
@@ -67531,6 +67656,18 @@ var WriteSettings = ReadSettings.extend({
|
|
|
67531
67656
|
var Id = z22.uuid();
|
|
67532
67657
|
function knowledgeHttpError(error) {
|
|
67533
67658
|
if (error instanceof HTTPException42) throw error;
|
|
67659
|
+
if (error instanceof KnowledgeVectorFundingError)
|
|
67660
|
+
throw new ApiHttpError(402, {
|
|
67661
|
+
code: "payment_required",
|
|
67662
|
+
message: error.message,
|
|
67663
|
+
details: { code: error.code, keywordAvailable: true }
|
|
67664
|
+
});
|
|
67665
|
+
if (error instanceof KnowledgeVectorQueryRejectedError)
|
|
67666
|
+
throw new ApiHttpError(error.code === "quota" ? 429 : 422, {
|
|
67667
|
+
code: error.code === "quota" ? "limit_exceeded" : "validation_failed",
|
|
67668
|
+
message: error.message,
|
|
67669
|
+
details: { code: error.code, keywordAvailable: true }
|
|
67670
|
+
});
|
|
67534
67671
|
if (error instanceof z22.ZodError)
|
|
67535
67672
|
throw new HTTPException42(422, {
|
|
67536
67673
|
message: error.issues[0]?.message ?? "Invalid Knowledge request"
|
|
@@ -67662,7 +67799,9 @@ function registerKnowledgeRoutes(app, deps) {
|
|
|
67662
67799
|
deps.db,
|
|
67663
67800
|
context,
|
|
67664
67801
|
KnowledgeSavePreparationRequest2.parse(await c.req.json()),
|
|
67665
|
-
() => deps.getDocumentServices().embedder
|
|
67802
|
+
() => deps.getDocumentServices().embedder,
|
|
67803
|
+
void 0,
|
|
67804
|
+
deps.settings
|
|
67666
67805
|
)
|
|
67667
67806
|
);
|
|
67668
67807
|
})
|
|
@@ -67677,7 +67816,8 @@ function registerKnowledgeRoutes(app, deps) {
|
|
|
67677
67816
|
deps.db,
|
|
67678
67817
|
context,
|
|
67679
67818
|
KnowledgeEntryListRequest3.parse(await c.req.json()),
|
|
67680
|
-
() => deps.getDocumentServices().embedder
|
|
67819
|
+
() => deps.getDocumentServices().embedder,
|
|
67820
|
+
deps.settings
|
|
67681
67821
|
)
|
|
67682
67822
|
)
|
|
67683
67823
|
)
|
|
@@ -67724,7 +67864,8 @@ function registerKnowledgeRoutes(app, deps) {
|
|
|
67724
67864
|
...query,
|
|
67725
67865
|
...query.limit ? { limit: Number(query.limit) } : {}
|
|
67726
67866
|
}),
|
|
67727
|
-
() => deps.getDocumentServices().embedder
|
|
67867
|
+
() => deps.getDocumentServices().embedder,
|
|
67868
|
+
deps.settings
|
|
67728
67869
|
)
|
|
67729
67870
|
);
|
|
67730
67871
|
})
|
|
@@ -70394,7 +70535,8 @@ import { randomUUID as randomUUID7 } from "crypto";
|
|
|
70394
70535
|
import {
|
|
70395
70536
|
environmentsEncryptionKeyBytes as environmentsEncryptionKeyBytes5,
|
|
70396
70537
|
resolveFirstPartyDelegationSecret as resolveFirstPartyDelegationSecret3,
|
|
70397
|
-
resolveStreamTokenSecret as resolveStreamTokenSecret2
|
|
70538
|
+
resolveStreamTokenSecret as resolveStreamTokenSecret2,
|
|
70539
|
+
sandboxWarmRateMicrosPerSecond as sandboxWarmRateMicrosPerSecond3
|
|
70398
70540
|
} from "@opengeni/config";
|
|
70399
70541
|
import {
|
|
70400
70542
|
BROWSER_CONTROL_WEBSOCKET_BEARER_PREFIX,
|
|
@@ -70412,6 +70554,8 @@ import {
|
|
|
70412
70554
|
BrowserDownloadSaveRequest,
|
|
70413
70555
|
BrowserDownloadSaveResponse,
|
|
70414
70556
|
BrowserDownloadListResponse,
|
|
70557
|
+
BrowserDomReadRequest,
|
|
70558
|
+
BrowserDomReadResponse,
|
|
70415
70559
|
BrowserExternalAuthCommand,
|
|
70416
70560
|
BrowserOpenTargetRequest,
|
|
70417
70561
|
BrowserObservation,
|
|
@@ -70423,6 +70567,7 @@ import {
|
|
|
70423
70567
|
BrowserSessionListResponse,
|
|
70424
70568
|
BrowserSessionMutationResponse,
|
|
70425
70569
|
BrowserTargetListResponse,
|
|
70570
|
+
BrowserTargetState,
|
|
70426
70571
|
CreateBrowserSessionRequest,
|
|
70427
70572
|
ExternalAuthInteractiveRequest,
|
|
70428
70573
|
ExternalAuthInteractiveResponse,
|
|
@@ -70454,6 +70599,7 @@ import {
|
|
|
70454
70599
|
BrowserSessionNotFoundError,
|
|
70455
70600
|
BrowserSessionOperationConflictError,
|
|
70456
70601
|
BrowserSessionStateError as BrowserSessionStateError2,
|
|
70602
|
+
SandboxPaidComputeAdmissionError as SandboxPaidComputeAdmissionError3,
|
|
70457
70603
|
completeBrowserSessionEnd,
|
|
70458
70604
|
completeExternalAuth,
|
|
70459
70605
|
completeBrowserDownloadSave,
|
|
@@ -70467,6 +70613,7 @@ import {
|
|
|
70467
70613
|
dispatchExternalAuth,
|
|
70468
70614
|
dispatchProtectedAuthFill,
|
|
70469
70615
|
failBrowserSessionOperation,
|
|
70616
|
+
failPreparedBrowserSessionSuspend,
|
|
70470
70617
|
failBrowserSessionResume,
|
|
70471
70618
|
failBrowserSessionResumePreparation,
|
|
70472
70619
|
failBrowserSessionSuspension,
|
|
@@ -72355,6 +72502,68 @@ function registerBrowserSessionRoutes(app, deps) {
|
|
|
72355
72502
|
return context.json(result);
|
|
72356
72503
|
}
|
|
72357
72504
|
);
|
|
72505
|
+
app.get(
|
|
72506
|
+
"/v1/workspaces/:workspaceId/browser-sessions/:browserSessionId/targets/:targetId/state",
|
|
72507
|
+
async (context) => {
|
|
72508
|
+
const { workspaceId, grant, browserSessionId } = await browserRoutePreamble(
|
|
72509
|
+
context,
|
|
72510
|
+
"sessions:read"
|
|
72511
|
+
);
|
|
72512
|
+
const targetId = requireOpaqueParam(context, "targetId");
|
|
72513
|
+
const result = await withActiveBrowserController(
|
|
72514
|
+
context,
|
|
72515
|
+
grant,
|
|
72516
|
+
workspaceId,
|
|
72517
|
+
browserSessionId,
|
|
72518
|
+
"session.read",
|
|
72519
|
+
"browser.read",
|
|
72520
|
+
async ({ sessionClient }) => await sessionClient.targetState(targetId)
|
|
72521
|
+
);
|
|
72522
|
+
return context.json(BrowserTargetState.parse(result));
|
|
72523
|
+
}
|
|
72524
|
+
);
|
|
72525
|
+
app.post(
|
|
72526
|
+
"/v1/workspaces/:workspaceId/browser-sessions/:browserSessionId/targets/:targetId/dom-read",
|
|
72527
|
+
async (context) => {
|
|
72528
|
+
const { workspaceId, grant, browserSessionId } = await browserRoutePreamble(
|
|
72529
|
+
context,
|
|
72530
|
+
"sessions:read"
|
|
72531
|
+
);
|
|
72532
|
+
const targetId = requireOpaqueParam(context, "targetId");
|
|
72533
|
+
const request = await parseJsonBody2(context, BrowserDomReadRequest);
|
|
72534
|
+
const result = await withActiveBrowserController(
|
|
72535
|
+
context,
|
|
72536
|
+
grant,
|
|
72537
|
+
workspaceId,
|
|
72538
|
+
browserSessionId,
|
|
72539
|
+
"session.read",
|
|
72540
|
+
"browser.read",
|
|
72541
|
+
async ({ sessionClient }) => await sessionClient.readDom(targetId, request)
|
|
72542
|
+
);
|
|
72543
|
+
return context.json(BrowserDomReadResponse.parse(result));
|
|
72544
|
+
}
|
|
72545
|
+
);
|
|
72546
|
+
app.get(
|
|
72547
|
+
"/v1/workspaces/:workspaceId/browser-sessions/:browserSessionId/targets/:targetId/screenshot",
|
|
72548
|
+
async (context) => {
|
|
72549
|
+
const { workspaceId, grant, browserSessionId } = await browserRoutePreamble(
|
|
72550
|
+
context,
|
|
72551
|
+
"sessions:read"
|
|
72552
|
+
);
|
|
72553
|
+
const targetId = requireOpaqueParam(context, "targetId");
|
|
72554
|
+
const captureOptions = parseBrowserScreenshotOptions(new URL(context.req.url).searchParams);
|
|
72555
|
+
const frame = await withActiveBrowserController(
|
|
72556
|
+
context,
|
|
72557
|
+
grant,
|
|
72558
|
+
workspaceId,
|
|
72559
|
+
browserSessionId,
|
|
72560
|
+
"session.read",
|
|
72561
|
+
"browser.read",
|
|
72562
|
+
async ({ sessionClient }) => await sessionClient.capture(targetId, captureOptions)
|
|
72563
|
+
);
|
|
72564
|
+
return browserScreenshotResponse(frame);
|
|
72565
|
+
}
|
|
72566
|
+
);
|
|
72358
72567
|
app.post(
|
|
72359
72568
|
"/v1/workspaces/:workspaceId/browser-sessions/:browserSessionId/actions",
|
|
72360
72569
|
async (context) => {
|
|
@@ -73388,6 +73597,7 @@ function registerBrowserSessionRoutes(app, deps) {
|
|
|
73388
73597
|
const request = await parseJsonBody2(context, BrowserSessionLifecycleRequest);
|
|
73389
73598
|
const startedAtMs = performance.now();
|
|
73390
73599
|
const origin = requestOrigin(context, deps.settings);
|
|
73600
|
+
let preparedForDispatch = false;
|
|
73391
73601
|
try {
|
|
73392
73602
|
const before = await getBrowserSessionControlRecord(deps.db, {
|
|
73393
73603
|
accountId: grant.accountId,
|
|
@@ -73436,6 +73646,7 @@ function registerBrowserSessionRoutes(app, deps) {
|
|
|
73436
73646
|
observeLifecycleResult(deps.observability, startedAtMs, parsed2);
|
|
73437
73647
|
return context.json(parsed2, 200);
|
|
73438
73648
|
}
|
|
73649
|
+
preparedForDispatch = true;
|
|
73439
73650
|
const record6 = await getBrowserSessionControlRecord(deps.db, {
|
|
73440
73651
|
accountId: grant.accountId,
|
|
73441
73652
|
workspaceId,
|
|
@@ -73594,6 +73805,15 @@ function registerBrowserSessionRoutes(app, deps) {
|
|
|
73594
73805
|
observeLifecycleResult(deps.observability, startedAtMs, parsed);
|
|
73595
73806
|
return context.json(parsed, 200);
|
|
73596
73807
|
} catch (error) {
|
|
73808
|
+
if (preparedForDispatch) {
|
|
73809
|
+
await failPreparedBrowserSessionSuspend(deps.db, {
|
|
73810
|
+
accountId: grant.accountId,
|
|
73811
|
+
workspaceId,
|
|
73812
|
+
browserSessionId,
|
|
73813
|
+
operationId: request.operationId,
|
|
73814
|
+
error: interactionFailure(error)
|
|
73815
|
+
});
|
|
73816
|
+
}
|
|
73597
73817
|
throw browserRouteError(error);
|
|
73598
73818
|
}
|
|
73599
73819
|
}
|
|
@@ -74082,6 +74302,11 @@ function registerBrowserSessionRoutes(app, deps) {
|
|
|
74082
74302
|
const resolved = await handle.routingSession.prime();
|
|
74083
74303
|
if (expectedPlacement?.kind === "connected_machine") {
|
|
74084
74304
|
if (resolved.kind !== "selfhosted" || resolved.sandboxId !== expectedPlacement.sandboxId) {
|
|
74305
|
+
if (operation === "browser.create") {
|
|
74306
|
+
throw new HTTPException51(422, {
|
|
74307
|
+
message: "The requested Connected Machine is not this session's current placement. Move the session to that machine before creating an interaction resource."
|
|
74308
|
+
});
|
|
74309
|
+
}
|
|
74085
74310
|
return await throwBrowserSourcePlacementChanged(
|
|
74086
74311
|
grant,
|
|
74087
74312
|
sourceSession.id,
|
|
@@ -74797,6 +75022,10 @@ async function ensureInteractionHolder(deps, grant, sourceSession, browserSessio
|
|
|
74797
75022
|
holderId: interactionHolderId(browserSessionId),
|
|
74798
75023
|
subjectId: sourceSession.id,
|
|
74799
75024
|
backend: placement.lease.backend,
|
|
75025
|
+
warmBilling: {
|
|
75026
|
+
mode: deps.settings.sandboxWarmBillingMode,
|
|
75027
|
+
rateMicrosPerSecond: sandboxWarmRateMicrosPerSecond3(deps.settings, placement.lease.backend)
|
|
75028
|
+
},
|
|
74800
75029
|
os: placement.lease.os,
|
|
74801
75030
|
image: sandboxRuntime.image,
|
|
74802
75031
|
rigVersionId: sourceSession.rigVersionId,
|
|
@@ -75086,6 +75315,41 @@ function optionalBoundedInteger(value, minimum, maximum) {
|
|
|
75086
75315
|
}
|
|
75087
75316
|
return parsed;
|
|
75088
75317
|
}
|
|
75318
|
+
function parseBrowserScreenshotOptions(query) {
|
|
75319
|
+
for (const key of ["fullPage", "format", "quality"]) {
|
|
75320
|
+
if (query.getAll(key).length > 1) {
|
|
75321
|
+
throw new HTTPException51(400, { message: `duplicate browser screenshot ${key}` });
|
|
75322
|
+
}
|
|
75323
|
+
}
|
|
75324
|
+
const fullPage = query.get("fullPage");
|
|
75325
|
+
if (fullPage !== null && fullPage !== "true" && fullPage !== "false") {
|
|
75326
|
+
throw new HTTPException51(400, { message: "invalid browser screenshot fullPage" });
|
|
75327
|
+
}
|
|
75328
|
+
const format = query.get("format");
|
|
75329
|
+
if (format !== null && format !== "jpeg" && format !== "png") {
|
|
75330
|
+
throw new HTTPException51(400, { message: "invalid browser screenshot format" });
|
|
75331
|
+
}
|
|
75332
|
+
const quality = query.get("quality");
|
|
75333
|
+
const parsedQuality = quality === null ? null : optionalBoundedInteger(quality, 1, 100);
|
|
75334
|
+
if (quality !== null && parsedQuality === null) {
|
|
75335
|
+
throw new HTTPException51(400, { message: "invalid browser screenshot quality" });
|
|
75336
|
+
}
|
|
75337
|
+
return {
|
|
75338
|
+
...fullPage === null ? {} : { fullPage: fullPage === "true" },
|
|
75339
|
+
...format === null ? {} : { format },
|
|
75340
|
+
...parsedQuality === null ? {} : { quality: parsedQuality }
|
|
75341
|
+
};
|
|
75342
|
+
}
|
|
75343
|
+
function browserScreenshotResponse(frame) {
|
|
75344
|
+
return new Response(Uint8Array.from(frame.data).buffer, {
|
|
75345
|
+
status: 200,
|
|
75346
|
+
headers: {
|
|
75347
|
+
"cache-control": "no-store",
|
|
75348
|
+
"content-type": frame.mediaType,
|
|
75349
|
+
"x-opengeni-browser-frame": frame.metadataHeader
|
|
75350
|
+
}
|
|
75351
|
+
});
|
|
75352
|
+
}
|
|
75089
75353
|
function isUuid(value) {
|
|
75090
75354
|
return typeof value === "string" && /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/iu.test(value);
|
|
75091
75355
|
}
|
|
@@ -75480,6 +75744,8 @@ function browserRouteError(error) {
|
|
|
75480
75744
|
const connectedMachineError = interactionControlApiError(error, "browser");
|
|
75481
75745
|
if (connectedMachineError) return connectedMachineError;
|
|
75482
75746
|
if (error instanceof HTTPException51) return error;
|
|
75747
|
+
if (error instanceof SandboxPaidComputeAdmissionError3)
|
|
75748
|
+
return new HTTPException51(402, { message: error.message, cause: error });
|
|
75483
75749
|
if (error instanceof BrowserSessionNotFoundError) {
|
|
75484
75750
|
return new HTTPException51(404, { message: error.message, cause: error });
|
|
75485
75751
|
}
|
|
@@ -75533,7 +75799,11 @@ function isAbort(error) {
|
|
|
75533
75799
|
|
|
75534
75800
|
// src/routes/computer-sessions.ts
|
|
75535
75801
|
import { randomUUID as randomUUID8 } from "crypto";
|
|
75536
|
-
import {
|
|
75802
|
+
import {
|
|
75803
|
+
resolveFirstPartyDelegationSecret as resolveFirstPartyDelegationSecret4,
|
|
75804
|
+
resolveStreamTokenSecret as resolveStreamTokenSecret3,
|
|
75805
|
+
sandboxWarmRateMicrosPerSecond as sandboxWarmRateMicrosPerSecond4
|
|
75806
|
+
} from "@opengeni/config";
|
|
75537
75807
|
import {
|
|
75538
75808
|
BROWSER_CONTROL_WEBSOCKET_BEARER_PREFIX as BROWSER_CONTROL_WEBSOCKET_BEARER_PREFIX2,
|
|
75539
75809
|
BROWSER_CONTROL_PORT as BROWSER_CONTROL_PORT2,
|
|
@@ -75560,6 +75830,7 @@ import {
|
|
|
75560
75830
|
ComputerSessionNotFoundError,
|
|
75561
75831
|
ComputerSessionOperationConflictError,
|
|
75562
75832
|
ComputerSessionStateError,
|
|
75833
|
+
SandboxPaidComputeAdmissionError as SandboxPaidComputeAdmissionError4,
|
|
75563
75834
|
dispatchComputerSessionOperation,
|
|
75564
75835
|
failComputerSessionOperation,
|
|
75565
75836
|
findComputerSessionControlRecordByOperation,
|
|
@@ -76447,6 +76718,11 @@ function registerComputerSessionRoutes(app, deps) {
|
|
|
76447
76718
|
}
|
|
76448
76719
|
if (expectedPlacement?.kind === "connected_machine") {
|
|
76449
76720
|
if (resolved.kind !== "selfhosted" || resolved.sandboxId !== expectedPlacement.sandboxId) {
|
|
76721
|
+
if (operation === "computer.create") {
|
|
76722
|
+
throw new HTTPException52(422, {
|
|
76723
|
+
message: "The requested Connected Machine is not this session's current placement. Move the session to that machine before creating an interaction resource."
|
|
76724
|
+
});
|
|
76725
|
+
}
|
|
76450
76726
|
return await throwComputerSourcePlacementChanged(
|
|
76451
76727
|
grant,
|
|
76452
76728
|
sourceSession.id,
|
|
@@ -76733,6 +77009,10 @@ function registerComputerSessionRoutes(app, deps) {
|
|
|
76733
77009
|
holderId: interactionHolderId2(computerSessionId),
|
|
76734
77010
|
subjectId: sourceSession.id,
|
|
76735
77011
|
backend: placement.lease.backend,
|
|
77012
|
+
warmBilling: {
|
|
77013
|
+
mode: deps.settings.sandboxWarmBillingMode,
|
|
77014
|
+
rateMicrosPerSecond: sandboxWarmRateMicrosPerSecond4(deps.settings, placement.lease.backend)
|
|
77015
|
+
},
|
|
76736
77016
|
os: placement.lease.os,
|
|
76737
77017
|
image: sandboxRuntime.image,
|
|
76738
77018
|
rigVersionId: sourceSession.rigVersionId,
|
|
@@ -77055,6 +77335,8 @@ function computerRouteError(error) {
|
|
|
77055
77335
|
const connectedMachineError = interactionControlApiError(error, "computer");
|
|
77056
77336
|
if (connectedMachineError) return connectedMachineError;
|
|
77057
77337
|
if (error instanceof HTTPException52) return error;
|
|
77338
|
+
if (error instanceof SandboxPaidComputeAdmissionError4)
|
|
77339
|
+
return new HTTPException52(402, { message: error.message, cause: error });
|
|
77058
77340
|
if (error instanceof ComputerSessionNotFoundError) {
|
|
77059
77341
|
return new HTTPException52(404, { message: error.message, cause: error });
|
|
77060
77342
|
}
|
|
@@ -77203,6 +77485,92 @@ async function integrationCommitGrant(authorization, permissions, request) {
|
|
|
77203
77485
|
};
|
|
77204
77486
|
}
|
|
77205
77487
|
|
|
77488
|
+
// src/routes/github-browser-pages.ts
|
|
77489
|
+
var pageStyle = `
|
|
77490
|
+
:root{color-scheme:dark;--bg:oklch(.155 .012 260);--surface:oklch(.19 .014 260);--raised:oklch(.225 .015 260);--border:oklch(.3 .014 260);--border-strong:oklch(.42 .016 260);--fg:oklch(.955 .005 260);--muted:oklch(.73 .012 260);--blue:oklch(.54 .18 255);--blue-light:oklch(.72 .15 255)}
|
|
77491
|
+
*{box-sizing:border-box}
|
|
77492
|
+
html{min-height:100%;background:var(--bg)}
|
|
77493
|
+
body{margin:0;min-height:100vh;min-height:100dvh;color:var(--fg);background:var(--bg);font-family:"Inter Variable",Inter,ui-sans-serif,system-ui,sans-serif;font-feature-settings:"cv11","ss01","ss03";-webkit-font-smoothing:antialiased}
|
|
77494
|
+
.shell{width:min(100% - 48px,700px);margin:0 auto}
|
|
77495
|
+
header{height:84px;display:flex;align-items:center;justify-content:space-between;gap:16px;border-bottom:1px solid var(--border)}
|
|
77496
|
+
.brand{font-size:16px;font-weight:670;letter-spacing:-.045em;color:var(--fg);text-decoration:none}
|
|
77497
|
+
.context{font-size:12px;color:var(--muted)}
|
|
77498
|
+
main{padding:clamp(48px,10vh,100px) 0 96px}
|
|
77499
|
+
h1{margin:0 0 14px;font-size:clamp(27px,4vw,36px);font-weight:640;letter-spacing:-.05em;line-height:1.17}
|
|
77500
|
+
p{margin:0;color:var(--muted);font-size:14px;line-height:1.65;max-width:59ch}
|
|
77501
|
+
.intro{margin-bottom:32px}
|
|
77502
|
+
.options{display:grid;gap:10px;margin:0 0 24px;padding:0;border:0;max-height:min(390px,52vh);overflow:auto}
|
|
77503
|
+
.option{display:flex;gap:14px;align-items:center;min-height:70px;padding:14px 16px;border:1px solid var(--border);border-radius:10px;background:var(--surface);cursor:pointer;transition:background .15s,border-color .15s}
|
|
77504
|
+
.option:hover{background:var(--raised)}
|
|
77505
|
+
.option:has(input:checked){border-color:var(--blue-light);background:var(--raised)}
|
|
77506
|
+
.option:has(input:focus-visible){outline:2px solid var(--blue-light);outline-offset:3px}
|
|
77507
|
+
.option input{margin:0;flex:none;width:17px;height:17px;accent-color:var(--blue-light)}
|
|
77508
|
+
.option-text{min-width:0;display:grid;gap:3px}
|
|
77509
|
+
.option strong{overflow-wrap:anywhere;font-size:14px;font-weight:600}
|
|
77510
|
+
.option small{font-size:12px;color:var(--muted)}
|
|
77511
|
+
.actions{display:flex;align-items:center;flex-wrap:wrap;gap:12px;margin-top:24px}
|
|
77512
|
+
.button{display:inline-flex;min-height:42px;align-items:center;justify-content:center;padding:0 17px;border:1px solid var(--blue);border-radius:8px;background:var(--blue);color:#fff;font-family:inherit;font-size:13px;font-weight:600;text-decoration:none;cursor:pointer}
|
|
77513
|
+
.button:hover{background:oklch(.6 .18 255)}
|
|
77514
|
+
.button:disabled{cursor:wait;opacity:.7}
|
|
77515
|
+
.secondary{border-color:var(--border);background:transparent;color:var(--fg)}
|
|
77516
|
+
.secondary:hover{background:var(--raised)}
|
|
77517
|
+
:is(button,a):focus-visible{outline:2px solid var(--blue-light);outline-offset:3px}
|
|
77518
|
+
.note{margin-top:30px;padding-top:20px;border-top:1px solid var(--border);font-size:12px}
|
|
77519
|
+
.env-header{display:flex;justify-content:space-between;align-items:center;gap:14px;margin-top:36px}
|
|
77520
|
+
h2{margin:0;font-size:14px;font-weight:600}
|
|
77521
|
+
pre{white-space:pre-wrap;overflow-wrap:anywhere;max-height:380px;overflow:auto;padding:18px;border:1px solid var(--border);border-radius:10px;background:var(--surface);font:12px/1.6 ui-monospace,SFMono-Regular,Menlo,monospace}
|
|
77522
|
+
@media(max-width:480px){.shell{width:calc(100% - 32px)}header{height:70px}main{padding-top:56px}.actions{align-items:stretch;flex-direction:column}.actions form,.actions .button{width:100%}}
|
|
77523
|
+
@media(prefers-reduced-motion:reduce){.option{transition:none}}
|
|
77524
|
+
`;
|
|
77525
|
+
function page(title, content) {
|
|
77526
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>${escapeHtml4(title)} \xB7 OpenGeni</title><style>${pageStyle}</style></head><body><div class="shell"><header><span class="brand">OpenGeni</span><span class="context">GitHub connection</span></header><main>${content}</main></div></body></html>`;
|
|
77527
|
+
}
|
|
77528
|
+
function githubInstallationChooserHtml(candidates, state, workspaceId, baseUrl) {
|
|
77529
|
+
const action = `${baseUrl}/v1/workspaces/${encodeURIComponent(workspaceId)}/github/installations/select`;
|
|
77530
|
+
const options = candidates.map(({ installation, authorityKind }, index) => {
|
|
77531
|
+
const account = escapeHtml4(
|
|
77532
|
+
installation.accountLogin ?? `installation ${installation.installationId}`
|
|
77533
|
+
);
|
|
77534
|
+
const label = authorityKind === "personal_owner" ? "Personal account" : "Organization owner";
|
|
77535
|
+
return `<label class="option"><input type="radio" name="installation_id" value="${installation.installationId}" required${candidates.length === 1 && index === 0 ? " checked" : ""}><span class="option-text"><strong>${account}</strong><small>${label}</small></span></label>`;
|
|
77536
|
+
}).join("");
|
|
77537
|
+
return page(
|
|
77538
|
+
"Choose a GitHub account",
|
|
77539
|
+
`<h1>Choose a GitHub account</h1><p class="intro">Connect an account where the OpenGeni GitHub App is already installed, or install it on another account.</p><form id="existing-account" method="get" action="${escapeHtml4(action)}"><input type="hidden" name="state" value="${escapeHtml4(state)}"><fieldset class="options" aria-label="Available GitHub accounts">${options}</fieldset></form><div class="actions"><button class="button" type="submit" form="existing-account">Connect selected account</button><form method="get" action="${escapeHtml4(action)}"><input type="hidden" name="state" value="${escapeHtml4(state)}"><input type="hidden" name="installation_id" value="new"><button class="button secondary" type="submit">Install on another account</button></form></div><p class="note">Only accounts GitHub has confirmed you own or manage appear here.</p>`
|
|
77540
|
+
);
|
|
77541
|
+
}
|
|
77542
|
+
function githubSetupSuccessHtml(account, returnUrl2) {
|
|
77543
|
+
return page(
|
|
77544
|
+
"GitHub connected",
|
|
77545
|
+
`<h1>GitHub connected</h1><p class="intro"><strong>${escapeHtml4(account)}</strong> is now available in this OpenGeni workspace. OpenGeni can access only the repositories allowed for this installation.</p><a class="button" href="${escapeHtml4(returnUrl2)}">Back to OpenGeni</a>`
|
|
77546
|
+
);
|
|
77547
|
+
}
|
|
77548
|
+
function githubSetupPendingHtml() {
|
|
77549
|
+
return page(
|
|
77550
|
+
"GitHub approval pending",
|
|
77551
|
+
`<h1>Waiting for an organization owner</h1><p>An owner needs to approve your GitHub App request before you can connect. OpenGeni has not created a workspace binding.</p>`
|
|
77552
|
+
);
|
|
77553
|
+
}
|
|
77554
|
+
function githubSuccessHtml(envLines) {
|
|
77555
|
+
const escaped = escapeHtml4(envLines.join("\n"));
|
|
77556
|
+
return page(
|
|
77557
|
+
"GitHub App created",
|
|
77558
|
+
`<h1>GitHub App created</h1><p>Add these values to .env, then restart API and worker.</p><div class="env-header"><h2>Environment variables</h2><button class="button secondary" id="copy-env" type="button">Copy env</button></div><pre id="env-lines">${escaped}</pre><script>(()=>{const button=document.getElementById("copy-env");const env=document.getElementById("env-lines");async function copyText(text){if(navigator.clipboard&&window.isSecureContext){await navigator.clipboard.writeText(text);return;}const area=document.createElement("textarea");area.value=text;area.setAttribute("readonly","");area.style.position="fixed";area.style.inset="-9999px";document.body.append(area);area.select();document.execCommand("copy");area.remove();}button?.addEventListener("click",async()=>{try{await copyText(env?.textContent||"");button.textContent="Copied";setTimeout(()=>button.textContent="Copy env",1600);}catch{button.textContent="Copy failed";setTimeout(()=>button.textContent="Copy env",2200);}});})();</script>`
|
|
77559
|
+
);
|
|
77560
|
+
}
|
|
77561
|
+
function escapeHtml4(value) {
|
|
77562
|
+
return value.replace(
|
|
77563
|
+
/[&<>"']/g,
|
|
77564
|
+
(char) => ({
|
|
77565
|
+
"&": "&",
|
|
77566
|
+
"<": "<",
|
|
77567
|
+
">": ">",
|
|
77568
|
+
'"': """,
|
|
77569
|
+
"'": "'"
|
|
77570
|
+
})[char] ?? char
|
|
77571
|
+
);
|
|
77572
|
+
}
|
|
77573
|
+
|
|
77206
77574
|
// src/routes/github.ts
|
|
77207
77575
|
var githubStateCookie = "opengeni_github_state";
|
|
77208
77576
|
var githubBindingStateMaxAgeSeconds = 10 * 60;
|
|
@@ -78006,28 +78374,6 @@ function requirePublicGitHubRepositoryVerificationPermission(grant) {
|
|
|
78006
78374
|
function isSecureRequest(c, deps) {
|
|
78007
78375
|
return deps.settings.publicBaseUrl?.startsWith("https://") || c.req.header("x-forwarded-proto") === "https" || new URL(c.req.url).protocol === "https:";
|
|
78008
78376
|
}
|
|
78009
|
-
function githubSuccessHtml(envLines) {
|
|
78010
|
-
const envText = envLines.join("\n");
|
|
78011
|
-
const escaped = escapeHtml4(envText);
|
|
78012
|
-
return `<!doctype html><html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>GitHub App Created</title><style>body{font-family:system-ui,sans-serif;margin:0;min-height:100vh;display:grid;place-items:center;background:#0b0b0d;color:#f4f4f5}main{width:min(760px,calc(100vw - 32px));border:1px solid #27272a;border-radius:8px;padding:28px;background:#111114}h1{margin:0 0 10px;font-size:24px;line-height:1.2}p{margin:0 0 18px;color:#d4d4d8}.env-header{display:flex;align-items:center;justify-content:space-between;gap:12px;margin:22px 0 8px}.env-header h2{margin:0;font-size:13px;line-height:1.2;text-transform:uppercase;letter-spacing:.08em;color:#a1a1aa}pre{white-space:pre-wrap;word-break:break-word;max-height:380px;overflow:auto;background:#09090b;border:1px solid #27272a;border-radius:8px;padding:16px;font-size:13px;line-height:1.5}button{display:inline-flex;align-items:center;justify-content:center;min-height:36px;border-radius:6px;border:1px solid #3f3f46;padding:0 12px;background:#f4f4f5;color:#09090b;font:600 14px system-ui,sans-serif;cursor:pointer}button:disabled{cursor:not-allowed;opacity:.7}</style></head><body><main><h1>GitHub App created</h1><p>Add these values to .env, then restart API and worker.</p><div class="env-header"><h2>Environment variables</h2><button id="copy-env" type="button">Copy env</button></div><pre id="env-lines">${escaped}</pre><script>(()=>{const button=document.getElementById("copy-env");const env=document.getElementById("env-lines");async function copyText(text){if(navigator.clipboard&&window.isSecureContext){await navigator.clipboard.writeText(text);return;}const area=document.createElement("textarea");area.value=text;area.setAttribute("readonly","");area.style.position="fixed";area.style.inset="-9999px";document.body.append(area);area.select();document.execCommand("copy");area.remove();}button?.addEventListener("click",async()=>{try{await copyText(env?.textContent||"");button.textContent="Copied";setTimeout(()=>button.textContent="Copy env",1600);}catch{button.textContent="Copy failed";setTimeout(()=>button.textContent="Copy env",2200);}});})();</script></main></body></html>`;
|
|
78013
|
-
}
|
|
78014
|
-
function githubSetupSuccessHtml(account, returnUrl2) {
|
|
78015
|
-
return `<!doctype html><html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>GitHub App Connected</title><style>body{font-family:system-ui,sans-serif;margin:0;min-height:100vh;display:grid;place-items:center;background:#0b0b0d;color:#f4f4f5}main{width:min(640px,calc(100vw - 32px));border:1px solid #27272a;border-radius:8px;padding:28px;background:#111114}h1{margin:0 0 10px;font-size:24px;line-height:1.2}p{margin:0 0 18px;color:#d4d4d8}.button{display:inline-flex;align-items:center;justify-content:center;min-height:36px;border-radius:6px;border:1px solid #3f3f46;padding:0 12px;background:#f4f4f5;color:#09090b;font:600 14px system-ui,sans-serif;text-decoration:none}</style></head><body><main><h1>GitHub App connected</h1><p>${escapeHtml4(account)} is now available to this OpenGeni workspace through an explicit repository allowlist.</p><a class="button" href="${escapeHtml4(returnUrl2)}">Back to OpenGeni</a></main></body></html>`;
|
|
78016
|
-
}
|
|
78017
|
-
function githubInstallationChooserHtml(candidates, state, workspaceId, baseUrl) {
|
|
78018
|
-
const action = `${baseUrl}/v1/workspaces/${encodeURIComponent(workspaceId)}/github/installations/select`;
|
|
78019
|
-
const options = candidates.map(({ installation, authorityKind }, index) => {
|
|
78020
|
-
const account = escapeHtml4(
|
|
78021
|
-
installation.accountLogin ?? `installation ${installation.installationId}`
|
|
78022
|
-
);
|
|
78023
|
-
const label = authorityKind === "personal_owner" ? "Personal account" : "Organization owner";
|
|
78024
|
-
return `<label class="option"><input type="radio" name="installation_id" value="${installation.installationId}" required${candidates.length === 1 && index === 0 ? " checked" : ""}><span><strong>${account}</strong><small>${label}</small></span></label>`;
|
|
78025
|
-
}).join("");
|
|
78026
|
-
return `<!doctype html><html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>Choose GitHub installation</title><style>body{font-family:system-ui,sans-serif;margin:0;min-height:100vh;display:grid;place-items:center;background:#0b0b0d;color:#f4f4f5}main{width:min(640px,calc(100vw - 32px));border:1px solid #27272a;border-radius:12px;padding:28px;background:#111114}h1{margin:0 0 10px;font-size:24px}p{margin:0 0 18px;color:#d4d4d8}.options{display:grid;gap:8px;margin-bottom:18px}.option{display:flex;align-items:center;gap:12px;border:1px solid #3f3f46;border-radius:8px;padding:12px;cursor:pointer}.option span{display:grid;gap:2px}.option small{color:#a1a1aa}button{min-height:38px;border-radius:7px;border:1px solid #3f3f46;padding:0 14px;background:#f4f4f5;color:#09090b;font:600 14px system-ui,sans-serif;cursor:pointer}.secondary{margin-left:8px;background:transparent;color:#f4f4f5}</style></head><body><main><h1>Choose a GitHub account</h1><p>These accounts already have the OpenGeni GitHub App installed and GitHub proved you are the personal owner or an active organization owner.</p><form method="get" action="${escapeHtml4(action)}"><input type="hidden" name="state" value="${escapeHtml4(state)}"><div class="options">${options}</div><button type="submit">Connect selected</button><button class="secondary" type="submit" name="installation_id" value="new" formnovalidate>Install on another account</button></form></main></body></html>`;
|
|
78027
|
-
}
|
|
78028
|
-
function githubSetupPendingHtml() {
|
|
78029
|
-
return `<!doctype html><html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>GitHub App Requested</title><style>body{font-family:system-ui,sans-serif;margin:0;min-height:100vh;display:grid;place-items:center;background:#0b0b0d;color:#f4f4f5}main{width:min(640px,calc(100vw - 32px));border:1px solid #27272a;border-radius:8px;padding:28px;background:#111114}h1{margin:0 0 10px;font-size:24px;line-height:1.2}p{margin:0;color:#d4d4d8}</style></head><body><main><h1>GitHub App request sent</h1><p>A GitHub organization owner must approve the installation. OpenGeni has not created a workspace binding.</p></main></body></html>`;
|
|
78030
|
-
}
|
|
78031
78377
|
function parsePositiveInteger(value) {
|
|
78032
78378
|
if (!value || !/^\d+$/.test(value)) {
|
|
78033
78379
|
return null;
|
|
@@ -78039,18 +78385,6 @@ function isFreshGitHubBindingState(payload) {
|
|
|
78039
78385
|
const age = Math.floor(Date.now() / 1e3) - payload.iat;
|
|
78040
78386
|
return age >= 0 && age < githubBindingStateMaxAgeSeconds;
|
|
78041
78387
|
}
|
|
78042
|
-
function escapeHtml4(value) {
|
|
78043
|
-
return value.replace(
|
|
78044
|
-
/[&<>"']/g,
|
|
78045
|
-
(char) => ({
|
|
78046
|
-
"&": "&",
|
|
78047
|
-
"<": "<",
|
|
78048
|
-
">": ">",
|
|
78049
|
-
'"': """,
|
|
78050
|
-
"'": "'"
|
|
78051
|
-
})[char] ?? char
|
|
78052
|
-
);
|
|
78053
|
-
}
|
|
78054
78388
|
function openGeniReturnUrl(settings, c, workspaceId, returnPath = null) {
|
|
78055
78389
|
const baseUrl = openGeniBaseUrl(settings, c) || new URL(c.req.url).origin;
|
|
78056
78390
|
const safeReturnPath4 = githubSessionReturnPath(returnPath, workspaceId);
|
|
@@ -78636,7 +78970,7 @@ function registerPersonalGitHubRoutes(app, deps) {
|
|
|
78636
78970
|
const query = ListPersonalGitHubRepositoriesQuery.parse(c.req.query());
|
|
78637
78971
|
try {
|
|
78638
78972
|
const selection = await loadRepositorySelectionState(deps, access.grant, connection);
|
|
78639
|
-
const
|
|
78973
|
+
const page2 = await listLivePersonalGitHubRepositories(deps, {
|
|
78640
78974
|
accountId: access.grant.accountId,
|
|
78641
78975
|
workspaceId,
|
|
78642
78976
|
subjectId: access.grant.subjectId,
|
|
@@ -78653,11 +78987,11 @@ function registerPersonalGitHubRoutes(app, deps) {
|
|
|
78653
78987
|
);
|
|
78654
78988
|
return c.json(
|
|
78655
78989
|
ListPersonalGitHubRepositoriesResponse.parse({
|
|
78656
|
-
repositories:
|
|
78990
|
+
repositories: page2.repositories.map((repository) => ({
|
|
78657
78991
|
...repository,
|
|
78658
78992
|
selectedAccess: selectedAccessById.get(repository.repositoryId) ?? null
|
|
78659
78993
|
})),
|
|
78660
|
-
nextCursor:
|
|
78994
|
+
nextCursor: page2.nextPage,
|
|
78661
78995
|
selection
|
|
78662
78996
|
})
|
|
78663
78997
|
);
|
|
@@ -79991,11 +80325,11 @@ async function sseSessionStream(db, bus, workspaceId, sessionId, after, signal,
|
|
|
79991
80325
|
if (targetSequence !== void 0 && lastSent >= targetSequence) return;
|
|
79992
80326
|
const previousLastSent = lastSent;
|
|
79993
80327
|
const limit = targetSequence === void 0 ? SESSION_REPLAY_PAGE_SIZE : Math.min(SESSION_REPLAY_PAGE_SIZE, targetSequence - lastSent);
|
|
79994
|
-
const
|
|
80328
|
+
const page2 = await listSessionEvents(db, workspaceId, sessionId, {
|
|
79995
80329
|
after: lastSent,
|
|
79996
80330
|
limit
|
|
79997
80331
|
});
|
|
79998
|
-
const eligible = targetSequence === void 0 ?
|
|
80332
|
+
const eligible = targetSequence === void 0 ? page2 : page2.filter((event) => event.sequence <= targetSequence);
|
|
79999
80333
|
if (eligible.length === 0) {
|
|
80000
80334
|
if (targetSequence === void 0) return;
|
|
80001
80335
|
throw new Error(
|
|
@@ -80105,16 +80439,16 @@ async function replaySessionEvents(loadPage, send, after, pageSize = SESSION_REP
|
|
|
80105
80439
|
let cursor = after;
|
|
80106
80440
|
while (true) {
|
|
80107
80441
|
const previousCursor = cursor;
|
|
80108
|
-
const
|
|
80109
|
-
if (
|
|
80442
|
+
const page2 = await loadPage(cursor, pageSize);
|
|
80443
|
+
if (page2.length === 0) {
|
|
80110
80444
|
return;
|
|
80111
80445
|
}
|
|
80112
|
-
for (const event of
|
|
80446
|
+
for (const event of page2.sort((a, b) => a.sequence - b.sequence)) {
|
|
80113
80447
|
if (event.sequence <= cursor) continue;
|
|
80114
80448
|
await send(event);
|
|
80115
80449
|
cursor = event.sequence;
|
|
80116
80450
|
}
|
|
80117
|
-
if (
|
|
80451
|
+
if (page2.length < pageSize) {
|
|
80118
80452
|
return;
|
|
80119
80453
|
}
|
|
80120
80454
|
if (cursor === previousCursor) {
|
|
@@ -80506,14 +80840,14 @@ async function replayWorkspaceControlEvents(loadPage, send, after, pageSize) {
|
|
|
80506
80840
|
let cursor = after;
|
|
80507
80841
|
while (true) {
|
|
80508
80842
|
const previousCursor = cursor;
|
|
80509
|
-
const
|
|
80510
|
-
if (
|
|
80511
|
-
for (const event of
|
|
80843
|
+
const page2 = await loadPage(cursor, pageSize);
|
|
80844
|
+
if (page2.length === 0) return;
|
|
80845
|
+
for (const event of page2.sort((a, b) => a.sequence - b.sequence)) {
|
|
80512
80846
|
if (event.sequence <= cursor) continue;
|
|
80513
80847
|
await send(event);
|
|
80514
80848
|
cursor = event.sequence;
|
|
80515
80849
|
}
|
|
80516
|
-
if (
|
|
80850
|
+
if (page2.length < pageSize) return;
|
|
80517
80851
|
if (cursor === previousCursor) {
|
|
80518
80852
|
throw new Error(
|
|
80519
80853
|
`Workspace control replay made no progress after sequence ${cursor}; refusing to repeat a full stale page`
|
|
@@ -84605,10 +84939,10 @@ function registerSkillContentRoutes(app, deps) {
|
|
|
84605
84939
|
...query.data.sessionId ? { sessionId: query.data.sessionId } : {}
|
|
84606
84940
|
}
|
|
84607
84941
|
);
|
|
84608
|
-
const
|
|
84609
|
-
const last =
|
|
84942
|
+
const page2 = rows2.slice(0, query.data.limit);
|
|
84943
|
+
const last = page2.at(-1);
|
|
84610
84944
|
return c.json({
|
|
84611
|
-
skills:
|
|
84945
|
+
skills: page2.map(({ files: _files, ...summary }) => summary),
|
|
84612
84946
|
nextCursor: rows2.length > query.data.limit && last ? Buffer.from(JSON.stringify({ stableKey: last.stableKey, id: last.id })).toString(
|
|
84613
84947
|
"base64url"
|
|
84614
84948
|
) : null
|
|
@@ -85665,6 +85999,8 @@ function registerScheduledTaskRoutes(app, deps) {
|
|
|
85665
85999
|
// src/routes/sessions.ts
|
|
85666
86000
|
import { getRetainedProviderCommand } from "@opengeni/db/retained-provider-commands";
|
|
85667
86001
|
import { searchSessionMessagesForSubject, SessionMessageSearchCursorError } from "@opengeni/db";
|
|
86002
|
+
import { listSessionEventSlices } from "@opengeni/db/session-event-slices";
|
|
86003
|
+
import * as sessionPreviewSchema from "@opengeni/db/schema";
|
|
85668
86004
|
import { SessionMessageSearchRequest } from "@opengeni/contracts";
|
|
85669
86005
|
import { scheduledSessionIds } from "@opengeni/db";
|
|
85670
86006
|
import { withSiteSessionOrigin as withSiteSessionOrigin2 } from "@opengeni/core";
|
|
@@ -87260,9 +87596,9 @@ function registerSessionRoutes(app, deps) {
|
|
|
87260
87596
|
}
|
|
87261
87597
|
const pageView = c.req.query("view") === "page";
|
|
87262
87598
|
const query = sessionListQuery(c.req.query(), pageView);
|
|
87263
|
-
let
|
|
87599
|
+
let page2;
|
|
87264
87600
|
try {
|
|
87265
|
-
|
|
87601
|
+
page2 = await listSessionsForSubject(db, workspaceId, {
|
|
87266
87602
|
subjectId: grant.subjectId,
|
|
87267
87603
|
limit: boundedLimit(query.limit),
|
|
87268
87604
|
materializeSnapshot: pageView,
|
|
@@ -87299,17 +87635,17 @@ function registerSessionRoutes(app, deps) {
|
|
|
87299
87635
|
}
|
|
87300
87636
|
throw error;
|
|
87301
87637
|
}
|
|
87302
|
-
c.header("x-opengeni-pinned-truncated",
|
|
87638
|
+
c.header("x-opengeni-pinned-truncated", page2.pinnedTruncated === true ? "true" : "false");
|
|
87303
87639
|
const policy = await loadEffectivePolicyContext(deps, workspaceId, grant.subjectId);
|
|
87304
87640
|
const commandActivity = await backgroundCommandActivityForSessions(db, {
|
|
87305
87641
|
accountId: grant.accountId,
|
|
87306
87642
|
workspaceId,
|
|
87307
|
-
sessionIds: [...
|
|
87643
|
+
sessionIds: [...page2.pinned, ...page2.sessions].map((session) => session.id)
|
|
87308
87644
|
});
|
|
87309
87645
|
const scheduleTargets = hasPermission19(grant.permissions, "scheduled_tasks:run") && hasPermission19(grant.permissions, "sessions:control") ? await scheduledSessionIds(
|
|
87310
87646
|
db,
|
|
87311
87647
|
workspaceId,
|
|
87312
|
-
[...
|
|
87648
|
+
[...page2.pinned, ...page2.sessions].map((session) => session.id)
|
|
87313
87649
|
) : /* @__PURE__ */ new Set();
|
|
87314
87650
|
const decorate = (session) => {
|
|
87315
87651
|
const activity = commandActivity.get(session.id);
|
|
@@ -87325,14 +87661,14 @@ function registerSessionRoutes(app, deps) {
|
|
|
87325
87661
|
};
|
|
87326
87662
|
if (pageView) {
|
|
87327
87663
|
return c.json({
|
|
87328
|
-
...
|
|
87664
|
+
...page2,
|
|
87329
87665
|
...query.hasPageFilters ? { filtersApplied: true } : {},
|
|
87330
87666
|
...query.originSiteId ? { originSiteId: query.originSiteId } : {},
|
|
87331
|
-
pinned:
|
|
87332
|
-
sessions:
|
|
87667
|
+
pinned: page2.pinned.map(decorate),
|
|
87668
|
+
sessions: page2.sessions.map(decorate)
|
|
87333
87669
|
});
|
|
87334
87670
|
}
|
|
87335
|
-
return c.json([...
|
|
87671
|
+
return c.json([...page2.pinned, ...page2.sessions].map(decorate));
|
|
87336
87672
|
});
|
|
87337
87673
|
app.get("/v1/workspaces/:workspaceId/agent-topology", async (c) => {
|
|
87338
87674
|
const workspaceId = c.req.param("workspaceId");
|
|
@@ -87365,7 +87701,7 @@ function registerSessionRoutes(app, deps) {
|
|
|
87365
87701
|
}
|
|
87366
87702
|
try {
|
|
87367
87703
|
const orderBy = query.query || query.subject ? "relevance" : "updatedAt";
|
|
87368
|
-
const
|
|
87704
|
+
const page2 = await listSessionDiscoverySummaries2(db, workspaceId, {
|
|
87369
87705
|
limit: query.limit,
|
|
87370
87706
|
orderBy,
|
|
87371
87707
|
subjectId: grant.subjectId,
|
|
@@ -87384,11 +87720,11 @@ function registerSessionRoutes(app, deps) {
|
|
|
87384
87720
|
const ancestorPaths = query.query || query.subject ? await listSessionDiscoveryAncestorPaths(
|
|
87385
87721
|
db,
|
|
87386
87722
|
workspaceId,
|
|
87387
|
-
|
|
87723
|
+
page2.sessions.map((session) => session.id),
|
|
87388
87724
|
authorizationScope ?? void 0,
|
|
87389
87725
|
grant.subjectId
|
|
87390
87726
|
) : /* @__PURE__ */ new Map();
|
|
87391
|
-
const sessions =
|
|
87727
|
+
const sessions = page2.sessions.map((session) => {
|
|
87392
87728
|
const blocker = session.effectiveControl.primaryBlocker;
|
|
87393
87729
|
return {
|
|
87394
87730
|
id: session.id,
|
|
@@ -87426,11 +87762,11 @@ function registerSessionRoutes(app, deps) {
|
|
|
87426
87762
|
});
|
|
87427
87763
|
const response = {
|
|
87428
87764
|
sessions,
|
|
87429
|
-
total:
|
|
87430
|
-
hasMore:
|
|
87765
|
+
total: page2.total,
|
|
87766
|
+
hasMore: page2.hasMore,
|
|
87431
87767
|
humanAdvisoriesEnabled: settings.workDiscoveryEnabled && settings.workDiscoveryHumanAdvisoriesEnabled,
|
|
87432
|
-
nextCursor:
|
|
87433
|
-
cursor:
|
|
87768
|
+
nextCursor: page2.nextCursor ? encodeAgentTopologyCursor({
|
|
87769
|
+
cursor: page2.nextCursor,
|
|
87434
87770
|
parentSessionId: query.parentSessionId === void 0 ? "all" : query.parentSessionId,
|
|
87435
87771
|
rootSessionId: query.rootSessionId ?? null,
|
|
87436
87772
|
query: query.query ?? null,
|
|
@@ -89211,35 +89547,94 @@ function registerSessionRoutes(app, deps) {
|
|
|
89211
89547
|
const compactProjection = compact ? coalesceSessionEventDeltasWithCoverage2(events) : null;
|
|
89212
89548
|
const projected = compactProjection?.events ?? events;
|
|
89213
89549
|
const forensicExact = !compact && mode === "forensic" && payloadMode === "full" && dbPage.fullPayloadsExact;
|
|
89214
|
-
const
|
|
89550
|
+
const page2 = boundSessionEventHttpPage(projected, {
|
|
89215
89551
|
direction,
|
|
89216
89552
|
eventProjection: payloadMode === "full" ? "exact" : "bounded",
|
|
89217
89553
|
...compactProjection ? { coveredThroughBySequence: compactProjection.coveredThroughBySequence } : {}
|
|
89218
89554
|
});
|
|
89219
|
-
const hasMore = dbPage.hasMore ||
|
|
89220
|
-
c.header("X-OpenGeni-Page-Bytes", String(
|
|
89221
|
-
c.header("X-OpenGeni-Page-Max-Bytes", String(Math.max(1024 * 1024,
|
|
89555
|
+
const hasMore = dbPage.hasMore || page2.truncated;
|
|
89556
|
+
c.header("X-OpenGeni-Page-Bytes", String(page2.bytes));
|
|
89557
|
+
c.header("X-OpenGeni-Page-Max-Bytes", String(Math.max(1024 * 1024, page2.bytes)));
|
|
89222
89558
|
c.header("X-OpenGeni-Page-Truncated", String(hasMore));
|
|
89223
89559
|
c.header("X-OpenGeni-Has-More", String(hasMore));
|
|
89224
89560
|
c.header("X-OpenGeni-Event-Mode", mode);
|
|
89225
89561
|
c.header("X-OpenGeni-Event-Direction", direction);
|
|
89226
89562
|
c.header("X-OpenGeni-Payload-Mode", payloadMode);
|
|
89227
89563
|
c.header("X-OpenGeni-Forensic-Exact", String(forensicExact));
|
|
89228
|
-
const coveredFirst =
|
|
89229
|
-
const coveredLastEvent =
|
|
89564
|
+
const coveredFirst = page2.events[0]?.sequence;
|
|
89565
|
+
const coveredLastEvent = page2.events.at(-1);
|
|
89230
89566
|
const coveredLast = coveredLastEvent === void 0 ? void 0 : compactProjection?.coveredThroughBySequence.get(coveredLastEvent.sequence) ?? coveredLastEvent.sequence;
|
|
89231
89567
|
if (coveredFirst !== void 0) c.header("X-OpenGeni-Covered-First", String(coveredFirst));
|
|
89232
89568
|
if (coveredLast !== void 0) c.header("X-OpenGeni-Covered-Last", String(coveredLast));
|
|
89233
|
-
const truncatedBy =
|
|
89569
|
+
const truncatedBy = page2.truncated ? "http_bytes" : dbPage.truncatedBy;
|
|
89234
89570
|
if (truncatedBy) c.header("X-OpenGeni-Truncated-By", truncatedBy);
|
|
89235
|
-
if (
|
|
89571
|
+
if (page2.nextSequence !== null) {
|
|
89236
89572
|
c.header(
|
|
89237
89573
|
direction === "before" ? "X-OpenGeni-Next-Before" : "X-OpenGeni-Next-After",
|
|
89238
|
-
String(
|
|
89574
|
+
String(page2.nextSequence)
|
|
89239
89575
|
);
|
|
89240
89576
|
}
|
|
89241
|
-
return c.json(
|
|
89577
|
+
return c.json(page2.events);
|
|
89242
89578
|
});
|
|
89579
|
+
app.get(
|
|
89580
|
+
"/v1/workspaces/:workspaceId/sessions/:sessionId/events/:eventId/message-preview",
|
|
89581
|
+
async (c) => {
|
|
89582
|
+
const workspaceId = c.req.param("workspaceId");
|
|
89583
|
+
await requireAccessGrant32(c, deps, workspaceId, "sessions:read");
|
|
89584
|
+
const sessionId = c.req.param("sessionId");
|
|
89585
|
+
await assertSessionExists(db, workspaceId, sessionId);
|
|
89586
|
+
const eventId = c.req.param("eventId");
|
|
89587
|
+
const rawSequence = c.req.query("sequence");
|
|
89588
|
+
const sequence = Number(rawSequence);
|
|
89589
|
+
if (!z27.string().uuid().safeParse(eventId).success || rawSequence === void 0 || !/^\d+$/.test(rawSequence) || !Number.isSafeInteger(sequence) || sequence < 1 || sequence > 2147483647)
|
|
89590
|
+
throw new HTTPException72(400, { message: "Invalid message preview reference" });
|
|
89591
|
+
const notFound = () => new HTTPException72(404, { message: "message not found" });
|
|
89592
|
+
const maxUnits = 12e3;
|
|
89593
|
+
const eventTable = sessionPreviewSchema.sessionEvents;
|
|
89594
|
+
const candidates = await withWorkspaceRls(
|
|
89595
|
+
db,
|
|
89596
|
+
workspaceId,
|
|
89597
|
+
(tx) => tx.select({ kind: sql`jsonb_typeof(${eventTable.payload}->'text')` }).from(eventTable).where(
|
|
89598
|
+
and(
|
|
89599
|
+
eq(eventTable.workspaceId, workspaceId),
|
|
89600
|
+
eq(eventTable.sessionId, sessionId),
|
|
89601
|
+
eq(eventTable.id, eventId),
|
|
89602
|
+
eq(eventTable.sequence, sequence),
|
|
89603
|
+
sql`${eventTable.type} in ('user.message', 'agent.message.completed')`
|
|
89604
|
+
)
|
|
89605
|
+
).limit(1)
|
|
89606
|
+
);
|
|
89607
|
+
if (candidates[0]?.kind !== "string") throw notFound();
|
|
89608
|
+
const read = (offset2) => listSessionEventSlices(db, workspaceId, sessionId, {
|
|
89609
|
+
sourceSequence: sequence,
|
|
89610
|
+
sourceOffset: offset2,
|
|
89611
|
+
after: sequence - 1,
|
|
89612
|
+
before: sequence + 1,
|
|
89613
|
+
includeTypes: ["user.message", "agent.message.completed"],
|
|
89614
|
+
view: "conversation"
|
|
89615
|
+
});
|
|
89616
|
+
const first = await read(0);
|
|
89617
|
+
const event = first.events[0];
|
|
89618
|
+
const slice = first.slices?.[sequence];
|
|
89619
|
+
if (!event || event.id !== eventId || event.sequence !== sequence || !slice || slice.omitted)
|
|
89620
|
+
throw notFound();
|
|
89621
|
+
if (slice.total > maxUnits) return c.json({ status: "unavailable" });
|
|
89622
|
+
let text = slice.text;
|
|
89623
|
+
let offset = slice.unit === "utf16" ? slice.text.length : Array.from(slice.text).length;
|
|
89624
|
+
if (text.length > maxUnits) return c.json({ status: "unavailable" });
|
|
89625
|
+
while (offset < slice.total) {
|
|
89626
|
+
if (offset === 0) throw notFound();
|
|
89627
|
+
const next = await read(offset);
|
|
89628
|
+
const part = next.slices?.[sequence];
|
|
89629
|
+
if (next.events[0]?.id !== eventId || !part || part.omitted || part.unit !== slice.unit || part.total !== slice.total || part.offset !== offset)
|
|
89630
|
+
throw notFound();
|
|
89631
|
+
text += part.text;
|
|
89632
|
+
offset += slice.unit === "utf16" ? part.text.length : Array.from(part.text).length;
|
|
89633
|
+
if (text.length > maxUnits) return c.json({ status: "unavailable" });
|
|
89634
|
+
}
|
|
89635
|
+
return c.json({ status: "available", text });
|
|
89636
|
+
}
|
|
89637
|
+
);
|
|
89243
89638
|
app.get("/v1/workspaces/:workspaceId/sessions/:sessionId/events/stream", async (c) => {
|
|
89244
89639
|
const workspaceId = c.req.param("workspaceId");
|
|
89245
89640
|
const grant = await requireAccessGrant32(c, deps, workspaceId, "sessions:read");
|
|
@@ -90807,6 +91202,8 @@ function sessionAuthorizationOperationForHttp(method, pathname, sessionId) {
|
|
|
90807
91202
|
return verb === "POST" ? "session.context.write" : null;
|
|
90808
91203
|
}
|
|
90809
91204
|
if (suffix === "/events/stream" && verb === "GET") return "session.stream.read";
|
|
91205
|
+
if (/^\/events\/[^/]+\/message-preview$/.test(suffix) && verb === "GET")
|
|
91206
|
+
return "session.events.read";
|
|
90810
91207
|
if (suffix === "/events") {
|
|
90811
91208
|
if (verb === "GET") return "session.events.read";
|
|
90812
91209
|
if (verb === "POST") return "session.append";
|
|
@@ -92641,14 +93038,14 @@ function registerWorkspaceRoutes(app, deps) {
|
|
|
92641
93038
|
const limit = boundedLimit(c.req.query("limit"));
|
|
92642
93039
|
const fetched = await listWorkspaceControlEvents2(deps.db, workspaceId, after, limit + 1);
|
|
92643
93040
|
const countHasMore = fetched.length > limit;
|
|
92644
|
-
const
|
|
92645
|
-
const truncated = countHasMore ||
|
|
92646
|
-
c.header("X-OpenGeni-Page-Bytes", String(
|
|
93041
|
+
const page2 = boundWorkspaceControlHttpPage(fetched.slice(0, limit));
|
|
93042
|
+
const truncated = countHasMore || page2.truncated;
|
|
93043
|
+
c.header("X-OpenGeni-Page-Bytes", String(page2.bytes));
|
|
92647
93044
|
c.header("X-OpenGeni-Page-Truncated", String(truncated));
|
|
92648
|
-
if (
|
|
92649
|
-
c.header("X-OpenGeni-Next-After", String(
|
|
93045
|
+
if (page2.nextSequence !== null) {
|
|
93046
|
+
c.header("X-OpenGeni-Next-After", String(page2.nextSequence));
|
|
92650
93047
|
}
|
|
92651
|
-
return c.json(
|
|
93048
|
+
return c.json(page2.events);
|
|
92652
93049
|
});
|
|
92653
93050
|
app.get("/v1/workspaces/:workspaceId/control-events/stream", async (c) => {
|
|
92654
93051
|
const workspaceId = c.req.param("workspaceId");
|
|
@@ -93800,10 +94197,10 @@ function preferenceLifecycle(row, generatedAt) {
|
|
|
93800
94197
|
if (row.status === "superseded") return "superseded";
|
|
93801
94198
|
return "historical";
|
|
93802
94199
|
}
|
|
93803
|
-
function preferenceEntries(
|
|
93804
|
-
const visibleRevisionIds = new Set(
|
|
93805
|
-
const visiblePreferenceIds = new Set(
|
|
93806
|
-
return
|
|
94200
|
+
function preferenceEntries(page2, generatedAt) {
|
|
94201
|
+
const visibleRevisionIds = new Set(page2.rows.map((row) => row.revisionId));
|
|
94202
|
+
const visiblePreferenceIds = new Set(page2.rows.map((row) => row.preferenceId));
|
|
94203
|
+
return page2.rows.map((row) => {
|
|
93807
94204
|
const scope = row.scope === "organization" ? "organization" : row.scope === "user" ? "personal" : "workspace";
|
|
93808
94205
|
const lifecycle2 = preferenceLifecycle(row, generatedAt);
|
|
93809
94206
|
const relationships = [];
|
|
@@ -95367,6 +95764,7 @@ import {
|
|
|
95367
95764
|
requireAccessGrant as requireAccessGrant41,
|
|
95368
95765
|
WorkspaceInsightsFilterValidationError
|
|
95369
95766
|
} from "@opengeni/core";
|
|
95767
|
+
import { currentSessionRlsActorIdentityKey } from "@opengeni/db";
|
|
95370
95768
|
import { workspaceInsightsMetricObserver } from "@opengeni/observability";
|
|
95371
95769
|
import { HTTPException as HTTPException85 } from "hono/http-exception";
|
|
95372
95770
|
function normalizeWorkspaceInsightsQueryFilter(value, field) {
|
|
@@ -95379,9 +95777,36 @@ function normalizeWorkspaceInsightsQueryFilter(value, field) {
|
|
|
95379
95777
|
throw error;
|
|
95380
95778
|
}
|
|
95381
95779
|
}
|
|
95780
|
+
function createInFlightCoalescer() {
|
|
95781
|
+
const inFlight = /* @__PURE__ */ new Map();
|
|
95782
|
+
return {
|
|
95783
|
+
run(key, work) {
|
|
95784
|
+
const pending = inFlight.get(key);
|
|
95785
|
+
if (pending) return pending;
|
|
95786
|
+
const started2 = work().finally(() => {
|
|
95787
|
+
if (inFlight.get(key) === started2) inFlight.delete(key);
|
|
95788
|
+
});
|
|
95789
|
+
inFlight.set(key, started2);
|
|
95790
|
+
return started2;
|
|
95791
|
+
},
|
|
95792
|
+
get size() {
|
|
95793
|
+
return inFlight.size;
|
|
95794
|
+
}
|
|
95795
|
+
};
|
|
95796
|
+
}
|
|
95797
|
+
function workspaceInsightsCoalesceKey(input) {
|
|
95798
|
+
return JSON.stringify([
|
|
95799
|
+
input.workspaceId,
|
|
95800
|
+
input.range,
|
|
95801
|
+
input.provider,
|
|
95802
|
+
input.model,
|
|
95803
|
+
input.rlsActor
|
|
95804
|
+
]);
|
|
95805
|
+
}
|
|
95382
95806
|
function registerInsightsRoutes(app, deps) {
|
|
95383
95807
|
const observeRequest = workspaceInsightsMetricObserver(deps.observability);
|
|
95384
95808
|
const observePhase = workspaceInsightsPhaseMetricObserver(deps.observability);
|
|
95809
|
+
const coalesce = createInFlightCoalescer();
|
|
95385
95810
|
app.get("/v1/workspaces/:workspaceId/insights", async (c) => {
|
|
95386
95811
|
const startedAtMs = performance.now();
|
|
95387
95812
|
const rangeRaw = c.req.query("range") ?? "week";
|
|
@@ -95405,16 +95830,25 @@ function registerInsightsRoutes(app, deps) {
|
|
|
95405
95830
|
}
|
|
95406
95831
|
provider = normalizeWorkspaceInsightsQueryFilter(providerRaw, "provider");
|
|
95407
95832
|
model = normalizeWorkspaceInsightsQueryFilter(modelRaw, "model");
|
|
95408
|
-
const response = await
|
|
95409
|
-
|
|
95410
|
-
deps.settings,
|
|
95411
|
-
{
|
|
95833
|
+
const response = await coalesce.run(
|
|
95834
|
+
workspaceInsightsCoalesceKey({
|
|
95412
95835
|
workspaceId,
|
|
95413
95836
|
range: rangeParsed.data,
|
|
95414
95837
|
provider,
|
|
95415
|
-
model
|
|
95416
|
-
|
|
95417
|
-
|
|
95838
|
+
model,
|
|
95839
|
+
rlsActor: currentSessionRlsActorIdentityKey()
|
|
95840
|
+
}),
|
|
95841
|
+
() => getWorkspaceInsights(
|
|
95842
|
+
deps.db,
|
|
95843
|
+
deps.settings,
|
|
95844
|
+
{
|
|
95845
|
+
workspaceId,
|
|
95846
|
+
range: rangeParsed.data,
|
|
95847
|
+
provider,
|
|
95848
|
+
model
|
|
95849
|
+
},
|
|
95850
|
+
observePhase
|
|
95851
|
+
)
|
|
95418
95852
|
);
|
|
95419
95853
|
c.header("cache-control", "private, no-store");
|
|
95420
95854
|
const result = c.json(WorkspaceInsightsResponse.parse(response));
|
|
@@ -98379,7 +98813,8 @@ function registerOrganizationMembershipRoutes(app, deps) {
|
|
|
98379
98813
|
await createManagedOrganization(deps.db, {
|
|
98380
98814
|
subjectId,
|
|
98381
98815
|
subjectLabel: session.user.email || session.user.name,
|
|
98382
|
-
...payload
|
|
98816
|
+
...payload,
|
|
98817
|
+
trialCreditsEnabled: deps.settings.productAccessMode === "managed" && deps.settings.verifiedSignupTrialCreditsEnabled
|
|
98383
98818
|
})
|
|
98384
98819
|
),
|
|
98385
98820
|
201
|
|
@@ -99155,7 +99590,7 @@ function registerOrganizationSessionRoutes(app, deps) {
|
|
|
99155
99590
|
while (index < workspaces.length && sessions.length < query.limit && reads < ORGANIZATION_SESSION_LIST_MAX_WORKSPACE_READS) {
|
|
99156
99591
|
const workspace = workspaces[index];
|
|
99157
99592
|
reads += 1;
|
|
99158
|
-
const
|
|
99593
|
+
const page2 = await listWorkspaceSessionPage(c, deps, {
|
|
99159
99594
|
workspace,
|
|
99160
99595
|
readAuthority,
|
|
99161
99596
|
innerCursor,
|
|
@@ -99163,21 +99598,21 @@ function registerOrganizationSessionRoutes(app, deps) {
|
|
|
99163
99598
|
limit: query.limit - sessions.length,
|
|
99164
99599
|
query
|
|
99165
99600
|
});
|
|
99166
|
-
if (
|
|
99601
|
+
if (page2 === null) {
|
|
99167
99602
|
index += 1;
|
|
99168
99603
|
innerCursor = null;
|
|
99169
99604
|
pinnedOffset = 0;
|
|
99170
99605
|
continue;
|
|
99171
99606
|
}
|
|
99172
|
-
sessions.push(...
|
|
99173
|
-
if (
|
|
99607
|
+
sessions.push(...page2.sessions);
|
|
99608
|
+
if (page2.nextPinnedOffset !== null) {
|
|
99174
99609
|
innerCursor = null;
|
|
99175
|
-
pinnedOffset =
|
|
99610
|
+
pinnedOffset = page2.nextPinnedOffset;
|
|
99176
99611
|
break;
|
|
99177
99612
|
}
|
|
99178
99613
|
pinnedOffset = 0;
|
|
99179
|
-
if (
|
|
99180
|
-
innerCursor =
|
|
99614
|
+
if (page2.nextCursor) {
|
|
99615
|
+
innerCursor = page2.nextCursor;
|
|
99181
99616
|
} else {
|
|
99182
99617
|
index += 1;
|
|
99183
99618
|
innerCursor = null;
|
|
@@ -99232,24 +99667,24 @@ async function listWorkspaceSessionPage(c, deps, input) {
|
|
|
99232
99667
|
personalWorkspaceOwnerException: authorization.canonicalManagedHumanSession
|
|
99233
99668
|
});
|
|
99234
99669
|
const withStatus = (rows3) => input.query.status ? rows3.filter((session) => session.status === input.query.status) : rows3;
|
|
99235
|
-
let
|
|
99670
|
+
let page2 = await list(input.limit);
|
|
99236
99671
|
let rows2;
|
|
99237
99672
|
let nextPinnedOffset = null;
|
|
99238
99673
|
if (cursor) {
|
|
99239
|
-
rows2 =
|
|
99674
|
+
rows2 = page2.sessions;
|
|
99240
99675
|
} else {
|
|
99241
|
-
const pinned =
|
|
99676
|
+
const pinned = page2.pinned.slice(input.pinnedOffset);
|
|
99242
99677
|
if (pinned.length >= input.limit) {
|
|
99243
99678
|
rows2 = pinned.slice(0, input.limit);
|
|
99244
99679
|
nextPinnedOffset = input.pinnedOffset + input.limit;
|
|
99245
99680
|
return { sessions: withStatus(rows2), nextCursor: null, nextPinnedOffset };
|
|
99246
99681
|
}
|
|
99247
|
-
if (pinned.length > 0 &&
|
|
99248
|
-
|
|
99682
|
+
if (pinned.length > 0 && page2.sessions.length > input.limit - pinned.length) {
|
|
99683
|
+
page2 = await list(input.limit - pinned.length);
|
|
99249
99684
|
}
|
|
99250
|
-
rows2 = [...pinned, ...
|
|
99685
|
+
rows2 = [...pinned, ...page2.sessions];
|
|
99251
99686
|
}
|
|
99252
|
-
return { sessions: withStatus(rows2), nextCursor:
|
|
99687
|
+
return { sessions: withStatus(rows2), nextCursor: page2.nextCursor, nextPinnedOffset };
|
|
99253
99688
|
} catch (error) {
|
|
99254
99689
|
if (error instanceof SessionListAccessError2) {
|
|
99255
99690
|
throw new HTTPException91(403, { message: error.message });
|
|
@@ -99591,7 +100026,8 @@ function registerManagedOnboardingRoutes(app, deps, options = {}) {
|
|
|
99591
100026
|
actorSubjectId: `user:${session.user.id}`,
|
|
99592
100027
|
organizationName,
|
|
99593
100028
|
operationId: parsed.data.operationId,
|
|
99594
|
-
requestFingerprint
|
|
100029
|
+
requestFingerprint,
|
|
100030
|
+
trialCreditsEnabled: deps.settings.productAccessMode === "managed" && deps.settings.verifiedSignupTrialCreditsEnabled
|
|
99595
100031
|
})
|
|
99596
100032
|
)
|
|
99597
100033
|
);
|
|
@@ -99843,7 +100279,7 @@ function registerUserResourceAuthorityRoutes(app, deps) {
|
|
|
99843
100279
|
"workspace:read"
|
|
99844
100280
|
);
|
|
99845
100281
|
try {
|
|
99846
|
-
const
|
|
100282
|
+
const page2 = await listManagedHumanUserResourceAuthorities(
|
|
99847
100283
|
deps,
|
|
99848
100284
|
access,
|
|
99849
100285
|
workspaceId,
|
|
@@ -99852,7 +100288,7 @@ function registerUserResourceAuthorityRoutes(app, deps) {
|
|
|
99852
100288
|
return context.json(
|
|
99853
100289
|
ListUserResourceAuthoritiesResponse.parse({
|
|
99854
100290
|
scope: "user",
|
|
99855
|
-
...
|
|
100291
|
+
...page2
|
|
99856
100292
|
})
|
|
99857
100293
|
);
|
|
99858
100294
|
} catch (error) {
|
|
@@ -101847,16 +102283,16 @@ async function publishSlackAppHome(deps, installation, refresh, renewLease) {
|
|
|
101847
102283
|
let cursor;
|
|
101848
102284
|
do {
|
|
101849
102285
|
await renewLease();
|
|
101850
|
-
const
|
|
102286
|
+
const page2 = await listSessionsForSubject3(deps.db, installation.workspaceId, {
|
|
101851
102287
|
subjectId: grant.subjectId,
|
|
101852
102288
|
limit: 500,
|
|
101853
102289
|
...cursor ? { cursor } : {},
|
|
101854
102290
|
...authorizationScope ? { authorizationScope } : {}
|
|
101855
102291
|
});
|
|
101856
|
-
if (!cursor) sessions.push(...
|
|
101857
|
-
sessions.push(...
|
|
101858
|
-
if (!
|
|
101859
|
-
cursor = decodeSessionListCursor3(
|
|
102292
|
+
if (!cursor) sessions.push(...page2.pinned);
|
|
102293
|
+
sessions.push(...page2.sessions);
|
|
102294
|
+
if (!page2.nextCursor) break;
|
|
102295
|
+
cursor = decodeSessionListCursor3(page2.nextCursor) ?? void 0;
|
|
101860
102296
|
if (!cursor) throw new Error("Slack App Home session cursor was invalid");
|
|
101861
102297
|
} while (cursor);
|
|
101862
102298
|
} catch (error) {
|
|
@@ -104167,13 +104603,13 @@ async function resolveSlackDeliveryHome(deps, interaction) {
|
|
|
104167
104603
|
}
|
|
104168
104604
|
async function deliverSlackSessionEvents(deps, interaction, claimHolderId) {
|
|
104169
104605
|
if (!interaction.sessionId) return;
|
|
104170
|
-
const
|
|
104606
|
+
const page2 = await listSessionEventPage3(deps.db, interaction.workspaceId, interaction.sessionId, {
|
|
104171
104607
|
after: interaction.lastDeliveredSessionEventSequence,
|
|
104172
104608
|
limit: 100,
|
|
104173
104609
|
includeTypes: [...SLACK_DELIVERY_EVENT_TYPES],
|
|
104174
104610
|
maxBytes: 256 * 1024
|
|
104175
104611
|
});
|
|
104176
|
-
if (
|
|
104612
|
+
if (page2.events.length === 0) {
|
|
104177
104613
|
await releaseSlackInteractionDelivery(deps.db, {
|
|
104178
104614
|
...interaction,
|
|
104179
104615
|
claimHolderId
|
|
@@ -104212,10 +104648,10 @@ async function deliverSlackSessionEvents(deps, interaction, claimHolderId) {
|
|
|
104212
104648
|
};
|
|
104213
104649
|
let lastSequence = interaction.lastDeliveredSessionEventSequence;
|
|
104214
104650
|
let terminal2 = null;
|
|
104215
|
-
const orderedEvents =
|
|
104651
|
+
const orderedEvents = page2.events.filter(
|
|
104216
104652
|
(event) => (event.turnAssociation === null || event.turnAssociation === "current") && event.duplicateOfEventId === null
|
|
104217
104653
|
).sort((left, right) => left.sequence - right.sequence);
|
|
104218
|
-
lastSequence =
|
|
104654
|
+
lastSequence = page2.events.reduce(
|
|
104219
104655
|
(latest, event) => Math.max(latest, event.sequence),
|
|
104220
104656
|
lastSequence
|
|
104221
104657
|
);
|
|
@@ -107113,4 +107549,4 @@ export {
|
|
|
107113
107549
|
withDefaultEnabledCapabilityMcpTools,
|
|
107114
107550
|
workflowIdForSession4 as workflowIdForSession
|
|
107115
107551
|
};
|
|
107116
|
-
//# sourceMappingURL=chunk-
|
|
107552
|
+
//# sourceMappingURL=chunk-2SSU5KWV.js.map
|