@elevasis/ui 2.33.2 → 2.34.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 (73) hide show
  1. package/dist/api/index.d.ts +9 -2
  2. package/dist/api/index.js +1 -1
  3. package/dist/app/index.css +452 -0
  4. package/dist/app/index.d.ts +1250 -3
  5. package/dist/app/index.js +144 -8
  6. package/dist/charts/index.js +2 -3
  7. package/dist/{chunk-VGU4ZFYZ.js → chunk-3AJVNMY5.js} +45 -28
  8. package/dist/chunk-3QXJK5IY.js +25 -0
  9. package/dist/chunk-4O4MII5S.js +4716 -0
  10. package/dist/{chunk-KW7ZNQD7.js → chunk-5EYJ2GIN.js} +4 -8
  11. package/dist/{chunk-OIBHQH5Q.js → chunk-BPQVTIUP.js} +12 -3
  12. package/dist/{chunk-52K5RFDH.js → chunk-DTFKWZ7A.js} +1098 -2280
  13. package/dist/{chunk-EPTHX4VZ.js → chunk-HRWLKKWM.js} +11 -2
  14. package/dist/{chunk-ZMK5Z6KE.js → chunk-IGDYWFNE.js} +2 -2
  15. package/dist/{chunk-44I4LOH6.js → chunk-IVGI4GDL.js} +3 -3
  16. package/dist/{chunk-4DYOXEH6.js → chunk-LAWLB6CT.js} +1 -1
  17. package/dist/{chunk-TGVAIWIL.js → chunk-LRWTWOGP.js} +3 -3
  18. package/dist/{chunk-O56ESZCQ.js → chunk-MP3GPBPX.js} +3 -3
  19. package/dist/{chunk-T3J6U77J.js → chunk-NLBQTDOW.js} +12 -17
  20. package/dist/{chunk-IBWMR4TI.js → chunk-O6JXQ6UQ.js} +1 -2
  21. package/dist/{chunk-TBVLQRXT.js → chunk-OBBQ2JCM.js} +3 -3
  22. package/dist/{chunk-GWGQI6V4.js → chunk-PLP3NYPL.js} +80 -171
  23. package/dist/{chunk-Z2K2EAPL.js → chunk-RIAXZ6AH.js} +5 -6
  24. package/dist/chunk-SDXSB3HN.js +425 -0
  25. package/dist/{chunk-JA5ECJJB.js → chunk-VTXTZXAU.js} +156 -4
  26. package/dist/{chunk-32I2RCGC.js → chunk-W73ZABT6.js} +1 -1
  27. package/dist/{chunk-2ZZ72TAB.js → chunk-WU4FNWCW.js} +3 -3
  28. package/dist/{chunk-A4VDJJCV.js → chunk-YNWZIWJL.js} +4 -5
  29. package/dist/components/index.d.ts +0 -23
  30. package/dist/components/index.js +27 -448
  31. package/dist/components/navigation/index.js +4 -6
  32. package/dist/features/clients/index.js +7 -12
  33. package/dist/features/crm/index.js +9 -14
  34. package/dist/features/dashboard/index.d.ts +0 -23
  35. package/dist/features/dashboard/index.js +9 -14
  36. package/dist/features/delivery/index.js +8 -13
  37. package/dist/features/knowledge/index.js +5 -7
  38. package/dist/features/lead-gen/index.js +9 -14
  39. package/dist/features/monitoring/index.js +10 -15
  40. package/dist/features/monitoring/requests/index.js +7 -12
  41. package/dist/features/operations/index.d.ts +44 -35
  42. package/dist/features/operations/index.js +12 -17
  43. package/dist/features/settings/index.js +8 -13
  44. package/dist/hooks/index.d.ts +20 -27
  45. package/dist/hooks/index.js +7 -12
  46. package/dist/hooks/operations/command-view/utils/transformCommandViewData.d.ts +20 -27
  47. package/dist/hooks/published.d.ts +20 -27
  48. package/dist/hooks/published.js +7 -12
  49. package/dist/index.d.ts +53 -38
  50. package/dist/index.js +8 -13
  51. package/dist/knowledge/index.d.ts +30 -38
  52. package/dist/knowledge/index.js +36 -200
  53. package/dist/{knowledge-search-index-VMAW7FLR.js → knowledge-search-index-ORIJCEZX.js} +3 -3
  54. package/dist/organization/index.js +1 -2
  55. package/dist/provider/index.d.ts +24 -31
  56. package/dist/provider/index.js +6 -11
  57. package/dist/provider/published.d.ts +24 -31
  58. package/dist/provider/published.js +5 -9
  59. package/dist/test-utils/index.d.ts +2 -0
  60. package/dist/test-utils/index.js +14 -2
  61. package/dist/test-utils/setup.js +38 -0
  62. package/dist/types/index.d.ts +20 -27
  63. package/dist/utils/index.d.ts +0 -23
  64. package/dist/zustand/index.d.ts +15 -2
  65. package/dist/zustand/index.js +35 -1
  66. package/package.json +4 -4
  67. package/dist/chunk-HUJCU55S.js +0 -159
  68. package/dist/chunk-IOXOPMYS.js +0 -145
  69. package/dist/chunk-J2UD7BOH.js +0 -347
  70. package/dist/chunk-QDFJSUG3.js +0 -13
  71. package/dist/chunk-SZHARWKU.js +0 -15
  72. package/dist/chunk-WKW6B5ID.js +0 -29
  73. package/dist/chunk-XCYKC6OZ.js +0 -1
@@ -1,6 +1,148 @@
1
+ import { IconMail, IconSend, IconFileText, IconClock, IconArrowUp, IconMessageCircle, IconRocket, IconEye, IconEdit, IconAlertTriangle, IconRefresh, IconX, IconCheck, IconShieldLock, IconActivity, IconTopologyStar3, IconApps, IconBriefcase, IconBuilding, IconBolt, IconSearch, IconChartBar, IconUsers, IconInfoCircle, IconDatabase, IconGitBranch, IconDashboard, IconBuildingStore, IconUser, IconPlug, IconBrain, IconTargetArrow, IconBook, IconLayoutGrid, IconArchive, IconSettings, IconTool, IconCalendar } from '@tabler/icons-react';
2
+ import { jsx } from 'react/jsx-runtime';
1
3
  import { z } from 'zod';
2
4
 
3
- // ../core/src/organization-model/ontology.ts
5
+ // src/icons/registry.tsx
6
+ var DEFAULT_SEMANTIC_ICON_REGISTRY = {
7
+ // Navigation / app areas
8
+ dashboard: IconDashboard,
9
+ calendar: IconCalendar,
10
+ sales: IconChartBar,
11
+ crm: IconBuildingStore,
12
+ "lead-gen": IconTargetArrow,
13
+ projects: IconBriefcase,
14
+ clients: IconUsers,
15
+ operations: IconTool,
16
+ monitoring: IconChartBar,
17
+ knowledge: IconBrain,
18
+ settings: IconSettings,
19
+ admin: IconShieldLock,
20
+ archive: IconArchive,
21
+ business: IconBriefcase,
22
+ finance: IconChartBar,
23
+ platform: IconLayoutGrid,
24
+ seo: IconSearch,
25
+ // Knowledge kinds
26
+ playbook: IconBook,
27
+ strategy: IconTargetArrow,
28
+ reference: IconFileText,
29
+ // Resource kinds
30
+ agent: IconBrain,
31
+ workflow: IconGitBranch,
32
+ integration: IconPlug,
33
+ database: IconDatabase,
34
+ user: IconUser,
35
+ team: IconUsers,
36
+ // Integration specifics
37
+ gmail: IconMail,
38
+ "google-sheets": IconDatabase,
39
+ attio: IconBuildingStore,
40
+ // Surface / UI views
41
+ overview: IconDashboard,
42
+ "command-view": IconTopologyStar3,
43
+ "command-queue": IconSend,
44
+ pipeline: IconGitBranch,
45
+ lists: IconFileText,
46
+ resources: IconDatabase,
47
+ // Actions
48
+ approve: IconCheck,
49
+ reject: IconX,
50
+ retry: IconRefresh,
51
+ edit: IconEdit,
52
+ view: IconEye,
53
+ launch: IconRocket,
54
+ message: IconMessageCircle,
55
+ escalate: IconAlertTriangle,
56
+ promote: IconArrowUp,
57
+ submit: IconSend,
58
+ email: IconMail,
59
+ // Status
60
+ success: IconCheck,
61
+ error: IconX,
62
+ warning: IconAlertTriangle,
63
+ info: IconInfoCircle,
64
+ pending: IconClock,
65
+ // OM / UI group icons
66
+ bolt: IconBolt,
67
+ building: IconBuilding,
68
+ briefcase: IconBriefcase,
69
+ apps: IconApps,
70
+ graph: IconTopologyStar3,
71
+ shield: IconShieldLock,
72
+ users: IconUsers,
73
+ "chart-bar": IconChartBar,
74
+ search: IconSearch,
75
+ // UI-only om.* group tokens (not in the core enum — kept for registry lookup
76
+ // by components that reference them directly via extendSemanticIconRegistry)
77
+ "om.quick-access": IconBolt,
78
+ "om.profile": IconBuilding,
79
+ "om.business-model": IconBriefcase,
80
+ "om.systems": IconApps,
81
+ "om.graph": IconTopologyStar3,
82
+ "om.governance-wiring": IconShieldLock,
83
+ // Graph node-kind fallback tokens (used internally by knowledge-tree helpers)
84
+ "entity.record": IconActivity,
85
+ "event.lifecycle": IconActivity,
86
+ "policy.governance": IconShieldLock,
87
+ // Compatibility aliases for existing command queue payloads.
88
+ IconCheck,
89
+ IconX,
90
+ IconRefresh,
91
+ IconAlertTriangle,
92
+ IconEdit,
93
+ IconEye,
94
+ IconRocket,
95
+ IconMessageCircle,
96
+ IconArrowUp,
97
+ IconClock,
98
+ IconFileText,
99
+ IconSend,
100
+ IconMail
101
+ };
102
+ var semanticIconRegistry = { ...DEFAULT_SEMANTIC_ICON_REGISTRY };
103
+ function extendSemanticIconRegistry(overrides) {
104
+ semanticIconRegistry = { ...semanticIconRegistry, ...overrides };
105
+ }
106
+ function getSemanticIconComponent(token, fallbackToken) {
107
+ const icon = resolveSemanticIconComponent(token);
108
+ if (icon) return icon;
109
+ if (fallbackToken && semanticIconRegistry[fallbackToken]) return semanticIconRegistry[fallbackToken];
110
+ return IconInfoCircle;
111
+ }
112
+ function resolveSemanticIconComponent(token) {
113
+ if (!token) return null;
114
+ return semanticIconRegistry[token] ?? null;
115
+ }
116
+ function SemanticIcon({
117
+ token,
118
+ fallbackToken,
119
+ size = 16,
120
+ stroke = 1.8,
121
+ className,
122
+ style,
123
+ "aria-hidden": ariaHidden = true
124
+ }) {
125
+ const Icon = getSemanticIconComponent(token, fallbackToken);
126
+ return /* @__PURE__ */ jsx(
127
+ "span",
128
+ {
129
+ className,
130
+ "aria-hidden": ariaHidden,
131
+ style: {
132
+ display: "inline-flex",
133
+ alignItems: "center",
134
+ justifyContent: "center",
135
+ width: size,
136
+ height: size,
137
+ minWidth: size,
138
+ color: "currentColor",
139
+ flexShrink: 0,
140
+ ...style
141
+ },
142
+ children: /* @__PURE__ */ jsx(Icon, { size, stroke })
143
+ }
144
+ );
145
+ }
4
146
  var OntologyKindSchema = z.enum([
5
147
  "object",
6
148
  "link",
@@ -332,40 +474,6 @@ function addLegacyActionProjections(index, diagnostics, sourcesById, actions, en
332
474
  });
333
475
  }
334
476
  }
335
- function addSystemContentProjections(index, diagnostics, sourcesById, systemPath, system, schemaPath) {
336
- const content = system.content ?? {};
337
- for (const [localId, node] of Object.entries(content)) {
338
- if (node.kind !== "schema") continue;
339
- const entries = Object.fromEntries(
340
- Object.entries(content).filter(([, candidate]) => candidate.parentContentId === localId).map(([entryId, candidate]) => [
341
- entryId,
342
- {
343
- label: candidate.label ?? entryId,
344
- type: candidate.type,
345
- ...candidate.description !== void 0 ? { description: candidate.description } : {},
346
- ...candidate.data !== void 0 ? candidate.data : {}
347
- }
348
- ])
349
- );
350
- const catalogType = {
351
- id: formatOntologyId({ scope: systemPath, kind: "catalog", localId }),
352
- label: node.label ?? localId,
353
- description: node.description,
354
- ownerSystemId: systemPath,
355
- kind: node.type,
356
- ...typeof node.data?.["entityId"] === "string" ? { appliesTo: formatOntologyId({ scope: systemPath, kind: "object", localId: node.data["entityId"] }) } : {},
357
- ...Object.keys(entries).length > 0 ? { entries } : {},
358
- ...node.data !== void 0 ? { data: node.data } : {}
359
- };
360
- addRecord(index, diagnostics, sourcesById, "catalogTypes", catalogType, {
361
- source: "legacy.system.content",
362
- path: [...schemaPath, "content", localId],
363
- kind: "projected",
364
- systemPath,
365
- legacyId: `${systemPath}:${localId}`
366
- });
367
- }
368
- }
369
477
  function addSystemScopes(index, diagnostics, sourcesById, systems, prefix, schemaPath) {
370
478
  for (const [key, system] of Object.entries(systems)) {
371
479
  const systemPath = prefix ? `${prefix}.${key}` : key;
@@ -374,7 +482,6 @@ function addSystemScopes(index, diagnostics, sourcesById, systems, prefix, schem
374
482
  ...currentPath,
375
483
  "ontology"
376
484
  ]);
377
- addSystemContentProjections(index, diagnostics, sourcesById, systemPath, system, currentPath);
378
485
  addSystemScopes(index, diagnostics, sourcesById, childSystemsOf(system), systemPath, [
379
486
  ...currentPath,
380
487
  system.systems !== void 0 ? "systems" : "subsystems"
@@ -399,6 +506,7 @@ var ORGANIZATION_MODEL_ICON_TOKENS = [
399
506
  "crm",
400
507
  "lead-gen",
401
508
  "projects",
509
+ "clients",
402
510
  "operations",
403
511
  "monitoring",
404
512
  "knowledge",
@@ -698,265 +806,7 @@ var ActionSchema = z.object({
698
806
  var ActionsDomainSchema = z.record(z.string(), ActionSchema).refine((record) => Object.entries(record).every(([key, entry]) => entry.id === key), {
699
807
  message: "Each action entry id must match its map key"
700
808
  }).default({});
701
- var LEAD_GEN_ACTION_ENTRY_INPUTS = [
702
- {
703
- id: "lead-gen.company.source",
704
- order: 10,
705
- label: "Source companies",
706
- description: "Import source companies from a list provider.",
707
- scope: { domain: "sales" },
708
- resourceId: "lgn-import-workflow",
709
- invocations: [{ kind: "api-endpoint", method: "POST", path: "/api/prospecting/companies/source" }]
710
- },
711
- {
712
- id: "lead-gen.company.apollo-import",
713
- order: 20,
714
- label: "Import from Apollo",
715
- description: "Pull companies and seed contact data from an Apollo search or list.",
716
- scope: { domain: "sales" },
717
- resourceId: "lgn-01c-apollo-import-workflow",
718
- invocations: [{ kind: "api-endpoint", method: "POST", path: "/api/prospecting/companies/apollo-import" }]
719
- },
720
- {
721
- id: "lead-gen.contact.discover",
722
- order: 30,
723
- label: "Discover contact emails",
724
- description: "Find email addresses for contacts at qualified companies.",
725
- scope: { domain: "sales" },
726
- resourceId: "lgn-04-email-discovery-workflow",
727
- invocations: [{ kind: "api-endpoint", method: "POST", path: "/api/prospecting/contacts/discover" }]
728
- },
729
- {
730
- id: "lead-gen.contact.verify-email",
731
- order: 40,
732
- label: "Verify emails",
733
- description: "Check email deliverability before outreach.",
734
- scope: { domain: "sales" },
735
- resourceId: "lgn-05-email-verification-workflow",
736
- invocations: [{ kind: "api-endpoint", method: "POST", path: "/api/prospecting/contacts/verify-email" }]
737
- },
738
- {
739
- id: "lead-gen.company.apify-crawl",
740
- order: 50,
741
- label: "Crawl websites",
742
- description: "Crawl company websites via Apify and store raw page markdown in enrichmentData.websiteCrawl.pages for downstream LLM analysis.",
743
- scope: { domain: "sales" },
744
- resourceId: "lgn-02a-apify-website-crawl-workflow",
745
- invocations: [{ kind: "api-endpoint", method: "POST", path: "/api/prospecting/companies/apify-crawl" }]
746
- },
747
- {
748
- id: "lead-gen.company.website-extract",
749
- order: 60,
750
- label: "Extract website signals",
751
- description: "Scrape and analyze company websites for qualification signals.",
752
- scope: { domain: "sales" },
753
- resourceId: "lgn-02-website-extract-workflow",
754
- invocations: [{ kind: "api-endpoint", method: "POST", path: "/api/prospecting/companies/website-extract" }]
755
- },
756
- {
757
- id: "lead-gen.company.qualify",
758
- order: 70,
759
- label: "Qualify companies",
760
- description: "Score and filter companies against the ICP rubric.",
761
- scope: { domain: "sales" },
762
- resourceId: "lgn-03-company-qualification-workflow",
763
- invocations: [{ kind: "api-endpoint", method: "POST", path: "/api/prospecting/companies/qualify" }]
764
- },
765
- {
766
- id: "lead-gen.company.dtc-subscription-qualify",
767
- order: 80,
768
- label: "Qualify DTC subscription fit",
769
- description: "Classify subscription potential and consumable-product fit for DTC brands.",
770
- scope: { domain: "sales" },
771
- resourceId: "lgn-03b-dtc-subscription-score-workflow",
772
- invocations: [{ kind: "api-endpoint", method: "POST", path: "/api/prospecting/companies/dtc-subscription-qualify" }]
773
- },
774
- {
775
- id: "lead-gen.contact.apollo-decision-maker-enrich",
776
- order: 90,
777
- label: "Enrich decision-makers",
778
- description: "Find and enrich qualified contacts at qualified companies via Apollo.",
779
- scope: { domain: "sales" },
780
- resourceId: "lgn-04b-apollo-decision-maker-enrich-workflow",
781
- invocations: [
782
- { kind: "api-endpoint", method: "POST", path: "/api/prospecting/contacts/apollo-decision-maker-enrich" }
783
- ]
784
- },
785
- {
786
- id: "lead-gen.contact.personalize",
787
- order: 100,
788
- label: "Personalize outreach",
789
- description: "Generate personalized opening lines for each contact.",
790
- scope: { domain: "sales" },
791
- resourceId: "ist-personalization-workflow",
792
- invocations: [{ kind: "api-endpoint", method: "POST", path: "/api/prospecting/contacts/personalize" }]
793
- },
794
- {
795
- id: "lead-gen.review.outreach-ready",
796
- order: 110,
797
- label: "Upload to outreach",
798
- description: "Upload approved contacts to the outreach sequence after QC review.",
799
- scope: { domain: "sales" },
800
- resourceId: "ist-upload-contacts-workflow",
801
- invocations: [{ kind: "api-endpoint", method: "POST", path: "/api/prospecting/review/outreach-ready" }]
802
- },
803
- {
804
- id: "lead-gen.export.list",
805
- order: 120,
806
- label: "Export lead list",
807
- description: "Export approved leads as a downloadable lead list.",
808
- scope: { domain: "sales" },
809
- resourceId: "lgn-06-export-list-workflow",
810
- invocations: [{ kind: "api-endpoint", method: "POST", path: "/api/prospecting/export/list" }]
811
- },
812
- {
813
- id: "lead-gen.company.cleanup",
814
- order: 130,
815
- label: "Clean up companies",
816
- description: "Remove disqualified or duplicate companies from the list.",
817
- scope: { domain: "sales" },
818
- resourceId: "lgn-company-cleanup-workflow",
819
- invocations: [{ kind: "api-endpoint", method: "POST", path: "/api/prospecting/companies/cleanup" }]
820
- }
821
- ];
822
- var LEAD_GEN_ACTION_ENTRIES = Object.fromEntries(
823
- LEAD_GEN_ACTION_ENTRY_INPUTS.map((action) => {
824
- const parsed = ActionSchema.parse(action);
825
- return [parsed.id, parsed];
826
- })
827
- );
828
- var CRM_ACTION_ENTRY_INPUTS = [
829
- {
830
- id: "send_reply",
831
- order: 210,
832
- label: "Send Reply",
833
- description: "Send a contextual reply for an active CRM deal.",
834
- scope: { domain: "sales" },
835
- resourceId: "crm-send-reply-workflow",
836
- affects: ["crm.deal"]
837
- },
838
- {
839
- id: "send_link",
840
- order: 220,
841
- label: "Send Booking Link",
842
- description: "Send a booking link to move a deal toward a scheduled call.",
843
- scope: { domain: "sales" },
844
- resourceId: "crm-send-booking-link-workflow",
845
- affects: ["crm.deal"]
846
- },
847
- {
848
- id: "send_nudge",
849
- order: 230,
850
- label: "Send Nudge",
851
- description: "Send a follow-up nudge for a stalled CRM deal.",
852
- scope: { domain: "sales" },
853
- resourceId: "crm-send-nudge-workflow",
854
- affects: ["crm.deal"]
855
- },
856
- {
857
- id: "rebook",
858
- order: 240,
859
- label: "Rebook",
860
- description: "Rebook a missed or rescheduled CRM appointment.",
861
- scope: { domain: "sales" },
862
- resourceId: "crm-rebook-workflow",
863
- affects: ["crm.deal"]
864
- },
865
- {
866
- id: "move_to_proposal",
867
- order: 250,
868
- label: "Move to Proposal",
869
- description: "Advance a qualified CRM deal into the proposal stage.",
870
- scope: { domain: "sales" },
871
- resourceId: "move_to_proposal-workflow",
872
- affects: ["crm.deal"]
873
- },
874
- {
875
- id: "move_to_closing",
876
- order: 260,
877
- label: "Move to Closing",
878
- description: "Advance a proposal-stage CRM deal into closing.",
879
- scope: { domain: "sales" },
880
- resourceId: "move_to_closing-workflow",
881
- affects: ["crm.deal"]
882
- },
883
- {
884
- id: "move_to_closed_won",
885
- order: 270,
886
- label: "Close Won",
887
- description: "Mark a CRM deal as closed won.",
888
- scope: { domain: "sales" },
889
- resourceId: "move_to_closed_won-workflow",
890
- affects: ["crm.deal"]
891
- },
892
- {
893
- id: "move_to_closed_lost",
894
- order: 280,
895
- label: "Close Lost",
896
- description: "Mark a CRM deal as closed lost.",
897
- scope: { domain: "sales" },
898
- resourceId: "move_to_closed_lost-workflow",
899
- affects: ["crm.deal"]
900
- },
901
- {
902
- id: "move_to_nurturing",
903
- order: 290,
904
- label: "Move to Nurturing",
905
- description: "Move a CRM deal into nurturing for future follow-up.",
906
- scope: { domain: "sales" },
907
- resourceId: "move_to_nurturing-workflow",
908
- affects: ["crm.deal"]
909
- }
910
- ];
911
- var CRM_ACTION_ENTRIES = Object.fromEntries(
912
- CRM_ACTION_ENTRY_INPUTS.map((action) => {
913
- const parsed = ActionSchema.parse(action);
914
- return [parsed.id, parsed];
915
- })
916
- );
917
- var DEFAULT_ORGANIZATION_MODEL_ACTIONS = {
918
- ...LEAD_GEN_ACTION_ENTRIES,
919
- ...CRM_ACTION_ENTRIES
920
- };
921
- var ContentNodeBaseSchema = z.object({
922
- /** Human-readable label for the content node. */
923
- label: z.string().trim().min(1).max(120).meta({ label: "Label" }),
924
- /** Optional one-paragraph description. */
925
- description: z.string().trim().min(1).max(2e3).optional().meta({ label: "Description" }),
926
- /** Optional display order within the system content map. */
927
- order: z.number().int().optional().meta({ label: "Order" }),
928
- /**
929
- * Local NodeId of the parent content node within the SAME system.
930
- * Per B4/L9: MUST resolve to a sibling in the same `system.content` map.
931
- * Per L19: parent and child MUST share the same `kind` (meta-category).
932
- */
933
- parentContentId: z.string().trim().min(1).max(200).optional().meta({ label: "Parent content id" })
934
- });
935
- var ContentNodeSchema = ContentNodeBaseSchema.extend({
936
- /** Meta-category (e.g. 'schema', 'config', 'knowledge', tenant-defined). */
937
- kind: z.string().trim().min(1).max(100).meta({ label: "Kind" }),
938
- /** Specific family within the meta-category (e.g. 'pipeline', 'kv'). */
939
- type: z.string().trim().min(1).max(100).meta({ label: "Type" }),
940
- /** Payload data; validated against registered payloadSchema when (kind, type) is known. */
941
- data: z.record(z.string(), z.unknown()).optional().meta({ label: "Data" })
942
- });
943
- z.object({
944
- /** Meta-category (tenant-defined or registry-shipped). */
945
- kind: z.string().trim().min(1).max(100).meta({ label: "Kind" }),
946
- /** Specific family within the meta-category. */
947
- type: z.string().trim().min(1).max(100).meta({ label: "Type" }),
948
- /** Human-readable label shown in the KB tree and describe views. */
949
- label: z.string().trim().min(1).max(120).meta({ label: "Label" }),
950
- /** Optional description. */
951
- description: z.string().trim().min(1).max(2e3).optional().meta({ label: "Description" }),
952
- /**
953
- * Which KB tree group this extension renders in.
954
- * Per L6: 'business-model' places it alongside Customers / Offerings / Goals.
955
- */
956
- treeGroup: z.union([z.enum(["profile", "business-model", "systems", "graph", "governance-wiring"]), z.string().min(1).max(100)]).meta({ label: "Tree group" }),
957
- /** Untyped payload; shape governed by the registered payloadSchema when available. */
958
- data: z.record(z.string(), z.unknown()).optional().meta({ label: "Data" })
959
- });
809
+ var DEFAULT_ORGANIZATION_MODEL_ACTIONS = {};
960
810
 
961
811
  // ../core/src/organization-model/domains/systems.ts
962
812
  var SystemKindSchema = z.enum(["product", "operational", "platform", "diagnostic"]).meta({ label: "System kind", color: "blue" });
@@ -970,7 +820,7 @@ var SystemPathSchema = z.string().trim().min(1).regex(
970
820
  var UiPositionSchema = z.enum(["sidebar-primary", "sidebar-bottom"]).meta({ label: "UI position" });
971
821
  var NodeIdStringSchema = z.string().trim().min(1).max(200).regex(
972
822
  /^[a-z][a-z-]*:([a-z0-9-]+)(\.[a-z0-9-]+)*(:[a-z0-9.-]+)*$/,
973
- "Node references must use kind:dotted-path (e.g. system:sales.crm or content-node:sales.crm:pipeline-id)"
823
+ "Node references must use kind:dotted-path (e.g. system:sales.crm or resource:lead-gen.company.qualify)"
974
824
  );
975
825
  var SystemUiSchema = z.object({
976
826
  path: PathSchema,
@@ -1044,13 +894,6 @@ var SystemEntrySchema = z.object({
1044
894
  * shared contract records owned by this system.
1045
895
  */
1046
896
  ontology: OntologyScopeSchema.optional(),
1047
- /**
1048
- * @deprecated Compatibility-only bridge for old tenant content nodes and
1049
- * migration readers. New schema/catalog authoring belongs in ontology;
1050
- * new system-local settings belong in config. Bridge nodes are keyed by
1051
- * local NodeId and may still project to content-node:* graph IDs.
1052
- */
1053
- content: z.record(z.string().trim().min(1).max(200), ContentNodeSchema).optional(),
1054
897
  /**
1055
898
  * Recursive child systems, authored via nesting (per L11).
1056
899
  * The key is the local system id; the full path is computed by joining
@@ -1061,7 +904,7 @@ var SystemEntrySchema = z.object({
1061
904
  systems: z.lazy(() => z.record(z.string().trim().min(1).max(100), SystemEntrySchema)).optional(),
1062
905
  /** @deprecated Use systems. Accepted as a compatibility alias during the ontology bridge. */
1063
906
  subsystems: z.lazy(() => z.record(z.string().trim().min(1).max(100), SystemEntrySchema)).optional()
1064
- }).refine((system) => system.label !== void 0 || system.title !== void 0, {
907
+ }).strict().refine((system) => system.label !== void 0 || system.title !== void 0, {
1065
908
  path: ["label"],
1066
909
  message: "System must provide label or title"
1067
910
  }).transform((system) => {
@@ -1140,6 +983,10 @@ var DEFAULT_ORGANIZATION_MODEL_IDENTITY = {
1140
983
  businessHours: {},
1141
984
  clientBrief: ""
1142
985
  };
986
+ var ContractRefSchema = z.string().trim().min(1).max(500).regex(
987
+ /^[A-Za-z0-9@](?:[A-Za-z0-9_./@-]*[A-Za-z0-9_])?\/?[A-Za-z0-9_./@-]*#[A-Za-z_$][A-Za-z0-9_$]*$/,
988
+ "ContractRef must be in the format package/subpath#ExportName (e.g. @repo/elevasis-core/contracts/apollo-import#inputSchema)"
989
+ );
1143
990
  z.enum(["workflow", "agent", "integration", "script"]).meta({ label: "Resource kind", color: "orange" });
1144
991
  var ResourceGovernanceStatusSchema = z.enum(["active", "deprecated", "archived"]).meta({ label: "Governance status", color: "teal" });
1145
992
  var AgentKindSchema = z.enum(["orchestrator", "specialist", "utility", "platform"]).meta({ label: "Agent kind", color: "violet" });
@@ -1168,7 +1015,20 @@ var ResourceOntologyBindingSchema = z.object({
1168
1015
  reads: z.array(OntologyIdSchema).optional(),
1169
1016
  writes: z.array(OntologyIdSchema).optional(),
1170
1017
  usesCatalogs: z.array(OntologyIdSchema).optional(),
1171
- emits: z.array(OntologyIdSchema).optional()
1018
+ emits: z.array(OntologyIdSchema).optional(),
1019
+ /**
1020
+ * Optional typed contract binding for this resource's workflow I/O.
1021
+ * Each ref is a `package/subpath#ExportName` string that resolves to a
1022
+ * Zod schema in `@repo/elevasis-core` (or the consumer's equivalent package).
1023
+ *
1024
+ * Absence of this field preserves all existing behavior — it is additive + optional.
1025
+ * Tier-1 validation (schema.ts): ref-string shape only (browser-safe, no imports).
1026
+ * Tier-2 validation (om:verify): intra-package typed-map resolution asserts ZodType.
1027
+ */
1028
+ contract: z.object({
1029
+ input: ContractRefSchema.optional(),
1030
+ output: ContractRefSchema.optional()
1031
+ }).optional()
1172
1032
  }).superRefine((binding, ctx) => {
1173
1033
  if (binding.primaryAction === void 0) return;
1174
1034
  if (binding.actions?.includes(binding.primaryAction)) return;
@@ -1248,6 +1108,11 @@ var ResourcesDomainSchema = z.record(z.string(), ResourceEntrySchema).refine((re
1248
1108
  message: "Each resource entry id must match its map key"
1249
1109
  }).default({});
1250
1110
  var DEFAULT_ORGANIZATION_MODEL_RESOURCES = {};
1111
+ function defineResources(resources) {
1112
+ return Object.fromEntries(
1113
+ Object.entries(resources).map(([key, resource]) => [key, ResourceEntrySchema.parse(resource)])
1114
+ );
1115
+ }
1251
1116
 
1252
1117
  // ../core/src/organization-model/helpers.ts
1253
1118
  function childSystemsOf2(system) {
@@ -1319,8 +1184,8 @@ function getSystemAncestors(model, path) {
1319
1184
  function listAllSystems(model) {
1320
1185
  const results = [];
1321
1186
  function walk(map, prefix) {
1322
- for (const [localId, system] of Object.entries(map)) {
1323
- const fullPath = prefix ? `${prefix}.${localId}` : localId;
1187
+ for (const [localId2, system] of Object.entries(map)) {
1188
+ const fullPath = prefix ? `${prefix}.${localId2}` : localId2;
1324
1189
  results.push({ path: fullPath, system });
1325
1190
  const childSystems = childSystemsOf2(system);
1326
1191
  if (Object.keys(childSystems).length > 0) {
@@ -1331,15 +1196,6 @@ function listAllSystems(model) {
1331
1196
  walk(model.systems, "");
1332
1197
  return results;
1333
1198
  }
1334
- function getContent(model, qualifiedId) {
1335
- const colonIndex = qualifiedId.indexOf(":");
1336
- if (colonIndex === -1) return void 0;
1337
- const systemPath = qualifiedId.slice(0, colonIndex);
1338
- const localId = qualifiedId.slice(colonIndex + 1);
1339
- if (!systemPath || !localId) return void 0;
1340
- const system = getSystem(model, systemPath);
1341
- return system?.content?.[localId];
1342
- }
1343
1199
  function isPlainJsonObject(value) {
1344
1200
  return typeof value === "object" && value !== null && !Array.isArray(value);
1345
1201
  }
@@ -1354,15 +1210,7 @@ function mergeJsonConfig(base, override) {
1354
1210
  function resolveSystemConfig(model, path) {
1355
1211
  const system = getSystem(model, path);
1356
1212
  if (system === void 0) return {};
1357
- let resolved = {};
1358
- for (const node of Object.values(system.content ?? {})) {
1359
- if (node.kind !== "config" || node.type !== "kv") continue;
1360
- const entries = node.data?.entries;
1361
- if (isPlainJsonObject(entries)) {
1362
- resolved = mergeJsonConfig(resolved, entries);
1363
- }
1364
- }
1365
- return mergeJsonConfig(resolved, system.config ?? {});
1213
+ return mergeJsonConfig({}, system.config ?? {});
1366
1214
  }
1367
1215
  function getResourcesForSystem(model, systemPath, options = {}) {
1368
1216
  const { includeDescendants = false } = options;
@@ -1371,861 +1219,241 @@ function getResourcesForSystem(model, systemPath, options = {}) {
1371
1219
  (r) => r.systemPath === systemPath || includeDescendants && r.systemPath.startsWith(prefix)
1372
1220
  );
1373
1221
  }
1374
- DisplayMetadataSchema.extend({
1375
- id: ModelIdSchema,
1376
- order: z.number().min(0)
1222
+
1223
+ // ../core/src/organization-model/migration-helpers.ts
1224
+ function catalogRecords(model) {
1225
+ return Object.values(compileOrganizationOntology(model).ontology.catalogTypes);
1226
+ }
1227
+ function localId(id) {
1228
+ return parseOntologyId(id).localId;
1229
+ }
1230
+ function systemScope(id, fallback) {
1231
+ return parseOntologyId(id).scope || fallback || "";
1232
+ }
1233
+ function entriesOf(catalog) {
1234
+ return Object.entries(catalog.entries ?? {}).map(([id, value]) => [
1235
+ id,
1236
+ value && typeof value === "object" && !Array.isArray(value) ? value : {}
1237
+ ]);
1238
+ }
1239
+ function stringValue(value) {
1240
+ return typeof value === "string" ? value : void 0;
1241
+ }
1242
+ function stringArray(value) {
1243
+ return Array.isArray(value) ? value.filter((item) => typeof item === "string") : [];
1244
+ }
1245
+ function numberValue(value, fallback = 0) {
1246
+ return typeof value === "number" ? value : fallback;
1247
+ }
1248
+ function stageFromEntry(entryId, entry) {
1249
+ return {
1250
+ id: entryId,
1251
+ label: stringValue(entry.label) ?? entryId,
1252
+ order: numberValue(entry.order),
1253
+ semanticClass: stringValue(entry.semanticClass) ?? "open",
1254
+ surfaceIds: stringArray(entry.surfaceIds),
1255
+ resourceIds: stringArray(entry.resourceIds),
1256
+ color: stringValue(entry.color)
1257
+ };
1258
+ }
1259
+ function appliesToLocalId(catalog) {
1260
+ const appliesTo = catalog.appliesTo;
1261
+ if (appliesTo === void 0) return void 0;
1262
+ return parseOntologyId(appliesTo).localId;
1263
+ }
1264
+ function appliesToEntityKind(catalog) {
1265
+ const id = appliesToLocalId(catalog);
1266
+ if (id === "company" || id === "contact" || id === "project" || id === "milestone" || id === "task") return id;
1267
+ if (id === "deal") return void 0;
1268
+ return void 0;
1269
+ }
1270
+ function getAllPipelines(model) {
1271
+ return catalogRecords(model).filter((catalog) => catalog.kind === "pipeline").map((catalog) => {
1272
+ const pipeline = {
1273
+ id: localId(catalog.id),
1274
+ label: catalog.label ?? localId(catalog.id),
1275
+ ...catalog.description ? { description: catalog.description } : {},
1276
+ entityId: appliesToLocalId(catalog) ?? "",
1277
+ stages: entriesOf(catalog).map(([entryId, entry]) => stageFromEntry(entryId, entry)).sort((a, b) => a.order - b.order || a.id.localeCompare(b.id))
1278
+ };
1279
+ return { systemPath: catalog.ownerSystemId ?? systemScope(catalog.id), pipeline };
1280
+ }).sort((a, b) => a.systemPath.localeCompare(b.systemPath) || a.pipeline.id.localeCompare(b.pipeline.id));
1281
+ }
1282
+ function getAllBuildTemplates(model) {
1283
+ const catalogs = catalogRecords(model);
1284
+ const stepCatalogs = new Map(
1285
+ catalogs.filter((catalog) => catalog.kind === "template-step").map((catalog) => [catalog.id, catalog])
1286
+ );
1287
+ return catalogs.filter((catalog) => catalog.kind === "template").flatMap(
1288
+ (catalog) => entriesOf(catalog).map(([templateId, templateEntry]) => {
1289
+ const stepCatalogId = stringValue(templateEntry.stepCatalog);
1290
+ const stepCatalog = stepCatalogId !== void 0 ? stepCatalogs.get(stepCatalogId) : void 0;
1291
+ const steps = stepCatalog === void 0 ? [] : entriesOf(stepCatalog);
1292
+ return {
1293
+ id: templateId,
1294
+ label: stringValue(templateEntry.label) ?? templateId,
1295
+ ...stringValue(templateEntry.description) ? { description: stringValue(templateEntry.description) } : {},
1296
+ ...stringValue(templateEntry.color) ? { color: stringValue(templateEntry.color) } : {},
1297
+ steps: steps.map(([stepId, step]) => ({
1298
+ id: stepId,
1299
+ label: stringValue(step.label) ?? stepId,
1300
+ ...stringValue(step.description) ? { description: stringValue(step.description) } : {},
1301
+ ...step
1302
+ }))
1303
+ };
1304
+ })
1305
+ ).sort((a, b) => a.id.localeCompare(b.id));
1306
+ }
1307
+ function getAllProspectingStages(model, kind) {
1308
+ return catalogRecords(model).filter((catalog) => catalog.kind === "stage" && appliesToEntityKind(catalog) === kind).flatMap(
1309
+ (catalog) => entriesOf(catalog).map(([entryId, entry]) => ({
1310
+ id: entryId,
1311
+ label: stringValue(entry.label) ?? entryId,
1312
+ order: numberValue(entry.order),
1313
+ ...stringValue(entry.color) ? { color: stringValue(entry.color) } : {},
1314
+ ...stringValue(entry.description) ? { description: stringValue(entry.description) } : {}
1315
+ }))
1316
+ ).sort((a, b) => a.order - b.order || a.id.localeCompare(b.id));
1317
+ }
1318
+ function getLeadGenStageCatalog(model) {
1319
+ const results = {};
1320
+ for (const catalog of catalogRecords(model).filter(
1321
+ (record) => record.kind === "stage" && (record.ownerSystemId ?? systemScope(record.id)) === "sales.lead-gen"
1322
+ )) {
1323
+ const catalogEntity = appliesToEntityKind(catalog);
1324
+ if (catalogEntity !== "company" && catalogEntity !== "contact") continue;
1325
+ for (const [entryId, entry] of entriesOf(catalog)) {
1326
+ const entity = entry.entity === "contact" ? "contact" : entry.entity === "company" ? "company" : catalogEntity;
1327
+ const additionalEntities = stringArray(entry.additionalEntities).filter(
1328
+ (item) => item === "company" || item === "contact"
1329
+ );
1330
+ const recordEntity = entry.recordEntity === "company" || entry.recordEntity === "contact" ? entry.recordEntity : void 0;
1331
+ const recordStageKey = stringValue(entry.recordStageKey);
1332
+ results[entryId] = {
1333
+ key: entryId,
1334
+ label: stringValue(entry.label) ?? entryId,
1335
+ description: stringValue(entry.description) ?? "",
1336
+ order: numberValue(entry.order),
1337
+ entity,
1338
+ ...additionalEntities.length > 0 ? { additionalEntities } : {},
1339
+ ...recordEntity ? { recordEntity } : {},
1340
+ ...recordStageKey ? { recordStageKey } : {}
1341
+ };
1342
+ }
1343
+ }
1344
+ return Object.fromEntries(
1345
+ Object.entries(results).sort(([, a], [, b]) => a.order - b.order || a.key.localeCompare(b.key))
1346
+ );
1347
+ }
1348
+ function getAllProjectStatuses(model, appliesTo) {
1349
+ return catalogRecords(model).filter((catalog) => catalog.kind === "status-flow" && appliesToEntityKind(catalog) === appliesTo).flatMap(
1350
+ (catalog) => entriesOf(catalog).map(([entryId, entry]) => ({
1351
+ id: entryId,
1352
+ label: stringValue(entry.label) ?? entryId,
1353
+ order: numberValue(entry.order),
1354
+ ...stringValue(entry.color) ? { color: stringValue(entry.color) } : {},
1355
+ ...stringValue(entry.description) ? { description: stringValue(entry.description) } : {}
1356
+ }))
1357
+ ).sort((a, b) => a.order - b.order || a.id.localeCompare(b.id));
1358
+ }
1359
+
1360
+ // ../core/src/organization-model/contracts.ts
1361
+ var PROJECTS_VIEW_ACTION_ID = "delivery.projects.view";
1362
+ var OrganizationModelBrandingSchema = z.object({
1363
+ organizationName: LabelSchema,
1364
+ productName: LabelSchema,
1365
+ shortName: z.string().trim().min(1).max(40),
1366
+ description: DescriptionSchema.optional(),
1367
+ logos: z.object({
1368
+ light: z.string().trim().min(1).max(2048).optional(),
1369
+ dark: z.string().trim().min(1).max(2048).optional()
1370
+ }).default({})
1377
1371
  });
1378
- var RecordColumnConfigSchema = z.object({
1379
- key: ModelIdSchema,
1380
- label: z.string().trim().min(1).max(120),
1381
- path: z.string().trim().min(1).max(500),
1382
- width: z.union([z.number().positive(), z.string().trim().min(1).max(100)]).optional(),
1383
- renderType: z.enum(["text", "badge", "datetime", "count", "json"]).optional(),
1384
- badgeColor: z.string().trim().min(1).max(40).optional()
1372
+ var DEFAULT_ORGANIZATION_MODEL_BRANDING = {
1373
+ organizationName: "Default Organization",
1374
+ productName: "Elevasis",
1375
+ shortName: "Elevasis",
1376
+ logos: {}
1377
+ };
1378
+ var SurfaceTypeSchema = z.enum(["page", "dashboard", "graph", "detail", "list", "settings"]).meta({ label: "Surface type", color: "blue" });
1379
+ var SurfaceDefinitionSchema = z.object({
1380
+ id: ModelIdSchema,
1381
+ label: LabelSchema,
1382
+ path: PathSchema,
1383
+ surfaceType: SurfaceTypeSchema,
1384
+ description: DescriptionSchema.optional(),
1385
+ enabled: z.boolean().default(true),
1386
+ devOnly: z.boolean().optional(),
1387
+ icon: IconNameSchema.optional(),
1388
+ systemIds: z.array(ModelIdSchema.meta({ ref: "system" })).default([]),
1389
+ entityIds: z.array(ModelIdSchema.meta({ ref: "entity" })).default([]),
1390
+ resourceIds: z.array(ModelIdSchema.meta({ ref: "resource" })).default([]),
1391
+ actionIds: z.array(ModelIdSchema.meta({ ref: "action" })).default([]),
1392
+ parentId: ModelIdSchema.meta({ ref: "surface" }).optional()
1385
1393
  });
1386
- var RecordColumnsConfigSchema = z.object({
1387
- company: z.array(RecordColumnConfigSchema).optional(),
1388
- contact: z.array(RecordColumnConfigSchema).optional()
1389
- }).refine((columns) => Boolean(columns.company?.length || columns.contact?.length), {
1390
- message: "recordColumns must include at least one entity column set"
1394
+ var SidebarSurfaceTargetsSchema = z.object({
1395
+ systems: z.array(ModelIdSchema.meta({ ref: "system" })).default([]).optional(),
1396
+ entities: z.array(ModelIdSchema.meta({ ref: "entity" })).default([]).optional(),
1397
+ resources: z.array(ModelIdSchema.meta({ ref: "resource" })).default([]).optional(),
1398
+ actions: z.array(ModelIdSchema.meta({ ref: "action" })).default([]).optional()
1399
+ }).default({});
1400
+ var SidebarNodeSchema = z.lazy(
1401
+ () => z.discriminatedUnion("type", [
1402
+ z.object({
1403
+ type: z.literal("group"),
1404
+ label: LabelSchema,
1405
+ description: DescriptionSchema.optional(),
1406
+ icon: IconNameSchema.optional(),
1407
+ order: z.number().int().optional(),
1408
+ children: z.record(z.string(), SidebarNodeSchema).default({})
1409
+ }),
1410
+ z.object({
1411
+ type: z.literal("surface"),
1412
+ label: LabelSchema,
1413
+ path: PathSchema,
1414
+ surfaceType: SurfaceTypeSchema,
1415
+ description: DescriptionSchema.optional(),
1416
+ icon: IconNameSchema.optional(),
1417
+ order: z.number().int().optional(),
1418
+ targets: SidebarSurfaceTargetsSchema.optional(),
1419
+ devOnly: z.boolean().optional(),
1420
+ requiresAdmin: z.boolean().optional()
1421
+ })
1422
+ ])
1423
+ );
1424
+ var SidebarSectionSchema = z.record(z.string(), SidebarNodeSchema).default({});
1425
+ var SidebarNavigationSchema = z.object({
1426
+ primary: SidebarSectionSchema,
1427
+ bottom: SidebarSectionSchema
1428
+ }).default({ primary: {}, bottom: {} });
1429
+ var OrganizationModelNavigationSchema = z.object({
1430
+ sidebar: SidebarNavigationSchema
1431
+ }).default({ sidebar: { primary: {}, bottom: {} } });
1432
+ function getSortedSidebarEntries(nodes) {
1433
+ return Object.entries(nodes).sort(([leftId, left], [rightId, right]) => {
1434
+ const orderDelta = (left.order ?? Number.MAX_SAFE_INTEGER) - (right.order ?? Number.MAX_SAFE_INTEGER);
1435
+ return orderDelta === 0 ? leftId.localeCompare(rightId) : orderDelta;
1436
+ });
1437
+ }
1438
+ z.object({
1439
+ id: ModelIdSchema,
1440
+ label: LabelSchema,
1441
+ placement: z.string().trim().min(1).max(50),
1442
+ surfaceIds: z.array(ModelIdSchema.meta({ ref: "surface" })).default([])
1391
1443
  });
1392
- var CredentialRequirementSchema = z.object({
1393
- key: ModelIdSchema,
1394
- provider: ModelIdSchema,
1395
- credentialType: z.enum(["api-key", "api-key-secret", "oauth", "webhook-secret"]),
1396
- label: z.string().trim().min(1).max(120),
1397
- required: z.boolean(),
1398
- selectionMode: z.enum(["single", "multiple"]).optional(),
1399
- inputPath: z.string().trim().min(1).max(500),
1400
- verifyOnRun: z.boolean().optional()
1401
- });
1402
- var ProspectingBuildTemplateStepSchema = DisplayMetadataSchema.extend({
1403
- id: ModelIdSchema,
1404
- primaryEntity: z.enum(["company", "contact"]),
1405
- outputs: z.array(z.enum(["company", "contact", "export"])).min(1),
1406
- stageKey: ModelIdSchema,
1407
- recordEntity: z.enum(["company", "contact"]).optional(),
1408
- recordsStageKey: ModelIdSchema.optional(),
1409
- recordSourceStageKey: ModelIdSchema.optional(),
1410
- dependsOn: z.array(ModelIdSchema).optional(),
1411
- dependencyMode: z.literal("per-record-eligibility"),
1412
- actionKey: ModelIdSchema,
1413
- defaultBatchSize: z.number().int().positive(),
1414
- maxBatchSize: z.number().int().positive(),
1415
- recordColumns: RecordColumnsConfigSchema.optional(),
1416
- credentialRequirements: z.array(CredentialRequirementSchema).optional()
1417
- }).refine((step) => step.defaultBatchSize <= step.maxBatchSize, {
1418
- message: "defaultBatchSize must be less than or equal to maxBatchSize",
1419
- path: ["defaultBatchSize"]
1420
- });
1421
- DisplayMetadataSchema.extend({
1422
- id: ModelIdSchema,
1423
- steps: z.array(ProspectingBuildTemplateStepSchema).min(1)
1424
- });
1425
- var DTC_RECORD_COLUMNS = {
1426
- populated: {
1427
- company: [
1428
- { key: "name", label: "Company", path: "company.name" },
1429
- { key: "domain", label: "Domain", path: "company.domain" },
1430
- { key: "employee-count", label: "Employees", path: "company.numEmployees", renderType: "count" },
1431
- { key: "apollo-industry", label: "Apollo industry", path: "company.category" },
1432
- { key: "location", label: "Location", path: "company.locationState" }
1433
- ]
1434
- },
1435
- crawled: {
1436
- company: [
1437
- { key: "name", label: "Company", path: "company.name" },
1438
- { key: "domain", label: "Domain", path: "company.domain" },
1439
- { key: "page-count", label: "Pages", path: "company.enrichmentData.websiteCrawl.pageCount", renderType: "count" },
1440
- { key: "crawl-status", label: "Crawl status", path: "processingState.crawled.status", renderType: "badge" }
1441
- ]
1442
- },
1443
- extracted: {
1444
- company: [
1445
- { key: "name", label: "Company", path: "company.name" },
1446
- { key: "domain", label: "Domain", path: "company.domain" },
1447
- { key: "description", label: "Description", path: "company.enrichmentData.websiteCrawl.companyDescription" },
1448
- { key: "services", label: "Services", path: "company.enrichmentData.websiteCrawl.services", renderType: "json" },
1449
- {
1450
- key: "automation-gaps",
1451
- label: "Automation gaps",
1452
- path: "company.enrichmentData.websiteCrawl.automationGaps",
1453
- renderType: "json"
1454
- },
1455
- {
1456
- key: "contact-count",
1457
- label: "Contacts",
1458
- path: "company.enrichmentData.websiteCrawl.emailCount",
1459
- renderType: "count"
1460
- }
1461
- ]
1462
- },
1463
- qualified: {
1464
- company: [
1465
- { key: "name", label: "Company", path: "company.name" },
1466
- { key: "domain", label: "Domain", path: "company.domain" },
1467
- { key: "score", label: "Score", path: "company.qualificationScore", renderType: "badge", badgeColor: "green" },
1468
- { key: "signals", label: "Signals", path: "company.qualificationSignals", renderType: "json" },
1469
- {
1470
- key: "disqualified-reason",
1471
- label: "Disqualified reason",
1472
- path: "processingState.qualified.data.disqualifiedReason"
1473
- }
1474
- ]
1475
- },
1476
- decisionMakers: {
1477
- contact: [
1478
- { key: "name", label: "Name", path: "contact.name" },
1479
- { key: "title", label: "Title", path: "contact.title" },
1480
- { key: "email", label: "Email", path: "contact.email" },
1481
- { key: "linkedin", label: "LinkedIn", path: "contact.linkedinUrl" },
1482
- {
1483
- key: "priority-score",
1484
- label: "Priority",
1485
- path: "contact.enrichmentData.apollo.priorityScore",
1486
- renderType: "badge"
1487
- }
1488
- ]
1489
- },
1490
- uploaded: {
1491
- company: [
1492
- { key: "name", label: "Company", path: "company.name" },
1493
- { key: "domain", label: "Domain", path: "company.domain" },
1494
- {
1495
- key: "contacts",
1496
- label: "Contacts",
1497
- path: "company.enrichmentData.approvedLeadListExport.contacts",
1498
- renderType: "json"
1499
- },
1500
- { key: "score", label: "Score", path: "company.qualificationScore", renderType: "badge", badgeColor: "green" },
1501
- {
1502
- key: "approval",
1503
- label: "Approval",
1504
- path: "company.enrichmentData.approvedLeadListExport.approvalStatus",
1505
- renderType: "badge"
1506
- }
1507
- ]
1508
- }
1509
- };
1510
- Object.values(LEAD_GEN_ACTION_ENTRIES);
1511
- var PROSPECTING_STEPS = {
1512
- localServices: {
1513
- sourceCompanies: {
1514
- id: "source-companies",
1515
- label: "Companies found",
1516
- primaryEntity: "company",
1517
- outputs: ["company"],
1518
- stageKey: "populated",
1519
- dependencyMode: "per-record-eligibility",
1520
- actionKey: "lead-gen.company.source",
1521
- defaultBatchSize: 100,
1522
- maxBatchSize: 250
1523
- },
1524
- analyzeWebsites: {
1525
- id: "analyze-websites",
1526
- label: "Websites analyzed",
1527
- primaryEntity: "company",
1528
- outputs: ["company"],
1529
- stageKey: "extracted",
1530
- dependsOn: ["source-companies"],
1531
- dependencyMode: "per-record-eligibility",
1532
- actionKey: "lead-gen.company.website-extract",
1533
- defaultBatchSize: 50,
1534
- maxBatchSize: 100
1535
- },
1536
- qualifyCompanies: {
1537
- id: "qualify-companies",
1538
- label: "Companies qualified",
1539
- primaryEntity: "company",
1540
- outputs: ["company"],
1541
- stageKey: "qualified",
1542
- dependsOn: ["analyze-websites"],
1543
- dependencyMode: "per-record-eligibility",
1544
- actionKey: "lead-gen.company.qualify",
1545
- defaultBatchSize: 100,
1546
- maxBatchSize: 250
1547
- },
1548
- findContacts: {
1549
- id: "find-contacts",
1550
- label: "Decision-makers found",
1551
- primaryEntity: "contact",
1552
- outputs: ["contact"],
1553
- stageKey: "discovered",
1554
- dependsOn: ["qualify-companies"],
1555
- dependencyMode: "per-record-eligibility",
1556
- actionKey: "lead-gen.contact.discover",
1557
- defaultBatchSize: 50,
1558
- maxBatchSize: 100
1559
- },
1560
- verifyEmails: {
1561
- id: "verify-emails",
1562
- label: "Emails verified",
1563
- primaryEntity: "contact",
1564
- outputs: ["contact"],
1565
- stageKey: "verified",
1566
- dependsOn: ["find-contacts"],
1567
- dependencyMode: "per-record-eligibility",
1568
- actionKey: "lead-gen.contact.verify-email",
1569
- defaultBatchSize: 100,
1570
- maxBatchSize: 500
1571
- },
1572
- personalize: {
1573
- id: "personalize",
1574
- label: "Personalize",
1575
- primaryEntity: "contact",
1576
- outputs: ["contact"],
1577
- stageKey: "personalized",
1578
- dependsOn: ["verify-emails"],
1579
- dependencyMode: "per-record-eligibility",
1580
- actionKey: "lead-gen.contact.personalize",
1581
- defaultBatchSize: 25,
1582
- maxBatchSize: 100
1583
- },
1584
- review: {
1585
- id: "review",
1586
- label: "Reviewed and exported",
1587
- primaryEntity: "contact",
1588
- outputs: ["export"],
1589
- stageKey: "uploaded",
1590
- dependsOn: ["personalize"],
1591
- dependencyMode: "per-record-eligibility",
1592
- actionKey: "lead-gen.review.outreach-ready",
1593
- defaultBatchSize: 25,
1594
- maxBatchSize: 100
1595
- }
1596
- },
1597
- dtcApolloClickup: {
1598
- importApolloSearch: {
1599
- id: "import-apollo-search",
1600
- label: "Companies found",
1601
- description: "Pull companies and seed contact data from a predefined Apollo search or list.",
1602
- primaryEntity: "company",
1603
- outputs: ["company", "contact"],
1604
- stageKey: "populated",
1605
- dependencyMode: "per-record-eligibility",
1606
- actionKey: "lead-gen.company.apollo-import",
1607
- defaultBatchSize: 250,
1608
- maxBatchSize: 1e3,
1609
- recordColumns: DTC_RECORD_COLUMNS.populated,
1610
- credentialRequirements: [
1611
- {
1612
- key: "apollo",
1613
- provider: "apollo",
1614
- credentialType: "api-key-secret",
1615
- label: "Apollo API key",
1616
- required: true,
1617
- selectionMode: "single",
1618
- inputPath: "credential"
1619
- }
1620
- ]
1621
- },
1622
- apifyCrawl: {
1623
- id: "apify-crawl",
1624
- label: "Websites crawled",
1625
- 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.",
1626
- primaryEntity: "company",
1627
- outputs: ["company"],
1628
- stageKey: "crawled",
1629
- dependsOn: ["import-apollo-search"],
1630
- dependencyMode: "per-record-eligibility",
1631
- actionKey: "lead-gen.company.apify-crawl",
1632
- defaultBatchSize: 50,
1633
- maxBatchSize: 100,
1634
- recordColumns: DTC_RECORD_COLUMNS.crawled,
1635
- credentialRequirements: [
1636
- {
1637
- key: "apify",
1638
- provider: "apify",
1639
- credentialType: "api-key-secret",
1640
- label: "Apify API token",
1641
- required: true,
1642
- selectionMode: "single",
1643
- inputPath: "credential",
1644
- verifyOnRun: true
1645
- }
1646
- ]
1647
- },
1648
- analyzeWebsites: {
1649
- id: "analyze-websites",
1650
- label: "Websites analyzed",
1651
- description: "Extract subscription, product, retention, and tech-stack signals from each brand website.",
1652
- primaryEntity: "company",
1653
- outputs: ["company"],
1654
- stageKey: "extracted",
1655
- dependsOn: ["apify-crawl"],
1656
- dependencyMode: "per-record-eligibility",
1657
- actionKey: "lead-gen.company.website-extract",
1658
- defaultBatchSize: 50,
1659
- maxBatchSize: 100,
1660
- recordColumns: DTC_RECORD_COLUMNS.extracted
1661
- },
1662
- scoreDtcFit: {
1663
- id: "score-dtc-fit",
1664
- label: "Companies qualified",
1665
- description: "Classify subscription potential, consumable-product fit, retention maturity, and disqualifiers.",
1666
- primaryEntity: "company",
1667
- outputs: ["company"],
1668
- stageKey: "qualified",
1669
- dependsOn: ["analyze-websites"],
1670
- dependencyMode: "per-record-eligibility",
1671
- actionKey: "lead-gen.company.dtc-subscription-qualify",
1672
- defaultBatchSize: 100,
1673
- maxBatchSize: 250,
1674
- recordColumns: DTC_RECORD_COLUMNS.qualified
1675
- },
1676
- enrichDecisionMakers: {
1677
- id: "enrich-decision-makers",
1678
- label: "Decision-makers found",
1679
- description: "Use Apollo to find qualified contacts at qualified companies - founders, retention leads, lifecycle leads, and marketing owners.",
1680
- primaryEntity: "company",
1681
- outputs: ["contact"],
1682
- stageKey: "decision-makers-enriched",
1683
- recordEntity: "contact",
1684
- dependsOn: ["score-dtc-fit"],
1685
- dependencyMode: "per-record-eligibility",
1686
- actionKey: "lead-gen.contact.apollo-decision-maker-enrich",
1687
- defaultBatchSize: 100,
1688
- maxBatchSize: 250,
1689
- recordColumns: DTC_RECORD_COLUMNS.decisionMakers,
1690
- credentialRequirements: [
1691
- {
1692
- key: "apollo",
1693
- provider: "apollo",
1694
- credentialType: "api-key-secret",
1695
- label: "Apollo API key",
1696
- required: true,
1697
- selectionMode: "single",
1698
- inputPath: "credential"
1699
- }
1700
- ]
1701
- },
1702
- reviewAndExport: {
1703
- id: "review-and-export",
1704
- label: "Reviewed and exported",
1705
- description: "Operator QC approves or rejects qualified companies, then approved records are exported as a lead list with unverified emails.",
1706
- primaryEntity: "company",
1707
- outputs: ["export"],
1708
- stageKey: "uploaded",
1709
- recordsStageKey: "uploaded",
1710
- recordSourceStageKey: "qualified",
1711
- dependsOn: ["enrich-decision-makers"],
1712
- dependencyMode: "per-record-eligibility",
1713
- actionKey: "lead-gen.export.list",
1714
- defaultBatchSize: 100,
1715
- maxBatchSize: 250,
1716
- recordColumns: DTC_RECORD_COLUMNS.uploaded,
1717
- credentialRequirements: [
1718
- {
1719
- key: "clickup",
1720
- provider: "clickup",
1721
- credentialType: "api-key-secret",
1722
- label: "ClickUp API token",
1723
- required: true,
1724
- selectionMode: "single",
1725
- inputPath: "clickupCredential",
1726
- verifyOnRun: true
1727
- }
1728
- ]
1729
- }
1730
- }
1731
- };
1732
-
1733
- // ../core/src/organization-model/catalogs/lead-gen.ts
1734
- var LEAD_GEN_STAGE_CATALOG = {
1735
- // Prospecting - company population
1736
- scraped: {
1737
- key: "scraped",
1738
- label: "Scraped",
1739
- description: "Company was scraped from a source directory (Apify actor run).",
1740
- order: 1,
1741
- entity: "company"
1742
- },
1743
- populated: {
1744
- key: "populated",
1745
- label: "Companies found",
1746
- description: "Companies have been found and added to the lead-gen list.",
1747
- order: 2,
1748
- entity: "company"
1749
- },
1750
- crawled: {
1751
- key: "crawled",
1752
- label: "Websites crawled",
1753
- description: "Company websites have been crawled (e.g. via Apify) and raw page content stored for downstream LLM analysis.",
1754
- order: 2.5,
1755
- entity: "company"
1756
- },
1757
- extracted: {
1758
- key: "extracted",
1759
- label: "Websites analyzed",
1760
- description: "Company websites have been analyzed for business signals.",
1761
- order: 3,
1762
- entity: "company"
1763
- },
1764
- enriched: {
1765
- key: "enriched",
1766
- label: "Enriched",
1767
- description: "Company or contact enriched with third-party data (e.g. Tomba, Anymailfinder).",
1768
- order: 4,
1769
- entity: "company"
1770
- },
1771
- "decision-makers-enriched": {
1772
- key: "decision-makers-enriched",
1773
- label: "Decision-makers found",
1774
- description: "Decision-maker contacts discovered and attached to a qualified company.",
1775
- order: 6,
1776
- entity: "company",
1777
- recordEntity: "contact",
1778
- recordStageKey: "discovered"
1779
- },
1780
- // Prospecting - contact discovery
1781
- discovered: {
1782
- key: "discovered",
1783
- label: "Decision-makers found",
1784
- description: "Decision-maker contact details have been found.",
1785
- order: 5,
1786
- entity: "contact"
1787
- },
1788
- verified: {
1789
- key: "verified",
1790
- label: "Emails verified",
1791
- description: "Contact email addresses have been checked for deliverability.",
1792
- order: 7,
1793
- entity: "contact"
1794
- },
1795
- // Qualification
1796
- qualified: {
1797
- key: "qualified",
1798
- label: "Companies qualified",
1799
- description: "Companies have been scored against the qualification criteria.",
1800
- order: 8,
1801
- entity: "company"
1802
- },
1803
- // Outreach
1804
- personalized: {
1805
- key: "personalized",
1806
- label: "Personalized",
1807
- description: "Outreach message personalized for the contact (Instantly personalization workflow).",
1808
- order: 9,
1809
- entity: "contact"
1810
- },
1811
- uploaded: {
1812
- key: "uploaded",
1813
- label: "Reviewed and exported",
1814
- description: "Approved records have been reviewed and exported for handoff.",
1815
- order: 10,
1816
- entity: "company",
1817
- additionalEntities: ["contact"]
1818
- },
1819
- interested: {
1820
- key: "interested",
1821
- label: "Interested",
1822
- description: "Contact replied with a positive signal (Instantly reply-handler transition).",
1823
- order: 11,
1824
- entity: "contact"
1825
- }
1826
- };
1827
- var SalesStageSemanticClassSchema = z.enum(["open", "active", "nurturing", "closed_won", "closed_lost"]);
1828
- var SalesStageSchema = DisplayMetadataSchema.extend({
1829
- id: ModelIdSchema,
1830
- order: z.number().int().min(0),
1831
- semanticClass: SalesStageSemanticClassSchema,
1832
- surfaceIds: ReferenceIdsSchema,
1833
- resourceIds: ReferenceIdsSchema
1834
- });
1835
- z.object({
1836
- id: ModelIdSchema,
1837
- label: z.string().trim().min(1).max(120),
1838
- description: DescriptionSchema.optional(),
1839
- entityId: ModelIdSchema,
1840
- stages: z.array(SalesStageSchema).min(1)
1841
- });
1842
- function findPipeline(definitions, pipelineKey) {
1843
- return definitions.find((def) => def.pipelineKey === pipelineKey);
1844
- }
1845
- var CRM_DISCOVERY_REPLIED_STATE = {
1846
- stateKey: "discovery_replied",
1847
- label: "Discovery Replied"
1848
- };
1849
- var CRM_DISCOVERY_LINK_SENT_STATE = {
1850
- stateKey: "discovery_link_sent",
1851
- label: "Discovery Link Sent"
1852
- };
1853
- var CRM_DISCOVERY_NUDGING_STATE = {
1854
- stateKey: "discovery_nudging",
1855
- label: "Discovery Nudging"
1856
- };
1857
- var CRM_DISCOVERY_BOOKING_CANCELLED_STATE = {
1858
- stateKey: "discovery_booking_cancelled",
1859
- label: "Discovery Booking Cancelled"
1860
- };
1861
- var CRM_REPLY_SENT_STATE = {
1862
- stateKey: "reply_sent",
1863
- label: "Reply Sent"
1864
- };
1865
- var CRM_FOLLOWUP_1_SENT_STATE = {
1866
- stateKey: "followup_1_sent",
1867
- label: "Follow-up 1 Sent"
1868
- };
1869
- var CRM_FOLLOWUP_2_SENT_STATE = {
1870
- stateKey: "followup_2_sent",
1871
- label: "Follow-up 2 Sent"
1872
- };
1873
- var CRM_FOLLOWUP_3_SENT_STATE = {
1874
- stateKey: "followup_3_sent",
1875
- label: "Follow-up 3 Sent"
1876
- };
1877
- var CRM_PIPELINE_DEFINITION = {
1878
- pipelineKey: "crm",
1879
- label: "CRM",
1880
- entityKey: "crm.deal",
1881
- stages: [
1882
- {
1883
- stageKey: "interested",
1884
- label: "Interested",
1885
- color: "blue",
1886
- states: [
1887
- CRM_DISCOVERY_REPLIED_STATE,
1888
- CRM_DISCOVERY_LINK_SENT_STATE,
1889
- CRM_DISCOVERY_NUDGING_STATE,
1890
- CRM_DISCOVERY_BOOKING_CANCELLED_STATE,
1891
- CRM_REPLY_SENT_STATE,
1892
- CRM_FOLLOWUP_1_SENT_STATE,
1893
- CRM_FOLLOWUP_2_SENT_STATE,
1894
- CRM_FOLLOWUP_3_SENT_STATE
1895
- ]
1896
- },
1897
- { stageKey: "proposal", label: "Proposal", color: "yellow", states: [] },
1898
- { stageKey: "closing", label: "Closing", color: "orange", states: [] },
1899
- { stageKey: "closed_won", label: "Closed Won", color: "green", states: [] },
1900
- { stageKey: "closed_lost", label: "Closed Lost", color: "red", states: [] },
1901
- { stageKey: "nurturing", label: "Nurturing", color: "grape", states: [] }
1902
- ]
1903
- };
1904
- var CRM_PRIORITY_BUCKETS = [
1905
- { bucketKey: "needs_response", label: "Needs Response", rank: 10, color: "red" },
1906
- { bucketKey: "follow_up_due", label: "Follow-up Due", rank: 20, color: "orange" },
1907
- { bucketKey: "waiting", label: "Waiting", rank: 30, color: "blue" },
1908
- { bucketKey: "stale", label: "Stale", rank: 40, color: "gray" },
1909
- { bucketKey: "closed_low", label: "Closed", rank: 50, color: "dark" }
1910
- ];
1911
- var DEFAULT_CRM_PRIORITY_RULE_CONFIG = {
1912
- buckets: CRM_PRIORITY_BUCKETS,
1913
- closedStageKeys: ["closed_won", "closed_lost"],
1914
- followUpAfterDaysByStateKey: {
1915
- discovery_link_sent: 3,
1916
- discovery_nudging: 2,
1917
- reply_sent: 3,
1918
- followup_1_sent: 3,
1919
- followup_2_sent: 5,
1920
- followup_3_sent: 7
1921
- },
1922
- staleAfterDays: 14
1923
- };
1924
- var PENDING_STATE = { stateKey: "pending", label: "Pending" };
1925
- var ACQ_LIST_MEMBERS_LEAD_GEN_PIPELINE = {
1926
- pipelineKey: "lead-gen",
1927
- label: "Lead Generation",
1928
- entityKey: "acq.list-member",
1929
- stages: [
1930
- {
1931
- stageKey: "outreach",
1932
- label: "Outreach",
1933
- states: [
1934
- PENDING_STATE,
1935
- { stateKey: "personalized", label: "Personalized" },
1936
- { stateKey: "uploaded", label: "Uploaded" },
1937
- { stateKey: "interested", label: "Interested" }
1938
- ]
1939
- },
1940
- {
1941
- stageKey: "prospecting",
1942
- label: "Prospecting",
1943
- states: [
1944
- PENDING_STATE,
1945
- { stateKey: "discovered", label: "Discovered" },
1946
- { stateKey: "verified", label: "Verified" }
1947
- ]
1948
- },
1949
- {
1950
- stageKey: "qualification",
1951
- label: "Qualification",
1952
- states: [PENDING_STATE]
1953
- }
1954
- ]
1955
- };
1956
- var ACQ_LIST_COMPANIES_LEAD_GEN_PIPELINE = {
1957
- pipelineKey: "lead-gen",
1958
- label: "Lead Generation",
1959
- entityKey: "acq.list-company",
1960
- stages: [
1961
- {
1962
- stageKey: "outreach",
1963
- label: "Outreach",
1964
- states: [PENDING_STATE, { stateKey: "uploaded", label: "Uploaded" }]
1965
- },
1966
- {
1967
- stageKey: "prospecting",
1968
- label: "Prospecting",
1969
- states: [
1970
- PENDING_STATE,
1971
- { stateKey: "populated", label: "Populated" },
1972
- { stateKey: "extracted", label: "Extracted" }
1973
- ]
1974
- },
1975
- {
1976
- stageKey: "qualification",
1977
- label: "Qualification",
1978
- states: [PENDING_STATE, { stateKey: "qualified", label: "Qualified" }]
1979
- }
1980
- ]
1981
- };
1982
- var LEAD_GEN_PIPELINE_DEFINITIONS = {
1983
- "acq.list-member": [ACQ_LIST_MEMBERS_LEAD_GEN_PIPELINE],
1984
- "acq.list-company": [ACQ_LIST_COMPANIES_LEAD_GEN_PIPELINE]
1985
- };
1986
-
1987
- // ../core/src/organization-model/contracts.ts
1988
- var PROJECTS_VIEW_ACTION_ID = "delivery.projects.view";
1989
-
1990
- // ../core/src/organization-model/content-kinds/registry.ts
1991
- function defineContentType(def) {
1992
- return def;
1993
- }
1994
- var PipelinePayloadSchema = z.object({
1995
- /**
1996
- * Local NodeId of the entity this pipeline applies to (e.g. 'crm.deal').
1997
- * `.meta({ ref: 'entity' })` enables SchemaDrivenFieldList to render a
1998
- * clickable graph link to the referenced entity node.
1999
- */
2000
- entityId: z.string().trim().min(1).max(200).meta({ label: "Entity", ref: "entity", hint: "The entity type this pipeline tracks" }),
2001
- /**
2002
- * Optional Kanban column color token for UI rendering.
2003
- */
2004
- kanbanColor: z.string().trim().min(1).max(40).optional().meta({ label: "Kanban color", hint: "UI color token" })
2005
- });
2006
- var pipelineKind = defineContentType({
2007
- kind: "schema",
2008
- type: "pipeline",
2009
- label: "Pipeline",
2010
- description: "A named progression pipeline that applies to a specific entity type.",
2011
- payloadSchema: PipelinePayloadSchema,
2012
- parentTypes: []
2013
- });
2014
- var StagePayloadSchema = z.object({
2015
- /**
2016
- * Semantic classification for this stage.
2017
- * Drives color, icon, and CRM-priority logic in consuming views.
2018
- * Optional — prospecting stages use data.entityKind instead.
2019
- * Enum aligned with SalesStageSemanticClassSchema (sales.ts).
2020
- */
2021
- semanticClass: z.enum(["open", "active", "nurturing", "closed_won", "closed_lost", "won", "lost", "closed"]).optional().meta({ label: "Semantic class", hint: "Semantic meaning of this stage", color: "blue" })
2022
- });
2023
- var stageKind = defineContentType({
2024
- kind: "schema",
2025
- type: "stage",
2026
- label: "Stage",
2027
- description: "A stage within a pipeline. Must be parented under a schema:pipeline content node.",
2028
- payloadSchema: StagePayloadSchema,
2029
- parentTypes: ["schema:pipeline"]
2030
- });
2031
- var TemplatePayloadSchema = z.object({
2032
- /**
2033
- * Optional description surfaced in the KB describe view and tooling.
2034
- */
2035
- description: z.string().trim().min(1).max(2e3).optional().meta({ label: "Description", hint: "What this template is used for" })
2036
- });
2037
- var templateKind = defineContentType({
2038
- kind: "schema",
2039
- type: "template",
2040
- label: "Template",
2041
- description: "A named build template (e.g. a prospecting pipeline sequence).",
2042
- payloadSchema: TemplatePayloadSchema,
2043
- parentTypes: []
2044
- });
2045
- var TemplateStepPayloadSchema = z.object({
2046
- /**
2047
- * Which entity type this step primarily operates on.
2048
- */
2049
- primaryEntity: z.enum(["company", "contact"]).meta({ label: "Primary entity", hint: "Entity type this step processes", color: "blue" }),
2050
- /**
2051
- * Action key identifying the workflow action executed by this step.
2052
- * `.meta({ ref: 'action' })` enables SchemaDrivenFieldList to render a
2053
- * clickable graph link.
2054
- */
2055
- actionKey: z.string().trim().min(1).max(200).meta({ label: "Action", ref: "action", hint: "Workflow action executed by this step" }),
2056
- /**
2057
- * IDs of sibling step local NodeIds this step depends on.
2058
- */
2059
- dependsOn: z.array(z.string().trim().min(1).max(200)).optional().meta({ label: "Depends on", hint: "Local NodeIds of prerequisite steps" })
2060
- });
2061
- var templateStepKind = defineContentType({
2062
- kind: "schema",
2063
- type: "template-step",
2064
- label: "Template Step",
2065
- description: "A step within a build template. Must be parented under a schema:template content node.",
2066
- payloadSchema: TemplateStepPayloadSchema,
2067
- parentTypes: ["schema:template"]
2068
- });
2069
- var StatusFlowPayloadSchema = z.object({
2070
- /**
2071
- * Which entity scope this status flow governs.
2072
- */
2073
- appliesTo: z.enum(["project", "milestone", "task"]).meta({ label: "Applies to", hint: "Entity scope governed by this status flow", color: "blue" })
2074
- });
2075
- var statusFlowKind = defineContentType({
2076
- kind: "schema",
2077
- type: "status-flow",
2078
- label: "Status Flow",
2079
- description: "A named set of statuses governing a project, milestone, or task entity.",
2080
- payloadSchema: StatusFlowPayloadSchema,
2081
- parentTypes: []
2082
- });
2083
- var StatusPayloadSchema = z.object({
2084
- /**
2085
- * Semantic classification string for this status.
2086
- * Free-form to allow tenant-defined classifications (e.g. 'active', 'blocked',
2087
- * 'completed'). Used by UI to apply color and icon fallbacks.
2088
- * Optional — status nodes may omit this when the label is self-descriptive.
2089
- */
2090
- semanticClass: z.string().trim().min(1).max(100).optional().meta({ label: "Semantic class", hint: "Semantic meaning of this status (e.g. active, blocked, completed)" }),
2091
- /**
2092
- * Optional UI color token override for this status.
2093
- */
2094
- color: z.string().trim().min(1).max(40).optional().meta({ label: "Color", hint: "UI color token" })
2095
- });
2096
- var statusKind = defineContentType({
2097
- kind: "schema",
2098
- type: "status",
2099
- label: "Status",
2100
- description: "A single status within a status flow. Must be parented under a schema:status-flow content node.",
2101
- payloadSchema: StatusPayloadSchema,
2102
- parentTypes: ["schema:status-flow"]
2103
- });
2104
- var ConfigKvPayloadSchema = z.object({
2105
- /**
2106
- * Flat key-value entries. Values are JSON primitives.
2107
- * Keys are short identifiers (e.g. 'maxBatchSize', 'featureEnabled').
2108
- */
2109
- entries: z.record(z.string().trim().min(1).max(200), z.union([z.string(), z.number(), z.boolean(), z.null()])).meta({ label: "Entries", hint: "Key-value configuration entries (string, number, boolean, or null values)" })
2110
- });
2111
- var configKvKind = defineContentType({
2112
- kind: "config",
2113
- type: "kv",
2114
- label: "Key-Value Config",
2115
- description: "A flat key-value configuration store co-located with a system. Values are JSON primitives.",
2116
- payloadSchema: ConfigKvPayloadSchema,
2117
- parentTypes: []
2118
- });
2119
-
2120
- // ../core/src/organization-model/content-kinds/index.ts
2121
- var CONTENT_KIND_REGISTRY = {
2122
- "schema:pipeline": pipelineKind,
2123
- "schema:stage": stageKind,
2124
- "schema:template": templateKind,
2125
- "schema:template-step": templateStepKind,
2126
- "schema:status-flow": statusFlowKind,
2127
- "schema:status": statusKind,
2128
- "config:kv": configKvKind
2129
- };
2130
- function lookupContentType(kind, type) {
2131
- const key = `${kind}:${type}`;
2132
- return CONTENT_KIND_REGISTRY[key];
2133
- }
2134
- var OrganizationModelBrandingSchema = z.object({
2135
- organizationName: LabelSchema,
2136
- productName: LabelSchema,
2137
- shortName: z.string().trim().min(1).max(40),
2138
- description: DescriptionSchema.optional(),
2139
- logos: z.object({
2140
- light: z.string().trim().min(1).max(2048).optional(),
2141
- dark: z.string().trim().min(1).max(2048).optional()
2142
- }).default({})
2143
- });
2144
- var DEFAULT_ORGANIZATION_MODEL_BRANDING = {
2145
- organizationName: "Default Organization",
2146
- productName: "Elevasis",
2147
- shortName: "Elevasis",
2148
- logos: {}
2149
- };
2150
- var SurfaceTypeSchema = z.enum(["page", "dashboard", "graph", "detail", "list", "settings"]).meta({ label: "Surface type", color: "blue" });
2151
- var SurfaceDefinitionSchema = z.object({
2152
- id: ModelIdSchema,
2153
- label: LabelSchema,
2154
- path: PathSchema,
2155
- surfaceType: SurfaceTypeSchema,
2156
- description: DescriptionSchema.optional(),
2157
- enabled: z.boolean().default(true),
2158
- devOnly: z.boolean().optional(),
2159
- icon: IconNameSchema.optional(),
2160
- systemIds: z.array(ModelIdSchema.meta({ ref: "system" })).default([]),
2161
- entityIds: z.array(ModelIdSchema.meta({ ref: "entity" })).default([]),
2162
- resourceIds: z.array(ModelIdSchema.meta({ ref: "resource" })).default([]),
2163
- actionIds: z.array(ModelIdSchema.meta({ ref: "action" })).default([]),
2164
- parentId: ModelIdSchema.meta({ ref: "surface" }).optional()
2165
- });
2166
- var SidebarSurfaceTargetsSchema = z.object({
2167
- systems: z.array(ModelIdSchema.meta({ ref: "system" })).default([]).optional(),
2168
- entities: z.array(ModelIdSchema.meta({ ref: "entity" })).default([]).optional(),
2169
- resources: z.array(ModelIdSchema.meta({ ref: "resource" })).default([]).optional(),
2170
- actions: z.array(ModelIdSchema.meta({ ref: "action" })).default([]).optional()
2171
- }).default({});
2172
- var SidebarNodeSchema = z.lazy(
2173
- () => z.discriminatedUnion("type", [
2174
- z.object({
2175
- type: z.literal("group"),
2176
- label: LabelSchema,
2177
- description: DescriptionSchema.optional(),
2178
- icon: IconNameSchema.optional(),
2179
- order: z.number().int().optional(),
2180
- children: z.record(z.string(), SidebarNodeSchema).default({})
2181
- }),
2182
- z.object({
2183
- type: z.literal("surface"),
2184
- label: LabelSchema,
2185
- path: PathSchema,
2186
- surfaceType: SurfaceTypeSchema,
2187
- description: DescriptionSchema.optional(),
2188
- icon: IconNameSchema.optional(),
2189
- order: z.number().int().optional(),
2190
- targets: SidebarSurfaceTargetsSchema.optional(),
2191
- devOnly: z.boolean().optional(),
2192
- requiresAdmin: z.boolean().optional()
2193
- })
2194
- ])
2195
- );
2196
- var SidebarSectionSchema = z.record(z.string(), SidebarNodeSchema).default({});
2197
- var SidebarNavigationSchema = z.object({
2198
- primary: SidebarSectionSchema,
2199
- bottom: SidebarSectionSchema
2200
- }).default({ primary: {}, bottom: {} });
2201
- var OrganizationModelNavigationSchema = z.object({
2202
- sidebar: SidebarNavigationSchema
2203
- }).default({ sidebar: { primary: {}, bottom: {} } });
2204
- function getSortedSidebarEntries(nodes) {
2205
- return Object.entries(nodes).sort(([leftId, left], [rightId, right]) => {
2206
- const orderDelta = (left.order ?? Number.MAX_SAFE_INTEGER) - (right.order ?? Number.MAX_SAFE_INTEGER);
2207
- return orderDelta === 0 ? leftId.localeCompare(rightId) : orderDelta;
2208
- });
2209
- }
2210
- z.object({
2211
- id: ModelIdSchema,
2212
- label: LabelSchema,
2213
- placement: z.string().trim().min(1).max(50),
2214
- surfaceIds: z.array(ModelIdSchema.meta({ ref: "surface" })).default([])
2215
- });
2216
- var FirmographicsSchema = z.object({
2217
- /** Industry vertical (e.g. "Marketing Agency", "Legal", "Real Estate"). */
2218
- industry: z.string().trim().max(200).optional(),
2219
- /**
2220
- * Company headcount band (e.g. "1–10", "11–50", "51–200", "200+").
2221
- * Free-form string to accommodate any band notation.
2222
- */
2223
- companySize: z.string().trim().max(100).optional(),
2224
- /**
2225
- * Primary geographic region the segment operates in or is targeted from
2226
- * (e.g. "North America", "Europe", "Global").
2227
- */
2228
- region: z.string().trim().max(200).optional()
1444
+ var FirmographicsSchema = z.object({
1445
+ /** Industry vertical (e.g. "Marketing Agency", "Legal", "Real Estate"). */
1446
+ industry: z.string().trim().max(200).optional(),
1447
+ /**
1448
+ * Company headcount band (e.g. "1–10", "11–50", "51–200", "200+").
1449
+ * Free-form string to accommodate any band notation.
1450
+ */
1451
+ companySize: z.string().trim().max(100).optional(),
1452
+ /**
1453
+ * Primary geographic region the segment operates in or is targeted from
1454
+ * (e.g. "North America", "Europe", "Global").
1455
+ */
1456
+ region: z.string().trim().max(200).optional()
2229
1457
  });
2230
1458
  var CustomerSegmentSchema = z.object({
2231
1459
  /** Stable unique identifier for the segment (e.g. "segment-smb-agencies"). */
@@ -2415,13 +1643,10 @@ var KnowledgeTargetKindSchema = z.enum([
2415
1643
  "goal",
2416
1644
  "customer-segment",
2417
1645
  "offering",
2418
- "ontology",
2419
- // D4: content nodes are a valid knowledge target after compound-domain data moved into system.content
2420
- "content-node"
1646
+ "ontology"
2421
1647
  ]).meta({ label: "Target kind" });
2422
1648
  var KnowledgeTargetRefSchema = z.object({
2423
1649
  kind: KnowledgeTargetKindSchema,
2424
- // D4: content-node targets use a qualified id format '<system-path>:<local-content-id>'.
2425
1650
  // Ontology targets use the canonical '<scope>:<kind>/<local-id>' ontology id format.
2426
1651
  // Business-logic validation of target existence is done in OrganizationModelSchema.superRefine.
2427
1652
  id: z.string().trim().min(1).max(300)
@@ -2438,6 +1663,15 @@ var KnowledgeTargetRefSchema = z.object({
2438
1663
  });
2439
1664
  var LegacyKnowledgeLinkSchema = z.object({
2440
1665
  nodeId: z.union([NodeIdStringSchema, z.templateLiteral(["ontology:", OntologyIdSchema])])
1666
+ }).superRefine((link, ctx) => {
1667
+ const [kind] = link.nodeId.split(":");
1668
+ if (!KnowledgeTargetKindSchema.safeParse(kind).success) {
1669
+ ctx.addIssue({
1670
+ code: z.ZodIssueCode.custom,
1671
+ path: ["nodeId"],
1672
+ message: `Unknown knowledge target kind "${kind}"`
1673
+ });
1674
+ }
2441
1675
  });
2442
1676
  var CanonicalKnowledgeLinkSchema = z.object({
2443
1677
  target: KnowledgeTargetRefSchema
@@ -2550,6 +1784,90 @@ var DEFAULT_ORGANIZATION_MODEL_TOPOLOGY = {
2550
1784
  version: 1,
2551
1785
  relationships: {}
2552
1786
  };
1787
+ function idFrom(input) {
1788
+ return typeof input === "string" ? input : input.id;
1789
+ }
1790
+ function parseRef(kind, id) {
1791
+ return OmTopologyNodeRefSchema.parse({ kind, id });
1792
+ }
1793
+ function isNodeRef(input) {
1794
+ return OmTopologyNodeRefSchema.safeParse(input).success;
1795
+ }
1796
+ function isResourceEntry(input) {
1797
+ if (typeof input !== "object" || input === null) return false;
1798
+ const candidate = input;
1799
+ return typeof candidate.id === "string" && typeof candidate.systemPath === "string" && typeof candidate.status === "string" && ["workflow", "agent", "integration", "script"].includes(String(candidate.kind));
1800
+ }
1801
+ var topologyRef = {
1802
+ system: (system) => parseRef("system", idFrom(system)),
1803
+ resource: (resource) => parseRef("resource", idFrom(resource)),
1804
+ ontology: (record) => parseRef("ontology", idFrom(record)),
1805
+ policy: (policy) => parseRef("policy", idFrom(policy)),
1806
+ role: (role) => parseRef("role", idFrom(role)),
1807
+ trigger: (trigger) => parseRef("trigger", idFrom(trigger)),
1808
+ humanCheckpoint: (checkpoint) => parseRef("humanCheckpoint", idFrom(checkpoint)),
1809
+ externalResource: (externalResource) => parseRef("externalResource", idFrom(externalResource))
1810
+ };
1811
+ var topologyRelationship = {
1812
+ triggers: (from, to, options = {}) => defineTopologyRelationship({
1813
+ ...options,
1814
+ from,
1815
+ kind: "triggers",
1816
+ to
1817
+ }),
1818
+ uses: (from, to, options = {}) => defineTopologyRelationship({
1819
+ ...options,
1820
+ from,
1821
+ kind: "uses",
1822
+ to
1823
+ }),
1824
+ approval: (from, to, options = {}) => defineTopologyRelationship({
1825
+ ...options,
1826
+ from,
1827
+ kind: "approval",
1828
+ to
1829
+ }),
1830
+ usesIntegration: (from, integration, options = {}) => defineTopologyRelationship({
1831
+ required: true,
1832
+ ...options,
1833
+ from,
1834
+ kind: "uses",
1835
+ to: integration
1836
+ }),
1837
+ requestsApproval: (from, checkpoint, options = {}) => defineTopologyRelationship({
1838
+ required: true,
1839
+ ...options,
1840
+ from,
1841
+ kind: "approval",
1842
+ to: topologyRef.humanCheckpoint(checkpoint)
1843
+ }),
1844
+ checkpointRoutesTo: (checkpoint, to, options = {}) => defineTopologyRelationship({
1845
+ required: true,
1846
+ ...options,
1847
+ from: topologyRef.humanCheckpoint(checkpoint),
1848
+ kind: "triggers",
1849
+ to
1850
+ })
1851
+ };
1852
+ function compileTopologyNodeRef(input) {
1853
+ if (isNodeRef(input)) return input;
1854
+ if (isResourceEntry(input)) return topologyRef.resource(input);
1855
+ throw new Error("Topology node refs must be typed node objects or serializable { kind, id } refs");
1856
+ }
1857
+ function defineTopologyRelationship(input) {
1858
+ return OmTopologyRelationshipSchema.parse({
1859
+ ...input,
1860
+ from: compileTopologyNodeRef(input.from),
1861
+ to: compileTopologyNodeRef(input.to)
1862
+ });
1863
+ }
1864
+ function defineTopology(relationships) {
1865
+ const entries = Array.isArray(relationships) ? relationships.map((relationship, index) => [`relationship-${index + 1}`, relationship]) : Object.entries(relationships);
1866
+ return OmTopologyDomainSchema.parse({
1867
+ version: 1,
1868
+ relationships: Object.fromEntries(entries.map(([key, relationship]) => [key, defineTopologyRelationship(relationship)]))
1869
+ });
1870
+ }
2553
1871
  var PolicyIdSchema = ModelIdSchema;
2554
1872
  var PolicyApplicabilitySchema = z.object({
2555
1873
  systemIds: z.array(ModelIdSchema.meta({ ref: "system" })).default([]),
@@ -2741,7 +2059,10 @@ var OrganizationModelSchema = OrganizationModelSchemaBase.superRefine((model, ct
2741
2059
  const childSystems = system.systems ?? system.subsystems;
2742
2060
  if (childSystems !== void 0) {
2743
2061
  result.push(
2744
- ...collectAllSystems(childSystems, path, [...currentSchemaPath, system.systems !== void 0 ? "systems" : "subsystems"])
2062
+ ...collectAllSystems(childSystems, path, [
2063
+ ...currentSchemaPath,
2064
+ system.systems !== void 0 ? "systems" : "subsystems"
2065
+ ])
2745
2066
  );
2746
2067
  }
2747
2068
  }
@@ -2762,7 +2083,9 @@ var OrganizationModelSchema = OrganizationModelSchemaBase.superRefine((model, ct
2762
2083
  `System "${system.id}" references unknown parent "${system.parentSystemId}"`
2763
2084
  );
2764
2085
  }
2765
- const hasChildren = Object.keys(system.systems ?? system.subsystems ?? {}).length > 0 || allSystems.some((candidate) => candidate.path.startsWith(`${path}.`) && !candidate.path.slice(path.length + 1).includes("."));
2086
+ const hasChildren = Object.keys(system.systems ?? system.subsystems ?? {}).length > 0 || allSystems.some(
2087
+ (candidate) => candidate.path.startsWith(`${path}.`) && !candidate.path.slice(path.length + 1).includes(".")
2088
+ );
2766
2089
  const contributesRoutePath = system.ui?.path !== void 0 || system.path !== void 0 || !hasChildren;
2767
2090
  if (contributesRoutePath) {
2768
2091
  const effectivePath = system.ui?.path ?? system.path ?? defaultSystemPathFor(path);
@@ -2784,11 +2107,7 @@ var OrganizationModelSchema = OrganizationModelSchemaBase.superRefine((model, ct
2784
2107
  (candidate) => candidate.path.startsWith(`${path}.`) && !candidate.path.slice(path.length + 1).includes(".") && isLifecycleEnabled(candidate.system.lifecycle, candidate.system.enabled)
2785
2108
  );
2786
2109
  if (!hasEnabledDescendant) {
2787
- addIssue(
2788
- ctx,
2789
- [...schemaPath, "lifecycle"],
2790
- `System "${path}" is active but has no active descendants`
2791
- );
2110
+ addIssue(ctx, [...schemaPath, "lifecycle"], `System "${path}" is active but has no active descendants`);
2792
2111
  }
2793
2112
  }
2794
2113
  });
@@ -3020,10 +2339,16 @@ var OrganizationModelSchema = OrganizationModelSchemaBase.superRefine((model, ct
3020
2339
  }
3021
2340
  });
3022
2341
  });
3023
- const stageIds = /* @__PURE__ */ new Set();
3024
2342
  const actionIds = new Set(Object.keys(model.actions));
3025
2343
  const offeringsById = new Map(Object.entries(model.offerings));
3026
2344
  const ontologyCompilation = compileOrganizationOntology(model);
2345
+ const stageIds = /* @__PURE__ */ new Set();
2346
+ for (const catalog of Object.values(ontologyCompilation.ontology.catalogTypes)) {
2347
+ if (catalog.kind !== "stage") continue;
2348
+ for (const stageId of Object.keys(catalog.entries ?? {})) {
2349
+ stageIds.add(stageId);
2350
+ }
2351
+ }
3027
2352
  const ontologyIndexByKind = {
3028
2353
  object: ontologyCompilation.ontology.objectTypes,
3029
2354
  link: ontologyCompilation.ontology.linkTypes,
@@ -3199,13 +2524,7 @@ var OrganizationModelSchema = OrganizationModelSchemaBase.superRefine((model, ct
3199
2524
  if (ontologyIndexByKind[expectedKind][ontologyId] === void 0) {
3200
2525
  addIssue(
3201
2526
  ctx,
3202
- [
3203
- "resources",
3204
- resourceId,
3205
- "ontology",
3206
- bindingKey,
3207
- ...Array.isArray(ids) ? [ontologyIndex] : []
3208
- ],
2527
+ ["resources", resourceId, "ontology", bindingKey, ...Array.isArray(ids) ? [ontologyIndex] : []],
3209
2528
  `Resource "${resourceId}" ontology binding "${bindingKey}" references unknown ${expectedKind} ontology ID "${ontologyId}"`
3210
2529
  );
3211
2530
  }
@@ -3220,6 +2539,23 @@ var OrganizationModelSchema = OrganizationModelSchemaBase.superRefine((model, ct
3220
2539
  validateResourceOntologyBinding(resource.id, "writes", "object", binding.writes);
3221
2540
  validateResourceOntologyBinding(resource.id, "usesCatalogs", "catalog", binding.usesCatalogs);
3222
2541
  validateResourceOntologyBinding(resource.id, "emits", "event", binding.emits);
2542
+ if (binding.contract !== void 0) {
2543
+ const contractEntries = [
2544
+ ["input", binding.contract.input],
2545
+ ["output", binding.contract.output]
2546
+ ];
2547
+ for (const [side, ref] of contractEntries) {
2548
+ if (ref === void 0) continue;
2549
+ const result = ContractRefSchema.safeParse(ref);
2550
+ if (!result.success) {
2551
+ addIssue(
2552
+ ctx,
2553
+ ["resources", resource.id, "ontology", "contract", side],
2554
+ `Resource "${resource.id}" contract.${side} "${ref}" is not a valid ContractRef (expected "package/subpath#ExportName")`
2555
+ );
2556
+ }
2557
+ }
2558
+ }
3223
2559
  });
3224
2560
  Object.values(model.roles).forEach((role) => {
3225
2561
  if (role.heldBy === void 0) return;
@@ -3254,78 +2590,6 @@ var OrganizationModelSchema = OrganizationModelSchemaBase.superRefine((model, ct
3254
2590
  }
3255
2591
  });
3256
2592
  });
3257
- function validateSystemContent(system, systemPath) {
3258
- const childSystems = system.systems ?? system.subsystems;
3259
- const childKey = system.systems !== void 0 ? "systems" : "subsystems";
3260
- const content = system.content;
3261
- if (content === void 0 || Object.keys(content).length === 0) {
3262
- if (childSystems !== void 0) {
3263
- Object.entries(childSystems).forEach(([childLocalId, child]) => {
3264
- validateSystemContent(child, [...systemPath, childKey, childLocalId]);
3265
- });
3266
- }
3267
- return;
3268
- }
3269
- Object.entries(content).forEach(([localId, node]) => {
3270
- if (node.parentContentId !== void 0 && !(node.parentContentId in content)) {
3271
- addIssue(
3272
- ctx,
3273
- [...systemPath, "content", localId, "parentContentId"],
3274
- `Content node "${localId}" parentContentId "${node.parentContentId}" does not resolve within the same system`
3275
- );
3276
- }
3277
- });
3278
- Object.entries(content).forEach(([localId, node]) => {
3279
- const visited = /* @__PURE__ */ new Set();
3280
- let currentId = node.parentContentId;
3281
- while (currentId !== void 0) {
3282
- if (currentId === localId || visited.has(currentId)) {
3283
- addIssue(
3284
- ctx,
3285
- [...systemPath, "content", localId, "parentContentId"],
3286
- `Content node "${localId}" has a parentContentId cycle`
3287
- );
3288
- break;
3289
- }
3290
- visited.add(currentId);
3291
- currentId = content[currentId]?.parentContentId;
3292
- }
3293
- });
3294
- Object.entries(content).forEach(([localId, node]) => {
3295
- const childDef = lookupContentType(node.kind, node.type);
3296
- if (childDef !== void 0 && node.data !== void 0) {
3297
- const result = childDef.payloadSchema.safeParse(node.data);
3298
- if (!result.success) {
3299
- addIssue(
3300
- ctx,
3301
- [...systemPath, "content", localId, "data"],
3302
- `Content node "${localId}" (${node.kind}:${node.type}) data failed payload validation: ${result.error.message}`
3303
- );
3304
- }
3305
- }
3306
- if (node.parentContentId !== void 0 && childDef !== void 0) {
3307
- const parentNode = content[node.parentContentId];
3308
- if (parentNode !== void 0) {
3309
- const parentDef = lookupContentType(parentNode.kind, parentNode.type);
3310
- if (parentDef !== void 0 && childDef.kind !== parentDef.kind) {
3311
- addIssue(
3312
- ctx,
3313
- [...systemPath, "content", localId, "parentContentId"],
3314
- `Content node "${localId}" kind "${childDef.kind}" cannot parent under "${node.parentContentId}" kind "${parentDef.kind}": parentContentId must be same-meta-kind (per L19)`
3315
- );
3316
- }
3317
- }
3318
- }
3319
- });
3320
- if (childSystems !== void 0) {
3321
- Object.entries(childSystems).forEach(([childLocalId, child]) => {
3322
- validateSystemContent(child, [...systemPath, childKey, childLocalId]);
3323
- });
3324
- }
3325
- }
3326
- Object.entries(model.systems).forEach(([systemKey, system]) => {
3327
- validateSystemContent(system, ["systems", systemKey]);
3328
- });
3329
2593
  for (const diagnostic of ontologyCompilation.diagnostics) {
3330
2594
  addIssue(ctx, diagnostic.path, diagnostic.message);
3331
2595
  }
@@ -3348,9 +2612,8 @@ var OrganizationGraphNodeKindSchema = z.enum([
3348
2612
  "goal",
3349
2613
  "surface",
3350
2614
  "navigation-group",
3351
- // Phase 3 preview Phase 4 populates via graph projection of system.content entries.
3352
- "ontology",
3353
- "content-node"
2615
+ // Ontology records are projected from compiled System.ontology scopes.
2616
+ "ontology"
3354
2617
  ]);
3355
2618
  var OrganizationGraphEdgeKindSchema = z.enum([
3356
2619
  "contains",
@@ -3379,133 +2642,27 @@ var OrganizationGraphNodeSchema = z.object({
3379
2642
  description: DescriptionSchema.optional(),
3380
2643
  icon: IconNameSchema.optional(),
3381
2644
  enabled: z.boolean().optional(),
3382
- ontologyKind: z.string().trim().min(1).max(80).optional(),
3383
- resourceType: z.enum(["workflow", "agent", "trigger", "integration", "external", "human_checkpoint", "script"]).optional()
3384
- });
3385
- var OrganizationGraphEdgeSchema = z.object({
3386
- id: z.string().trim().min(1).max(900),
3387
- kind: OrganizationGraphEdgeKindSchema,
3388
- sourceId: z.string().trim().min(1).max(400),
3389
- targetId: z.string().trim().min(1).max(400),
3390
- label: z.string().trim().min(1).max(120).optional(),
3391
- relationshipType: z.enum(["triggers", "uses", "approval"]).optional()
3392
- });
3393
- var OrganizationGraphSchema = z.object({
3394
- version: z.literal(1),
3395
- organizationModelVersion: OrganizationModelSchema.shape.version,
3396
- nodes: z.array(OrganizationGraphNodeSchema),
3397
- edges: z.array(OrganizationGraphEdgeSchema)
3398
- });
3399
- var BuildOrganizationGraphInputSchema = z.object({
3400
- organizationModel: OrganizationModelSchema,
3401
- commandViewData: z.unknown().optional()
3402
- });
3403
-
3404
- // ../core/src/organization-model/migration-helpers.ts
3405
- function getAllPipelines(model) {
3406
- const results = [];
3407
- for (const { path: systemPath, system } of listAllSystems(model)) {
3408
- const content = system.content ?? {};
3409
- for (const [localId, node] of Object.entries(content)) {
3410
- if (node.kind !== "schema" || node.type !== "pipeline") continue;
3411
- const data = node.data ?? {};
3412
- const stages = Object.entries(content).filter(([, s]) => s.kind === "schema" && s.type === "stage" && s.parentContentId === localId).map(([stageLocalId, s]) => {
3413
- const sd = s.data ?? {};
3414
- return {
3415
- id: stageLocalId,
3416
- label: s.label ?? stageLocalId,
3417
- order: typeof sd.order === "number" ? sd.order : 0,
3418
- semanticClass: sd.semanticClass ?? "open",
3419
- surfaceIds: Array.isArray(sd.surfaceIds) ? sd.surfaceIds : [],
3420
- resourceIds: Array.isArray(sd.resourceIds) ? sd.resourceIds : [],
3421
- color: typeof sd.color === "string" ? sd.color : void 0
3422
- };
3423
- }).sort((a, b) => a.order - b.order);
3424
- const pipeline = {
3425
- id: localId,
3426
- label: node.label ?? localId,
3427
- entityId: typeof data.entityId === "string" ? data.entityId : "",
3428
- stages,
3429
- ...typeof node.description === "string" ? { description: node.description } : {}
3430
- };
3431
- results.push({ systemPath, pipeline });
3432
- }
3433
- }
3434
- return results;
3435
- }
3436
- function getAllBuildTemplates(model) {
3437
- const results = [];
3438
- for (const { system } of listAllSystems(model)) {
3439
- const content = system.content ?? {};
3440
- for (const [localId, node] of Object.entries(content)) {
3441
- if (node.kind !== "schema" || node.type !== "template") continue;
3442
- const nd = node.data ?? {};
3443
- const steps = Object.entries(content).filter(([, s]) => s.kind === "schema" && s.type === "template-step" && s.parentContentId === localId).map(([stepLocalId, s]) => {
3444
- const sd = s.data ?? {};
3445
- return {
3446
- id: stepLocalId,
3447
- label: s.label ?? stepLocalId,
3448
- ...s.description ? { description: s.description } : {},
3449
- // Pass through all data fields — template-step payload is richer than Pipeline;
3450
- // Bridge readers preserve the historical shape for round-trip fidelity.
3451
- ...sd
3452
- };
3453
- });
3454
- results.push({
3455
- id: localId,
3456
- label: node.label ?? localId,
3457
- ...node.description ? { description: node.description } : {},
3458
- ...typeof nd.color === "string" ? { color: nd.color } : {},
3459
- // BuildTemplate requires steps array — cast via spread; Wave 4 adds type-safe assertions.
3460
- steps
3461
- });
3462
- }
3463
- }
3464
- return results;
3465
- }
3466
- function getAllProspectingStages(model, kind) {
3467
- const results = [];
3468
- for (const { system } of listAllSystems(model)) {
3469
- const content = system.content ?? {};
3470
- for (const [localId, node] of Object.entries(content)) {
3471
- if (node.kind !== "schema" || node.type !== "stage") continue;
3472
- const sd = node.data ?? {};
3473
- if (sd.entityKind !== kind) continue;
3474
- results.push({
3475
- id: localId,
3476
- label: node.label ?? localId,
3477
- order: typeof sd.order === "number" ? sd.order : 0,
3478
- ...typeof sd.color === "string" ? { color: sd.color } : {},
3479
- ...node.description ? { description: node.description } : {}
3480
- });
3481
- }
3482
- }
3483
- return results.sort((a, b) => a.order - b.order);
3484
- }
3485
- function getAllProjectStatuses(model, appliesTo) {
3486
- const results = [];
3487
- for (const { system } of listAllSystems(model)) {
3488
- const content = system.content ?? {};
3489
- for (const [flowLocalId, flowNode] of Object.entries(content)) {
3490
- if (flowNode.kind !== "schema" || flowNode.type !== "status-flow") continue;
3491
- const fd = flowNode.data ?? {};
3492
- if (fd.appliesTo !== appliesTo) continue;
3493
- for (const [statusLocalId, statusNode] of Object.entries(content)) {
3494
- if (statusNode.kind !== "schema" || statusNode.type !== "status") continue;
3495
- if (statusNode.parentContentId !== flowLocalId) continue;
3496
- const sd = statusNode.data ?? {};
3497
- results.push({
3498
- id: statusLocalId,
3499
- label: statusNode.label ?? statusLocalId,
3500
- order: typeof sd.order === "number" ? sd.order : 0,
3501
- ...typeof sd.color === "string" ? { color: sd.color } : {},
3502
- ...statusNode.description ? { description: statusNode.description } : {}
3503
- });
3504
- }
3505
- }
3506
- }
3507
- return results.sort((a, b) => a.order - b.order);
3508
- }
2645
+ ontologyKind: z.string().trim().min(1).max(80).optional(),
2646
+ resourceType: z.enum(["workflow", "agent", "trigger", "integration", "external", "human_checkpoint", "script"]).optional()
2647
+ });
2648
+ var OrganizationGraphEdgeSchema = z.object({
2649
+ id: z.string().trim().min(1).max(900),
2650
+ kind: OrganizationGraphEdgeKindSchema,
2651
+ sourceId: z.string().trim().min(1).max(400),
2652
+ targetId: z.string().trim().min(1).max(400),
2653
+ label: z.string().trim().min(1).max(120).optional(),
2654
+ relationshipType: z.enum(["triggers", "uses", "approval"]).optional()
2655
+ });
2656
+ var OrganizationGraphSchema = z.object({
2657
+ version: z.literal(1),
2658
+ organizationModelVersion: OrganizationModelSchema.shape.version,
2659
+ nodes: z.array(OrganizationGraphNodeSchema),
2660
+ edges: z.array(OrganizationGraphEdgeSchema)
2661
+ });
2662
+ var BuildOrganizationGraphInputSchema = z.object({
2663
+ organizationModel: OrganizationModelSchema,
2664
+ commandViewData: z.unknown().optional()
2665
+ });
3509
2666
 
3510
2667
  // ../core/src/organization-model/graph/build.ts
3511
2668
  function nodeId(kind, sourceId) {
@@ -3979,7 +3136,7 @@ function buildOrganizationGraph(input) {
3979
3136
  }
3980
3137
  if (entity.stateCatalogId === "lead-gen.company" || entity.stateCatalogId === "lead-gen.contact") {
3981
3138
  const leadGenEntity = entity.stateCatalogId === "lead-gen.company" ? "company" : "contact";
3982
- for (const stage of Object.values(LEAD_GEN_STAGE_CATALOG).sort(
3139
+ for (const stage of Object.values(getLeadGenStageCatalog(organizationModel)).sort(
3983
3140
  (a, b) => a.order - b.order || a.key.localeCompare(b.key)
3984
3141
  )) {
3985
3142
  if (stage.entity !== leadGenEntity && !(stage.additionalEntities ?? []).includes(leadGenEntity)) continue;
@@ -4283,49 +3440,6 @@ function buildOrganizationGraph(input) {
4283
3440
  targetId: id
4284
3441
  });
4285
3442
  }
4286
- for (const { path, system } of listAllSystems(organizationModel).sort((a, b) => a.path.localeCompare(b.path))) {
4287
- const contentMap = system.content ?? {};
4288
- const systemSpineId = nodeId("system", path);
4289
- for (const [localId, contentNode] of Object.entries(contentMap).sort(([a], [b]) => a.localeCompare(b))) {
4290
- const contentNodeGraphId = `content-node:${path}:${localId}`;
4291
- pushUniqueNode(nodes, nodeIds, {
4292
- id: contentNodeGraphId,
4293
- kind: "content-node",
4294
- label: contentNode.label,
4295
- sourceId: `${path}:${localId}`,
4296
- description: contentNode.description
4297
- // Spread contentKind and contentType into attributes; the node schema
4298
- // does not have custom attribute slots, so we encode them in the label
4299
- // suffix for now. The actual kind/type are recoverable from sourceId +
4300
- // the registry lookup by consumers.
4301
- });
4302
- pushUniqueEdge(edges, edgeIds, {
4303
- id: edgeId("contains", systemSpineId, contentNodeGraphId, "system-content"),
4304
- kind: "contains",
4305
- sourceId: systemSpineId,
4306
- targetId: contentNodeGraphId
4307
- });
4308
- if (contentNode.parentContentId) {
4309
- const parentContentNodeGraphId = `content-node:${path}:${contentNode.parentContentId}`;
4310
- pushUniqueEdge(edges, edgeIds, {
4311
- id: edgeId("contains", parentContentNodeGraphId, contentNodeGraphId, "content-parent"),
4312
- kind: "contains",
4313
- sourceId: parentContentNodeGraphId,
4314
- targetId: contentNodeGraphId
4315
- });
4316
- }
4317
- if (contentNode.kind === "schema" && contentNode.type === "pipeline" && contentNode.data && typeof contentNode.data["entityId"] === "string") {
4318
- const targetEntityId = nodeId("entity", contentNode.data["entityId"]);
4319
- pushUniqueEdge(edges, edgeIds, {
4320
- id: edgeId("references", contentNodeGraphId, targetEntityId, "pipeline-entity"),
4321
- kind: "references",
4322
- sourceId: contentNodeGraphId,
4323
- targetId: targetEntityId,
4324
- label: "applies to entity"
4325
- });
4326
- }
4327
- }
4328
- }
4329
3443
  for (const template of getAllBuildTemplates(organizationModel).sort((a, b) => a.id.localeCompare(b.id))) {
4330
3444
  const steps = template.steps;
4331
3445
  const stepById = new Map(steps.map((s) => [s.id, s]));
@@ -4411,863 +3525,567 @@ function buildOrganizationGraph(input) {
4411
3525
 
4412
3526
  // ../core/src/organization-model/defaults.ts
4413
3527
  var DEFAULT_ORGANIZATION_MODEL_KNOWLEDGE = {};
4414
- var DEFAULT_ORGANIZATION_MODEL_ENTITIES2 = DEFAULT_ORGANIZATION_MODEL_ENTITIES;
3528
+ var DEFAULT_ORGANIZATION_MODEL_ENTITIES2 = {};
4415
3529
  var DEFAULT_ORGANIZATION_MODEL_NAVIGATION = {
4416
3530
  sidebar: {
4417
- primary: {
4418
- dashboard: {
4419
- type: "surface",
4420
- label: "Dashboard",
4421
- path: "/",
4422
- surfaceType: "dashboard",
4423
- icon: "dashboard",
4424
- order: 10,
4425
- targets: { systems: ["dashboard"] }
4426
- },
4427
- business: {
4428
- type: "group",
4429
- label: "Business",
4430
- icon: "briefcase",
4431
- order: 20,
4432
- children: {
4433
- sales: {
4434
- type: "surface",
4435
- label: "Sales",
4436
- path: "/sales",
4437
- surfaceType: "page",
4438
- icon: "sales",
4439
- order: 10,
4440
- targets: { systems: ["sales"] }
4441
- },
4442
- clients: {
4443
- type: "surface",
4444
- label: "Clients",
4445
- path: "/clients",
4446
- surfaceType: "list",
4447
- icon: "projects",
4448
- order: 20,
4449
- targets: { systems: ["clients"] }
4450
- },
4451
- projects: {
4452
- type: "surface",
4453
- label: "Projects",
4454
- path: "/projects",
4455
- surfaceType: "page",
4456
- icon: "projects",
4457
- order: 30,
4458
- targets: { systems: ["projects"] }
4459
- }
4460
- }
4461
- },
4462
- operations: {
4463
- type: "group",
4464
- label: "Operations",
4465
- icon: "operations",
4466
- order: 30,
4467
- children: {
4468
- "operations-overview": {
4469
- type: "surface",
4470
- label: "Overview",
4471
- path: "/operations",
4472
- surfaceType: "page",
4473
- order: 10,
4474
- targets: { systems: ["operations.overview"] }
4475
- },
4476
- "operations-systems": {
4477
- type: "surface",
4478
- label: "Systems",
4479
- path: "/operations/systems",
4480
- surfaceType: "page",
4481
- order: 20,
4482
- targets: { systems: ["operations"] }
4483
- },
4484
- "operations-resources": {
4485
- type: "surface",
4486
- label: "Resources",
4487
- path: "/operations/resources",
4488
- surfaceType: "list",
4489
- order: 30,
4490
- targets: { systems: ["operations.resources"] }
4491
- },
4492
- "operations-command-queue": {
4493
- type: "surface",
4494
- label: "Command Queue",
4495
- path: "/operations/command-queue",
4496
- surfaceType: "list",
4497
- order: 40,
4498
- targets: { systems: ["operations.command-queue"] }
4499
- },
4500
- "operations-task-scheduler": {
4501
- type: "surface",
4502
- label: "Task Scheduler",
4503
- path: "/operations/task-scheduler",
4504
- surfaceType: "list",
4505
- order: 50,
4506
- targets: { systems: ["operations.task-scheduler"] }
4507
- }
4508
- }
4509
- },
4510
- monitoring: {
4511
- type: "group",
4512
- label: "Monitoring",
4513
- icon: "monitoring",
4514
- order: 40,
4515
- children: {
4516
- "monitoring-overview": {
4517
- type: "surface",
4518
- label: "Overview",
4519
- path: "/monitoring",
4520
- surfaceType: "page",
4521
- order: 10,
4522
- targets: { systems: ["monitoring"] }
4523
- },
4524
- "monitoring-calendar": {
4525
- type: "surface",
4526
- label: "Calendar",
4527
- path: "/monitoring/calendar",
4528
- surfaceType: "page",
4529
- order: 20,
4530
- targets: { systems: ["monitoring.calendar"] }
4531
- },
4532
- "monitoring-activity-log": {
4533
- type: "surface",
4534
- label: "Activity Log",
4535
- path: "/monitoring/activity-log",
4536
- surfaceType: "list",
4537
- order: 30,
4538
- targets: { systems: ["monitoring.activity-log"] }
4539
- },
4540
- "monitoring-execution-logs": {
4541
- type: "surface",
4542
- label: "Execution Logs",
4543
- path: "/monitoring/execution-logs",
4544
- surfaceType: "list",
4545
- order: 40,
4546
- targets: { systems: ["monitoring.execution-logs"] }
4547
- },
4548
- "monitoring-execution-health": {
4549
- type: "surface",
4550
- label: "Execution Health",
4551
- path: "/monitoring/execution-health",
4552
- surfaceType: "dashboard",
4553
- order: 50,
4554
- targets: { systems: ["monitoring.execution-health"] }
4555
- },
4556
- "monitoring-notifications": {
4557
- type: "surface",
4558
- label: "Notifications",
4559
- path: "/monitoring/notifications",
4560
- surfaceType: "list",
4561
- order: 60,
4562
- targets: { systems: ["monitoring.notifications"] }
4563
- },
4564
- "monitoring-requests": {
4565
- type: "surface",
4566
- label: "Requests",
4567
- path: "/monitoring/requests",
4568
- surfaceType: "list",
4569
- order: 70,
4570
- targets: { systems: ["monitoring.submitted-requests"] }
4571
- }
4572
- }
3531
+ primary: {},
3532
+ bottom: {}
3533
+ }
3534
+ };
3535
+ var DEFAULT_ORGANIZATION_MODEL = {
3536
+ version: 1,
3537
+ domainMetadata: DEFAULT_ORGANIZATION_MODEL_DOMAIN_METADATA,
3538
+ branding: DEFAULT_ORGANIZATION_MODEL_BRANDING,
3539
+ navigation: DEFAULT_ORGANIZATION_MODEL_NAVIGATION,
3540
+ identity: DEFAULT_ORGANIZATION_MODEL_IDENTITY,
3541
+ customers: DEFAULT_ORGANIZATION_MODEL_CUSTOMERS,
3542
+ offerings: DEFAULT_ORGANIZATION_MODEL_OFFERINGS,
3543
+ roles: DEFAULT_ORGANIZATION_MODEL_ROLES,
3544
+ goals: DEFAULT_ORGANIZATION_MODEL_GOALS,
3545
+ // Generic empty systems map. Elevasis-specific systems (platform, sales, sales.crm,
3546
+ // sales.lead-gen, monitoring, settings, admin, etc.) have been relocated to
3547
+ // `@repo/elevasis-core/src/organization-model/systems.ts` via `canonicalOrganizationModel`.
3548
+ // Tenant OM configs supply their own systems via `resolveOrganizationModel`.
3549
+ systems: {},
3550
+ ontology: DEFAULT_ONTOLOGY_SCOPE,
3551
+ resources: DEFAULT_ORGANIZATION_MODEL_RESOURCES,
3552
+ topology: DEFAULT_ORGANIZATION_MODEL_TOPOLOGY,
3553
+ // Generic empty actions map. Elevasis-specific action entries have been relocated to
3554
+ // `@repo/elevasis-core/src/organization-model/actions.ts`.
3555
+ actions: {},
3556
+ entities: DEFAULT_ORGANIZATION_MODEL_ENTITIES2,
3557
+ policies: DEFAULT_ORGANIZATION_MODEL_POLICIES,
3558
+ knowledge: DEFAULT_ORGANIZATION_MODEL_KNOWLEDGE
3559
+ };
3560
+
3561
+ // ../core/src/organization-model/resolve.ts
3562
+ function isPlainObject(value) {
3563
+ return typeof value === "object" && value !== null && !Array.isArray(value);
3564
+ }
3565
+ function collectNestedSystemPaths(systems, prefix = "") {
3566
+ const paths = /* @__PURE__ */ new Set();
3567
+ for (const [key, value] of Object.entries(systems)) {
3568
+ if (!isPlainObject(value)) continue;
3569
+ const path = prefix ? `${prefix}.${key}` : key;
3570
+ for (const childKey of ["systems", "subsystems"]) {
3571
+ const childSystems = value[childKey];
3572
+ if (!isPlainObject(childSystems)) continue;
3573
+ for (const childPath of collectNestedSystemPaths(childSystems, path)) {
3574
+ paths.add(childPath);
3575
+ }
3576
+ }
3577
+ if (prefix !== "") {
3578
+ paths.add(path);
3579
+ }
3580
+ }
3581
+ return paths;
3582
+ }
3583
+ function pruneFlatSystemDescendantCollisions(base, override) {
3584
+ const result = { ...base };
3585
+ for (const nestedPath of collectNestedSystemPaths(override)) {
3586
+ delete result[nestedPath];
3587
+ }
3588
+ return result;
3589
+ }
3590
+ function deepMerge(base, override) {
3591
+ if (override === void 0) {
3592
+ return base;
3593
+ }
3594
+ if (Array.isArray(base)) {
3595
+ return override ?? base;
3596
+ }
3597
+ if (!isPlainObject(base) || !isPlainObject(override)) {
3598
+ return override ?? base;
3599
+ }
3600
+ const result = { ...base };
3601
+ for (const [key, value] of Object.entries(override)) {
3602
+ if (value === void 0) continue;
3603
+ const existing = result[key];
3604
+ if (key === "systems" && isPlainObject(existing) && isPlainObject(value)) {
3605
+ result[key] = deepMerge(pruneFlatSystemDescendantCollisions(existing, value), value);
3606
+ continue;
3607
+ }
3608
+ result[key] = isPlainObject(existing) && isPlainObject(value) ? deepMerge(existing, value) : value;
3609
+ }
3610
+ return result;
3611
+ }
3612
+ function resolveOrganizationModel(override, organizationIdOrOptions, options) {
3613
+ const resolvedOptions = typeof organizationIdOrOptions === "object" ? organizationIdOrOptions : options;
3614
+ const mergeDefaults = resolvedOptions?.mergeDefaults ?? true;
3615
+ const merged = mergeDefaults ? deepMerge(DEFAULT_ORGANIZATION_MODEL, override) : override ?? {};
3616
+ return OrganizationModelSchema.parse(merged);
3617
+ }
3618
+
3619
+ // ../core/src/organization-model/surface-projection.ts
3620
+ function collectSystemsById(model) {
3621
+ const systemsById = /* @__PURE__ */ new Map();
3622
+ for (const { path, system } of listAllSystems(model)) {
3623
+ systemsById.set(path, system);
3624
+ systemsById.set(system.id, system);
3625
+ }
3626
+ return systemsById;
3627
+ }
3628
+ function getSystemWithAncestors(systemsById, systemId) {
3629
+ const systems = [];
3630
+ let current = systemsById.get(systemId);
3631
+ while (current !== void 0) {
3632
+ systems.unshift(current);
3633
+ current = current.parentSystemId ? systemsById.get(current.parentSystemId) : void 0;
3634
+ }
3635
+ return systems;
3636
+ }
3637
+ function hasInheritedFlag(systemsById, systemIds, flag) {
3638
+ return systemIds.some(
3639
+ (systemId) => getSystemWithAncestors(systemsById, systemId).some((system) => system[flag] === true)
3640
+ );
3641
+ }
3642
+ function isLifecycleEnabled2(system) {
3643
+ if (system.enabled === false) return false;
3644
+ return system.lifecycle !== "deprecated" && system.lifecycle !== "archived";
3645
+ }
3646
+ function isLifecycleDevOnly(system) {
3647
+ return system.devOnly === true || system.lifecycle === "beta";
3648
+ }
3649
+ function isSystemEnabled(systemsById, systemId) {
3650
+ const systemLineage = getSystemWithAncestors(systemsById, systemId);
3651
+ return systemLineage.length > 0 && systemLineage.every(isLifecycleEnabled2);
3652
+ }
3653
+ function unique(values) {
3654
+ return [...new Set(values)];
3655
+ }
3656
+ function collectSidebarSurfaces(nodes, schemaPath, surfaces = []) {
3657
+ getSortedSidebarEntries(nodes).forEach(([id, node]) => {
3658
+ const nodePath = [...schemaPath, id];
3659
+ if (node.type === "group") {
3660
+ collectSidebarSurfaces(node.children, [...nodePath, "children"], surfaces);
3661
+ return;
3662
+ }
3663
+ surfaces.push({ id, surface: node, path: nodePath });
3664
+ });
3665
+ return surfaces;
3666
+ }
3667
+ function getSidebarSurfaces(model) {
3668
+ return [
3669
+ ...collectSidebarSurfaces(model.navigation.sidebar.primary, ["navigation", "sidebar", "primary"]),
3670
+ ...collectSidebarSurfaces(model.navigation.sidebar.bottom, ["navigation", "sidebar", "bottom"])
3671
+ ];
3672
+ }
3673
+ function projectOrganizationSurfaces(model) {
3674
+ const systemsById = collectSystemsById(model);
3675
+ return getSidebarSurfaces(model).map(({ id, surface }) => {
3676
+ const targets = surface.targets ?? {};
3677
+ const systemIds = unique((targets.systems ?? []).filter((systemId) => systemsById.has(systemId)));
3678
+ const enabled = systemIds.every((candidate) => isSystemEnabled(systemsById, candidate));
3679
+ const devOnly = surface.devOnly === true || hasInheritedFlag(systemsById, systemIds, "devOnly") || systemIds.some((candidate) => getSystemWithAncestors(systemsById, candidate).some(isLifecycleDevOnly));
3680
+ const requiresAdmin = hasInheritedFlag(systemsById, systemIds, "requiresAdmin");
3681
+ return {
3682
+ id,
3683
+ label: surface.label,
3684
+ path: surface.path,
3685
+ surfaceType: surface.surfaceType,
3686
+ ...surface.description !== void 0 ? { description: surface.description } : {},
3687
+ ...surface.icon !== void 0 ? { icon: surface.icon } : {},
3688
+ ...surface.order !== void 0 ? { order: surface.order } : {},
3689
+ systemIds,
3690
+ entityIds: [...targets.entities ?? []],
3691
+ resourceIds: [...targets.resources ?? []],
3692
+ actionIds: [...targets.actions ?? []],
3693
+ enabled,
3694
+ ...devOnly ? { devOnly } : {},
3695
+ ...surface.requiresAdmin === true || requiresAdmin ? { requiresAdmin: true } : {}
3696
+ };
3697
+ });
3698
+ }
3699
+ var SalesStageSemanticClassSchema = z.enum(["open", "active", "nurturing", "closed_won", "closed_lost"]);
3700
+ var SalesStageSchema = DisplayMetadataSchema.extend({
3701
+ id: ModelIdSchema,
3702
+ order: z.number().int().min(0),
3703
+ semanticClass: SalesStageSemanticClassSchema,
3704
+ surfaceIds: ReferenceIdsSchema,
3705
+ resourceIds: ReferenceIdsSchema
3706
+ });
3707
+ z.object({
3708
+ id: ModelIdSchema,
3709
+ label: z.string().trim().min(1).max(120),
3710
+ description: DescriptionSchema.optional(),
3711
+ entityId: ModelIdSchema,
3712
+ stages: z.array(SalesStageSchema).min(1)
3713
+ });
3714
+ function findPipeline(definitions, pipelineKey) {
3715
+ return definitions.find((def) => def.pipelineKey === pipelineKey);
3716
+ }
3717
+ var CRM_DISCOVERY_REPLIED_STATE = {
3718
+ stateKey: "discovery_replied",
3719
+ label: "Discovery Replied"
3720
+ };
3721
+ var CRM_DISCOVERY_LINK_SENT_STATE = {
3722
+ stateKey: "discovery_link_sent",
3723
+ label: "Discovery Link Sent"
3724
+ };
3725
+ var CRM_DISCOVERY_NUDGING_STATE = {
3726
+ stateKey: "discovery_nudging",
3727
+ label: "Discovery Nudging"
3728
+ };
3729
+ var CRM_DISCOVERY_BOOKING_CANCELLED_STATE = {
3730
+ stateKey: "discovery_booking_cancelled",
3731
+ label: "Discovery Booking Cancelled"
3732
+ };
3733
+ DisplayMetadataSchema.extend({
3734
+ id: ModelIdSchema,
3735
+ order: z.number().min(0)
3736
+ });
3737
+ var RecordColumnConfigSchema = z.object({
3738
+ key: ModelIdSchema,
3739
+ label: z.string().trim().min(1).max(120),
3740
+ path: z.string().trim().min(1).max(500),
3741
+ width: z.union([z.number().positive(), z.string().trim().min(1).max(100)]).optional(),
3742
+ renderType: z.enum(["text", "badge", "datetime", "count", "json"]).optional(),
3743
+ badgeColor: z.string().trim().min(1).max(40).optional()
3744
+ });
3745
+ var RecordColumnsConfigSchema = z.object({
3746
+ company: z.array(RecordColumnConfigSchema).optional(),
3747
+ contact: z.array(RecordColumnConfigSchema).optional()
3748
+ }).refine((columns) => Boolean(columns.company?.length || columns.contact?.length), {
3749
+ message: "recordColumns must include at least one entity column set"
3750
+ });
3751
+ var CredentialRequirementSchema = z.object({
3752
+ key: ModelIdSchema,
3753
+ provider: ModelIdSchema,
3754
+ credentialType: z.enum(["api-key", "api-key-secret", "oauth", "webhook-secret"]),
3755
+ label: z.string().trim().min(1).max(120),
3756
+ required: z.boolean(),
3757
+ selectionMode: z.enum(["single", "multiple"]).optional(),
3758
+ inputPath: z.string().trim().min(1).max(500),
3759
+ verifyOnRun: z.boolean().optional()
3760
+ });
3761
+ var ProspectingBuildTemplateStepSchema = DisplayMetadataSchema.extend({
3762
+ id: ModelIdSchema,
3763
+ primaryEntity: z.enum(["company", "contact"]),
3764
+ outputs: z.array(z.enum(["company", "contact", "export"])).min(1),
3765
+ stageKey: ModelIdSchema,
3766
+ recordEntity: z.enum(["company", "contact"]).optional(),
3767
+ recordsStageKey: ModelIdSchema.optional(),
3768
+ recordSourceStageKey: ModelIdSchema.optional(),
3769
+ dependsOn: z.array(ModelIdSchema).optional(),
3770
+ dependencyMode: z.literal("per-record-eligibility"),
3771
+ actionKey: ModelIdSchema,
3772
+ defaultBatchSize: z.number().int().positive(),
3773
+ maxBatchSize: z.number().int().positive(),
3774
+ recordColumns: RecordColumnsConfigSchema.optional(),
3775
+ credentialRequirements: z.array(CredentialRequirementSchema).optional()
3776
+ }).refine((step) => step.defaultBatchSize <= step.maxBatchSize, {
3777
+ message: "defaultBatchSize must be less than or equal to maxBatchSize",
3778
+ path: ["defaultBatchSize"]
3779
+ });
3780
+ DisplayMetadataSchema.extend({
3781
+ id: ModelIdSchema,
3782
+ steps: z.array(ProspectingBuildTemplateStepSchema).min(1)
3783
+ });
3784
+ var DTC_RECORD_COLUMNS = {
3785
+ populated: {
3786
+ company: [
3787
+ { key: "name", label: "Company", path: "company.name" },
3788
+ { key: "domain", label: "Domain", path: "company.domain" },
3789
+ { key: "employee-count", label: "Employees", path: "company.numEmployees", renderType: "count" },
3790
+ { key: "apollo-industry", label: "Apollo industry", path: "company.category" },
3791
+ { key: "location", label: "Location", path: "company.locationState" }
3792
+ ]
3793
+ },
3794
+ crawled: {
3795
+ company: [
3796
+ { key: "name", label: "Company", path: "company.name" },
3797
+ { key: "domain", label: "Domain", path: "company.domain" },
3798
+ { key: "page-count", label: "Pages", path: "company.enrichmentData.websiteCrawl.pageCount", renderType: "count" },
3799
+ { key: "crawl-status", label: "Crawl status", path: "processingState.crawled.status", renderType: "badge" }
3800
+ ]
3801
+ },
3802
+ extracted: {
3803
+ company: [
3804
+ { key: "name", label: "Company", path: "company.name" },
3805
+ { key: "domain", label: "Domain", path: "company.domain" },
3806
+ { key: "description", label: "Description", path: "company.enrichmentData.websiteCrawl.companyDescription" },
3807
+ { key: "services", label: "Services", path: "company.enrichmentData.websiteCrawl.services", renderType: "json" },
3808
+ {
3809
+ key: "automation-gaps",
3810
+ label: "Automation gaps",
3811
+ path: "company.enrichmentData.websiteCrawl.automationGaps",
3812
+ renderType: "json"
4573
3813
  },
4574
- knowledge: {
4575
- type: "surface",
4576
- label: "Knowledge Base",
4577
- path: "/knowledge",
4578
- surfaceType: "page",
4579
- icon: "knowledge",
4580
- order: 50
3814
+ {
3815
+ key: "contact-count",
3816
+ label: "Contacts",
3817
+ path: "company.enrichmentData.websiteCrawl.emailCount",
3818
+ renderType: "count"
4581
3819
  }
4582
- },
4583
- bottom: {
4584
- settings: {
4585
- type: "group",
4586
- label: "Settings",
4587
- icon: "settings",
4588
- order: 10,
4589
- children: {
4590
- "settings-account": {
4591
- type: "surface",
4592
- label: "Account",
4593
- path: "/settings/account",
4594
- surfaceType: "settings",
4595
- order: 10,
4596
- targets: { systems: ["settings.account"] }
4597
- },
4598
- "settings-appearance": {
4599
- type: "surface",
4600
- label: "Appearance",
4601
- path: "/settings/appearance",
4602
- surfaceType: "settings",
4603
- order: 20,
4604
- targets: { systems: ["settings.appearance"] }
4605
- },
4606
- "settings-roles": {
4607
- type: "surface",
4608
- label: "My Roles",
4609
- path: "/settings/roles",
4610
- surfaceType: "settings",
4611
- order: 30,
4612
- targets: { systems: ["settings.roles"] }
4613
- },
4614
- "settings-organization": {
4615
- type: "surface",
4616
- label: "Organization",
4617
- path: "/settings/organization",
4618
- surfaceType: "settings",
4619
- order: 40,
4620
- targets: { systems: ["settings.organization"] }
4621
- },
4622
- "settings-credentials": {
4623
- type: "surface",
4624
- label: "Credentials",
4625
- path: "/settings/credentials",
4626
- surfaceType: "settings",
4627
- order: 50,
4628
- targets: { systems: ["settings.credentials"] }
4629
- },
4630
- "settings-api-keys": {
4631
- type: "surface",
4632
- label: "API Keys",
4633
- path: "/settings/api-keys",
4634
- surfaceType: "settings",
4635
- order: 60,
4636
- targets: { systems: ["settings.api-keys"] }
4637
- },
4638
- "settings-webhooks": {
4639
- type: "surface",
4640
- label: "Webhooks",
4641
- path: "/settings/webhooks",
4642
- surfaceType: "settings",
4643
- order: 70,
4644
- targets: { systems: ["settings.webhooks"] }
4645
- },
4646
- "settings-deployments": {
4647
- type: "surface",
4648
- label: "Deployments",
4649
- path: "/settings/deployments",
4650
- surfaceType: "settings",
4651
- order: 80,
4652
- targets: { systems: ["settings.deployments"] }
4653
- }
4654
- }
3820
+ ]
3821
+ },
3822
+ qualified: {
3823
+ company: [
3824
+ { key: "name", label: "Company", path: "company.name" },
3825
+ { key: "domain", label: "Domain", path: "company.domain" },
3826
+ { key: "score", label: "Score", path: "company.qualificationScore", renderType: "badge", badgeColor: "green" },
3827
+ { key: "signals", label: "Signals", path: "company.qualificationSignals", renderType: "json" },
3828
+ {
3829
+ key: "disqualified-reason",
3830
+ label: "Disqualified reason",
3831
+ path: "processingState.qualified.data.disqualifiedReason"
3832
+ }
3833
+ ]
3834
+ },
3835
+ decisionMakers: {
3836
+ contact: [
3837
+ { key: "name", label: "Name", path: "contact.name" },
3838
+ { key: "title", label: "Title", path: "contact.title" },
3839
+ { key: "email", label: "Email", path: "contact.email" },
3840
+ { key: "linkedin", label: "LinkedIn", path: "contact.linkedinUrl" },
3841
+ {
3842
+ key: "priority-score",
3843
+ label: "Priority",
3844
+ path: "contact.enrichmentData.apollo.priorityScore",
3845
+ renderType: "badge"
3846
+ }
3847
+ ]
3848
+ },
3849
+ uploaded: {
3850
+ company: [
3851
+ { key: "name", label: "Company", path: "company.name" },
3852
+ { key: "domain", label: "Domain", path: "company.domain" },
3853
+ {
3854
+ key: "contacts",
3855
+ label: "Contacts",
3856
+ path: "company.enrichmentData.approvedLeadListExport.contacts",
3857
+ renderType: "json"
4655
3858
  },
4656
- admin: {
4657
- type: "group",
4658
- label: "Admin",
4659
- icon: "admin",
4660
- order: 20,
4661
- children: {
4662
- "admin-dashboard": {
4663
- type: "surface",
4664
- label: "Dashboard",
4665
- path: "/admin/dashboard",
4666
- surfaceType: "dashboard",
4667
- order: 10,
4668
- targets: { systems: ["admin"] },
4669
- requiresAdmin: true
4670
- },
4671
- "admin-system-health": {
4672
- type: "surface",
4673
- label: "System Health",
4674
- path: "/admin/system-health",
4675
- surfaceType: "dashboard",
4676
- order: 20,
4677
- targets: { systems: ["admin.system-health"] },
4678
- requiresAdmin: true
4679
- },
4680
- "admin-organizations": {
4681
- type: "surface",
4682
- label: "Organizations",
4683
- path: "/admin/organizations",
4684
- surfaceType: "list",
4685
- order: 30,
4686
- targets: { systems: ["admin.organizations"] },
4687
- requiresAdmin: true
4688
- },
4689
- "admin-users": {
4690
- type: "surface",
4691
- label: "Users",
4692
- path: "/admin/users",
4693
- surfaceType: "list",
4694
- order: 40,
4695
- targets: { systems: ["admin.users"] },
4696
- requiresAdmin: true
4697
- },
4698
- "admin-design-showcase": {
4699
- type: "surface",
4700
- label: "Design Showcase",
4701
- path: "/admin/design-showcase",
4702
- surfaceType: "page",
4703
- order: 50,
4704
- targets: { systems: ["admin.design-showcase"] },
4705
- requiresAdmin: true
4706
- },
4707
- "admin-debug": {
4708
- type: "surface",
4709
- label: "Debug",
4710
- path: "/admin/debug",
4711
- surfaceType: "page",
4712
- order: 60,
4713
- targets: { systems: ["admin.debug"] },
4714
- requiresAdmin: true
4715
- }
4716
- }
3859
+ { key: "score", label: "Score", path: "company.qualificationScore", renderType: "badge", badgeColor: "green" },
3860
+ {
3861
+ key: "approval",
3862
+ label: "Approval",
3863
+ path: "company.enrichmentData.approvedLeadListExport.approvalStatus",
3864
+ renderType: "badge"
4717
3865
  }
4718
- }
3866
+ ]
4719
3867
  }
4720
3868
  };
4721
- var DEFAULT_ORGANIZATION_MODEL = {
4722
- version: 1,
4723
- domainMetadata: DEFAULT_ORGANIZATION_MODEL_DOMAIN_METADATA,
4724
- branding: DEFAULT_ORGANIZATION_MODEL_BRANDING,
4725
- navigation: DEFAULT_ORGANIZATION_MODEL_NAVIGATION,
4726
- identity: DEFAULT_ORGANIZATION_MODEL_IDENTITY,
4727
- customers: DEFAULT_ORGANIZATION_MODEL_CUSTOMERS,
4728
- offerings: DEFAULT_ORGANIZATION_MODEL_OFFERINGS,
4729
- roles: DEFAULT_ORGANIZATION_MODEL_ROLES,
4730
- goals: DEFAULT_ORGANIZATION_MODEL_GOALS,
4731
- systems: {
4732
- dashboard: {
4733
- id: "dashboard",
4734
- order: 10,
4735
- label: "Dashboard",
4736
- enabled: true,
4737
- lifecycle: "active",
4738
- path: "/",
4739
- icon: "dashboard"
4740
- },
4741
- platform: {
4742
- id: "platform",
4743
- order: 30,
4744
- label: "Platform",
4745
- description: "Elevasis platform architecture, capabilities, and implementation patterns",
4746
- enabled: true,
4747
- lifecycle: "active",
4748
- color: "cyan",
4749
- icon: "platform"
4750
- },
4751
- finance: {
4752
- id: "finance",
4753
- order: 40,
4754
- label: "Finance",
4755
- description: "Finance operations, accounting, billing, reconciliation, and tax prep",
4756
- enabled: true,
4757
- lifecycle: "active",
4758
- color: "green",
4759
- icon: "finance"
4760
- },
4761
- sales: {
4762
- id: "sales",
4763
- order: 60,
4764
- label: "Sales",
4765
- description: "Revenue workflows and customer acquisition",
4766
- enabled: true,
4767
- lifecycle: "active",
4768
- color: "blue",
4769
- icon: "sales",
4770
- path: "/sales"
4771
- },
4772
- "sales.crm": {
4773
- id: "sales.crm",
4774
- order: 70,
4775
- label: "CRM",
4776
- description: "Relationship pipeline and deal management",
4777
- enabled: true,
4778
- lifecycle: "active",
4779
- actions: Object.values(CRM_ACTION_ENTRIES).map((action) => ({
4780
- actionId: action.id,
4781
- intent: "exposes"
4782
- })),
4783
- color: "blue",
4784
- icon: "crm",
4785
- path: "/crm"
4786
- },
4787
- "sales.lead-gen": {
4788
- id: "sales.lead-gen",
4789
- order: 80,
4790
- label: "Lead Gen",
4791
- description: "Prospecting, qualification, and outreach preparation",
4792
- enabled: true,
4793
- lifecycle: "active",
4794
- actions: Object.values(LEAD_GEN_ACTION_ENTRIES).map((action) => ({
4795
- actionId: action.id,
4796
- intent: "exposes"
4797
- })),
4798
- color: "cyan",
4799
- icon: "lead-gen",
4800
- path: "/lead-gen"
4801
- },
4802
- projects: {
4803
- id: "projects",
4804
- order: 90,
4805
- label: "Projects",
4806
- description: "Projects, milestones, and client work execution",
4807
- enabled: true,
4808
- lifecycle: "active",
4809
- color: "orange",
4810
- icon: "projects",
4811
- path: "/projects"
4812
- },
4813
- clients: {
4814
- id: "clients",
4815
- order: 100,
4816
- label: "Clients",
4817
- description: "Client relationships, accounts, and business context",
4818
- enabled: true,
4819
- lifecycle: "active",
4820
- color: "orange",
4821
- icon: "projects",
4822
- path: "/clients"
4823
- },
4824
- operations: {
4825
- id: "operations",
4826
- order: 110,
4827
- label: "Operations",
4828
- description: "Operational resources, topology, and orchestration visibility",
4829
- enabled: true,
4830
- lifecycle: "active",
4831
- color: "violet",
4832
- icon: "operations"
4833
- },
4834
- "knowledge.command-view": {
4835
- id: "knowledge.command-view",
4836
- order: 120,
4837
- label: "Command View",
4838
- enabled: true,
4839
- lifecycle: "active",
4840
- path: "/knowledge/command-view",
4841
- devOnly: true
4842
- },
4843
- "operations.overview": {
4844
- id: "operations.overview",
4845
- order: 130,
4846
- label: "Overview",
4847
- enabled: true,
4848
- lifecycle: "active",
4849
- path: "/operations"
4850
- },
4851
- "operations.resources": {
4852
- id: "operations.resources",
4853
- order: 140,
4854
- label: "Resources",
4855
- enabled: true,
4856
- lifecycle: "active",
4857
- path: "/operations/resources"
4858
- },
4859
- "operations.command-queue": {
4860
- id: "operations.command-queue",
4861
- order: 150,
4862
- label: "Command Queue",
4863
- enabled: true,
4864
- lifecycle: "active",
4865
- path: "/operations/command-queue"
4866
- },
4867
- "operations.sessions": {
4868
- id: "operations.sessions",
4869
- order: 160,
4870
- label: "Sessions",
4871
- enabled: false,
4872
- lifecycle: "deprecated",
4873
- path: "/operations/sessions"
4874
- },
4875
- "operations.task-scheduler": {
4876
- id: "operations.task-scheduler",
4877
- order: 170,
4878
- label: "Task Scheduler",
4879
- enabled: true,
4880
- lifecycle: "active",
4881
- path: "/operations/task-scheduler"
4882
- },
4883
- monitoring: {
4884
- id: "monitoring",
4885
- order: 180,
4886
- label: "Monitoring",
4887
- enabled: true,
4888
- lifecycle: "active"
4889
- },
4890
- "monitoring.calendar": {
4891
- id: "monitoring.calendar",
4892
- order: 190,
4893
- label: "Calendar",
4894
- description: "Google Calendar events and agenda views",
4895
- enabled: true,
4896
- lifecycle: "active",
4897
- path: "/monitoring/calendar",
4898
- icon: "calendar"
4899
- },
4900
- "monitoring.activity-log": {
4901
- id: "monitoring.activity-log",
4902
- order: 200,
4903
- label: "Activity Log",
4904
- enabled: true,
4905
- lifecycle: "active",
4906
- path: "/monitoring/activity-log"
4907
- },
4908
- "monitoring.execution-logs": {
4909
- id: "monitoring.execution-logs",
4910
- order: 210,
4911
- label: "Execution Logs",
4912
- enabled: true,
4913
- lifecycle: "active",
4914
- path: "/monitoring/execution-logs"
4915
- },
4916
- "monitoring.execution-health": {
4917
- id: "monitoring.execution-health",
4918
- order: 220,
4919
- label: "Execution Health",
4920
- enabled: true,
4921
- lifecycle: "active",
4922
- path: "/monitoring/execution-health"
4923
- },
4924
- "monitoring.cost-analytics": {
4925
- id: "monitoring.cost-analytics",
4926
- order: 230,
4927
- label: "Cost Analytics",
4928
- enabled: false,
4929
- lifecycle: "deprecated",
4930
- path: "/monitoring/cost-analytics"
4931
- },
4932
- "monitoring.notifications": {
4933
- id: "monitoring.notifications",
4934
- order: 240,
4935
- label: "Notifications",
4936
- enabled: true,
4937
- lifecycle: "active",
4938
- path: "/monitoring/notifications"
4939
- },
4940
- "monitoring.submitted-requests": {
4941
- id: "monitoring.submitted-requests",
4942
- order: 250,
4943
- label: "Submitted Requests",
4944
- enabled: true,
4945
- lifecycle: "active",
4946
- path: "/monitoring/requests"
4947
- },
4948
- settings: {
4949
- id: "settings",
4950
- order: 260,
4951
- label: "Settings",
4952
- enabled: true,
4953
- lifecycle: "active",
4954
- icon: "settings"
4955
- },
4956
- "settings.account": {
4957
- id: "settings.account",
4958
- order: 270,
4959
- label: "Account",
4960
- enabled: true,
4961
- lifecycle: "active",
4962
- path: "/settings/account"
4963
- },
4964
- "settings.appearance": {
4965
- id: "settings.appearance",
4966
- order: 280,
4967
- label: "Appearance",
4968
- enabled: true,
4969
- lifecycle: "active",
4970
- path: "/settings/appearance"
4971
- },
4972
- "settings.roles": {
4973
- id: "settings.roles",
4974
- order: 290,
4975
- label: "My Roles",
4976
- enabled: true,
4977
- lifecycle: "active",
4978
- path: "/settings/roles"
4979
- },
4980
- "settings.organization": {
4981
- id: "settings.organization",
4982
- order: 300,
4983
- label: "Organization",
4984
- enabled: true,
4985
- lifecycle: "active",
4986
- path: "/settings/organization"
4987
- },
4988
- "settings.credentials": {
4989
- id: "settings.credentials",
4990
- order: 310,
4991
- label: "Credentials",
4992
- enabled: true,
4993
- lifecycle: "active",
4994
- path: "/settings/credentials"
4995
- },
4996
- "settings.api-keys": {
4997
- id: "settings.api-keys",
4998
- order: 320,
4999
- label: "API Keys",
5000
- enabled: true,
5001
- lifecycle: "active",
5002
- path: "/settings/api-keys"
5003
- },
5004
- "settings.webhooks": {
5005
- id: "settings.webhooks",
5006
- order: 330,
5007
- label: "Webhooks",
5008
- enabled: true,
5009
- lifecycle: "active",
5010
- path: "/settings/webhooks"
5011
- },
5012
- "settings.deployments": {
5013
- id: "settings.deployments",
5014
- order: 340,
5015
- label: "Deployments",
5016
- enabled: true,
5017
- lifecycle: "active",
5018
- path: "/settings/deployments"
5019
- },
5020
- admin: {
5021
- id: "admin",
5022
- order: 350,
5023
- label: "Admin",
5024
- enabled: true,
5025
- lifecycle: "active",
5026
- path: "/admin",
5027
- icon: "admin",
5028
- requiresAdmin: true
3869
+ var PROSPECTING_STEPS = {
3870
+ localServices: {
3871
+ sourceCompanies: {
3872
+ id: "source-companies",
3873
+ label: "Companies found",
3874
+ primaryEntity: "company",
3875
+ outputs: ["company"],
3876
+ stageKey: "populated",
3877
+ dependencyMode: "per-record-eligibility",
3878
+ actionKey: "lead-gen.company.source",
3879
+ defaultBatchSize: 100,
3880
+ maxBatchSize: 250
5029
3881
  },
5030
- "admin.system-health": {
5031
- id: "admin.system-health",
5032
- order: 360,
5033
- label: "System Health",
5034
- enabled: true,
5035
- lifecycle: "active",
5036
- path: "/admin/system-health"
3882
+ analyzeWebsites: {
3883
+ id: "analyze-websites",
3884
+ label: "Websites analyzed",
3885
+ primaryEntity: "company",
3886
+ outputs: ["company"],
3887
+ stageKey: "extracted",
3888
+ dependsOn: ["source-companies"],
3889
+ dependencyMode: "per-record-eligibility",
3890
+ actionKey: "lead-gen.company.website-extract",
3891
+ defaultBatchSize: 50,
3892
+ maxBatchSize: 100
5037
3893
  },
5038
- "admin.organizations": {
5039
- id: "admin.organizations",
5040
- order: 370,
5041
- label: "Organizations",
5042
- enabled: true,
5043
- lifecycle: "active",
5044
- path: "/admin/organizations"
3894
+ qualifyCompanies: {
3895
+ id: "qualify-companies",
3896
+ label: "Companies qualified",
3897
+ primaryEntity: "company",
3898
+ outputs: ["company"],
3899
+ stageKey: "qualified",
3900
+ dependsOn: ["analyze-websites"],
3901
+ dependencyMode: "per-record-eligibility",
3902
+ actionKey: "lead-gen.company.qualify",
3903
+ defaultBatchSize: 100,
3904
+ maxBatchSize: 250
5045
3905
  },
5046
- "admin.users": {
5047
- id: "admin.users",
5048
- order: 380,
5049
- label: "Users",
5050
- enabled: true,
5051
- lifecycle: "active",
5052
- path: "/admin/users"
3906
+ findContacts: {
3907
+ id: "find-contacts",
3908
+ label: "Decision-makers found",
3909
+ primaryEntity: "contact",
3910
+ outputs: ["contact"],
3911
+ stageKey: "discovered",
3912
+ dependsOn: ["qualify-companies"],
3913
+ dependencyMode: "per-record-eligibility",
3914
+ actionKey: "lead-gen.contact.discover",
3915
+ defaultBatchSize: 50,
3916
+ maxBatchSize: 100
5053
3917
  },
5054
- "admin.design-showcase": {
5055
- id: "admin.design-showcase",
5056
- order: 390,
5057
- label: "Design Showcase",
5058
- enabled: true,
5059
- lifecycle: "active",
5060
- path: "/admin/design-showcase"
3918
+ verifyEmails: {
3919
+ id: "verify-emails",
3920
+ label: "Emails verified",
3921
+ primaryEntity: "contact",
3922
+ outputs: ["contact"],
3923
+ stageKey: "verified",
3924
+ dependsOn: ["find-contacts"],
3925
+ dependencyMode: "per-record-eligibility",
3926
+ actionKey: "lead-gen.contact.verify-email",
3927
+ defaultBatchSize: 100,
3928
+ maxBatchSize: 500
5061
3929
  },
5062
- "admin.debug": {
5063
- id: "admin.debug",
5064
- order: 400,
5065
- label: "Debug",
5066
- enabled: true,
5067
- lifecycle: "active",
5068
- path: "/admin/debug"
3930
+ personalize: {
3931
+ id: "personalize",
3932
+ label: "Personalize",
3933
+ primaryEntity: "contact",
3934
+ outputs: ["contact"],
3935
+ stageKey: "personalized",
3936
+ dependsOn: ["verify-emails"],
3937
+ dependencyMode: "per-record-eligibility",
3938
+ actionKey: "lead-gen.contact.personalize",
3939
+ defaultBatchSize: 25,
3940
+ maxBatchSize: 100
5069
3941
  },
5070
- archive: {
5071
- id: "archive",
5072
- order: 410,
5073
- label: "Archive",
5074
- enabled: true,
5075
- lifecycle: "active",
5076
- path: "/archive",
5077
- icon: "archive",
5078
- devOnly: true
3942
+ review: {
3943
+ id: "review",
3944
+ label: "Reviewed and exported",
3945
+ primaryEntity: "contact",
3946
+ outputs: ["export"],
3947
+ stageKey: "uploaded",
3948
+ dependsOn: ["personalize"],
3949
+ dependencyMode: "per-record-eligibility",
3950
+ actionKey: "lead-gen.review.outreach-ready",
3951
+ defaultBatchSize: 25,
3952
+ maxBatchSize: 100
3953
+ }
3954
+ },
3955
+ dtcApolloClickup: {
3956
+ importApolloSearch: {
3957
+ id: "import-apollo-search",
3958
+ label: "Companies found",
3959
+ description: "Pull companies and seed contact data from a predefined Apollo search or list.",
3960
+ primaryEntity: "company",
3961
+ outputs: ["company", "contact"],
3962
+ stageKey: "populated",
3963
+ dependencyMode: "per-record-eligibility",
3964
+ actionKey: "lead-gen.company.apollo-import",
3965
+ defaultBatchSize: 250,
3966
+ maxBatchSize: 1e3,
3967
+ recordColumns: DTC_RECORD_COLUMNS.populated,
3968
+ credentialRequirements: [
3969
+ {
3970
+ key: "apollo",
3971
+ provider: "apollo",
3972
+ credentialType: "api-key-secret",
3973
+ label: "Apollo API key",
3974
+ required: true,
3975
+ selectionMode: "single",
3976
+ inputPath: "credential"
3977
+ }
3978
+ ]
5079
3979
  },
5080
- "archive.agent-chat": {
5081
- id: "archive.agent-chat",
5082
- order: 420,
5083
- label: "Agent Chat",
5084
- enabled: true,
5085
- lifecycle: "active",
5086
- path: "/archive/agent-chat"
3980
+ apifyCrawl: {
3981
+ id: "apify-crawl",
3982
+ label: "Websites crawled",
3983
+ 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.",
3984
+ primaryEntity: "company",
3985
+ outputs: ["company"],
3986
+ stageKey: "crawled",
3987
+ dependsOn: ["import-apollo-search"],
3988
+ dependencyMode: "per-record-eligibility",
3989
+ actionKey: "lead-gen.company.apify-crawl",
3990
+ defaultBatchSize: 50,
3991
+ maxBatchSize: 100,
3992
+ recordColumns: DTC_RECORD_COLUMNS.crawled,
3993
+ credentialRequirements: [
3994
+ {
3995
+ key: "apify",
3996
+ provider: "apify",
3997
+ credentialType: "api-key-secret",
3998
+ label: "Apify API token",
3999
+ required: true,
4000
+ selectionMode: "single",
4001
+ inputPath: "credential",
4002
+ verifyOnRun: true
4003
+ }
4004
+ ]
5087
4005
  },
5088
- "archive.execution-runner": {
5089
- id: "archive.execution-runner",
5090
- order: 430,
5091
- label: "Execution Runner",
5092
- enabled: true,
5093
- lifecycle: "active",
5094
- path: "/archive/execution-runner"
4006
+ analyzeWebsites: {
4007
+ id: "analyze-websites",
4008
+ label: "Websites analyzed",
4009
+ description: "Extract subscription, product, retention, and tech-stack signals from each brand website.",
4010
+ primaryEntity: "company",
4011
+ outputs: ["company"],
4012
+ stageKey: "extracted",
4013
+ dependsOn: ["apify-crawl"],
4014
+ dependencyMode: "per-record-eligibility",
4015
+ actionKey: "lead-gen.company.website-extract",
4016
+ defaultBatchSize: 50,
4017
+ maxBatchSize: 100,
4018
+ recordColumns: DTC_RECORD_COLUMNS.extracted
5095
4019
  },
5096
- seo: {
5097
- id: "seo",
5098
- order: 440,
5099
- label: "SEO",
5100
- enabled: false,
5101
- lifecycle: "deprecated",
5102
- path: "/seo"
4020
+ scoreDtcFit: {
4021
+ id: "score-dtc-fit",
4022
+ label: "Companies qualified",
4023
+ description: "Classify subscription potential, consumable-product fit, retention maturity, and disqualifiers.",
4024
+ primaryEntity: "company",
4025
+ outputs: ["company"],
4026
+ stageKey: "qualified",
4027
+ dependsOn: ["analyze-websites"],
4028
+ dependencyMode: "per-record-eligibility",
4029
+ actionKey: "lead-gen.company.dtc-subscription-qualify",
4030
+ defaultBatchSize: 100,
4031
+ maxBatchSize: 250,
4032
+ recordColumns: DTC_RECORD_COLUMNS.qualified
5103
4033
  },
5104
- knowledge: {
5105
- id: "knowledge",
5106
- order: 450,
5107
- label: "Knowledge",
5108
- description: "Operational knowledge, playbooks, and strategy docs",
5109
- enabled: true,
5110
- lifecycle: "active",
5111
- color: "teal",
5112
- icon: "knowledge"
4034
+ enrichDecisionMakers: {
4035
+ id: "enrich-decision-makers",
4036
+ label: "Decision-makers found",
4037
+ description: "Use Apollo to find qualified contacts at qualified companies - founders, retention leads, lifecycle leads, and marketing owners.",
4038
+ primaryEntity: "company",
4039
+ outputs: ["contact"],
4040
+ stageKey: "decision-makers-enriched",
4041
+ recordEntity: "contact",
4042
+ dependsOn: ["score-dtc-fit"],
4043
+ dependencyMode: "per-record-eligibility",
4044
+ actionKey: "lead-gen.contact.apollo-decision-maker-enrich",
4045
+ defaultBatchSize: 100,
4046
+ maxBatchSize: 250,
4047
+ recordColumns: DTC_RECORD_COLUMNS.decisionMakers,
4048
+ credentialRequirements: [
4049
+ {
4050
+ key: "apollo",
4051
+ provider: "apollo",
4052
+ credentialType: "api-key-secret",
4053
+ label: "Apollo API key",
4054
+ required: true,
4055
+ selectionMode: "single",
4056
+ inputPath: "credential"
4057
+ }
4058
+ ]
5113
4059
  },
5114
- "knowledge.base": {
5115
- id: "knowledge.base",
5116
- order: 460,
5117
- label: "Knowledge Base",
5118
- enabled: true,
5119
- lifecycle: "active",
5120
- path: "/knowledge"
5121
- }
5122
- },
5123
- ontology: DEFAULT_ONTOLOGY_SCOPE,
5124
- resources: DEFAULT_ORGANIZATION_MODEL_RESOURCES,
5125
- topology: DEFAULT_ORGANIZATION_MODEL_TOPOLOGY,
5126
- actions: DEFAULT_ORGANIZATION_MODEL_ACTIONS,
5127
- entities: DEFAULT_ORGANIZATION_MODEL_ENTITIES2,
5128
- policies: DEFAULT_ORGANIZATION_MODEL_POLICIES,
5129
- // Phase 4 (D1): statuses top-level field removed; bridge status mirrors may
5130
- // still project from System.content, but primary authoring belongs in ontology.
5131
- knowledge: DEFAULT_ORGANIZATION_MODEL_KNOWLEDGE
5132
- };
5133
-
5134
- // ../core/src/organization-model/resolve.ts
5135
- function isPlainObject(value) {
5136
- return typeof value === "object" && value !== null && !Array.isArray(value);
5137
- }
5138
- function collectNestedSystemPaths(systems, prefix = "") {
5139
- const paths = /* @__PURE__ */ new Set();
5140
- for (const [key, value] of Object.entries(systems)) {
5141
- if (!isPlainObject(value)) continue;
5142
- const path = prefix ? `${prefix}.${key}` : key;
5143
- for (const childKey of ["systems", "subsystems"]) {
5144
- const childSystems = value[childKey];
5145
- if (!isPlainObject(childSystems)) continue;
5146
- for (const childPath of collectNestedSystemPaths(childSystems, path)) {
5147
- paths.add(childPath);
5148
- }
5149
- }
5150
- if (prefix !== "") {
5151
- paths.add(path);
5152
- }
5153
- }
5154
- return paths;
5155
- }
5156
- function pruneFlatSystemDescendantCollisions(base, override) {
5157
- const result = { ...base };
5158
- for (const nestedPath of collectNestedSystemPaths(override)) {
5159
- delete result[nestedPath];
5160
- }
5161
- return result;
5162
- }
5163
- function deepMerge(base, override) {
5164
- if (override === void 0) {
5165
- return base;
5166
- }
5167
- if (Array.isArray(base)) {
5168
- return override ?? base;
5169
- }
5170
- if (!isPlainObject(base) || !isPlainObject(override)) {
5171
- return override ?? base;
5172
- }
5173
- const result = { ...base };
5174
- for (const [key, value] of Object.entries(override)) {
5175
- if (value === void 0) continue;
5176
- const existing = result[key];
5177
- if (key === "systems" && isPlainObject(existing) && isPlainObject(value)) {
5178
- result[key] = deepMerge(pruneFlatSystemDescendantCollisions(existing, value), value);
5179
- continue;
4060
+ reviewAndExport: {
4061
+ id: "review-and-export",
4062
+ label: "Reviewed and exported",
4063
+ description: "Operator QC approves or rejects qualified companies, then approved records are exported as a lead list with unverified emails.",
4064
+ primaryEntity: "company",
4065
+ outputs: ["export"],
4066
+ stageKey: "uploaded",
4067
+ recordsStageKey: "uploaded",
4068
+ recordSourceStageKey: "qualified",
4069
+ dependsOn: ["enrich-decision-makers"],
4070
+ dependencyMode: "per-record-eligibility",
4071
+ actionKey: "lead-gen.export.list",
4072
+ defaultBatchSize: 100,
4073
+ maxBatchSize: 250,
4074
+ recordColumns: DTC_RECORD_COLUMNS.uploaded,
4075
+ credentialRequirements: [
4076
+ {
4077
+ key: "clickup",
4078
+ provider: "clickup",
4079
+ credentialType: "api-key-secret",
4080
+ label: "ClickUp API token",
4081
+ required: true,
4082
+ selectionMode: "single",
4083
+ inputPath: "clickupCredential",
4084
+ verifyOnRun: true
4085
+ }
4086
+ ]
5180
4087
  }
5181
- result[key] = isPlainObject(existing) && isPlainObject(value) ? deepMerge(existing, value) : value;
5182
- }
5183
- return result;
5184
- }
5185
- function resolveOrganizationModel(override, organizationIdOrOptions, options) {
5186
- const resolvedOptions = typeof organizationIdOrOptions === "object" ? organizationIdOrOptions : options;
5187
- const mergeDefaults = resolvedOptions?.mergeDefaults ?? true;
5188
- const merged = mergeDefaults ? deepMerge(DEFAULT_ORGANIZATION_MODEL, override) : override ?? {};
5189
- return OrganizationModelSchema.parse(merged);
5190
- }
5191
-
5192
- // ../core/src/organization-model/surface-projection.ts
5193
- function collectSystemsById(model) {
5194
- const systemsById = /* @__PURE__ */ new Map();
5195
- for (const { path, system } of listAllSystems(model)) {
5196
- systemsById.set(path, system);
5197
- systemsById.set(system.id, system);
5198
- }
5199
- return systemsById;
5200
- }
5201
- function getSystemWithAncestors(systemsById, systemId) {
5202
- const systems = [];
5203
- let current = systemsById.get(systemId);
5204
- while (current !== void 0) {
5205
- systems.unshift(current);
5206
- current = current.parentSystemId ? systemsById.get(current.parentSystemId) : void 0;
5207
4088
  }
5208
- return systems;
5209
- }
5210
- function hasInheritedFlag(systemsById, systemIds, flag) {
5211
- return systemIds.some(
5212
- (systemId) => getSystemWithAncestors(systemsById, systemId).some((system) => system[flag] === true)
5213
- );
5214
- }
5215
- function isLifecycleEnabled2(system) {
5216
- if (system.enabled === false) return false;
5217
- return system.lifecycle !== "deprecated" && system.lifecycle !== "archived";
5218
- }
5219
- function isLifecycleDevOnly(system) {
5220
- return system.devOnly === true || system.lifecycle === "beta";
5221
- }
5222
- function isSystemEnabled(systemsById, systemId) {
5223
- const systemLineage = getSystemWithAncestors(systemsById, systemId);
5224
- return systemLineage.length > 0 && systemLineage.every(isLifecycleEnabled2);
5225
- }
5226
- function unique(values) {
5227
- return [...new Set(values)];
5228
- }
5229
- function collectSidebarSurfaces(nodes, schemaPath, surfaces = []) {
5230
- getSortedSidebarEntries(nodes).forEach(([id, node]) => {
5231
- const nodePath = [...schemaPath, id];
5232
- if (node.type === "group") {
5233
- collectSidebarSurfaces(node.children, [...nodePath, "children"], surfaces);
5234
- return;
5235
- }
5236
- surfaces.push({ id, surface: node, path: nodePath });
5237
- });
5238
- return surfaces;
5239
- }
5240
- function getSidebarSurfaces(model) {
5241
- return [
5242
- ...collectSidebarSurfaces(model.navigation.sidebar.primary, ["navigation", "sidebar", "primary"]),
5243
- ...collectSidebarSurfaces(model.navigation.sidebar.bottom, ["navigation", "sidebar", "bottom"])
5244
- ];
5245
- }
5246
- function projectOrganizationSurfaces(model) {
5247
- const systemsById = collectSystemsById(model);
5248
- return getSidebarSurfaces(model).map(({ id, surface }) => {
5249
- const targets = surface.targets ?? {};
5250
- const systemIds = unique((targets.systems ?? []).filter((systemId) => systemsById.has(systemId)));
5251
- const enabled = systemIds.every((candidate) => isSystemEnabled(systemsById, candidate));
5252
- const devOnly = surface.devOnly === true || hasInheritedFlag(systemsById, systemIds, "devOnly") || systemIds.some((candidate) => getSystemWithAncestors(systemsById, candidate).some(isLifecycleDevOnly));
5253
- const requiresAdmin = hasInheritedFlag(systemsById, systemIds, "requiresAdmin");
5254
- return {
5255
- id,
5256
- label: surface.label,
5257
- path: surface.path,
5258
- surfaceType: surface.surfaceType,
5259
- ...surface.description !== void 0 ? { description: surface.description } : {},
5260
- ...surface.icon !== void 0 ? { icon: surface.icon } : {},
5261
- ...surface.order !== void 0 ? { order: surface.order } : {},
5262
- systemIds,
5263
- entityIds: [...targets.entities ?? []],
5264
- resourceIds: [...targets.resources ?? []],
5265
- actionIds: [...targets.actions ?? []],
5266
- enabled,
5267
- ...devOnly ? { devOnly } : {},
5268
- ...surface.requiresAdmin === true || requiresAdmin ? { requiresAdmin: true } : {}
5269
- };
5270
- });
5271
- }
4089
+ };
5272
4090
 
5273
- export { ActionSchema, AgentResourceEntrySchema, CRM_DISCOVERY_BOOKING_CANCELLED_STATE, CRM_DISCOVERY_LINK_SENT_STATE, CRM_DISCOVERY_NUDGING_STATE, CRM_DISCOVERY_REPLIED_STATE, CRM_PIPELINE_DEFINITION, CRM_PRIORITY_BUCKETS, DEFAULT_CRM_PRIORITY_RULE_CONFIG, DEFAULT_ORGANIZATION_MODEL, EntitySchema, IdentityDomainSchema, IntegrationResourceEntrySchema, LEAD_GEN_PIPELINE_DEFINITIONS, LEAD_GEN_STAGE_CATALOG, OntologyIdSchema, PROJECTS_VIEW_ACTION_ID, PROSPECTING_STEPS, PolicySchema, RoleSchema, SalesStageSchema, ScriptResourceEntrySchema, SurfaceDefinitionSchema, SystemEntrySchema, WorkflowResourceEntrySchema, ancestorsOf, buildOrganizationGraph, childrenOf, compileOrganizationOntology, defaultPathFor, devOnlyFor, findById, findByPath, findPipeline, formatOntologyId, getContent, getResourcesForSystem, getSortedSidebarEntries, getSystem, getSystemAncestors, listAllSystems, lookupContentType, ontologyGraphNodeId, parentOf, parseOntologyId, projectOrganizationSurfaces, requiresAdminFor, resolveOrganizationModel, resolveSystemConfig, topLevel };
4091
+ export { ActionSchema, AgentResourceEntrySchema, CRM_DISCOVERY_BOOKING_CANCELLED_STATE, CRM_DISCOVERY_LINK_SENT_STATE, CRM_DISCOVERY_NUDGING_STATE, CRM_DISCOVERY_REPLIED_STATE, EntitySchema, IdentityDomainSchema, IntegrationResourceEntrySchema, OntologyIdSchema, OrgKnowledgeNodeSchema, PROJECTS_VIEW_ACTION_ID, PROSPECTING_STEPS, PolicySchema, RoleSchema, ScriptResourceEntrySchema, SemanticIcon, SurfaceDefinitionSchema, SystemEntrySchema, WorkflowResourceEntrySchema, ancestorsOf, buildOrganizationGraph, childrenOf, compileOrganizationOntology, defaultPathFor, defineResources, defineTopology, devOnlyFor, extendSemanticIconRegistry, findById, findByPath, findPipeline, getLeadGenStageCatalog, getResourcesForSystem, getSemanticIconComponent, getSortedSidebarEntries, getSystem, getSystemAncestors, listAllSystems, ontologyGraphNodeId, parentOf, parseOntologyId, projectOrganizationSurfaces, requiresAdminFor, resolveOrganizationModel, resolveSemanticIconComponent, resolveSystemConfig, topLevel, topologyRef, topologyRelationship };