import { readFile } from "node:fs/promises"; import { join } from "node:path"; import { loadDoctorCase } from "./doctor-evidence.ts"; import { createNavigatorAttendance } from "./navigator-attendance.ts"; import { createNavigatorLookup } from "./navigator-lookup.ts"; import { loadNotarySourceRunLocator } from "./notary-source-run.ts"; import { type RoleRuntimeDependencies } from "./role-runtime.ts"; import { loadAuditorReferenceMaterialsFromSubjectInput, loadAuditorSoulFromSubjectInput, } from "./auditor-soul.ts"; import { packagedRoleMetadata, type PackagedRole } from "./packaged-role-registry.ts"; import { loadMainRoleReferenceMaterials, loadMainRoleSessionMaterials, } from "./session-opening-materials.ts"; function usesSubjectSoul(role: string): boolean { const record = packagedRoleMetadata(role); return record !== undefined && "soulSource" in record && record.soulSource === "subject"; } /** Single packaged source for reference materials across production composition roots. */ export function loadPackagedRoleReferenceMaterials(role: Parameters>[0]): Promise { return usesSubjectSoul(role) ? loadAuditorReferenceMaterialsFromSubjectInput() : loadMainRoleReferenceMaterials(role); } /** One production soul loader. Subject seats read the subject input; every other seat reads its record. */ export function loadRegisteredRoleSoul(role: PackagedRole): Promise { return usesSubjectSoul(role) ? loadAuditorSoulFromSubjectInput() : loadMainRoleSessionMaterials(role); } /** Host-neutral packaged role runtime deps for the parent-process envelope. */ export function createRoleRuntimeDependencies(packageRoot: string): RoleRuntimeDependencies { // packageRoot is the install root (resources/ lives there). Never resolve via // import.meta.url — headless/acp production-host bundles live under dist/*/ // and would otherwise look for dist/resources/ (#962). const navigatorLookup = createNavigatorLookup(); return { packageRoot, loadRoleReferenceMaterials: loadPackagedRoleReferenceMaterials, loadRoleSoul: loadRegisteredRoleSoul, loadDoctorCase, loadNotarySourceRun: loadNotarySourceRunLocator, loadMergerInput: async (path) => JSON.parse(await readFile(path, "utf8")), createNavigatorAttendance: (options) => createNavigatorAttendance({ context: options.context, role: options.role, phase: options.phase, subjectKey: options.subjectKey, invocationId: options.invocationId, lookup: navigatorLookup, onEvent: options.onEvent, }), }; }