[Init] Initial commit - NetMesh terminal manager
Some checks failed
build-packages / resolve bundled mosh-client (push) Has been cancelled
build-packages / resolve bundled et-client (push) Has been cancelled
build-packages / build-macos (push) Has been cancelled
build-packages / build-windows (push) Has been cancelled
build-packages / build-linux-x64 (push) Has been cancelled
build-packages / build-linux-arm64 (push) Has been cancelled
build-packages / release (push) Has been cancelled
build-packages / update Nix release metadata (push) Has been cancelled
build-packages / bump homebrew tap (push) Has been cancelled
test / lint-and-test (push) Has been cancelled
AI automation / Route event (push) Has been cancelled
AI automation / Hand reopened issue to maintainers (push) Has been cancelled
AI automation / Clean source issue state (push) Has been cancelled
AI automation / Reconcile handoffs (push) Has been cancelled
AI automation / Classify issue (push) Has been cancelled
AI automation / Claude Code smoke (push) Has been cancelled
AI automation / Review issue follow-up (push) Has been cancelled
AI automation / Publish issue follow-up (push) Has been cancelled
AI automation / Implement with Claude Code (push) Has been cancelled
AI automation / Publish implement PR (push) Has been cancelled
AI automation / Continue queued issue comments (push) Has been cancelled
AI automation / Codex review loop (push) Has been cancelled
AI automation / Publish Codex fix (push) Has been cancelled
AI automation / Clear Codex dispatch marker (push) Has been cancelled
AI automation / Own PR re-request Codex (push) Has been cancelled
AI automation / External PR re-request Codex (push) Has been cancelled
AI automation / Poll Codex reaction / retry (push) Has been cancelled
build-et-binaries / build-linux-x64 (push) Has been cancelled
build-et-binaries / build-linux-arm64 (push) Has been cancelled
build-et-binaries / build-macos-universal (push) Has been cancelled
build-et-binaries / build-windows-x64 (push) Has been cancelled
build-et-binaries / release (push) Has been cancelled
Some checks failed
build-packages / resolve bundled mosh-client (push) Has been cancelled
build-packages / resolve bundled et-client (push) Has been cancelled
build-packages / build-macos (push) Has been cancelled
build-packages / build-windows (push) Has been cancelled
build-packages / build-linux-x64 (push) Has been cancelled
build-packages / build-linux-arm64 (push) Has been cancelled
build-packages / release (push) Has been cancelled
build-packages / update Nix release metadata (push) Has been cancelled
build-packages / bump homebrew tap (push) Has been cancelled
test / lint-and-test (push) Has been cancelled
AI automation / Route event (push) Has been cancelled
AI automation / Hand reopened issue to maintainers (push) Has been cancelled
AI automation / Clean source issue state (push) Has been cancelled
AI automation / Reconcile handoffs (push) Has been cancelled
AI automation / Classify issue (push) Has been cancelled
AI automation / Claude Code smoke (push) Has been cancelled
AI automation / Review issue follow-up (push) Has been cancelled
AI automation / Publish issue follow-up (push) Has been cancelled
AI automation / Implement with Claude Code (push) Has been cancelled
AI automation / Publish implement PR (push) Has been cancelled
AI automation / Continue queued issue comments (push) Has been cancelled
AI automation / Codex review loop (push) Has been cancelled
AI automation / Publish Codex fix (push) Has been cancelled
AI automation / Clear Codex dispatch marker (push) Has been cancelled
AI automation / Own PR re-request Codex (push) Has been cancelled
AI automation / External PR re-request Codex (push) Has been cancelled
AI automation / Poll Codex reaction / retry (push) Has been cancelled
build-et-binaries / build-linux-x64 (push) Has been cancelled
build-et-binaries / build-linux-arm64 (push) Has been cancelled
build-et-binaries / build-macos-universal (push) Has been cancelled
build-et-binaries / build-windows-x64 (push) Has been cancelled
build-et-binaries / release (push) Has been cancelled
This commit is contained in:
179
electron/bridges/mcpServerBridge/capabilityRpcDispatch.cjs
Normal file
179
electron/bridges/mcpServerBridge/capabilityRpcDispatch.cjs
Normal file
@@ -0,0 +1,179 @@
|
||||
"use strict";
|
||||
|
||||
const { CAPABILITY_STATUS, CAPABILITY_SURFACES } = require("../../capabilities/constants.cjs");
|
||||
const { getCapabilityByRpcMethod } = require("../../capabilities/registry.cjs");
|
||||
const { getMcpToolNameForRpcMethod } = require("../../capabilities/adapters/mcpAdapter.cjs");
|
||||
const { createVaultService } = require("../../capabilities/services/vaultService.cjs");
|
||||
const { createPortForwardService } = require("../../capabilities/services/portforwardService.cjs");
|
||||
const { createSessionService } = require("../../capabilities/services/sessionService.cjs");
|
||||
|
||||
const UNROUTED = Symbol("capability-rpc-unrouted");
|
||||
|
||||
const SERVICE_BINDINGS = Object.freeze({
|
||||
"vault.host.get": { domain: "vault", method: "getHost" },
|
||||
"vault.host.list": { domain: "vault", method: "listHosts" },
|
||||
"vault.host.open": { domain: "vault", method: "openHost" },
|
||||
"vault.hosts.create": { domain: "vault", method: "createHosts" },
|
||||
"vault.host.update": { domain: "vault", method: "updateHost" },
|
||||
"vault.host.delete": { domain: "vault", method: "deleteHost" },
|
||||
"vault.host.import": { domain: "vault", method: "importHosts" },
|
||||
"vault.host.notes.get": { domain: "vault", method: "getHostNotes" },
|
||||
"vault.host.notes.set": { domain: "vault", method: "setHostNotes" },
|
||||
"vault.note.list": { domain: "vault", method: "listNotes" },
|
||||
"vault.note.get": { domain: "vault", method: "getNote" },
|
||||
"vault.note.create": { domain: "vault", method: "createNote" },
|
||||
"vault.note.update": { domain: "vault", method: "updateNote" },
|
||||
"vault.note.delete": { domain: "vault", method: "deleteNote" },
|
||||
"vault.identity.list": { domain: "vault", method: "listIdentities" },
|
||||
"vault.proxyProfile.list": { domain: "vault", method: "listProxyProfiles" },
|
||||
"vault.group.list": { domain: "vault", method: "listGroups" },
|
||||
"vault.group.create": { domain: "vault", method: "createGroup" },
|
||||
"vault.group.update": { domain: "vault", method: "updateGroup" },
|
||||
"vault.group.delete": { domain: "vault", method: "deleteGroup" },
|
||||
"vault.snippets.list": { domain: "vault", method: "listSnippets" },
|
||||
"vault.snippets.get": { domain: "vault", method: "getSnippet" },
|
||||
"vault.snippets.run": { domain: "vault", method: "runSnippet" },
|
||||
"vault.snippets.create": { domain: "vault", method: "createSnippet" },
|
||||
"vault.snippets.update": { domain: "vault", method: "updateSnippet" },
|
||||
"vault.snippets.delete": { domain: "vault", method: "deleteSnippet" },
|
||||
"vault.scripts.list": { domain: "vault", method: "listScripts" },
|
||||
"vault.scripts.get": { domain: "vault", method: "getScript" },
|
||||
"vault.scripts.create": { domain: "vault", method: "createScript" },
|
||||
"vault.scripts.update": { domain: "vault", method: "updateScript" },
|
||||
"vault.scripts.delete": { domain: "vault", method: "deleteScript" },
|
||||
"vault.scripts.run": { domain: "vault", method: "runScript" },
|
||||
"vault.scripts.reference": { domain: "vault", method: "getScriptReference" },
|
||||
"vault.scripts.runs.list": { domain: "vault", method: "listScriptRuns" },
|
||||
"vault.scripts.run.stop": { domain: "vault", method: "stopScriptRun" },
|
||||
"vault.scripts.run.pause": { domain: "vault", method: "pauseScriptRun" },
|
||||
"vault.scripts.run.resume": { domain: "vault", method: "resumeScriptRun" },
|
||||
"vault.scripts.targets.set": { domain: "vault", method: "setScriptTargets" },
|
||||
"vault.host.connectScripts.list": { domain: "vault", method: "listHostConnectScripts" },
|
||||
"vault.host.connectScripts.set": { domain: "vault", method: "setHostConnectScripts" },
|
||||
"portforward.rules.list": { domain: "portforward", method: "listRules" },
|
||||
"portforward.rules.create": { domain: "portforward", method: "createRule" },
|
||||
"portforward.rules.update": { domain: "portforward", method: "updateRule" },
|
||||
"portforward.rules.duplicate": { domain: "portforward", method: "duplicateRule" },
|
||||
"portforward.rules.delete": { domain: "portforward", method: "deleteRule" },
|
||||
"portforward.tunnels.list": { domain: "portforward", method: "listTunnels" },
|
||||
"portforward.start": { domain: "portforward", method: "start" },
|
||||
"portforward.stop": { domain: "portforward", method: "stop" },
|
||||
"session.close": { domain: "session", method: "close" },
|
||||
});
|
||||
|
||||
function resolveCapabilitySurface(rpcMethod) {
|
||||
for (const surface of [
|
||||
CAPABILITY_SURFACES.PUBLIC,
|
||||
CAPABILITY_SURFACES.GLOBAL,
|
||||
CAPABILITY_SURFACES.BUILTIN,
|
||||
]) {
|
||||
if (rpcMethod.startsWith("netcatty/") && surface !== CAPABILITY_SURFACES.BUILTIN) {
|
||||
continue;
|
||||
}
|
||||
const capability = getCapabilityByRpcMethod(rpcMethod, surface);
|
||||
if (capability) {
|
||||
return { capability, surface };
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function createCapabilityRpcDispatcher(deps) {
|
||||
const {
|
||||
invokeVaultAgent,
|
||||
evaluatePermissionWithGrants,
|
||||
isChatSessionCancelled,
|
||||
requestApprovalFromRenderer,
|
||||
USER_DENIED_MESSAGE,
|
||||
} = deps;
|
||||
|
||||
const vaultService = createVaultService({ invokeVaultAgent });
|
||||
const portforwardService = createPortForwardService({
|
||||
invokeVaultAgent,
|
||||
listPortForwards: deps.listPortForwards,
|
||||
});
|
||||
const sessionService = deps.sessionService || createSessionService({
|
||||
invokeSessionAgent: invokeVaultAgent,
|
||||
validateClose: deps.validateSessionClose,
|
||||
beforeClose: deps.beforeSessionClose,
|
||||
afterClose: deps.afterSessionClose,
|
||||
onClosed: deps.onSessionClosed,
|
||||
});
|
||||
const services = {
|
||||
vault: vaultService,
|
||||
portforward: portforwardService,
|
||||
session: sessionService,
|
||||
};
|
||||
|
||||
return async function dispatchCapabilityRpc(rpcMethod, params = {}) {
|
||||
if (typeof rpcMethod !== "string" || rpcMethod.startsWith("netcatty/")) {
|
||||
return UNROUTED;
|
||||
}
|
||||
|
||||
const resolved = resolveCapabilitySurface(rpcMethod);
|
||||
if (!resolved) {
|
||||
return UNROUTED;
|
||||
}
|
||||
|
||||
const { capability, surface } = resolved;
|
||||
if (capability.status !== CAPABILITY_STATUS.IMPLEMENTED) {
|
||||
return {
|
||||
ok: false,
|
||||
code: "CAPABILITY_NOT_IMPLEMENTED",
|
||||
error: `Capability "${capability.id}" is not implemented yet.`,
|
||||
};
|
||||
}
|
||||
|
||||
const binding = SERVICE_BINDINGS[capability.id];
|
||||
if (!binding) {
|
||||
return UNROUTED;
|
||||
}
|
||||
|
||||
const permission = evaluatePermissionWithGrants({
|
||||
rpcMethod,
|
||||
surface,
|
||||
permissionMode: deps.permissionMode,
|
||||
params,
|
||||
context: {
|
||||
chatSessionCancelled: isChatSessionCancelled(params?.chatSessionId),
|
||||
},
|
||||
}, deps.permissionGrantsSnapshot);
|
||||
|
||||
if (!permission.allowed) {
|
||||
return { ok: false, error: permission.error };
|
||||
}
|
||||
|
||||
if (permission.requiresApproval) {
|
||||
const { chatSessionId, ...toolArgs } = params || {};
|
||||
const toolName = getMcpToolNameForRpcMethod(rpcMethod, surface) || capability.id;
|
||||
const approved = await requestApprovalFromRenderer(toolName, toolArgs, chatSessionId);
|
||||
if (!approved) {
|
||||
return { ok: false, error: USER_DENIED_MESSAGE };
|
||||
}
|
||||
}
|
||||
|
||||
const service = services[binding.domain];
|
||||
const handler = service?.[binding.method];
|
||||
if (typeof handler !== "function") {
|
||||
return {
|
||||
ok: false,
|
||||
error: `Capability handler "${capability.id}" is unavailable.`,
|
||||
};
|
||||
}
|
||||
|
||||
const hostOpenGeneration = capability.id === "vault.host.open"
|
||||
? deps.captureHostOpenScope?.(params?.chatSessionId)
|
||||
: null;
|
||||
const result = await handler(params);
|
||||
if (capability.id === "vault.host.open" && result?.ok !== false && result?.sessionId) {
|
||||
await deps.onHostOpened?.(params?.chatSessionId, result.sessionId, hostOpenGeneration, result);
|
||||
}
|
||||
return result;
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
UNROUTED,
|
||||
createCapabilityRpcDispatcher,
|
||||
SERVICE_BINDINGS,
|
||||
};
|
||||
Reference in New Issue
Block a user