@elevasis/core 0.21.0 → 0.23.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 (132) hide show
  1. package/dist/index.d.ts +2518 -2169
  2. package/dist/index.js +2495 -1095
  3. package/dist/knowledge/index.d.ts +706 -1044
  4. package/dist/knowledge/index.js +9 -9
  5. package/dist/organization-model/index.d.ts +2518 -2169
  6. package/dist/organization-model/index.js +2495 -1095
  7. package/dist/test-utils/index.d.ts +826 -1014
  8. package/dist/test-utils/index.js +1894 -1032
  9. package/package.json +3 -3
  10. package/src/__tests__/template-core-compatibility.test.ts +11 -79
  11. package/src/_gen/__tests__/__snapshots__/contracts.md.snap +852 -397
  12. package/src/auth/multi-tenancy/permissions.ts +20 -8
  13. package/src/business/README.md +2 -2
  14. package/src/business/acquisition/api-schemas.test.ts +175 -2
  15. package/src/business/acquisition/api-schemas.ts +132 -16
  16. package/src/business/acquisition/build-templates.test.ts +4 -4
  17. package/src/business/acquisition/build-templates.ts +72 -30
  18. package/src/business/acquisition/crm-state-actions.test.ts +13 -11
  19. package/src/business/acquisition/index.ts +12 -0
  20. package/src/business/acquisition/types.ts +7 -3
  21. package/src/business/clients/api-schemas.test.ts +115 -0
  22. package/src/business/clients/api-schemas.ts +158 -0
  23. package/src/business/clients/index.ts +1 -0
  24. package/src/business/deals/api-schemas.ts +8 -0
  25. package/src/business/index.ts +5 -2
  26. package/src/business/projects/types.ts +19 -0
  27. package/src/execution/engine/__tests__/fixtures/test-agents.ts +10 -8
  28. package/src/execution/engine/agent/core/__tests__/agent.test.ts +16 -12
  29. package/src/execution/engine/agent/core/__tests__/error-passthrough.test.ts +4 -3
  30. package/src/execution/engine/agent/core/types.ts +25 -15
  31. package/src/execution/engine/agent/index.ts +6 -4
  32. package/src/execution/engine/agent/reasoning/__tests__/request-builder.test.ts +24 -18
  33. package/src/execution/engine/index.ts +3 -0
  34. package/src/execution/engine/workflow/types.ts +9 -2
  35. package/src/knowledge/README.md +8 -7
  36. package/src/knowledge/__tests__/queries.test.ts +74 -73
  37. package/src/knowledge/format.ts +10 -9
  38. package/src/knowledge/index.ts +1 -1
  39. package/src/knowledge/published.ts +1 -1
  40. package/src/knowledge/queries.ts +26 -25
  41. package/src/organization-model/README.md +73 -26
  42. package/src/organization-model/__tests__/content-kinds-registry.test.ts +210 -0
  43. package/src/organization-model/__tests__/defaults.test.ts +76 -96
  44. package/src/organization-model/__tests__/domains/actions.test.ts +56 -0
  45. package/src/organization-model/__tests__/domains/customers.test.ts +299 -295
  46. package/src/organization-model/__tests__/domains/entities.test.ts +56 -0
  47. package/src/organization-model/__tests__/domains/goals.test.ts +493 -479
  48. package/src/organization-model/__tests__/domains/identity.test.ts +280 -279
  49. package/src/organization-model/__tests__/domains/navigation.test.ts +268 -212
  50. package/src/organization-model/__tests__/domains/offerings.test.ts +414 -419
  51. package/src/organization-model/__tests__/domains/policies.test.ts +323 -0
  52. package/src/organization-model/__tests__/domains/resource-mappings.test.ts +271 -271
  53. package/src/organization-model/__tests__/domains/resources.test.ts +310 -0
  54. package/src/organization-model/__tests__/domains/roles.test.ts +463 -347
  55. package/src/organization-model/__tests__/domains/statuses.test.ts +246 -243
  56. package/src/organization-model/__tests__/domains/systems.test.ts +209 -0
  57. package/src/organization-model/__tests__/flatten-additive-merge.test.ts +361 -0
  58. package/src/organization-model/__tests__/foundation.test.ts +74 -102
  59. package/src/organization-model/__tests__/get-resources-for-system.test.ts +144 -0
  60. package/src/organization-model/__tests__/graph.test.ts +899 -71
  61. package/src/organization-model/__tests__/knowledge.test.ts +209 -49
  62. package/src/organization-model/__tests__/lookup-helpers.test.ts +438 -0
  63. package/src/organization-model/__tests__/migration-helpers.test.ts +591 -0
  64. package/src/organization-model/__tests__/prospecting-ssot.test.ts +36 -27
  65. package/src/organization-model/__tests__/recursive-system-schema.test.ts +520 -0
  66. package/src/organization-model/__tests__/resolve.test.ts +174 -23
  67. package/src/organization-model/__tests__/schema.test.ts +291 -114
  68. package/src/organization-model/__tests__/surface-projection.test.ts +207 -97
  69. package/src/organization-model/catalogs/lead-gen.ts +144 -0
  70. package/src/organization-model/content-kinds/config.ts +36 -0
  71. package/src/organization-model/content-kinds/index.ts +74 -0
  72. package/src/organization-model/content-kinds/pipeline.ts +68 -0
  73. package/src/organization-model/content-kinds/registry.ts +44 -0
  74. package/src/organization-model/content-kinds/status.ts +71 -0
  75. package/src/organization-model/content-kinds/template.ts +83 -0
  76. package/src/organization-model/content-kinds/types.ts +117 -0
  77. package/src/organization-model/contracts.ts +13 -3
  78. package/src/organization-model/defaults.ts +499 -86
  79. package/src/organization-model/domains/actions.ts +239 -0
  80. package/src/organization-model/domains/customers.ts +78 -75
  81. package/src/organization-model/domains/entities.ts +144 -0
  82. package/src/organization-model/domains/goals.ts +83 -80
  83. package/src/organization-model/domains/knowledge.ts +76 -17
  84. package/src/organization-model/domains/navigation.ts +107 -384
  85. package/src/organization-model/domains/offerings.ts +71 -66
  86. package/src/organization-model/domains/policies.ts +102 -0
  87. package/src/organization-model/domains/projects.ts +14 -48
  88. package/src/organization-model/domains/prospecting.ts +62 -181
  89. package/src/organization-model/domains/resources.ts +145 -0
  90. package/src/organization-model/domains/roles.ts +96 -55
  91. package/src/organization-model/domains/sales.ts +10 -219
  92. package/src/organization-model/domains/shared.ts +57 -57
  93. package/src/organization-model/domains/statuses.ts +339 -130
  94. package/src/organization-model/domains/systems.ts +203 -0
  95. package/src/organization-model/foundation.ts +54 -67
  96. package/src/organization-model/graph/build.ts +682 -54
  97. package/src/organization-model/graph/link.ts +1 -1
  98. package/src/organization-model/graph/schema.ts +24 -9
  99. package/src/organization-model/graph/types.ts +20 -7
  100. package/src/organization-model/helpers.ts +231 -26
  101. package/src/organization-model/icons.ts +1 -0
  102. package/src/organization-model/index.ts +118 -5
  103. package/src/organization-model/migration-helpers.ts +249 -0
  104. package/src/organization-model/organization-graph.mdx +16 -15
  105. package/src/organization-model/organization-model.mdx +111 -44
  106. package/src/organization-model/published.ts +172 -19
  107. package/src/organization-model/resolve.ts +117 -54
  108. package/src/organization-model/schema.ts +654 -112
  109. package/src/organization-model/surface-projection.ts +116 -122
  110. package/src/organization-model/types.ts +146 -20
  111. package/src/platform/api/types.ts +38 -35
  112. package/src/platform/constants/versions.ts +1 -1
  113. package/src/platform/registry/__tests__/command-view.test.ts +6 -8
  114. package/src/platform/registry/__tests__/resource-link.test.ts +13 -8
  115. package/src/platform/registry/__tests__/resource-registry.integration.test.ts +16 -31
  116. package/src/platform/registry/__tests__/resource-registry.nested-systems.test.ts +245 -0
  117. package/src/platform/registry/__tests__/resource-registry.test.ts +2053 -2005
  118. package/src/platform/registry/__tests__/validation.test.ts +1347 -1086
  119. package/src/platform/registry/index.ts +14 -0
  120. package/src/platform/registry/resource-registry.ts +52 -2
  121. package/src/platform/registry/serialization.ts +241 -202
  122. package/src/platform/registry/serialized-types.ts +1 -0
  123. package/src/platform/registry/types.ts +411 -361
  124. package/src/platform/registry/validation.ts +745 -513
  125. package/src/projects/api-schemas.ts +290 -267
  126. package/src/reference/_generated/contracts.md +853 -397
  127. package/src/reference/glossary.md +23 -18
  128. package/src/supabase/database.types.ts +181 -0
  129. package/src/test-utils/test-utils.test.ts +1 -6
  130. package/src/organization-model/__tests__/domains/operations.test.ts +0 -203
  131. package/src/organization-model/domains/features.ts +0 -31
  132. package/src/organization-model/domains/operations.ts +0 -85
@@ -0,0 +1,145 @@
1
+ import { z } from 'zod'
2
+ import { ModelIdSchema } from './shared'
3
+ import { SystemPathSchema, SystemLifecycleSchema } from './systems'
4
+ import { ActionInvocationSchema } from './actions'
5
+
6
+ // ---------------------------------------------------------------------------
7
+ // Resources domain
8
+ // ---------------------------------------------------------------------------
9
+ //
10
+ // Resources are governance-only OM descriptors. Runtime code imports these
11
+ // descriptors and attaches executable behavior; it does not re-author identity.
12
+
13
+ export const ResourceKindSchema = z
14
+ .enum(['workflow', 'agent', 'integration', 'script'])
15
+ .meta({ label: 'Resource kind', color: 'orange' })
16
+ export const ResourceGovernanceStatusSchema = z
17
+ .enum(['active', 'deprecated', 'archived'])
18
+ .meta({ label: 'Governance status', color: 'teal' })
19
+ export const AgentKindSchema = z
20
+ .enum(['orchestrator', 'specialist', 'utility', 'platform'])
21
+ .meta({ label: 'Agent kind', color: 'violet' })
22
+ export const ScriptResourceLanguageSchema = z.enum(['shell', 'sql', 'typescript', 'python']).meta({ label: 'Language' })
23
+
24
+ export const ResourceIdSchema = z
25
+ .string()
26
+ .trim()
27
+ .min(1)
28
+ .max(255)
29
+ .regex(/^[A-Za-z0-9]+(?:[-._][A-Za-z0-9]+)*$/, 'Resource IDs must use letters, numbers, -, _, or . separators')
30
+
31
+ export const EventIdSchema = z
32
+ .string()
33
+ .trim()
34
+ .min(1)
35
+ .max(300)
36
+ .regex(
37
+ /^[A-Za-z0-9]+(?:[-._][A-Za-z0-9]+)*:[a-z0-9]+(?:[-._][a-z0-9]+)*$/,
38
+ 'Event IDs must use <owner-id>:<event-key>'
39
+ )
40
+
41
+ export const EventKeySchema = ModelIdSchema
42
+
43
+ export const EventEmissionDescriptorSchema = z.object({
44
+ eventKey: EventKeySchema,
45
+ label: z.string().trim().min(1).max(120),
46
+ payloadSchema: ModelIdSchema.optional(),
47
+ lifecycle: SystemLifecycleSchema.optional()
48
+ })
49
+
50
+ export const EventDescriptorSchema = EventEmissionDescriptorSchema.extend({
51
+ id: EventIdSchema,
52
+ ownerId: z.union([ResourceIdSchema, ModelIdSchema]),
53
+ ownerKind: z.enum(['resource', 'entity']).meta({ label: 'Owner kind' })
54
+ })
55
+
56
+ const ResourceEntryBaseSchema = z.object({
57
+ /** Canonical resource id; runtime resourceId derives from this value. */
58
+ id: ResourceIdSchema,
59
+ /** Domain-map iteration order. Convention: multiples of 10 (10, 20, 30, ...) to allow easy insertion. */
60
+ order: z.number().default(0),
61
+ /** Required single System membership — value is a dot-separated system path (e.g. "sales.lead-gen"). */
62
+ systemPath: SystemPathSchema.meta({ ref: 'system' }),
63
+ /** Optional role responsible for maintaining this resource. */
64
+ ownerRoleId: ModelIdSchema.meta({ ref: 'role' }).optional(),
65
+ status: ResourceGovernanceStatusSchema
66
+ })
67
+
68
+ export const WorkflowResourceEntrySchema = ResourceEntryBaseSchema.extend({
69
+ kind: z.literal('workflow'),
70
+ /** Mirrors WorkflowConfig.actionKey when the runtime workflow has one. */
71
+ actionKey: z.string().trim().min(1).max(255).optional(),
72
+ emits: z.array(EventEmissionDescriptorSchema).optional()
73
+ })
74
+
75
+ export const AgentResourceEntrySchema = ResourceEntryBaseSchema.extend({
76
+ kind: z.literal('agent'),
77
+ /** Mirrors code-side AgentConfig.kind. */
78
+ agentKind: AgentKindSchema,
79
+ /** Role this agent embodies, if any. */
80
+ actsAsRoleId: ModelIdSchema.meta({ ref: 'role' }).optional(),
81
+ /** Mirrors AgentConfig.sessionCapable. */
82
+ sessionCapable: z.boolean(),
83
+ /** Broad/composite callable entry points orchestrated by this agent. */
84
+ invocations: z.array(ActionInvocationSchema).default([]),
85
+ emits: z.array(EventEmissionDescriptorSchema).optional()
86
+ })
87
+
88
+ export const IntegrationResourceEntrySchema = ResourceEntryBaseSchema.extend({
89
+ kind: z.literal('integration'),
90
+ provider: z.string().trim().min(1).max(100)
91
+ })
92
+
93
+ export const ScriptResourceSourceSchema = z.union([
94
+ z.string().trim().min(1).max(50_000),
95
+ z.object({
96
+ file: z.string().trim().min(1).max(500)
97
+ })
98
+ ])
99
+
100
+ export const ScriptResourceEntrySchema = ResourceEntryBaseSchema.extend({
101
+ kind: z.literal('script'),
102
+ language: ScriptResourceLanguageSchema,
103
+ source: ScriptResourceSourceSchema
104
+ })
105
+
106
+ export const ResourceEntrySchema = z.discriminatedUnion('kind', [
107
+ WorkflowResourceEntrySchema,
108
+ AgentResourceEntrySchema,
109
+ IntegrationResourceEntrySchema,
110
+ ScriptResourceEntrySchema
111
+ ])
112
+
113
+ export const ResourcesDomainSchema = z
114
+ .record(z.string(), ResourceEntrySchema)
115
+ .refine((record) => Object.entries(record).every(([key, entry]) => entry.id === key), {
116
+ message: 'Each resource entry id must match its map key'
117
+ })
118
+ .default({})
119
+
120
+ export const DEFAULT_ORGANIZATION_MODEL_RESOURCES: z.infer<typeof ResourcesDomainSchema> = {}
121
+
122
+ export function defineResource<const TResource extends ResourceEntry>(resource: TResource): TResource {
123
+ return ResourceEntrySchema.parse(resource) as TResource
124
+ }
125
+
126
+ export function defineResources<const TResources extends Record<string, ResourceEntry>>(
127
+ resources: TResources
128
+ ): TResources {
129
+ return Object.fromEntries(
130
+ Object.entries(resources).map(([key, resource]) => [key, ResourceEntrySchema.parse(resource)])
131
+ ) as TResources
132
+ }
133
+
134
+ export type ResourceId = z.infer<typeof ResourceIdSchema>
135
+ export type ResourceKind = z.infer<typeof ResourceKindSchema>
136
+ export type ResourceGovernanceStatus = z.infer<typeof ResourceGovernanceStatusSchema>
137
+ export type ResourceAgentKind = z.infer<typeof AgentKindSchema>
138
+ export type ScriptResourceLanguage = z.infer<typeof ScriptResourceLanguageSchema>
139
+ export type ScriptResourceSource = z.infer<typeof ScriptResourceSourceSchema>
140
+ export type WorkflowResourceEntry = z.infer<typeof WorkflowResourceEntrySchema>
141
+ export type AgentResourceEntry = z.infer<typeof AgentResourceEntrySchema>
142
+ export type IntegrationResourceEntry = z.infer<typeof IntegrationResourceEntrySchema>
143
+ export type ScriptResourceEntry = z.infer<typeof ScriptResourceEntrySchema>
144
+ export type ResourceEntry = z.infer<typeof ResourceEntrySchema>
145
+ export type ResourcesDomain = z.infer<typeof ResourcesDomainSchema>
@@ -1,55 +1,96 @@
1
- import { z } from 'zod'
2
-
3
- // ---------------------------------------------------------------------------
4
- // Role schema one entry per distinct role in the organization's chart.
5
- // Inspired by the EOS Accountability Chart but uses plain-language field names
6
- // throughout. No EOS jargon: "title" (not seatTitle), "responsibilities"
7
- // (not accountabilities), "reportsToId", "heldBy".
8
- //
9
- // Cross-reference: `reportsToId` (when present) must resolve to another
10
- // `roles[].id` in the same collection. Enforcement is via
11
- // `OrganizationModelSchema.superRefine()` — not at the individual schema level.
12
- // Cycle detection is NOT enforced (known limitation; document if needed).
13
- // ---------------------------------------------------------------------------
14
-
15
- export const RoleSchema = z.object({
16
- /** Stable unique identifier for the role (e.g. "role-ceo", "role-head-of-sales"). */
17
- id: z.string().trim().min(1).max(100),
18
- /** Human-readable title shown to agents and in UI (e.g. "CEO", "Head of Sales"). */
19
- title: z.string().trim().min(1).max(200),
20
- /**
21
- * List of responsibilities this role owns — plain-language descriptions of
22
- * what the person in this role is accountable for delivering.
23
- * Defaults to empty array so minimal role definitions stay concise.
24
- */
25
- responsibilities: z.array(z.string().trim().max(500)).default([]),
26
- /**
27
- * Optional: ID of another role this role reports to.
28
- * When present, must reference another `roles[].id` in the same organization.
29
- * Cross-reference enforced in `OrganizationModelSchema.superRefine()`.
30
- * Absence indicates a top-level role (no reporting line).
31
- */
32
- reportsToId: z.string().trim().min(1).max(100).optional(),
33
- /**
34
- * Optional: name or email of the person currently holding this role.
35
- * Free-form string supports "Alice Johnson", "alice@example.com", or
36
- * any human-readable identifier. Not validated against any user registry.
37
- */
38
- heldBy: z.string().trim().max(200).optional()
39
- })
40
-
41
- // ---------------------------------------------------------------------------
42
- // Roles domain schema — a collection of roles.
43
- // ---------------------------------------------------------------------------
44
-
45
- export const RolesDomainSchema = z.object({
46
- roles: z.array(RoleSchema).default([])
47
- })
48
-
49
- // ---------------------------------------------------------------------------
50
- // Seed — empty by default; adapters populate with real role definitions.
51
- // ---------------------------------------------------------------------------
52
-
53
- export const DEFAULT_ORGANIZATION_MODEL_ROLES: z.infer<typeof RolesDomainSchema> = {
54
- roles: []
55
- }
1
+ import { z } from 'zod'
2
+ import { ResourceIdSchema } from './resources'
3
+ import { ModelIdSchema } from './shared'
4
+ import { SystemIdSchema } from './systems'
5
+
6
+ // ---------------------------------------------------------------------------
7
+ // Role schema - one entry per distinct role in the organization's chart.
8
+ // Inspired by the EOS Accountability Chart but uses plain-language field names
9
+ // throughout. No EOS jargon: "title" (not seatTitle), "responsibilities"
10
+ // (not accountabilities), "reportsToId", "heldBy".
11
+ //
12
+ // Cross-reference enforcement lives in `OrganizationModelSchema.superRefine()`:
13
+ // `reportsToId` must resolve to another Role, `responsibleFor` entries must
14
+ // resolve to Systems, and agent holders must resolve to Agent Resources.
15
+ // Role hierarchy cycle detection is also enforced at the model level.
16
+ // ---------------------------------------------------------------------------
17
+
18
+ export const RoleIdSchema = ModelIdSchema
19
+
20
+ export const HumanRoleHolderSchema = z.object({
21
+ kind: z.literal('human'),
22
+ userId: z.string().trim().min(1).max(200)
23
+ })
24
+
25
+ export const AgentRoleHolderSchema = z.object({
26
+ kind: z.literal('agent'),
27
+ agentId: ResourceIdSchema.meta({ ref: 'resource' })
28
+ })
29
+
30
+ export const TeamRoleHolderSchema = z.object({
31
+ kind: z.literal('team'),
32
+ memberIds: z.array(z.string().trim().min(1).max(200)).min(1)
33
+ })
34
+
35
+ export const RoleHolderSchema = z.discriminatedUnion('kind', [
36
+ HumanRoleHolderSchema,
37
+ AgentRoleHolderSchema,
38
+ TeamRoleHolderSchema
39
+ ])
40
+
41
+ export const RoleHoldersSchema = z.union([RoleHolderSchema, z.array(RoleHolderSchema).min(1)])
42
+
43
+ export const RoleSchema = z.object({
44
+ /** Stable unique identifier for the role (e.g. "role-ceo", "role-head-of-sales"). */
45
+ id: RoleIdSchema,
46
+ /** Domain-map iteration order. Convention: multiples of 10 (10, 20, 30, ...) to allow easy insertion. */
47
+ order: z.number(),
48
+ /** Human-readable title shown to agents and in UI (e.g. "CEO", "Head of Sales"). */
49
+ title: z.string().trim().min(1).max(200),
50
+ /**
51
+ * List of responsibilities this role owns - plain-language descriptions of
52
+ * what the person in this role is accountable for delivering.
53
+ * Defaults to empty array so minimal role definitions stay concise.
54
+ */
55
+ responsibilities: z.array(z.string().trim().max(500)).default([]),
56
+ /**
57
+ * Optional: ID of another role this role reports to.
58
+ * When present, must reference another `roles[].id` in the same organization.
59
+ */
60
+ reportsToId: RoleIdSchema.meta({ ref: 'role' }).optional(),
61
+ /**
62
+ * Optional: human, agent, or team holder currently filling this role.
63
+ * Agent holders reference OM Resource IDs and are validated at the model level.
64
+ */
65
+ heldBy: RoleHoldersSchema.optional(),
66
+ /**
67
+ * Optional Systems this role is accountable for.
68
+ * Cross-reference enforced in `OrganizationModelSchema.superRefine()`.
69
+ */
70
+ responsibleFor: z.array(SystemIdSchema.meta({ ref: 'system' })).optional()
71
+ })
72
+
73
+ // ---------------------------------------------------------------------------
74
+ // Roles domain schema - a collection of roles.
75
+ // ---------------------------------------------------------------------------
76
+
77
+ export const RolesDomainSchema = z
78
+ .record(z.string(), RoleSchema)
79
+ .refine((record) => Object.entries(record).every(([key, entry]) => entry.id === key), {
80
+ message: 'Each role entry id must match its map key'
81
+ })
82
+ .default({})
83
+
84
+ // ---------------------------------------------------------------------------
85
+ // Seed - empty by default; adapters populate with real role definitions.
86
+ // ---------------------------------------------------------------------------
87
+
88
+ export const DEFAULT_ORGANIZATION_MODEL_ROLES: z.infer<typeof RolesDomainSchema> = {}
89
+
90
+ export type RoleId = z.infer<typeof RoleIdSchema>
91
+ export type HumanRoleHolder = z.infer<typeof HumanRoleHolderSchema>
92
+ export type AgentRoleHolder = z.infer<typeof AgentRoleHolderSchema>
93
+ export type TeamRoleHolder = z.infer<typeof TeamRoleHolderSchema>
94
+ export type RoleHolder = z.infer<typeof RoleHolderSchema>
95
+ export type Role = z.infer<typeof RoleSchema>
96
+ export type RolesDomain = z.infer<typeof RolesDomainSchema>
@@ -1,6 +1,16 @@
1
1
  import { z } from 'zod'
2
2
  import { DescriptionSchema, DisplayMetadataSchema, ModelIdSchema, ReferenceIdsSchema } from './shared'
3
3
 
4
+ export { LEAD_GEN_STAGE_CATALOG, type LeadGenStageCatalogEntry } from '../catalogs/lead-gen'
5
+
6
+ // Phase 4 cut: OrganizationModelSalesSchema and DEFAULT_ORGANIZATION_MODEL_SALES removed.
7
+ // Pipeline/stage data moved into system.content as (schema:pipeline) and (schema:stage)
8
+ // content nodes on the owning system (e.g. sales.crm). Use getAllPipelines() /
9
+ // getStagesInPipeline() from migration-helpers to read pipeline data portably.
10
+ //
11
+ // SalesStageSemanticClassSchema, SalesStageSchema, SalesPipelineSchema are retained
12
+ // below as TypeScript types used by CRM business logic and the Stateful pipeline definitions.
13
+
4
14
  export const SalesStageSemanticClassSchema = z.enum(['open', 'active', 'nurturing', 'closed_won', 'closed_lost'])
5
15
 
6
16
  export const SalesStageSchema = DisplayMetadataSchema.extend({
@@ -19,80 +29,6 @@ export const SalesPipelineSchema = z.object({
19
29
  stages: z.array(SalesStageSchema).min(1)
20
30
  })
21
31
 
22
- export const OrganizationModelSalesSchema = z.object({
23
- entityId: ModelIdSchema,
24
- defaultPipelineId: ModelIdSchema,
25
- pipelines: z.array(SalesPipelineSchema).min(1)
26
- })
27
-
28
- export const DEFAULT_ORGANIZATION_MODEL_SALES: z.infer<typeof OrganizationModelSalesSchema> = {
29
- entityId: 'crm.deal',
30
- defaultPipelineId: 'default',
31
- pipelines: [
32
- {
33
- id: 'default',
34
- label: 'Default Pipeline',
35
- entityId: 'crm.deal',
36
- stages: [
37
- {
38
- id: 'interested',
39
- label: 'Interested',
40
- color: 'blue',
41
- order: 1,
42
- semanticClass: 'open',
43
- surfaceIds: ['crm.pipeline'],
44
- resourceIds: []
45
- },
46
- {
47
- id: 'proposal',
48
- label: 'Proposal',
49
- color: 'yellow',
50
- order: 2,
51
- semanticClass: 'active',
52
- surfaceIds: ['crm.pipeline'],
53
- resourceIds: []
54
- },
55
- {
56
- id: 'closing',
57
- label: 'Closing',
58
- color: 'lime',
59
- order: 3,
60
- semanticClass: 'active',
61
- surfaceIds: ['crm.pipeline'],
62
- resourceIds: []
63
- },
64
- {
65
- id: 'closed_won',
66
- label: 'Closed Won',
67
- color: 'green',
68
- order: 4,
69
- semanticClass: 'closed_won',
70
- surfaceIds: ['crm.pipeline'],
71
- resourceIds: []
72
- },
73
- {
74
- id: 'closed_lost',
75
- label: 'Closed Lost',
76
- color: 'red',
77
- order: 5,
78
- semanticClass: 'closed_lost',
79
- surfaceIds: ['crm.pipeline'],
80
- resourceIds: []
81
- },
82
- {
83
- id: 'nurturing',
84
- label: 'Nurturing',
85
- color: 'grape',
86
- order: 6,
87
- semanticClass: 'nurturing',
88
- surfaceIds: ['crm.pipeline'],
89
- resourceIds: []
90
- }
91
- ]
92
- }
93
- ]
94
- }
95
-
96
32
  // ============================================================================
97
33
  // Lead-Gen Stateful Pipeline Definitions (Decision N8, Wave 4)
98
34
  //
@@ -442,148 +378,3 @@ export const LEAD_GEN_PIPELINE_DEFINITIONS: Record<string, StatefulPipelineDefin
442
378
  'acq.list-member': [ACQ_LIST_MEMBERS_LEAD_GEN_PIPELINE],
443
379
  'acq.list-company': [ACQ_LIST_COMPANIES_LEAD_GEN_PIPELINE]
444
380
  }
445
-
446
- // ============================================================================
447
- // Lead-Gen Stage Catalog (OM Spine processing-state model)
448
- //
449
- // Canonical set of processing stage keys for acq_companies.processing_state and
450
- // acq_contacts.processing_state. These keys coordinate build templates, workflow
451
- // factory validation, API filters, and UI progress projections.
452
- //
453
- // State is sparse: absent keys mean "not attempted"; present keys hold terminal
454
- // status entries such as success, no_result, skipped, or error.
455
- //
456
- // Historical sources:
457
- // ACQ_LIST_MEMBERS_LEAD_GEN_PIPELINE → personalized, uploaded, interested,
458
- // discovered, verified
459
- // ACQ_LIST_COMPANIES_LEAD_GEN_PIPELINE → populated, extracted, qualified
460
- // Design plan hint (lead-gen-domain-cleanup.mdx §4) → scraped, enriched
461
- //
462
- // ============================================================================
463
-
464
- /** One entry in the lead-gen stage catalog. */
465
- export interface LeadGenStageCatalogEntry {
466
- /** Matches the status key written into processing_state jsonb (e.g. 'scraped'). */
467
- key: string
468
- /** Human-readable label for UI display. */
469
- label: string
470
- /** Short description of what this stage represents. */
471
- description: string
472
- /** Canonical pipeline order for UI sorting. Lower = earlier in the funnel. */
473
- order: number
474
- /** Which entity's processing_state jsonb carries this stage status. */
475
- entity: 'company' | 'contact'
476
- /** Additional entities allowed to write/read this processing_state key. */
477
- additionalEntities?: Array<'company' | 'contact'>
478
- /**
479
- * Optional read-side override for Records views when a company-scoped step
480
- * produces records on a different entity.
481
- */
482
- recordEntity?: 'company' | 'contact'
483
- /** Stage key to read from recordEntity.processing_state for Records views. */
484
- recordStageKey?: string
485
- }
486
-
487
- /**
488
- * Canonical lead-gen processing stage catalog.
489
- * Keys are the stage names written by workflow steps into processing_state jsonb.
490
- *
491
- * Ordered roughly by pipeline progression (prospecting → outreach → qualification).
492
- */
493
- export const LEAD_GEN_STAGE_CATALOG: Record<string, LeadGenStageCatalogEntry> = {
494
- // Prospecting — company population
495
- scraped: {
496
- key: 'scraped',
497
- label: 'Scraped',
498
- description: 'Company was scraped from a source directory (Apify actor run).',
499
- order: 1,
500
- entity: 'company'
501
- },
502
- populated: {
503
- key: 'populated',
504
- label: 'Companies found',
505
- description: 'Companies have been found and added to the lead-gen list.',
506
- order: 2,
507
- entity: 'company'
508
- },
509
- crawled: {
510
- key: 'crawled',
511
- label: 'Websites crawled',
512
- description:
513
- 'Company websites have been crawled (e.g. via Apify) and raw page content stored for downstream LLM analysis.',
514
- order: 2.5,
515
- entity: 'company'
516
- },
517
- extracted: {
518
- key: 'extracted',
519
- label: 'Websites analyzed',
520
- description: 'Company websites have been analyzed for business signals.',
521
- order: 3,
522
- entity: 'company'
523
- },
524
- enriched: {
525
- key: 'enriched',
526
- label: 'Enriched',
527
- description: 'Company or contact enriched with third-party data (e.g. Tomba, Anymailfinder).',
528
- order: 4,
529
- entity: 'company'
530
- },
531
- 'decision-makers-enriched': {
532
- key: 'decision-makers-enriched',
533
- label: 'Decision-makers found',
534
- description: 'Decision-maker contacts discovered and attached to a qualified company.',
535
- order: 6,
536
- entity: 'company',
537
- recordEntity: 'contact',
538
- recordStageKey: 'discovered'
539
- },
540
-
541
- // Prospecting — contact discovery
542
- discovered: {
543
- key: 'discovered',
544
- label: 'Decision-makers found',
545
- description: 'Decision-maker contact details have been found.',
546
- order: 5,
547
- entity: 'contact'
548
- },
549
- verified: {
550
- key: 'verified',
551
- label: 'Emails verified',
552
- description: 'Contact email addresses have been checked for deliverability.',
553
- order: 7,
554
- entity: 'contact'
555
- },
556
-
557
- // Qualification
558
- qualified: {
559
- key: 'qualified',
560
- label: 'Companies qualified',
561
- description: 'Companies have been scored against the qualification criteria.',
562
- order: 8,
563
- entity: 'company'
564
- },
565
-
566
- // Outreach
567
- personalized: {
568
- key: 'personalized',
569
- label: 'Personalized',
570
- description: 'Outreach message personalized for the contact (Instantly personalization workflow).',
571
- order: 9,
572
- entity: 'contact'
573
- },
574
- uploaded: {
575
- key: 'uploaded',
576
- label: 'Reviewed and exported',
577
- description: 'Approved records have been reviewed and exported for handoff.',
578
- order: 10,
579
- entity: 'company',
580
- additionalEntities: ['contact']
581
- },
582
- interested: {
583
- key: 'interested',
584
- label: 'Interested',
585
- description: 'Contact replied with a positive signal (Instantly reply-handler transition).',
586
- order: 11,
587
- entity: 'contact'
588
- }
589
- }
@@ -1,63 +1,63 @@
1
1
  import { z } from 'zod'
2
2
  import { OrganizationModelIconTokenSchema } from '../icons'
3
-
4
- export const ModelIdSchema = z
5
- .string()
6
- .trim()
7
- .min(1)
8
- .max(100)
9
- .regex(/^[a-z0-9]+(?:[-._][a-z0-9]+)*$/, 'IDs must be lowercase and use -, _, or . separators')
10
-
11
- export const LabelSchema = z.string().trim().min(1).max(120)
3
+
4
+ export const ModelIdSchema = z
5
+ .string()
6
+ .trim()
7
+ .min(1)
8
+ .max(100)
9
+ .regex(/^[a-z0-9]+(?:[-._][a-z0-9]+)*$/, 'IDs must be lowercase and use -, _, or . separators')
10
+
11
+ export const LabelSchema = z.string().trim().min(1).max(120)
12
12
  export const DescriptionSchema = z.string().trim().min(1).max(2000)
13
13
  export const ColorTokenSchema = z.string().trim().min(1).max(50)
14
14
  export const IconNameSchema = OrganizationModelIconTokenSchema
15
15
  export const PathSchema = z.string().trim().startsWith('/').max(300)
16
-
17
- export const ReferenceIdsSchema = z.array(ModelIdSchema).default([])
18
-
19
- export const DisplayMetadataSchema = z.object({
20
- label: LabelSchema,
21
- description: DescriptionSchema.optional(),
22
- color: ColorTokenSchema.optional(),
23
- icon: IconNameSchema.optional()
24
- })
25
-
26
- // ---------------------------------------------------------------------------
27
- // TechStack subsection — optional extension on a ResourceMapping entry that
28
- // captures external-SaaS integration metadata: which platform, its purpose,
29
- // credential health, and whether it is the system of record for its domain.
30
- // Backward-compatible: existing entries without this key parse cleanly.
31
- // ---------------------------------------------------------------------------
32
-
33
- export const TechStackEntrySchema = z.object({
34
- /** Name of the external platform (e.g. "HubSpot", "Stripe", "Notion"). */
35
- platform: z.string().trim().min(1).max(200),
36
- /** Free-form description of what this integration is used for. */
37
- purpose: z.string().trim().min(1).max(500),
38
- /**
39
- * Health of the credential backing this integration.
40
- * - configured: credential present and valid
41
- * - pending: not yet set up
42
- * - expired: credential existed but has lapsed
43
- * - missing: expected but not present
44
- */
45
- credentialStatus: z.enum(['configured', 'pending', 'expired', 'missing']),
46
- /**
47
- * Whether this integration is the primary system of record for its domain
48
- * (e.g. HubSpot is SoR for contacts). Defaults to false.
49
- */
50
- isSystemOfRecord: z.boolean().default(false)
51
- })
52
-
53
- export const ResourceMappingSchema = DisplayMetadataSchema.extend({
54
- id: ModelIdSchema,
55
- resourceId: z.string().trim().min(1).max(255),
56
- resourceType: z.enum(['workflow', 'agent', 'trigger', 'integration', 'external', 'human_checkpoint']),
57
- featureIds: ReferenceIdsSchema,
58
- entityIds: ReferenceIdsSchema,
59
- surfaceIds: ReferenceIdsSchema,
60
- capabilityIds: ReferenceIdsSchema,
61
- /** Optional tech-stack metadata for external-SaaS integrations. */
62
- techStack: TechStackEntrySchema.optional()
63
- })
16
+
17
+ export const ReferenceIdsSchema = z.array(ModelIdSchema).default([])
18
+
19
+ export const DisplayMetadataSchema = z.object({
20
+ label: LabelSchema,
21
+ description: DescriptionSchema.optional(),
22
+ color: ColorTokenSchema.optional(),
23
+ icon: IconNameSchema.optional()
24
+ })
25
+
26
+ // ---------------------------------------------------------------------------
27
+ // TechStack subsection — optional extension on a ResourceMapping entry that
28
+ // captures external-SaaS integration metadata: which platform, its purpose,
29
+ // credential health, and whether it is the system of record for its domain.
30
+ // Backward-compatible: existing entries without this key parse cleanly.
31
+ // ---------------------------------------------------------------------------
32
+
33
+ export const TechStackEntrySchema = z.object({
34
+ /** Name of the external platform (e.g. "HubSpot", "Stripe", "Notion"). */
35
+ platform: z.string().trim().min(1).max(200),
36
+ /** Free-form description of what this integration is used for. */
37
+ purpose: z.string().trim().min(1).max(500),
38
+ /**
39
+ * Health of the credential backing this integration.
40
+ * - configured: credential present and valid
41
+ * - pending: not yet set up
42
+ * - expired: credential existed but has lapsed
43
+ * - missing: expected but not present
44
+ */
45
+ credentialStatus: z.enum(['configured', 'pending', 'expired', 'missing']),
46
+ /**
47
+ * Whether this integration is the primary system of record for its domain
48
+ * (e.g. HubSpot is SoR for contacts). Defaults to false.
49
+ */
50
+ isSystemOfRecord: z.boolean().default(false)
51
+ })
52
+
53
+ export const ResourceMappingSchema = DisplayMetadataSchema.extend({
54
+ id: ModelIdSchema,
55
+ resourceId: z.string().trim().min(1).max(255),
56
+ resourceType: z.enum(['workflow', 'agent', 'trigger', 'integration', 'external', 'human_checkpoint']),
57
+ systemIds: ReferenceIdsSchema,
58
+ entityIds: ReferenceIdsSchema,
59
+ surfaceIds: ReferenceIdsSchema,
60
+ actionIds: ReferenceIdsSchema,
61
+ /** Optional tech-stack metadata for external-SaaS integrations. */
62
+ techStack: TechStackEntrySchema.optional()
63
+ })