@elevasis/sdk 1.20.1 → 1.21.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 +3388 -1530
  2. package/dist/index.d.ts +412 -149
  3. package/dist/index.js +955 -721
  4. package/dist/node/index.d.ts +0 -3
  5. package/dist/node/index.js +22 -49
  6. package/dist/test-utils/index.d.ts +395 -128
  7. package/dist/test-utils/index.js +599 -368
  8. package/dist/worker/index.js +536 -323
  9. package/package.json +4 -4
  10. package/reference/_navigation.md +9 -7
  11. package/reference/_reference-manifest.json +1 -1
  12. package/reference/claude-config/rules/agent-start-here.md +4 -0
  13. package/reference/claude-config/rules/frontend.md +2 -2
  14. package/reference/claude-config/rules/organization-model.md +44 -2
  15. package/reference/claude-config/rules/organization-os.md +12 -12
  16. package/reference/claude-config/rules/ui.md +14 -14
  17. package/reference/claude-config/rules/vibe.md +37 -33
  18. package/reference/claude-config/skills/explore/SKILL.md +6 -6
  19. package/reference/claude-config/skills/knowledge/SKILL.md +73 -29
  20. package/reference/claude-config/skills/knowledge/operations/codify-level-a.md +1 -1
  21. package/reference/claude-config/skills/knowledge/operations/codify-level-b.md +25 -24
  22. package/reference/claude-config/skills/knowledge/operations/features.md +56 -93
  23. package/reference/claude-config/skills/knowledge/operations/labels.md +19 -14
  24. package/reference/claude-config/skills/knowledge/operations/offerings.md +6 -6
  25. package/reference/claude-config/skills/save/SKILL.md +2 -2
  26. package/reference/claude-config/skills/setup/SKILL.md +1 -1
  27. package/reference/claude-config/skills/tutorial/technical.md +23 -26
  28. package/reference/claude-config/skills/tutorial/vibe-coder.md +9 -9
  29. package/reference/claude-config/sync-notes/2026-05-12-sdk-ready-release-train.md +30 -0
  30. package/reference/cli.mdx +140 -0
  31. package/reference/deployment/provided-features.mdx +29 -15
  32. package/reference/examples/organization-model.ts +1 -1
  33. package/reference/packages/core/src/knowledge/README.md +8 -7
  34. package/reference/packages/core/src/organization-model/README.md +66 -26
  35. package/reference/packages/ui/src/provider/README.md +5 -5
  36. package/reference/scaffold/core/organization-graph.mdx +16 -15
  37. package/reference/scaffold/core/organization-model.mdx +89 -41
  38. package/reference/scaffold/index.mdx +9 -9
  39. package/reference/scaffold/operations/propagation-pipeline.md +3 -3
  40. package/reference/scaffold/operations/scaffold-maintenance.md +11 -11
  41. package/reference/scaffold/recipes/add-a-feature.md +26 -24
  42. package/reference/scaffold/recipes/add-a-resource.md +10 -14
  43. package/reference/scaffold/recipes/customize-crm-actions.md +439 -439
  44. package/reference/scaffold/recipes/customize-knowledge-browser.md +384 -0
  45. package/reference/scaffold/recipes/customize-organization-model.md +72 -44
  46. package/reference/scaffold/recipes/extend-crm.md +40 -39
  47. package/reference/scaffold/recipes/extend-lead-gen.md +15 -16
  48. package/reference/scaffold/recipes/gate-by-feature-or-admin.md +34 -30
  49. package/reference/scaffold/recipes/index.md +13 -12
  50. package/reference/scaffold/recipes/query-the-knowledge-graph.md +200 -0
  51. package/reference/scaffold/reference/contracts.md +362 -99
  52. package/reference/scaffold/reference/feature-registry.md +9 -20
  53. package/reference/scaffold/reference/glossary.md +18 -18
  54. package/reference/scaffold/ui/composition-extensibility.mdx +23 -23
  55. package/reference/scaffold/ui/customization.md +11 -11
  56. package/reference/scaffold/ui/feature-flags-and-gating.md +8 -8
  57. package/reference/scaffold/ui/feature-shell.mdx +19 -19
  58. package/reference/scaffold/ui/recipes.md +29 -28
@@ -6622,188 +6622,327 @@ DisplayMetadataSchema.extend({
6622
6622
  id: ModelIdSchema,
6623
6623
  resourceId: z.string().trim().min(1).max(255),
6624
6624
  resourceType: z.enum(["workflow", "agent", "trigger", "integration", "external", "human_checkpoint"]),
6625
- featureIds: ReferenceIdsSchema,
6625
+ systemIds: ReferenceIdsSchema,
6626
6626
  entityIds: ReferenceIdsSchema,
6627
6627
  surfaceIds: ReferenceIdsSchema,
6628
- capabilityIds: ReferenceIdsSchema,
6628
+ actionIds: ReferenceIdsSchema,
6629
6629
  /** Optional tech-stack metadata for external-SaaS integrations. */
6630
6630
  techStack: TechStackEntrySchema.optional()
6631
6631
  });
6632
6632
 
6633
- // ../core/src/organization-model/domains/sales.ts
6634
- var SalesStageSemanticClassSchema = z.enum(["open", "active", "nurturing", "closed_won", "closed_lost"]);
6635
- var SalesStageSchema = DisplayMetadataSchema.extend({
6636
- id: ModelIdSchema,
6637
- order: z.number().int().min(0),
6638
- semanticClass: SalesStageSemanticClassSchema,
6639
- surfaceIds: ReferenceIdsSchema,
6640
- resourceIds: ReferenceIdsSchema
6633
+ // ../core/src/organization-model/domains/entities.ts
6634
+ var EntityIdSchema = ModelIdSchema;
6635
+ var EntityLinkKindSchema = z.enum(["belongs-to", "has-many", "has-one", "many-to-many"]).meta({ label: "Link kind" });
6636
+ var EntityLinkSchema = z.object({
6637
+ toEntity: EntityIdSchema.meta({ ref: "entity" }),
6638
+ kind: EntityLinkKindSchema,
6639
+ via: z.string().trim().min(1).max(255).optional(),
6640
+ label: LabelSchema.optional()
6641
6641
  });
6642
- var SalesPipelineSchema = z.object({
6643
- id: ModelIdSchema,
6644
- label: z.string().trim().min(1).max(120),
6642
+ var EntitySchema = z.object({
6643
+ id: EntityIdSchema,
6644
+ /** Domain-map iteration order. Convention: multiples of 10 (10, 20, 30, ...) to allow easy insertion. */
6645
+ order: z.number(),
6646
+ label: LabelSchema,
6645
6647
  description: DescriptionSchema.optional(),
6646
- entityId: ModelIdSchema,
6647
- stages: z.array(SalesStageSchema).min(1)
6648
+ ownedBySystemId: ModelIdSchema.meta({ ref: "system" }),
6649
+ table: z.string().trim().min(1).max(255).optional(),
6650
+ rowSchema: ModelIdSchema.optional(),
6651
+ stateCatalogId: ModelIdSchema.optional(),
6652
+ links: z.array(EntityLinkSchema).optional()
6648
6653
  });
6654
+ z.record(z.string(), EntitySchema).refine((record) => Object.entries(record).every(([key, entry]) => entry.id === key), {
6655
+ message: "Each entity entry id must match its map key"
6656
+ }).default({});
6657
+ var ENTITY_ENTRY_INPUTS = [
6658
+ {
6659
+ id: "crm.deal",
6660
+ order: 10,
6661
+ label: "Deal",
6662
+ description: "A CRM opportunity or sales pipeline record.",
6663
+ ownedBySystemId: "sales.crm",
6664
+ table: "crm_deals",
6665
+ stateCatalogId: "crm.pipeline",
6666
+ links: [{ toEntity: "crm.contact", kind: "has-many", via: "deal_contacts", label: "contacts" }]
6667
+ },
6668
+ {
6669
+ id: "crm.contact",
6670
+ order: 20,
6671
+ label: "CRM Contact",
6672
+ description: "A person associated with a CRM relationship or deal.",
6673
+ ownedBySystemId: "sales.crm",
6674
+ table: "crm_contacts"
6675
+ },
6676
+ {
6677
+ id: "leadgen.list",
6678
+ order: 30,
6679
+ label: "Lead List",
6680
+ description: "A prospecting list that groups companies and contacts for acquisition workflows.",
6681
+ ownedBySystemId: "sales.lead-gen",
6682
+ table: "acq_lists",
6683
+ links: [
6684
+ { toEntity: "leadgen.company", kind: "has-many", via: "acq_list_companies", label: "companies" },
6685
+ { toEntity: "leadgen.contact", kind: "has-many", via: "acq_list_members", label: "contacts" }
6686
+ ]
6687
+ },
6688
+ {
6689
+ id: "leadgen.company",
6690
+ order: 40,
6691
+ label: "Lead Company",
6692
+ description: "A company record sourced, enriched, and qualified during prospecting.",
6693
+ ownedBySystemId: "sales.lead-gen",
6694
+ table: "acq_list_companies",
6695
+ stateCatalogId: "lead-gen.company",
6696
+ links: [
6697
+ { toEntity: "leadgen.list", kind: "belongs-to", via: "list_id", label: "list" },
6698
+ { toEntity: "leadgen.contact", kind: "has-many", via: "company_id", label: "contacts" }
6699
+ ]
6700
+ },
6701
+ {
6702
+ id: "leadgen.contact",
6703
+ order: 50,
6704
+ label: "Lead Contact",
6705
+ description: "A prospect contact discovered or enriched during lead generation.",
6706
+ ownedBySystemId: "sales.lead-gen",
6707
+ table: "acq_list_members",
6708
+ stateCatalogId: "lead-gen.contact",
6709
+ links: [
6710
+ { toEntity: "leadgen.list", kind: "belongs-to", via: "list_id", label: "list" },
6711
+ { toEntity: "leadgen.company", kind: "belongs-to", via: "company_id", label: "company" }
6712
+ ]
6713
+ },
6714
+ {
6715
+ id: "delivery.project",
6716
+ order: 60,
6717
+ label: "Project",
6718
+ description: "A client delivery project.",
6719
+ ownedBySystemId: "projects",
6720
+ table: "projects",
6721
+ links: [
6722
+ { toEntity: "delivery.milestone", kind: "has-many", via: "project_id", label: "milestones" },
6723
+ { toEntity: "delivery.task", kind: "has-many", via: "project_id", label: "tasks" }
6724
+ ]
6725
+ },
6726
+ {
6727
+ id: "delivery.milestone",
6728
+ order: 70,
6729
+ label: "Milestone",
6730
+ description: "A delivery checkpoint within a project.",
6731
+ ownedBySystemId: "projects",
6732
+ table: "project_milestones",
6733
+ links: [
6734
+ { toEntity: "delivery.project", kind: "belongs-to", via: "project_id", label: "project" },
6735
+ { toEntity: "delivery.task", kind: "has-many", via: "milestone_id", label: "tasks" }
6736
+ ]
6737
+ },
6738
+ {
6739
+ id: "delivery.task",
6740
+ order: 80,
6741
+ label: "Task",
6742
+ description: "A delivery task that can move through the task status catalog.",
6743
+ ownedBySystemId: "projects",
6744
+ table: "project_tasks",
6745
+ stateCatalogId: "delivery.task",
6746
+ links: [
6747
+ { toEntity: "delivery.project", kind: "belongs-to", via: "project_id", label: "project" },
6748
+ { toEntity: "delivery.milestone", kind: "belongs-to", via: "milestone_id", label: "milestone" }
6749
+ ]
6750
+ }
6751
+ ];
6752
+ Object.fromEntries(
6753
+ ENTITY_ENTRY_INPUTS.map((entity) => {
6754
+ const parsed = EntitySchema.parse(entity);
6755
+ return [parsed.id, parsed];
6756
+ })
6757
+ );
6758
+
6759
+ // ../core/src/organization-model/domains/actions.ts
6760
+ var ActionResourceIdSchema = z.string().trim().min(1).max(255).regex(/^[A-Za-z0-9]+(?:[-._][A-Za-z0-9]+)*$/, "Resource IDs must use letters, numbers, -, _, or . separators");
6761
+ z.enum(["slash-command", "mcp-tool", "api-endpoint", "script-execution"]).meta({ label: "Invocation kind" });
6762
+ var ActionIdSchema = ModelIdSchema;
6763
+ var ActionScopeSchema = z.union([
6764
+ z.literal("global"),
6765
+ z.object({
6766
+ domain: ModelIdSchema
6767
+ })
6768
+ ]);
6649
6769
  z.object({
6650
- entityId: ModelIdSchema,
6651
- defaultPipelineId: ModelIdSchema,
6652
- pipelines: z.array(SalesPipelineSchema).min(1)
6770
+ actionId: ActionIdSchema.meta({ ref: "action" }),
6771
+ intent: z.enum(["exposes", "consumes"]).meta({ label: "Intent" })
6653
6772
  });
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
- };
6711
- var LEAD_GEN_STAGE_CATALOG = {
6712
- // Prospecting — company population
6713
- scraped: {
6714
- key: "scraped",
6715
- label: "Scraped",
6716
- description: "Company was scraped from a source directory (Apify actor run).",
6717
- order: 1,
6718
- entity: "company"
6773
+ var SlashCommandInvocationSchema = z.object({
6774
+ kind: z.literal("slash-command"),
6775
+ command: z.string().trim().min(1).max(200).regex(/^\/[^\s].*$/, "Slash commands must start with /"),
6776
+ toolFactory: ModelIdSchema.optional()
6777
+ });
6778
+ var McpToolInvocationSchema = z.object({
6779
+ kind: z.literal("mcp-tool"),
6780
+ server: ModelIdSchema,
6781
+ name: ModelIdSchema
6782
+ });
6783
+ var ApiEndpointInvocationSchema = z.object({
6784
+ kind: z.literal("api-endpoint"),
6785
+ method: z.enum(["GET", "POST", "PATCH", "DELETE"]).meta({ label: "HTTP method" }),
6786
+ path: z.string().trim().startsWith("/").max(500),
6787
+ requestSchema: ModelIdSchema.optional(),
6788
+ responseSchema: ModelIdSchema.optional()
6789
+ });
6790
+ var ScriptExecutionInvocationSchema = z.object({
6791
+ kind: z.literal("script-execution"),
6792
+ resourceId: ActionResourceIdSchema
6793
+ });
6794
+ var ActionInvocationSchema = z.discriminatedUnion("kind", [
6795
+ SlashCommandInvocationSchema,
6796
+ McpToolInvocationSchema,
6797
+ ApiEndpointInvocationSchema,
6798
+ ScriptExecutionInvocationSchema
6799
+ ]);
6800
+ var ActionSchema = z.object({
6801
+ id: ActionIdSchema,
6802
+ /** Domain-map iteration order. Convention: multiples of 10 (10, 20, 30, ...) to allow easy insertion. */
6803
+ order: z.number(),
6804
+ label: LabelSchema,
6805
+ description: DescriptionSchema.optional(),
6806
+ scope: ActionScopeSchema.default("global"),
6807
+ resourceId: ActionResourceIdSchema.optional(),
6808
+ affects: z.array(EntityIdSchema.meta({ ref: "entity" })).optional(),
6809
+ invocations: z.array(ActionInvocationSchema).default([]),
6810
+ knowledge: z.array(ModelIdSchema.meta({ ref: "knowledge" })).default([]).optional(),
6811
+ lifecycle: z.enum(["draft", "beta", "active", "deprecated", "archived"]).meta({ label: "Lifecycle", color: "teal" }).default("active")
6812
+ });
6813
+ z.record(z.string(), ActionSchema).refine((record) => Object.entries(record).every(([key, entry]) => entry.id === key), {
6814
+ message: "Each action entry id must match its map key"
6815
+ }).default({});
6816
+ var LEAD_GEN_ACTION_ENTRY_INPUTS = [
6817
+ {
6818
+ id: "lead-gen.company.source",
6819
+ order: 10,
6820
+ label: "Source companies",
6821
+ description: "Import source companies from a list provider.",
6822
+ scope: { domain: "sales" },
6823
+ resourceId: "lgn-import-workflow",
6824
+ invocations: [{ kind: "api-endpoint", method: "POST", path: "/api/prospecting/companies/source" }]
6719
6825
  },
6720
- populated: {
6721
- key: "populated",
6722
- label: "Companies found",
6723
- description: "Companies have been found and added to the lead-gen list.",
6724
- order: 2,
6725
- entity: "company"
6826
+ {
6827
+ id: "lead-gen.company.apollo-import",
6828
+ order: 20,
6829
+ label: "Import from Apollo",
6830
+ description: "Pull companies and seed contact data from an Apollo search or list.",
6831
+ scope: { domain: "sales" },
6832
+ resourceId: "lgn-01c-apollo-import-workflow",
6833
+ invocations: [{ kind: "api-endpoint", method: "POST", path: "/api/prospecting/companies/apollo-import" }]
6726
6834
  },
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"
6835
+ {
6836
+ id: "lead-gen.contact.discover",
6837
+ order: 30,
6838
+ label: "Discover contact emails",
6839
+ description: "Find email addresses for contacts at qualified companies.",
6840
+ scope: { domain: "sales" },
6841
+ resourceId: "lgn-04-email-discovery-workflow",
6842
+ invocations: [{ kind: "api-endpoint", method: "POST", path: "/api/prospecting/contacts/discover" }]
6733
6843
  },
6734
- extracted: {
6735
- key: "extracted",
6736
- label: "Websites analyzed",
6737
- description: "Company websites have been analyzed for business signals.",
6738
- order: 3,
6739
- entity: "company"
6844
+ {
6845
+ id: "lead-gen.contact.verify-email",
6846
+ order: 40,
6847
+ label: "Verify emails",
6848
+ description: "Check email deliverability before outreach.",
6849
+ scope: { domain: "sales" },
6850
+ resourceId: "lgn-05-email-verification-workflow",
6851
+ invocations: [{ kind: "api-endpoint", method: "POST", path: "/api/prospecting/contacts/verify-email" }]
6740
6852
  },
6741
- enriched: {
6742
- key: "enriched",
6743
- label: "Enriched",
6744
- description: "Company or contact enriched with third-party data (e.g. Tomba, Anymailfinder).",
6745
- order: 4,
6746
- entity: "company"
6853
+ {
6854
+ id: "lead-gen.company.apify-crawl",
6855
+ order: 50,
6856
+ label: "Crawl websites",
6857
+ description: "Crawl company websites via Apify and store raw page markdown in enrichmentData.websiteCrawl.pages for downstream LLM analysis.",
6858
+ scope: { domain: "sales" },
6859
+ resourceId: "lgn-02a-apify-website-crawl-workflow",
6860
+ invocations: [{ kind: "api-endpoint", method: "POST", path: "/api/prospecting/companies/apify-crawl" }]
6747
6861
  },
6748
- "decision-makers-enriched": {
6749
- key: "decision-makers-enriched",
6750
- label: "Decision-makers found",
6751
- description: "Decision-maker contacts discovered and attached to a qualified company.",
6752
- order: 6,
6753
- entity: "company",
6754
- recordEntity: "contact",
6755
- recordStageKey: "discovered"
6862
+ {
6863
+ id: "lead-gen.company.website-extract",
6864
+ order: 60,
6865
+ label: "Extract website signals",
6866
+ description: "Scrape and analyze company websites for qualification signals.",
6867
+ scope: { domain: "sales" },
6868
+ resourceId: "lgn-02-website-extract-workflow",
6869
+ invocations: [{ kind: "api-endpoint", method: "POST", path: "/api/prospecting/companies/website-extract" }]
6756
6870
  },
6757
- // Prospecting — contact discovery
6758
- discovered: {
6759
- key: "discovered",
6760
- label: "Decision-makers found",
6761
- description: "Decision-maker contact details have been found.",
6762
- order: 5,
6763
- entity: "contact"
6871
+ {
6872
+ id: "lead-gen.company.qualify",
6873
+ order: 70,
6874
+ label: "Qualify companies",
6875
+ description: "Score and filter companies against the ICP rubric.",
6876
+ scope: { domain: "sales" },
6877
+ resourceId: "lgn-03-company-qualification-workflow",
6878
+ invocations: [{ kind: "api-endpoint", method: "POST", path: "/api/prospecting/companies/qualify" }]
6764
6879
  },
6765
- verified: {
6766
- key: "verified",
6767
- label: "Emails verified",
6768
- description: "Contact email addresses have been checked for deliverability.",
6769
- order: 7,
6770
- entity: "contact"
6880
+ {
6881
+ id: "lead-gen.company.dtc-subscription-qualify",
6882
+ order: 80,
6883
+ label: "Qualify DTC subscription fit",
6884
+ description: "Classify subscription potential and consumable-product fit for DTC brands.",
6885
+ scope: { domain: "sales" },
6886
+ resourceId: "lgn-03b-dtc-subscription-score-workflow",
6887
+ invocations: [{ kind: "api-endpoint", method: "POST", path: "/api/prospecting/companies/dtc-subscription-qualify" }]
6771
6888
  },
6772
- // Qualification
6773
- qualified: {
6774
- key: "qualified",
6775
- label: "Companies qualified",
6776
- description: "Companies have been scored against the qualification criteria.",
6777
- order: 8,
6778
- entity: "company"
6889
+ {
6890
+ id: "lead-gen.contact.apollo-decision-maker-enrich",
6891
+ order: 90,
6892
+ label: "Enrich decision-makers",
6893
+ description: "Find and enrich qualified contacts at qualified companies via Apollo.",
6894
+ scope: { domain: "sales" },
6895
+ resourceId: "lgn-04b-apollo-decision-maker-enrich-workflow",
6896
+ invocations: [
6897
+ { kind: "api-endpoint", method: "POST", path: "/api/prospecting/contacts/apollo-decision-maker-enrich" }
6898
+ ]
6779
6899
  },
6780
- // Outreach
6781
- personalized: {
6782
- key: "personalized",
6783
- label: "Personalized",
6784
- description: "Outreach message personalized for the contact (Instantly personalization workflow).",
6785
- order: 9,
6786
- entity: "contact"
6900
+ {
6901
+ id: "lead-gen.contact.personalize",
6902
+ order: 100,
6903
+ label: "Personalize outreach",
6904
+ description: "Generate personalized opening lines for each contact.",
6905
+ scope: { domain: "sales" },
6906
+ resourceId: "ist-personalization-workflow",
6907
+ invocations: [{ kind: "api-endpoint", method: "POST", path: "/api/prospecting/contacts/personalize" }]
6787
6908
  },
6788
- uploaded: {
6789
- key: "uploaded",
6790
- label: "Reviewed and exported",
6791
- description: "Approved records have been reviewed and exported for handoff.",
6792
- order: 10,
6793
- entity: "company",
6794
- additionalEntities: ["contact"]
6909
+ {
6910
+ id: "lead-gen.review.outreach-ready",
6911
+ order: 110,
6912
+ label: "Upload to outreach",
6913
+ description: "Upload approved contacts to the outreach sequence after QC review.",
6914
+ scope: { domain: "sales" },
6915
+ resourceId: "ist-upload-contacts-workflow",
6916
+ invocations: [{ kind: "api-endpoint", method: "POST", path: "/api/prospecting/review/outreach-ready" }]
6795
6917
  },
6796
- interested: {
6797
- key: "interested",
6798
- label: "Interested",
6799
- description: "Contact replied with a positive signal (Instantly reply-handler transition).",
6800
- order: 11,
6801
- entity: "contact"
6918
+ {
6919
+ id: "lead-gen.export.list",
6920
+ order: 120,
6921
+ label: "Export lead list",
6922
+ description: "Export approved leads as a downloadable lead list.",
6923
+ scope: { domain: "sales" },
6924
+ resourceId: "lgn-06-export-list-workflow",
6925
+ invocations: [{ kind: "api-endpoint", method: "POST", path: "/api/prospecting/export/list" }]
6926
+ },
6927
+ {
6928
+ id: "lead-gen.company.cleanup",
6929
+ order: 130,
6930
+ label: "Clean up companies",
6931
+ description: "Remove disqualified or duplicate companies from the list.",
6932
+ scope: { domain: "sales" },
6933
+ resourceId: "lgn-company-cleanup-workflow",
6934
+ invocations: [{ kind: "api-endpoint", method: "POST", path: "/api/prospecting/companies/cleanup" }]
6802
6935
  }
6803
- };
6936
+ ];
6937
+ var LEAD_GEN_ACTION_ENTRIES = Object.fromEntries(
6938
+ LEAD_GEN_ACTION_ENTRY_INPUTS.map((action) => {
6939
+ const parsed = ActionSchema.parse(action);
6940
+ return [parsed.id, parsed];
6941
+ })
6942
+ );
6804
6943
 
6805
6944
  // ../core/src/organization-model/domains/prospecting.ts
6806
- var ProspectingLifecycleStageSchema = DisplayMetadataSchema.extend({
6945
+ DisplayMetadataSchema.extend({
6807
6946
  id: ModelIdSchema,
6808
6947
  order: z.number().min(0)
6809
6948
  });
@@ -6841,7 +6980,7 @@ var ProspectingBuildTemplateStepSchema = DisplayMetadataSchema.extend({
6841
6980
  recordSourceStageKey: ModelIdSchema.optional(),
6842
6981
  dependsOn: z.array(ModelIdSchema).optional(),
6843
6982
  dependencyMode: z.literal("per-record-eligibility"),
6844
- capabilityKey: ModelIdSchema,
6983
+ actionKey: ModelIdSchema,
6845
6984
  defaultBatchSize: z.number().int().positive(),
6846
6985
  maxBatchSize: z.number().int().positive(),
6847
6986
  recordColumns: RecordColumnsConfigSchema.optional(),
@@ -6850,7 +6989,7 @@ var ProspectingBuildTemplateStepSchema = DisplayMetadataSchema.extend({
6850
6989
  message: "defaultBatchSize must be less than or equal to maxBatchSize",
6851
6990
  path: ["defaultBatchSize"]
6852
6991
  });
6853
- var ProspectingBuildTemplateSchema = DisplayMetadataSchema.extend({
6992
+ DisplayMetadataSchema.extend({
6854
6993
  id: ModelIdSchema,
6855
6994
  steps: z.array(ProspectingBuildTemplateStepSchema).min(1)
6856
6995
  });
@@ -6862,140 +7001,84 @@ var DTC_RECORD_COLUMNS = {
6862
7001
  { key: "employee-count", label: "Employees", path: "company.numEmployees", renderType: "count" },
6863
7002
  { key: "apollo-industry", label: "Apollo industry", path: "company.category" },
6864
7003
  { 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
- }
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"
7004
+ ]
6967
7005
  },
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"
7006
+ crawled: {
7007
+ company: [
7008
+ { key: "name", label: "Company", path: "company.name" },
7009
+ { key: "domain", label: "Domain", path: "company.domain" },
7010
+ { key: "page-count", label: "Pages", path: "company.enrichmentData.websiteCrawl.pageCount", renderType: "count" },
7011
+ { key: "crawl-status", label: "Crawl status", path: "processingState.crawled.status", renderType: "badge" }
7012
+ ]
6973
7013
  },
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"
7014
+ extracted: {
7015
+ company: [
7016
+ { key: "name", label: "Company", path: "company.name" },
7017
+ { key: "domain", label: "Domain", path: "company.domain" },
7018
+ { key: "description", label: "Description", path: "company.enrichmentData.websiteCrawl.companyDescription" },
7019
+ { key: "services", label: "Services", path: "company.enrichmentData.websiteCrawl.services", renderType: "json" },
7020
+ {
7021
+ key: "automation-gaps",
7022
+ label: "Automation gaps",
7023
+ path: "company.enrichmentData.websiteCrawl.automationGaps",
7024
+ renderType: "json"
7025
+ },
7026
+ {
7027
+ key: "contact-count",
7028
+ label: "Contacts",
7029
+ path: "company.enrichmentData.websiteCrawl.emailCount",
7030
+ renderType: "count"
7031
+ }
7032
+ ]
6979
7033
  },
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"
7034
+ qualified: {
7035
+ company: [
7036
+ { key: "name", label: "Company", path: "company.name" },
7037
+ { key: "domain", label: "Domain", path: "company.domain" },
7038
+ { key: "score", label: "Score", path: "company.qualificationScore", renderType: "badge", badgeColor: "green" },
7039
+ { key: "signals", label: "Signals", path: "company.qualificationSignals", renderType: "json" },
7040
+ {
7041
+ key: "disqualified-reason",
7042
+ label: "Disqualified reason",
7043
+ path: "processingState.qualified.data.disqualifiedReason"
7044
+ }
7045
+ ]
6985
7046
  },
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"
7047
+ decisionMakers: {
7048
+ contact: [
7049
+ { key: "name", label: "Name", path: "contact.name" },
7050
+ { key: "title", label: "Title", path: "contact.title" },
7051
+ { key: "email", label: "Email", path: "contact.email" },
7052
+ { key: "linkedin", label: "LinkedIn", path: "contact.linkedinUrl" },
7053
+ {
7054
+ key: "priority-score",
7055
+ label: "Priority",
7056
+ path: "contact.enrichmentData.apollo.priorityScore",
7057
+ renderType: "badge"
7058
+ }
7059
+ ]
6991
7060
  },
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"
7061
+ uploaded: {
7062
+ company: [
7063
+ { key: "name", label: "Company", path: "company.name" },
7064
+ { key: "domain", label: "Domain", path: "company.domain" },
7065
+ {
7066
+ key: "contacts",
7067
+ label: "Contacts",
7068
+ path: "company.enrichmentData.approvedLeadListExport.contacts",
7069
+ renderType: "json"
7070
+ },
7071
+ { key: "score", label: "Score", path: "company.qualificationScore", renderType: "badge", badgeColor: "green" },
7072
+ {
7073
+ key: "approval",
7074
+ label: "Approval",
7075
+ path: "company.enrichmentData.approvedLeadListExport.approvalStatus",
7076
+ renderType: "badge"
7077
+ }
7078
+ ]
6997
7079
  }
6998
- ];
7080
+ };
7081
+ var ACTION_REGISTRY = Object.values(LEAD_GEN_ACTION_ENTRIES);
6999
7082
  var PROSPECTING_STEPS = {
7000
7083
  localServices: {
7001
7084
  sourceCompanies: {
@@ -7005,7 +7088,7 @@ var PROSPECTING_STEPS = {
7005
7088
  outputs: ["company"],
7006
7089
  stageKey: "populated",
7007
7090
  dependencyMode: "per-record-eligibility",
7008
- capabilityKey: "lead-gen.company.source",
7091
+ actionKey: "lead-gen.company.source",
7009
7092
  defaultBatchSize: 100,
7010
7093
  maxBatchSize: 250
7011
7094
  },
@@ -7017,7 +7100,7 @@ var PROSPECTING_STEPS = {
7017
7100
  stageKey: "extracted",
7018
7101
  dependsOn: ["source-companies"],
7019
7102
  dependencyMode: "per-record-eligibility",
7020
- capabilityKey: "lead-gen.company.website-extract",
7103
+ actionKey: "lead-gen.company.website-extract",
7021
7104
  defaultBatchSize: 50,
7022
7105
  maxBatchSize: 100
7023
7106
  },
@@ -7029,7 +7112,7 @@ var PROSPECTING_STEPS = {
7029
7112
  stageKey: "qualified",
7030
7113
  dependsOn: ["analyze-websites"],
7031
7114
  dependencyMode: "per-record-eligibility",
7032
- capabilityKey: "lead-gen.company.qualify",
7115
+ actionKey: "lead-gen.company.qualify",
7033
7116
  defaultBatchSize: 100,
7034
7117
  maxBatchSize: 250
7035
7118
  },
@@ -7041,7 +7124,7 @@ var PROSPECTING_STEPS = {
7041
7124
  stageKey: "discovered",
7042
7125
  dependsOn: ["qualify-companies"],
7043
7126
  dependencyMode: "per-record-eligibility",
7044
- capabilityKey: "lead-gen.contact.discover",
7127
+ actionKey: "lead-gen.contact.discover",
7045
7128
  defaultBatchSize: 50,
7046
7129
  maxBatchSize: 100
7047
7130
  },
@@ -7053,7 +7136,7 @@ var PROSPECTING_STEPS = {
7053
7136
  stageKey: "verified",
7054
7137
  dependsOn: ["find-contacts"],
7055
7138
  dependencyMode: "per-record-eligibility",
7056
- capabilityKey: "lead-gen.contact.verify-email",
7139
+ actionKey: "lead-gen.contact.verify-email",
7057
7140
  defaultBatchSize: 100,
7058
7141
  maxBatchSize: 500
7059
7142
  },
@@ -7065,7 +7148,7 @@ var PROSPECTING_STEPS = {
7065
7148
  stageKey: "personalized",
7066
7149
  dependsOn: ["verify-emails"],
7067
7150
  dependencyMode: "per-record-eligibility",
7068
- capabilityKey: "lead-gen.contact.personalize",
7151
+ actionKey: "lead-gen.contact.personalize",
7069
7152
  defaultBatchSize: 25,
7070
7153
  maxBatchSize: 100
7071
7154
  },
@@ -7077,7 +7160,7 @@ var PROSPECTING_STEPS = {
7077
7160
  stageKey: "uploaded",
7078
7161
  dependsOn: ["personalize"],
7079
7162
  dependencyMode: "per-record-eligibility",
7080
- capabilityKey: "lead-gen.review.outreach-ready",
7163
+ actionKey: "lead-gen.review.outreach-ready",
7081
7164
  defaultBatchSize: 25,
7082
7165
  maxBatchSize: 100
7083
7166
  }
@@ -7091,7 +7174,7 @@ var PROSPECTING_STEPS = {
7091
7174
  outputs: ["company", "contact"],
7092
7175
  stageKey: "populated",
7093
7176
  dependencyMode: "per-record-eligibility",
7094
- capabilityKey: "lead-gen.company.apollo-import",
7177
+ actionKey: "lead-gen.company.apollo-import",
7095
7178
  defaultBatchSize: 250,
7096
7179
  maxBatchSize: 1e3,
7097
7180
  recordColumns: DTC_RECORD_COLUMNS.populated,
@@ -7116,7 +7199,7 @@ var PROSPECTING_STEPS = {
7116
7199
  stageKey: "crawled",
7117
7200
  dependsOn: ["import-apollo-search"],
7118
7201
  dependencyMode: "per-record-eligibility",
7119
- capabilityKey: "lead-gen.company.apify-crawl",
7202
+ actionKey: "lead-gen.company.apify-crawl",
7120
7203
  defaultBatchSize: 50,
7121
7204
  maxBatchSize: 100,
7122
7205
  recordColumns: DTC_RECORD_COLUMNS.crawled,
@@ -7142,7 +7225,7 @@ var PROSPECTING_STEPS = {
7142
7225
  stageKey: "extracted",
7143
7226
  dependsOn: ["apify-crawl"],
7144
7227
  dependencyMode: "per-record-eligibility",
7145
- capabilityKey: "lead-gen.company.website-extract",
7228
+ actionKey: "lead-gen.company.website-extract",
7146
7229
  defaultBatchSize: 50,
7147
7230
  maxBatchSize: 100,
7148
7231
  recordColumns: DTC_RECORD_COLUMNS.extracted
@@ -7156,7 +7239,7 @@ var PROSPECTING_STEPS = {
7156
7239
  stageKey: "qualified",
7157
7240
  dependsOn: ["analyze-websites"],
7158
7241
  dependencyMode: "per-record-eligibility",
7159
- capabilityKey: "lead-gen.company.dtc-subscription-qualify",
7242
+ actionKey: "lead-gen.company.dtc-subscription-qualify",
7160
7243
  defaultBatchSize: 100,
7161
7244
  maxBatchSize: 250,
7162
7245
  recordColumns: DTC_RECORD_COLUMNS.qualified
@@ -7171,7 +7254,7 @@ var PROSPECTING_STEPS = {
7171
7254
  recordEntity: "contact",
7172
7255
  dependsOn: ["score-dtc-fit"],
7173
7256
  dependencyMode: "per-record-eligibility",
7174
- capabilityKey: "lead-gen.contact.apollo-decision-maker-enrich",
7257
+ actionKey: "lead-gen.contact.apollo-decision-maker-enrich",
7175
7258
  defaultBatchSize: 100,
7176
7259
  maxBatchSize: 250,
7177
7260
  recordColumns: DTC_RECORD_COLUMNS.decisionMakers,
@@ -7198,7 +7281,7 @@ var PROSPECTING_STEPS = {
7198
7281
  recordSourceStageKey: "qualified",
7199
7282
  dependsOn: ["enrich-decision-makers"],
7200
7283
  dependencyMode: "per-record-eligibility",
7201
- capabilityKey: "lead-gen.export.list",
7284
+ actionKey: "lead-gen.export.list",
7202
7285
  defaultBatchSize: 100,
7203
7286
  maxBatchSize: 250,
7204
7287
  recordColumns: DTC_RECORD_COLUMNS.uploaded,
@@ -7217,77 +7300,207 @@ var PROSPECTING_STEPS = {
7217
7300
  }
7218
7301
  }
7219
7302
  };
7303
+
7304
+ // ../core/src/business/acquisition/build-templates.ts
7305
+ var BUILD_TEMPLATE_CATALOG = [
7306
+ {
7307
+ id: "local-services",
7308
+ label: "Local Services",
7309
+ description: "Source, analyze, qualify, and personalize local service businesses for outreach.",
7310
+ steps: Object.values(PROSPECTING_STEPS.localServices)
7311
+ },
7312
+ {
7313
+ id: "dtc-subscription-apollo-clickup",
7314
+ label: "DTC Subscription (Apollo + ClickUp)",
7315
+ description: "Import DTC brand leads from Apollo, crawl their websites, score fit, enrich contacts, and export via ClickUp.",
7316
+ steps: Object.values(PROSPECTING_STEPS.dtcApolloClickup)
7317
+ }
7318
+ ];
7319
+ var PROSPECTING_BUILD_TEMPLATE_OPTIONS = BUILD_TEMPLATE_CATALOG.map(({ id, label, description }) => ({
7320
+ id,
7321
+ label,
7322
+ description
7323
+ }));
7324
+ function isProspectingBuildTemplateId(value) {
7325
+ return PROSPECTING_BUILD_TEMPLATE_OPTIONS.some((template) => template.id === value);
7326
+ }
7327
+
7328
+ // ../core/src/organization-model/catalogs/lead-gen.ts
7329
+ var LEAD_GEN_STAGE_CATALOG = {
7330
+ // Prospecting - company population
7331
+ scraped: {
7332
+ key: "scraped",
7333
+ label: "Scraped",
7334
+ description: "Company was scraped from a source directory (Apify actor run).",
7335
+ order: 1,
7336
+ entity: "company"
7337
+ },
7338
+ populated: {
7339
+ key: "populated",
7340
+ label: "Companies found",
7341
+ description: "Companies have been found and added to the lead-gen list.",
7342
+ order: 2,
7343
+ entity: "company"
7344
+ },
7345
+ crawled: {
7346
+ key: "crawled",
7347
+ label: "Websites crawled",
7348
+ description: "Company websites have been crawled (e.g. via Apify) and raw page content stored for downstream LLM analysis.",
7349
+ order: 2.5,
7350
+ entity: "company"
7351
+ },
7352
+ extracted: {
7353
+ key: "extracted",
7354
+ label: "Websites analyzed",
7355
+ description: "Company websites have been analyzed for business signals.",
7356
+ order: 3,
7357
+ entity: "company"
7358
+ },
7359
+ enriched: {
7360
+ key: "enriched",
7361
+ label: "Enriched",
7362
+ description: "Company or contact enriched with third-party data (e.g. Tomba, Anymailfinder).",
7363
+ order: 4,
7364
+ entity: "company"
7365
+ },
7366
+ "decision-makers-enriched": {
7367
+ key: "decision-makers-enriched",
7368
+ label: "Decision-makers found",
7369
+ description: "Decision-maker contacts discovered and attached to a qualified company.",
7370
+ order: 6,
7371
+ entity: "company",
7372
+ recordEntity: "contact",
7373
+ recordStageKey: "discovered"
7374
+ },
7375
+ // Prospecting - contact discovery
7376
+ discovered: {
7377
+ key: "discovered",
7378
+ label: "Decision-makers found",
7379
+ description: "Decision-maker contact details have been found.",
7380
+ order: 5,
7381
+ entity: "contact"
7382
+ },
7383
+ verified: {
7384
+ key: "verified",
7385
+ label: "Emails verified",
7386
+ description: "Contact email addresses have been checked for deliverability.",
7387
+ order: 7,
7388
+ entity: "contact"
7389
+ },
7390
+ // Qualification
7391
+ qualified: {
7392
+ key: "qualified",
7393
+ label: "Companies qualified",
7394
+ description: "Companies have been scored against the qualification criteria.",
7395
+ order: 8,
7396
+ entity: "company"
7397
+ },
7398
+ // Outreach
7399
+ personalized: {
7400
+ key: "personalized",
7401
+ label: "Personalized",
7402
+ description: "Outreach message personalized for the contact (Instantly personalization workflow).",
7403
+ order: 9,
7404
+ entity: "contact"
7405
+ },
7406
+ uploaded: {
7407
+ key: "uploaded",
7408
+ label: "Reviewed and exported",
7409
+ description: "Approved records have been reviewed and exported for handoff.",
7410
+ order: 10,
7411
+ entity: "company",
7412
+ additionalEntities: ["contact"]
7413
+ },
7414
+ interested: {
7415
+ key: "interested",
7416
+ label: "Interested",
7417
+ description: "Contact replied with a positive signal (Instantly reply-handler transition).",
7418
+ order: 11,
7419
+ entity: "contact"
7420
+ }
7421
+ };
7422
+
7423
+ // ../core/src/organization-model/domains/sales.ts
7424
+ var SalesStageSemanticClassSchema = z.enum(["open", "active", "nurturing", "closed_won", "closed_lost"]);
7425
+ var SalesStageSchema = DisplayMetadataSchema.extend({
7426
+ id: ModelIdSchema,
7427
+ order: z.number().int().min(0),
7428
+ semanticClass: SalesStageSemanticClassSchema,
7429
+ surfaceIds: ReferenceIdsSchema,
7430
+ resourceIds: ReferenceIdsSchema
7431
+ });
7220
7432
  z.object({
7221
- listEntityId: ModelIdSchema,
7222
- companyEntityId: ModelIdSchema,
7223
- contactEntityId: ModelIdSchema,
7433
+ id: ModelIdSchema,
7434
+ label: z.string().trim().min(1).max(120),
7224
7435
  description: DescriptionSchema.optional(),
7225
- companyStages: z.array(ProspectingLifecycleStageSchema).min(1),
7226
- contactStages: z.array(ProspectingLifecycleStageSchema).min(1),
7227
- defaultBuildTemplateId: ModelIdSchema,
7228
- buildTemplates: z.array(ProspectingBuildTemplateSchema).min(1)
7436
+ entityId: ModelIdSchema,
7437
+ stages: z.array(SalesStageSchema).min(1)
7229
7438
  });
7230
- function toProspectingLifecycleStage(stage) {
7231
- return {
7232
- id: stage.key,
7233
- label: stage.label,
7234
- order: stage.order
7235
- };
7236
- }
7237
- function leadGenStagesForEntity(entity) {
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);
7239
- }
7240
- var DEFAULT_ORGANIZATION_MODEL_PROSPECTING = {
7241
- companyStages: leadGenStagesForEntity("company"),
7242
- contactStages: leadGenStagesForEntity("contact"),
7243
- buildTemplates: [
7439
+ var CRM_DISCOVERY_REPLIED_STATE = {
7440
+ stateKey: "discovery_replied",
7441
+ label: "Discovery Replied"
7442
+ };
7443
+ var CRM_DISCOVERY_LINK_SENT_STATE = {
7444
+ stateKey: "discovery_link_sent",
7445
+ label: "Discovery Link Sent"
7446
+ };
7447
+ var CRM_DISCOVERY_NUDGING_STATE = {
7448
+ stateKey: "discovery_nudging",
7449
+ label: "Discovery Nudging"
7450
+ };
7451
+ var CRM_DISCOVERY_BOOKING_CANCELLED_STATE = {
7452
+ stateKey: "discovery_booking_cancelled",
7453
+ label: "Discovery Booking Cancelled"
7454
+ };
7455
+ var CRM_REPLY_SENT_STATE = {
7456
+ stateKey: "reply_sent",
7457
+ label: "Reply Sent"
7458
+ };
7459
+ var CRM_FOLLOWUP_1_SENT_STATE = {
7460
+ stateKey: "followup_1_sent",
7461
+ label: "Follow-up 1 Sent"
7462
+ };
7463
+ var CRM_FOLLOWUP_2_SENT_STATE = {
7464
+ stateKey: "followup_2_sent",
7465
+ label: "Follow-up 2 Sent"
7466
+ };
7467
+ var CRM_FOLLOWUP_3_SENT_STATE = {
7468
+ stateKey: "followup_3_sent",
7469
+ label: "Follow-up 3 Sent"
7470
+ };
7471
+ var CRM_PIPELINE_DEFINITION = {
7472
+ pipelineKey: "crm",
7473
+ stages: [
7244
7474
  {
7245
- id: "local-services",
7246
- label: "Local Services Prospecting",
7247
- description: "Curated local-services list build using company sourcing, website analysis, qualification, contact discovery, verification, personalization, and review.",
7248
- steps: [
7249
- PROSPECTING_STEPS.localServices.sourceCompanies,
7250
- PROSPECTING_STEPS.localServices.analyzeWebsites,
7251
- PROSPECTING_STEPS.localServices.qualifyCompanies,
7252
- PROSPECTING_STEPS.localServices.findContacts,
7253
- PROSPECTING_STEPS.localServices.verifyEmails,
7254
- PROSPECTING_STEPS.localServices.personalize,
7255
- PROSPECTING_STEPS.localServices.review
7475
+ stageKey: "interested",
7476
+ label: "Interested",
7477
+ color: "blue",
7478
+ states: [
7479
+ CRM_DISCOVERY_REPLIED_STATE,
7480
+ CRM_DISCOVERY_LINK_SENT_STATE,
7481
+ CRM_DISCOVERY_NUDGING_STATE,
7482
+ CRM_DISCOVERY_BOOKING_CANCELLED_STATE,
7483
+ CRM_REPLY_SENT_STATE,
7484
+ CRM_FOLLOWUP_1_SENT_STATE,
7485
+ CRM_FOLLOWUP_2_SENT_STATE,
7486
+ CRM_FOLLOWUP_3_SENT_STATE
7256
7487
  ]
7257
7488
  },
7258
- {
7259
- id: "dtc-subscription-apollo-clickup",
7260
- label: "DTC Subscription Apollo Export",
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.",
7262
- steps: [
7263
- PROSPECTING_STEPS.dtcApolloClickup.importApolloSearch,
7264
- PROSPECTING_STEPS.dtcApolloClickup.apifyCrawl,
7265
- PROSPECTING_STEPS.dtcApolloClickup.analyzeWebsites,
7266
- PROSPECTING_STEPS.dtcApolloClickup.scoreDtcFit,
7267
- PROSPECTING_STEPS.dtcApolloClickup.enrichDecisionMakers,
7268
- PROSPECTING_STEPS.dtcApolloClickup.reviewAndExport
7269
- ]
7270
- }
7489
+ { stageKey: "proposal", label: "Proposal", color: "yellow", states: [] },
7490
+ { stageKey: "closing", label: "Closing", color: "orange", states: [] },
7491
+ { stageKey: "closed_won", label: "Closed Won", color: "green", states: [] },
7492
+ { stageKey: "closed_lost", label: "Closed Lost", color: "red", states: [] },
7493
+ { stageKey: "nurturing", label: "Nurturing", color: "grape", states: [] }
7271
7494
  ]
7272
7495
  };
7273
7496
 
7274
- // ../core/src/business/acquisition/build-templates.ts
7275
- var PROSPECTING_BUILD_TEMPLATE_OPTIONS = DEFAULT_ORGANIZATION_MODEL_PROSPECTING.buildTemplates.map(
7276
- ({ id, label, description }) => ({
7277
- id,
7278
- label,
7279
- description
7280
- })
7281
- );
7282
- function isProspectingBuildTemplateId(value) {
7283
- return PROSPECTING_BUILD_TEMPLATE_OPTIONS.some((template) => template.id === value);
7284
- }
7497
+ // ../core/src/business/acquisition/api-schemas.ts
7285
7498
  var ProcessingStageStatusSchema = z.enum(["success", "no_result", "skipped", "error"]);
7286
7499
  var LeadGenStageKeySchema = z.string().refine((value) => Object.prototype.hasOwnProperty.call(LEAD_GEN_STAGE_CATALOG, value), {
7287
7500
  message: "processing state key must match LEAD_GEN_STAGE_CATALOG"
7288
7501
  });
7289
- var LeadGenCapabilityKeySchema = z.string().refine((value) => CAPABILITY_REGISTRY.some((c) => c.id === value), {
7290
- message: "capabilityKey must match CAPABILITY_REGISTRY"
7502
+ var LeadGenActionKeySchema = z.string().refine((value) => ACTION_REGISTRY.some((c) => c.id === value), {
7503
+ message: "actionKey must match ACTION_REGISTRY"
7291
7504
  });
7292
7505
  var crmStageKeys = CRM_PIPELINE_DEFINITION.stages.map((stage) => stage.stageKey);
7293
7506
  var crmStateKeys = CRM_PIPELINE_DEFINITION.stages.flatMap((stage) => stage.states.map((state) => state.stateKey));
@@ -7567,7 +7780,7 @@ var BuildPlanSnapshotStepSchema = z.object({
7567
7780
  recordSourceStageKey: LeadGenStageKeySchema.optional(),
7568
7781
  dependsOn: z.array(z.string().trim().min(1).max(100)).optional(),
7569
7782
  dependencyMode: z.literal("per-record-eligibility"),
7570
- capabilityKey: LeadGenCapabilityKeySchema,
7783
+ actionKey: LeadGenActionKeySchema,
7571
7784
  defaultBatchSize: z.number().int().positive(),
7572
7785
  maxBatchSize: z.number().int().positive(),
7573
7786
  recordColumns: z.object({
@@ -8484,6 +8697,22 @@ createAdapter("execution", ["trigger", "triggerAsync"]);
8484
8697
  // src/worker/adapters/email.ts
8485
8698
  createAdapter("email", ["send"]);
8486
8699
 
8700
+ // ../core/src/organization-model/helpers.ts
8701
+ function listAllSystems(model) {
8702
+ const results = [];
8703
+ function walk(map2, prefix) {
8704
+ for (const [localId, system] of Object.entries(map2)) {
8705
+ const fullPath = prefix ? `${prefix}.${localId}` : localId;
8706
+ results.push({ path: fullPath, system });
8707
+ if (system.subsystems) {
8708
+ walk(system.subsystems, fullPath);
8709
+ }
8710
+ }
8711
+ }
8712
+ walk(model.systems, "");
8713
+ return results;
8714
+ }
8715
+
8487
8716
  // ../core/src/platform/registry/validation.ts
8488
8717
  var RegistryValidationError = class extends Error {
8489
8718
  constructor(orgName, resourceId, field, message) {
@@ -8539,25 +8768,27 @@ function getRuntimeResources(resources) {
8539
8768
  }
8540
8769
  function validateResourceGovernance(orgName, deployment, organizationModel = deployment.organizationModel, options = {}) {
8541
8770
  const mode = getResourceValidatorMode(options.mode);
8542
- const omResources = organizationModel?.resources?.entries;
8543
- const omSystems = organizationModel?.systems?.systems;
8771
+ const omResourcesMap = organizationModel?.resources;
8772
+ const omSystemsMap = organizationModel?.systems;
8544
8773
  const issues = [];
8545
- if (!omResources || !omSystems) {
8774
+ if (!omResourcesMap || !omSystemsMap) {
8546
8775
  return { valid: true, mode, issues };
8547
8776
  }
8548
- const systemsById = new Map(omSystems.map((system) => [system.id, system]));
8549
- const activeOmResources = omResources.filter((resource) => resource.status === "active");
8777
+ const systemsById = new Map(
8778
+ listAllSystems({ systems: omSystemsMap }).map(({ path, system }) => [path, system])
8779
+ );
8780
+ const activeOmResources = Object.values(omResourcesMap).filter((resource) => resource.status === "active");
8550
8781
  const omResourcesById = new Map(activeOmResources.map((resource) => [resource.id, resource]));
8551
8782
  const runtimeResources = getRuntimeResources(deployment);
8552
8783
  const runtimeResourcesById = new Map(runtimeResources.map((resource) => [resource.resourceId, resource]));
8553
8784
  for (const resource of activeOmResources) {
8554
- if (!systemsById.has(resource.systemId)) {
8785
+ if (!systemsById.has(resource.systemPath)) {
8555
8786
  addGovernanceIssue(
8556
8787
  issues,
8557
8788
  "missing-om-system",
8558
8789
  orgName,
8559
8790
  resource.id,
8560
- `[${orgName}] OM resource '${resource.id}' references missing System '${resource.systemId}'.`
8791
+ `[${orgName}] OM resource '${resource.id}' references missing system path '${resource.systemPath}'.`
8561
8792
  );
8562
8793
  }
8563
8794
  const runtimeResource = runtimeResourcesById.get(resource.id);
@@ -8580,13 +8811,13 @@ function validateResourceGovernance(orgName, deployment, organizationModel = dep
8580
8811
  `[${orgName}] Resource '${resource.id}' type mismatch: code has '${runtimeResource.type}', OM has '${resource.kind}'.`
8581
8812
  );
8582
8813
  }
8583
- if (runtimeResource.descriptor && runtimeResource.descriptor.systemId !== resource.systemId) {
8814
+ if (runtimeResource.descriptor && runtimeResource.descriptor.systemPath !== resource.systemPath) {
8584
8815
  addGovernanceIssue(
8585
8816
  issues,
8586
8817
  "system-mismatch",
8587
8818
  orgName,
8588
8819
  resource.id,
8589
- `[${orgName}] Resource '${resource.id}' system mismatch: code descriptor has '${runtimeResource.descriptor.systemId}', OM has '${resource.systemId}'.`
8820
+ `[${orgName}] Resource '${resource.id}' system mismatch: code descriptor has '${runtimeResource.descriptor.systemPath}', OM has '${resource.systemPath}'.`
8590
8821
  );
8591
8822
  }
8592
8823
  }