@elevasis/core 0.20.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.
- package/dist/index.d.ts +524 -6
- package/dist/index.js +417 -42
- package/dist/knowledge/index.d.ts +151 -1
- package/dist/organization-model/index.d.ts +524 -6
- package/dist/organization-model/index.js +417 -42
- package/dist/test-utils/index.d.ts +270 -1
- package/dist/test-utils/index.js +407 -41
- package/package.json +5 -5
- package/src/_gen/__tests__/__snapshots__/contracts.md.snap +501 -303
- package/src/auth/multi-tenancy/permissions.ts +20 -8
- package/src/business/README.md +2 -2
- package/src/business/acquisition/api-schemas.test.ts +198 -0
- package/src/business/acquisition/api-schemas.ts +250 -9
- package/src/business/acquisition/build-templates.test.ts +28 -0
- package/src/business/acquisition/build-templates.ts +20 -8
- package/src/business/acquisition/index.ts +12 -0
- package/src/business/acquisition/types.ts +6 -1
- package/src/business/clients/api-schemas.test.ts +115 -0
- package/src/business/clients/api-schemas.ts +158 -0
- package/src/business/clients/index.ts +1 -0
- package/src/business/deals/api-schemas.ts +8 -0
- package/src/business/index.ts +5 -2
- package/src/business/projects/types.ts +19 -0
- package/src/execution/engine/__tests__/fixtures/test-agents.ts +10 -8
- package/src/execution/engine/agent/core/__tests__/agent.test.ts +16 -12
- package/src/execution/engine/agent/core/__tests__/error-passthrough.test.ts +4 -3
- package/src/execution/engine/agent/core/types.ts +25 -15
- package/src/execution/engine/agent/index.ts +6 -4
- package/src/execution/engine/agent/reasoning/__tests__/request-builder.test.ts +24 -18
- package/src/execution/engine/index.ts +3 -0
- package/src/execution/engine/tools/integration/server/adapters/apify/apify-adapter.test.ts +55 -0
- package/src/execution/engine/tools/integration/server/adapters/apify/apify-adapter.ts +107 -41
- package/src/execution/engine/tools/integration/server/adapters/apollo/apollo-adapter.test.ts +48 -0
- package/src/execution/engine/tools/integration/server/adapters/apollo/apollo-adapter.ts +99 -0
- package/src/execution/engine/tools/integration/server/adapters/apollo/index.ts +1 -0
- package/src/execution/engine/tools/integration/server/adapters/clickup/clickup-adapter.test.ts +18 -0
- package/src/execution/engine/tools/integration/server/adapters/clickup/clickup-adapter.ts +194 -0
- package/src/execution/engine/tools/integration/server/adapters/clickup/index.ts +7 -0
- package/src/execution/engine/workflow/types.ts +7 -0
- package/src/integrations/credentials/api-schemas.ts +21 -2
- package/src/integrations/credentials/schemas.ts +200 -164
- package/src/organization-model/README.md +10 -3
- package/src/organization-model/__tests__/defaults.test.ts +6 -0
- package/src/organization-model/__tests__/domains/resources.test.ts +188 -0
- package/src/organization-model/__tests__/domains/roles.test.ts +402 -347
- package/src/organization-model/__tests__/domains/systems.test.ts +193 -0
- package/src/organization-model/__tests__/knowledge.test.ts +39 -0
- package/src/organization-model/__tests__/prospecting-ssot.test.ts +7 -4
- package/src/organization-model/__tests__/resolve.test.ts +1 -1
- package/src/organization-model/defaults.ts +24 -3
- package/src/organization-model/domains/knowledge.ts +3 -2
- package/src/organization-model/domains/prospecting.ts +182 -25
- package/src/organization-model/domains/resources.ts +88 -0
- package/src/organization-model/domains/roles.ts +93 -55
- package/src/organization-model/domains/sales.ts +24 -3
- package/src/organization-model/domains/systems.ts +46 -0
- package/src/organization-model/icons.ts +1 -0
- package/src/organization-model/index.ts +2 -0
- package/src/organization-model/organization-model.mdx +33 -14
- package/src/organization-model/published.ts +52 -1
- package/src/organization-model/schema.ts +121 -0
- package/src/organization-model/types.ts +46 -1
- package/src/platform/api/types.ts +38 -35
- package/src/platform/constants/versions.ts +1 -1
- package/src/platform/registry/__tests__/resource-registry.test.ts +2051 -2005
- package/src/platform/registry/__tests__/validation.test.ts +1343 -1086
- package/src/platform/registry/index.ts +14 -0
- package/src/platform/registry/resource-registry.ts +40 -2
- package/src/platform/registry/serialization.ts +241 -202
- package/src/platform/registry/serialized-types.ts +1 -0
- package/src/platform/registry/types.ts +411 -361
- package/src/platform/registry/validation.ts +743 -513
- package/src/projects/api-schemas.ts +290 -267
- package/src/reference/_generated/contracts.md +501 -303
- package/src/reference/glossary.md +8 -3
- package/src/server.ts +2 -0
- package/src/supabase/database.types.ts +121 -0
|
@@ -1,164 +1,200 @@
|
|
|
1
|
-
import { z } from 'zod'
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Credential field definition
|
|
5
|
-
*/
|
|
6
|
-
export interface CredentialField {
|
|
7
|
-
key: string
|
|
8
|
-
label: string
|
|
9
|
-
type: 'password' | 'text'
|
|
10
|
-
required: boolean
|
|
11
|
-
placeholder?: string
|
|
12
|
-
description?: string
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* Credential schema definition
|
|
17
|
-
*/
|
|
18
|
-
export interface CredentialSchema {
|
|
19
|
-
type: string
|
|
20
|
-
label: string
|
|
21
|
-
description: string
|
|
22
|
-
fields?: CredentialField[]
|
|
23
|
-
docsUrl?: string
|
|
24
|
-
nameSuggestions: string[]
|
|
25
|
-
oauthProvider?: string // For OAuth types
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
* Zod schemas for runtime validation
|
|
30
|
-
*/
|
|
31
|
-
const CredentialFieldSchema = z.object({
|
|
32
|
-
key: z.string(),
|
|
33
|
-
label: z.string(),
|
|
34
|
-
type: z.enum(['password', 'text']),
|
|
35
|
-
required: z.boolean(),
|
|
36
|
-
placeholder: z.string().optional(),
|
|
37
|
-
description: z.string().optional()
|
|
38
|
-
})
|
|
39
|
-
|
|
40
|
-
const CredentialSchemaZod = z.object({
|
|
41
|
-
type: z.string(),
|
|
42
|
-
label: z.string(),
|
|
43
|
-
description: z.string(),
|
|
44
|
-
fields: z.array(CredentialFieldSchema).optional(),
|
|
45
|
-
docsUrl: z.string().url().optional(),
|
|
46
|
-
nameSuggestions: z.array(z.string()),
|
|
47
|
-
oauthProvider: z.string().optional()
|
|
48
|
-
})
|
|
49
|
-
|
|
50
|
-
/**
|
|
51
|
-
* Credential Schema Registry
|
|
52
|
-
*
|
|
53
|
-
* Add new integration = add schema object here (no modal changes needed)
|
|
54
|
-
*
|
|
55
|
-
* Schema types:
|
|
56
|
-
* - oauth: OAuth-based authentication (handled via OAuth flow)
|
|
57
|
-
* - single_field: Single API key field (generic)
|
|
58
|
-
*/
|
|
59
|
-
export const CREDENTIAL_SCHEMAS: Record<string, CredentialSchema> = {
|
|
60
|
-
'google-sheets': {
|
|
61
|
-
type: 'oauth',
|
|
62
|
-
label: 'Google Sheets',
|
|
63
|
-
description: 'Google Sheets OAuth integration',
|
|
64
|
-
oauthProvider: 'google-sheets',
|
|
65
|
-
nameSuggestions: ['google-sheets-prod', 'google-sheets-dev', 'sheets-workspace']
|
|
66
|
-
},
|
|
67
|
-
|
|
68
|
-
dropbox: {
|
|
69
|
-
type: 'oauth',
|
|
70
|
-
label: 'Dropbox',
|
|
71
|
-
description: 'Dropbox OAuth integration',
|
|
72
|
-
oauthProvider: 'dropbox',
|
|
73
|
-
nameSuggestions: ['dropbox-prod', 'dropbox-dev', 'elevasis-dropbox']
|
|
74
|
-
},
|
|
75
|
-
|
|
76
|
-
oauth: {
|
|
77
|
-
type: 'oauth',
|
|
78
|
-
label: 'OAuth',
|
|
79
|
-
description: 'Generic OAuth credential',
|
|
80
|
-
nameSuggestions: []
|
|
81
|
-
},
|
|
82
|
-
|
|
83
|
-
'api-key': {
|
|
84
|
-
type: 'single_field',
|
|
85
|
-
label: 'API Key',
|
|
86
|
-
description: 'Single-field API key credential',
|
|
87
|
-
fields: [
|
|
88
|
-
{
|
|
89
|
-
key: 'apiKey',
|
|
90
|
-
label: 'API Key',
|
|
91
|
-
type: 'password',
|
|
92
|
-
required: true,
|
|
93
|
-
placeholder: 'Enter your API key',
|
|
94
|
-
description: 'API key for the service'
|
|
95
|
-
}
|
|
96
|
-
],
|
|
97
|
-
nameSuggestions: ['service-prod', 'service-dev', 'api-key']
|
|
98
|
-
},
|
|
99
|
-
|
|
100
|
-
'webhook-secret': {
|
|
101
|
-
type: 'single_field',
|
|
102
|
-
label: 'Webhook Secret',
|
|
103
|
-
description: 'Webhook signing secret for signature validation',
|
|
104
|
-
fields: [
|
|
105
|
-
{
|
|
106
|
-
key: 'signingSecret',
|
|
107
|
-
label: 'Signing Secret',
|
|
108
|
-
type: 'password',
|
|
109
|
-
required: true,
|
|
110
|
-
placeholder: 'whsec_...',
|
|
111
|
-
description: 'Webhook signing secret from provider dashboard'
|
|
112
|
-
}
|
|
113
|
-
],
|
|
114
|
-
nameSuggestions: ['my-org-cal-com-webhook', 'my-org-stripe-webhook', 'my-org-signature-api-webhook']
|
|
115
|
-
},
|
|
116
|
-
|
|
117
|
-
'api-key-secret': {
|
|
118
|
-
type: 'api-key-secret',
|
|
119
|
-
label: 'API Key + Secret',
|
|
120
|
-
description: 'API key and secret pair authentication',
|
|
121
|
-
fields: [
|
|
122
|
-
{
|
|
123
|
-
key: 'apiKey',
|
|
124
|
-
label: 'API Key',
|
|
125
|
-
type: 'password',
|
|
126
|
-
required: true
|
|
127
|
-
},
|
|
128
|
-
{
|
|
129
|
-
key: 'apiSecret',
|
|
130
|
-
label: 'API Secret',
|
|
131
|
-
type: 'password',
|
|
132
|
-
required: true
|
|
133
|
-
}
|
|
134
|
-
],
|
|
135
|
-
nameSuggestions: []
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
1
|
+
import { z } from 'zod'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Credential field definition
|
|
5
|
+
*/
|
|
6
|
+
export interface CredentialField {
|
|
7
|
+
key: string
|
|
8
|
+
label: string
|
|
9
|
+
type: 'password' | 'text'
|
|
10
|
+
required: boolean
|
|
11
|
+
placeholder?: string
|
|
12
|
+
description?: string
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Credential schema definition
|
|
17
|
+
*/
|
|
18
|
+
export interface CredentialSchema {
|
|
19
|
+
type: string
|
|
20
|
+
label: string
|
|
21
|
+
description: string
|
|
22
|
+
fields?: CredentialField[]
|
|
23
|
+
docsUrl?: string
|
|
24
|
+
nameSuggestions: string[]
|
|
25
|
+
oauthProvider?: string // For OAuth types
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Zod schemas for runtime validation
|
|
30
|
+
*/
|
|
31
|
+
const CredentialFieldSchema = z.object({
|
|
32
|
+
key: z.string(),
|
|
33
|
+
label: z.string(),
|
|
34
|
+
type: z.enum(['password', 'text']),
|
|
35
|
+
required: z.boolean(),
|
|
36
|
+
placeholder: z.string().optional(),
|
|
37
|
+
description: z.string().optional()
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
const CredentialSchemaZod = z.object({
|
|
41
|
+
type: z.string(),
|
|
42
|
+
label: z.string(),
|
|
43
|
+
description: z.string(),
|
|
44
|
+
fields: z.array(CredentialFieldSchema).optional(),
|
|
45
|
+
docsUrl: z.string().url().optional(),
|
|
46
|
+
nameSuggestions: z.array(z.string()),
|
|
47
|
+
oauthProvider: z.string().optional()
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Credential Schema Registry
|
|
52
|
+
*
|
|
53
|
+
* Add new integration = add schema object here (no modal changes needed)
|
|
54
|
+
*
|
|
55
|
+
* Schema types:
|
|
56
|
+
* - oauth: OAuth-based authentication (handled via OAuth flow)
|
|
57
|
+
* - single_field: Single API key field (generic)
|
|
58
|
+
*/
|
|
59
|
+
export const CREDENTIAL_SCHEMAS: Record<string, CredentialSchema> = {
|
|
60
|
+
'google-sheets': {
|
|
61
|
+
type: 'oauth',
|
|
62
|
+
label: 'Google Sheets',
|
|
63
|
+
description: 'Google Sheets OAuth integration',
|
|
64
|
+
oauthProvider: 'google-sheets',
|
|
65
|
+
nameSuggestions: ['google-sheets-prod', 'google-sheets-dev', 'sheets-workspace']
|
|
66
|
+
},
|
|
67
|
+
|
|
68
|
+
dropbox: {
|
|
69
|
+
type: 'oauth',
|
|
70
|
+
label: 'Dropbox',
|
|
71
|
+
description: 'Dropbox OAuth integration',
|
|
72
|
+
oauthProvider: 'dropbox',
|
|
73
|
+
nameSuggestions: ['dropbox-prod', 'dropbox-dev', 'elevasis-dropbox']
|
|
74
|
+
},
|
|
75
|
+
|
|
76
|
+
oauth: {
|
|
77
|
+
type: 'oauth',
|
|
78
|
+
label: 'OAuth',
|
|
79
|
+
description: 'Generic OAuth credential',
|
|
80
|
+
nameSuggestions: []
|
|
81
|
+
},
|
|
82
|
+
|
|
83
|
+
'api-key': {
|
|
84
|
+
type: 'single_field',
|
|
85
|
+
label: 'API Key',
|
|
86
|
+
description: 'Single-field API key credential',
|
|
87
|
+
fields: [
|
|
88
|
+
{
|
|
89
|
+
key: 'apiKey',
|
|
90
|
+
label: 'API Key',
|
|
91
|
+
type: 'password',
|
|
92
|
+
required: true,
|
|
93
|
+
placeholder: 'Enter your API key',
|
|
94
|
+
description: 'API key for the service'
|
|
95
|
+
}
|
|
96
|
+
],
|
|
97
|
+
nameSuggestions: ['service-prod', 'service-dev', 'api-key']
|
|
98
|
+
},
|
|
99
|
+
|
|
100
|
+
'webhook-secret': {
|
|
101
|
+
type: 'single_field',
|
|
102
|
+
label: 'Webhook Secret',
|
|
103
|
+
description: 'Webhook signing secret for signature validation',
|
|
104
|
+
fields: [
|
|
105
|
+
{
|
|
106
|
+
key: 'signingSecret',
|
|
107
|
+
label: 'Signing Secret',
|
|
108
|
+
type: 'password',
|
|
109
|
+
required: true,
|
|
110
|
+
placeholder: 'whsec_...',
|
|
111
|
+
description: 'Webhook signing secret from provider dashboard'
|
|
112
|
+
}
|
|
113
|
+
],
|
|
114
|
+
nameSuggestions: ['my-org-cal-com-webhook', 'my-org-stripe-webhook', 'my-org-signature-api-webhook']
|
|
115
|
+
},
|
|
116
|
+
|
|
117
|
+
'api-key-secret': {
|
|
118
|
+
type: 'api-key-secret',
|
|
119
|
+
label: 'API Key + Secret',
|
|
120
|
+
description: 'API key and secret pair authentication',
|
|
121
|
+
fields: [
|
|
122
|
+
{
|
|
123
|
+
key: 'apiKey',
|
|
124
|
+
label: 'API Key',
|
|
125
|
+
type: 'password',
|
|
126
|
+
required: true
|
|
127
|
+
},
|
|
128
|
+
{
|
|
129
|
+
key: 'apiSecret',
|
|
130
|
+
label: 'API Secret',
|
|
131
|
+
type: 'password',
|
|
132
|
+
required: true
|
|
133
|
+
}
|
|
134
|
+
],
|
|
135
|
+
nameSuggestions: []
|
|
136
|
+
},
|
|
137
|
+
|
|
138
|
+
apify: {
|
|
139
|
+
type: 'single_field',
|
|
140
|
+
label: 'Apify',
|
|
141
|
+
description: 'Apify API token for running web-scraping actors (e.g. website crawl, Google Places scrape).',
|
|
142
|
+
fields: [
|
|
143
|
+
{
|
|
144
|
+
key: 'apiKey',
|
|
145
|
+
label: 'API Token',
|
|
146
|
+
type: 'password',
|
|
147
|
+
required: true,
|
|
148
|
+
placeholder: 'apify_api_...',
|
|
149
|
+
description: 'Personal API token from https://console.apify.com/account/integrations'
|
|
150
|
+
}
|
|
151
|
+
],
|
|
152
|
+
docsUrl: 'https://docs.apify.com/platform/integrations/api',
|
|
153
|
+
nameSuggestions: ['elevasis-apify', 'apify-prod', 'apify-dev']
|
|
154
|
+
},
|
|
155
|
+
|
|
156
|
+
clickup: {
|
|
157
|
+
type: 'single_field',
|
|
158
|
+
label: 'ClickUp',
|
|
159
|
+
description: 'ClickUp personal API token for creating tasks in tenant-managed ClickUp workspaces.',
|
|
160
|
+
fields: [
|
|
161
|
+
{
|
|
162
|
+
key: 'apiToken',
|
|
163
|
+
label: 'API Token',
|
|
164
|
+
type: 'password',
|
|
165
|
+
required: true,
|
|
166
|
+
placeholder: 'pk_...',
|
|
167
|
+
description: 'Personal API token from ClickUp settings. Personal tokens start with pk_.'
|
|
168
|
+
}
|
|
169
|
+
],
|
|
170
|
+
docsUrl: 'https://developer.clickup.com/docs/authentication',
|
|
171
|
+
nameSuggestions: ['clickup-demo', 'clickup-prod', 'clickup-dev']
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* Get credential schema by type
|
|
177
|
+
* @param type - Credential type identifier
|
|
178
|
+
* @returns Validated credential schema
|
|
179
|
+
* @throws ZodError if schema is malformed
|
|
180
|
+
*/
|
|
181
|
+
export function getCredentialSchema(type: string): CredentialSchema {
|
|
182
|
+
const schema = CREDENTIAL_SCHEMAS[type] || CREDENTIAL_SCHEMAS['api-key']
|
|
183
|
+
return CredentialSchemaZod.parse(schema)
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* List all available credential types (for frontend dropdown)
|
|
188
|
+
* @returns Array of credential schemas
|
|
189
|
+
*/
|
|
190
|
+
export function listCredentialSchemas(): CredentialSchema[] {
|
|
191
|
+
return Object.values(CREDENTIAL_SCHEMAS)
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* Get all credential type identifiers
|
|
196
|
+
* @returns Array of type strings
|
|
197
|
+
*/
|
|
198
|
+
export function getCredentialTypes(): string[] {
|
|
199
|
+
return Object.keys(CREDENTIAL_SCHEMAS)
|
|
200
|
+
}
|
|
@@ -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
|
-
|
|
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
|
-
-
|
|
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
|
|
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
|
+
})
|