@sellable/install
Version:
One-command installer for Sellable MCP in Claude Code, Codex, and Hermes
361 lines (344 loc) • 13.9 kB
JavaScript
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)),
});
}