@elevasis/core 0.22.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 (112) hide show
  1. package/dist/index.d.ts +2330 -2391
  2. package/dist/index.js +2322 -1147
  3. package/dist/knowledge/index.d.ts +702 -1136
  4. package/dist/knowledge/index.js +9 -9
  5. package/dist/organization-model/index.d.ts +2330 -2391
  6. package/dist/organization-model/index.js +2322 -1147
  7. package/dist/test-utils/index.d.ts +703 -1106
  8. package/dist/test-utils/index.js +1735 -1089
  9. package/package.json +1 -1
  10. package/src/__tests__/template-core-compatibility.test.ts +11 -79
  11. package/src/_gen/__tests__/__snapshots__/contracts.md.snap +360 -98
  12. package/src/business/acquisition/api-schemas.test.ts +2 -2
  13. package/src/business/acquisition/api-schemas.ts +7 -9
  14. package/src/business/acquisition/build-templates.test.ts +4 -4
  15. package/src/business/acquisition/build-templates.ts +72 -30
  16. package/src/business/acquisition/crm-state-actions.test.ts +13 -11
  17. package/src/business/acquisition/types.ts +7 -3
  18. package/src/execution/engine/agent/core/types.ts +1 -1
  19. package/src/execution/engine/workflow/types.ts +2 -2
  20. package/src/knowledge/README.md +8 -7
  21. package/src/knowledge/__tests__/queries.test.ts +74 -73
  22. package/src/knowledge/format.ts +10 -9
  23. package/src/knowledge/index.ts +1 -1
  24. package/src/knowledge/published.ts +1 -1
  25. package/src/knowledge/queries.ts +26 -25
  26. package/src/organization-model/README.md +66 -26
  27. package/src/organization-model/__tests__/content-kinds-registry.test.ts +210 -0
  28. package/src/organization-model/__tests__/defaults.test.ts +72 -98
  29. package/src/organization-model/__tests__/domains/actions.test.ts +56 -0
  30. package/src/organization-model/__tests__/domains/customers.test.ts +299 -295
  31. package/src/organization-model/__tests__/domains/entities.test.ts +56 -0
  32. package/src/organization-model/__tests__/domains/goals.test.ts +493 -479
  33. package/src/organization-model/__tests__/domains/identity.test.ts +280 -279
  34. package/src/organization-model/__tests__/domains/navigation.test.ts +268 -212
  35. package/src/organization-model/__tests__/domains/offerings.test.ts +414 -419
  36. package/src/organization-model/__tests__/domains/policies.test.ts +323 -0
  37. package/src/organization-model/__tests__/domains/resource-mappings.test.ts +271 -271
  38. package/src/organization-model/__tests__/domains/resources.test.ts +159 -37
  39. package/src/organization-model/__tests__/domains/roles.test.ts +147 -86
  40. package/src/organization-model/__tests__/domains/statuses.test.ts +246 -243
  41. package/src/organization-model/__tests__/domains/systems.test.ts +67 -51
  42. package/src/organization-model/__tests__/flatten-additive-merge.test.ts +361 -0
  43. package/src/organization-model/__tests__/foundation.test.ts +74 -102
  44. package/src/organization-model/__tests__/get-resources-for-system.test.ts +144 -0
  45. package/src/organization-model/__tests__/graph.test.ts +899 -71
  46. package/src/organization-model/__tests__/knowledge.test.ts +173 -52
  47. package/src/organization-model/__tests__/lookup-helpers.test.ts +438 -0
  48. package/src/organization-model/__tests__/migration-helpers.test.ts +591 -0
  49. package/src/organization-model/__tests__/prospecting-ssot.test.ts +36 -27
  50. package/src/organization-model/__tests__/recursive-system-schema.test.ts +520 -0
  51. package/src/organization-model/__tests__/resolve.test.ts +174 -23
  52. package/src/organization-model/__tests__/schema.test.ts +291 -114
  53. package/src/organization-model/__tests__/surface-projection.test.ts +207 -97
  54. package/src/organization-model/catalogs/lead-gen.ts +144 -0
  55. package/src/organization-model/content-kinds/config.ts +36 -0
  56. package/src/organization-model/content-kinds/index.ts +74 -0
  57. package/src/organization-model/content-kinds/pipeline.ts +68 -0
  58. package/src/organization-model/content-kinds/registry.ts +44 -0
  59. package/src/organization-model/content-kinds/status.ts +71 -0
  60. package/src/organization-model/content-kinds/template.ts +83 -0
  61. package/src/organization-model/content-kinds/types.ts +117 -0
  62. package/src/organization-model/contracts.ts +13 -3
  63. package/src/organization-model/defaults.ts +488 -96
  64. package/src/organization-model/domains/actions.ts +239 -0
  65. package/src/organization-model/domains/customers.ts +78 -75
  66. package/src/organization-model/domains/entities.ts +144 -0
  67. package/src/organization-model/domains/goals.ts +83 -80
  68. package/src/organization-model/domains/knowledge.ts +74 -16
  69. package/src/organization-model/domains/navigation.ts +107 -384
  70. package/src/organization-model/domains/offerings.ts +71 -66
  71. package/src/organization-model/domains/policies.ts +102 -0
  72. package/src/organization-model/domains/projects.ts +14 -48
  73. package/src/organization-model/domains/prospecting.ts +62 -181
  74. package/src/organization-model/domains/resources.ts +81 -24
  75. package/src/organization-model/domains/roles.ts +13 -10
  76. package/src/organization-model/domains/sales.ts +10 -219
  77. package/src/organization-model/domains/shared.ts +57 -57
  78. package/src/organization-model/domains/statuses.ts +339 -130
  79. package/src/organization-model/domains/systems.ts +186 -29
  80. package/src/organization-model/foundation.ts +54 -67
  81. package/src/organization-model/graph/build.ts +682 -54
  82. package/src/organization-model/graph/link.ts +1 -1
  83. package/src/organization-model/graph/schema.ts +24 -9
  84. package/src/organization-model/graph/types.ts +20 -7
  85. package/src/organization-model/helpers.ts +231 -26
  86. package/src/organization-model/index.ts +116 -5
  87. package/src/organization-model/migration-helpers.ts +249 -0
  88. package/src/organization-model/organization-graph.mdx +16 -15
  89. package/src/organization-model/organization-model.mdx +89 -41
  90. package/src/organization-model/published.ts +120 -18
  91. package/src/organization-model/resolve.ts +117 -54
  92. package/src/organization-model/schema.ts +561 -140
  93. package/src/organization-model/surface-projection.ts +116 -122
  94. package/src/organization-model/types.ts +102 -21
  95. package/src/platform/constants/versions.ts +1 -1
  96. package/src/platform/registry/__tests__/command-view.test.ts +6 -8
  97. package/src/platform/registry/__tests__/resource-link.test.ts +13 -8
  98. package/src/platform/registry/__tests__/resource-registry.integration.test.ts +16 -31
  99. package/src/platform/registry/__tests__/resource-registry.nested-systems.test.ts +245 -0
  100. package/src/platform/registry/__tests__/resource-registry.test.ts +9 -7
  101. package/src/platform/registry/__tests__/validation.test.ts +15 -11
  102. package/src/platform/registry/resource-registry.ts +20 -8
  103. package/src/platform/registry/serialization.ts +7 -7
  104. package/src/platform/registry/types.ts +3 -3
  105. package/src/platform/registry/validation.ts +17 -15
  106. package/src/reference/_generated/contracts.md +362 -99
  107. package/src/reference/glossary.md +18 -18
  108. package/src/supabase/database.types.ts +60 -0
  109. package/src/test-utils/test-utils.test.ts +1 -6
  110. package/src/organization-model/__tests__/domains/operations.test.ts +0 -203
  111. package/src/organization-model/domains/features.ts +0 -31
  112. package/src/organization-model/domains/operations.ts +0 -85
@@ -1,5 +1,11 @@
1
- export { OrganizationModelSchema } from './schema'
2
- export { FeatureSchema, NodeIdPathSchema, NodeIdStringSchema, UiPositionSchema } from './domains/features'
1
+ export {
2
+ DEFAULT_ORGANIZATION_MODEL_DOMAIN_METADATA,
3
+ OrganizationModelDomainKeySchema,
4
+ OrganizationModelDomainMetadataByDomainSchema,
5
+ OrganizationModelDomainMetadataSchema,
6
+ OrganizationModelSchema
7
+ } from './schema'
8
+ export { NodeIdPathSchema, NodeIdStringSchema, UiPositionSchema } from './domains/systems'
3
9
  export { LinkSchema } from './graph/link'
4
10
  export { IconNameSchema, TechStackEntrySchema } from './domains/shared'
5
11
  export {
@@ -9,15 +15,23 @@ export {
9
15
  } from './icons'
10
16
  export {
11
17
  KNOWLEDGE_FEATURE_ID,
18
+ KNOWLEDGE_SYSTEM_ID,
12
19
  PROJECTS_FEATURE_ID,
20
+ PROJECTS_SYSTEM_ID,
13
21
  PROJECTS_INDEX_SURFACE_ID,
14
- PROJECTS_VIEW_CAPABILITY_ID,
22
+ PROJECTS_VIEW_ACTION_ID,
15
23
  SALES_FEATURE_ID,
16
24
  PROSPECTING_FEATURE_ID,
17
25
  OPERATIONS_FEATURE_ID,
26
+ SALES_SYSTEM_ID,
27
+ PROSPECTING_SYSTEM_ID,
28
+ OPERATIONS_SYSTEM_ID,
18
29
  MONITORING_FEATURE_ID,
30
+ MONITORING_SYSTEM_ID,
19
31
  SETTINGS_FEATURE_ID,
32
+ SETTINGS_SYSTEM_ID,
20
33
  SEO_FEATURE_ID,
34
+ SEO_SYSTEM_ID,
21
35
  SALES_PIPELINE_SURFACE_ID,
22
36
  PROSPECTING_LISTS_SURFACE_ID,
23
37
  OPERATIONS_COMMAND_VIEW_SURFACE_ID,
@@ -30,12 +44,6 @@ export {
30
44
  StatusEntrySchema,
31
45
  StatusSemanticClassSchema
32
46
  } from './domains/statuses'
33
- export {
34
- DEFAULT_ORGANIZATION_MODEL_OPERATIONS,
35
- OperationsDomainSchema,
36
- OperationEntrySchema,
37
- OperationSemanticClassSchema
38
- } from './domains/operations'
39
47
  export {
40
48
  DEFAULT_ORGANIZATION_MODEL_CUSTOMERS,
41
49
  CustomersDomainSchema,
@@ -65,6 +73,9 @@ export {
65
73
  SystemEntrySchema,
66
74
  SystemIdSchema,
67
75
  SystemKindSchema,
76
+ SystemLifecycleSchema,
77
+ SystemPathSchema,
78
+ SystemUiSchema,
68
79
  SystemsDomainSchema,
69
80
  SystemStatusSchema
70
81
  } from './domains/systems'
@@ -74,55 +85,140 @@ export {
74
85
  DEFAULT_ORGANIZATION_MODEL_RESOURCES,
75
86
  defineResource,
76
87
  defineResources,
88
+ EventDescriptorSchema,
89
+ EventEmissionDescriptorSchema,
90
+ EventIdSchema,
77
91
  IntegrationResourceEntrySchema,
78
92
  ResourceEntrySchema,
79
93
  ResourceGovernanceStatusSchema,
80
94
  ResourceIdSchema,
81
95
  ResourceKindSchema,
82
96
  ResourcesDomainSchema,
97
+ ScriptResourceEntrySchema,
98
+ ScriptResourceLanguageSchema,
99
+ ScriptResourceSourceSchema,
83
100
  WorkflowResourceEntrySchema
84
101
  } from './domains/resources'
102
+ export {
103
+ ActionsDomainSchema,
104
+ ActionIdSchema,
105
+ ActionInvocationKindSchema,
106
+ ActionInvocationSchema,
107
+ ActionRefSchema,
108
+ ActionSchema,
109
+ ActionScopeSchema,
110
+ ApiEndpointInvocationSchema,
111
+ DEFAULT_ORGANIZATION_MODEL_ACTIONS,
112
+ findOrganizationActionById,
113
+ LEAD_GEN_ACTION_ENTRIES,
114
+ McpToolInvocationSchema,
115
+ ScriptExecutionInvocationSchema,
116
+ SlashCommandInvocationSchema
117
+ } from './domains/actions'
118
+ export {
119
+ DEFAULT_ORGANIZATION_MODEL_ENTITIES,
120
+ EntitiesDomainSchema,
121
+ EntityIdSchema,
122
+ EntityLinkKindSchema,
123
+ EntityLinkSchema,
124
+ EntitySchema
125
+ } from './domains/entities'
126
+ export {
127
+ DEFAULT_ORGANIZATION_MODEL_POLICIES,
128
+ PoliciesDomainSchema,
129
+ PolicyEffectSchema,
130
+ PolicyApplicabilitySchema,
131
+ PolicyIdSchema,
132
+ PolicyPredicateSchema,
133
+ PolicySchema,
134
+ PolicyTriggerSchema
135
+ } from './domains/policies'
136
+ export { LEAD_GEN_STAGE_CATALOG } from './catalogs/lead-gen'
137
+ export {
138
+ DEFAULT_ORGANIZATION_MODEL_NAVIGATION,
139
+ getSortedSidebarEntries,
140
+ NavigationGroupSchema,
141
+ OrganizationModelNavigationSchema,
142
+ SidebarNavigationSchema,
143
+ SidebarNodeSchema,
144
+ SidebarSectionSchema,
145
+ SidebarSurfaceTargetsSchema,
146
+ SurfaceDefinitionSchema,
147
+ SurfaceTypeSchema
148
+ } from './domains/navigation'
85
149
  export {
86
150
  KnowledgeDomainSchema,
87
151
  KnowledgeLinkSchema,
152
+ KnowledgeTargetKindSchema,
153
+ KnowledgeTargetRefSchema,
88
154
  OrgKnowledgeNodeSchema,
89
155
  OrgKnowledgeKindSchema
90
156
  } from './domains/knowledge'
91
- export { defineOrganizationModel, resolveOrganizationModel } from './resolve'
157
+ export { defineOrganizationModel, resolveOrganizationModel, resolveOrganizationModelWithResources } from './resolve'
158
+ export type { ResolvedSystemEntry, ResolvedOrganizationModel } from './resolve'
92
159
  export { createFoundationOrganizationModel } from './foundation'
93
160
 
94
161
  export type {
95
162
  DeepPartial,
163
+ KnowledgeLink,
164
+ KnowledgeTargetKind,
165
+ KnowledgeTargetRef,
96
166
  OrganizationModel,
97
167
  OrganizationModelBranding,
98
- OrganizationModelSales,
99
- OrganizationModelProspecting,
100
- OrganizationModelProjects,
101
168
  OrganizationModelCustomerFirmographics,
102
169
  OrganizationModelCustomers,
103
170
  OrganizationModelCustomerSegment,
104
- OrganizationModelFeature,
105
171
  OrganizationModelGoals,
172
+ OrganizationModelNavigation,
173
+ OrganizationModelSidebar,
174
+ OrganizationModelSidebarGroupNode,
175
+ OrganizationModelSidebarNode,
176
+ OrganizationModelSidebarSection,
177
+ OrganizationModelSidebarSurfaceNode,
178
+ OrganizationModelSidebarSurfaceTargets,
106
179
  OrganizationModelKeyResult,
107
180
  OrganizationModelObjective,
108
181
  OrganizationModelSystemEntry,
109
182
  OrganizationModelSystemId,
110
183
  OrganizationModelSystemKind,
184
+ OrganizationModelSystemLifecycle,
111
185
  OrganizationModelSystems,
112
186
  OrganizationModelSystemStatus,
113
187
  OrganizationModelAgentKind,
114
188
  OrganizationModelAgentResourceEntry,
189
+ EventDescriptor,
190
+ EventEmissionDescriptor,
191
+ EventId,
115
192
  OrganizationModelIntegrationResourceEntry,
116
193
  OrganizationModelResourceEntry,
117
194
  OrganizationModelResourceGovernanceStatus,
118
195
  OrganizationModelResourceId,
119
196
  OrganizationModelResourceKind,
120
197
  OrganizationModelResources,
198
+ OrganizationModelScriptResourceEntry,
199
+ OrganizationModelScriptResourceLanguage,
200
+ OrganizationModelScriptResourceSource,
121
201
  OrganizationModelWorkflowResourceEntry,
202
+ OrganizationModelActions,
203
+ OrganizationModelAction,
204
+ OrganizationModelActionId,
205
+ OrganizationModelActionInvocation,
206
+ OrganizationModelActionInvocationKind,
207
+ OrganizationModelActionRef,
208
+ OrganizationModelActionScope,
209
+ Entity,
210
+ EntityId,
211
+ EntityLink,
212
+ OrganizationModelEntities,
213
+ OrganizationModelEntity,
214
+ OrganizationModelPolicies,
215
+ OrganizationModelPolicy,
216
+ OrganizationModelPolicyEffect,
217
+ OrganizationModelPolicyApplicability,
218
+ OrganizationModelPolicyId,
219
+ OrganizationModelPolicyPredicate,
220
+ OrganizationModelPolicyTrigger,
122
221
  OrganizationModelOfferings,
123
- OrganizationModelOperationEntry,
124
- OrganizationModelOperationSemanticClass,
125
- OrganizationModelOperations,
126
222
  OrganizationModelPricingModel,
127
223
  OrganizationModelProduct,
128
224
  OrganizationModelRole,
@@ -140,11 +236,17 @@ export type {
140
236
  NodeIdString,
141
237
  OrganizationModelKnowledge,
142
238
  OrgKnowledgeNode,
239
+ OrgKnowledgeNodeInput,
143
240
  OrgKnowledgeKind,
144
241
  OrganizationModelIconToken,
145
- OrganizationModelBuiltinIconToken
242
+ OrganizationModelBuiltinIconToken,
243
+ OrganizationModelDomainKey,
244
+ OrganizationModelDomainMetadata,
245
+ OrganizationModelDomainMetadataByDomain
146
246
  } from './types'
147
247
 
248
+ export type { LeadGenStageCatalogEntry } from './catalogs/lead-gen'
249
+
148
250
  export type {
149
251
  FoundationBranding,
150
252
  FoundationNavigationSurface,
@@ -1,54 +1,117 @@
1
- import { DEFAULT_ORGANIZATION_MODEL } from './defaults'
2
- import { OrganizationModelSchema } from './schema'
3
- import type { DeepPartial, OrganizationModel } from './types'
4
-
5
- function isPlainObject(value: unknown): value is Record<string, unknown> {
6
- return typeof value === 'object' && value !== null && !Array.isArray(value)
7
- }
8
-
9
- function deepMerge<T>(base: T, override: DeepPartial<T> | undefined): T {
10
- if (override === undefined) {
11
- return base
12
- }
13
-
14
- if (Array.isArray(base)) {
15
- return (override as T) ?? base
16
- }
17
-
18
- if (!isPlainObject(base) || !isPlainObject(override)) {
19
- return (override as T) ?? base
20
- }
21
-
22
- const result: Record<string, unknown> = { ...base }
23
-
24
- for (const [key, value] of Object.entries(override)) {
25
- if (value === undefined) continue
26
-
27
- const existing = result[key]
28
- result[key] = isPlainObject(existing) && isPlainObject(value) ? deepMerge(existing, value) : value
29
- }
30
-
31
- return result as T
32
- }
33
-
34
- export function defineOrganizationModel<T extends DeepPartial<OrganizationModel>>(model: T): T {
35
- return model
36
- }
37
-
38
- export function resolveOrganizationModel(
39
- override?: DeepPartial<OrganizationModel>,
40
- organizationId?: string
41
- ): OrganizationModel {
42
- const merged = deepMerge(DEFAULT_ORGANIZATION_MODEL, override)
43
- const model = OrganizationModelSchema.parse(merged)
44
-
45
- if (!model.sales?.pipelines || model.sales.pipelines.length === 0) {
46
- const orgLabel = organizationId ? `Organization ${organizationId}` : 'Organization'
47
- throw new Error(
48
- `${orgLabel} has no sales pipeline configuration. ` +
49
- `This indicates an incomplete provisioning state. Run org provisioning to seed defaults.`
50
- )
51
- }
52
-
53
- return model
54
- }
1
+ import { DEFAULT_ORGANIZATION_MODEL } from './defaults'
2
+ import { listAllSystems } from './helpers'
3
+ import { OrganizationModelSchema } from './schema'
4
+ import type { DeepPartial, OrganizationModel, OrganizationModelSystemEntry } from './types'
5
+ import type { ResourceEntry } from './domains/resources'
6
+
7
+ /**
8
+ * A system entry enriched with the list of resources that directly attach to
9
+ * this system (i.e. `resource.systemPath` exactly matches the system's path).
10
+ *
11
+ * Descendant rollup is NOT included here — callers that need it should use
12
+ * `getResourcesForSystem(model, path, { includeDescendants: true })` from helpers.
13
+ */
14
+ export type ResolvedSystemEntry = OrganizationModelSystemEntry & {
15
+ /** Resources whose `systemPath` exactly matches this system's path. */
16
+ resources?: ResourceEntry[]
17
+ }
18
+
19
+ /**
20
+ * An `OrganizationModel` where every flat-system entry in `systems` has been
21
+ * enriched with its directly-attached `resources`.
22
+ *
23
+ * Produced by `resolveOrganizationModelWithResources`. The flat `systems` map
24
+ * only covers top-level keys (same shape as `OrganizationModel.systems`);
25
+ * hierarchical walk uses `listAllSystems` from helpers.
26
+ */
27
+ export type ResolvedOrganizationModel = Omit<OrganizationModel, 'systems'> & {
28
+ systems: Record<string, ResolvedSystemEntry>
29
+ }
30
+
31
+ function isPlainObject(value: unknown): value is Record<string, unknown> {
32
+ return typeof value === 'object' && value !== null && !Array.isArray(value)
33
+ }
34
+
35
+ function deepMerge<T>(base: T, override: DeepPartial<T> | undefined): T {
36
+ if (override === undefined) {
37
+ return base
38
+ }
39
+
40
+ if (Array.isArray(base)) {
41
+ return (override as T) ?? base
42
+ }
43
+
44
+ if (!isPlainObject(base) || !isPlainObject(override)) {
45
+ return (override as T) ?? base
46
+ }
47
+
48
+ const result: Record<string, unknown> = { ...base }
49
+
50
+ for (const [key, value] of Object.entries(override)) {
51
+ if (value === undefined) continue
52
+
53
+ const existing = result[key]
54
+ result[key] = isPlainObject(existing) && isPlainObject(value) ? deepMerge(existing, value) : value
55
+ }
56
+
57
+ return result as T
58
+ }
59
+
60
+ export function defineOrganizationModel<T extends DeepPartial<OrganizationModel>>(model: T): T {
61
+ return model
62
+ }
63
+
64
+ export function resolveOrganizationModel(
65
+ override?: DeepPartial<OrganizationModel>,
66
+ organizationId?: string
67
+ ): OrganizationModel {
68
+ void organizationId
69
+ const merged = deepMerge(DEFAULT_ORGANIZATION_MODEL, override)
70
+ // Phase 4: compound-domain sanity gate for model.sales?.pipelines removed.
71
+ // Pipeline data now lives in system.content; use getAllPipelines(model) from
72
+ // migration-helpers to check pipeline presence when needed.
73
+ return OrganizationModelSchema.parse(merged)
74
+ }
75
+
76
+ /**
77
+ * Resolve the organization model and enrich each flat system entry in
78
+ * `model.systems` with the list of resources whose `systemPath` exactly
79
+ * matches that system's flat key.
80
+ *
81
+ * This is a pure additive view — no schema is changed. Descendant resource
82
+ * rollup is intentionally excluded; consumers that need it can call
83
+ * `getResourcesForSystem(model, path, { includeDescendants: true })`.
84
+ *
85
+ * @example
86
+ * const resolved = resolveOrganizationModelWithResources(override)
87
+ * resolved.systems['sys.lead-gen']?.resources
88
+ * // → ResourceEntry[] | undefined
89
+ */
90
+ export function resolveOrganizationModelWithResources(
91
+ override?: DeepPartial<OrganizationModel>,
92
+ organizationId?: string
93
+ ): ResolvedOrganizationModel {
94
+ const model = resolveOrganizationModel(override, organizationId)
95
+
96
+ // Build a path → resource[] index from the flat resources map.
97
+ // Only direct system-path matches (no descendant rollup).
98
+ const byPath = new Map<string, ResourceEntry[]>()
99
+ for (const resource of Object.values(model.resources ?? {})) {
100
+ const existing = byPath.get(resource.systemPath)
101
+ if (existing) {
102
+ existing.push(resource)
103
+ } else {
104
+ byPath.set(resource.systemPath, [resource])
105
+ }
106
+ }
107
+
108
+ // Enrich every system entry, including nested subsystems, with directly
109
+ // attached resources keyed by computed system path.
110
+ const enrichedSystems: Record<string, ResolvedSystemEntry> = {}
111
+ for (const { path, system } of listAllSystems(model)) {
112
+ const resources = byPath.get(path) ?? byPath.get(system.id)
113
+ enrichedSystems[path] = resources !== undefined ? { ...system, id: path, resources } : { ...system, id: path }
114
+ }
115
+
116
+ return { ...model, systems: enrichedSystems }
117
+ }