UNPKG

@sellable/install

Version:

One-command installer for Sellable MCP in Claude Code, Codex, and Hermes

361 lines (344 loc) • 13.9 kB
import { createHash } from "node:crypto"; export const HERMES_MULTIPLEX_CONTRACT_ID = "sellable-agent-hermes-multiplex/v2026.7.20-v1"; const sha256 = (value) => createHash("sha256").update(value).digest("hex"); const isSha256 = (value) => typeof value === "string" && /^[a-f0-9]{64}$/.test(value); const isImageDigest = (value) => typeof value === "string" && /^sha256:[a-f0-9]{64}$/.test(value); const PINNED_SOURCES = Object.freeze([ Object.freeze({ path: "Dockerfile", sha256: "25b3ec8a3726324f0cdfe9a95ad68eacb30d9d0e0b47fe7f884ee57ec0a2df15", }), Object.freeze({ path: "gateway/config.py", sha256: "7221ee05798566ca7cf570035615a9b29034cf92ce5a6eaa5eec0693040c08aa", }), Object.freeze({ path: "gateway/profile_routing.py", sha256: "1948c862fe2cdd3b9dd211e8bff7be1269a3b413e6c370192dac7e1f47f44c44", }), Object.freeze({ path: "hermes_cli/__init__.py", sha256: "d9805993b3f400e9891c9dc97acb2ff1554f54c78061d57dc48a80493e244157", }), Object.freeze({ path: "plugins/platforms/slack/adapter.py", sha256: "b89cb173a98c4ec948198556da9f8dfce66d3b44754a0a24a38f9c5f30add817", }), Object.freeze({ path: "pyproject.toml", sha256: "7fc0552a6bfdd8d58632a9164e3432c868fc4d928170f8c8a545421134c5952f", }), Object.freeze({ path: "tools/mcp_tool.py", sha256: "a7328f3f3762ae43f6a9426646b0c28c17ec8663aa391506f48d628035ad5460", }), ]); /** * The source and executable closure digests are deliberately separate. The * former covers the audited integration seams; the latter also binds the * dependency lock and resolved commit used by the executable image. */ export const HERMES_MULTIPLEX_UPSTREAM_IDENTITY = Object.freeze({ releaseVersion: "0.19.0", gitTag: "v2026.7.20", gitCommit: "3ef6bbd201263d354fd83ec55b3c306ded2eb72a", sources: PINNED_SOURCES, sourceClosureDigest: "d7d6ed12b6168b4c0c604ce954a8ca08d59742ac7ec43b6ae909d8eded64400c", dependencyLock: Object.freeze({ path: "uv.lock", sha256: "456f76d5396df0f543d1035c2d05173cae1882c290ba585cc926a79958b9d7fe", }), executableClosureDigest: "adb24067cf63775c46b217ee0a38c43cae403b88654ed21051e7f4a97aa63954", upstreamImage: Object.freeze({ repository: "docker.io/nousresearch/hermes-agent", digest: "sha256:f7b35053268f532f98955195c909f15a230470fbcbdacaa9fdecb95707dad04a", platforms: Object.freeze({ "linux/amd64": "sha256:a6ce64e2038867885c2c90f6602425e6e70293d5e6d952a0e603a99265e01c40", "linux/arm64": "sha256:ef58f7f6906a19ca4d7d77bb35711f3a9740c83c8eac692b9c038e13f27e09d5", }), }), }); export const HERMES_MULTIPLEX_CALLBACK_SHAPES = Object.freeze({ preResolution: "sellable.slack.authorize-ingress/v1", egressClient: "sellable.slack.select-workspace-client/v1", }); export const HERMES_MULTIPLEX_SEAMS = Object.freeze({ tokenSource: Object.freeze({ sourcePath: "plugins/platforms/slack/adapter.py", patchKind: "slack-adapter-v019", behavior: "root_owned_token_file_only", }), preResolution: Object.freeze({ sourcePath: "plugins/platforms/slack/adapter.py", companionSourcePath: "gateway/profile_routing.py", patchKind: "slack-adapter-v019", companionPatchKind: "profile-routing-v019", callbackShape: HERMES_MULTIPLEX_CALLBACK_SHAPES.preResolution, behavior: "deny_before_native_profile_resolution", }), egressClient: Object.freeze({ sourcePath: "plugins/platforms/slack/adapter.py", patchKind: "slack-adapter-v019", callbackShape: HERMES_MULTIPLEX_CALLBACK_SHAPES.egressClient, behavior: "exact_team_client_without_primary_fallback", }), }); export class HermesMultiplexContractError extends Error { constructor(code, message, details = {}) { super(message); this.name = "HermesMultiplexContractError"; this.code = code; this.details = details; } } function deny(code, message, details = {}) { throw new HermesMultiplexContractError(code, message, details); } function stableJson(value) { if (Array.isArray(value)) return `[${value.map(stableJson).join(",")}]`; if (value && typeof value === "object") { return `{${Object.keys(value) .sort() .map((key) => `${JSON.stringify(key)}:${stableJson(value[key])}`) .join(",")}}`; } return JSON.stringify(value); } function canonicalSources(sources) { if (!Array.isArray(sources)) { deny("HERMES_MULTIPLEX_IDENTITY_INVALID", "Hermes source identities are required"); } const normalized = sources .map((source) => ({ path: String(source?.path ?? ""), sha256: String(source?.sha256 ?? "") })) .sort((left, right) => left.path.localeCompare(right.path)); const paths = new Set(); for (const source of normalized) { if (!source.path || !isSha256(source.sha256) || paths.has(source.path)) { deny("HERMES_MULTIPLEX_IDENTITY_INVALID", "Hermes source identity is malformed"); } paths.add(source.path); } return normalized; } export function verifyHermesMultiplexIdentity(identity) { if (!identity || typeof identity !== "object") { deny("HERMES_MULTIPLEX_IDENTITY_INVALID", "Hermes identity is required"); } const expected = HERMES_MULTIPLEX_UPSTREAM_IDENTITY; const sources = canonicalSources(identity.sources); if ( identity.releaseVersion !== expected.releaseVersion || identity.gitTag !== expected.gitTag || identity.gitCommit !== expected.gitCommit || stableJson(sources) !== stableJson(expected.sources) || identity.sourceClosureDigest !== expected.sourceClosureDigest || identity.dependencyLock?.path !== expected.dependencyLock.path || identity.dependencyLock?.sha256 !== expected.dependencyLock.sha256 || identity.executableClosureDigest !== expected.executableClosureDigest || identity.upstreamImage?.repository !== expected.upstreamImage.repository || identity.upstreamImage?.digest !== expected.upstreamImage.digest || stableJson(identity.upstreamImage?.platforms) !== stableJson(expected.upstreamImage.platforms) ) { deny("HERMES_MULTIPLEX_IDENTITY_MISMATCH", "Hermes identity does not match the pinned release"); } if ( !isSha256(identity.sourceClosureDigest) || !isSha256(identity.dependencyLock.sha256) || !isSha256(identity.executableClosureDigest) || !isImageDigest(identity.upstreamImage.digest) || !Object.values(identity.upstreamImage.platforms).every(isImageDigest) ) { deny("HERMES_MULTIPLEX_IDENTITY_INVALID", "Hermes identity contains an invalid digest"); } const calculatedSourceClosure = sha256(stableJson(sources)); if (calculatedSourceClosure !== identity.sourceClosureDigest) { deny("HERMES_MULTIPLEX_SOURCE_CLOSURE_MISMATCH", "Hermes source closure is inconsistent"); } const calculatedExecutableClosure = sha256( stableJson({ commit: identity.gitCommit, dependencyLock: identity.dependencyLock, sources, }), ); if (calculatedExecutableClosure !== identity.executableClosureDigest) { deny("HERMES_MULTIPLEX_EXECUTABLE_CLOSURE_MISMATCH", "Hermes executable closure is inconsistent"); } return Object.freeze({ contractId: HERMES_MULTIPLEX_CONTRACT_ID, status: "verified", identityDigest: sha256(stableJson(identity)), sourceClosureDigest: identity.sourceClosureDigest, executableClosureDigest: identity.executableClosureDigest, upstreamImageDigest: identity.upstreamImage.digest, }); } function validateCallbackShapes(callbackShapes) { if (callbackShapes === undefined) return HERMES_MULTIPLEX_CALLBACK_SHAPES; if ( !callbackShapes || callbackShapes.preResolution !== HERMES_MULTIPLEX_CALLBACK_SHAPES.preResolution || callbackShapes.egressClient !== HERMES_MULTIPLEX_CALLBACK_SHAPES.egressClient ) { deny( "HERMES_MULTIPLEX_CALLBACK_SHAPE_UNSUPPORTED", "Hermes multiplex callback shape is not supported", ); } return HERMES_MULTIPLEX_CALLBACK_SHAPES; } function normalizedTokenRecords({ tokenFile, compatibilityTokens, sellableRuntime }) { const hasCompatibilityTokens = Array.isArray(compatibilityTokens) ? compatibilityTokens.some((value) => String(value).trim()) : typeof compatibilityTokens === "string" && compatibilityTokens.trim().length > 0; if (sellableRuntime && hasCompatibilityTokens) { deny( "HERMES_MULTIPLEX_ENV_TOKEN_LIST_FORBIDDEN", "Sellable runtime accepts only its root-owned OAuth token file", ); } if ( (sellableRuntime || tokenFile !== undefined) && (!tokenFile || typeof tokenFile !== "object" || Array.isArray(tokenFile)) ) { deny("HERMES_MULTIPLEX_TOKEN_FILE_INVALID", "OAuth token map is required"); } const records = Object.entries(tokenFile ?? {}) .sort(([left], [right]) => left.localeCompare(right)) .map(([teamId, entry]) => ({ expectedTeamId: String(teamId), installationId: String(entry?.installationId ?? ""), token: entry?.token, teamName: typeof entry?.team_name === "string" ? entry.team_name : "", source: "token_file", })); if (!sellableRuntime && hasCompatibilityTokens) { const values = Array.isArray(compatibilityTokens) ? compatibilityTokens : String(compatibilityTokens).split(","); for (const value of values) { const token = String(value).trim(); if (token) records.push({ expectedTeamId: "", installationId: "", token, teamName: "", source: "compatibility" }); } } const seen = new Map(); return records.filter((record) => { if ( typeof record.token !== "string" || !record.token.startsWith("xoxb-") || (record.source === "token_file" && (!record.expectedTeamId || !record.installationId)) ) { deny("HERMES_MULTIPLEX_TOKEN_RECORD_INVALID", "OAuth token record is malformed"); } const fingerprint = sha256(record.token); const claimed = seen.get(fingerprint); if ( claimed && (claimed.expectedTeamId !== record.expectedTeamId || claimed.installationId !== record.installationId) ) { deny( "HERMES_MULTIPLEX_DIVERGENT_CREDENTIAL_OWNER", "One OAuth credential cannot belong to divergent installations", ); } if (claimed) return false; seen.set(fingerprint, record); return true; }); } /** * Executes the audited multi-workspace bootstrap through injected fake or real * ports. It authenticates but never starts Socket Mode; the returned primary * app is the sole object allowed to own the listener in the next layer. */ export async function inspectHermesMultiplexContract(input) { verifyHermesMultiplexIdentity(input?.identity); validateCallbackShapes(input?.callbackShapes); const ports = input?.ports; if ( !ports || typeof ports.authTest !== "function" || typeof ports.createClient !== "function" || typeof ports.createPrimaryApp !== "function" ) { deny("HERMES_MULTIPLEX_PORTS_INVALID", "Hermes multiplex ports are required"); } const records = normalizedTokenRecords({ tokenFile: input.tokenFile, compatibilityTokens: input.compatibilityTokens, sellableRuntime: input.sellableRuntime !== false, }); if (records.length === 0) { deny("HERMES_MULTIPLEX_NO_WORKSPACES", "At least one OAuth installation is required"); } const authenticated = []; const quarantined = []; const claimedTeams = new Map(); for (const record of records) { const credentialFingerprint = sha256(record.token); try { const auth = await ports.authTest(record.token); const teamId = typeof auth?.team_id === "string" ? auth.team_id : ""; const botUserId = typeof auth?.user_id === "string" ? auth.user_id : ""; const botId = typeof auth?.bot_id === "string" ? auth.bot_id : ""; if (!teamId || !botUserId || !botId) { throw new Error("not_an_authenticated_bot"); } if (record.expectedTeamId && record.expectedTeamId !== teamId) { throw new Error("team_mismatch"); } const prior = claimedTeams.get(teamId); if (prior && (prior.credentialFingerprint !== credentialFingerprint || prior.installationId !== record.installationId)) { deny("HERMES_MULTIPLEX_DIVERGENT_TEAM_CREDENTIAL", "A Slack team has divergent OAuth ownership"); } const client = await ports.createClient(record.token, { teamId, botUserId }); const item = Object.freeze({ teamId, installationId: record.installationId || null, botUserId, credentialFingerprint, client, }); claimedTeams.set(teamId, item); authenticated.push(item); } catch (error) { if (error instanceof HermesMultiplexContractError) throw error; quarantined.push(Object.freeze({ expectedTeamId: record.expectedTeamId || null, installationId: record.installationId || null, credentialFingerprint, code: "WORKSPACE_AUTH_QUARANTINED", })); } } if (authenticated.length === 0) { deny("HERMES_MULTIPLEX_NO_HEALTHY_WORKSPACES", "No Slack workspace authenticated"); } const primary = authenticated[0]; const primaryApp = await ports.createPrimaryApp(records.find((record) => sha256(record.token) === primary.credentialFingerprint).token, { teamId: primary.teamId, botUserId: primary.botUserId, }); const publicWorkspaces = authenticated.map(({ client: _client, ...workspace }) => workspace); return Object.freeze({ contractId: HERMES_MULTIPLEX_CONTRACT_ID, status: "verified", listenerOwnerCount: 1, seams: HERMES_MULTIPLEX_SEAMS, primary: Object.freeze({ teamId: primary.teamId, botUserId: primary.botUserId, app: primaryApp }), workspaceClients: Object.freeze(new Map(authenticated.map((item) => [item.teamId, item]))), workspaces: Object.freeze(publicWorkspaces), quarantined: Object.freeze(quarantined), workspaceMapDigest: sha256(stableJson(publicWorkspaces)), }); }