@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.
Files changed (77) hide show
  1. package/dist/index.d.ts +524 -6
  2. package/dist/index.js +417 -42
  3. package/dist/knowledge/index.d.ts +151 -1
  4. package/dist/organization-model/index.d.ts +524 -6
  5. package/dist/organization-model/index.js +417 -42
  6. package/dist/test-utils/index.d.ts +270 -1
  7. package/dist/test-utils/index.js +407 -41
  8. package/package.json +5 -5
  9. package/src/_gen/__tests__/__snapshots__/contracts.md.snap +501 -303
  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 +198 -0
  13. package/src/business/acquisition/api-schemas.ts +250 -9
  14. package/src/business/acquisition/build-templates.test.ts +28 -0
  15. package/src/business/acquisition/build-templates.ts +20 -8
  16. package/src/business/acquisition/index.ts +12 -0
  17. package/src/business/acquisition/types.ts +6 -1
  18. package/src/business/clients/api-schemas.test.ts +115 -0
  19. package/src/business/clients/api-schemas.ts +158 -0
  20. package/src/business/clients/index.ts +1 -0
  21. package/src/business/deals/api-schemas.ts +8 -0
  22. package/src/business/index.ts +5 -2
  23. package/src/business/projects/types.ts +19 -0
  24. package/src/execution/engine/__tests__/fixtures/test-agents.ts +10 -8
  25. package/src/execution/engine/agent/core/__tests__/agent.test.ts +16 -12
  26. package/src/execution/engine/agent/core/__tests__/error-passthrough.test.ts +4 -3
  27. package/src/execution/engine/agent/core/types.ts +25 -15
  28. package/src/execution/engine/agent/index.ts +6 -4
  29. package/src/execution/engine/agent/reasoning/__tests__/request-builder.test.ts +24 -18
  30. package/src/execution/engine/index.ts +3 -0
  31. package/src/execution/engine/tools/integration/server/adapters/apify/apify-adapter.test.ts +55 -0
  32. package/src/execution/engine/tools/integration/server/adapters/apify/apify-adapter.ts +107 -41
  33. package/src/execution/engine/tools/integration/server/adapters/apollo/apollo-adapter.test.ts +48 -0
  34. package/src/execution/engine/tools/integration/server/adapters/apollo/apollo-adapter.ts +99 -0
  35. package/src/execution/engine/tools/integration/server/adapters/apollo/index.ts +1 -0
  36. package/src/execution/engine/tools/integration/server/adapters/clickup/clickup-adapter.test.ts +18 -0
  37. package/src/execution/engine/tools/integration/server/adapters/clickup/clickup-adapter.ts +194 -0
  38. package/src/execution/engine/tools/integration/server/adapters/clickup/index.ts +7 -0
  39. package/src/execution/engine/workflow/types.ts +7 -0
  40. package/src/integrations/credentials/api-schemas.ts +21 -2
  41. package/src/integrations/credentials/schemas.ts +200 -164
  42. package/src/organization-model/README.md +10 -3
  43. package/src/organization-model/__tests__/defaults.test.ts +6 -0
  44. package/src/organization-model/__tests__/domains/resources.test.ts +188 -0
  45. package/src/organization-model/__tests__/domains/roles.test.ts +402 -347
  46. package/src/organization-model/__tests__/domains/systems.test.ts +193 -0
  47. package/src/organization-model/__tests__/knowledge.test.ts +39 -0
  48. package/src/organization-model/__tests__/prospecting-ssot.test.ts +7 -4
  49. package/src/organization-model/__tests__/resolve.test.ts +1 -1
  50. package/src/organization-model/defaults.ts +24 -3
  51. package/src/organization-model/domains/knowledge.ts +3 -2
  52. package/src/organization-model/domains/prospecting.ts +182 -25
  53. package/src/organization-model/domains/resources.ts +88 -0
  54. package/src/organization-model/domains/roles.ts +93 -55
  55. package/src/organization-model/domains/sales.ts +24 -3
  56. package/src/organization-model/domains/systems.ts +46 -0
  57. package/src/organization-model/icons.ts +1 -0
  58. package/src/organization-model/index.ts +2 -0
  59. package/src/organization-model/organization-model.mdx +33 -14
  60. package/src/organization-model/published.ts +52 -1
  61. package/src/organization-model/schema.ts +121 -0
  62. package/src/organization-model/types.ts +46 -1
  63. package/src/platform/api/types.ts +38 -35
  64. package/src/platform/constants/versions.ts +1 -1
  65. package/src/platform/registry/__tests__/resource-registry.test.ts +2051 -2005
  66. package/src/platform/registry/__tests__/validation.test.ts +1343 -1086
  67. package/src/platform/registry/index.ts +14 -0
  68. package/src/platform/registry/resource-registry.ts +40 -2
  69. package/src/platform/registry/serialization.ts +241 -202
  70. package/src/platform/registry/serialized-types.ts +1 -0
  71. package/src/platform/registry/types.ts +411 -361
  72. package/src/platform/registry/validation.ts +743 -513
  73. package/src/projects/api-schemas.ts +290 -267
  74. package/src/reference/_generated/contracts.md +501 -303
  75. package/src/reference/glossary.md +8 -3
  76. package/src/server.ts +2 -0
  77. package/src/supabase/database.types.ts +121 -0
@@ -15,8 +15,19 @@ export {
15
15
  validateDeploymentSpec,
16
16
  validateRelationships,
17
17
  validateExecutionInterface,
18
+ validateResourceGovernance,
18
19
  RegistryValidationError
19
20
  } from './validation'
21
+ export type {
22
+ ResourceGovernanceModel,
23
+ ResourceGovernanceValidationIssue,
24
+ ResourceGovernanceValidationIssueType,
25
+ ResourceGovernanceValidationOptions,
26
+ ResourceGovernanceValidationResult,
27
+ ResourceValidatorMode
28
+ } from './validation'
29
+
30
+ export { bindResourceDescriptor } from './types'
20
31
 
21
32
  // Serialization utilities
22
33
  export { serializeAllOrganizations, serializeOrganization, buildEdges } from './serialization'
@@ -27,6 +38,9 @@ export type {
27
38
  ResourceType,
28
39
  ExecutableResourceType,
29
40
  ResourceDefinition,
41
+ RuntimeResourceDescriptor,
42
+ DescriptorBackedResourceDefinition,
43
+ BoundResourceDefinition,
30
44
  ResourceList,
31
45
  TriggerDefinition,
32
46
  IntegrationDefinition,
@@ -11,6 +11,9 @@
11
11
 
12
12
  import type { WorkflowDefinition } from '../../execution/engine/workflow/types'
13
13
  import type { AgentDefinition } from '../../execution/engine/agent/core/types'
14
+ import type { OrganizationModelResources, OrganizationModelSystems } from '../../organization-model/types'
15
+ import type { ResourceEntry } from '../../organization-model/domains/resources'
16
+ import type { SystemEntry } from '../../organization-model/domains/systems'
14
17
  import type {
15
18
  ResourceStatus,
16
19
  ResourceDefinition,
@@ -44,6 +47,18 @@ function filterArchived(org: DeploymentSpec): DeploymentSpec {
44
47
  }
45
48
  }
46
49
 
50
+ function summarizeSystem(system: SystemEntry | undefined): ResourceDefinition['system'] {
51
+ if (!system) return undefined
52
+
53
+ return {
54
+ id: system.id,
55
+ title: system.title,
56
+ description: system.description,
57
+ kind: system.kind,
58
+ status: system.status
59
+ }
60
+ }
61
+
47
62
  /**
48
63
  * Configuration for a remotely-deployed organization
49
64
  *
@@ -88,6 +103,11 @@ export interface SystemConfig {
88
103
  export interface DeploymentSpec {
89
104
  /** Deployment version (semver) */
90
105
  version: string
106
+ /** Optional Organization Model governance catalog used for OM-code validation */
107
+ organizationModel?: {
108
+ systems?: OrganizationModelSystems
109
+ resources?: OrganizationModelResources
110
+ }
91
111
  /** Workflow definitions */
92
112
  workflows?: WorkflowDefinition[]
93
113
  /** Agent definitions */
@@ -283,6 +303,22 @@ export class ResourceRegistry {
283
303
  }
284
304
  }
285
305
 
306
+ const resourcesById = new Map((orgResources.organizationModel?.resources?.entries ?? []).map((r) => [r.id, r]))
307
+ const systemsById = new Map((orgResources.organizationModel?.systems?.systems ?? []).map((s) => [s.id, s]))
308
+ const getGovernanceMetadata = (
309
+ resourceId: string,
310
+ descriptor: ResourceEntry | undefined
311
+ ): Pick<ResourceDefinition, 'systemId' | 'system' | 'governanceStatus'> => {
312
+ const resource = descriptor ?? resourcesById.get(resourceId)
313
+ if (!resource) return {}
314
+
315
+ return {
316
+ systemId: resource.systemId,
317
+ system: summarizeSystem(systemsById.get(resource.systemId)),
318
+ governanceStatus: resource.status
319
+ }
320
+ }
321
+
286
322
  // Map workflows to ResourceDefinition metadata and filter by environment
287
323
  const workflows: ResourceDefinition[] = (orgResources.workflows || [])
288
324
  .map((def) => ({
@@ -296,7 +332,8 @@ export class ResourceRegistry {
296
332
  category: def.config.category,
297
333
  origin: this.remoteResources.has(`${organizationName}/${def.config.resourceId}`)
298
334
  ? ('remote' as const)
299
- : ('local' as const)
335
+ : ('local' as const),
336
+ ...getGovernanceMetadata(def.config.resourceId, def.config.resource)
300
337
  }))
301
338
  .filter((resource) => !environment || resource.status === environment)
302
339
 
@@ -314,7 +351,8 @@ export class ResourceRegistry {
314
351
  sessionCapable: def.config.sessionCapable ?? false,
315
352
  origin: this.remoteResources.has(`${organizationName}/${def.config.resourceId}`)
316
353
  ? ('remote' as const)
317
- : ('local' as const)
354
+ : ('local' as const),
355
+ ...getGovernanceMetadata(def.config.resourceId, def.config.resource)
318
356
  }))
319
357
  .filter((resource) => !environment || resource.status === environment)
320
358
 
@@ -1,50 +1,85 @@
1
- /**
2
- * Registry Serialization Utilities
3
- *
4
- * Pre-serialization logic for ResourceRegistry.
5
- * Converts resource definitions to JSON-safe structures at startup.
6
- */
7
-
8
- import type { DeploymentSpec } from './resource-registry'
9
- import type { ResourceDefinition } from './types'
1
+ /**
2
+ * Registry Serialization Utilities
3
+ *
4
+ * Pre-serialization logic for ResourceRegistry.
5
+ * Converts resource definitions to JSON-safe structures at startup.
6
+ */
7
+
8
+ import type { DeploymentSpec } from './resource-registry'
9
+ import type { ResourceDefinition } from './types'
10
+ import type { ResourceEntry } from '../../organization-model/domains/resources'
11
+ import type { SystemEntry } from '../../organization-model/domains/systems'
10
12
  import type {
11
13
  SerializedOrganizationData,
12
14
  SerializedAgentDefinition,
13
15
  SerializedWorkflowDefinition,
14
16
  CommandViewAgent,
15
- CommandViewWorkflow,
16
- CommandViewEdge
17
+ CommandViewWorkflow,
18
+ CommandViewEdge
17
19
  } from './serialized-types'
18
20
  import { serializeDefinition } from '../../execution/engine/base/serialization'
19
-
20
- /**
21
- * Serialize all organization resources
22
- * Called once during ResourceRegistry construction
23
- */
24
- export function serializeAllOrganizations(
25
- registry: Record<string, DeploymentSpec>
26
- ): Map<string, SerializedOrganizationData> {
27
- const cache = new Map<string, SerializedOrganizationData>()
28
- for (const [orgName, resources] of Object.entries(registry)) {
29
- cache.set(orgName, serializeOrganization(resources))
30
- }
31
- return cache
32
- }
33
-
21
+
22
+ function summarizeSystem(system: SystemEntry | undefined): ResourceDefinition['system'] {
23
+ if (!system) return undefined
24
+
25
+ return {
26
+ id: system.id,
27
+ title: system.title,
28
+ description: system.description,
29
+ kind: system.kind,
30
+ status: system.status
31
+ }
32
+ }
33
+
34
+ function createGovernanceMetadataResolver(resources: DeploymentSpec) {
35
+ const resourcesById = new Map((resources.organizationModel?.resources?.entries ?? []).map((r) => [r.id, r]))
36
+ const systemsById = new Map((resources.organizationModel?.systems?.systems ?? []).map((s) => [s.id, s]))
37
+
38
+ return (
39
+ resourceId: string,
40
+ descriptor: ResourceEntry | undefined
41
+ ): Pick<ResourceDefinition, 'systemId' | 'system' | 'governanceStatus'> => {
42
+ const resource = descriptor ?? resourcesById.get(resourceId)
43
+ if (!resource) return {}
44
+
45
+ return {
46
+ systemId: resource.systemId,
47
+ system: summarizeSystem(systemsById.get(resource.systemId)),
48
+ governanceStatus: resource.status
49
+ }
50
+ }
51
+ }
52
+
53
+ /**
54
+ * Serialize all organization resources
55
+ * Called once during ResourceRegistry construction
56
+ */
57
+ export function serializeAllOrganizations(
58
+ registry: Record<string, DeploymentSpec>
59
+ ): Map<string, SerializedOrganizationData> {
60
+ const cache = new Map<string, SerializedOrganizationData>()
61
+ for (const [orgName, resources] of Object.entries(registry)) {
62
+ cache.set(orgName, serializeOrganization(resources))
63
+ }
64
+ return cache
65
+ }
66
+
34
67
  /**
35
68
  * Serialize single organization's resources
36
69
  */
37
- export function serializeOrganization(resources: DeploymentSpec): SerializedOrganizationData {
38
- // Serialize workflows
39
- const workflowDefinitions = new Map<string, SerializedWorkflowDefinition>()
40
- const workflowResources: ResourceDefinition[] = []
41
- const commandViewWorkflows: CommandViewWorkflow[] = []
42
-
43
- for (const workflow of resources.workflows ?? []) {
44
- const resourceId = workflow.config.resourceId
45
- const serialized = serializeDefinition(workflow) as SerializedWorkflowDefinition
46
- workflowDefinitions.set(resourceId, serialized)
47
-
70
+ export function serializeOrganization(resources: DeploymentSpec): SerializedOrganizationData {
71
+ const getGovernanceMetadata = createGovernanceMetadataResolver(resources)
72
+
73
+ // Serialize workflows
74
+ const workflowDefinitions = new Map<string, SerializedWorkflowDefinition>()
75
+ const workflowResources: ResourceDefinition[] = []
76
+ const commandViewWorkflows: CommandViewWorkflow[] = []
77
+
78
+ for (const workflow of resources.workflows ?? []) {
79
+ const resourceId = workflow.config.resourceId
80
+ const serialized = serializeDefinition(workflow) as SerializedWorkflowDefinition
81
+ workflowDefinitions.set(resourceId, serialized)
82
+
48
83
  workflowResources.push({
49
84
  resourceId,
50
85
  name: workflow.config.name,
@@ -53,33 +88,35 @@ export function serializeOrganization(resources: DeploymentSpec): SerializedOrga
53
88
  type: 'workflow',
54
89
  status: workflow.config.status,
55
90
  links: workflow.config.links,
56
- category: workflow.config.category
91
+ category: workflow.config.category,
92
+ ...getGovernanceMetadata(resourceId, workflow.config.resource)
57
93
  })
58
-
59
- commandViewWorkflows.push({
60
- resourceId,
61
- name: workflow.config.name,
94
+
95
+ commandViewWorkflows.push({
96
+ resourceId,
97
+ name: workflow.config.name,
62
98
  description: workflow.config.description,
63
99
  version: workflow.config.version,
64
100
  type: 'workflow',
65
101
  status: workflow.config.status,
66
102
  links: workflow.config.links,
67
103
  category: workflow.config.category,
104
+ ...getGovernanceMetadata(resourceId, workflow.config.resource),
68
105
  stepCount: Object.keys(workflow.steps).length,
69
106
  entryPoint: workflow.entryPoint
70
107
  })
71
- }
72
-
73
- // Serialize agents
74
- const agentDefinitions = new Map<string, SerializedAgentDefinition>()
75
- const agentResources: ResourceDefinition[] = []
76
- const commandViewAgents: CommandViewAgent[] = []
77
-
78
- for (const agent of resources.agents ?? []) {
79
- const resourceId = agent.config.resourceId
80
- const serialized = serializeDefinition(agent) as SerializedAgentDefinition
81
- agentDefinitions.set(resourceId, serialized)
82
-
108
+ }
109
+
110
+ // Serialize agents
111
+ const agentDefinitions = new Map<string, SerializedAgentDefinition>()
112
+ const agentResources: ResourceDefinition[] = []
113
+ const commandViewAgents: CommandViewAgent[] = []
114
+
115
+ for (const agent of resources.agents ?? []) {
116
+ const resourceId = agent.config.resourceId
117
+ const serialized = serializeDefinition(agent) as SerializedAgentDefinition
118
+ agentDefinitions.set(resourceId, serialized)
119
+
83
120
  agentResources.push({
84
121
  resourceId,
85
122
  name: agent.config.name,
@@ -88,169 +125,171 @@ export function serializeOrganization(resources: DeploymentSpec): SerializedOrga
88
125
  type: 'agent',
89
126
  status: agent.config.status,
90
127
  links: agent.config.links,
91
- category: agent.config.category
128
+ category: agent.config.category,
129
+ ...getGovernanceMetadata(resourceId, agent.config.resource)
92
130
  })
93
-
94
- commandViewAgents.push({
95
- resourceId,
96
- name: agent.config.name,
131
+
132
+ commandViewAgents.push({
133
+ resourceId,
134
+ name: agent.config.name,
97
135
  description: agent.config.description,
98
136
  version: agent.config.version,
99
137
  type: 'agent',
100
138
  status: agent.config.status,
101
139
  links: agent.config.links,
102
140
  category: agent.config.category,
141
+ ...getGovernanceMetadata(resourceId, agent.config.resource),
103
142
  modelProvider: agent.modelConfig.provider,
104
- modelId: agent.modelConfig.model,
105
- toolCount: agent.tools.length,
106
- hasKnowledgeMap: agent.knowledgeMap !== undefined,
107
- hasMemory: agent.config.memoryPreferences !== undefined,
108
- sessionCapable: agent.config.sessionCapable ?? false
109
- })
110
- }
111
-
112
- // Build edges from triggers and relationships
113
- const edges = buildEdges(resources)
114
-
115
- // Pass-through manifest data (already JSON-safe)
116
- const triggers = resources.triggers ?? []
143
+ modelId: agent.modelConfig.model,
144
+ toolCount: agent.tools.length,
145
+ hasKnowledgeMap: agent.knowledgeMap !== undefined,
146
+ hasMemory: agent.config.memoryPreferences !== undefined,
147
+ sessionCapable: agent.config.sessionCapable ?? false
148
+ })
149
+ }
150
+
151
+ // Build edges from triggers and relationships
152
+ const edges = buildEdges(resources)
153
+
154
+ // Pass-through manifest data (already JSON-safe)
155
+ const triggers = resources.triggers ?? []
117
156
  const integrations = resources.integrations ?? []
118
157
  const externalResources = resources.externalResources ?? []
119
158
  const humanCheckpoints = resources.humanCheckpoints ?? []
120
159
 
121
160
  return {
122
- version: resources.version,
123
- resources: {
124
- workflows: workflowResources,
125
- agents: agentResources,
126
- total: workflowResources.length + agentResources.length
127
- },
128
- definitions: {
129
- workflows: workflowDefinitions,
130
- agents: agentDefinitions
131
- },
132
- commandView: {
133
- workflows: commandViewWorkflows,
134
- agents: commandViewAgents,
135
- triggers,
161
+ version: resources.version,
162
+ resources: {
163
+ workflows: workflowResources,
164
+ agents: agentResources,
165
+ total: workflowResources.length + agentResources.length
166
+ },
167
+ definitions: {
168
+ workflows: workflowDefinitions,
169
+ agents: agentDefinitions
170
+ },
171
+ commandView: {
172
+ workflows: commandViewWorkflows,
173
+ agents: commandViewAgents,
174
+ triggers,
136
175
  integrations,
137
176
  externalResources,
138
177
  humanCheckpoints,
139
178
  edges
140
179
  },
141
- triggers,
142
- integrations,
143
- externalResources,
144
- humanCheckpoints,
145
- relationships: resources.relationships
146
- }
147
- }
148
-
149
- /**
150
- * Build Command View edges from relationships
151
- * NOTE: Trigger relationships are now declared in ResourceRelationships, not on TriggerDefinition
152
- */
153
- export function buildEdges(resources: DeploymentSpec): CommandViewEdge[] {
154
- const edges: CommandViewEdge[] = []
155
- let edgeId = 0
156
-
157
- // All relationship edges (triggers, agents, workflows can all declare relationships)
158
- for (const [resourceId, declaration] of Object.entries(resources.relationships ?? {})) {
159
- for (const agentId of declaration.triggers?.agents ?? []) {
160
- edges.push({
161
- id: `edge-${edgeId++}`,
162
- source: resourceId,
163
- target: agentId,
164
- relationship: 'triggers'
165
- })
166
- }
167
- for (const workflowId of declaration.triggers?.workflows ?? []) {
168
- edges.push({
169
- id: `edge-${edgeId++}`,
170
- source: resourceId,
171
- target: workflowId,
172
- relationship: 'triggers'
173
- })
174
- }
175
- for (const integrationId of declaration.uses?.integrations ?? []) {
176
- edges.push({
177
- id: `edge-${edgeId++}`,
178
- source: resourceId,
179
- target: integrationId,
180
- relationship: 'uses'
181
- })
182
- }
183
- }
184
-
185
- // External Resource edges (forward-only)
186
- for (const external of resources.externalResources ?? []) {
187
- // External -> Internal
188
- for (const workflowId of external.triggers?.workflows ?? []) {
189
- edges.push({
190
- id: `edge-${edgeId++}`,
191
- source: external.resourceId,
192
- target: workflowId,
193
- relationship: 'triggers'
194
- })
195
- }
196
- for (const agentId of external.triggers?.agents ?? []) {
197
- edges.push({
198
- id: `edge-${edgeId++}`,
199
- source: external.resourceId,
200
- target: agentId,
201
- relationship: 'triggers'
202
- })
203
- }
204
-
205
- // External -> Integration
206
- for (const integrationId of external.uses?.integrations ?? []) {
207
- edges.push({
208
- id: `edge-${edgeId++}`,
209
- source: external.resourceId,
210
- target: integrationId,
211
- relationship: 'uses'
212
- })
213
- }
214
- }
215
-
216
- // Human Checkpoint edges
217
- for (const humanCheckpoint of resources.humanCheckpoints ?? []) {
218
- // Agent/Workflow -> ApprovalPoint
219
- for (const agentId of humanCheckpoint.requestedBy?.agents ?? []) {
220
- edges.push({
221
- id: `edge-${edgeId++}`,
222
- source: agentId,
223
- target: humanCheckpoint.resourceId,
224
- relationship: 'approval'
225
- })
226
- }
227
- for (const workflowId of humanCheckpoint.requestedBy?.workflows ?? []) {
228
- edges.push({
229
- id: `edge-${edgeId++}`,
230
- source: workflowId,
231
- target: humanCheckpoint.resourceId,
232
- relationship: 'approval'
233
- })
234
- }
235
-
236
- // ApprovalPoint -> Agent/Workflow
237
- for (const agentId of humanCheckpoint.routesTo?.agents ?? []) {
238
- edges.push({
239
- id: `edge-${edgeId++}`,
240
- source: humanCheckpoint.resourceId,
241
- target: agentId,
242
- relationship: 'triggers'
243
- })
244
- }
245
- for (const workflowId of humanCheckpoint.routesTo?.workflows ?? []) {
246
- edges.push({
247
- id: `edge-${edgeId++}`,
248
- source: humanCheckpoint.resourceId,
249
- target: workflowId,
250
- relationship: 'triggers'
251
- })
252
- }
253
- }
254
-
255
- return edges
256
- }
180
+ triggers,
181
+ integrations,
182
+ externalResources,
183
+ humanCheckpoints,
184
+ relationships: resources.relationships
185
+ }
186
+ }
187
+
188
+ /**
189
+ * Build Command View edges from relationships
190
+ * NOTE: Trigger relationships are now declared in ResourceRelationships, not on TriggerDefinition
191
+ */
192
+ export function buildEdges(resources: DeploymentSpec): CommandViewEdge[] {
193
+ const edges: CommandViewEdge[] = []
194
+ let edgeId = 0
195
+
196
+ // All relationship edges (triggers, agents, workflows can all declare relationships)
197
+ for (const [resourceId, declaration] of Object.entries(resources.relationships ?? {})) {
198
+ for (const agentId of declaration.triggers?.agents ?? []) {
199
+ edges.push({
200
+ id: `edge-${edgeId++}`,
201
+ source: resourceId,
202
+ target: agentId,
203
+ relationship: 'triggers'
204
+ })
205
+ }
206
+ for (const workflowId of declaration.triggers?.workflows ?? []) {
207
+ edges.push({
208
+ id: `edge-${edgeId++}`,
209
+ source: resourceId,
210
+ target: workflowId,
211
+ relationship: 'triggers'
212
+ })
213
+ }
214
+ for (const integrationId of declaration.uses?.integrations ?? []) {
215
+ edges.push({
216
+ id: `edge-${edgeId++}`,
217
+ source: resourceId,
218
+ target: integrationId,
219
+ relationship: 'uses'
220
+ })
221
+ }
222
+ }
223
+
224
+ // External Resource edges (forward-only)
225
+ for (const external of resources.externalResources ?? []) {
226
+ // External -> Internal
227
+ for (const workflowId of external.triggers?.workflows ?? []) {
228
+ edges.push({
229
+ id: `edge-${edgeId++}`,
230
+ source: external.resourceId,
231
+ target: workflowId,
232
+ relationship: 'triggers'
233
+ })
234
+ }
235
+ for (const agentId of external.triggers?.agents ?? []) {
236
+ edges.push({
237
+ id: `edge-${edgeId++}`,
238
+ source: external.resourceId,
239
+ target: agentId,
240
+ relationship: 'triggers'
241
+ })
242
+ }
243
+
244
+ // External -> Integration
245
+ for (const integrationId of external.uses?.integrations ?? []) {
246
+ edges.push({
247
+ id: `edge-${edgeId++}`,
248
+ source: external.resourceId,
249
+ target: integrationId,
250
+ relationship: 'uses'
251
+ })
252
+ }
253
+ }
254
+
255
+ // Human Checkpoint edges
256
+ for (const humanCheckpoint of resources.humanCheckpoints ?? []) {
257
+ // Agent/Workflow -> ApprovalPoint
258
+ for (const agentId of humanCheckpoint.requestedBy?.agents ?? []) {
259
+ edges.push({
260
+ id: `edge-${edgeId++}`,
261
+ source: agentId,
262
+ target: humanCheckpoint.resourceId,
263
+ relationship: 'approval'
264
+ })
265
+ }
266
+ for (const workflowId of humanCheckpoint.requestedBy?.workflows ?? []) {
267
+ edges.push({
268
+ id: `edge-${edgeId++}`,
269
+ source: workflowId,
270
+ target: humanCheckpoint.resourceId,
271
+ relationship: 'approval'
272
+ })
273
+ }
274
+
275
+ // ApprovalPoint -> Agent/Workflow
276
+ for (const agentId of humanCheckpoint.routesTo?.agents ?? []) {
277
+ edges.push({
278
+ id: `edge-${edgeId++}`,
279
+ source: humanCheckpoint.resourceId,
280
+ target: agentId,
281
+ relationship: 'triggers'
282
+ })
283
+ }
284
+ for (const workflowId of humanCheckpoint.routesTo?.workflows ?? []) {
285
+ edges.push({
286
+ id: `edge-${edgeId++}`,
287
+ source: humanCheckpoint.resourceId,
288
+ target: workflowId,
289
+ relationship: 'triggers'
290
+ })
291
+ }
292
+ }
293
+
294
+ return edges
295
+ }
@@ -31,6 +31,7 @@ export interface SerializedAgentDefinition {
31
31
  description: string
32
32
  version: string
33
33
  type: 'agent'
34
+ kind: 'orchestrator' | 'specialist' | 'utility' | 'system'
34
35
  status: 'dev' | 'prod'
35
36
  links?: ResourceLink[]
36
37
  category?: ResourceCategory