@elevasis/core 0.17.0 → 0.19.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 (44) hide show
  1. package/dist/index.d.ts +82 -1
  2. package/dist/index.js +291 -171
  3. package/dist/knowledge/index.d.ts +43 -0
  4. package/dist/organization-model/index.d.ts +82 -1
  5. package/dist/organization-model/index.js +291 -171
  6. package/dist/test-utils/index.d.ts +41 -12
  7. package/dist/test-utils/index.js +291 -171
  8. package/package.json +2 -1
  9. package/src/_gen/__tests__/__snapshots__/contracts.md.snap +78 -65
  10. package/src/auth/multi-tenancy/organizations/__tests__/api-schemas.test.ts +194 -0
  11. package/src/auth/multi-tenancy/organizations/api-schemas.ts +136 -128
  12. package/src/business/acquisition/api-schemas.test.ts +100 -2
  13. package/src/business/acquisition/api-schemas.ts +81 -43
  14. package/src/business/acquisition/build-templates.test.ts +212 -0
  15. package/src/business/acquisition/types.ts +21 -38
  16. package/src/execution/engine/index.ts +436 -434
  17. package/src/execution/engine/tools/integration/server/adapters/google-calendar/google-calendar-adapter.ts +428 -0
  18. package/src/execution/engine/tools/integration/server/adapters/google-calendar/index.ts +2 -0
  19. package/src/execution/engine/tools/lead-service-types.ts +51 -9
  20. package/src/execution/engine/tools/platform/acquisition/company-tools.ts +7 -6
  21. package/src/execution/engine/tools/platform/acquisition/contact-tools.ts +6 -5
  22. package/src/execution/engine/tools/platform/acquisition/types.ts +20 -9
  23. package/src/execution/engine/tools/registry.ts +700 -698
  24. package/src/execution/engine/tools/tool-maps.ts +10 -0
  25. package/src/execution/external/__tests__/api-schemas.test.ts +127 -0
  26. package/src/integrations/oauth/__tests__/provider-registry.test.ts +7 -6
  27. package/src/integrations/oauth/provider-registry.ts +74 -61
  28. package/src/integrations/oauth/server/credentials.ts +43 -39
  29. package/src/knowledge/__tests__/queries.test.ts +89 -0
  30. package/src/organization-model/__tests__/icons.test.ts +61 -0
  31. package/src/organization-model/__tests__/knowledge.test.ts +118 -1
  32. package/src/organization-model/__tests__/prospecting-ssot.test.ts +94 -0
  33. package/src/organization-model/defaults.ts +8 -0
  34. package/src/organization-model/domains/knowledge.ts +9 -0
  35. package/src/organization-model/domains/prospecting.ts +272 -226
  36. package/src/organization-model/domains/sales.ts +32 -25
  37. package/src/organization-model/icons.ts +3 -0
  38. package/src/organization-model/types.ts +9 -1
  39. package/src/platform/constants/versions.ts +1 -1
  40. package/src/platform/utils/__tests__/validation.test.ts +1084 -1083
  41. package/src/platform/utils/validation.ts +425 -425
  42. package/src/reference/_generated/contracts.md +78 -65
  43. package/src/server.ts +6 -0
  44. package/src/supabase/database.types.ts +6 -12
@@ -1,5 +1,10 @@
1
1
  import { describe, expect, it } from 'vitest'
2
- import { OrgKnowledgeNodeSchema, OrgKnowledgeKindSchema, KnowledgeDomainSchema } from '../domains/knowledge'
2
+ import {
3
+ OrgKnowledgeNodeSchema,
4
+ OrgKnowledgeKindSchema,
5
+ KnowledgeDomainSchema,
6
+ KnowledgeLinkSchema
7
+ } from '../domains/knowledge'
3
8
  import { OrganizationGraphEdgeKindSchema } from '../graph/schema'
4
9
  import { buildOrganizationGraph } from '../graph/build'
5
10
  import { DEFAULT_ORGANIZATION_MODEL, DEFAULT_ORGANIZATION_MODEL_KNOWLEDGE } from '../defaults'
@@ -212,3 +217,115 @@ describe('buildOrganizationGraph with knowledge', () => {
212
217
  expect(defaultKnowledgeNodes).toHaveLength(0)
213
218
  })
214
219
  })
220
+
221
+ // ---------------------------------------------------------------------------
222
+ // KnowledgeLinkSchema — nodeId format validation
223
+ // ---------------------------------------------------------------------------
224
+
225
+ describe('KnowledgeLinkSchema', () => {
226
+ it('accepts a valid kind:dotted-path nodeId', () => {
227
+ expect(() => KnowledgeLinkSchema.parse({ nodeId: 'feature:sales.crm' })).not.toThrow()
228
+ expect(() => KnowledgeLinkSchema.parse({ nodeId: 'feature:sales.lead-gen' })).not.toThrow()
229
+ })
230
+
231
+ it('accepts resource: and knowledge: prefixed node IDs', () => {
232
+ expect(() => KnowledgeLinkSchema.parse({ nodeId: 'resource:my-resource' })).not.toThrow()
233
+ expect(() => KnowledgeLinkSchema.parse({ nodeId: 'knowledge:knowledge.test-doc' })).not.toThrow()
234
+ })
235
+
236
+ it('rejects a bare dotted ID with no kind: prefix', () => {
237
+ // NodeIdStringSchema requires kind:dotted-path format
238
+ expect(KnowledgeLinkSchema.safeParse({ nodeId: 'sales.crm' }).success).toBe(false)
239
+ })
240
+
241
+ it('rejects an empty nodeId', () => {
242
+ expect(KnowledgeLinkSchema.safeParse({ nodeId: '' }).success).toBe(false)
243
+ })
244
+
245
+ it('rejects a nodeId with uppercase characters', () => {
246
+ // NodeIdStringSchema regex requires lowercase
247
+ expect(KnowledgeLinkSchema.safeParse({ nodeId: 'Feature:Sales.CRM' }).success).toBe(false)
248
+ })
249
+
250
+ it('rejects a link missing the nodeId field', () => {
251
+ expect(KnowledgeLinkSchema.safeParse({}).success).toBe(false)
252
+ })
253
+
254
+ it('rejects a plain number as nodeId', () => {
255
+ expect(KnowledgeLinkSchema.safeParse({ nodeId: 123 }).success).toBe(false)
256
+ })
257
+ })
258
+
259
+ // ---------------------------------------------------------------------------
260
+ // OrgKnowledgeNodeSchema — field length constraints
261
+ // ---------------------------------------------------------------------------
262
+
263
+ describe('OrgKnowledgeNodeSchema length constraints', () => {
264
+ const BASE = {
265
+ id: 'knowledge.test-node',
266
+ kind: 'playbook',
267
+ title: 'Test Node',
268
+ summary: 'A valid summary.',
269
+ body: 'Body content.',
270
+ links: [],
271
+ ownerIds: [],
272
+ updatedAt: '2026-05-01'
273
+ }
274
+
275
+ it('rejects title exceeding 200 characters', () => {
276
+ const result = OrgKnowledgeNodeSchema.safeParse({ ...BASE, title: 'x'.repeat(201) })
277
+ expect(result.success).toBe(false)
278
+ })
279
+
280
+ it('accepts title exactly at 200 characters', () => {
281
+ const result = OrgKnowledgeNodeSchema.safeParse({ ...BASE, title: 'x'.repeat(200) })
282
+ expect(result.success).toBe(true)
283
+ })
284
+
285
+ it('rejects summary exceeding 1000 characters', () => {
286
+ const result = OrgKnowledgeNodeSchema.safeParse({ ...BASE, summary: 'x'.repeat(1001) })
287
+ expect(result.success).toBe(false)
288
+ })
289
+
290
+ it('accepts summary exactly at 1000 characters', () => {
291
+ const result = OrgKnowledgeNodeSchema.safeParse({ ...BASE, summary: 'x'.repeat(1000) })
292
+ expect(result.success).toBe(true)
293
+ })
294
+
295
+ it('rejects empty title', () => {
296
+ const result = OrgKnowledgeNodeSchema.safeParse({ ...BASE, title: '' })
297
+ expect(result.success).toBe(false)
298
+ })
299
+
300
+ it('rejects empty summary', () => {
301
+ const result = OrgKnowledgeNodeSchema.safeParse({ ...BASE, summary: '' })
302
+ expect(result.success).toBe(false)
303
+ })
304
+
305
+ it('rejects empty body', () => {
306
+ const result = OrgKnowledgeNodeSchema.safeParse({ ...BASE, body: '' })
307
+ expect(result.success).toBe(false)
308
+ })
309
+
310
+ it('rejects id with uppercase characters', () => {
311
+ // ModelIdSchema requires lowercase kebab/dot/underscore separated IDs
312
+ const result = OrgKnowledgeNodeSchema.safeParse({ ...BASE, id: 'Knowledge.Test' })
313
+ expect(result.success).toBe(false)
314
+ })
315
+
316
+ it('rejects id exceeding 100 characters', () => {
317
+ const result = OrgKnowledgeNodeSchema.safeParse({ ...BASE, id: 'knowledge.' + 'a'.repeat(95) })
318
+ expect(result.success).toBe(false)
319
+ })
320
+
321
+ it('accepts a valid custom icon token on a node', () => {
322
+ const result = OrgKnowledgeNodeSchema.safeParse({ ...BASE, icon: 'custom.my-icon' })
323
+ expect(result.success).toBe(true)
324
+ })
325
+
326
+ it('trims whitespace from title and summary', () => {
327
+ const node = OrgKnowledgeNodeSchema.parse({ ...BASE, title: ' Trimmed ', summary: ' Summary. ' })
328
+ expect(node.title).toBe('Trimmed')
329
+ expect(node.summary).toBe('Summary.')
330
+ })
331
+ })
@@ -0,0 +1,94 @@
1
+ import { describe, expect, it } from 'vitest'
2
+ import { LEAD_GEN_STAGE_CATALOG } from '../domains/sales'
3
+ import {
4
+ CAPABILITY_REGISTRY,
5
+ DEFAULT_ORGANIZATION_MODEL_PROSPECTING,
6
+ PROSPECTING_STEPS
7
+ } from '../domains/prospecting'
8
+
9
+ const EXPECTED_CAPABILITY_REGISTRY = {
10
+ 'lead-gen.company.source': 'lgn-import-workflow',
11
+ 'lead-gen.company.apollo-import': 'lgn-01c-apollo-import-workflow',
12
+ 'lead-gen.contact.discover': 'lgn-04-email-discovery-workflow',
13
+ 'lead-gen.contact.verify-email': 'lgn-05-email-verification-workflow',
14
+ 'lead-gen.company.website-extract': 'lgn-02-website-extract-workflow',
15
+ 'lead-gen.company.qualify': 'lgn-03-company-qualification-workflow',
16
+ 'lead-gen.company.dtc-subscription-qualify': 'lgn-03b-dtc-subscription-score-workflow',
17
+ 'lead-gen.contact.apollo-decision-maker-enrich': 'lgn-04b-apollo-decision-maker-enrich-workflow',
18
+ 'lead-gen.contact.personalize': 'ist-personalization-workflow',
19
+ 'lead-gen.review.outreach-ready': 'ist-upload-contacts-workflow',
20
+ 'lead-gen.export.list': 'lgn-06-export-list-workflow',
21
+ 'lead-gen.company.cleanup': 'lgn-company-cleanup-workflow'
22
+ }
23
+
24
+ describe('prospecting organization-model SSOT', () => {
25
+ it('catalogs the DTC decision-maker enrichment stage', () => {
26
+ expect(LEAD_GEN_STAGE_CATALOG['decision-makers-enriched']).toEqual({
27
+ key: 'decision-makers-enriched',
28
+ label: 'Decision-makers found',
29
+ description: 'Decision-maker contacts discovered and attached to a qualified company.',
30
+ order: 6,
31
+ entity: 'company'
32
+ })
33
+ })
34
+
35
+ it('scopes prospecting steps per build template', () => {
36
+ expect(PROSPECTING_STEPS.localServices.findContacts).toMatchObject({
37
+ id: 'find-contacts',
38
+ primaryEntity: 'contact',
39
+ stageKey: 'discovered'
40
+ })
41
+ expect(PROSPECTING_STEPS.dtcApolloClickup.enrichDecisionMakers).toMatchObject({
42
+ id: 'enrich-decision-makers',
43
+ primaryEntity: 'company',
44
+ stageKey: 'decision-makers-enriched'
45
+ })
46
+ })
47
+
48
+ it('uses catalog stage keys for every prospecting step', () => {
49
+ const catalogKeys = new Set(Object.keys(LEAD_GEN_STAGE_CATALOG))
50
+
51
+ for (const templateSteps of Object.values(PROSPECTING_STEPS)) {
52
+ for (const step of Object.values(templateSteps)) {
53
+ expect(catalogKeys.has(step.stageKey), step.id).toBe(true)
54
+ }
55
+ }
56
+ })
57
+
58
+ it('uses registered capabilities for every prospecting step', () => {
59
+ const capabilityKeys = new Set(Object.keys(CAPABILITY_REGISTRY))
60
+
61
+ for (const templateSteps of Object.values(PROSPECTING_STEPS)) {
62
+ for (const step of Object.values(templateSteps)) {
63
+ expect(capabilityKeys.has(step.capabilityKey), step.id).toBe(true)
64
+ }
65
+ }
66
+ })
67
+
68
+ it('derives prospecting lifecycle stages from the stage catalog by entity', () => {
69
+ const expectedCompanyStages = Object.values(LEAD_GEN_STAGE_CATALOG)
70
+ .filter((stage) => stage.entity === 'company')
71
+ .sort((a, b) => a.order - b.order)
72
+ .map(({ key, label, order }) => ({ id: key, label, order }))
73
+
74
+ const expectedContactStages = Object.values(LEAD_GEN_STAGE_CATALOG)
75
+ .filter((stage) => stage.entity === 'contact')
76
+ .sort((a, b) => a.order - b.order)
77
+ .map(({ key, label, order }) => ({ id: key, label, order }))
78
+
79
+ expect(DEFAULT_ORGANIZATION_MODEL_PROSPECTING.companyStages).toEqual(expectedCompanyStages)
80
+ expect(DEFAULT_ORGANIZATION_MODEL_PROSPECTING.contactStages).toEqual(expectedContactStages)
81
+ })
82
+
83
+ it('build templates reference PROSPECTING_STEPS entries', () => {
84
+ const [localServices, dtcApolloClickup] = DEFAULT_ORGANIZATION_MODEL_PROSPECTING.buildTemplates
85
+
86
+ expect(localServices?.steps).toEqual(Object.values(PROSPECTING_STEPS.localServices))
87
+ expect(dtcApolloClickup?.steps).toEqual(Object.values(PROSPECTING_STEPS.dtcApolloClickup))
88
+ })
89
+
90
+ it('covers all known lead-gen capability registry entries', () => {
91
+ expect(CAPABILITY_REGISTRY).toEqual(EXPECTED_CAPABILITY_REGISTRY)
92
+ expect(Object.keys(CAPABILITY_REGISTRY)).toHaveLength(12)
93
+ })
94
+ })
@@ -150,6 +150,14 @@ export const DEFAULT_ORGANIZATION_MODEL: OrganizationModel = {
150
150
  enabled: true,
151
151
  uiPosition: 'sidebar-primary'
152
152
  },
153
+ {
154
+ id: 'monitoring.calendar',
155
+ label: 'Calendar',
156
+ description: 'Google Calendar events and agenda views',
157
+ enabled: true,
158
+ path: '/monitoring/calendar',
159
+ icon: 'feature.calendar'
160
+ },
153
161
  {
154
162
  id: 'monitoring.activity-log',
155
163
  label: 'Activity Log',
@@ -12,6 +12,9 @@ export const KnowledgeLinkSchema = z.object({
12
12
  nodeId: NodeIdStringSchema
13
13
  })
14
14
 
15
+ export const KnowledgeSkillBindingSchema = z.string().trim().min(1).max(120)
16
+ export const KnowledgeDomainBindingSchema = z.string().trim().min(1).max(80)
17
+
15
18
  // ---------------------------------------------------------------------------
16
19
  // OrgKnowledgeNode — single schema, `kind` discriminator drives presentation.
17
20
  // Phase 1: body is raw MDX string (lossless migration from operations/ docs).
@@ -33,6 +36,10 @@ export const OrgKnowledgeNodeSchema = z.object({
33
36
  * Each link emits a `governs` edge: knowledge-node -> target node.
34
37
  */
35
38
  links: z.array(KnowledgeLinkSchema).default([]),
39
+ /** Operator skill or command bindings relevant to this node. */
40
+ skills: z.array(KnowledgeSkillBindingSchema).optional(),
41
+ /** Domain key used to derive fast graph->skill registries. */
42
+ domain: KnowledgeDomainBindingSchema.optional(),
36
43
  /** Identifiers of the roles or members who own this knowledge node. */
37
44
  ownerIds: z.array(ModelIdSchema).default([]),
38
45
  /** ISO date string (YYYY-MM-DD or full ISO 8601) of last meaningful update. */
@@ -50,4 +57,6 @@ export const KnowledgeDomainSchema = z.object({
50
57
  export type OrgKnowledgeNode = z.infer<typeof OrgKnowledgeNodeSchema>
51
58
  export type OrgKnowledgeKind = z.infer<typeof OrgKnowledgeKindSchema>
52
59
  export type KnowledgeLink = z.infer<typeof KnowledgeLinkSchema>
60
+ export type KnowledgeSkillBinding = z.infer<typeof KnowledgeSkillBindingSchema>
61
+ export type KnowledgeDomainBinding = z.infer<typeof KnowledgeDomainBindingSchema>
53
62
  export type KnowledgeDomain = z.infer<typeof KnowledgeDomainSchema>