@elevasis/sdk 1.27.1 → 1.28.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -5857,8 +5857,8 @@ async function processMemory(memoryManager, response, logger, iteration) {
5857
5857
  continue;
5858
5858
  }
5859
5859
  const startTime = Date.now();
5860
- const stringValue = typeof content === "string" ? content : JSON.stringify(content);
5861
- memoryManager.set(key, stringValue);
5860
+ const stringValue2 = typeof content === "string" ? content : JSON.stringify(content);
5861
+ memoryManager.set(key, stringValue2);
5862
5862
  const endTime = Date.now();
5863
5863
  logger.action("memory-set", `Set: ${key}`, iteration, startTime, endTime, endTime - startTime);
5864
5864
  }
@@ -6966,6 +6966,19 @@ DisplayMetadataSchema.extend({
6966
6966
  function childSystemsOf(system) {
6967
6967
  return system.systems ?? system.subsystems ?? {};
6968
6968
  }
6969
+ function getSystem(model, path) {
6970
+ const flatMatch = model.systems[path];
6971
+ if (flatMatch !== void 0) return flatMatch;
6972
+ const segments = path.split(".");
6973
+ let current = model.systems;
6974
+ let node;
6975
+ for (const seg of segments) {
6976
+ node = current[seg];
6977
+ if (node === void 0) return void 0;
6978
+ current = childSystemsOf(node);
6979
+ }
6980
+ return node;
6981
+ }
6969
6982
  function listAllSystems(model) {
6970
6983
  const results = [];
6971
6984
  function walk(map2, prefix) {
@@ -8536,6 +8549,70 @@ function compileOrganizationOntology(model) {
8536
8549
  addLegacyActionProjections(ontology, diagnostics, sourcesById, model.actions ?? {}, model.entities ?? {});
8537
8550
  return { ontology: sortResolvedOntologyIndex(ontology), diagnostics };
8538
8551
  }
8552
+
8553
+ // ../core/src/organization-model/migration-helpers.ts
8554
+ function catalogRecords(model) {
8555
+ return Object.values(compileOrganizationOntology(model).ontology.catalogTypes);
8556
+ }
8557
+ function systemScope(id, fallback) {
8558
+ return parseOntologyId(id).scope || fallback || "";
8559
+ }
8560
+ function entriesOf(catalog) {
8561
+ return Object.entries(catalog.entries ?? {}).map(([id, value]) => [
8562
+ id,
8563
+ value && typeof value === "object" && !Array.isArray(value) ? value : {}
8564
+ ]);
8565
+ }
8566
+ function stringValue(value) {
8567
+ return typeof value === "string" ? value : void 0;
8568
+ }
8569
+ function stringArray(value) {
8570
+ return Array.isArray(value) ? value.filter((item) => typeof item === "string") : [];
8571
+ }
8572
+ function numberValue(value, fallback = 0) {
8573
+ return typeof value === "number" ? value : fallback;
8574
+ }
8575
+ function appliesToLocalId(catalog) {
8576
+ const appliesTo = catalog.appliesTo;
8577
+ if (appliesTo === void 0) return void 0;
8578
+ return parseOntologyId(appliesTo).localId;
8579
+ }
8580
+ function appliesToEntityKind(catalog) {
8581
+ const id = appliesToLocalId(catalog);
8582
+ if (id === "company" || id === "contact" || id === "project" || id === "milestone" || id === "task") return id;
8583
+ if (id === "deal") return void 0;
8584
+ return void 0;
8585
+ }
8586
+ function getLeadGenStageCatalog(model) {
8587
+ const results = {};
8588
+ for (const catalog of catalogRecords(model).filter(
8589
+ (record) => record.kind === "stage" && (record.ownerSystemId ?? systemScope(record.id)) === "sales.lead-gen"
8590
+ )) {
8591
+ const catalogEntity = appliesToEntityKind(catalog);
8592
+ if (catalogEntity !== "company" && catalogEntity !== "contact") continue;
8593
+ for (const [entryId, entry] of entriesOf(catalog)) {
8594
+ const entity = entry.entity === "contact" ? "contact" : entry.entity === "company" ? "company" : catalogEntity;
8595
+ const additionalEntities = stringArray(entry.additionalEntities).filter(
8596
+ (item) => item === "company" || item === "contact"
8597
+ );
8598
+ const recordEntity = entry.recordEntity === "company" || entry.recordEntity === "contact" ? entry.recordEntity : void 0;
8599
+ const recordStageKey = stringValue(entry.recordStageKey);
8600
+ results[entryId] = {
8601
+ key: entryId,
8602
+ label: stringValue(entry.label) ?? entryId,
8603
+ description: stringValue(entry.description) ?? "",
8604
+ order: numberValue(entry.order),
8605
+ entity,
8606
+ ...additionalEntities.length > 0 ? { additionalEntities } : {},
8607
+ ...recordEntity ? { recordEntity } : {},
8608
+ ...recordStageKey ? { recordStageKey } : {}
8609
+ };
8610
+ }
8611
+ }
8612
+ return Object.fromEntries(
8613
+ Object.entries(results).sort(([, a3], [, b2]) => a3.order - b2.order || a3.key.localeCompare(b2.key))
8614
+ );
8615
+ }
8539
8616
  z.object({
8540
8617
  success: z.boolean(),
8541
8618
  tool: z.string(),
@@ -8548,6 +8625,455 @@ z.object({
8548
8625
  credential: z.string().describe("Credential name registered for this integration")
8549
8626
  });
8550
8627
 
8628
+ // ../core/src/business/acquisition/ontology-validation.ts
8629
+ var LEAD_GEN_API_INTERFACE = {
8630
+ interfaceKey: "api",
8631
+ readinessProfile: "sales.lead-gen.api"
8632
+ };
8633
+ var CRM_API_INTERFACE = {
8634
+ systemPath: "sales.crm",
8635
+ interfaceKey: "api",
8636
+ readinessProfile: "sales.crm.api"
8637
+ };
8638
+ var LEAD_GEN_CRM_HANDOFF_INTERFACE = {
8639
+ systemPath: "sales.lead-gen",
8640
+ interfaceKey: "crm-handoff",
8641
+ readinessProfile: "sales.lead-gen.crm-handoff"
8642
+ };
8643
+ CRM_API_INTERFACE.readinessProfile;
8644
+ var LEAD_GEN_LIST_OBJECT_ONTOLOGY_ID = formatOntologyId({
8645
+ scope: "sales.lead-gen",
8646
+ kind: "object",
8647
+ localId: "list"
8648
+ });
8649
+ var LEAD_GEN_COMPANY_OBJECT_ONTOLOGY_ID = formatOntologyId({
8650
+ scope: "sales.lead-gen",
8651
+ kind: "object",
8652
+ localId: "company"
8653
+ });
8654
+ var LEAD_GEN_CONTACT_OBJECT_ONTOLOGY_ID = formatOntologyId({
8655
+ scope: "sales.lead-gen",
8656
+ kind: "object",
8657
+ localId: "contact"
8658
+ });
8659
+ var LEAD_GEN_BUILD_TEMPLATE_CATALOG_ONTOLOGY_ID = formatOntologyId({
8660
+ scope: "sales.lead-gen",
8661
+ kind: "catalog",
8662
+ localId: "build-template"
8663
+ });
8664
+ var LEAD_GEN_COMPANY_STAGE_CATALOG_ONTOLOGY_ID = formatOntologyId({
8665
+ scope: "sales.lead-gen",
8666
+ kind: "catalog",
8667
+ localId: "company-stage"
8668
+ });
8669
+ var LEAD_GEN_CONTACT_STAGE_CATALOG_ONTOLOGY_ID = formatOntologyId({
8670
+ scope: "sales.lead-gen",
8671
+ kind: "catalog",
8672
+ localId: "contact-stage"
8673
+ });
8674
+ var CRM_PIPELINE_CATALOG_ONTOLOGY_ID = formatOntologyId({
8675
+ scope: "sales.crm",
8676
+ kind: "catalog",
8677
+ localId: "crm.pipeline"
8678
+ });
8679
+ var LEAD_GEN_STAGE_CATALOG_ONTOLOGY_ID = formatOntologyId({
8680
+ scope: "sales.lead-gen",
8681
+ kind: "catalog",
8682
+ localId: "lead-gen.stage-catalog"
8683
+ });
8684
+ function createLeadGenStageCatalog(model) {
8685
+ return {
8686
+ id: LEAD_GEN_STAGE_CATALOG_ONTOLOGY_ID,
8687
+ label: "Lead Gen Processing Stages",
8688
+ ownerSystemId: "sales.lead-gen",
8689
+ kind: "processing-stage-catalog",
8690
+ entries: Object.fromEntries(
8691
+ Object.entries(getLeadGenStageCatalog(model)).map(([key, entry]) => [
8692
+ key,
8693
+ {
8694
+ ...entry
8695
+ }
8696
+ ])
8697
+ ),
8698
+ legacyCatalogKey: "LEAD_GEN_STAGE_CATALOG"
8699
+ };
8700
+ }
8701
+ function isPlainRecord(value) {
8702
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value);
8703
+ }
8704
+ function addReadinessIssue(issues, family, code, message, details = {}) {
8705
+ issues.push({
8706
+ family,
8707
+ code,
8708
+ message,
8709
+ ...details
8710
+ });
8711
+ }
8712
+ function formatInterfaceIdentity(systemPath, interfaceKey) {
8713
+ return `${systemPath}/${interfaceKey}`;
8714
+ }
8715
+ function profileForInterface(systemPath, interfaceKey, readinessProfile) {
8716
+ return readinessProfile ?? `${systemPath}.${interfaceKey}`;
8717
+ }
8718
+ function readinessMarkerPath(context) {
8719
+ return context.interfaceKey === "api" ? `systems.${context.systemPath}.apiInterface` : `systems.${context.systemPath}.derivedCrmHandoffReadiness`;
8720
+ }
8721
+ function getActiveScopedResources(model, resourceIds, issues, context) {
8722
+ const resources = [];
8723
+ for (const [index2, resourceId] of resourceIds.entries()) {
8724
+ const resource = model.resources?.[resourceId];
8725
+ const path = `${readinessMarkerPath(context)}.resourceIds.${index2}`;
8726
+ if (resource === void 0) {
8727
+ addReadinessIssue(
8728
+ issues,
8729
+ "SYSTEM_INTERFACE_NOT_READY",
8730
+ "missing-resource",
8731
+ `System Interface "${formatInterfaceIdentity(context.systemPath, context.interfaceKey)}" scopes missing resource "${resourceId}".`,
8732
+ { path, ref: resourceId }
8733
+ );
8734
+ continue;
8735
+ }
8736
+ if (resource.systemPath !== context.systemPath) {
8737
+ addReadinessIssue(
8738
+ issues,
8739
+ "SYSTEM_INTERFACE_INVALID",
8740
+ "resource-system-mismatch",
8741
+ `System Interface "${formatInterfaceIdentity(context.systemPath, context.interfaceKey)}" scopes resource "${resourceId}" from system "${resource.systemPath}".`,
8742
+ { path, ref: resourceId }
8743
+ );
8744
+ continue;
8745
+ }
8746
+ if (resource.status !== "active") {
8747
+ addReadinessIssue(
8748
+ issues,
8749
+ "SYSTEM_INTERFACE_NOT_READY",
8750
+ "inactive-resource",
8751
+ `System Interface "${formatInterfaceIdentity(context.systemPath, context.interfaceKey)}" scopes inactive resource "${resourceId}".`,
8752
+ { path, ref: resourceId }
8753
+ );
8754
+ continue;
8755
+ }
8756
+ resources.push(resource);
8757
+ }
8758
+ return resources;
8759
+ }
8760
+ function resourceBindingIds(resources, key) {
8761
+ return new Set(resources.flatMap((resource) => resource.ontology?.[key] ?? []));
8762
+ }
8763
+ function requireScopedBinding(issues, boundIds, bindingKey, ontologyId, context) {
8764
+ if (boundIds.has(ontologyId)) return;
8765
+ addReadinessIssue(
8766
+ issues,
8767
+ "SYSTEM_INTERFACE_NOT_READY",
8768
+ "missing-resource-binding",
8769
+ `System Interface "${formatInterfaceIdentity(context.systemPath, context.interfaceKey)}" has no active scoped resource with ontology.${bindingKey} binding "${ontologyId}".`,
8770
+ { path: `${readinessMarkerPath(context)}.resourceIds`, ref: ontologyId }
8771
+ );
8772
+ }
8773
+ function ontologyOwnerMatches(ontologyId, expectedSystemPath, catalog) {
8774
+ if (catalog?.ownerSystemId !== void 0) return catalog.ownerSystemId === expectedSystemPath;
8775
+ return parseOntologyId(ontologyId).scope === expectedSystemPath;
8776
+ }
8777
+ function requireObjectReadiness(issues, index2, objectId, context) {
8778
+ const object2 = index2.ontology.objectTypes[objectId];
8779
+ if (object2 === void 0) {
8780
+ addReadinessIssue(
8781
+ issues,
8782
+ "SYSTEM_INTERFACE_NOT_READY",
8783
+ "missing-object",
8784
+ `System Interface "${formatInterfaceIdentity(context.systemPath, context.interfaceKey)}" is missing required object type "${objectId}".`,
8785
+ { ref: objectId }
8786
+ );
8787
+ return;
8788
+ }
8789
+ const ownerSystemId = object2.ownerSystemId ?? parseOntologyId(objectId).scope;
8790
+ if (ownerSystemId !== context.systemPath) {
8791
+ addReadinessIssue(
8792
+ issues,
8793
+ "SYSTEM_INTERFACE_INVALID",
8794
+ "foreign-object",
8795
+ `System Interface "${formatInterfaceIdentity(context.systemPath, context.interfaceKey)}" requires object "${objectId}" owned by "${ownerSystemId}".`,
8796
+ { ref: objectId }
8797
+ );
8798
+ }
8799
+ }
8800
+ function requireCatalogReadiness(issues, index2, catalogId, context) {
8801
+ const catalog = index2.ontology.catalogTypes[catalogId];
8802
+ if (catalog === void 0) {
8803
+ addReadinessIssue(
8804
+ issues,
8805
+ "SYSTEM_INTERFACE_NOT_READY",
8806
+ "missing-catalog",
8807
+ `System Interface "${formatInterfaceIdentity(context.systemPath, context.interfaceKey)}" is missing required catalog "${catalogId}".`,
8808
+ { ref: catalogId }
8809
+ );
8810
+ return void 0;
8811
+ }
8812
+ if (context.allowForeignOwner !== true && !ontologyOwnerMatches(catalogId, context.systemPath, catalog)) {
8813
+ addReadinessIssue(
8814
+ issues,
8815
+ "SYSTEM_INTERFACE_INVALID",
8816
+ "foreign-catalog",
8817
+ `System Interface "${formatInterfaceIdentity(context.systemPath, context.interfaceKey)}" requires catalog "${catalogId}" owned by "${catalog.ownerSystemId ?? parseOntologyId(catalogId).scope}".`,
8818
+ { ref: catalogId }
8819
+ );
8820
+ }
8821
+ if (Object.keys(getCatalogEntries(catalog)).length === 0) {
8822
+ addReadinessIssue(
8823
+ issues,
8824
+ "SYSTEM_INTERFACE_NOT_READY",
8825
+ "empty-catalog",
8826
+ `System Interface "${formatInterfaceIdentity(context.systemPath, context.interfaceKey)}" requires catalog entries for "${catalogId}".`,
8827
+ { ref: catalogId }
8828
+ );
8829
+ }
8830
+ return catalog;
8831
+ }
8832
+ function requireLeadGenInterfaceReadiness(issues, index2, resources, context) {
8833
+ const reads = resourceBindingIds(resources, "reads");
8834
+ const catalogs = resourceBindingIds(resources, "usesCatalogs");
8835
+ for (const objectId of [
8836
+ LEAD_GEN_LIST_OBJECT_ONTOLOGY_ID,
8837
+ LEAD_GEN_COMPANY_OBJECT_ONTOLOGY_ID,
8838
+ LEAD_GEN_CONTACT_OBJECT_ONTOLOGY_ID
8839
+ ]) {
8840
+ requireObjectReadiness(issues, index2, objectId, context);
8841
+ requireScopedBinding(issues, reads, "reads", objectId, context);
8842
+ }
8843
+ for (const catalogId of [
8844
+ LEAD_GEN_BUILD_TEMPLATE_CATALOG_ONTOLOGY_ID,
8845
+ LEAD_GEN_COMPANY_STAGE_CATALOG_ONTOLOGY_ID,
8846
+ LEAD_GEN_CONTACT_STAGE_CATALOG_ONTOLOGY_ID
8847
+ ]) {
8848
+ requireCatalogReadiness(issues, index2, catalogId, context);
8849
+ requireScopedBinding(issues, catalogs, "usesCatalogs", catalogId, context);
8850
+ }
8851
+ const templateStepCatalog = findLeadGenTemplateStepCatalog(index2);
8852
+ if (templateStepCatalog === void 0) {
8853
+ addReadinessIssue(
8854
+ issues,
8855
+ "SYSTEM_INTERFACE_NOT_READY",
8856
+ "missing-template-step-catalog",
8857
+ `System Interface "${formatInterfaceIdentity(context.systemPath, context.interfaceKey)}" is missing a lead-gen template-step catalog.`
8858
+ );
8859
+ } else {
8860
+ requireCatalogReadiness(issues, index2, templateStepCatalog.id, context);
8861
+ requireScopedBinding(issues, catalogs, "usesCatalogs", templateStepCatalog.id, context);
8862
+ }
8863
+ const leadGenStageCatalog = requireCatalogReadiness(issues, index2, LEAD_GEN_STAGE_CATALOG_ONTOLOGY_ID, context);
8864
+ return leadGenStageCatalog;
8865
+ }
8866
+ function requireCrmInterfaceReadiness(issues, index2, resources, context) {
8867
+ const catalogs = resourceBindingIds(resources, "usesCatalogs");
8868
+ const crmPipelineCatalog = requireCatalogReadiness(issues, index2, CRM_PIPELINE_CATALOG_ONTOLOGY_ID, context);
8869
+ requireScopedBinding(issues, catalogs, "usesCatalogs", CRM_PIPELINE_CATALOG_ONTOLOGY_ID, context);
8870
+ return crmPipelineCatalog;
8871
+ }
8872
+ function findSystemInterfaceGrant(model, consumer, provider) {
8873
+ return Object.values(model.topology?.relationships ?? {}).find((relationship) => {
8874
+ const grant = relationship.metadata?.["systemInterfaceGrant"];
8875
+ if (!isPlainRecord(grant) || !isPlainRecord(grant.consumer) || !isPlainRecord(grant.provider)) return false;
8876
+ return grant.consumer.systemPath === consumer.systemPath && grant.consumer.interfaceKey === consumer.interfaceKey && grant.provider.systemPath === provider.systemPath && grant.provider.interfaceKey === provider.interfaceKey;
8877
+ });
8878
+ }
8879
+ function requireHandoffBridgeReadiness(issues, model, context) {
8880
+ const crmResult = computeInterfaceReadiness(model, CRM_API_INTERFACE);
8881
+ if (!crmResult.ready) {
8882
+ for (const issue of crmResult.issues) {
8883
+ addReadinessIssue(
8884
+ issues,
8885
+ "SYSTEM_BRIDGE_NOT_READY",
8886
+ issue.code,
8887
+ `Provider interface ${formatInterfaceIdentity(CRM_API_INTERFACE.systemPath, CRM_API_INTERFACE.interfaceKey)} is not ready: ${issue.message}`,
8888
+ { path: issue.path, ref: issue.ref }
8889
+ );
8890
+ }
8891
+ }
8892
+ const bridgeGrant = findSystemInterfaceGrant(model, context, CRM_API_INTERFACE);
8893
+ if (bridgeGrant === void 0) {
8894
+ addReadinessIssue(
8895
+ issues,
8896
+ "SYSTEM_BRIDGE_NOT_READY",
8897
+ "missing-topology-grant",
8898
+ `System Interface "${formatInterfaceIdentity(context.systemPath, context.interfaceKey)}" requires a scoped topology grant to "${formatInterfaceIdentity(CRM_API_INTERFACE.systemPath, CRM_API_INTERFACE.interfaceKey)}".`
8899
+ );
8900
+ }
8901
+ return bridgeGrant;
8902
+ }
8903
+ function getLeadGenCrmHandoffResourceIds(model) {
8904
+ return Object.values(model.resources ?? {}).filter(
8905
+ (resource) => resource.systemPath === LEAD_GEN_CRM_HANDOFF_INTERFACE.systemPath && resource.ontology?.usesCatalogs?.includes(CRM_PIPELINE_CATALOG_ONTOLOGY_ID) === true
8906
+ ).map((resource) => resource.id);
8907
+ }
8908
+ function getSystemInterfaceReadinessMarker(model, request) {
8909
+ const system = getSystem(model, request.systemPath);
8910
+ if (system === void 0) return void 0;
8911
+ if (request.interfaceKey === LEAD_GEN_API_INTERFACE.interfaceKey) {
8912
+ return system.apiInterface;
8913
+ }
8914
+ if (request.systemPath === LEAD_GEN_CRM_HANDOFF_INTERFACE.systemPath && request.interfaceKey === LEAD_GEN_CRM_HANDOFF_INTERFACE.interfaceKey) {
8915
+ return {
8916
+ lifecycle: "active",
8917
+ readinessProfile: LEAD_GEN_CRM_HANDOFF_INTERFACE.readinessProfile,
8918
+ resourceIds: getLeadGenCrmHandoffResourceIds(model)
8919
+ };
8920
+ }
8921
+ return void 0;
8922
+ }
8923
+ function mergeLeadGenDerivedCatalogs(model) {
8924
+ const baseCatalogTypes = model.ontology?.catalogTypes ?? {};
8925
+ const derivedCatalogTypes = {};
8926
+ if (baseCatalogTypes[LEAD_GEN_STAGE_CATALOG_ONTOLOGY_ID] === void 0) {
8927
+ derivedCatalogTypes[LEAD_GEN_STAGE_CATALOG_ONTOLOGY_ID] = createLeadGenStageCatalog(model);
8928
+ }
8929
+ if (Object.keys(derivedCatalogTypes).length === 0) return model;
8930
+ return {
8931
+ ...model,
8932
+ ontology: {
8933
+ ...model.ontology ?? {},
8934
+ catalogTypes: {
8935
+ ...baseCatalogTypes,
8936
+ ...derivedCatalogTypes
8937
+ }
8938
+ }
8939
+ };
8940
+ }
8941
+ function compileBusinessOntology(model, contractId) {
8942
+ const compilation = compileOrganizationOntology(mergeLeadGenDerivedCatalogs(model));
8943
+ if (compilation.diagnostics.length > 0) {
8944
+ const summary = compilation.diagnostics.map((diagnostic) => diagnostic.message).join("; ");
8945
+ throw new Error(`${contractId} ontology validation index failed to compile: ${summary}`);
8946
+ }
8947
+ return {
8948
+ ontology: compilation.ontology,
8949
+ actionTypesByLegacyId: indexActionTypesByLegacyId(compilation.ontology.actionTypes)
8950
+ };
8951
+ }
8952
+ function tryCompileBusinessOntology(model, readinessProfile, issues) {
8953
+ try {
8954
+ return compileBusinessOntology(model, readinessProfile);
8955
+ } catch (error) {
8956
+ addReadinessIssue(
8957
+ issues,
8958
+ "SYSTEM_INTERFACE_INVALID",
8959
+ "ontology-compile-failed",
8960
+ error instanceof Error ? error.message : String(error)
8961
+ );
8962
+ return void 0;
8963
+ }
8964
+ }
8965
+ function computeInterfaceReadiness(model, request) {
8966
+ const issues = [];
8967
+ const system = getSystem(model, request.systemPath);
8968
+ const systemInterface = getSystemInterfaceReadinessMarker(model, request);
8969
+ const readinessProfile = systemInterface === void 0 ? void 0 : profileForInterface(request.systemPath, request.interfaceKey, systemInterface.readinessProfile);
8970
+ const scopedResourceIds = systemInterface?.resourceIds ?? [];
8971
+ if (system === void 0) {
8972
+ addReadinessIssue(
8973
+ issues,
8974
+ "SYSTEM_INTERFACE_MISSING",
8975
+ "missing-system",
8976
+ `System "${request.systemPath}" is missing.`,
8977
+ { ref: request.systemPath }
8978
+ );
8979
+ return { ready: false, systemPath: request.systemPath, interfaceKey: request.interfaceKey, scopedResourceIds, issues };
8980
+ }
8981
+ if (systemInterface === void 0) {
8982
+ addReadinessIssue(
8983
+ issues,
8984
+ "SYSTEM_INTERFACE_MISSING",
8985
+ "missing-interface",
8986
+ `System "${request.systemPath}" does not declare interface "${request.interfaceKey}".`,
8987
+ { path: readinessMarkerPath(request) }
8988
+ );
8989
+ return { ready: false, systemPath: request.systemPath, interfaceKey: request.interfaceKey, scopedResourceIds, issues };
8990
+ }
8991
+ if (systemInterface.lifecycle !== "active") {
8992
+ addReadinessIssue(
8993
+ issues,
8994
+ "SYSTEM_INTERFACE_DISABLED",
8995
+ "inactive-interface",
8996
+ `System Interface "${formatInterfaceIdentity(request.systemPath, request.interfaceKey)}" lifecycle is "${systemInterface.lifecycle}".`,
8997
+ { path: `${readinessMarkerPath(request)}.lifecycle` }
8998
+ );
8999
+ }
9000
+ const supportedProfiles = [
9001
+ LEAD_GEN_API_INTERFACE.readinessProfile,
9002
+ CRM_API_INTERFACE.readinessProfile,
9003
+ LEAD_GEN_CRM_HANDOFF_INTERFACE.readinessProfile
9004
+ ];
9005
+ const supportedProfile = readinessProfile !== void 0 && supportedProfiles.some((profile) => profile === readinessProfile);
9006
+ if (!supportedProfile) {
9007
+ addReadinessIssue(
9008
+ issues,
9009
+ "SYSTEM_INTERFACE_INVALID",
9010
+ "unknown-readiness-profile",
9011
+ `System Interface "${formatInterfaceIdentity(request.systemPath, request.interfaceKey)}" references unknown readiness profile "${readinessProfile}".`,
9012
+ { path: `${readinessMarkerPath(request)}.readinessProfile`, ref: readinessProfile }
9013
+ );
9014
+ return {
9015
+ ready: false,
9016
+ systemPath: request.systemPath,
9017
+ interfaceKey: request.interfaceKey,
9018
+ readinessProfile,
9019
+ scopedResourceIds,
9020
+ issues
9021
+ };
9022
+ }
9023
+ if (scopedResourceIds.length === 0) {
9024
+ addReadinessIssue(
9025
+ issues,
9026
+ "SYSTEM_INTERFACE_NOT_READY",
9027
+ "missing-scoped-resources",
9028
+ `System Interface "${formatInterfaceIdentity(request.systemPath, request.interfaceKey)}" must scope at least one active resource.`,
9029
+ { path: `${readinessMarkerPath(request)}.resourceIds` }
9030
+ );
9031
+ }
9032
+ const checkedReadinessProfile = readinessProfile;
9033
+ if (checkedReadinessProfile === void 0) {
9034
+ throw new Error("Supported readiness profile unexpectedly resolved to undefined");
9035
+ }
9036
+ const resources = getActiveScopedResources(model, scopedResourceIds, issues, request);
9037
+ const index2 = tryCompileBusinessOntology(model, checkedReadinessProfile, issues);
9038
+ if (index2 !== void 0) {
9039
+ if (checkedReadinessProfile === LEAD_GEN_API_INTERFACE.readinessProfile) {
9040
+ requireLeadGenInterfaceReadiness(issues, index2, resources, request);
9041
+ } else if (checkedReadinessProfile === CRM_API_INTERFACE.readinessProfile) {
9042
+ requireCrmInterfaceReadiness(issues, index2, resources, request);
9043
+ } else if (checkedReadinessProfile === LEAD_GEN_CRM_HANDOFF_INTERFACE.readinessProfile) {
9044
+ requireLeadGenInterfaceReadiness(issues, index2, resources, request);
9045
+ requireCrmInterfaceReadiness(issues, index2, resources, { ...request, allowForeignOwner: true });
9046
+ requireHandoffBridgeReadiness(issues, model, request);
9047
+ }
9048
+ }
9049
+ return {
9050
+ ready: issues.length === 0,
9051
+ systemPath: request.systemPath,
9052
+ interfaceKey: request.interfaceKey,
9053
+ readinessProfile,
9054
+ scopedResourceIds,
9055
+ issues
9056
+ };
9057
+ }
9058
+ function findLeadGenTemplateStepCatalog(index2) {
9059
+ return Object.values(index2.ontology.catalogTypes).find(
9060
+ (catalog) => catalog.ownerSystemId === "sales.lead-gen" && catalog.kind === "template-step" && catalog.appliesTo === LEAD_GEN_LIST_OBJECT_ONTOLOGY_ID
9061
+ );
9062
+ }
9063
+ function indexActionTypesByLegacyId(actionTypes) {
9064
+ const byLegacyId = {};
9065
+ for (const actionType of Object.values(actionTypes)) {
9066
+ const legacyActionId = actionType["legacyActionId"];
9067
+ if (typeof legacyActionId === "string") {
9068
+ byLegacyId[legacyActionId] = actionType;
9069
+ }
9070
+ }
9071
+ return byLegacyId;
9072
+ }
9073
+ function getCatalogEntries(catalog) {
9074
+ return isPlainRecord(catalog.entries) ? catalog.entries : {};
9075
+ }
9076
+
8551
9077
  // ../core/src/platform/registry/validation.ts
8552
9078
  var RegistryValidationError = class extends Error {
8553
9079
  constructor(orgName, resourceId, field, message) {
@@ -8638,7 +9164,7 @@ function ontologyIndexForKind(index2, kind) {
8638
9164
  function sameJson(left, right) {
8639
9165
  return JSON.stringify(left ?? null) === JSON.stringify(right ?? null);
8640
9166
  }
8641
- function addOntologyBindingIssues(issues, orgName, resource, ontologyIndex) {
9167
+ function addOntologyBindingIssues(issues, orgName, resource, ontologyIndex, organizationModel) {
8642
9168
  const binding = resource.ontology;
8643
9169
  if (binding === void 0) return;
8644
9170
  const hasOperationalOntologyBinding = binding.primaryAction !== void 0 || (binding.reads?.length ?? 0) > 0 || (binding.writes?.length ?? 0) > 0 || (binding.usesCatalogs?.length ?? 0) > 0 || (binding.emits?.length ?? 0) > 0;
@@ -8681,6 +9207,45 @@ function addOntologyBindingIssues(issues, orgName, resource, ontologyIndex) {
8681
9207
  validateRefs("writes", "object", binding.writes);
8682
9208
  validateRefs("usesCatalogs", "catalog", binding.usesCatalogs);
8683
9209
  validateRefs("emits", "event", binding.emits);
9210
+ addOntologyTopologyGrantIssues(issues, orgName, resource, organizationModel);
9211
+ }
9212
+ function addOntologyTopologyGrantIssues(issues, orgName, resource, organizationModel) {
9213
+ const binding = resource.ontology;
9214
+ if (binding === void 0) return;
9215
+ const refs = [
9216
+ ...binding.actions ?? [],
9217
+ ...binding.primaryAction !== void 0 ? [binding.primaryAction] : [],
9218
+ ...binding.reads ?? [],
9219
+ ...binding.writes ?? [],
9220
+ ...binding.usesCatalogs ?? [],
9221
+ ...binding.emits ?? []
9222
+ ];
9223
+ for (const ontologyId of new Set(refs)) {
9224
+ const parsed = parseOntologyId(ontologyId);
9225
+ if (parsed.isGlobal || parsed.scope === resource.systemPath) continue;
9226
+ if (hasScopedTopologyGrant(organizationModel, resource, parsed.scope, ontologyId)) continue;
9227
+ const missingGrant = `systemInterfaceGrant(${resource.systemPath} -> ${parsed.scope}, resourceIds: ["${resource.id}"], ontologyIds: ["${ontologyId}"])`;
9228
+ addGovernanceIssue(
9229
+ issues,
9230
+ "ontology-topology-grant-missing",
9231
+ orgName,
9232
+ resource.id,
9233
+ `[${orgName}] Resource '${resource.id}' in system '${resource.systemPath}' references ontology '${ontologyId}' from system '${parsed.scope}' without scoped topology grant '${missingGrant}'.`
9234
+ );
9235
+ }
9236
+ }
9237
+ function hasScopedTopologyGrant(organizationModel, resource, targetSystemPath, ontologyId) {
9238
+ return Object.values(organizationModel.topology?.relationships ?? {}).some((relationship) => {
9239
+ if (relationship.kind !== "uses") return false;
9240
+ const grant = relationship.metadata?.["systemInterfaceGrant"];
9241
+ if (!isSystemInterfaceGrantRecord(grant)) return false;
9242
+ return grant.consumer.systemPath === resource.systemPath && grant.provider.systemPath === targetSystemPath && grant.resourceIds.includes(resource.id) && grant.ontologyIds.includes(ontologyId);
9243
+ });
9244
+ }
9245
+ function isSystemInterfaceGrantRecord(value) {
9246
+ if (typeof value !== "object" || value === null) return false;
9247
+ const grant = value;
9248
+ return typeof grant.consumer?.systemPath === "string" && typeof grant.consumer.interfaceKey === "string" && typeof grant.provider?.systemPath === "string" && typeof grant.provider.interfaceKey === "string" && Array.isArray(grant.resourceIds) && grant.resourceIds.every((id) => typeof id === "string") && Array.isArray(grant.ontologyIds) && grant.ontologyIds.every((id) => typeof id === "string");
8684
9249
  }
8685
9250
  function addTopologyIssues(issues, orgName, deployment, organizationModel, systemsById, omResourcesById, ontologyIndex) {
8686
9251
  const relationships = organizationModel.topology?.relationships;
@@ -8795,7 +9360,7 @@ function validateResourceGovernance(orgName, deployment, organizationModel = dep
8795
9360
  `[${orgName}] Resource '${resource.id}' ontology descriptor mismatch between code and OM.`
8796
9361
  );
8797
9362
  }
8798
- addOntologyBindingIssues(issues, orgName, resource, ontologyIndex);
9363
+ addOntologyBindingIssues(issues, orgName, resource, ontologyIndex, organizationModel);
8799
9364
  }
8800
9365
  for (const runtimeResource of runtimeResources) {
8801
9366
  const omResource = omResourcesById.get(runtimeResource.resourceId);
@@ -8845,6 +9410,41 @@ function validateResourceGovernance(orgName, deployment, organizationModel = dep
8845
9410
  issues
8846
9411
  };
8847
9412
  }
9413
+ function addSystemInterfaceIssue(issues, orgName, systemPath, interfaceKey, issue) {
9414
+ issues.push({
9415
+ type: issue.family,
9416
+ orgName,
9417
+ systemPath,
9418
+ interfaceKey,
9419
+ code: issue.code,
9420
+ path: issue.path,
9421
+ ref: issue.ref,
9422
+ message: `[${orgName}] ${issue.family}:${issue.code}: ${issue.message}`
9423
+ });
9424
+ }
9425
+ function validateDeclaredSystemInterfaceReadiness(orgName, organizationModel) {
9426
+ const issues = [];
9427
+ if (organizationModel === void 0) return { valid: true, issues };
9428
+ const model = organizationModel;
9429
+ for (const { path, system } of listAllSystems(model)) {
9430
+ if (system.apiInterface === void 0) continue;
9431
+ const interfaceKey = "api";
9432
+ const result = computeInterfaceReadiness(model, { systemPath: path, interfaceKey });
9433
+ for (const issue of result.issues) {
9434
+ addSystemInterfaceIssue(issues, orgName, path, interfaceKey, issue);
9435
+ }
9436
+ }
9437
+ if (issues.length > 0) {
9438
+ const first = issues[0];
9439
+ throw new RegistryValidationError(
9440
+ first.orgName,
9441
+ `${first.systemPath}/${first.interfaceKey}`,
9442
+ first.path ?? "organizationModel.systems.apiInterface",
9443
+ first.message
9444
+ );
9445
+ }
9446
+ return { valid: true, issues };
9447
+ }
8848
9448
  function validateDeploymentSpec(orgName, resources) {
8849
9449
  const seenIds = /* @__PURE__ */ new Set();
8850
9450
  resources.workflows?.forEach((workflow) => {
@@ -8882,6 +9482,7 @@ function validateDeploymentSpec(orgName, resources) {
8882
9482
  }
8883
9483
  });
8884
9484
  validateResourceGovernance(orgName, resources);
9485
+ validateDeclaredSystemInterfaceReadiness(orgName, resources.organizationModel);
8885
9486
  }
8886
9487
  function validateResourceModelConfig(orgName, resourceId, modelConfig) {
8887
9488
  try {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@elevasis/sdk",
3
- "version": "1.27.1",
3
+ "version": "1.28.1",
4
4
  "description": "SDK for building Elevasis organization resources",
5
5
  "type": "module",
6
6
  "bin": {
@@ -58,7 +58,7 @@
58
58
  "tsup": "^8.0.0",
59
59
  "typescript": "5.9.2",
60
60
  "zod": "^4.1.0",
61
- "@repo/core": "0.34.2",
61
+ "@repo/core": "0.35.1",
62
62
  "@repo/typescript-config": "0.0.0",
63
63
  "@repo/eslint-config": "0.0.0"
64
64
  },