UNPKG

@dollhousemcp/mcp-server

Version:

DollhouseMCP - A Model Context Protocol (MCP) server that enables dynamic AI persona management from markdown files, allowing Claude and other compatible AI assistants to activate and switch between different behavioral personas.

42 lines 7.24 kB
import { createHash } from 'node:crypto'; import os from 'node:os'; import { UnicodeValidator } from '../security/validators/unicodeValidator.js'; /** Session ID validation: must start with a letter, then alphanumeric/hyphens/underscores, 1-64 chars */ export const SESSION_ID_PATTERN = /^[a-zA-Z][a-zA-Z0-9_-]{0,63}$/; const DERIVED_SESSION_PREFIX = 'local'; const DERIVED_SESSION_HASH_LENGTH = 10; function normalizeIdentityPart(value) { return UnicodeValidator.normalize(value).normalizedContent.trim(); } function deriveSessionId(cwd, homeDir) { const seed = `${normalizeIdentityPart(homeDir)}\u0000${normalizeIdentityPart(cwd)}`; const hash = createHash('sha256').update(seed).digest('hex').slice(0, DERIVED_SESSION_HASH_LENGTH); return `${DERIVED_SESSION_PREFIX}-${hash}`; } /** * Resolve the stable Dollhouse session identity and the live runtime session * identifier for the current process. When a host provides * `DOLLHOUSE_SESSION_ID`, that explicit identity is used everywhere. When it * does not, we derive a restart-stable workspace identity and add a PID suffix * for the live runtime identity so concurrent unnamed sessions do not collide * in the console registry. */ export function resolveSessionIdentity(options = {}) { const envValue = options.envValue ?? process.env.DOLLHOUSE_SESSION_ID; const normalizedEnvValue = typeof envValue === 'string' ? normalizeIdentityPart(envValue) : ''; if (normalizedEnvValue && SESSION_ID_PATTERN.test(normalizedEnvValue)) { return { sessionId: normalizedEnvValue, runtimeSessionId: normalizedEnvValue, source: 'env', }; } const derivedSessionId = deriveSessionId(options.cwd ?? process.cwd(), options.homeDir ?? os.homedir()); const pidSuffix = (options.pid ?? process.pid).toString(36); return { sessionId: derivedSessionId, runtimeSessionId: `${derivedSessionId}-${pidSuffix}`, source: 'derived', }; } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2Vzc2lvbklkZW50aXR5LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3NlcnZpY2VzL3Nlc3Npb25JZGVudGl0eS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sYUFBYSxDQUFDO0FBQ3pDLE9BQU8sRUFBRSxNQUFNLFNBQVMsQ0FBQztBQUN6QixPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSw0Q0FBNEMsQ0FBQztBQUU5RSx5R0FBeUc7QUFDekcsTUFBTSxDQUFDLE1BQU0sa0JBQWtCLEdBQUcsK0JBQStCLENBQUM7QUFDbEUsTUFBTSxzQkFBc0IsR0FBRyxPQUFPLENBQUM7QUFDdkMsTUFBTSwyQkFBMkIsR0FBRyxFQUFFLENBQUM7QUFldkMsU0FBUyxxQkFBcUIsQ0FBQyxLQUFhO0lBQzFDLE9BQU8sZ0JBQWdCLENBQUMsU0FBUyxDQUFDLEtBQUssQ0FBQyxDQUFDLGlCQUFpQixDQUFDLElBQUksRUFBRSxDQUFDO0FBQ3BFLENBQUM7QUFFRCxTQUFTLGVBQWUsQ0FBQyxHQUFXLEVBQUUsT0FBZTtJQUNuRCxNQUFNLElBQUksR0FBRyxHQUFHLHFCQUFxQixDQUFDLE9BQU8sQ0FBQyxTQUFTLHFCQUFxQixDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUM7SUFDcEYsTUFBTSxJQUFJLEdBQUcsVUFBVSxDQUFDLFFBQVEsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLENBQUMsS0FBSyxDQUFDLENBQUMsRUFBRSwyQkFBMkIsQ0FBQyxDQUFDO0lBQ25HLE9BQU8sR0FBRyxzQkFBc0IsSUFBSSxJQUFJLEVBQUUsQ0FBQztBQUM3QyxDQUFDO0FBRUQ7Ozs7Ozs7R0FPRztBQUNILE1BQU0sVUFBVSxzQkFBc0IsQ0FDcEMsVUFBeUMsRUFBRTtJQUUzQyxNQUFNLFFBQVEsR0FBRyxPQUFPLENBQUMsUUFBUSxJQUFJLE9BQU8sQ0FBQyxHQUFHLENBQUMsb0JBQW9CLENBQUM7SUFDdEUsTUFBTSxrQkFBa0IsR0FBRyxPQUFPLFFBQVEsS0FBSyxRQUFRLENBQUMsQ0FBQyxDQUFDLHFCQUFxQixDQUFDLFFBQVEsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUM7SUFDL0YsSUFBSSxrQkFBa0IsSUFBSSxrQkFBa0IsQ0FBQyxJQUFJLENBQUMsa0JBQWtCLENBQUMsRUFBRSxDQUFDO1FBQ3RFLE9BQU87WUFDTCxTQUFTLEVBQUUsa0JBQWtCO1lBQzdCLGdCQUFnQixFQUFFLGtCQUFrQjtZQUNwQyxNQUFNLEVBQUUsS0FBSztTQUNkLENBQUM7SUFDSixDQUFDO0lBRUQsTUFBTSxnQkFBZ0IsR0FBRyxlQUFlLENBQ3RDLE9BQU8sQ0FBQyxHQUFHLElBQUksT0FBTyxDQUFDLEdBQUcsRUFBRSxFQUM1QixPQUFPLENBQUMsT0FBTyxJQUFJLEVBQUUsQ0FBQyxPQUFPLEVBQUUsQ0FDaEMsQ0FBQztJQUNGLE1BQU0sU0FBUyxHQUFHLENBQUMsT0FBTyxDQUFDLEdBQUcsSUFBSSxPQUFPLENBQUMsR0FBRyxDQUFDLENBQUMsUUFBUSxDQUFDLEVBQUUsQ0FBQyxDQUFDO0lBQzVELE9BQU87UUFDTCxTQUFTLEVBQUUsZ0JBQWdCO1FBQzNCLGdCQUFnQixFQUFFLEdBQUcsZ0JBQWdCLElBQUksU0FBUyxFQUFFO1FBQ3BELE1BQU0sRUFBRSxTQUFTO0tBQ2xCLENBQUM7QUFDSixDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgY3JlYXRlSGFzaCB9IGZyb20gJ25vZGU6Y3J5cHRvJztcbmltcG9ydCBvcyBmcm9tICdub2RlOm9zJztcbmltcG9ydCB7IFVuaWNvZGVWYWxpZGF0b3IgfSBmcm9tICcuLi9zZWN1cml0eS92YWxpZGF0b3JzL3VuaWNvZGVWYWxpZGF0b3IuanMnO1xuXG4vKiogU2Vzc2lvbiBJRCB2YWxpZGF0aW9uOiBtdXN0IHN0YXJ0IHdpdGggYSBsZXR0ZXIsIHRoZW4gYWxwaGFudW1lcmljL2h5cGhlbnMvdW5kZXJzY29yZXMsIDEtNjQgY2hhcnMgKi9cbmV4cG9ydCBjb25zdCBTRVNTSU9OX0lEX1BBVFRFUk4gPSAvXlthLXpBLVpdW2EtekEtWjAtOV8tXXswLDYzfSQvO1xuY29uc3QgREVSSVZFRF9TRVNTSU9OX1BSRUZJWCA9ICdsb2NhbCc7XG5jb25zdCBERVJJVkVEX1NFU1NJT05fSEFTSF9MRU5HVEggPSAxMDtcblxuZXhwb3J0IGludGVyZmFjZSBTZXNzaW9uSWRlbnRpdHkge1xuICBzZXNzaW9uSWQ6IHN0cmluZztcbiAgcnVudGltZVNlc3Npb25JZDogc3RyaW5nO1xuICBzb3VyY2U6ICdlbnYnIHwgJ2Rlcml2ZWQnO1xufVxuXG5pbnRlcmZhY2UgUmVzb2x2ZVNlc3Npb25JZGVudGl0eU9wdGlvbnMge1xuICBlbnZWYWx1ZT86IHN0cmluZztcbiAgY3dkPzogc3RyaW5nO1xuICBob21lRGlyPzogc3RyaW5nO1xuICBwaWQ/OiBudW1iZXI7XG59XG5cbmZ1bmN0aW9uIG5vcm1hbGl6ZUlkZW50aXR5UGFydCh2YWx1ZTogc3RyaW5nKTogc3RyaW5nIHtcbiAgcmV0dXJuIFVuaWNvZGVWYWxpZGF0b3Iubm9ybWFsaXplKHZhbHVlKS5ub3JtYWxpemVkQ29udGVudC50cmltKCk7XG59XG5cbmZ1bmN0aW9uIGRlcml2ZVNlc3Npb25JZChjd2Q6IHN0cmluZywgaG9tZURpcjogc3RyaW5nKTogc3RyaW5nIHtcbiAgY29uc3Qgc2VlZCA9IGAke25vcm1hbGl6ZUlkZW50aXR5UGFydChob21lRGlyKX1cXHUwMDAwJHtub3JtYWxpemVJZGVudGl0eVBhcnQoY3dkKX1gO1xuICBjb25zdCBoYXNoID0gY3JlYXRlSGFzaCgnc2hhMjU2JykudXBkYXRlKHNlZWQpLmRpZ2VzdCgnaGV4Jykuc2xpY2UoMCwgREVSSVZFRF9TRVNTSU9OX0hBU0hfTEVOR1RIKTtcbiAgcmV0dXJuIGAke0RFUklWRURfU0VTU0lPTl9QUkVGSVh9LSR7aGFzaH1gO1xufVxuXG4vKipcbiAqIFJlc29sdmUgdGhlIHN0YWJsZSBEb2xsaG91c2Ugc2Vzc2lvbiBpZGVudGl0eSBhbmQgdGhlIGxpdmUgcnVudGltZSBzZXNzaW9uXG4gKiBpZGVudGlmaWVyIGZvciB0aGUgY3VycmVudCBwcm9jZXNzLiBXaGVuIGEgaG9zdCBwcm92aWRlc1xuICogYERPTExIT1VTRV9TRVNTSU9OX0lEYCwgdGhhdCBleHBsaWNpdCBpZGVudGl0eSBpcyB1c2VkIGV2ZXJ5d2hlcmUuIFdoZW4gaXRcbiAqIGRvZXMgbm90LCB3ZSBkZXJpdmUgYSByZXN0YXJ0LXN0YWJsZSB3b3Jrc3BhY2UgaWRlbnRpdHkgYW5kIGFkZCBhIFBJRCBzdWZmaXhcbiAqIGZvciB0aGUgbGl2ZSBydW50aW1lIGlkZW50aXR5IHNvIGNvbmN1cnJlbnQgdW5uYW1lZCBzZXNzaW9ucyBkbyBub3QgY29sbGlkZVxuICogaW4gdGhlIGNvbnNvbGUgcmVnaXN0cnkuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiByZXNvbHZlU2Vzc2lvbklkZW50aXR5KFxuICBvcHRpb25zOiBSZXNvbHZlU2Vzc2lvbklkZW50aXR5T3B0aW9ucyA9IHt9LFxuKTogU2Vzc2lvbklkZW50aXR5IHtcbiAgY29uc3QgZW52VmFsdWUgPSBvcHRpb25zLmVudlZhbHVlID8/IHByb2Nlc3MuZW52LkRPTExIT1VTRV9TRVNTSU9OX0lEO1xuICBjb25zdCBub3JtYWxpemVkRW52VmFsdWUgPSB0eXBlb2YgZW52VmFsdWUgPT09ICdzdHJpbmcnID8gbm9ybWFsaXplSWRlbnRpdHlQYXJ0KGVudlZhbHVlKSA6ICcnO1xuICBpZiAobm9ybWFsaXplZEVudlZhbHVlICYmIFNFU1NJT05fSURfUEFUVEVSTi50ZXN0KG5vcm1hbGl6ZWRFbnZWYWx1ZSkpIHtcbiAgICByZXR1cm4ge1xuICAgICAgc2Vzc2lvbklkOiBub3JtYWxpemVkRW52VmFsdWUsXG4gICAgICBydW50aW1lU2Vzc2lvbklkOiBub3JtYWxpemVkRW52VmFsdWUsXG4gICAgICBzb3VyY2U6ICdlbnYnLFxuICAgIH07XG4gIH1cblxuICBjb25zdCBkZXJpdmVkU2Vzc2lvbklkID0gZGVyaXZlU2Vzc2lvbklkKFxuICAgIG9wdGlvbnMuY3dkID8/IHByb2Nlc3MuY3dkKCksXG4gICAgb3B0aW9ucy5ob21lRGlyID8/IG9zLmhvbWVkaXIoKSxcbiAgKTtcbiAgY29uc3QgcGlkU3VmZml4ID0gKG9wdGlvbnMucGlkID8/IHByb2Nlc3MucGlkKS50b1N0cmluZygzNik7XG4gIHJldHVybiB7XG4gICAgc2Vzc2lvbklkOiBkZXJpdmVkU2Vzc2lvbklkLFxuICAgIHJ1bnRpbWVTZXNzaW9uSWQ6IGAke2Rlcml2ZWRTZXNzaW9uSWR9LSR7cGlkU3VmZml4fWAsXG4gICAgc291cmNlOiAnZGVyaXZlZCcsXG4gIH07XG59XG4iXX0=