{"version":3,"file":"executor-registry-store.d.ts","sourceRoot":"","sources":["../../../src/core/executor-registry/executor-registry-store.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EACN,KAAK,oBAAoB,EACzB,KAAK,kBAAkB,EACvB,KAAK,cAAc,EAGnB,MAAM,8BAA8B,CAAC;AAEtC,eAAO,MAAM,gCAAgC,GAAa,CAAC;AAM3D,MAAM,MAAM,sBAAsB,GAC/B;IAAE,MAAM,EAAE,SAAS,CAAA;CAAE,GACrB;IAAE,MAAM,EAAE,YAAY,CAAC;IAAC,MAAM,EAAE,cAAc,CAAA;CAAE,GAChD;IAAE,MAAM,EAAE,UAAU,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAEzC,MAAM,MAAM,kBAAkB,GAC3B;IAAE,MAAM,EAAE,IAAI,CAAC;IAAC,MAAM,EAAE,cAAc,CAAA;CAAE,GACxC;IAAE,MAAM,EAAE,SAAS,CAAA;CAAE,GACrB;IAAE,MAAM,EAAE,SAAS,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,CAAC;AAEjE,uEAAuE;AACvE,MAAM,MAAM,gBAAgB,CAAC,CAAC,IAAI;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,IAAI,EAAE,cAAc,CAAC;IAAC,KAAK,EAAE,CAAC,CAAA;CAAE,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,CAAC,CAAA;CAAE,CAAC;AAEjH,MAAM,MAAM,oBAAoB,CAAC,CAAC,IAC/B;IAAE,MAAM,EAAE,IAAI,CAAC;IAAC,KAAK,EAAE,CAAC,CAAA;CAAE,GAC1B;IAAE,MAAM,EAAE,SAAS,CAAA;CAAE,GACrB;IAAE,MAAM,EAAE,SAAS,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,CAAC;AAEjE;;;;GAIG;AACH,MAAM,WAAW,qBAAqB;IACrC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IAEzB,QAAQ,CAAC,MAAM,EAAE,cAAc,GAAG,OAAO,CAAC,sBAAsB,CAAC,CAAC;IAClE,IAAI,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAAC;IACtD,aAAa,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IACnC,MAAM,CAAC,CAAC,EACP,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,CAAC,OAAO,EAAE,cAAc,KAAK,gBAAgB,CAAC,CAAC,CAAC,GACxD,OAAO,CAAC,oBAAoB,CAAC,CAAC,CAAC,CAAC,CAAC;CACpC;AAmBD,8DAA8D;AAC9D,wBAAgB,wBAAwB,CAAC,CAAC,EAAE,kBAAkB,EAAE,CAAC,EAAE,kBAAkB,GAAG,OAAO,CAE9F;AAMD,MAAM,MAAM,yBAAyB,GAAG;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,MAAM,EAAE,cAAc,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,CAAC;AA+FjH;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,OAAO,GAAG,yBAAyB,CAyD7E;AAMD,MAAM,WAAW,yBAAyB;IACzC,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,sBAAsB,CAAC,EAAE,oBAAoB,CAAC;IAC9C,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,GAAG,CAAC,EAAE,MAAM,CAAC;CACb;AAED,6EAA6E;AAC7E,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,yBAAyB,GAAG,cAAc,CAkBrF","sourcesContent":["/**\n * Executor Registry — domain-facing persistence port (2.10.0).\n *\n * Pure types + validation only. No filesystem, process, provider, or scheduler\n * machinery. A future scheduler/worker daemon consumes this same port without\n * needing the local file implementation.\n *\n * Authority model:\n *   - The registry records what executors exist and what runtimes are alive.\n *   - Capability/resource fields are advertisements and observations, never\n *     authorization grants and never assignments.\n */\n\nimport {\n\ttype ExecutorCapabilities,\n\ttype ExecutorDefinition,\n\ttype ExecutorRecord,\n\ttype ExecutorRuntime,\n\tisSafeExecutorId,\n} from \"./executor-registry-types.js\";\n\nexport const EXECUTOR_REGISTRY_SCHEMA_VERSION = 1 as const;\n\n// =============================================================================\n// Store port result types\n// =============================================================================\n\nexport type ExecutorRegisterResult =\n\t| { status: \"created\" }\n\t| { status: \"idempotent\"; record: ExecutorRecord }\n\t| { status: \"conflict\"; error: string };\n\nexport type ExecutorLoadResult =\n\t| { status: \"ok\"; record: ExecutorRecord }\n\t| { status: \"missing\" }\n\t| { status: \"corrupt\"; executorId: string; diagnostic: string };\n\n/** A store-level atomic read-modify-write mutation (sync callback). */\nexport type ExecutorMutation<T> = { kind: \"write\"; next: ExecutorRecord; value: T } | { kind: \"noop\"; value: T };\n\nexport type ExecutorMutateResult<T> =\n\t| { status: \"ok\"; value: T }\n\t| { status: \"missing\" }\n\t| { status: \"corrupt\"; executorId: string; diagnostic: string };\n\n/**\n * Canonical executor registry persistence port. Implementations must be\n * crash-conscious (atomic record replacement, schema validation on load,\n * deterministic corrupt handling) and must never fabricate a healthy executor.\n */\nexport interface ExecutorRegistryStore {\n\treadonly storeId: string;\n\n\tregister(record: ExecutorRecord): Promise<ExecutorRegisterResult>;\n\tload(executorId: string): Promise<ExecutorLoadResult>;\n\tlistExecutors(): Promise<string[]>;\n\tmutate<T>(\n\t\texecutorId: string,\n\t\tmutation: (current: ExecutorRecord) => ExecutorMutation<T>,\n\t): Promise<ExecutorMutateResult<T>>;\n}\n\n// =============================================================================\n// Definition equality\n// =============================================================================\n\nfunction stableStringify(value: unknown): string {\n\tif (value === undefined) return \"null\";\n\tif (value === null || typeof value !== \"object\") return JSON.stringify(value);\n\tif (Array.isArray(value)) {\n\t\treturn `[${value.map((item) => stableStringify(item)).join(\",\")}]`;\n\t}\n\tconst record = value as Record<string, unknown>;\n\tconst keys = Object.keys(record)\n\t\t.filter((key) => record[key] !== undefined)\n\t\t.sort();\n\treturn `{${keys.map((key) => `${JSON.stringify(key)}:${stableStringify(record[key])}`).join(\",\")}}`;\n}\n\n/** Structural equality of two stable executor definitions. */\nexport function executorDefinitionsEqual(a: ExecutorDefinition, b: ExecutorDefinition): boolean {\n\treturn stableStringify(a) === stableStringify(b);\n}\n\n// =============================================================================\n// Validation\n// =============================================================================\n\nexport type ExecutorRecordParseResult = { ok: true; record: ExecutorRecord } | { ok: false; diagnostic: string };\n\nfunction invalid(why: string): ExecutorRecordParseResult {\n\treturn { ok: false, diagnostic: why };\n}\n\nfunction isSafeInteger(value: unknown): value is number {\n\treturn typeof value === \"number\" && Number.isSafeInteger(value);\n}\n\nfunction isStringArray(value: unknown): value is string[] {\n\treturn Array.isArray(value) && value.every((entry) => typeof entry === \"string\");\n}\n\nfunction validateGpuDevice(value: unknown): string | undefined {\n\tif (typeof value !== \"object\" || value === null || Array.isArray(value)) return \"gpu device must be an object\";\n\tconst d = value as Record<string, unknown>;\n\tfor (const key of [\"id\", \"name\", \"vendor\"] as const) {\n\t\tif (d[key] !== undefined && typeof d[key] !== \"string\") return `gpu device ${key} must be a string`;\n\t}\n\tfor (const key of [\"memoryTotalBytes\", \"memoryFreeBytes\"] as const) {\n\t\tif (d[key] !== undefined && !isSafeInteger(d[key])) return `gpu device ${key} must be a safe integer`;\n\t}\n\treturn undefined;\n}\n\nfunction validateResources(value: unknown): string | undefined {\n\tif (typeof value !== \"object\" || value === null || Array.isArray(value)) return \"resources must be an object\";\n\tconst r = value as Record<string, unknown>;\n\tif (!isSafeInteger(r.observedAtMs)) return \"resources.observedAtMs must be a safe integer\";\n\tif (r.cpuLogicalCount !== undefined && !isSafeInteger(r.cpuLogicalCount))\n\t\treturn \"resources.cpuLogicalCount must be a safe integer\";\n\tif (r.memoryTotalBytes !== undefined && !isSafeInteger(r.memoryTotalBytes))\n\t\treturn \"resources.memoryTotalBytes must be a safe integer\";\n\tif (r.memoryFreeBytes !== undefined && !isSafeInteger(r.memoryFreeBytes))\n\t\treturn \"resources.memoryFreeBytes must be a safe integer\";\n\tif (r.gpu !== undefined) {\n\t\tif (typeof r.gpu !== \"object\" || r.gpu === null || Array.isArray(r.gpu)) return \"resources.gpu must be an object\";\n\t\tconst gpu = r.gpu as Record<string, unknown>;\n\t\tif (gpu.status !== \"unavailable\" && gpu.status !== \"available\") return \"resources.gpu.status is invalid\";\n\t\tif (!Array.isArray(gpu.devices)) return \"resources.gpu.devices must be an array\";\n\t\tfor (const device of gpu.devices) {\n\t\t\tconst err = validateGpuDevice(device);\n\t\t\tif (err) return err;\n\t\t}\n\t}\n\treturn undefined;\n}\n\nfunction validateCapabilities(value: unknown): string | undefined {\n\tif (typeof value !== \"object\" || value === null || Array.isArray(value)) return \"capabilities must be an object\";\n\tconst c = value as Record<string, unknown>;\n\tif (c.platform !== undefined) {\n\t\tif (typeof c.platform !== \"object\" || c.platform === null || Array.isArray(c.platform))\n\t\t\treturn \"capabilities.platform must be an object\";\n\t\tconst platform = c.platform as Record<string, unknown>;\n\t\tif (platform.os !== undefined && typeof platform.os !== \"string\")\n\t\t\treturn \"capabilities.platform.os must be a string\";\n\t\tif (platform.arch !== undefined && typeof platform.arch !== \"string\")\n\t\t\treturn \"capabilities.platform.arch must be a string\";\n\t}\n\tfor (const key of [\"execution\", \"providers\", \"models\", \"tools\", \"specialized\", \"extra\"] as const) {\n\t\tif (c[key] !== undefined && !isStringArray(c[key])) return `capabilities.${key} must be a string array`;\n\t}\n\treturn undefined;\n}\n\nfunction validateRuntime(value: unknown): string | undefined {\n\tif (typeof value !== \"object\" || value === null || Array.isArray(value)) return \"runtime must be an object\";\n\tconst r = value as Record<string, unknown>;\n\tif (typeof r.runtimeInstanceId !== \"string\" || r.runtimeInstanceId.length === 0)\n\t\treturn \"runtime.runtimeInstanceId must be a non-empty string\";\n\tif (typeof r.ownerId !== \"string\" || r.ownerId.length === 0) return \"runtime.ownerId must be a non-empty string\";\n\tfor (const key of [\"hostname\", \"platform\", \"arch\", \"jensenVersion\"] as const) {\n\t\tif (r[key] !== undefined && typeof r[key] !== \"string\") return `runtime.${key} must be a string`;\n\t}\n\tif (r.pid !== undefined && !isSafeInteger(r.pid)) return \"runtime.pid must be a safe integer\";\n\tif (r.processStartedAtMs !== undefined && !isSafeInteger(r.processStartedAtMs))\n\t\treturn \"runtime.processStartedAtMs must be a safe integer\";\n\tfor (const key of [\"startedAtMs\", \"lastHeartbeatAtMs\", \"expiresAtMs\"] as const) {\n\t\tif (!isSafeInteger(r[key])) return `runtime.${key} must be a safe integer`;\n\t}\n\tif ((r.lastHeartbeatAtMs as number) < (r.startedAtMs as number))\n\t\treturn \"runtime.lastHeartbeatAtMs must be >= startedAtMs\";\n\tif ((r.expiresAtMs as number) < (r.lastHeartbeatAtMs as number))\n\t\treturn \"runtime.expiresAtMs must be >= lastHeartbeatAtMs\";\n\tconst capabilitiesError = validateCapabilities(r.advertisedCapabilities);\n\tif (capabilitiesError) return `runtime.advertisedCapabilities: ${capabilitiesError}`;\n\tif (r.resources !== undefined) {\n\t\tconst resourcesError = validateResources(r.resources);\n\t\tif (resourcesError) return `runtime.resources: ${resourcesError}`;\n\t}\n\treturn undefined;\n}\n\n/**\n * Validate an untrusted persisted value into an ExecutorRecord. Corruption is\n * surfaced structurally (`ok: false`), never silently dropped or fabricated.\n */\nexport function parseExecutorRecord(value: unknown): ExecutorRecordParseResult {\n\tif (typeof value !== \"object\" || value === null || Array.isArray(value)) return invalid(\"record must be an object\");\n\tconst doc = value as Record<string, unknown>;\n\n\tif (doc.schemaVersion !== EXECUTOR_REGISTRY_SCHEMA_VERSION) {\n\t\treturn invalid(`unsupported schemaVersion: ${String(doc.schemaVersion)}`);\n\t}\n\tif (typeof doc.executorId !== \"string\" || !isSafeExecutorId(doc.executorId)) {\n\t\treturn invalid(\"executorId is missing or unsafe\");\n\t}\n\tconst executorId = doc.executorId;\n\n\tif (doc.displayName !== undefined && typeof doc.displayName !== \"string\")\n\t\treturn invalid(\"displayName must be a string\");\n\tif (!isSafeInteger(doc.createdAtMs) || !isSafeInteger(doc.updatedAtMs))\n\t\treturn invalid(\"timestamps must be safe integers\");\n\tif (typeof doc.retired !== \"boolean\") return invalid(\"retired must be a boolean\");\n\tif (!isStringArray(doc.labels)) return invalid(\"labels must be a string array\");\n\tif (!isSafeInteger(doc.runtimeEpoch) || (doc.runtimeEpoch as number) < 0)\n\t\treturn invalid(\"runtimeEpoch must be a non-negative integer\");\n\tif (!isSafeInteger(doc.revision) || (doc.revision as number) < 0)\n\t\treturn invalid(\"revision must be a non-negative integer\");\n\n\tconst capabilitiesError = validateCapabilities(doc.configuredCapabilities);\n\tif (capabilitiesError) return invalid(`configuredCapabilities: ${capabilitiesError}`);\n\n\tif (\n\t\tdoc.remoteTargetId !== undefined &&\n\t\t(typeof doc.remoteTargetId !== \"string\" || !isSafeExecutorId(doc.remoteTargetId))\n\t) {\n\t\treturn invalid(\"remoteTargetId must be a safe string identifier\");\n\t}\n\n\tlet runtime: ExecutorRuntime | undefined;\n\tif (doc.runtime !== undefined) {\n\t\tconst runtimeError = validateRuntime(doc.runtime);\n\t\tif (runtimeError) return invalid(runtimeError);\n\t\truntime = doc.runtime as ExecutorRuntime;\n\t}\n\n\treturn {\n\t\tok: true,\n\t\trecord: {\n\t\t\tschemaVersion: EXECUTOR_REGISTRY_SCHEMA_VERSION,\n\t\t\texecutorId,\n\t\t\tdisplayName: doc.displayName as string | undefined,\n\t\t\tcreatedAtMs: doc.createdAtMs as number,\n\t\t\tupdatedAtMs: doc.updatedAtMs as number,\n\t\t\tretired: doc.retired as boolean,\n\t\t\tlabels: (doc.labels as string[]).map((entry) => entry),\n\t\t\tconfiguredCapabilities: doc.configuredCapabilities as ExecutorCapabilities,\n\t\t\tremoteTargetId: doc.remoteTargetId as string | undefined,\n\t\t\truntimeEpoch: doc.runtimeEpoch as number,\n\t\t\truntime,\n\t\t\trevision: doc.revision as number,\n\t\t},\n\t};\n}\n\n// =============================================================================\n// Record construction helper\n// =============================================================================\n\nexport interface CreateExecutorRecordInput {\n\texecutorId: string;\n\tdisplayName?: string;\n\tlabels?: string[];\n\tconfiguredCapabilities?: ExecutorCapabilities;\n\tremoteTargetId?: string;\n\tnow?: number;\n}\n\n/** Build an initial registered record (no runtime, epoch 0, not retired). */\nexport function createExecutorRecord(input: CreateExecutorRecordInput): ExecutorRecord {\n\tif (!isSafeExecutorId(input.executorId)) {\n\t\tthrow new Error(`Unsafe executor id: ${input.executorId}`);\n\t}\n\tconst now = input.now ?? Date.now();\n\treturn {\n\t\tschemaVersion: EXECUTOR_REGISTRY_SCHEMA_VERSION,\n\t\texecutorId: input.executorId,\n\t\tdisplayName: input.displayName,\n\t\tcreatedAtMs: now,\n\t\tupdatedAtMs: now,\n\t\tretired: false,\n\t\tlabels: input.labels ? [...new Set(input.labels)].sort() : [],\n\t\tconfiguredCapabilities: input.configuredCapabilities ?? {},\n\t\tremoteTargetId: input.remoteTargetId,\n\t\truntimeEpoch: 0,\n\t\trevision: 1,\n\t};\n}\n"]}