@elevasis/core 0.21.0 → 0.22.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 (59) hide show
  1. package/dist/index.d.ts +416 -6
  2. package/dist/index.js +240 -15
  3. package/dist/knowledge/index.d.ts +97 -1
  4. package/dist/organization-model/index.d.ts +416 -6
  5. package/dist/organization-model/index.js +240 -15
  6. package/dist/test-utils/index.d.ts +216 -1
  7. package/dist/test-utils/index.js +230 -14
  8. package/package.json +3 -3
  9. package/src/_gen/__tests__/__snapshots__/contracts.md.snap +495 -302
  10. package/src/auth/multi-tenancy/permissions.ts +20 -8
  11. package/src/business/README.md +2 -2
  12. package/src/business/acquisition/api-schemas.test.ts +173 -0
  13. package/src/business/acquisition/api-schemas.ts +125 -7
  14. package/src/business/acquisition/index.ts +12 -0
  15. package/src/business/clients/api-schemas.test.ts +115 -0
  16. package/src/business/clients/api-schemas.ts +158 -0
  17. package/src/business/clients/index.ts +1 -0
  18. package/src/business/deals/api-schemas.ts +8 -0
  19. package/src/business/index.ts +5 -2
  20. package/src/business/projects/types.ts +19 -0
  21. package/src/execution/engine/__tests__/fixtures/test-agents.ts +10 -8
  22. package/src/execution/engine/agent/core/__tests__/agent.test.ts +16 -12
  23. package/src/execution/engine/agent/core/__tests__/error-passthrough.test.ts +4 -3
  24. package/src/execution/engine/agent/core/types.ts +25 -15
  25. package/src/execution/engine/agent/index.ts +6 -4
  26. package/src/execution/engine/agent/reasoning/__tests__/request-builder.test.ts +24 -18
  27. package/src/execution/engine/index.ts +3 -0
  28. package/src/execution/engine/workflow/types.ts +7 -0
  29. package/src/organization-model/README.md +10 -3
  30. package/src/organization-model/__tests__/defaults.test.ts +6 -0
  31. package/src/organization-model/__tests__/domains/resources.test.ts +188 -0
  32. package/src/organization-model/__tests__/domains/roles.test.ts +402 -347
  33. package/src/organization-model/__tests__/domains/systems.test.ts +193 -0
  34. package/src/organization-model/__tests__/knowledge.test.ts +39 -0
  35. package/src/organization-model/__tests__/resolve.test.ts +1 -1
  36. package/src/organization-model/defaults.ts +24 -3
  37. package/src/organization-model/domains/knowledge.ts +3 -2
  38. package/src/organization-model/domains/resources.ts +88 -0
  39. package/src/organization-model/domains/roles.ts +93 -55
  40. package/src/organization-model/domains/systems.ts +46 -0
  41. package/src/organization-model/icons.ts +1 -0
  42. package/src/organization-model/index.ts +2 -0
  43. package/src/organization-model/organization-model.mdx +33 -14
  44. package/src/organization-model/published.ts +52 -1
  45. package/src/organization-model/schema.ts +121 -0
  46. package/src/organization-model/types.ts +46 -1
  47. package/src/platform/api/types.ts +38 -35
  48. package/src/platform/registry/__tests__/resource-registry.test.ts +2051 -2005
  49. package/src/platform/registry/__tests__/validation.test.ts +1343 -1086
  50. package/src/platform/registry/index.ts +14 -0
  51. package/src/platform/registry/resource-registry.ts +40 -2
  52. package/src/platform/registry/serialization.ts +241 -202
  53. package/src/platform/registry/serialized-types.ts +1 -0
  54. package/src/platform/registry/types.ts +411 -361
  55. package/src/platform/registry/validation.ts +743 -513
  56. package/src/projects/api-schemas.ts +290 -267
  57. package/src/reference/_generated/contracts.md +495 -302
  58. package/src/reference/glossary.md +8 -3
  59. package/src/supabase/database.types.ts +121 -0
@@ -47,10 +47,13 @@ Top-level fields:
47
47
  - `offerings`
48
48
  - `roles`
49
49
  - `goals`
50
+ - `systems`
51
+ - `resources`
50
52
  - `statuses`
51
53
  - `operations`
54
+ - `knowledge`
52
55
 
53
- Resources bind to the graph from deployment metadata through `links` and `category`.
56
+ Resource identity is authored in `resources.entries`. Runtime workflows, agents, and integrations import those descriptors, derive `resourceId` and kind from them, and attach executable behavior in operations code.
54
57
 
55
58
  ## Feature Set
56
59
 
@@ -77,6 +80,10 @@ Cross-collection links use kind-prefixed IDs:
77
80
  - `resource:lead-import`
78
81
  - `capability:operations.queue.review`
79
82
 
83
+ ## Resource Descriptors
84
+
85
+ The OM Resources domain is governance-only. Descriptors declare canonical `id`, required `systemId`, governance `status`, and optional role ownership. `DeploymentSpec` remains the runtime/deploy assembly around those descriptors, not a second resource identity catalog.
86
+
80
87
  ## Resolution Semantics
81
88
 
82
89
  - `defineOrganizationModel()` is a typed helper.
@@ -92,11 +99,11 @@ Cross-collection links use kind-prefixed IDs:
92
99
  - Child feature IDs require ancestor feature nodes.
93
100
  - Container features omit `path`.
94
101
  - Leaf features provide `path`.
95
- - Resource links are validated against graph node IDs during registry registration.
102
+ - Systems, resources, roles, knowledge nodes, and goals must resolve their declared cross-references.
96
103
 
97
104
  ## Practical Guidance
98
105
 
99
106
  - Use `resolveOrganizationModel()` when you need a runtime-safe model.
100
107
  - Use `defineOrganizationModel()` when authoring static overrides.
101
108
  - Keep feature IDs stable because shell routing, gating, breadcrumbs, and docs depend on them.
102
- - Put semantic resource relationships on resource metadata, not on feature nodes.
109
+ - Put resource identity and governance in `resources.entries`; attach executable behavior in operations.
@@ -14,6 +14,7 @@ import { DEFAULT_ORGANIZATION_MODEL_OPERATIONS } from '../domains/operations'
14
14
  import { OperationsDomainSchema } from '../domains/operations'
15
15
  import { DEFAULT_ORGANIZATION_MODEL_STATUSES } from '../domains/statuses'
16
16
  import { StatusesDomainSchema } from '../domains/statuses'
17
+ import { DEFAULT_ORGANIZATION_MODEL_SYSTEMS, SystemsDomainSchema } from '../domains/systems'
17
18
  import { resolveOrganizationModel } from '../resolve'
18
19
  import { OrganizationModelSchema } from '../schema'
19
20
 
@@ -55,6 +56,11 @@ const domainCases = [
55
56
  name: 'DEFAULT_ORGANIZATION_MODEL_OPERATIONS',
56
57
  constant: DEFAULT_ORGANIZATION_MODEL_OPERATIONS,
57
58
  schema: OperationsDomainSchema
59
+ },
60
+ {
61
+ name: 'DEFAULT_ORGANIZATION_MODEL_SYSTEMS',
62
+ constant: DEFAULT_ORGANIZATION_MODEL_SYSTEMS,
63
+ schema: SystemsDomainSchema
58
64
  }
59
65
  ] as const
60
66
 
@@ -0,0 +1,188 @@
1
+ import { describe, expect, it } from 'vitest'
2
+ import { bindResourceDescriptor } from '../../../platform/registry/types'
3
+ import {
4
+ DEFAULT_ORGANIZATION_MODEL_RESOURCES,
5
+ ResourceEntrySchema,
6
+ ResourceKindSchema,
7
+ ResourcesDomainSchema,
8
+ defineResource,
9
+ defineResources
10
+ } from '../../domains/resources'
11
+ import { resolveOrganizationModel } from '../../resolve'
12
+
13
+ const VALID_SYSTEM = {
14
+ id: 'sys.lead-gen',
15
+ title: 'Lead Generation Pipeline',
16
+ description: 'Coordinates prospecting, enrichment, qualification, and outreach preparation.',
17
+ kind: 'operational' as const,
18
+ status: 'active' as const
19
+ }
20
+
21
+ const VALID_ROLE = {
22
+ id: 'role.sales-ops',
23
+ title: 'Sales Ops'
24
+ }
25
+
26
+ const WORKFLOW_RESOURCE = {
27
+ id: 'LGN-01-company-scrape',
28
+ kind: 'workflow' as const,
29
+ systemId: 'sys.lead-gen',
30
+ ownerRoleId: 'role.sales-ops',
31
+ status: 'active' as const,
32
+ capabilityKey: 'lead-gen.company.scrape'
33
+ }
34
+
35
+ const AGENT_RESOURCE = {
36
+ id: 'command-center-assistant',
37
+ kind: 'agent' as const,
38
+ systemId: 'sys.lead-gen',
39
+ ownerRoleId: 'role.sales-ops',
40
+ status: 'active' as const,
41
+ agentKind: 'system' as const,
42
+ actsAsRoleId: 'role.sales-ops',
43
+ sessionCapable: true
44
+ }
45
+
46
+ const INTEGRATION_RESOURCE = {
47
+ id: 'attio-crm',
48
+ kind: 'integration' as const,
49
+ systemId: 'sys.lead-gen',
50
+ ownerRoleId: 'role.sales-ops',
51
+ status: 'active' as const,
52
+ provider: 'attio'
53
+ }
54
+
55
+ function resolveWithResources(resources: unknown[]) {
56
+ return resolveOrganizationModel({
57
+ roles: { roles: [VALID_ROLE] },
58
+ systems: { systems: [VALID_SYSTEM] },
59
+ resources: { entries: resources }
60
+ })
61
+ }
62
+
63
+ describe('ResourceEntrySchema', () => {
64
+ it('accepts workflow, agent, and integration descriptors with required systemId', () => {
65
+ expect(ResourceEntrySchema.safeParse(WORKFLOW_RESOURCE).success).toBe(true)
66
+ expect(ResourceEntrySchema.safeParse(AGENT_RESOURCE).success).toBe(true)
67
+ expect(ResourceEntrySchema.safeParse(INTEGRATION_RESOURCE).success).toBe(true)
68
+ })
69
+
70
+ it('rejects resources without a systemId', () => {
71
+ const { systemId: _systemId, ...resourceWithoutSystem } = WORKFLOW_RESOURCE
72
+
73
+ expect(ResourceEntrySchema.safeParse(resourceWithoutSystem).success).toBe(false)
74
+ })
75
+
76
+ it('rejects multi-system membership', () => {
77
+ expect(
78
+ ResourceEntrySchema.safeParse({
79
+ ...WORKFLOW_RESOURCE,
80
+ systemId: ['sys.lead-gen', 'sys.crm']
81
+ }).success
82
+ ).toBe(false)
83
+ })
84
+
85
+ it('rejects an agent kind outside the code-side mirror enum', () => {
86
+ expect(
87
+ ResourceEntrySchema.safeParse({
88
+ ...AGENT_RESOURCE,
89
+ agentKind: 'runner'
90
+ }).success
91
+ ).toBe(false)
92
+ })
93
+ })
94
+
95
+ describe('ResourcesDomainSchema', () => {
96
+ it('defaults resources to an empty array when omitted', () => {
97
+ const result = ResourcesDomainSchema.safeParse({})
98
+
99
+ expect(result.success).toBe(true)
100
+ if (result.success) {
101
+ expect(result.data).toEqual(DEFAULT_ORGANIZATION_MODEL_RESOURCES)
102
+ }
103
+ })
104
+
105
+ it.each(['workflow', 'agent', 'integration'] as const)('accepts kind "%s"', (kind) => {
106
+ expect(ResourceKindSchema.safeParse(kind).success).toBe(true)
107
+ })
108
+ })
109
+
110
+ describe('resolveOrganizationModel - resources domain integration', () => {
111
+ it('accepts valid resources with system and role references', () => {
112
+ const model = resolveWithResources([WORKFLOW_RESOURCE, AGENT_RESOURCE, INTEGRATION_RESOURCE])
113
+
114
+ expect(model.resources.entries).toHaveLength(3)
115
+ })
116
+
117
+ it('throws when resource IDs are duplicated', () => {
118
+ expect(() =>
119
+ resolveWithResources([
120
+ WORKFLOW_RESOURCE,
121
+ {
122
+ ...WORKFLOW_RESOURCE,
123
+ capabilityKey: 'lead-gen.company.scrape-duplicate'
124
+ }
125
+ ])
126
+ ).toThrow(/Resource id \\"LGN-01-company-scrape\\" must be unique/)
127
+ })
128
+
129
+ it('throws when systemId references an unknown system', () => {
130
+ expect(() =>
131
+ resolveWithResources([
132
+ {
133
+ ...WORKFLOW_RESOURCE,
134
+ systemId: 'sys.missing'
135
+ }
136
+ ])
137
+ ).toThrow(/unknown systemId \\"sys\.missing\\"/)
138
+ })
139
+
140
+ it('throws when ownerRoleId references an unknown role', () => {
141
+ expect(() =>
142
+ resolveWithResources([
143
+ {
144
+ ...WORKFLOW_RESOURCE,
145
+ ownerRoleId: 'role.missing'
146
+ }
147
+ ])
148
+ ).toThrow(/unknown ownerRoleId \\"role\.missing\\"/)
149
+ })
150
+
151
+ it('throws when agent actsAsRoleId references an unknown role', () => {
152
+ expect(() =>
153
+ resolveWithResources([
154
+ {
155
+ ...AGENT_RESOURCE,
156
+ actsAsRoleId: 'role.missing'
157
+ }
158
+ ])
159
+ ).toThrow(/unknown actsAsRoleId \\"role\.missing\\"/)
160
+ })
161
+ })
162
+
163
+ describe('descriptor helper contract', () => {
164
+ it('preserves typed descriptor exports through defineResource and defineResources', () => {
165
+ const workflow = defineResource(WORKFLOW_RESOURCE)
166
+ const resources = defineResources({
167
+ companyScrape: WORKFLOW_RESOURCE,
168
+ commandCenterAssistant: AGENT_RESOURCE
169
+ })
170
+
171
+ expect(workflow.id).toBe('LGN-01-company-scrape')
172
+ expect(resources.commandCenterAssistant.agentKind).toBe('system')
173
+ })
174
+
175
+ it('derives runtime resourceId and type from the descriptor', () => {
176
+ const bound = bindResourceDescriptor({
177
+ resource: WORKFLOW_RESOURCE,
178
+ name: 'Company Scrape',
179
+ description: 'Scrapes company data for lead generation.',
180
+ version: '1.0.0',
181
+ status: 'prod'
182
+ })
183
+
184
+ expect(bound.resourceId).toBe('LGN-01-company-scrape')
185
+ expect(bound.type).toBe('workflow')
186
+ expect(bound.resource).toBe(WORKFLOW_RESOURCE)
187
+ })
188
+ })