@vibedeckx/linux-x64 0.3.30 → 0.3.32
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/bin.js +327 -184
- package/package.json +1 -1
package/dist/bin.js
CHANGED
|
@@ -188505,6 +188505,10 @@ var createWorkflowRunRepos = (kdb) => ({
|
|
|
188505
188505
|
const row = await kdb.selectFrom("workflow_runs").selectAll().where("source_session_id", "=", sourceSessionId).where("status", "=", "completed").where("reviewer_session_id", "is not", null).orderBy("created_at", "desc").orderBy(sql`rowid`, "desc").executeTakeFirst();
|
|
188506
188506
|
return row ? asRun(row) : void 0;
|
|
188507
188507
|
},
|
|
188508
|
+
listReviewedSourceSessions: async (projectId, branch) => {
|
|
188509
|
+
const rows = await kdb.selectFrom("workflow_runs").select("source_session_id").distinct().where("project_id", "=", projectId).where("branch", "is", branch).where("status", "=", "completed").where("reviewer_session_id", "is not", null).execute();
|
|
188510
|
+
return rows.map((r) => r.source_session_id);
|
|
188511
|
+
},
|
|
188508
188512
|
update: async (id, patch) => {
|
|
188509
188513
|
if (Object.keys(patch).length > 0) {
|
|
188510
188514
|
await kdb.updateTable("workflow_runs").set({ ...patch, updated_at: sql`datetime('now')` }).where("id", "=", id).execute();
|
|
@@ -205224,6 +205228,12 @@ var initializeSchema = (db) => {
|
|
|
205224
205228
|
FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE
|
|
205225
205229
|
);
|
|
205226
205230
|
|
|
205231
|
+
-- getActive (panel poll, every 5s per open workspace) and
|
|
205232
|
+
-- listReviewedSourceSessions (same request) both scope by project+branch
|
|
205233
|
+
-- and differ only in the status filter.
|
|
205234
|
+
CREATE INDEX IF NOT EXISTS idx_workflow_runs_project_branch_status
|
|
205235
|
+
ON workflow_runs(project_id, branch, status);
|
|
205236
|
+
|
|
205227
205237
|
CREATE TABLE IF NOT EXISTS turn_snapshots (
|
|
205228
205238
|
session_id TEXT NOT NULL,
|
|
205229
205239
|
turn_end_index INTEGER NOT NULL,
|
|
@@ -207854,6 +207864,176 @@ function getAllProviders() {
|
|
|
207854
207864
|
return Array.from(providers.values());
|
|
207855
207865
|
}
|
|
207856
207866
|
|
|
207867
|
+
// src/utils/cross-remote-token.ts
|
|
207868
|
+
import { createHmac as createHmac2, randomBytes as randomBytes2, timingSafeEqual as timingSafeEqual2 } from "crypto";
|
|
207869
|
+
var CROSS_REMOTE_SECRET_SETTING = "cross_remote_token_secret";
|
|
207870
|
+
var CROSS_REMOTE_TOKEN_TTL_MS = 7 * 864e5;
|
|
207871
|
+
var sign2 = (secret, body) => createHmac2("sha256", secret).update(body).digest("base64url");
|
|
207872
|
+
function signRemoteMcpHandle(secret, payload, nowMs, ttlMs = CROSS_REMOTE_TOKEN_TTL_MS) {
|
|
207873
|
+
const wire = {
|
|
207874
|
+
u: payload.userId,
|
|
207875
|
+
s: payload.sessionId,
|
|
207876
|
+
r: payload.remoteId,
|
|
207877
|
+
h: payload.workerHandle,
|
|
207878
|
+
n: payload.serverLabel,
|
|
207879
|
+
exp: nowMs + ttlMs
|
|
207880
|
+
};
|
|
207881
|
+
const body = Buffer.from(JSON.stringify(wire)).toString("base64url");
|
|
207882
|
+
return `mcp.${body}.${sign2(secret, `mcp:${body}`)}`;
|
|
207883
|
+
}
|
|
207884
|
+
function verifyRemoteMcpHandle(secret, handle, nowMs) {
|
|
207885
|
+
const parts = handle.split(".");
|
|
207886
|
+
if (parts.length !== 3) return null;
|
|
207887
|
+
const [prefix, body, providedSig] = parts;
|
|
207888
|
+
if (prefix !== "mcp" || !body || !providedSig) return null;
|
|
207889
|
+
const expectedSig = sign2(secret, `mcp:${body}`);
|
|
207890
|
+
const provided = Buffer.from(providedSig);
|
|
207891
|
+
const expected = Buffer.from(expectedSig);
|
|
207892
|
+
if (provided.length !== expected.length || !timingSafeEqual2(provided, expected)) return null;
|
|
207893
|
+
let wire;
|
|
207894
|
+
try {
|
|
207895
|
+
wire = JSON.parse(Buffer.from(body, "base64url").toString());
|
|
207896
|
+
} catch {
|
|
207897
|
+
return null;
|
|
207898
|
+
}
|
|
207899
|
+
if (![wire.u, wire.s, wire.r, wire.h, wire.n].every((v2) => typeof v2 === "string" && v2.length > 0)) return null;
|
|
207900
|
+
if (typeof wire.exp !== "number" || nowMs >= wire.exp) return null;
|
|
207901
|
+
return { userId: wire.u, sessionId: wire.s, remoteId: wire.r, workerHandle: wire.h, serverLabel: wire.n };
|
|
207902
|
+
}
|
|
207903
|
+
function signCrossRemoteToken(secret, payload, nowMs, ttlMs = CROSS_REMOTE_TOKEN_TTL_MS) {
|
|
207904
|
+
const wire = {
|
|
207905
|
+
u: payload.userId,
|
|
207906
|
+
s: payload.sessionId,
|
|
207907
|
+
src: payload.sourceRemoteServerId,
|
|
207908
|
+
exp: nowMs + ttlMs
|
|
207909
|
+
};
|
|
207910
|
+
const body = Buffer.from(JSON.stringify(wire)).toString("base64url");
|
|
207911
|
+
return `${body}.${sign2(secret, body)}`;
|
|
207912
|
+
}
|
|
207913
|
+
function verifyCrossRemoteTokenDetailed(secret, token, nowMs) {
|
|
207914
|
+
const invalid = { status: "invalid" };
|
|
207915
|
+
const parts = token.split(".");
|
|
207916
|
+
if (parts.length !== 2) return invalid;
|
|
207917
|
+
const [body, providedSig] = parts;
|
|
207918
|
+
if (!body || !providedSig) return invalid;
|
|
207919
|
+
const expectedSig = sign2(secret, body);
|
|
207920
|
+
const provided = Buffer.from(providedSig);
|
|
207921
|
+
const expected = Buffer.from(expectedSig);
|
|
207922
|
+
if (provided.length !== expected.length) return invalid;
|
|
207923
|
+
if (!timingSafeEqual2(provided, expected)) return invalid;
|
|
207924
|
+
let wire;
|
|
207925
|
+
try {
|
|
207926
|
+
wire = JSON.parse(Buffer.from(body, "base64url").toString());
|
|
207927
|
+
} catch {
|
|
207928
|
+
return invalid;
|
|
207929
|
+
}
|
|
207930
|
+
if (typeof wire.u !== "string" || typeof wire.s !== "string" || typeof wire.exp !== "number") return invalid;
|
|
207931
|
+
if (wire.src !== null && typeof wire.src !== "string") return invalid;
|
|
207932
|
+
if (!wire.u || !wire.s) return invalid;
|
|
207933
|
+
const payload = { userId: wire.u, sessionId: wire.s, sourceRemoteServerId: wire.src };
|
|
207934
|
+
if (nowMs >= wire.exp) return { status: "expired", payload, exp: wire.exp };
|
|
207935
|
+
return { status: "ok", payload };
|
|
207936
|
+
}
|
|
207937
|
+
async function getCrossRemoteSecret(storage2) {
|
|
207938
|
+
return storage2.settings.getOrCreate(
|
|
207939
|
+
CROSS_REMOTE_SECRET_SETTING,
|
|
207940
|
+
() => randomBytes2(32).toString("hex")
|
|
207941
|
+
);
|
|
207942
|
+
}
|
|
207943
|
+
|
|
207944
|
+
// src/cross-remote-access.ts
|
|
207945
|
+
var CROSS_REMOTE_MCP_PATH = "/api/cross-remote-mcp";
|
|
207946
|
+
var TOOL_TIERS = {
|
|
207947
|
+
remote_read_file: "read",
|
|
207948
|
+
remote_list_dir: "read",
|
|
207949
|
+
remote_stat_path: "read",
|
|
207950
|
+
remote_process_list: "read",
|
|
207951
|
+
remote_bash: "exec",
|
|
207952
|
+
remote_mcp_open: "exec",
|
|
207953
|
+
remote_mcp_list_tools: "exec",
|
|
207954
|
+
remote_mcp_call: "exec",
|
|
207955
|
+
remote_mcp_ping: "exec",
|
|
207956
|
+
remote_mcp_close: "exec"
|
|
207957
|
+
};
|
|
207958
|
+
var MAX_IN_FLIGHT_PER_SESSION = 4;
|
|
207959
|
+
var REMOTE_MCP_CAPABILITIES = [
|
|
207960
|
+
"http:POST /api/path/cross-remote/mcp/open",
|
|
207961
|
+
"http:POST /api/path/cross-remote/mcp/list-tools",
|
|
207962
|
+
"http:POST /api/path/cross-remote/mcp/call",
|
|
207963
|
+
"http:POST /api/path/cross-remote/mcp/ping",
|
|
207964
|
+
"http:POST /api/path/cross-remote/mcp/close"
|
|
207965
|
+
];
|
|
207966
|
+
var supportsRemoteMcpBroker = (server) => REMOTE_MCP_CAPABILITIES.every((capability) => server.worker_capabilities?.includes(capability));
|
|
207967
|
+
var tierSatisfies = (granted, required2) => granted === "exec" || granted === "read" && required2 === "read";
|
|
207968
|
+
var isOnline = (deps, server) => deps.reverseConnectManager.isConnected(server.id);
|
|
207969
|
+
function isSessionUsable(deps, sessionId) {
|
|
207970
|
+
if (sessionId.startsWith("remote-")) return deps.remoteSessionMap.has(sessionId);
|
|
207971
|
+
return deps.agentSessionManager.getSessionProcessAlive(sessionId);
|
|
207972
|
+
}
|
|
207973
|
+
async function resolveTarget(deps, payload, targetRemoteId, requiredTier) {
|
|
207974
|
+
if (payload.sourceRemoteServerId && payload.sourceRemoteServerId === targetRemoteId) {
|
|
207975
|
+
return { ok: false, reason: "not_accessible" };
|
|
207976
|
+
}
|
|
207977
|
+
const server = await deps.storage.remoteServers.getById(targetRemoteId, payload.userId);
|
|
207978
|
+
if (!server) return { ok: false, reason: "not_accessible" };
|
|
207979
|
+
if (!tierSatisfies(server.cross_remote_access, requiredTier)) {
|
|
207980
|
+
return { ok: false, reason: "not_accessible" };
|
|
207981
|
+
}
|
|
207982
|
+
if (!isOnline(deps, server)) return { ok: false, reason: "offline" };
|
|
207983
|
+
return { ok: true, server };
|
|
207984
|
+
}
|
|
207985
|
+
async function listAccessibleRemotes(deps, payload) {
|
|
207986
|
+
const servers = await deps.storage.remoteServers.getAll(payload.userId);
|
|
207987
|
+
return servers.filter((s3) => s3.cross_remote_access !== "off").filter((s3) => s3.id !== payload.sourceRemoteServerId).map((s3) => ({
|
|
207988
|
+
id: s3.id,
|
|
207989
|
+
name: s3.name,
|
|
207990
|
+
access: s3.cross_remote_access,
|
|
207991
|
+
online: isOnline(deps, s3),
|
|
207992
|
+
mcp_broker_supported: supportsRemoteMcpBroker(s3)
|
|
207993
|
+
}));
|
|
207994
|
+
}
|
|
207995
|
+
var SessionConcurrencyGuard = class {
|
|
207996
|
+
constructor(maxInFlight = MAX_IN_FLIGHT_PER_SESSION) {
|
|
207997
|
+
this.maxInFlight = maxInFlight;
|
|
207998
|
+
}
|
|
207999
|
+
maxInFlight;
|
|
208000
|
+
inFlight = /* @__PURE__ */ new Map();
|
|
208001
|
+
acquire(sessionId) {
|
|
208002
|
+
const current = this.inFlight.get(sessionId) ?? 0;
|
|
208003
|
+
if (current >= this.maxInFlight) return false;
|
|
208004
|
+
this.inFlight.set(sessionId, current + 1);
|
|
208005
|
+
return true;
|
|
208006
|
+
}
|
|
208007
|
+
release(sessionId) {
|
|
208008
|
+
const current = this.inFlight.get(sessionId) ?? 0;
|
|
208009
|
+
if (current <= 1) this.inFlight.delete(sessionId);
|
|
208010
|
+
else this.inFlight.set(sessionId, current - 1);
|
|
208011
|
+
}
|
|
208012
|
+
};
|
|
208013
|
+
|
|
208014
|
+
// src/cross-remote-mcp-config.ts
|
|
208015
|
+
function crossRemoteMcpEnabled() {
|
|
208016
|
+
return !!process.env.VIBEDECKX_PUBLIC_URL?.trim();
|
|
208017
|
+
}
|
|
208018
|
+
async function mintCrossRemoteMcpConfig(deps, args) {
|
|
208019
|
+
const baseUrl = process.env.VIBEDECKX_PUBLIC_URL?.trim();
|
|
208020
|
+
if (!baseUrl) return void 0;
|
|
208021
|
+
const { userId } = args;
|
|
208022
|
+
if (!userId) return void 0;
|
|
208023
|
+
const servers = await deps.storage.remoteServers.getAll(userId);
|
|
208024
|
+
const hasTarget = servers.some(
|
|
208025
|
+
(s3) => s3.cross_remote_access !== "off" && s3.id !== args.sourceRemoteServerId
|
|
208026
|
+
);
|
|
208027
|
+
if (!hasTarget) return void 0;
|
|
208028
|
+
const secret = await getCrossRemoteSecret(deps.storage);
|
|
208029
|
+
const token = signCrossRemoteToken(
|
|
208030
|
+
secret,
|
|
208031
|
+
{ userId, sessionId: args.sessionId, sourceRemoteServerId: args.sourceRemoteServerId },
|
|
208032
|
+
Date.now()
|
|
208033
|
+
);
|
|
208034
|
+
return { url: `${baseUrl.replace(/\/+$/, "")}${CROSS_REMOTE_MCP_PATH}`, token };
|
|
208035
|
+
}
|
|
208036
|
+
|
|
207857
208037
|
// src/conversation-patch.ts
|
|
207858
208038
|
var ConversationPatch = {
|
|
207859
208039
|
/**
|
|
@@ -230222,6 +230402,7 @@ var AgentSessionManager = class {
|
|
|
230222
230402
|
skipDb,
|
|
230223
230403
|
permissionMode,
|
|
230224
230404
|
crossRemoteMcp: opts.crossRemoteMcp,
|
|
230405
|
+
userId: opts.userId && opts.userId !== "local" ? opts.userId : void 0,
|
|
230225
230406
|
agentType,
|
|
230226
230407
|
model,
|
|
230227
230408
|
completion: new TurnCompletionLedger(this.parkTimeoutMs),
|
|
@@ -230276,6 +230457,18 @@ var AgentSessionManager = class {
|
|
|
230276
230457
|
await this.restartSession(session.id, projectPath);
|
|
230277
230458
|
return session.id;
|
|
230278
230459
|
}
|
|
230460
|
+
/**
|
|
230461
|
+
* Replace the session's cross-remote MCP config for its NEXT spawn. Worker
|
|
230462
|
+
* side of the hub's per-message token refresh: a live process keeps the
|
|
230463
|
+
* token it was spawned with (baked into --mcp-config), but the next wake
|
|
230464
|
+
* picks this one up instead of the possibly-expired original.
|
|
230465
|
+
*/
|
|
230466
|
+
updateCrossRemoteMcp(sessionId, config2) {
|
|
230467
|
+
const session = this.sessions.get(sessionId);
|
|
230468
|
+
if (!session) return false;
|
|
230469
|
+
session.crossRemoteMcp = config2;
|
|
230470
|
+
return true;
|
|
230471
|
+
}
|
|
230279
230472
|
/**
|
|
230280
230473
|
* Kill an agent process and its entire process tree.
|
|
230281
230474
|
* Uses negative PID to signal the process group (requires detached: true at spawn).
|
|
@@ -230322,6 +230515,16 @@ var AgentSessionManager = class {
|
|
|
230322
230515
|
console.error(`[AgentSession] Failed to mint session tools MCP config for ${session.id}:`, err);
|
|
230323
230516
|
return void 0;
|
|
230324
230517
|
});
|
|
230518
|
+
if (session.userId && crossRemoteMcpEnabled()) {
|
|
230519
|
+
try {
|
|
230520
|
+
session.crossRemoteMcp = await mintCrossRemoteMcpConfig(
|
|
230521
|
+
{ storage: this.storage },
|
|
230522
|
+
{ userId: session.userId, sessionId: session.id, sourceRemoteServerId: null }
|
|
230523
|
+
);
|
|
230524
|
+
} catch (err) {
|
|
230525
|
+
console.error(`[AgentSession] Cross-remote token re-mint failed for ${session.id}, keeping cached config:`, err);
|
|
230526
|
+
}
|
|
230527
|
+
}
|
|
230325
230528
|
const config2 = provider.buildSpawnConfig(
|
|
230326
230529
|
cwd,
|
|
230327
230530
|
session.permissionMode,
|
|
@@ -231092,6 +231295,7 @@ var AgentSessionManager = class {
|
|
|
231092
231295
|
async sendUserMessage(sessionId, content, projectPath, userId = "local", opts) {
|
|
231093
231296
|
const session = this.sessions.get(sessionId);
|
|
231094
231297
|
if (!session) return false;
|
|
231298
|
+
if (userId && userId !== "local" && !session.userId) session.userId = userId;
|
|
231095
231299
|
const disposition = this.resolveOutgoingDisposition(sessionId, opts);
|
|
231096
231300
|
if (session.dormant) {
|
|
231097
231301
|
if (!projectPath) {
|
|
@@ -232213,6 +232417,7 @@ var AgentSessionManager = class {
|
|
|
232213
232417
|
turnOpenSince: null,
|
|
232214
232418
|
turnDisposition: null,
|
|
232215
232419
|
crossRemoteMcp: opts.crossRemoteMcp,
|
|
232420
|
+
userId: opts.userId && opts.userId !== "local" ? opts.userId : void 0,
|
|
232216
232421
|
branchedFromSessionId: sourceSessionId,
|
|
232217
232422
|
branchedFromEntryIndex
|
|
232218
232423
|
};
|
|
@@ -232299,7 +232504,7 @@ import { randomUUID as randomUUID3 } from "crypto";
|
|
|
232299
232504
|
|
|
232300
232505
|
// src/trace-context.ts
|
|
232301
232506
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
232302
|
-
import { randomBytes as
|
|
232507
|
+
import { randomBytes as randomBytes3 } from "node:crypto";
|
|
232303
232508
|
var VERSION8 = "00";
|
|
232304
232509
|
var INVALID_VERSION = "ff";
|
|
232305
232510
|
var ZERO_TRACE_ID = "0".repeat(32);
|
|
@@ -232324,10 +232529,10 @@ function formatTraceparent(ctx) {
|
|
|
232324
232529
|
return `${VERSION8}-${ctx.traceId}-${ctx.spanId}-${ctx.sampled ? "01" : "00"}`;
|
|
232325
232530
|
}
|
|
232326
232531
|
function newTraceId() {
|
|
232327
|
-
return
|
|
232532
|
+
return randomBytes3(16).toString("hex");
|
|
232328
232533
|
}
|
|
232329
232534
|
function newSpanId() {
|
|
232330
|
-
return
|
|
232535
|
+
return randomBytes3(8).toString("hex");
|
|
232331
232536
|
}
|
|
232332
232537
|
function newTraceContext(incoming) {
|
|
232333
232538
|
const parsed = parseTraceparent(incoming);
|
|
@@ -232493,6 +232698,13 @@ function mapRemoteRun(run2, remoteServerId, projectId) {
|
|
|
232493
232698
|
reviewer_session_id: run2.reviewer_session_id ? `${prefix}${run2.reviewer_session_id}` : null
|
|
232494
232699
|
};
|
|
232495
232700
|
}
|
|
232701
|
+
var UUID_PATTERN = "[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}";
|
|
232702
|
+
var REMOTE_RUN_ID_RE = new RegExp(`^remote-(${UUID_PATTERN})-(${UUID_PATTERN})-(${UUID_PATTERN})$`);
|
|
232703
|
+
function parseRemoteRunId(runId) {
|
|
232704
|
+
const match2 = REMOTE_RUN_ID_RE.exec(runId);
|
|
232705
|
+
if (!match2) return null;
|
|
232706
|
+
return { remoteServerId: match2[1], projectId: match2[2], bareRunId: match2[3] };
|
|
232707
|
+
}
|
|
232496
232708
|
function mapRemoteReviewerCandidate(candidate, remoteServerId, projectId) {
|
|
232497
232709
|
if (!candidate?.sessionId) return candidate;
|
|
232498
232710
|
return {
|
|
@@ -232511,171 +232723,6 @@ function runUpdatedFrameForSubscribers(evt) {
|
|
|
232511
232723
|
return JSON.stringify({ workflowRunUpdated: evt.run });
|
|
232512
232724
|
}
|
|
232513
232725
|
|
|
232514
|
-
// src/utils/cross-remote-token.ts
|
|
232515
|
-
import { createHmac as createHmac2, randomBytes as randomBytes3, timingSafeEqual as timingSafeEqual2 } from "crypto";
|
|
232516
|
-
var CROSS_REMOTE_SECRET_SETTING = "cross_remote_token_secret";
|
|
232517
|
-
var CROSS_REMOTE_TOKEN_TTL_MS = 864e5;
|
|
232518
|
-
var sign2 = (secret, body) => createHmac2("sha256", secret).update(body).digest("base64url");
|
|
232519
|
-
function signRemoteMcpHandle(secret, payload, nowMs, ttlMs = CROSS_REMOTE_TOKEN_TTL_MS) {
|
|
232520
|
-
const wire = {
|
|
232521
|
-
u: payload.userId,
|
|
232522
|
-
s: payload.sessionId,
|
|
232523
|
-
r: payload.remoteId,
|
|
232524
|
-
h: payload.workerHandle,
|
|
232525
|
-
n: payload.serverLabel,
|
|
232526
|
-
exp: nowMs + ttlMs
|
|
232527
|
-
};
|
|
232528
|
-
const body = Buffer.from(JSON.stringify(wire)).toString("base64url");
|
|
232529
|
-
return `mcp.${body}.${sign2(secret, `mcp:${body}`)}`;
|
|
232530
|
-
}
|
|
232531
|
-
function verifyRemoteMcpHandle(secret, handle, nowMs) {
|
|
232532
|
-
const parts = handle.split(".");
|
|
232533
|
-
if (parts.length !== 3) return null;
|
|
232534
|
-
const [prefix, body, providedSig] = parts;
|
|
232535
|
-
if (prefix !== "mcp" || !body || !providedSig) return null;
|
|
232536
|
-
const expectedSig = sign2(secret, `mcp:${body}`);
|
|
232537
|
-
const provided = Buffer.from(providedSig);
|
|
232538
|
-
const expected = Buffer.from(expectedSig);
|
|
232539
|
-
if (provided.length !== expected.length || !timingSafeEqual2(provided, expected)) return null;
|
|
232540
|
-
let wire;
|
|
232541
|
-
try {
|
|
232542
|
-
wire = JSON.parse(Buffer.from(body, "base64url").toString());
|
|
232543
|
-
} catch {
|
|
232544
|
-
return null;
|
|
232545
|
-
}
|
|
232546
|
-
if (![wire.u, wire.s, wire.r, wire.h, wire.n].every((v2) => typeof v2 === "string" && v2.length > 0)) return null;
|
|
232547
|
-
if (typeof wire.exp !== "number" || nowMs >= wire.exp) return null;
|
|
232548
|
-
return { userId: wire.u, sessionId: wire.s, remoteId: wire.r, workerHandle: wire.h, serverLabel: wire.n };
|
|
232549
|
-
}
|
|
232550
|
-
function signCrossRemoteToken(secret, payload, nowMs, ttlMs = CROSS_REMOTE_TOKEN_TTL_MS) {
|
|
232551
|
-
const wire = {
|
|
232552
|
-
u: payload.userId,
|
|
232553
|
-
s: payload.sessionId,
|
|
232554
|
-
src: payload.sourceRemoteServerId,
|
|
232555
|
-
exp: nowMs + ttlMs
|
|
232556
|
-
};
|
|
232557
|
-
const body = Buffer.from(JSON.stringify(wire)).toString("base64url");
|
|
232558
|
-
return `${body}.${sign2(secret, body)}`;
|
|
232559
|
-
}
|
|
232560
|
-
function verifyCrossRemoteToken(secret, token, nowMs) {
|
|
232561
|
-
const parts = token.split(".");
|
|
232562
|
-
if (parts.length !== 2) return null;
|
|
232563
|
-
const [body, providedSig] = parts;
|
|
232564
|
-
if (!body || !providedSig) return null;
|
|
232565
|
-
const expectedSig = sign2(secret, body);
|
|
232566
|
-
const provided = Buffer.from(providedSig);
|
|
232567
|
-
const expected = Buffer.from(expectedSig);
|
|
232568
|
-
if (provided.length !== expected.length) return null;
|
|
232569
|
-
if (!timingSafeEqual2(provided, expected)) return null;
|
|
232570
|
-
let wire;
|
|
232571
|
-
try {
|
|
232572
|
-
wire = JSON.parse(Buffer.from(body, "base64url").toString());
|
|
232573
|
-
} catch {
|
|
232574
|
-
return null;
|
|
232575
|
-
}
|
|
232576
|
-
if (typeof wire.u !== "string" || typeof wire.s !== "string" || typeof wire.exp !== "number") return null;
|
|
232577
|
-
if (wire.src !== null && typeof wire.src !== "string") return null;
|
|
232578
|
-
if (!wire.u || !wire.s) return null;
|
|
232579
|
-
if (nowMs >= wire.exp) return null;
|
|
232580
|
-
return { userId: wire.u, sessionId: wire.s, sourceRemoteServerId: wire.src };
|
|
232581
|
-
}
|
|
232582
|
-
async function getCrossRemoteSecret(storage2) {
|
|
232583
|
-
return storage2.settings.getOrCreate(
|
|
232584
|
-
CROSS_REMOTE_SECRET_SETTING,
|
|
232585
|
-
() => randomBytes3(32).toString("hex")
|
|
232586
|
-
);
|
|
232587
|
-
}
|
|
232588
|
-
|
|
232589
|
-
// src/cross-remote-access.ts
|
|
232590
|
-
var CROSS_REMOTE_MCP_PATH = "/api/cross-remote-mcp";
|
|
232591
|
-
var TOOL_TIERS = {
|
|
232592
|
-
remote_read_file: "read",
|
|
232593
|
-
remote_list_dir: "read",
|
|
232594
|
-
remote_stat_path: "read",
|
|
232595
|
-
remote_process_list: "read",
|
|
232596
|
-
remote_bash: "exec",
|
|
232597
|
-
remote_mcp_open: "exec",
|
|
232598
|
-
remote_mcp_list_tools: "exec",
|
|
232599
|
-
remote_mcp_call: "exec",
|
|
232600
|
-
remote_mcp_ping: "exec",
|
|
232601
|
-
remote_mcp_close: "exec"
|
|
232602
|
-
};
|
|
232603
|
-
var MAX_IN_FLIGHT_PER_SESSION = 4;
|
|
232604
|
-
var REMOTE_MCP_CAPABILITIES = [
|
|
232605
|
-
"http:POST /api/path/cross-remote/mcp/open",
|
|
232606
|
-
"http:POST /api/path/cross-remote/mcp/list-tools",
|
|
232607
|
-
"http:POST /api/path/cross-remote/mcp/call",
|
|
232608
|
-
"http:POST /api/path/cross-remote/mcp/ping",
|
|
232609
|
-
"http:POST /api/path/cross-remote/mcp/close"
|
|
232610
|
-
];
|
|
232611
|
-
var supportsRemoteMcpBroker = (server) => REMOTE_MCP_CAPABILITIES.every((capability) => server.worker_capabilities?.includes(capability));
|
|
232612
|
-
var tierSatisfies = (granted, required2) => granted === "exec" || granted === "read" && required2 === "read";
|
|
232613
|
-
var isOnline = (deps, server) => deps.reverseConnectManager.isConnected(server.id);
|
|
232614
|
-
function isSessionUsable(deps, sessionId) {
|
|
232615
|
-
if (sessionId.startsWith("remote-")) return deps.remoteSessionMap.has(sessionId);
|
|
232616
|
-
return deps.agentSessionManager.getSessionProcessAlive(sessionId);
|
|
232617
|
-
}
|
|
232618
|
-
async function resolveTarget(deps, payload, targetRemoteId, requiredTier) {
|
|
232619
|
-
if (payload.sourceRemoteServerId && payload.sourceRemoteServerId === targetRemoteId) {
|
|
232620
|
-
return { ok: false, reason: "not_accessible" };
|
|
232621
|
-
}
|
|
232622
|
-
const server = await deps.storage.remoteServers.getById(targetRemoteId, payload.userId);
|
|
232623
|
-
if (!server) return { ok: false, reason: "not_accessible" };
|
|
232624
|
-
if (!tierSatisfies(server.cross_remote_access, requiredTier)) {
|
|
232625
|
-
return { ok: false, reason: "not_accessible" };
|
|
232626
|
-
}
|
|
232627
|
-
if (!isOnline(deps, server)) return { ok: false, reason: "offline" };
|
|
232628
|
-
return { ok: true, server };
|
|
232629
|
-
}
|
|
232630
|
-
async function listAccessibleRemotes(deps, payload) {
|
|
232631
|
-
const servers = await deps.storage.remoteServers.getAll(payload.userId);
|
|
232632
|
-
return servers.filter((s3) => s3.cross_remote_access !== "off").filter((s3) => s3.id !== payload.sourceRemoteServerId).map((s3) => ({
|
|
232633
|
-
id: s3.id,
|
|
232634
|
-
name: s3.name,
|
|
232635
|
-
access: s3.cross_remote_access,
|
|
232636
|
-
online: isOnline(deps, s3),
|
|
232637
|
-
mcp_broker_supported: supportsRemoteMcpBroker(s3)
|
|
232638
|
-
}));
|
|
232639
|
-
}
|
|
232640
|
-
var SessionConcurrencyGuard = class {
|
|
232641
|
-
constructor(maxInFlight = MAX_IN_FLIGHT_PER_SESSION) {
|
|
232642
|
-
this.maxInFlight = maxInFlight;
|
|
232643
|
-
}
|
|
232644
|
-
maxInFlight;
|
|
232645
|
-
inFlight = /* @__PURE__ */ new Map();
|
|
232646
|
-
acquire(sessionId) {
|
|
232647
|
-
const current = this.inFlight.get(sessionId) ?? 0;
|
|
232648
|
-
if (current >= this.maxInFlight) return false;
|
|
232649
|
-
this.inFlight.set(sessionId, current + 1);
|
|
232650
|
-
return true;
|
|
232651
|
-
}
|
|
232652
|
-
release(sessionId) {
|
|
232653
|
-
const current = this.inFlight.get(sessionId) ?? 0;
|
|
232654
|
-
if (current <= 1) this.inFlight.delete(sessionId);
|
|
232655
|
-
else this.inFlight.set(sessionId, current - 1);
|
|
232656
|
-
}
|
|
232657
|
-
};
|
|
232658
|
-
|
|
232659
|
-
// src/cross-remote-mcp-config.ts
|
|
232660
|
-
async function mintCrossRemoteMcpConfig(deps, args) {
|
|
232661
|
-
const baseUrl = process.env.VIBEDECKX_PUBLIC_URL?.trim();
|
|
232662
|
-
if (!baseUrl) return void 0;
|
|
232663
|
-
const { userId } = args;
|
|
232664
|
-
if (!userId) return void 0;
|
|
232665
|
-
const servers = await deps.storage.remoteServers.getAll(userId);
|
|
232666
|
-
const hasTarget = servers.some(
|
|
232667
|
-
(s3) => s3.cross_remote_access !== "off" && s3.id !== args.sourceRemoteServerId
|
|
232668
|
-
);
|
|
232669
|
-
if (!hasTarget) return void 0;
|
|
232670
|
-
const secret = await getCrossRemoteSecret(deps.storage);
|
|
232671
|
-
const token = signCrossRemoteToken(
|
|
232672
|
-
secret,
|
|
232673
|
-
{ userId, sessionId: args.sessionId, sourceRemoteServerId: args.sourceRemoteServerId },
|
|
232674
|
-
Date.now()
|
|
232675
|
-
);
|
|
232676
|
-
return { url: `${baseUrl.replace(/\/+$/, "")}${CROSS_REMOTE_MCP_PATH}`, token };
|
|
232677
|
-
}
|
|
232678
|
-
|
|
232679
232726
|
// src/routes/notification-outbox-routes.ts
|
|
232680
232727
|
var import_fastify_plugin = __toESM(require_plugin2(), 1);
|
|
232681
232728
|
var MAX_SESSIONS_PER_REQUEST = 100;
|
|
@@ -239708,6 +239755,7 @@ function selfReportSection(report) {
|
|
|
239708
239755
|
var VERDICT_INSTRUCTIONS = [
|
|
239709
239756
|
"\nThe bar for blocking: a real defect that is worth fixing \u2014 wrong behavior, a case a user or caller will actually hit, a security or data-loss risk, or a missing test for logic that matters. Report those plainly; do not soften a real problem because the fix is inconvenient.",
|
|
239710
239757
|
"Not blocking: over-engineering \u2014 speculative hardening, defenses against inputs this code cannot receive, abstractions or configurability for cases nobody has asked for, or a rewrite in your preferred style. When the fix would add more complexity than the problem it prevents is worth, it is a non-blocking note at most.",
|
|
239758
|
+
"Both halves matter equally: solve real problems, and do not over-engineer.",
|
|
239711
239759
|
"\nEnd your final message with:",
|
|
239712
239760
|
"1. Verdict \u2014 exactly one of: ship / needs-changes / cannot-verify. Use cannot-verify when you could not gather enough evidence to judge, rather than guessing.",
|
|
239713
239761
|
"2. Blocking findings \u2014 what must change before shipping, each specific and actionable (say explicitly when there are none).",
|
|
@@ -241998,7 +242046,11 @@ var TITLE_BY_KIND = {
|
|
|
241998
242046
|
review_ready: "Review feedback is ready",
|
|
241999
242047
|
session_result_ready: "Session result is ready",
|
|
242000
242048
|
session_failed: "Session failed",
|
|
242001
|
-
workflow_failed: "Workflow needs attention"
|
|
242049
|
+
workflow_failed: "Workflow needs attention",
|
|
242050
|
+
// "Stop, then send" — NOT "restart": restartSession wipes the conversation
|
|
242051
|
+
// history, while stop → dormant → next message respawns with a fresh token
|
|
242052
|
+
// and keeps everything.
|
|
242053
|
+
cross_remote_token_expired: "Cross-remote access expired \u2014 stop the session, then send a message to renew"
|
|
242002
242054
|
};
|
|
242003
242055
|
var PLACEHOLDER_TITLES = /* @__PURE__ */ new Set(["New Session", "Generating title\u2026", "Generating title..."]);
|
|
242004
242056
|
var LOCAL_CURSOR_KEY = "notification_local_cursor";
|
|
@@ -247835,7 +247887,7 @@ var routes11 = async (fastify2) => {
|
|
|
247835
247887
|
const result = await fastify2.agentSessionManager.branchSession(
|
|
247836
247888
|
sourceSessionId,
|
|
247837
247889
|
opts.agentType,
|
|
247838
|
-
{ sessionId: opts.sessionId, crossRemoteMcp: opts.crossRemoteMcp, upToEntryIndex: opts.upToEntryIndex }
|
|
247890
|
+
{ sessionId: opts.sessionId, crossRemoteMcp: opts.crossRemoteMcp, upToEntryIndex: opts.upToEntryIndex, userId }
|
|
247839
247891
|
);
|
|
247840
247892
|
if (!result.ok) {
|
|
247841
247893
|
if (result.reason === "invalid-cutoff") {
|
|
@@ -248546,7 +248598,7 @@ var routes11 = async (fastify2) => {
|
|
|
248546
248598
|
agentType || "claude-code",
|
|
248547
248599
|
false,
|
|
248548
248600
|
force === true,
|
|
248549
|
-
{ sessionId: preSessionId, crossRemoteMcp, model }
|
|
248601
|
+
{ sessionId: preSessionId, crossRemoteMcp, model, userId: userId ?? void 0 }
|
|
248550
248602
|
);
|
|
248551
248603
|
const session = fastify2.agentSessionManager.getSession(sessionId);
|
|
248552
248604
|
return reply.code(200).send({
|
|
@@ -248830,12 +248882,27 @@ var routes11 = async (fastify2) => {
|
|
|
248830
248882
|
errorCode: "notification_baseline_failed"
|
|
248831
248883
|
});
|
|
248832
248884
|
}
|
|
248885
|
+
const freshCrossRemoteMcp = typeof authResult === "string" ? await mintCrossRemoteMcpConfig(
|
|
248886
|
+
{ storage: fastify2.storage },
|
|
248887
|
+
{
|
|
248888
|
+
userId: authResult,
|
|
248889
|
+
sessionId: req.params.sessionId,
|
|
248890
|
+
sourceRemoteServerId: remoteInfo.remoteServerId
|
|
248891
|
+
}
|
|
248892
|
+
).catch((err) => {
|
|
248893
|
+
console.error(`[API] cross-remote token refresh mint failed for ${req.params.sessionId}:`, err);
|
|
248894
|
+
return void 0;
|
|
248895
|
+
}) : void 0;
|
|
248833
248896
|
const activityAt = Date.now();
|
|
248834
248897
|
const result = await proxyAuto(
|
|
248835
248898
|
remoteInfo.remoteServerId,
|
|
248836
248899
|
"POST",
|
|
248837
248900
|
`/api/agent-sessions/${remoteInfo.remoteSessionId}/message`,
|
|
248838
|
-
{
|
|
248901
|
+
{
|
|
248902
|
+
content,
|
|
248903
|
+
...idempotencyKey ? { idempotencyKey } : {},
|
|
248904
|
+
...freshCrossRemoteMcp ? { crossRemoteMcp: freshCrossRemoteMcp } : {}
|
|
248905
|
+
}
|
|
248839
248906
|
);
|
|
248840
248907
|
if (!result.ok) {
|
|
248841
248908
|
const status = proxyStatus(result);
|
|
@@ -248894,6 +248961,13 @@ var routes11 = async (fastify2) => {
|
|
|
248894
248961
|
if (!storedSession || !storedProjection || !await fastify2.storage.projects.getById(storedProjection.projectId, authResult)) {
|
|
248895
248962
|
return reply.code(404).send({ error: "Session not found or not running" });
|
|
248896
248963
|
}
|
|
248964
|
+
const incomingCrossRemoteMcp = req.body.crossRemoteMcp;
|
|
248965
|
+
if (incomingCrossRemoteMcp && typeof incomingCrossRemoteMcp.url === "string" && typeof incomingCrossRemoteMcp.token === "string") {
|
|
248966
|
+
fastify2.agentSessionManager.updateCrossRemoteMcp(req.params.sessionId, {
|
|
248967
|
+
url: incomingCrossRemoteMcp.url,
|
|
248968
|
+
token: incomingCrossRemoteMcp.token
|
|
248969
|
+
});
|
|
248970
|
+
}
|
|
248897
248971
|
const session = fastify2.agentSessionManager.getSession(req.params.sessionId);
|
|
248898
248972
|
let projectPathForWake;
|
|
248899
248973
|
if (session?.dormant) {
|
|
@@ -250876,10 +250950,14 @@ async function routes20(fastify2) {
|
|
|
250876
250950
|
result.status === 0 ? { error: `Remote proxy failed: ${result.errorCode || "unknown"}` } : result.data
|
|
250877
250951
|
);
|
|
250878
250952
|
const resolveRemoteRun = async (runId, userId) => {
|
|
250879
|
-
const
|
|
250953
|
+
const tracked = remoteRunMap.get(runId);
|
|
250954
|
+
const info = tracked ?? parseRemoteRunId(runId);
|
|
250880
250955
|
if (!info) return null;
|
|
250881
250956
|
const project = await fastify2.storage.projects.getById(info.projectId, userId);
|
|
250882
250957
|
if (!project) return null;
|
|
250958
|
+
if (!tracked && !await fastify2.storage.projectRemotes.getByProjectAndServer(info.projectId, info.remoteServerId)) {
|
|
250959
|
+
return null;
|
|
250960
|
+
}
|
|
250883
250961
|
return info;
|
|
250884
250962
|
};
|
|
250885
250963
|
const distillIntentBrief = async (userId, sourceSessionId) => {
|
|
@@ -251272,19 +251350,27 @@ async function routes20(fastify2) {
|
|
|
251272
251350
|
};
|
|
251273
251351
|
const result = await proxyAuto(info, "GET", `/api/path/workflow-runs?${q}`);
|
|
251274
251352
|
if (!result.ok) return sendProxyFailure(reply, result);
|
|
251275
|
-
const
|
|
251353
|
+
const data = result.data;
|
|
251354
|
+
const bareRuns = data.runs ?? [];
|
|
251276
251355
|
const runs2 = bareRuns.map((r) => {
|
|
251277
251356
|
const mapped = mapRemoteRun(r, info.remoteServerId, projectId);
|
|
251278
251357
|
trackRemoteRun(mapped, { ...info, bareRunId: r.id, projectId });
|
|
251279
251358
|
return mapped;
|
|
251280
251359
|
});
|
|
251281
251360
|
logRead(runs2.length, `remote:${info.remoteServerId}`);
|
|
251282
|
-
|
|
251361
|
+
const prefix = `remote-${info.remoteServerId}-${projectId}-`;
|
|
251362
|
+
return reply.send({
|
|
251363
|
+
runs: runs2,
|
|
251364
|
+
...data.reviewedSessionIds ? { reviewedSessionIds: data.reviewedSessionIds.map((id) => prefix + id) } : {}
|
|
251365
|
+
});
|
|
251283
251366
|
}
|
|
251284
251367
|
}
|
|
251285
|
-
const runs = await
|
|
251368
|
+
const [runs, reviewedSessionIds] = await Promise.all([
|
|
251369
|
+
fastify2.storage.workflowRuns.getActive(projectId, branch ?? null),
|
|
251370
|
+
fastify2.storage.workflowRuns.listReviewedSourceSessions(projectId, branch ?? null)
|
|
251371
|
+
]);
|
|
251286
251372
|
logRead(runs.length, "local");
|
|
251287
|
-
return reply.send({ runs });
|
|
251373
|
+
return reply.send({ runs, reviewedSessionIds });
|
|
251288
251374
|
}
|
|
251289
251375
|
);
|
|
251290
251376
|
fastify2.get("/api/workflow-runs/:id", async (req, reply) => {
|
|
@@ -251536,9 +251622,12 @@ async function routes20(fastify2) {
|
|
|
251536
251622
|
const { path: projectPath, branch } = req.query;
|
|
251537
251623
|
if (!projectPath) return reply.code(400).send({ error: "path is required" });
|
|
251538
251624
|
const project = await fastify2.storage.projects.getByPath(projectPath) ?? await fastify2.storage.projects.getById(`path:${projectPath}`);
|
|
251539
|
-
if (!project) return reply.send({ runs: [] });
|
|
251540
|
-
const runs = await
|
|
251541
|
-
|
|
251625
|
+
if (!project) return reply.send({ runs: [], reviewedSessionIds: [] });
|
|
251626
|
+
const [runs, reviewedSessionIds] = await Promise.all([
|
|
251627
|
+
fastify2.storage.workflowRuns.getActive(project.id, branch || null),
|
|
251628
|
+
fastify2.storage.workflowRuns.listReviewedSourceSessions(project.id, branch || null)
|
|
251629
|
+
]);
|
|
251630
|
+
return reply.send({ runs, reviewedSessionIds });
|
|
251542
251631
|
});
|
|
251543
251632
|
}
|
|
251544
251633
|
var workflow_run_routes_default = (0, import_fastify_plugin21.default)(routes20, { name: "workflow-run-routes" });
|
|
@@ -259609,14 +259698,68 @@ var routes30 = async (fastify2) => {
|
|
|
259609
259698
|
if (!cachedSecret) cachedSecret = getCrossRemoteSecret(fastify2.storage);
|
|
259610
259699
|
return cachedSecret;
|
|
259611
259700
|
};
|
|
259701
|
+
const expiredNotifyAt = /* @__PURE__ */ new Map();
|
|
259702
|
+
const EXPIRED_NOTIFY_MIN_INTERVAL_MS = 6e4;
|
|
259703
|
+
const notifyTokenExpired = async (payload, exp) => {
|
|
259704
|
+
const last = expiredNotifyAt.get(payload.sessionId);
|
|
259705
|
+
const now3 = Date.now();
|
|
259706
|
+
if (last !== void 0 && now3 - last < EXPIRED_NOTIFY_MIN_INTERVAL_MS) return;
|
|
259707
|
+
expiredNotifyAt.set(payload.sessionId, now3);
|
|
259708
|
+
let projectId;
|
|
259709
|
+
let branch = null;
|
|
259710
|
+
const runtime2 = fastify2.agentSessionManager.getSession(payload.sessionId);
|
|
259711
|
+
if (runtime2) {
|
|
259712
|
+
projectId = runtime2.projectId;
|
|
259713
|
+
branch = runtime2.branch;
|
|
259714
|
+
} else if (payload.sessionId.startsWith("remote-")) {
|
|
259715
|
+
const mapping = await fastify2.storage.remoteSessionMappings.getByLocal(payload.sessionId);
|
|
259716
|
+
if (mapping) {
|
|
259717
|
+
projectId = mapping.project_id;
|
|
259718
|
+
branch = mapping.branch ?? null;
|
|
259719
|
+
}
|
|
259720
|
+
} else {
|
|
259721
|
+
const row = await fastify2.storage.agentSessions.getById(payload.sessionId);
|
|
259722
|
+
if (row) {
|
|
259723
|
+
projectId = row.project_id;
|
|
259724
|
+
branch = row.branch || null;
|
|
259725
|
+
}
|
|
259726
|
+
}
|
|
259727
|
+
if (!projectId) return;
|
|
259728
|
+
const project = await fastify2.storage.projects.getById(projectId);
|
|
259729
|
+
const session = await fastify2.storage.agentSessions.getById(payload.sessionId);
|
|
259730
|
+
const notification = {
|
|
259731
|
+
// Deterministic per token instance: retries and multiple expired calls
|
|
259732
|
+
// from the same process collapse onto one inbox row.
|
|
259733
|
+
id: `cross-remote-expired:${payload.sessionId}:${exp}`,
|
|
259734
|
+
user_id: payload.userId,
|
|
259735
|
+
kind: "cross_remote_token_expired",
|
|
259736
|
+
project_id: projectId,
|
|
259737
|
+
branch,
|
|
259738
|
+
session_id: payload.sessionId,
|
|
259739
|
+
workflow_run_id: null,
|
|
259740
|
+
title: notificationTitle("cross_remote_token_expired"),
|
|
259741
|
+
body: notificationBody({ sessionTitle: session?.title, branch, projectName: project?.name }),
|
|
259742
|
+
created_at: now3,
|
|
259743
|
+
read_at: null
|
|
259744
|
+
};
|
|
259745
|
+
if (await fastify2.storage.notifications.insert(notification)) {
|
|
259746
|
+
fastify2.eventBus.emit({ type: "notification:created", projectId, notification });
|
|
259747
|
+
}
|
|
259748
|
+
};
|
|
259612
259749
|
const authenticate = async (request) => {
|
|
259613
259750
|
const header = request.headers.authorization;
|
|
259614
259751
|
if (!header?.startsWith("Bearer ")) return null;
|
|
259615
259752
|
const secret = await getSecret();
|
|
259616
|
-
const
|
|
259617
|
-
if (
|
|
259618
|
-
|
|
259619
|
-
|
|
259753
|
+
const verified = verifyCrossRemoteTokenDetailed(secret, header.slice("Bearer ".length), Date.now());
|
|
259754
|
+
if (verified.status === "expired") {
|
|
259755
|
+
void notifyTokenExpired(verified.payload, verified.exp).catch(
|
|
259756
|
+
(err) => console.error("[CrossRemoteMCP] expired-token notification failed:", err)
|
|
259757
|
+
);
|
|
259758
|
+
return null;
|
|
259759
|
+
}
|
|
259760
|
+
if (verified.status !== "ok") return null;
|
|
259761
|
+
if (!isSessionUsable(fastify2, verified.payload.sessionId)) return null;
|
|
259762
|
+
return verified.payload;
|
|
259620
259763
|
};
|
|
259621
259764
|
const audit = async (payload, targetRemoteId, toolName, summary, status, exitCode, startedAt) => {
|
|
259622
259765
|
try {
|