@elevasis/sdk 1.18.0 → 1.20.0

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.
Files changed (58) hide show
  1. package/dist/cli.cjs +1915 -70
  2. package/dist/index.d.ts +825 -16
  3. package/dist/index.js +714 -63
  4. package/dist/node/index.d.ts +1 -0
  5. package/dist/node/index.js +213 -2
  6. package/dist/test-utils/index.d.ts +479 -14
  7. package/dist/test-utils/index.js +660 -54
  8. package/dist/worker/index.js +516 -54
  9. package/package.json +4 -4
  10. package/reference/_navigation.md +2 -1
  11. package/reference/_reference-manifest.json +14 -0
  12. package/reference/claude-config/registries/graph-skills.json +4 -0
  13. package/reference/claude-config/rules/agent-start-here.md +5 -5
  14. package/reference/claude-config/rules/deployment.md +4 -3
  15. package/reference/claude-config/rules/frontend.md +2 -2
  16. package/reference/claude-config/rules/operations.md +17 -13
  17. package/reference/claude-config/rules/organization-model.md +7 -5
  18. package/reference/claude-config/rules/organization-os.md +13 -11
  19. package/reference/claude-config/rules/ui.md +3 -3
  20. package/reference/claude-config/rules/vibe.md +4 -4
  21. package/reference/claude-config/skills/explore/SKILL.md +4 -4
  22. package/reference/claude-config/skills/knowledge/SKILL.md +17 -16
  23. package/reference/claude-config/skills/knowledge/operations/codify-level-a.md +7 -7
  24. package/reference/claude-config/skills/knowledge/operations/codify-level-b.md +13 -13
  25. package/reference/claude-config/skills/knowledge/operations/customers.md +1 -1
  26. package/reference/claude-config/skills/knowledge/operations/goals.md +1 -1
  27. package/reference/claude-config/skills/knowledge/operations/identity.md +1 -1
  28. package/reference/claude-config/skills/knowledge/operations/offerings.md +1 -1
  29. package/reference/claude-config/skills/knowledge/operations/roles.md +1 -1
  30. package/reference/claude-config/skills/knowledge/operations/techStack.md +19 -91
  31. package/reference/claude-config/skills/project/SKILL.md +73 -13
  32. package/reference/claude-config/skills/save/SKILL.md +5 -5
  33. package/reference/claude-config/skills/tutorial/technical.md +11 -14
  34. package/reference/claude-config/sync-notes/2026-05-06-crm-spine.md +60 -0
  35. package/reference/claude-config/sync-notes/2026-05-07-sdk-changes-release-train.md +34 -0
  36. package/reference/claude-config/sync-notes/2026-05-08-resource-governance-scaffold-guidance.md +38 -0
  37. package/reference/claude-config/sync-notes/2026-05-09-clients-domain.md +32 -0
  38. package/reference/claude-config/sync-notes/2026-05-09-command-system.md +33 -0
  39. package/reference/claude-config/sync-notes/2026-05-09-resource-governance-and-misc.md +69 -0
  40. package/reference/examples/organization-model.ts +17 -5
  41. package/reference/framework/index.mdx +1 -1
  42. package/reference/framework/project-structure.mdx +10 -8
  43. package/reference/packages/core/src/business/README.md +2 -2
  44. package/reference/packages/core/src/organization-model/README.md +10 -3
  45. package/reference/resources/index.mdx +27 -17
  46. package/reference/scaffold/core/organization-model.mdx +33 -14
  47. package/reference/scaffold/operations/workflow-recipes.md +35 -29
  48. package/reference/scaffold/recipes/add-a-feature.md +18 -3
  49. package/reference/scaffold/recipes/add-a-resource.md +50 -10
  50. package/reference/scaffold/recipes/customize-crm-actions.md +12 -6
  51. package/reference/scaffold/recipes/customize-organization-model.md +18 -3
  52. package/reference/scaffold/recipes/extend-crm.md +17 -19
  53. package/reference/scaffold/recipes/extend-lead-gen.md +31 -31
  54. package/reference/scaffold/recipes/index.md +1 -1
  55. package/reference/scaffold/reference/contracts.md +512 -307
  56. package/reference/scaffold/reference/feature-registry.md +1 -1
  57. package/reference/scaffold/reference/glossary.md +8 -3
  58. package/reference/scaffold/ui/recipes.md +21 -6
@@ -6529,6 +6529,7 @@ var ORGANIZATION_MODEL_ICON_TOKENS = [
6529
6529
  "knowledge.reference",
6530
6530
  "feature.dashboard",
6531
6531
  "feature.calendar",
6532
+ "feature.business",
6532
6533
  "feature.sales",
6533
6534
  "feature.crm",
6534
6535
  "feature.finance",
@@ -6650,6 +6651,63 @@ z.object({
6650
6651
  defaultPipelineId: ModelIdSchema,
6651
6652
  pipelines: z.array(SalesPipelineSchema).min(1)
6652
6653
  });
6654
+ var CRM_DISCOVERY_REPLIED_STATE = {
6655
+ stateKey: "discovery_replied",
6656
+ label: "Discovery Replied"
6657
+ };
6658
+ var CRM_DISCOVERY_LINK_SENT_STATE = {
6659
+ stateKey: "discovery_link_sent",
6660
+ label: "Discovery Link Sent"
6661
+ };
6662
+ var CRM_DISCOVERY_NUDGING_STATE = {
6663
+ stateKey: "discovery_nudging",
6664
+ label: "Discovery Nudging"
6665
+ };
6666
+ var CRM_DISCOVERY_BOOKING_CANCELLED_STATE = {
6667
+ stateKey: "discovery_booking_cancelled",
6668
+ label: "Discovery Booking Cancelled"
6669
+ };
6670
+ var CRM_REPLY_SENT_STATE = {
6671
+ stateKey: "reply_sent",
6672
+ label: "Reply Sent"
6673
+ };
6674
+ var CRM_FOLLOWUP_1_SENT_STATE = {
6675
+ stateKey: "followup_1_sent",
6676
+ label: "Follow-up 1 Sent"
6677
+ };
6678
+ var CRM_FOLLOWUP_2_SENT_STATE = {
6679
+ stateKey: "followup_2_sent",
6680
+ label: "Follow-up 2 Sent"
6681
+ };
6682
+ var CRM_FOLLOWUP_3_SENT_STATE = {
6683
+ stateKey: "followup_3_sent",
6684
+ label: "Follow-up 3 Sent"
6685
+ };
6686
+ var CRM_PIPELINE_DEFINITION = {
6687
+ pipelineKey: "crm",
6688
+ stages: [
6689
+ {
6690
+ stageKey: "interested",
6691
+ label: "Interested",
6692
+ color: "blue",
6693
+ states: [
6694
+ CRM_DISCOVERY_REPLIED_STATE,
6695
+ CRM_DISCOVERY_LINK_SENT_STATE,
6696
+ CRM_DISCOVERY_NUDGING_STATE,
6697
+ CRM_DISCOVERY_BOOKING_CANCELLED_STATE,
6698
+ CRM_REPLY_SENT_STATE,
6699
+ CRM_FOLLOWUP_1_SENT_STATE,
6700
+ CRM_FOLLOWUP_2_SENT_STATE,
6701
+ CRM_FOLLOWUP_3_SENT_STATE
6702
+ ]
6703
+ },
6704
+ { stageKey: "proposal", label: "Proposal", color: "yellow", states: [] },
6705
+ { stageKey: "closing", label: "Closing", color: "orange", states: [] },
6706
+ { stageKey: "closed_won", label: "Closed Won", color: "green", states: [] },
6707
+ { stageKey: "closed_lost", label: "Closed Lost", color: "red", states: [] },
6708
+ { stageKey: "nurturing", label: "Nurturing", color: "grape", states: [] }
6709
+ ]
6710
+ };
6653
6711
  var LEAD_GEN_STAGE_CATALOG = {
6654
6712
  // Prospecting — company population
6655
6713
  scraped: {
@@ -6666,6 +6724,13 @@ var LEAD_GEN_STAGE_CATALOG = {
6666
6724
  order: 2,
6667
6725
  entity: "company"
6668
6726
  },
6727
+ crawled: {
6728
+ key: "crawled",
6729
+ label: "Websites crawled",
6730
+ description: "Company websites have been crawled (e.g. via Apify) and raw page content stored for downstream LLM analysis.",
6731
+ order: 2.5,
6732
+ entity: "company"
6733
+ },
6669
6734
  extracted: {
6670
6735
  key: "extracted",
6671
6736
  label: "Websites analyzed",
@@ -6685,7 +6750,9 @@ var LEAD_GEN_STAGE_CATALOG = {
6685
6750
  label: "Decision-makers found",
6686
6751
  description: "Decision-maker contacts discovered and attached to a qualified company.",
6687
6752
  order: 6,
6688
- entity: "company"
6753
+ entity: "company",
6754
+ recordEntity: "contact",
6755
+ recordStageKey: "discovered"
6689
6756
  },
6690
6757
  // Prospecting — contact discovery
6691
6758
  discovered: {
@@ -6723,7 +6790,8 @@ var LEAD_GEN_STAGE_CATALOG = {
6723
6790
  label: "Reviewed and exported",
6724
6791
  description: "Approved records have been reviewed and exported for handoff.",
6725
6792
  order: 10,
6726
- entity: "contact"
6793
+ entity: "company",
6794
+ additionalEntities: ["contact"]
6727
6795
  },
6728
6796
  interested: {
6729
6797
  key: "interested",
@@ -6737,18 +6805,47 @@ var LEAD_GEN_STAGE_CATALOG = {
6737
6805
  // ../core/src/organization-model/domains/prospecting.ts
6738
6806
  var ProspectingLifecycleStageSchema = DisplayMetadataSchema.extend({
6739
6807
  id: ModelIdSchema,
6740
- order: z.number().int().min(0)
6808
+ order: z.number().min(0)
6809
+ });
6810
+ var RecordColumnConfigSchema = z.object({
6811
+ key: ModelIdSchema,
6812
+ label: z.string().trim().min(1).max(120),
6813
+ path: z.string().trim().min(1).max(500),
6814
+ width: z.union([z.number().positive(), z.string().trim().min(1).max(100)]).optional(),
6815
+ renderType: z.enum(["text", "badge", "datetime", "count", "json"]).optional(),
6816
+ badgeColor: z.string().trim().min(1).max(40).optional()
6817
+ });
6818
+ var RecordColumnsConfigSchema = z.object({
6819
+ company: z.array(RecordColumnConfigSchema).optional(),
6820
+ contact: z.array(RecordColumnConfigSchema).optional()
6821
+ }).refine((columns) => Boolean(columns.company?.length || columns.contact?.length), {
6822
+ message: "recordColumns must include at least one entity column set"
6823
+ });
6824
+ var CredentialRequirementSchema = z.object({
6825
+ key: ModelIdSchema,
6826
+ provider: ModelIdSchema,
6827
+ credentialType: z.enum(["api-key", "api-key-secret", "oauth", "webhook-secret"]),
6828
+ label: z.string().trim().min(1).max(120),
6829
+ required: z.boolean(),
6830
+ selectionMode: z.enum(["single", "multiple"]).optional(),
6831
+ inputPath: z.string().trim().min(1).max(500),
6832
+ verifyOnRun: z.boolean().optional()
6741
6833
  });
6742
6834
  var ProspectingBuildTemplateStepSchema = DisplayMetadataSchema.extend({
6743
6835
  id: ModelIdSchema,
6744
6836
  primaryEntity: z.enum(["company", "contact"]),
6745
6837
  outputs: z.array(z.enum(["company", "contact", "export"])).min(1),
6746
6838
  stageKey: ModelIdSchema,
6839
+ recordEntity: z.enum(["company", "contact"]).optional(),
6840
+ recordsStageKey: ModelIdSchema.optional(),
6841
+ recordSourceStageKey: ModelIdSchema.optional(),
6747
6842
  dependsOn: z.array(ModelIdSchema).optional(),
6748
6843
  dependencyMode: z.literal("per-record-eligibility"),
6749
6844
  capabilityKey: ModelIdSchema,
6750
6845
  defaultBatchSize: z.number().int().positive(),
6751
- maxBatchSize: z.number().int().positive()
6846
+ maxBatchSize: z.number().int().positive(),
6847
+ recordColumns: RecordColumnsConfigSchema.optional(),
6848
+ credentialRequirements: z.array(CredentialRequirementSchema).optional()
6752
6849
  }).refine((step) => step.defaultBatchSize <= step.maxBatchSize, {
6753
6850
  message: "defaultBatchSize must be less than or equal to maxBatchSize",
6754
6851
  path: ["defaultBatchSize"]
@@ -6757,20 +6854,148 @@ var ProspectingBuildTemplateSchema = DisplayMetadataSchema.extend({
6757
6854
  id: ModelIdSchema,
6758
6855
  steps: z.array(ProspectingBuildTemplateStepSchema).min(1)
6759
6856
  });
6760
- var CAPABILITY_REGISTRY = {
6761
- "lead-gen.company.source": "lgn-import-workflow",
6762
- "lead-gen.company.apollo-import": "lgn-01c-apollo-import-workflow",
6763
- "lead-gen.contact.discover": "lgn-04-email-discovery-workflow",
6764
- "lead-gen.contact.verify-email": "lgn-05-email-verification-workflow",
6765
- "lead-gen.company.website-extract": "lgn-02-website-extract-workflow",
6766
- "lead-gen.company.qualify": "lgn-03-company-qualification-workflow",
6767
- "lead-gen.company.dtc-subscription-qualify": "lgn-03b-dtc-subscription-score-workflow",
6768
- "lead-gen.contact.apollo-decision-maker-enrich": "lgn-04b-apollo-decision-maker-enrich-workflow",
6769
- "lead-gen.contact.personalize": "ist-personalization-workflow",
6770
- "lead-gen.review.outreach-ready": "ist-upload-contacts-workflow",
6771
- "lead-gen.export.list": "lgn-06-export-list-workflow",
6772
- "lead-gen.company.cleanup": "lgn-company-cleanup-workflow"
6857
+ var DTC_RECORD_COLUMNS = {
6858
+ populated: {
6859
+ company: [
6860
+ { key: "name", label: "Company", path: "company.name" },
6861
+ { key: "domain", label: "Domain", path: "company.domain" },
6862
+ { key: "employee-count", label: "Employees", path: "company.numEmployees", renderType: "count" },
6863
+ { key: "apollo-industry", label: "Apollo industry", path: "company.category" },
6864
+ { key: "location", label: "Location", path: "company.locationState" }
6865
+ ]
6866
+ },
6867
+ crawled: {
6868
+ company: [
6869
+ { key: "name", label: "Company", path: "company.name" },
6870
+ { key: "domain", label: "Domain", path: "company.domain" },
6871
+ { key: "page-count", label: "Pages", path: "company.enrichmentData.websiteCrawl.pageCount", renderType: "count" },
6872
+ { key: "crawl-status", label: "Crawl status", path: "processingState.crawled.status", renderType: "badge" }
6873
+ ]
6874
+ },
6875
+ extracted: {
6876
+ company: [
6877
+ { key: "name", label: "Company", path: "company.name" },
6878
+ { key: "domain", label: "Domain", path: "company.domain" },
6879
+ { key: "description", label: "Description", path: "company.enrichmentData.websiteCrawl.companyDescription" },
6880
+ { key: "services", label: "Services", path: "company.enrichmentData.websiteCrawl.services", renderType: "json" },
6881
+ { key: "automation-gaps", label: "Automation gaps", path: "company.enrichmentData.websiteCrawl.automationGaps", renderType: "json" },
6882
+ { key: "contact-count", label: "Contacts", path: "company.enrichmentData.websiteCrawl.emailCount", renderType: "count" }
6883
+ ]
6884
+ },
6885
+ qualified: {
6886
+ company: [
6887
+ { key: "name", label: "Company", path: "company.name" },
6888
+ { key: "domain", label: "Domain", path: "company.domain" },
6889
+ { key: "score", label: "Score", path: "company.qualificationScore", renderType: "badge", badgeColor: "green" },
6890
+ { key: "signals", label: "Signals", path: "company.qualificationSignals", renderType: "json" },
6891
+ { key: "disqualified-reason", label: "Disqualified reason", path: "processingState.qualified.data.disqualifiedReason" }
6892
+ ]
6893
+ },
6894
+ decisionMakers: {
6895
+ contact: [
6896
+ { key: "name", label: "Name", path: "contact.name" },
6897
+ { key: "title", label: "Title", path: "contact.title" },
6898
+ { key: "email", label: "Email", path: "contact.email" },
6899
+ { key: "linkedin", label: "LinkedIn", path: "contact.linkedinUrl" },
6900
+ { key: "priority-score", label: "Priority", path: "contact.enrichmentData.apollo.priorityScore", renderType: "badge" }
6901
+ ]
6902
+ },
6903
+ uploaded: {
6904
+ company: [
6905
+ { key: "name", label: "Company", path: "company.name" },
6906
+ { key: "domain", label: "Domain", path: "company.domain" },
6907
+ { key: "contacts", label: "Contacts", path: "company.enrichmentData.approvedLeadListExport.contacts", renderType: "json" },
6908
+ { key: "score", label: "Score", path: "company.qualificationScore", renderType: "badge", badgeColor: "green" },
6909
+ { key: "approval", label: "Approval", path: "company.enrichmentData.approvedLeadListExport.approvalStatus", renderType: "badge" }
6910
+ ]
6911
+ }
6773
6912
  };
6913
+ z.object({
6914
+ id: ModelIdSchema,
6915
+ label: z.string(),
6916
+ description: z.string(),
6917
+ resourceId: ModelIdSchema
6918
+ });
6919
+ var CAPABILITY_REGISTRY = [
6920
+ {
6921
+ id: "lead-gen.company.source",
6922
+ label: "Source companies",
6923
+ description: "Import source companies from a list provider.",
6924
+ resourceId: "lgn-import-workflow"
6925
+ },
6926
+ {
6927
+ id: "lead-gen.company.apollo-import",
6928
+ label: "Import from Apollo",
6929
+ description: "Pull companies and seed contact data from an Apollo search or list.",
6930
+ resourceId: "lgn-01c-apollo-import-workflow"
6931
+ },
6932
+ {
6933
+ id: "lead-gen.contact.discover",
6934
+ label: "Discover contact emails",
6935
+ description: "Find email addresses for contacts at qualified companies.",
6936
+ resourceId: "lgn-04-email-discovery-workflow"
6937
+ },
6938
+ {
6939
+ id: "lead-gen.contact.verify-email",
6940
+ label: "Verify emails",
6941
+ description: "Check email deliverability before outreach.",
6942
+ resourceId: "lgn-05-email-verification-workflow"
6943
+ },
6944
+ {
6945
+ id: "lead-gen.company.apify-crawl",
6946
+ label: "Crawl websites",
6947
+ description: "Crawl company websites via Apify and store raw page markdown in enrichmentData.websiteCrawl.pages for downstream LLM analysis.",
6948
+ resourceId: "lgn-02a-apify-website-crawl-workflow"
6949
+ },
6950
+ {
6951
+ id: "lead-gen.company.website-extract",
6952
+ label: "Extract website signals",
6953
+ description: "Scrape and analyze company websites for qualification signals.",
6954
+ resourceId: "lgn-02-website-extract-workflow"
6955
+ },
6956
+ {
6957
+ id: "lead-gen.company.qualify",
6958
+ label: "Qualify companies",
6959
+ description: "Score and filter companies against the ICP rubric.",
6960
+ resourceId: "lgn-03-company-qualification-workflow"
6961
+ },
6962
+ {
6963
+ id: "lead-gen.company.dtc-subscription-qualify",
6964
+ label: "Qualify DTC subscription fit",
6965
+ description: "Classify subscription potential and consumable-product fit for DTC brands.",
6966
+ resourceId: "lgn-03b-dtc-subscription-score-workflow"
6967
+ },
6968
+ {
6969
+ id: "lead-gen.contact.apollo-decision-maker-enrich",
6970
+ label: "Enrich decision-makers",
6971
+ description: "Find and enrich qualified contacts at qualified companies via Apollo.",
6972
+ resourceId: "lgn-04b-apollo-decision-maker-enrich-workflow"
6973
+ },
6974
+ {
6975
+ id: "lead-gen.contact.personalize",
6976
+ label: "Personalize outreach",
6977
+ description: "Generate personalized opening lines for each contact.",
6978
+ resourceId: "ist-personalization-workflow"
6979
+ },
6980
+ {
6981
+ id: "lead-gen.review.outreach-ready",
6982
+ label: "Upload to outreach",
6983
+ description: "Upload approved contacts to the outreach sequence after QC review.",
6984
+ resourceId: "ist-upload-contacts-workflow"
6985
+ },
6986
+ {
6987
+ id: "lead-gen.export.list",
6988
+ label: "Export lead list",
6989
+ description: "Export approved leads as a downloadable lead list.",
6990
+ resourceId: "lgn-06-export-list-workflow"
6991
+ },
6992
+ {
6993
+ id: "lead-gen.company.cleanup",
6994
+ label: "Clean up companies",
6995
+ description: "Remove disqualified or duplicate companies from the list.",
6996
+ resourceId: "lgn-company-cleanup-workflow"
6997
+ }
6998
+ ];
6774
6999
  var PROSPECTING_STEPS = {
6775
7000
  localServices: {
6776
7001
  sourceCompanies: {
@@ -6868,7 +7093,45 @@ var PROSPECTING_STEPS = {
6868
7093
  dependencyMode: "per-record-eligibility",
6869
7094
  capabilityKey: "lead-gen.company.apollo-import",
6870
7095
  defaultBatchSize: 250,
6871
- maxBatchSize: 1e3
7096
+ maxBatchSize: 1e3,
7097
+ recordColumns: DTC_RECORD_COLUMNS.populated,
7098
+ credentialRequirements: [
7099
+ {
7100
+ key: "apollo",
7101
+ provider: "apollo",
7102
+ credentialType: "api-key-secret",
7103
+ label: "Apollo API key",
7104
+ required: true,
7105
+ selectionMode: "single",
7106
+ inputPath: "credential"
7107
+ }
7108
+ ]
7109
+ },
7110
+ apifyCrawl: {
7111
+ id: "apify-crawl",
7112
+ label: "Websites crawled",
7113
+ description: "Crawl company websites via Apify and store raw page markdown in enrichmentData.websiteCrawl.pages for downstream LLM analysis. Overwrites the synthetic seed Apollo Import wrote with real page content.",
7114
+ primaryEntity: "company",
7115
+ outputs: ["company"],
7116
+ stageKey: "crawled",
7117
+ dependsOn: ["import-apollo-search"],
7118
+ dependencyMode: "per-record-eligibility",
7119
+ capabilityKey: "lead-gen.company.apify-crawl",
7120
+ defaultBatchSize: 50,
7121
+ maxBatchSize: 100,
7122
+ recordColumns: DTC_RECORD_COLUMNS.crawled,
7123
+ credentialRequirements: [
7124
+ {
7125
+ key: "apify",
7126
+ provider: "apify",
7127
+ credentialType: "api-key-secret",
7128
+ label: "Apify API token",
7129
+ required: true,
7130
+ selectionMode: "single",
7131
+ inputPath: "credential",
7132
+ verifyOnRun: true
7133
+ }
7134
+ ]
6872
7135
  },
6873
7136
  analyzeWebsites: {
6874
7137
  id: "analyze-websites",
@@ -6877,11 +7140,12 @@ var PROSPECTING_STEPS = {
6877
7140
  primaryEntity: "company",
6878
7141
  outputs: ["company"],
6879
7142
  stageKey: "extracted",
6880
- dependsOn: ["import-apollo-search"],
7143
+ dependsOn: ["apify-crawl"],
6881
7144
  dependencyMode: "per-record-eligibility",
6882
7145
  capabilityKey: "lead-gen.company.website-extract",
6883
7146
  defaultBatchSize: 50,
6884
- maxBatchSize: 100
7147
+ maxBatchSize: 100,
7148
+ recordColumns: DTC_RECORD_COLUMNS.extracted
6885
7149
  },
6886
7150
  scoreDtcFit: {
6887
7151
  id: "score-dtc-fit",
@@ -6894,7 +7158,8 @@ var PROSPECTING_STEPS = {
6894
7158
  dependencyMode: "per-record-eligibility",
6895
7159
  capabilityKey: "lead-gen.company.dtc-subscription-qualify",
6896
7160
  defaultBatchSize: 100,
6897
- maxBatchSize: 250
7161
+ maxBatchSize: 250,
7162
+ recordColumns: DTC_RECORD_COLUMNS.qualified
6898
7163
  },
6899
7164
  enrichDecisionMakers: {
6900
7165
  id: "enrich-decision-makers",
@@ -6903,37 +7168,52 @@ var PROSPECTING_STEPS = {
6903
7168
  primaryEntity: "company",
6904
7169
  outputs: ["contact"],
6905
7170
  stageKey: "decision-makers-enriched",
7171
+ recordEntity: "contact",
6906
7172
  dependsOn: ["score-dtc-fit"],
6907
7173
  dependencyMode: "per-record-eligibility",
6908
7174
  capabilityKey: "lead-gen.contact.apollo-decision-maker-enrich",
6909
7175
  defaultBatchSize: 100,
6910
- maxBatchSize: 250
6911
- },
6912
- verifyEmails: {
6913
- id: "verify-emails",
6914
- label: "Emails verified",
6915
- description: "Verify deliverability before the QC and handoff step.",
6916
- primaryEntity: "contact",
6917
- outputs: ["contact"],
6918
- stageKey: "verified",
6919
- dependsOn: ["enrich-decision-makers"],
6920
- dependencyMode: "per-record-eligibility",
6921
- capabilityKey: "lead-gen.contact.verify-email",
6922
- defaultBatchSize: 250,
6923
- maxBatchSize: 500
7176
+ maxBatchSize: 250,
7177
+ recordColumns: DTC_RECORD_COLUMNS.decisionMakers,
7178
+ credentialRequirements: [
7179
+ {
7180
+ key: "apollo",
7181
+ provider: "apollo",
7182
+ credentialType: "api-key-secret",
7183
+ label: "Apollo API key",
7184
+ required: true,
7185
+ selectionMode: "single",
7186
+ inputPath: "credential"
7187
+ }
7188
+ ]
6924
7189
  },
6925
7190
  reviewAndExport: {
6926
7191
  id: "review-and-export",
6927
7192
  label: "Reviewed and exported",
6928
- description: "Operator QC approves or rejects leads, then approved records are exported as a lead list.",
7193
+ description: "Operator QC approves or rejects qualified companies, then approved records are exported as a lead list with unverified emails.",
6929
7194
  primaryEntity: "company",
6930
7195
  outputs: ["export"],
6931
7196
  stageKey: "uploaded",
6932
- dependsOn: ["verify-emails"],
7197
+ recordsStageKey: "uploaded",
7198
+ recordSourceStageKey: "qualified",
7199
+ dependsOn: ["enrich-decision-makers"],
6933
7200
  dependencyMode: "per-record-eligibility",
6934
7201
  capabilityKey: "lead-gen.export.list",
6935
7202
  defaultBatchSize: 100,
6936
- maxBatchSize: 250
7203
+ maxBatchSize: 250,
7204
+ recordColumns: DTC_RECORD_COLUMNS.uploaded,
7205
+ credentialRequirements: [
7206
+ {
7207
+ key: "clickup",
7208
+ provider: "clickup",
7209
+ credentialType: "api-key-secret",
7210
+ label: "ClickUp API token",
7211
+ required: true,
7212
+ selectionMode: "single",
7213
+ inputPath: "clickupCredential",
7214
+ verifyOnRun: true
7215
+ }
7216
+ ]
6937
7217
  }
6938
7218
  }
6939
7219
  };
@@ -6955,7 +7235,7 @@ function toProspectingLifecycleStage(stage) {
6955
7235
  };
6956
7236
  }
6957
7237
  function leadGenStagesForEntity(entity) {
6958
- return Object.values(LEAD_GEN_STAGE_CATALOG).filter((stage) => stage.entity === entity).sort((a3, b2) => a3.order - b2.order).map(toProspectingLifecycleStage);
7238
+ return Object.values(LEAD_GEN_STAGE_CATALOG).filter((stage) => stage.entity === entity || stage.additionalEntities?.includes(entity)).sort((a3, b2) => a3.order - b2.order).map(toProspectingLifecycleStage);
6959
7239
  }
6960
7240
  var DEFAULT_ORGANIZATION_MODEL_PROSPECTING = {
6961
7241
  companyStages: leadGenStagesForEntity("company"),
@@ -6981,10 +7261,10 @@ var DEFAULT_ORGANIZATION_MODEL_PROSPECTING = {
6981
7261
  description: "Prospecting pipeline for DTC subscription or subscription-ready brands where Apollo is the source and contact-enrichment layer, Elevasis handles company research and fit scoring, and approved leads export as an approved lead list.",
6982
7262
  steps: [
6983
7263
  PROSPECTING_STEPS.dtcApolloClickup.importApolloSearch,
7264
+ PROSPECTING_STEPS.dtcApolloClickup.apifyCrawl,
6984
7265
  PROSPECTING_STEPS.dtcApolloClickup.analyzeWebsites,
6985
7266
  PROSPECTING_STEPS.dtcApolloClickup.scoreDtcFit,
6986
7267
  PROSPECTING_STEPS.dtcApolloClickup.enrichDecisionMakers,
6987
- PROSPECTING_STEPS.dtcApolloClickup.verifyEmails,
6988
7268
  PROSPECTING_STEPS.dtcApolloClickup.reviewAndExport
6989
7269
  ]
6990
7270
  }
@@ -7006,9 +7286,13 @@ var ProcessingStageStatusSchema = z.enum(["success", "no_result", "skipped", "er
7006
7286
  var LeadGenStageKeySchema = z.string().refine((value) => Object.prototype.hasOwnProperty.call(LEAD_GEN_STAGE_CATALOG, value), {
7007
7287
  message: "processing state key must match LEAD_GEN_STAGE_CATALOG"
7008
7288
  });
7009
- var LeadGenCapabilityKeySchema = z.string().refine((value) => Object.prototype.hasOwnProperty.call(CAPABILITY_REGISTRY, value), {
7289
+ var LeadGenCapabilityKeySchema = z.string().refine((value) => CAPABILITY_REGISTRY.some((c) => c.id === value), {
7010
7290
  message: "capabilityKey must match CAPABILITY_REGISTRY"
7011
7291
  });
7292
+ var crmStageKeys = CRM_PIPELINE_DEFINITION.stages.map((stage) => stage.stageKey);
7293
+ var crmStateKeys = CRM_PIPELINE_DEFINITION.stages.flatMap((stage) => stage.states.map((state) => state.stateKey));
7294
+ var CrmStageKeySchema = z.enum(crmStageKeys);
7295
+ var CrmStateKeySchema = z.enum(crmStateKeys);
7012
7296
  var ProcessingStateEntrySchema = z.object({
7013
7297
  status: ProcessingStageStatusSchema,
7014
7298
  data: z.unknown().optional()
@@ -7016,7 +7300,7 @@ var ProcessingStateEntrySchema = z.object({
7016
7300
  var ProcessingStateSchema = z.record(LeadGenStageKeySchema, ProcessingStateEntrySchema);
7017
7301
  var CompanyProcessingStateSchema = ProcessingStateSchema;
7018
7302
  var ContactProcessingStateSchema = ProcessingStateSchema;
7019
- var DealStageSchema = z.enum(["interested", "proposal", "closing", "closed_won", "closed_lost", "nurturing"]);
7303
+ var DealStageSchema = CrmStageKeySchema;
7020
7304
  var AcqDealTaskKindSchema = z.enum(["call", "email", "meeting", "other"]);
7021
7305
  z.object({
7022
7306
  dealId: UuidSchema
@@ -7027,6 +7311,9 @@ z.object({
7027
7311
  });
7028
7312
  z.object({
7029
7313
  stage: DealStageSchema.optional(),
7314
+ list: UuidSchema.optional(),
7315
+ batch: z.string().trim().min(1).max(255).optional(),
7316
+ staleSince: z.string().datetime().optional(),
7030
7317
  search: z.string().optional(),
7031
7318
  limit: z.coerce.number().int().positive().default(50),
7032
7319
  offset: z.coerce.number().int().min(0).default(0)
@@ -7052,12 +7339,19 @@ z.object({
7052
7339
  z.object({
7053
7340
  pipelineKey: z.string().min(1),
7054
7341
  stageKey: z.string().min(1),
7055
- stateKey: z.string().nullable().optional(),
7342
+ stateKey: z.string().min(1).nullable().optional(),
7343
+ reason: z.string().optional(),
7344
+ expectedUpdatedAt: z.string().datetime().optional()
7345
+ }).strict();
7346
+ z.object({
7347
+ pipelineKey: z.literal(CRM_PIPELINE_DEFINITION.pipelineKey),
7348
+ stageKey: CrmStageKeySchema,
7349
+ stateKey: CrmStateKeySchema.nullable().optional(),
7056
7350
  reason: z.string().optional(),
7057
7351
  expectedUpdatedAt: z.string().datetime().optional()
7058
7352
  }).strict();
7059
7353
  z.object({
7060
- stateKey: z.string().min(1),
7354
+ stateKey: CrmStateKeySchema,
7061
7355
  reason: z.string().optional(),
7062
7356
  expectedUpdatedAt: z.string().datetime().optional()
7063
7357
  }).strict();
@@ -7102,6 +7396,7 @@ var DealListItemSchema = z.object({
7102
7396
  // acq_deals columns
7103
7397
  id: z.string(),
7104
7398
  organization_id: z.string(),
7399
+ client_id: z.string().nullable().optional(),
7105
7400
  contact_id: z.string().nullable(),
7106
7401
  contact_email: z.string(),
7107
7402
  pipeline_key: z.string(),
@@ -7182,8 +7477,31 @@ var ConversationMessageSchema = z.object({
7182
7477
  var DealConversationSchema = z.object({
7183
7478
  messages: z.array(ConversationMessageSchema)
7184
7479
  });
7480
+ var DealLineageListRefSchema = z.object({
7481
+ id: z.string(),
7482
+ name: z.string(),
7483
+ status: z.string()
7484
+ });
7485
+ var DealLineageProjectRefSchema = z.object({
7486
+ id: z.string(),
7487
+ name: z.string(),
7488
+ kind: z.string(),
7489
+ status: z.string(),
7490
+ updatedAt: z.string()
7491
+ });
7492
+ var DealLineageClientRefSchema = z.object({
7493
+ id: z.string(),
7494
+ name: z.string(),
7495
+ status: z.string()
7496
+ });
7497
+ var DealLineageSchema = z.object({
7498
+ list: DealLineageListRefSchema.nullable(),
7499
+ projects: z.array(DealLineageProjectRefSchema),
7500
+ client: DealLineageClientRefSchema.nullable()
7501
+ });
7185
7502
  DealListItemSchema.extend({
7186
- conversation: DealConversationSchema
7503
+ conversation: DealConversationSchema,
7504
+ lineage: DealLineageSchema.optional()
7187
7505
  });
7188
7506
  var DealNoteResponseSchema = z.object({
7189
7507
  id: z.string(),
@@ -7244,11 +7562,19 @@ var BuildPlanSnapshotStepSchema = z.object({
7244
7562
  primaryEntity: z.enum(["company", "contact"]),
7245
7563
  outputs: z.array(z.enum(["company", "contact", "export"])).min(1),
7246
7564
  stageKey: LeadGenStageKeySchema,
7565
+ recordEntity: z.enum(["company", "contact"]).optional(),
7566
+ recordsStageKey: LeadGenStageKeySchema.optional(),
7567
+ recordSourceStageKey: LeadGenStageKeySchema.optional(),
7247
7568
  dependsOn: z.array(z.string().trim().min(1).max(100)).optional(),
7248
7569
  dependencyMode: z.literal("per-record-eligibility"),
7249
7570
  capabilityKey: LeadGenCapabilityKeySchema,
7250
7571
  defaultBatchSize: z.number().int().positive(),
7251
- maxBatchSize: z.number().int().positive()
7572
+ maxBatchSize: z.number().int().positive(),
7573
+ recordColumns: z.object({
7574
+ company: z.array(RecordColumnConfigSchema).optional(),
7575
+ contact: z.array(RecordColumnConfigSchema).optional()
7576
+ }).optional(),
7577
+ credentialRequirements: z.array(CredentialRequirementSchema).optional()
7252
7578
  }).refine((step) => step.defaultBatchSize <= step.maxBatchSize, {
7253
7579
  message: "defaultBatchSize must be less than or equal to maxBatchSize",
7254
7580
  path: ["defaultBatchSize"]
@@ -7387,6 +7713,23 @@ var AcqListResponseSchema = z.object({
7387
7713
  });
7388
7714
  z.array(AcqListResponseSchema);
7389
7715
  z.array(ListTelemetrySchema);
7716
+ var QueryBooleanSchema = z.preprocess((value) => {
7717
+ if (value === "true" || value === "1" || value === true) return true;
7718
+ if (value === "false" || value === "0" || value === false) return false;
7719
+ return value;
7720
+ }, z.boolean());
7721
+ z.object({
7722
+ status: ListStatusSchema.optional(),
7723
+ batch: z.string().trim().min(1).max(255).optional(),
7724
+ vertical: z.string().trim().min(1).max(255).optional(),
7725
+ limit: z.coerce.number().int().min(1).max(500).optional(),
7726
+ offset: z.coerce.number().int().min(0).optional()
7727
+ }).strict();
7728
+ z.object({
7729
+ includeDeals: QueryBooleanSchema.default(true),
7730
+ includeProgress: QueryBooleanSchema.default(false),
7731
+ dealLimit: z.coerce.number().int().min(0).max(100).default(25)
7732
+ }).strict();
7390
7733
  var ListStageProgressSchema = z.object({
7391
7734
  total: z.number().int().min(0),
7392
7735
  attempted: z.number().int().min(0),
@@ -7397,12 +7740,48 @@ var ListStageProgressSchema = z.object({
7397
7740
  other: z.number().int().min(0),
7398
7741
  notAttempted: z.number().int().min(0)
7399
7742
  });
7400
- z.object({
7743
+ var ListProgressResponseSchema = z.object({
7401
7744
  totalMembers: z.number().int().min(0),
7402
7745
  totalCompanies: z.number().int().min(0),
7403
7746
  byCompanyStage: z.record(z.string(), ListStageProgressSchema),
7404
7747
  byContactStage: z.record(z.string(), ListStageProgressSchema)
7405
7748
  });
7749
+ var AcqListDealRefSchema = z.object({
7750
+ id: z.string(),
7751
+ contactEmail: z.string(),
7752
+ stageKey: z.string().nullable(),
7753
+ stateKey: z.string().nullable(),
7754
+ sourceType: z.string().nullable(),
7755
+ lastActivityAt: z.string()
7756
+ });
7757
+ var AcqListLineageSchema = z.object({
7758
+ deals: z.object({
7759
+ total: z.number().int().min(0),
7760
+ refs: z.array(AcqListDealRefSchema),
7761
+ truncated: z.boolean()
7762
+ })
7763
+ });
7764
+ AcqListResponseSchema.extend({
7765
+ lineage: AcqListLineageSchema.optional(),
7766
+ progress: ListProgressResponseSchema.optional()
7767
+ });
7768
+ var AcqListStatusListItemSchema = z.object({
7769
+ listId: z.string(),
7770
+ name: z.string(),
7771
+ status: ListStatusSchema,
7772
+ totalCompanies: z.number().int().min(0),
7773
+ totalContacts: z.number().int().min(0),
7774
+ totalDeals: z.number().int().min(0),
7775
+ createdAt: z.string()
7776
+ });
7777
+ z.object({
7778
+ totalLists: z.number().int().min(0),
7779
+ totalCompanies: z.number().int().min(0),
7780
+ totalContacts: z.number().int().min(0),
7781
+ totalDeals: z.number().int().min(0),
7782
+ byStatus: z.record(z.string(), z.number().int().min(0)),
7783
+ lists: z.array(AcqListStatusListItemSchema)
7784
+ });
7406
7785
  var ListExecutionSummarySchema = z.object({
7407
7786
  executionId: z.string(),
7408
7787
  resourceId: z.string(),
@@ -7413,11 +7792,6 @@ var ListExecutionSummarySchema = z.object({
7413
7792
  input: z.unknown().nullable().optional()
7414
7793
  });
7415
7794
  z.array(ListExecutionSummarySchema);
7416
- var QueryBooleanSchema = z.preprocess((value) => {
7417
- if (value === "true" || value === "1" || value === true) return true;
7418
- if (value === "false" || value === "0" || value === false) return false;
7419
- return value;
7420
- }, z.boolean());
7421
7795
  var AcqCompanyStatusSchema = z.enum(["active", "invalid"]);
7422
7796
  var AcqContactStatusSchema = z.enum(["active", "invalid"]);
7423
7797
  var AcqEmailValidSchema = z.enum(["VALID", "INVALID", "RISKY", "UNKNOWN"]);
@@ -7452,6 +7826,7 @@ z.object({
7452
7826
  }).strict();
7453
7827
  z.object({
7454
7828
  name: z.string().trim().min(1).max(255),
7829
+ clientId: UuidSchema.nullable().optional(),
7455
7830
  domain: z.string().trim().min(1).max(255).optional(),
7456
7831
  linkedinUrl: z.string().trim().url().optional(),
7457
7832
  website: z.string().trim().url().optional(),
@@ -7467,6 +7842,7 @@ z.object({
7467
7842
  }).strict();
7468
7843
  z.object({
7469
7844
  name: z.string().trim().min(1).max(255).optional(),
7845
+ clientId: UuidSchema.nullable().optional(),
7470
7846
  domain: z.string().trim().min(1).max(255).optional(),
7471
7847
  linkedinUrl: z.string().trim().url().optional(),
7472
7848
  website: z.string().trim().url().optional(),
@@ -7484,13 +7860,14 @@ z.object({
7484
7860
  status: AcqCompanyStatusSchema.optional(),
7485
7861
  verticalResearch: z.string().trim().min(1).max(5e3).nullable().optional()
7486
7862
  }).strict().refine(
7487
- (data) => data.name !== void 0 || data.domain !== void 0 || data.linkedinUrl !== void 0 || data.website !== void 0 || data.numEmployees !== void 0 || data.foundedYear !== void 0 || data.locationCity !== void 0 || data.locationState !== void 0 || data.category !== void 0 || data.segment !== void 0 || data.processingState !== void 0 || data.pipelineStatus !== void 0 || data.enrichmentData !== void 0 || data.source !== void 0 || data.batchId !== void 0 || data.status !== void 0 || data.verticalResearch !== void 0,
7863
+ (data) => data.name !== void 0 || data.clientId !== void 0 || data.domain !== void 0 || data.linkedinUrl !== void 0 || data.website !== void 0 || data.numEmployees !== void 0 || data.foundedYear !== void 0 || data.locationCity !== void 0 || data.locationState !== void 0 || data.category !== void 0 || data.segment !== void 0 || data.processingState !== void 0 || data.pipelineStatus !== void 0 || data.enrichmentData !== void 0 || data.source !== void 0 || data.batchId !== void 0 || data.status !== void 0 || data.verticalResearch !== void 0,
7488
7864
  {
7489
7865
  message: "At least one field must be provided"
7490
7866
  }
7491
7867
  );
7492
7868
  z.object({
7493
7869
  email: z.string().trim().email(),
7870
+ clientId: UuidSchema.nullable().optional(),
7494
7871
  companyId: UuidSchema.optional(),
7495
7872
  firstName: z.string().trim().min(1).max(255).optional(),
7496
7873
  lastName: z.string().trim().min(1).max(255).optional(),
@@ -7503,6 +7880,7 @@ z.object({
7503
7880
  }).strict();
7504
7881
  z.object({
7505
7882
  companyId: UuidSchema.optional(),
7883
+ clientId: UuidSchema.nullable().optional(),
7506
7884
  emailValid: AcqEmailValidSchema.optional(),
7507
7885
  firstName: z.string().trim().min(1).max(255).optional(),
7508
7886
  lastName: z.string().trim().min(1).max(255).optional(),
@@ -7516,7 +7894,7 @@ z.object({
7516
7894
  enrichmentData: z.record(z.string(), z.unknown()).optional(),
7517
7895
  status: AcqContactStatusSchema.optional()
7518
7896
  }).strict().refine(
7519
- (data) => data.companyId !== void 0 || data.emailValid !== void 0 || data.firstName !== void 0 || data.lastName !== void 0 || data.linkedinUrl !== void 0 || data.title !== void 0 || data.headline !== void 0 || data.filterReason !== void 0 || data.openingLine !== void 0 || data.processingState !== void 0 || data.pipelineStatus !== void 0 || data.enrichmentData !== void 0 || data.status !== void 0,
7897
+ (data) => data.companyId !== void 0 || data.clientId !== void 0 || data.emailValid !== void 0 || data.firstName !== void 0 || data.lastName !== void 0 || data.linkedinUrl !== void 0 || data.title !== void 0 || data.headline !== void 0 || data.filterReason !== void 0 || data.openingLine !== void 0 || data.processingState !== void 0 || data.pipelineStatus !== void 0 || data.enrichmentData !== void 0 || data.status !== void 0,
7520
7898
  {
7521
7899
  message: "At least one field must be provided"
7522
7900
  }
@@ -7524,6 +7902,7 @@ z.object({
7524
7902
  var AcqCompanyResponseSchema = z.object({
7525
7903
  id: z.string(),
7526
7904
  organizationId: z.string(),
7905
+ clientId: z.string().nullable().optional(),
7527
7906
  name: z.string(),
7528
7907
  domain: z.string().nullable(),
7529
7908
  linkedinUrl: z.string().nullable(),
@@ -7570,6 +7949,7 @@ var AcqContactCompanySummarySchema = z.object({
7570
7949
  var AcqContactResponseSchema = z.object({
7571
7950
  id: z.string(),
7572
7951
  organizationId: z.string(),
7952
+ clientId: z.string().nullable().optional(),
7573
7953
  companyId: z.string().nullable(),
7574
7954
  email: z.string(),
7575
7955
  emailValid: AcqEmailValidSchema.nullable(),
@@ -7629,6 +8009,24 @@ z.object({
7629
8009
  limit: z.coerce.number().int().min(1).max(500).default(50),
7630
8010
  offset: z.coerce.number().int().min(0).default(0)
7631
8011
  }).strict();
8012
+ var ListRecordEntitySchema = z.enum(["company", "contact"]);
8013
+ z.object({
8014
+ entity: ListRecordEntitySchema,
8015
+ stage: LeadGenStageKeySchema.optional(),
8016
+ limit: z.coerce.number().int().min(1).max(500).default(50),
8017
+ offset: z.coerce.number().int().min(0).default(0)
8018
+ }).strict().superRefine((query, ctx) => {
8019
+ if (!query.stage) return;
8020
+ const stage = LEAD_GEN_STAGE_CATALOG[query.stage];
8021
+ const validEntity = stage?.entity === query.entity || stage?.additionalEntities?.includes(query.entity) || stage?.recordEntity === query.entity;
8022
+ if (!validEntity) {
8023
+ ctx.addIssue({
8024
+ code: z.ZodIssueCode.custom,
8025
+ message: `stage "${query.stage}" is not valid for ${query.entity} records`,
8026
+ path: ["stage"]
8027
+ });
8028
+ }
8029
+ });
7632
8030
  z.object({
7633
8031
  memberId: UuidSchema
7634
8032
  });
@@ -7657,6 +8055,70 @@ var AcqListMemberResponseSchema = z.object({
7657
8055
  z.object({
7658
8056
  members: z.array(AcqListMemberResponseSchema)
7659
8057
  });
8058
+ var AcqListRecordCompanySummarySchema = z.object({
8059
+ id: z.string(),
8060
+ name: z.string(),
8061
+ domain: z.string().nullable(),
8062
+ website: z.string().nullable(),
8063
+ linkedinUrl: z.string().nullable(),
8064
+ numEmployees: z.number().nullable(),
8065
+ foundedYear: z.number().nullable(),
8066
+ locationCity: z.string().nullable(),
8067
+ locationState: z.string().nullable(),
8068
+ category: z.string().nullable(),
8069
+ segment: z.string().nullable(),
8070
+ status: AcqCompanyStatusSchema,
8071
+ qualificationScore: z.number().nullable(),
8072
+ qualificationSignals: z.record(z.string(), z.unknown()).nullable(),
8073
+ qualificationRubricKey: z.string().nullable()
8074
+ });
8075
+ var AcqListRecordContactSummarySchema = z.object({
8076
+ id: z.string(),
8077
+ email: z.string(),
8078
+ firstName: z.string().nullable(),
8079
+ lastName: z.string().nullable(),
8080
+ title: z.string().nullable(),
8081
+ headline: z.string().nullable(),
8082
+ linkedinUrl: z.string().nullable(),
8083
+ companyId: z.string().nullable(),
8084
+ status: AcqContactStatusSchema,
8085
+ qualificationScore: z.number().nullable(),
8086
+ qualificationSignals: z.record(z.string(), z.unknown()).nullable(),
8087
+ qualificationRubricKey: z.string().nullable()
8088
+ });
8089
+ var ListRecordBaseSchema = z.object({
8090
+ id: z.string(),
8091
+ listId: z.string(),
8092
+ pipelineKey: z.string(),
8093
+ stageKey: z.string(),
8094
+ stateKey: z.string(),
8095
+ activityLog: z.unknown(),
8096
+ addedAt: z.string(),
8097
+ addedBy: z.string().nullable(),
8098
+ sourceExecutionId: z.string().nullable(),
8099
+ processingState: z.record(z.string(), z.unknown()).nullable(),
8100
+ enrichmentData: z.record(z.string(), z.unknown()).nullable()
8101
+ });
8102
+ var AcqListCompanyRecordRowSchema = ListRecordBaseSchema.extend({
8103
+ entity: z.literal("company"),
8104
+ companyId: z.string(),
8105
+ company: AcqListRecordCompanySummarySchema.nullable()
8106
+ });
8107
+ var AcqListContactRecordRowSchema = ListRecordBaseSchema.extend({
8108
+ entity: z.literal("contact"),
8109
+ contactId: z.string(),
8110
+ contact: AcqListRecordContactSummarySchema.nullable()
8111
+ });
8112
+ var ListRecordRowSchema = z.discriminatedUnion("entity", [
8113
+ AcqListCompanyRecordRowSchema,
8114
+ AcqListContactRecordRowSchema
8115
+ ]);
8116
+ z.object({
8117
+ data: z.array(ListRecordRowSchema),
8118
+ total: z.number().int().min(0),
8119
+ limit: z.number().int().min(1),
8120
+ offset: z.number().int().min(0)
8121
+ });
7660
8122
  z.object({
7661
8123
  listCompanyId: UuidSchema
7662
8124
  });
@@ -8032,6 +8494,149 @@ var RegistryValidationError = class extends Error {
8032
8494
  this.name = "RegistryValidationError";
8033
8495
  }
8034
8496
  };
8497
+ function getResourceValidatorMode(explicitMode) {
8498
+ if (explicitMode) return explicitMode;
8499
+ const env = globalThis.process?.env;
8500
+ return env?.ELEVASIS_RESOURCE_VALIDATOR === "warn-only" ? "warn-only" : "strict";
8501
+ }
8502
+ function addGovernanceIssue(issues, type3, orgName, resourceId, message) {
8503
+ issues.push({
8504
+ type: type3,
8505
+ orgName,
8506
+ resourceId,
8507
+ message
8508
+ });
8509
+ }
8510
+ function emitGovernanceIssues(issues, mode, onWarning) {
8511
+ if (issues.length === 0) return;
8512
+ if (mode === "strict") {
8513
+ const first = issues[0];
8514
+ throw new RegistryValidationError(first.orgName, first.resourceId, "organizationModel.resources", first.message);
8515
+ }
8516
+ const warn = onWarning ?? ((issue) => console.warn(issue.message));
8517
+ for (const issue of issues) {
8518
+ warn(issue);
8519
+ }
8520
+ }
8521
+ function getRuntimeResources(resources) {
8522
+ return [
8523
+ ...(resources.workflows ?? []).map((workflow) => ({
8524
+ resourceId: workflow.config.resourceId,
8525
+ type: workflow.config.type,
8526
+ descriptor: workflow.config.resource
8527
+ })),
8528
+ ...(resources.agents ?? []).map((agent) => ({
8529
+ resourceId: agent.config.resourceId,
8530
+ type: agent.config.type,
8531
+ descriptor: agent.config.resource
8532
+ })),
8533
+ ...(resources.integrations ?? []).map((integration) => ({
8534
+ resourceId: integration.resourceId,
8535
+ type: integration.type,
8536
+ descriptor: integration.resource
8537
+ }))
8538
+ ];
8539
+ }
8540
+ function validateResourceGovernance(orgName, deployment, organizationModel = deployment.organizationModel, options = {}) {
8541
+ const mode = getResourceValidatorMode(options.mode);
8542
+ const omResources = organizationModel?.resources?.entries;
8543
+ const omSystems = organizationModel?.systems?.systems;
8544
+ const issues = [];
8545
+ if (!omResources || !omSystems) {
8546
+ return { valid: true, mode, issues };
8547
+ }
8548
+ const systemsById = new Map(omSystems.map((system) => [system.id, system]));
8549
+ const activeOmResources = omResources.filter((resource) => resource.status === "active");
8550
+ const omResourcesById = new Map(activeOmResources.map((resource) => [resource.id, resource]));
8551
+ const runtimeResources = getRuntimeResources(deployment);
8552
+ const runtimeResourcesById = new Map(runtimeResources.map((resource) => [resource.resourceId, resource]));
8553
+ for (const resource of activeOmResources) {
8554
+ if (!systemsById.has(resource.systemId)) {
8555
+ addGovernanceIssue(
8556
+ issues,
8557
+ "missing-om-system",
8558
+ orgName,
8559
+ resource.id,
8560
+ `[${orgName}] OM resource '${resource.id}' references missing System '${resource.systemId}'.`
8561
+ );
8562
+ }
8563
+ const runtimeResource = runtimeResourcesById.get(resource.id);
8564
+ if (!runtimeResource) {
8565
+ addGovernanceIssue(
8566
+ issues,
8567
+ "missing-code-resource",
8568
+ orgName,
8569
+ resource.id,
8570
+ `[${orgName}] OM resource '${resource.id}' has no matching code-side resource.`
8571
+ );
8572
+ continue;
8573
+ }
8574
+ if (runtimeResource.type !== resource.kind) {
8575
+ addGovernanceIssue(
8576
+ issues,
8577
+ "type-mismatch",
8578
+ orgName,
8579
+ resource.id,
8580
+ `[${orgName}] Resource '${resource.id}' type mismatch: code has '${runtimeResource.type}', OM has '${resource.kind}'.`
8581
+ );
8582
+ }
8583
+ if (runtimeResource.descriptor && runtimeResource.descriptor.systemId !== resource.systemId) {
8584
+ addGovernanceIssue(
8585
+ issues,
8586
+ "system-mismatch",
8587
+ orgName,
8588
+ resource.id,
8589
+ `[${orgName}] Resource '${resource.id}' system mismatch: code descriptor has '${runtimeResource.descriptor.systemId}', OM has '${resource.systemId}'.`
8590
+ );
8591
+ }
8592
+ }
8593
+ for (const runtimeResource of runtimeResources) {
8594
+ const omResource = omResourcesById.get(runtimeResource.resourceId);
8595
+ if (!omResource) {
8596
+ addGovernanceIssue(
8597
+ issues,
8598
+ "missing-om-resource",
8599
+ orgName,
8600
+ runtimeResource.resourceId,
8601
+ `[${orgName}] Code-side resource '${runtimeResource.resourceId}' has no active OM Resource descriptor.`
8602
+ );
8603
+ }
8604
+ if (!runtimeResource.descriptor) {
8605
+ addGovernanceIssue(
8606
+ issues,
8607
+ "raw-resource-id",
8608
+ orgName,
8609
+ runtimeResource.resourceId,
8610
+ `[${orgName}] Code-side resource '${runtimeResource.resourceId}' authors raw resourceId/type values. Use an OM Resource descriptor and bindResourceDescriptor().`
8611
+ );
8612
+ continue;
8613
+ }
8614
+ if (runtimeResource.descriptor.id !== runtimeResource.resourceId) {
8615
+ addGovernanceIssue(
8616
+ issues,
8617
+ "raw-resource-id",
8618
+ orgName,
8619
+ runtimeResource.resourceId,
8620
+ `[${orgName}] Code-side resource '${runtimeResource.resourceId}' does not derive identity from its OM descriptor '${runtimeResource.descriptor.id}'.`
8621
+ );
8622
+ }
8623
+ if (runtimeResource.descriptor.kind !== runtimeResource.type) {
8624
+ addGovernanceIssue(
8625
+ issues,
8626
+ "type-mismatch",
8627
+ orgName,
8628
+ runtimeResource.resourceId,
8629
+ `[${orgName}] Code-side resource '${runtimeResource.resourceId}' descriptor kind '${runtimeResource.descriptor.kind}' does not match runtime type '${runtimeResource.type}'.`
8630
+ );
8631
+ }
8632
+ }
8633
+ emitGovernanceIssues(issues, mode, options.onWarning);
8634
+ return {
8635
+ valid: issues.length === 0,
8636
+ mode,
8637
+ issues
8638
+ };
8639
+ }
8035
8640
  function validateDeploymentSpec(orgName, resources) {
8036
8641
  const seenIds = /* @__PURE__ */ new Set();
8037
8642
  resources.workflows?.forEach((workflow) => {
@@ -8068,6 +8673,7 @@ function validateDeploymentSpec(orgName, resources) {
8068
8673
  validateExecutionInterface(orgName, id, agent.interface, agent.contract.inputSchema);
8069
8674
  }
8070
8675
  });
8676
+ validateResourceGovernance(orgName, resources);
8071
8677
  }
8072
8678
  function validateResourceModelConfig(orgName, resourceId, modelConfig) {
8073
8679
  try {