import * as fs from 'node:fs'; import * as path from 'node:path'; import { RequestReply } from '@open-matrix/core/engine/remoting/RequestReply.js'; import type { MatrixActor } from '@open-matrix/core/core/MatrixActor.js'; import { MatrixRuntime } from '@open-matrix/core/runtime/MatrixRuntime.js'; import { countRuntimeDirectory, publishRuntimePresence, } from '@open-matrix/core'; import type { MatrixMountCardinality, MatrixPlacementClaimMode, RuntimeInventoryPlacementMetadata, } from '@open-matrix/contracts/placement'; import type { RuntimePresenceRecordV1 } from '@open-matrix/contracts/runtime-presence'; import type { ILoadedMatrixPackageEnvironment } from './package-environment.js'; import type { IResolvedRunnerTransportPlan } from './runner-transport.js'; import type { ILoadedMatrixBindingDeclaration, ILoadedMatrixServiceManifest, } from './service-manifest.js'; import { readRunnerPlacementStandbyResults } from './runner-placement-policy.js'; import { BindingsRegistryActor } from '@open-matrix/system-bindings'; import { ServiceRegistryActor } from '@open-matrix/system-platform'; import { RuntimeManagerActor } from '@open-matrix/system-runtimes'; const RUNTIME_REGISTRY_MOUNT = 'system.runtimes'; const LOGICAL_REGISTRY_MOUNT = 'system.registry'; const BINDINGS_REGISTRY_MOUNT = 'system.bindings'; const RUNTIME_PRESENCE_TTL_MS = 30_000; const LOCAL_CONTROL_PLANE_REQUEST_TIMEOUT_MS = 5_000; const LINKED_CONTROL_PLANE_REQUEST_TIMEOUT_MS = 15_000; interface IRuntimeInventoryEntry { readonly mount: string; readonly type?: string; readonly runtimeId: string; readonly claimKind: MatrixPlacementClaimMode; readonly placement: RuntimeInventoryPlacementMetadata; readonly description?: string; readonly hasChildren?: boolean; } interface IPlacementDeclarationIndex { readonly byMount: ReadonlyMap; } export interface IRunnerControlPlaneState { readonly runtimeRegistryMount: string; readonly logicalRegistryMount: string; readonly bindingsRegistryMount: string; readonly createdRuntimeRegistry: boolean; readonly createdLogicalRegistry: boolean; readonly createdBindingsRegistry: boolean; } export interface IRunnerRuntimeRegistration { readonly runtimeId: string; readonly runtimeRoot: string; readonly presence: RuntimePresenceRecordV1; readonly registryMount: string; readonly logicalRegistryMount: string; readonly controlTargetRoot?: string; readonly protocolRequest?: boolean; readonly runtimeMount?: string; readonly controlMount?: string; readonly created: boolean; readonly actorCount: number; readonly inventoryClaimCount: number; readonly runtimeCount: number; readonly registryOptional?: boolean; /** * Re-issue the inventory `registry.claim` calls and re-publish presence. * Used by the heartbeat tick when `registry.claim.renew` reports the * registry no longer has our claim (e.g. after the registry actor's * in-memory `_claims` map was wiped by a SYSTEM runtime restart). * Idempotent: `onRegistryClaim` preserves `registeredAt`/`claimedAt` * when an existing entry is found. */ readonly reclaim: () => Promise<{ inventoryClaimCount: number }>; } export interface IRunnerRuntimeDeregistration { readonly runtimeId: string; readonly registryMount: string; readonly removed: boolean; readonly runtimeCount: number; } export interface IRunnerRuntimeHeartbeat { readonly runtimeId: string; readonly known: boolean; } export interface IRunnerWebappRouteMetadata { readonly appName: string; readonly routePrefix?: string; readonly displayName?: string; readonly icon?: string; readonly navOrder?: number; readonly description?: string; readonly shells?: readonly string[]; readonly assetMount?: string; readonly origin?: string; readonly port?: number; } export interface IRunnerBindingRegistration { readonly runtimeId: string; readonly registryMount: string; readonly logicalRegistryMount: string; readonly controlTargetRoot?: string; readonly protocolRequest?: boolean; readonly registeredCount: number; readonly registryClaimCount: number; readonly registryOptional?: boolean; readonly bindings: ReadonlyArray<{ readonly binding: string; readonly localMount: string; readonly ops: readonly string[]; readonly packageName: string; }>; /** * Re-issue every server-side record this runner published at registration * time: the canonical-binding `registry.claim` calls AND the * `bindings.register` calls. Both are in-memory on their respective * registry actors, so a single SYSTEM restart wipes them together. The * heartbeat tick triggers reclaim when `registry.claim.renew` reports the * registry no longer has our claims; bindings.register loss is treated as * a co-occurring symptom of the same SYSTEM restart and reclaimed in * lockstep. Both server-side ops are idempotent (onRegistryClaim * preserves identity; bindings.register is keyed by provider+match), so * calling reclaim() against a healthy registry is harmless. */ readonly reclaim: () => Promise<{ readonly registryClaimCount: number; readonly bindingsRegisteredCount: number; }>; } export interface IRunnerBindingDeregistration { readonly runtimeId: string; readonly registryMount: string; readonly logicalRegistryMount: string; readonly removedCount: number; readonly registryRemovedCount: number; } export interface IRunnerBindingRenewal { readonly runtimeId: string; readonly refreshed: number; } interface ICanonicalBindingDefinition { readonly binding: string; readonly localMount: string; readonly ops: readonly string[]; readonly packageName: string; } interface IRunnerHostPlacement { readonly deviceId: string; readonly hostId: string; readonly hostName?: string; readonly deviceSlug?: string; } interface IControlPlaneRequestOptions { readonly timeoutMs: number; readonly targetRoot?: string; readonly protocolRequest?: boolean; } export async function ensureRunnerControlPlane(runtime: MatrixRuntime): Promise { const createdRuntimeRegistry = await ensureRegistryActor(runtime, RUNTIME_REGISTRY_MOUNT, RuntimeManagerActor); const createdLogicalRegistry = await ensureRegistryActor(runtime, LOGICAL_REGISTRY_MOUNT, ServiceRegistryActor); const createdBindingsRegistry = await ensureRegistryActor(runtime, BINDINGS_REGISTRY_MOUNT, BindingsRegistryActor); return { runtimeRegistryMount: RUNTIME_REGISTRY_MOUNT, logicalRegistryMount: LOGICAL_REGISTRY_MOUNT, bindingsRegistryMount: BINDINGS_REGISTRY_MOUNT, createdRuntimeRegistry, createdLogicalRegistry, createdBindingsRegistry, }; } export interface IEnsureRunnerControlPlaneOptions { readonly createLocalRegistries?: boolean; } export async function ensureRunnerControlPlaneForMode( runtime: MatrixRuntime, options: IEnsureRunnerControlPlaneOptions = {}, ): Promise { const createLocalRegistries = options.createLocalRegistries ?? true; const createdRuntimeRegistry = createLocalRegistries ? await ensureRegistryActor(runtime, RUNTIME_REGISTRY_MOUNT, RuntimeManagerActor) : false; const createdLogicalRegistry = createLocalRegistries ? await ensureRegistryActor(runtime, LOGICAL_REGISTRY_MOUNT, ServiceRegistryActor) : false; const createdBindingsRegistry = createLocalRegistries ? await ensureRegistryActor(runtime, BINDINGS_REGISTRY_MOUNT, BindingsRegistryActor) : false; return { runtimeRegistryMount: RUNTIME_REGISTRY_MOUNT, logicalRegistryMount: LOGICAL_REGISTRY_MOUNT, bindingsRegistryMount: BINDINGS_REGISTRY_MOUNT, createdRuntimeRegistry, createdLogicalRegistry, createdBindingsRegistry, }; } export async function registerRunnerRuntime( runtime: MatrixRuntime, manifest: ILoadedMatrixServiceManifest, environment: ILoadedMatrixPackageEnvironment | undefined, runnerTransport: IResolvedRunnerTransportPlan | undefined, serviceMount?: string, runtimeMount?: string, controlMount?: string, webappRoute?: IRunnerWebappRouteMetadata, ): Promise { const controlPlane = await ensureRunnerControlPlaneForMode(runtime, { createLocalRegistries: !isHostManagedEnvironment(environment), }); const runtimeId = resolveRunnerRuntimeId(manifest, environment); const runtimeRoot = readTransportRoot(runtime) ?? environment?.environment.runtime.root ?? manifest.root ?? runtimeId; const hostPlacement = resolveRunnerHostPlacement(runtime, environment); const registryOptional = isHostedAuthorityLeafEnvironment(runtime, environment); const actorCount = runtime.getAllComponents().length; const placementDeclarations = readPlacementDeclarations(manifest); const requestOptions = controlPlaneRequestOptions( runtime, environment, controlPlaneRequestTimeoutMs(environment), ); const inventory = buildRuntimeInventory(runtime, runtimeId, placementDeclarations); const presence = buildRuntimePresenceRecord({ runtimeId, runtimeRoot, manifest, environment, actorCount, inventory, serviceMount, runtimeMount, controlMount, runnerTransport, webappRoute, hostPlacement, }); const inventoryClaimCount = await registerRuntimeInventoryClaims( runtime, controlPlane.logicalRegistryMount, manifest, environment, runtimeId, runtimeRoot, inventory, serviceMount, webappRoute, hostPlacement, registryOptional, ); publishRuntimePresence(runtime.getRootContext(), presence, 'announce'); const runtimeCount = await tryReadRegisteredRuntimeCount( runtime, controlPlane.logicalRegistryMount, ); // Closure for re-issuing the same inventory claims when the registry has // forgotten us (renew returns renewed: 0). Captures everything needed — // the runtime, the original manifest/environment, runtimeId, etc. — // so the heartbeat tick can call reclaim() without re-resolving any // identity. `onRegistryClaim` is idempotent for an existing entry, so // calling reclaim() when the registry IS healthy is harmless. const reclaim = async (): Promise<{ inventoryClaimCount: number }> => { const freshActorCount = runtime.getAllComponents().length; const freshInventory = buildRuntimeInventory(runtime, runtimeId, placementDeclarations); const freshPresence = buildRuntimePresenceRecord({ runtimeId, runtimeRoot, manifest, environment, actorCount: freshActorCount, inventory: freshInventory, serviceMount, runtimeMount, controlMount, runnerTransport, webappRoute, hostPlacement, }); const reclaimedCount = await registerRuntimeInventoryClaims( runtime, controlPlane.logicalRegistryMount, manifest, environment, runtimeId, runtimeRoot, freshInventory, serviceMount, webappRoute, hostPlacement, registryOptional, ); // Re-announce presence so RuntimeManagerActor's _runtimes Map repopulates // with us even if it was cleared by a SYSTEM restart. publishRuntimePresence(runtime.getRootContext(), freshPresence, 'announce'); return { inventoryClaimCount: reclaimedCount }; }; return { runtimeId, runtimeRoot, presence, registryMount: controlPlane.runtimeRegistryMount, logicalRegistryMount: controlPlane.logicalRegistryMount, ...(requestOptions.targetRoot ? { controlTargetRoot: requestOptions.targetRoot } : {}), ...(requestOptions.protocolRequest === true ? { protocolRequest: true } : {}), ...(runtimeMount ? { runtimeMount } : {}), ...(controlMount ? { controlMount } : {}), created: true, actorCount, inventoryClaimCount, runtimeCount, ...(registryOptional ? { registryOptional: true } : {}), reclaim, }; } export async function deregisterRunnerRuntime( runtime: MatrixRuntime, registration: IRunnerRuntimeRegistration | undefined, ): Promise { if (!registration) { return undefined; } if (registration.registryOptional === true) { const departedAt = Date.now(); publishRuntimePresence( runtime.getRootContext(), { ...registration.presence, lastHeartbeat: departedAt, health: { status: 'stopped', updatedAt: departedAt, }, }, 'departed', ); return { runtimeId: registration.runtimeId, registryMount: registration.registryMount, removed: false, runtimeCount: 0, }; } const registryReleased = await RequestReply.execute, { removed?: number }>( runtime.getRootContext(), registration.logicalRegistryMount, 'registry.release', { providerRuntimeId: registration.runtimeId }, registrationControlPlaneRequestOptions(registration, LOCAL_CONTROL_PLANE_REQUEST_TIMEOUT_MS), ); const departedAt = Date.now(); publishRuntimePresence( runtime.getRootContext(), { ...registration.presence, lastHeartbeat: departedAt, health: { status: 'stopped', updatedAt: departedAt, }, }, 'departed', ); const runtimeCount = await tryReadRegisteredRuntimeCount( runtime, registration.logicalRegistryMount, ); return { runtimeId: registration.runtimeId, registryMount: registration.registryMount, removed: typeof registryReleased.removed === 'number' && registryReleased.removed > 0, runtimeCount, }; } async function tryReadRegisteredRuntimeCount( runtime: MatrixRuntime, _registryMount: string, ): Promise { // Slice 1b (control-actor-nav): runtime directory authority is // `system.runtimes`, not the service registry. Read through the adapter. try { return await countRuntimeDirectory(runtime.getRootContext(), { includeStale: true }); } catch { return 0; } } export async function heartbeatRunnerRuntime( runtime: MatrixRuntime, registration: IRunnerRuntimeRegistration | undefined, ): Promise { if (!registration) { return undefined; } if (registration.registryOptional === true) { const now = Date.now(); publishRuntimePresence( runtime.getRootContext(), { ...registration.presence, inventory: rebuildRuntimeInventoryForHeartbeat(runtime, registration), lastHeartbeat: now, health: { status: registration.presence.health?.status ?? 'ok', ...(registration.presence.health?.reason ? { reason: registration.presence.health.reason } : {}), updatedAt: now, }, }, 'heartbeat', ); return { runtimeId: registration.runtimeId, known: true, }; } const renewal = await RequestReply.execute, { renewed?: number }>( runtime.getRootContext(), registration.logicalRegistryMount, 'registry.claim.renew', { providerRuntimeId: registration.runtimeId, ttlMs: 30_000, }, registrationControlPlaneRequestOptions(registration, 5_000), ); const now = Date.now(); publishRuntimePresence( runtime.getRootContext(), { ...registration.presence, inventory: rebuildRuntimeInventoryForHeartbeat(runtime, registration), lastHeartbeat: now, health: { status: registration.presence.health?.status ?? 'ok', ...(registration.presence.health?.reason ? { reason: registration.presence.health.reason } : {}), updatedAt: now, }, }, 'heartbeat', ); return { runtimeId: registration.runtimeId, known: typeof renewal.renewed === 'number' && renewal.renewed > 0, }; } export async function registerRunnerBindings( runtime: MatrixRuntime, manifest: ILoadedMatrixServiceManifest, environment: ILoadedMatrixPackageEnvironment | undefined, runtimeId: string, serviceMount?: string, ): Promise { const controlPlane = await ensureRunnerControlPlaneForMode(runtime, { createLocalRegistries: !isHostManagedEnvironment(environment), }); const nonCallableBindingMounts = await resolveNonCallableBindingMounts(runtime, manifest, serviceMount); const bindings = deriveCanonicalBindings(manifest, environment, serviceMount) .filter((binding) => !nonCallableBindingMounts.has(binding.localMount)); const placementDeclarations = readPlacementDeclarations(manifest); const runtimeWireRoot = readTransportRoot(runtime) ?? environment?.environment.runtime.root ?? manifest.root ?? runtimeId; const authorityRoot = environment?.environment.runtime.root ?? manifest.root ?? runtimeWireRoot; const hostPlacement = resolveRunnerHostPlacement(runtime, environment); const registryOptional = isHostedAuthorityLeafEnvironment(runtime, environment); const timeoutMs = controlPlaneRequestTimeoutMs(environment); const requestOptions = controlPlaneRequestOptions(runtime, environment, timeoutMs); const publishBindingForwards = shouldPublishBindingForwards(environment); const issueBindingClaims = async (): Promise => { let issued = 0; for (const binding of bindings) { const placement = placementForMount( binding.localMount, binding.binding, resolveCardinalityForMount(placementDeclarations, binding.localMount), true, ); await RequestReply.execute( runtime.getRootContext(), controlPlane.logicalRegistryMount, 'registry.claim', { mount: binding.binding, kind: 'actor', componentId: `${binding.packageName}:${binding.binding}`, componentType: 'actor', authorityRoot, scope: 'identity-relative', providerRuntimeId: runtimeId, runtimeWireRoot, localMount: binding.localMount, packageName: binding.packageName, mode: placement.claimMode, cardinality: placement.cardinality, claimMode: placement.claimMode, logicalMount: placement.logicalMount, physicalMount: placement.physicalMount, callable: placement.callable, ...registryClaimPlacement(hostPlacement), metadata: { ops: [...binding.ops], source: 'runner-control-plane', placement, ...hostPlacementMetadata(hostPlacement), }, }, requestOptions, ); issued += 1; } return issued; }; const registerBindingForwards = async (): Promise => { if (!publishBindingForwards) { return 0; } let registered = 0; for (const binding of bindings) { await RequestReply.execute( runtime.getRootContext(), controlPlane.bindingsRegistryMount, 'bindings.register', { provider: runtimeId, runtimeId, packageName: binding.packageName, localMount: binding.localMount, match: binding.binding, ops: [...binding.ops], forward: binding.localMount, }, requestOptions, ); registered += 1; } return registered; }; const registryClaimCount = registryOptional ? 0 : await issueBindingClaims(); const bindingsRegisteredCount = registryOptional ? 0 : await registerBindingForwards(); // Reclaim re-issues every server-side record this runner published at // registration time. Both registries (system.registry and system.bindings) // store their state in-memory. A single SYSTEM restart wipes them // together, so the heartbeat tick reclaims both in lockstep when // registry.claim.renew reports loss. const reclaim = async (): Promise<{ registryClaimCount: number; bindingsRegisteredCount: number; }> => { const registryClaimCount = registryOptional ? 0 : await issueBindingClaims(); const bindingsRegisteredCount = registryOptional ? 0 : await registerBindingForwards(); return { registryClaimCount, bindingsRegisteredCount }; }; return { runtimeId, registryMount: controlPlane.bindingsRegistryMount, logicalRegistryMount: controlPlane.logicalRegistryMount, ...(requestOptions.targetRoot ? { controlTargetRoot: requestOptions.targetRoot } : {}), ...(requestOptions.protocolRequest === true ? { protocolRequest: true } : {}), registeredCount: bindingsRegisteredCount, registryClaimCount, ...(registryOptional ? { registryOptional: true } : {}), bindings, reclaim, }; } export async function deregisterRunnerBindings( runtime: MatrixRuntime, registration: IRunnerBindingRegistration | undefined, ): Promise { if (!registration) { return undefined; } if (registration.registeredCount === 0) { return { runtimeId: registration.runtimeId, registryMount: registration.registryMount, logicalRegistryMount: registration.logicalRegistryMount, removedCount: 0, registryRemovedCount: 0, }; } const removed = await RequestReply.execute( runtime.getRootContext(), registration.registryMount, 'bindings.remove', { provider: registration.runtimeId }, registrationControlPlaneRequestOptions(registration, 5_000), ) as { removed?: number }; return { runtimeId: registration.runtimeId, registryMount: registration.registryMount, logicalRegistryMount: registration.logicalRegistryMount, removedCount: typeof removed.removed === 'number' ? removed.removed : 0, registryRemovedCount: 0, }; } export async function renewRunnerBindings( runtime: MatrixRuntime, registration: IRunnerBindingRegistration | undefined, ): Promise { if (!registration) { return undefined; } if (registration.registryOptional === true) { return { runtimeId: registration.runtimeId, refreshed: registration.bindings.length, }; } const renewal = await RequestReply.execute( runtime.getRootContext(), registration.logicalRegistryMount, 'registry.claim.renew', { packageName: registration.bindings[0]?.packageName, providerRuntimeId: registration.runtimeId, }, registrationControlPlaneRequestOptions(registration, 5_000), ) as { renewed?: number }; return { runtimeId: registration.runtimeId, refreshed: typeof renewal.renewed === 'number' ? renewal.renewed : 0, }; } export function resolveRunnerRuntimeId( manifest: ILoadedMatrixServiceManifest, environment: ILoadedMatrixPackageEnvironment | undefined, ): string { const runtimeId = environment?.environment.runtime.runtimeId?.trim(); if (runtimeId) { return runtimeId; } const manifestId = manifest.serviceInstance.id.trim(); if (manifestId.length > 0) { return manifestId; } return manifest.packageName; } function isHostManagedEnvironment(environment: ILoadedMatrixPackageEnvironment | undefined): boolean { const matrixDir = environment?.environment.host?.matrixDir; return typeof matrixDir === 'string' && matrixDir.trim().length > 0; } function isHostedAuthorityLeafEnvironment( runtime: MatrixRuntime, environment: ILoadedMatrixPackageEnvironment | undefined, ): boolean { if (!isHostManagedEnvironment(environment)) { return false; } const topology = readRecord(runtime.getRootContext().getService('matrix-node-topology')) ?? readRecord(environment?.environment.topology); const roles = readRecord(topology?.roles); const authorityCoordinator = readRecord(roles?.authorityCoordinator); if (authorityCoordinator?.active === false) { return true; } const hostHome = trimToUndefined(runtime.getRootContext().getService('matrix-host-home')) ?? trimToUndefined(environment?.environment.host?.matrixDir); if (!hostHome) { return false; } const linkRecord = readJsonObjectIfPresent(path.join(hostHome, 'credentials', 'hivecast-link.json')); return linkRecord?.authorityCoordinator === false && Boolean(trimToUndefined(linkRecord.deviceRegistryRoot)); } function readTransportRoot(runtime: MatrixRuntime): string | undefined { const root = (runtime.transport as { root?: unknown }).root; return typeof root === 'string' && root.trim().length > 0 ? root.trim() : undefined; } async function resolveNonCallableBindingMounts( runtime: MatrixRuntime, manifest: ILoadedMatrixServiceManifest, serviceMount: string | undefined, ): Promise> { const mounts = new Set(); for (const standby of readRunnerPlacementStandbyResults(runtime)) { if (standby.placement.callable === false) { mounts.add(standby.mount); } } if (manifest.packageName === '@open-matrix/system') { const systemMount = serviceMount?.trim() || manifest.mount?.trim() || manifest.packageRoot?.mount?.trim() || 'system'; const response = await RequestReply.execute, { readonly children?: readonly unknown[]; }>( runtime.getRootContext(), systemMount, 'system.children', {}, { timeoutMs: 2_000 }, ); for (const child of response.children ?? []) { const record = isRecord(child) ? child : null; const mount = trimToUndefined(record?.mount); const status = trimToUndefined(record?.status); if (mount && status !== 'mounted') { mounts.add(mount); } } } return mounts; } function buildRuntimeInventory( runtime: MatrixRuntime, runtimeId: string, placementDeclarations: IPlacementDeclarationIndex, ): IRuntimeInventoryEntry[] { const inventory: IRuntimeInventoryEntry[] = []; for (const component of runtime.getAllComponents()) { const mount = component.mount.trim(); if (mount.length === 0) { continue; } const placement = placementForMount( mount, mount, resolveCardinalityForMount(placementDeclarations, mount), true, ); const description = typeof (component.constructor as { description?: unknown }).description === 'string' ? (component.constructor as { description?: string }).description : undefined; inventory.push({ mount, ...(component.constructor.name ? { type: component.constructor.name } : {}), runtimeId, claimKind: placement.claimMode, placement, ...(description ? { description } : {}), ...(hasIntrospectChildren(component) ? { hasChildren: true } : {}), }); } appendStandbyPlacementResults(inventory, runtime, runtimeId); return inventory; } function rebuildRuntimeInventoryForHeartbeat( runtime: MatrixRuntime, registration: IRunnerRuntimeRegistration, ): IRuntimeInventoryEntry[] { const previousPlacementByMount = new Map(); for (const entry of registration.presence.inventory ?? []) { if (entry.placement) { previousPlacementByMount.set(entry.mount, entry.placement); } } const inventory: IRuntimeInventoryEntry[] = []; for (const component of runtime.getAllComponents()) { const mount = component.mount.trim(); if (mount.length === 0) { continue; } const previousPlacement = previousPlacementByMount.get(mount) ?? placementForMount(mount, mount, 'named-instance', true); const description = typeof (component.constructor as { description?: unknown }).description === 'string' ? (component.constructor as { description?: string }).description : undefined; inventory.push({ mount, ...(component.constructor.name ? { type: component.constructor.name } : {}), runtimeId: registration.runtimeId, claimKind: previousPlacement.claimMode, placement: previousPlacement, ...(description ? { description } : {}), ...(hasIntrospectChildren(component) ? { hasChildren: true } : {}), }); } appendStandbyPlacementResults(inventory, runtime, registration.runtimeId); return inventory; } function appendStandbyPlacementResults( inventory: IRuntimeInventoryEntry[], runtime: MatrixRuntime, runtimeId: string, ): void { const seen = new Set(inventory.map((entry) => entry.mount)); for (const standby of readRunnerPlacementStandbyResults(runtime)) { if (standby.runtimeId !== runtimeId || seen.has(standby.mount)) { continue; } inventory.push({ mount: standby.mount, runtimeId, claimKind: standby.placement.claimMode, placement: standby.placement, }); seen.add(standby.mount); } } function buildRuntimePresenceRecord(params: { runtimeId: string; runtimeRoot: string; manifest: ILoadedMatrixServiceManifest; environment: ILoadedMatrixPackageEnvironment | undefined; actorCount: number; inventory: readonly IRuntimeInventoryEntry[]; serviceMount: string | undefined; runtimeMount: string | undefined; controlMount: string | undefined; runnerTransport: IResolvedRunnerTransportPlan | undefined; webappRoute: IRunnerWebappRouteMetadata | undefined; hostPlacement: IRunnerHostPlacement | undefined; }): RuntimePresenceRecordV1 { const now = Date.now(); const namespaceRoot = params.runtimeRoot; return { version: '1', namespaceRoot, runtimeId: params.runtimeId, runtimeType: 'folder', runtimeRoot: params.runtimeRoot, authorityRoot: namespaceRoot, app: params.manifest.packageName, claims: buildRuntimeClaims(params.serviceMount, params.environment), inventoryMode: 'embedded', inventory: [...params.inventory], ...(params.controlMount ? { controlMount: params.controlMount } : {}), heartbeatTtlMs: RUNTIME_PRESENCE_TTL_MS, registeredAt: now, lastHeartbeat: now, health: { status: 'ok', updatedAt: now, }, metadata: { source: 'mx-runner-runtime-presence', actorCount: params.actorCount, packageDir: params.manifest.packageDir, packageName: params.manifest.packageName, // Runtime displayName is set by host-service at spawn (--name or // generated). The host passes it via env so the runtime can publish // it in its registry presence record. Consumers read this field // directly; no derivation from package or runtimeId. ...(process.env.MATRIX_RUNTIME_DISPLAY_NAME ? { displayName: process.env.MATRIX_RUNTIME_DISPLAY_NAME } : {}), ...(params.environment ? { environmentName: params.environment.envName, environmentPath: params.environment.environmentPath, } : {}), ...(params.runtimeMount ? { runtimeMount: params.runtimeMount } : {}), ...(params.manifest.mount ? { serviceMount: params.manifest.mount } : {}), ...(params.environment?.environment.package?.publicRoot ? { publicRoot: params.environment.environment.package.publicRoot, } : {}), ...(params.runnerTransport ? { runnerTransport: params.runnerTransport } : {}), ...(params.webappRoute ? { webapp: params.webappRoute } : {}), ...hostPlacementMetadata(params.hostPlacement), }, }; } function hasIntrospectChildren(component: MatrixActor): boolean { const constructor = component.constructor as { readonly hasDynamicChildren?: unknown }; if (constructor.hasDynamicChildren === true) { return true; } try { const introspection = component.on$introspect({ depth: 'basic' }); return Array.isArray(introspection.children) && introspection.children.length > 0; } catch { return false; } } async function registerRuntimeInventoryClaims( runtime: MatrixRuntime, logicalRegistryMount: string, manifest: ILoadedMatrixServiceManifest, environment: ILoadedMatrixPackageEnvironment | undefined, runtimeId: string, runtimeWireRoot: string, inventory: readonly IRuntimeInventoryEntry[], _serviceMount: string | undefined, webappRoute: IRunnerWebappRouteMetadata | undefined, hostPlacement: IRunnerHostPlacement | undefined, registryOptional: boolean, ): Promise { if (registryOptional) { return 0; } const authorityRoot = environment?.environment.runtime.root ?? manifest.root ?? runtimeWireRoot; const timeoutMs = controlPlaneRequestTimeoutMs(environment); const requestOptions = controlPlaneRequestOptions(runtime, environment, timeoutMs); let registered = 0; for (const entry of inventory) { const logicalMount = entry.mount.trim(); if (entry.placement.callable === false) { continue; } if (!shouldRegisterRuntimeInventoryClaim(runtimeId, logicalMount)) { continue; } await RequestReply.execute( runtime.getRootContext(), logicalRegistryMount, 'registry.claim', { mount: logicalMount, kind: 'actor', componentId: `${manifest.packageName}:inventory:${logicalMount}`, componentType: entry.type ?? 'actor', authorityRoot, scope: 'identity-relative', providerRuntimeId: runtimeId, runtimeWireRoot, localMount: logicalMount, packageName: manifest.packageName, mode: entry.placement.claimMode, cardinality: entry.placement.cardinality, claimMode: entry.placement.claimMode, logicalMount: entry.placement.logicalMount, physicalMount: entry.placement.physicalMount, callable: entry.placement.callable, ...(entry.placement.standbyReason ? { standbyReason: entry.placement.standbyReason } : {}), ...(typeof entry.placement.placementEpoch === 'number' ? { placementEpoch: entry.placement.placementEpoch } : {}), ...registryClaimPlacement(hostPlacement), ttlMs: 30_000, metadata: { source: 'runner-runtime-inventory', placement: entry.placement, ...(entry.description ? { description: entry.description } : {}), ...(entry.hasChildren === true ? { hasChildren: true } : {}), ...hostPlacementMetadata(hostPlacement), }, }, requestOptions, ); registered++; } if (webappRoute) { registered += await registerWebappSurfaceClaim( runtime, logicalRegistryMount, manifest, authorityRoot, runtimeId, runtimeWireRoot, webappRoute, hostPlacement, requestOptions, ); } return registered; } async function registerWebappSurfaceClaim( runtime: MatrixRuntime, logicalRegistryMount: string, manifest: ILoadedMatrixServiceManifest, authorityRoot: string, runtimeId: string, runtimeWireRoot: string, webappRoute: IRunnerWebappRouteMetadata, hostPlacement: IRunnerHostPlacement | undefined, requestOptions: IControlPlaneRequestOptions, ): Promise { const appName = webappRoute.appName.trim(); if (!appName) { return 0; } const routePrefix = normalizeWebappRoutePrefix(webappRoute.routePrefix, appName); const placement = placementForMount( webappRoute.assetMount ?? appName, appName, 'named-instance', true, ); const displayName = readOptionalString(webappRoute.displayName); const icon = readOptionalString(webappRoute.icon); const description = readOptionalString(webappRoute.description); const shells = [...new Set((webappRoute.shells ?? []).map((entry) => entry.trim()).filter((entry) => entry.length > 0))]; await RequestReply.execute( runtime.getRootContext(), logicalRegistryMount, 'registry.claim', { mount: appName, kind: 'app', componentId: `${manifest.packageName}:webapp:${appName}`, componentType: 'webapp', authorityRoot, scope: 'identity-relative', providerRuntimeId: runtimeId, runtimeWireRoot, localMount: webappRoute.assetMount ?? appName, packageName: manifest.packageName, runtimeId, packageId: manifest.packageName, packageRef: manifest.packageName, mode: placement.claimMode, cardinality: placement.cardinality, claimMode: placement.claimMode, logicalMount: placement.logicalMount, physicalMount: placement.physicalMount, callable: placement.callable, ...registryClaimPlacement(hostPlacement), ttlMs: 30_000, app: { route: routePrefix, title: displayName ?? titleFromAppName(appName), ...(icon ? { icon } : {}), surface: 'page', openable: true, appName, }, metadata: { source: 'runner-webapp-surface', placement, routeKind: webappRoute.assetMount ? 'matrix-asset-endpoint' : 'standalone-webapp', ...(description ? { description } : {}), ...(shells.length > 0 ? { shells } : {}), ...(typeof webappRoute.navOrder === 'number' && Number.isFinite(webappRoute.navOrder) ? { navOrder: webappRoute.navOrder } : {}), ...(webappRoute.assetMount ? { assetMount: webappRoute.assetMount } : {}), ...(webappRoute.origin ? { origin: webappRoute.origin } : {}), ...(typeof webappRoute.port === 'number' ? { port: webappRoute.port } : {}), ...hostPlacementMetadata(hostPlacement), }, }, requestOptions, ); return 1; } function controlPlaneRequestOptions( runtime: MatrixRuntime, environment: ILoadedMatrixPackageEnvironment | undefined, timeoutMs: number, ): IControlPlaneRequestOptions { const targetRoot = environment?.environment.runtime.root ?? readTransportRoot(runtime); const protocolRequest = isHostManagedEnvironment(environment) && typeof environment?.environment.nats?.credentialsRef === 'string' && environment.environment.nats.credentialsRef.trim().length > 0; return { timeoutMs, ...(targetRoot ? { targetRoot } : {}), ...(protocolRequest ? { protocolRequest: true } : {}), }; } function registrationControlPlaneRequestOptions( registration: Pick, timeoutMs: number, ): IControlPlaneRequestOptions { return { timeoutMs, ...(registration.controlTargetRoot ? { targetRoot: registration.controlTargetRoot } : {}), ...(registration.protocolRequest === true ? { protocolRequest: true } : {}), }; } function shouldPublishBindingForwards(environment: ILoadedMatrixPackageEnvironment | undefined): boolean { return !isHostManagedEnvironment(environment); } function controlPlaneRequestTimeoutMs(environment: ILoadedMatrixPackageEnvironment | undefined): number { return environment?.environment.nats?.credentialsRef ? LINKED_CONTROL_PLANE_REQUEST_TIMEOUT_MS : LOCAL_CONTROL_PLANE_REQUEST_TIMEOUT_MS; } function normalizeWebappRoutePrefix(value: string | undefined, appName: string): string { const routePrefix = value?.trim() || `/apps/${appName}/`; return routePrefix.endsWith('/') ? routePrefix : `${routePrefix}/`; } function readOptionalString(value: string | undefined): string | undefined { const trimmed = value?.trim() ?? ''; return trimmed.length > 0 ? trimmed : undefined; } function titleFromAppName(appName: string): string { return appName .split(/[-_.]/) .filter(Boolean) .map((segment) => `${segment.charAt(0).toUpperCase()}${segment.slice(1)}`) .join(' '); } export function shouldRegisterRuntimeInventoryClaim(runtimeId: string, logicalMount: string): boolean { const trimmedRuntimeId = runtimeId.trim(); const trimmedMount = logicalMount.trim(); if (!trimmedRuntimeId || !trimmedMount) { return false; } const runtimeMount = `system.runtimes.${trimmedRuntimeId}`; if (trimmedMount === runtimeMount || trimmedMount.startsWith(`${runtimeMount}.`)) { return false; } return true; } function buildRuntimeClaims( serviceMount: string | undefined, environment: ILoadedMatrixPackageEnvironment | undefined, ): Array<{ prefix: string; kind: 'authoritative' }> { const claims = new Set(); const publicRoot = environment?.environment.package?.publicRoot?.trim(); if (publicRoot) { claims.add(publicRoot); } const resolvedServiceMount = serviceMount?.trim(); if (resolvedServiceMount) { claims.add(resolvedServiceMount); } return [...claims].map((prefix) => ({ prefix, kind: 'authoritative' as const })); } function deriveCanonicalBindings( manifest: ILoadedMatrixServiceManifest, environment: ILoadedMatrixPackageEnvironment | undefined, serviceMount: string | undefined, ): ICanonicalBindingDefinition[] { const bindings = new Map(); const packageName = manifest.packageName; const publicRoot = trimToUndefined(environment?.environment.package?.publicRoot) ?? trimToUndefined(manifest.packageNamespace); const resolvedServiceMount = trimToUndefined(serviceMount) ?? trimToUndefined(manifest.mount); const rootKind = trimToUndefined(manifest.serviceInstance.rootKind) ?? 'package-root'; if (rootKind === 'package-root' && manifest.packageRoot) { const canonicalRoot = resolveCanonicalRootBinding(manifest.packageRoot, publicRoot); const localRootMount = resolvedServiceMount ?? resolveLocalRootMount(manifest.packageRoot, publicRoot); if (canonicalRoot && localRootMount) { bindings.set(canonicalRoot, { binding: canonicalRoot, localMount: localRootMount, ops: manifest.packageRoot.accepts, packageName, }); } } for (const declaration of manifest.packageComponents) { const binding = resolveCanonicalComponentBinding(declaration, publicRoot); const localMount = resolveLocalComponentMount(declaration, resolvedServiceMount, rootKind); if (!binding || !localMount) { continue; } bindings.set(binding, { binding, localMount, ops: declaration.accepts, packageName, }); } return [...bindings.values()]; } function resolveCanonicalRootBinding( declaration: ILoadedMatrixBindingDeclaration, publicRoot: string | undefined, ): string | undefined { if (isExplicitAbsoluteMount(declaration.mount)) { return declaration.mount; } return publicRoot ?? declaration.mount; } function resolveCanonicalComponentBinding( declaration: ILoadedMatrixBindingDeclaration, publicRoot: string | undefined, ): string | undefined { if (isExplicitAbsoluteMount(declaration.mount)) { return declaration.mount; } if (!publicRoot) { return undefined; } return `${publicRoot}.${declaration.mount}`; } function resolveLocalRootMount( declaration: ILoadedMatrixBindingDeclaration, publicRoot: string | undefined, ): string | undefined { return declaration.mount || publicRoot; } function resolveLocalComponentMount( declaration: ILoadedMatrixBindingDeclaration, serviceMount: string | undefined, rootKind: string, ): string | undefined { if (isExplicitAbsoluteMount(declaration.mount)) { return declaration.mount; } if (rootKind === 'package-root' && serviceMount) { return `${serviceMount}.${declaration.mount}`; } return declaration.mount; } function isExplicitAbsoluteMount(mount: string): boolean { return mount.includes('.'); } function trimToUndefined(value: unknown): string | undefined { if (typeof value !== 'string') { return undefined; } const trimmed = value.trim(); return trimmed.length > 0 ? trimmed : undefined; } function readPlacementDeclarations(manifest: ILoadedMatrixServiceManifest): IPlacementDeclarationIndex { const byMount = new Map(); const manifestRecord = readJsonObjectIfPresent(path.join(manifest.packageDir, 'matrix.json')); if (!manifestRecord) { return { byMount }; } addPlacementDeclaration(byMount, manifestRecord.root); const components = manifestRecord.components; if (Array.isArray(components)) { for (const component of components) { addPlacementDeclaration(byMount, component); } } return { byMount }; } function addPlacementDeclaration( byMount: Map, value: unknown, ): void { if (!isRecord(value)) { return; } const mount = trimToUndefined(value.mount); if (!mount) { return; } const placement = isRecord(value.placement) ? value.placement : undefined; const cardinality = readMountCardinality(placement?.cardinality); if (cardinality) { byMount.set(mount, cardinality); } } function resolveCardinalityForMount( declarations: IPlacementDeclarationIndex, mount: string, ): MatrixMountCardinality { return declarations.byMount.get(mount) ?? 'named-instance'; } function placementForMount( physicalMount: string, logicalMount: string, cardinality: MatrixMountCardinality, callable: boolean, ): RuntimeInventoryPlacementMetadata { return { cardinality, claimMode: claimModeForCardinality(cardinality), logicalMount, physicalMount, callable, }; } function claimModeForCardinality(cardinality: MatrixMountCardinality): MatrixPlacementClaimMode { if (cardinality === 'authority-singleton') { return 'authoritative'; } if (cardinality === 'queue-service') { return 'pool-member'; } if (cardinality === 'replicated-read') { return 'mirror'; } return 'local-only'; } function readMountCardinality(value: unknown): MatrixMountCardinality | undefined { return value === 'authority-singleton' || value === 'device-singleton' || value === 'device-local-control' || value === 'queue-service' || value === 'named-instance' || value === 'replicated-read' ? value : undefined; } function isRecord(value: unknown): value is Record { return Boolean(value) && typeof value === 'object' && !Array.isArray(value); } function readRecord(value: unknown): Record | undefined { return isRecord(value) ? value : undefined; } function resolveRunnerHostPlacement( runtime: MatrixRuntime, environment: ILoadedMatrixPackageEnvironment | undefined, ): IRunnerHostPlacement | undefined { const hostHome = trimToUndefined(runtime.getRootContext().getService('matrix-host-home')) ?? trimToUndefined(environment?.environment.host?.matrixDir); if (!hostHome) { return undefined; } const credentialsDir = path.join(hostHome, 'credentials'); const linkRecord = readJsonObjectIfPresent(path.join(credentialsDir, 'hivecast-link.json')); const installRecord = readJsonObjectIfPresent(path.join(credentialsDir, 'hivecast-install.json')); const hostId = trimToUndefined(linkRecord?.hostId) ?? trimToUndefined(installRecord?.installId); if (!hostId) { return undefined; } const hostName = trimToUndefined(linkRecord?.hostName) ?? trimToUndefined(installRecord?.hostName); const deviceSlug = trimToUndefined(linkRecord?.deviceSlug); return { deviceId: hostId, hostId, ...(hostName ? { hostName } : {}), ...(deviceSlug ? { deviceSlug } : {}), }; } function registryClaimPlacement(hostPlacement: IRunnerHostPlacement | undefined): Record { return hostPlacement ? { deviceId: hostPlacement.deviceId, hostId: hostPlacement.hostId, } : {}; } function hostPlacementMetadata(hostPlacement: IRunnerHostPlacement | undefined): Record { return hostPlacement ? { deviceId: hostPlacement.deviceId, hostId: hostPlacement.hostId, ...(hostPlacement.hostName ? { hostName: hostPlacement.hostName } : {}), ...(hostPlacement.deviceSlug ? { deviceSlug: hostPlacement.deviceSlug } : {}), } : {}; } function readJsonObjectIfPresent(filePath: string): Record | undefined { if (!fs.existsSync(filePath)) { return undefined; } const parsed = JSON.parse(fs.readFileSync(filePath, 'utf8').replace(/^\uFEFF/, '')) as unknown; if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) { throw new Error(`Expected JSON object at ${filePath}`); } return parsed as Record; } async function ensureRegistryActor( runtime: MatrixRuntime, mount: string, ActorClass: new () => TActor, ): Promise { if (runtime.hasComponent(mount)) { return false; } await runtime.createSupervised(ActorClass as never, mount); return true; }