@elevasis/ui 2.31.0 → 2.32.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/{CoreAuthKitInner-KSEGSB67.js → CoreAuthKitInner-QC62UHTZ.js} +1 -1
- package/dist/api/index.js +3 -3
- package/dist/app/index.css +38 -0
- package/dist/app/index.d.ts +69 -9
- package/dist/app/index.js +7 -6
- package/dist/auth/context.js +1 -1
- package/dist/auth/index.js +1 -1
- package/dist/charts/index.js +5 -6
- package/dist/{chunk-XQHZBA65.js → chunk-2RJMVWFJ.js} +1 -6
- package/dist/{chunk-CW3UNAF2.js → chunk-4DYOXEH6.js} +410 -5
- package/dist/{chunk-HQGF4ATG.js → chunk-4MFNGNHF.js} +118 -141
- package/dist/{chunk-ND42LPY4.js → chunk-4QK76KIF.js} +6 -6
- package/dist/chunk-5FJJ72HU.js +13 -0
- package/dist/chunk-5J4PDX26.js +112 -0
- package/dist/{chunk-QDEETKYT.js → chunk-6DWD423K.js} +9 -9
- package/dist/{chunk-SHQXMW4F.js → chunk-7KZINJLP.js} +46 -28
- package/dist/{chunk-L3BVJWML.js → chunk-EPTHX4VZ.js} +1 -1
- package/dist/{chunk-JKSUN5GN.js → chunk-GCOQ3TBG.js} +81 -746
- package/dist/{chunk-DZTG5IAC.js → chunk-I2KLQ2HA.js} +1 -7
- package/dist/{chunk-L2NVFLXU.js → chunk-IQHU7O5Y.js} +4 -4
- package/dist/{chunk-P55BJZZW.js → chunk-IZWTVFJ2.js} +16 -4
- package/dist/{chunk-QHEWXU7I.js → chunk-JFL3GRD4.js} +1 -1
- package/dist/{chunk-Q6OYNEGR.js → chunk-LLRXA7D7.js} +5 -6
- package/dist/{chunk-7KC4P3AU.js → chunk-MOY4VOHF.js} +2 -12
- package/dist/{chunk-XQQEKWTL.js → chunk-N55DVMAG.js} +6 -2
- package/dist/{chunk-TOIXUWR6.js → chunk-ND5TDV2J.js} +1 -1
- package/dist/{chunk-WF227UBV.js → chunk-QQHOKTJA.js} +4 -4
- package/dist/{chunk-T3IPHEYJ.js → chunk-QTI3KC7D.js} +4335 -554
- package/dist/chunk-QXCDKE2O.js +486 -0
- package/dist/{chunk-3BAPR3KA.js → chunk-RQA2EVN3.js} +5 -15
- package/dist/{chunk-HYNYEBHM.js → chunk-RQTWIXJ5.js} +3 -3
- package/dist/chunk-T35FWDAB.js +4342 -0
- package/dist/{chunk-DWK2QIAK.js → chunk-TYRUKGGD.js} +1 -1
- package/dist/{chunk-GRDLB6LM.js → chunk-UROTM5OR.js} +13 -1
- package/dist/{chunk-6YT4IKJ7.js → chunk-VNAZTCHA.js} +15 -0
- package/dist/{chunk-5LJAEZMA.js → chunk-VRNMNB3O.js} +5 -6
- package/dist/chunk-WQPX44YM.js +1626 -0
- package/dist/{chunk-7HMCB26R.js → chunk-XZGSCABI.js} +1 -1
- package/dist/chunk-YLQEVSOR.js +299 -0
- package/dist/{chunk-Y4FWCG7Y.js → chunk-ZQOKIGZP.js} +8 -7
- package/dist/components/chat/index.js +1 -1
- package/dist/components/index.css +38 -0
- package/dist/components/index.d.ts +152 -50
- package/dist/components/index.js +36 -39
- package/dist/components/navigation/index.css +38 -0
- package/dist/components/navigation/index.js +4 -3
- package/dist/execution/index.d.ts +7 -2
- package/dist/execution/index.js +1 -1
- package/dist/features/auth/index.css +38 -0
- package/dist/features/auth/index.d.ts +91 -14
- package/dist/features/auth/index.js +42 -10
- package/dist/features/clients/index.css +38 -0
- package/dist/features/clients/index.d.ts +1 -1
- package/dist/features/clients/index.js +16 -15
- package/dist/features/crm/index.css +38 -0
- package/dist/features/crm/index.d.ts +80 -18
- package/dist/features/crm/index.js +16 -15
- package/dist/features/dashboard/index.css +38 -0
- package/dist/features/dashboard/index.d.ts +65 -25
- package/dist/features/dashboard/index.js +16 -16
- package/dist/features/delivery/index.css +38 -0
- package/dist/features/delivery/index.d.ts +80 -18
- package/dist/features/delivery/index.js +15 -15
- package/dist/features/knowledge/index.css +38 -0
- package/dist/features/knowledge/index.d.ts +20 -18
- package/dist/features/knowledge/index.js +112 -597
- package/dist/features/lead-gen/index.css +38 -0
- package/dist/features/lead-gen/index.d.ts +45 -43
- package/dist/features/lead-gen/index.js +16 -16
- package/dist/features/monitoring/index.css +38 -0
- package/dist/features/monitoring/index.d.ts +20 -18
- package/dist/features/monitoring/index.js +17 -17
- package/dist/features/monitoring/requests/index.css +38 -0
- package/dist/features/monitoring/requests/index.d.ts +21 -19
- package/dist/features/monitoring/requests/index.js +15 -14
- package/dist/features/operations/index.css +38 -0
- package/dist/features/operations/index.d.ts +930 -66
- package/dist/features/operations/index.js +21 -24
- package/dist/features/seo/index.d.ts +20 -18
- package/dist/features/seo/index.js +2 -2
- package/dist/features/settings/index.css +38 -0
- package/dist/features/settings/index.d.ts +80 -18
- package/dist/features/settings/index.js +16 -15
- package/dist/graph/index.js +1 -1
- package/dist/hooks/delivery/index.css +38 -0
- package/dist/hooks/delivery/index.d.ts +60 -0
- package/dist/hooks/delivery/index.js +3 -3
- package/dist/hooks/index.css +38 -0
- package/dist/hooks/index.d.ts +301 -87
- package/dist/hooks/index.js +14 -13
- package/dist/hooks/operations/command-view/utils/transformCommandViewData.d.ts +143 -33
- package/dist/hooks/operations/command-view/utils/transformCommandViewData.js +1 -1
- package/dist/hooks/published.css +38 -0
- package/dist/hooks/published.d.ts +301 -87
- package/dist/hooks/published.js +14 -13
- package/dist/index.css +38 -0
- package/dist/index.d.ts +976 -1341
- package/dist/index.js +15 -14
- package/dist/initialization/index.d.ts +60 -0
- package/dist/initialization/index.js +1 -1
- package/dist/knowledge/index.d.ts +809 -1160
- package/dist/knowledge/index.js +5988 -2140
- package/dist/{chunk-O2QOPJI5.js → knowledge-search-index-5KYPO746.js} +96 -852
- package/dist/layout/index.js +3 -4
- package/dist/organization/index.css +38 -0
- package/dist/organization/index.js +1 -1
- package/dist/profile/index.d.ts +60 -0
- package/dist/profile/index.js +1 -1
- package/dist/provider/ElevasisServiceContext.js +1 -1
- package/dist/provider/index.css +38 -0
- package/dist/provider/index.d.ts +786 -1249
- package/dist/provider/index.js +11 -10
- package/dist/provider/published.css +38 -0
- package/dist/provider/published.d.ts +783 -1246
- package/dist/provider/published.js +8 -7
- package/dist/router/context.js +1 -1
- package/dist/router/index.js +1 -1
- package/dist/sse/index.js +1 -1
- package/dist/supabase/index.d.ts +117 -0
- package/dist/supabase/index.js +1 -1
- package/dist/test-utils/index.d.ts +16 -9
- package/dist/test-utils/index.js +40 -33
- package/dist/test-utils/setup-integration.js +1 -1
- package/dist/test-utils/setup.js +1 -1
- package/dist/theme/index.js +3 -3
- package/dist/theme/presets/index.js +1 -1
- package/dist/typeform/index.js +1 -1
- package/dist/typeform/schemas.js +1 -1
- package/dist/types/index.d.ts +205 -35
- package/dist/utils/index.d.ts +65 -25
- package/dist/utils/index.js +2 -2
- package/dist/vite/index.js +1 -1
- package/dist/vite-plugin-knowledge/index.js +1 -1
- package/dist/zustand/index.js +1 -1
- package/package.json +39 -38
- package/src/provider/README.md +5 -5
- package/dist/chunk-542WPQU2.js +0 -413
- package/dist/chunk-6IXOKUBC.js +0 -347
- package/dist/chunk-CQZ3DNQY.js +0 -740
- package/dist/chunk-ECNNI3NT.js +0 -6
- package/dist/chunk-JDNEWB5F.js +0 -10
- package/dist/chunk-MVFCLZSK.js +0 -4337
- package/dist/chunk-OAVTMITG.js +0 -13
- package/dist/chunk-TVRQ6AQI.js +0 -476
|
@@ -0,0 +1,4342 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
|
|
3
|
+
// ../core/src/organization-model/domains/systems.ts
|
|
4
|
+
var ORGANIZATION_MODEL_ICON_TOKENS = [
|
|
5
|
+
"nav.dashboard",
|
|
6
|
+
"nav.calendar",
|
|
7
|
+
"nav.sales",
|
|
8
|
+
"nav.crm",
|
|
9
|
+
"nav.lead-gen",
|
|
10
|
+
"nav.projects",
|
|
11
|
+
"nav.operations",
|
|
12
|
+
"nav.monitoring",
|
|
13
|
+
"nav.knowledge",
|
|
14
|
+
"nav.settings",
|
|
15
|
+
"nav.admin",
|
|
16
|
+
"nav.archive",
|
|
17
|
+
"knowledge.playbook",
|
|
18
|
+
"knowledge.strategy",
|
|
19
|
+
"knowledge.reference",
|
|
20
|
+
"feature.dashboard",
|
|
21
|
+
"feature.calendar",
|
|
22
|
+
"feature.business",
|
|
23
|
+
"feature.sales",
|
|
24
|
+
"feature.crm",
|
|
25
|
+
"feature.finance",
|
|
26
|
+
"feature.lead-gen",
|
|
27
|
+
"feature.platform",
|
|
28
|
+
"feature.projects",
|
|
29
|
+
"feature.operations",
|
|
30
|
+
"feature.knowledge",
|
|
31
|
+
"feature.monitoring",
|
|
32
|
+
"feature.settings",
|
|
33
|
+
"feature.admin",
|
|
34
|
+
"feature.archive",
|
|
35
|
+
"feature.seo",
|
|
36
|
+
"resource.agent",
|
|
37
|
+
"resource.workflow",
|
|
38
|
+
"resource.integration",
|
|
39
|
+
"resource.database",
|
|
40
|
+
"resource.user",
|
|
41
|
+
"resource.team",
|
|
42
|
+
"integration.gmail",
|
|
43
|
+
"integration.google-sheets",
|
|
44
|
+
"integration.attio",
|
|
45
|
+
"surface.dashboard",
|
|
46
|
+
"surface.calendar",
|
|
47
|
+
"surface.overview",
|
|
48
|
+
"surface.command-view",
|
|
49
|
+
"surface.command-queue",
|
|
50
|
+
"surface.pipeline",
|
|
51
|
+
"surface.lists",
|
|
52
|
+
"surface.resources",
|
|
53
|
+
"surface.settings",
|
|
54
|
+
"status.success",
|
|
55
|
+
"status.error",
|
|
56
|
+
"status.warning",
|
|
57
|
+
"status.info",
|
|
58
|
+
"status.pending",
|
|
59
|
+
"action.approve",
|
|
60
|
+
"action.reject",
|
|
61
|
+
"action.retry",
|
|
62
|
+
"action.edit",
|
|
63
|
+
"action.view",
|
|
64
|
+
"action.launch",
|
|
65
|
+
"action.message",
|
|
66
|
+
"action.escalate",
|
|
67
|
+
"action.promote",
|
|
68
|
+
"action.submit",
|
|
69
|
+
"action.email"
|
|
70
|
+
];
|
|
71
|
+
var CustomIconTokenSchema = z.string().trim().max(80).regex(/^custom\.[a-z0-9]+(?:[-._][a-z0-9]+)*$/, "Custom icon tokens must start with custom.");
|
|
72
|
+
var OrganizationModelBuiltinIconTokenSchema = z.enum(ORGANIZATION_MODEL_ICON_TOKENS);
|
|
73
|
+
var OrganizationModelIconTokenSchema = z.union([
|
|
74
|
+
OrganizationModelBuiltinIconTokenSchema,
|
|
75
|
+
CustomIconTokenSchema
|
|
76
|
+
]);
|
|
77
|
+
|
|
78
|
+
// ../core/src/organization-model/domains/shared.ts
|
|
79
|
+
var ModelIdSchema = z.string().trim().min(1).max(100).regex(/^[a-z0-9]+(?:[-._][a-z0-9]+)*$/, "IDs must be lowercase and use -, _, or . separators");
|
|
80
|
+
var LabelSchema = z.string().trim().min(1).max(120);
|
|
81
|
+
var DescriptionSchema = z.string().trim().min(1).max(2e3);
|
|
82
|
+
var ColorTokenSchema = z.string().trim().min(1).max(50);
|
|
83
|
+
var IconNameSchema = OrganizationModelIconTokenSchema;
|
|
84
|
+
var PathSchema = z.string().trim().startsWith("/").max(300);
|
|
85
|
+
var ReferenceIdsSchema = z.array(ModelIdSchema).default([]);
|
|
86
|
+
var DisplayMetadataSchema = z.object({
|
|
87
|
+
label: LabelSchema,
|
|
88
|
+
description: DescriptionSchema.optional(),
|
|
89
|
+
color: ColorTokenSchema.optional(),
|
|
90
|
+
icon: IconNameSchema.optional()
|
|
91
|
+
});
|
|
92
|
+
var TechStackEntrySchema = z.object({
|
|
93
|
+
/** Name of the external platform (e.g. "HubSpot", "Stripe", "Notion"). */
|
|
94
|
+
platform: z.string().trim().min(1).max(200),
|
|
95
|
+
/** Free-form description of what this integration is used for. */
|
|
96
|
+
purpose: z.string().trim().min(1).max(500),
|
|
97
|
+
/**
|
|
98
|
+
* Health of the credential backing this integration.
|
|
99
|
+
* - configured: credential present and valid
|
|
100
|
+
* - pending: not yet set up
|
|
101
|
+
* - expired: credential existed but has lapsed
|
|
102
|
+
* - missing: expected but not present
|
|
103
|
+
*/
|
|
104
|
+
credentialStatus: z.enum(["configured", "pending", "expired", "missing"]),
|
|
105
|
+
/**
|
|
106
|
+
* Whether this integration is the primary system of record for its domain
|
|
107
|
+
* (e.g. HubSpot is SoR for contacts). Defaults to false.
|
|
108
|
+
*/
|
|
109
|
+
isSystemOfRecord: z.boolean().default(false)
|
|
110
|
+
});
|
|
111
|
+
DisplayMetadataSchema.extend({
|
|
112
|
+
id: ModelIdSchema,
|
|
113
|
+
resourceId: z.string().trim().min(1).max(255),
|
|
114
|
+
resourceType: z.enum(["workflow", "agent", "trigger", "integration", "external", "human_checkpoint"]),
|
|
115
|
+
systemIds: ReferenceIdsSchema,
|
|
116
|
+
entityIds: ReferenceIdsSchema,
|
|
117
|
+
surfaceIds: ReferenceIdsSchema,
|
|
118
|
+
actionIds: ReferenceIdsSchema,
|
|
119
|
+
/** Optional tech-stack metadata for external-SaaS integrations. */
|
|
120
|
+
techStack: TechStackEntrySchema.optional()
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
// ../core/src/organization-model/domains/entities.ts
|
|
124
|
+
var EntityIdSchema = ModelIdSchema;
|
|
125
|
+
var EntityLinkKindSchema = z.enum(["belongs-to", "has-many", "has-one", "many-to-many"]).meta({ label: "Link kind" });
|
|
126
|
+
var EntityLinkSchema = z.object({
|
|
127
|
+
toEntity: EntityIdSchema.meta({ ref: "entity" }),
|
|
128
|
+
kind: EntityLinkKindSchema,
|
|
129
|
+
via: z.string().trim().min(1).max(255).optional(),
|
|
130
|
+
label: LabelSchema.optional()
|
|
131
|
+
});
|
|
132
|
+
var EntitySchema = z.object({
|
|
133
|
+
id: EntityIdSchema,
|
|
134
|
+
/** Domain-map iteration order. Convention: multiples of 10 (10, 20, 30, ...) to allow easy insertion. */
|
|
135
|
+
order: z.number(),
|
|
136
|
+
label: LabelSchema,
|
|
137
|
+
description: DescriptionSchema.optional(),
|
|
138
|
+
ownedBySystemId: ModelIdSchema.meta({ ref: "system" }),
|
|
139
|
+
table: z.string().trim().min(1).max(255).optional(),
|
|
140
|
+
rowSchema: ModelIdSchema.optional(),
|
|
141
|
+
stateCatalogId: ModelIdSchema.optional(),
|
|
142
|
+
links: z.array(EntityLinkSchema).optional()
|
|
143
|
+
});
|
|
144
|
+
var EntitiesDomainSchema = z.record(z.string(), EntitySchema).refine((record) => Object.entries(record).every(([key, entry]) => entry.id === key), {
|
|
145
|
+
message: "Each entity entry id must match its map key"
|
|
146
|
+
}).default({});
|
|
147
|
+
var ENTITY_ENTRY_INPUTS = [
|
|
148
|
+
{
|
|
149
|
+
id: "crm.deal",
|
|
150
|
+
order: 10,
|
|
151
|
+
label: "Deal",
|
|
152
|
+
description: "A CRM opportunity or sales pipeline record.",
|
|
153
|
+
ownedBySystemId: "sales.crm",
|
|
154
|
+
table: "crm_deals",
|
|
155
|
+
stateCatalogId: "crm.pipeline",
|
|
156
|
+
links: [{ toEntity: "crm.contact", kind: "has-many", via: "deal_contacts", label: "contacts" }]
|
|
157
|
+
},
|
|
158
|
+
{
|
|
159
|
+
id: "crm.contact",
|
|
160
|
+
order: 20,
|
|
161
|
+
label: "CRM Contact",
|
|
162
|
+
description: "A person associated with a CRM relationship or deal.",
|
|
163
|
+
ownedBySystemId: "sales.crm",
|
|
164
|
+
table: "crm_contacts"
|
|
165
|
+
},
|
|
166
|
+
{
|
|
167
|
+
id: "leadgen.list",
|
|
168
|
+
order: 30,
|
|
169
|
+
label: "Lead List",
|
|
170
|
+
description: "A prospecting list that groups companies and contacts for acquisition workflows.",
|
|
171
|
+
ownedBySystemId: "sales.lead-gen",
|
|
172
|
+
table: "acq_lists",
|
|
173
|
+
links: [
|
|
174
|
+
{ toEntity: "leadgen.company", kind: "has-many", via: "acq_list_companies", label: "companies" },
|
|
175
|
+
{ toEntity: "leadgen.contact", kind: "has-many", via: "acq_list_members", label: "contacts" }
|
|
176
|
+
]
|
|
177
|
+
},
|
|
178
|
+
{
|
|
179
|
+
id: "leadgen.company",
|
|
180
|
+
order: 40,
|
|
181
|
+
label: "Lead Company",
|
|
182
|
+
description: "A company record sourced, enriched, and qualified during prospecting.",
|
|
183
|
+
ownedBySystemId: "sales.lead-gen",
|
|
184
|
+
table: "acq_list_companies",
|
|
185
|
+
stateCatalogId: "lead-gen.company",
|
|
186
|
+
links: [
|
|
187
|
+
{ toEntity: "leadgen.list", kind: "belongs-to", via: "list_id", label: "list" },
|
|
188
|
+
{ toEntity: "leadgen.contact", kind: "has-many", via: "company_id", label: "contacts" }
|
|
189
|
+
]
|
|
190
|
+
},
|
|
191
|
+
{
|
|
192
|
+
id: "leadgen.contact",
|
|
193
|
+
order: 50,
|
|
194
|
+
label: "Lead Contact",
|
|
195
|
+
description: "A prospect contact discovered or enriched during lead generation.",
|
|
196
|
+
ownedBySystemId: "sales.lead-gen",
|
|
197
|
+
table: "acq_list_members",
|
|
198
|
+
stateCatalogId: "lead-gen.contact",
|
|
199
|
+
links: [
|
|
200
|
+
{ toEntity: "leadgen.list", kind: "belongs-to", via: "list_id", label: "list" },
|
|
201
|
+
{ toEntity: "leadgen.company", kind: "belongs-to", via: "company_id", label: "company" }
|
|
202
|
+
]
|
|
203
|
+
},
|
|
204
|
+
{
|
|
205
|
+
id: "delivery.project",
|
|
206
|
+
order: 60,
|
|
207
|
+
label: "Project",
|
|
208
|
+
description: "A client delivery project.",
|
|
209
|
+
ownedBySystemId: "projects",
|
|
210
|
+
table: "projects",
|
|
211
|
+
links: [
|
|
212
|
+
{ toEntity: "delivery.milestone", kind: "has-many", via: "project_id", label: "milestones" },
|
|
213
|
+
{ toEntity: "delivery.task", kind: "has-many", via: "project_id", label: "tasks" }
|
|
214
|
+
]
|
|
215
|
+
},
|
|
216
|
+
{
|
|
217
|
+
id: "delivery.milestone",
|
|
218
|
+
order: 70,
|
|
219
|
+
label: "Milestone",
|
|
220
|
+
description: "A delivery checkpoint within a project.",
|
|
221
|
+
ownedBySystemId: "projects",
|
|
222
|
+
table: "project_milestones",
|
|
223
|
+
links: [
|
|
224
|
+
{ toEntity: "delivery.project", kind: "belongs-to", via: "project_id", label: "project" },
|
|
225
|
+
{ toEntity: "delivery.task", kind: "has-many", via: "milestone_id", label: "tasks" }
|
|
226
|
+
]
|
|
227
|
+
},
|
|
228
|
+
{
|
|
229
|
+
id: "delivery.task",
|
|
230
|
+
order: 80,
|
|
231
|
+
label: "Task",
|
|
232
|
+
description: "A delivery task that can move through the task status catalog.",
|
|
233
|
+
ownedBySystemId: "projects",
|
|
234
|
+
table: "project_tasks",
|
|
235
|
+
stateCatalogId: "delivery.task",
|
|
236
|
+
links: [
|
|
237
|
+
{ toEntity: "delivery.project", kind: "belongs-to", via: "project_id", label: "project" },
|
|
238
|
+
{ toEntity: "delivery.milestone", kind: "belongs-to", via: "milestone_id", label: "milestone" }
|
|
239
|
+
]
|
|
240
|
+
}
|
|
241
|
+
];
|
|
242
|
+
var DEFAULT_ORGANIZATION_MODEL_ENTITIES = Object.fromEntries(
|
|
243
|
+
ENTITY_ENTRY_INPUTS.map((entity) => {
|
|
244
|
+
const parsed = EntitySchema.parse(entity);
|
|
245
|
+
return [parsed.id, parsed];
|
|
246
|
+
})
|
|
247
|
+
);
|
|
248
|
+
|
|
249
|
+
// ../core/src/organization-model/domains/actions.ts
|
|
250
|
+
var ActionResourceIdSchema = z.string().trim().min(1).max(255).regex(/^[A-Za-z0-9]+(?:[-._][A-Za-z0-9]+)*$/, "Resource IDs must use letters, numbers, -, _, or . separators");
|
|
251
|
+
z.enum(["slash-command", "mcp-tool", "api-endpoint", "script-execution"]).meta({ label: "Invocation kind" });
|
|
252
|
+
var ActionIdSchema = ModelIdSchema;
|
|
253
|
+
var ActionScopeSchema = z.union([
|
|
254
|
+
z.literal("global"),
|
|
255
|
+
z.object({
|
|
256
|
+
domain: ModelIdSchema
|
|
257
|
+
})
|
|
258
|
+
]);
|
|
259
|
+
var ActionRefSchema = z.object({
|
|
260
|
+
actionId: ActionIdSchema.meta({ ref: "action" }),
|
|
261
|
+
intent: z.enum(["exposes", "consumes"]).meta({ label: "Intent" })
|
|
262
|
+
});
|
|
263
|
+
var SlashCommandInvocationSchema = z.object({
|
|
264
|
+
kind: z.literal("slash-command"),
|
|
265
|
+
command: z.string().trim().min(1).max(200).regex(/^\/[^\s].*$/, "Slash commands must start with /"),
|
|
266
|
+
toolFactory: ModelIdSchema.optional()
|
|
267
|
+
});
|
|
268
|
+
var McpToolInvocationSchema = z.object({
|
|
269
|
+
kind: z.literal("mcp-tool"),
|
|
270
|
+
server: ModelIdSchema,
|
|
271
|
+
name: ModelIdSchema
|
|
272
|
+
});
|
|
273
|
+
var ApiEndpointInvocationSchema = z.object({
|
|
274
|
+
kind: z.literal("api-endpoint"),
|
|
275
|
+
method: z.enum(["GET", "POST", "PATCH", "DELETE"]).meta({ label: "HTTP method" }),
|
|
276
|
+
path: z.string().trim().startsWith("/").max(500),
|
|
277
|
+
requestSchema: ModelIdSchema.optional(),
|
|
278
|
+
responseSchema: ModelIdSchema.optional()
|
|
279
|
+
});
|
|
280
|
+
var ScriptExecutionInvocationSchema = z.object({
|
|
281
|
+
kind: z.literal("script-execution"),
|
|
282
|
+
resourceId: ActionResourceIdSchema
|
|
283
|
+
});
|
|
284
|
+
var ActionInvocationSchema = z.discriminatedUnion("kind", [
|
|
285
|
+
SlashCommandInvocationSchema,
|
|
286
|
+
McpToolInvocationSchema,
|
|
287
|
+
ApiEndpointInvocationSchema,
|
|
288
|
+
ScriptExecutionInvocationSchema
|
|
289
|
+
]);
|
|
290
|
+
var ActionSchema = z.object({
|
|
291
|
+
id: ActionIdSchema,
|
|
292
|
+
/** Domain-map iteration order. Convention: multiples of 10 (10, 20, 30, ...) to allow easy insertion. */
|
|
293
|
+
order: z.number(),
|
|
294
|
+
label: LabelSchema,
|
|
295
|
+
description: DescriptionSchema.optional(),
|
|
296
|
+
scope: ActionScopeSchema.default("global"),
|
|
297
|
+
resourceId: ActionResourceIdSchema.optional(),
|
|
298
|
+
affects: z.array(EntityIdSchema.meta({ ref: "entity" })).optional(),
|
|
299
|
+
invocations: z.array(ActionInvocationSchema).default([]),
|
|
300
|
+
knowledge: z.array(ModelIdSchema.meta({ ref: "knowledge" })).default([]).optional(),
|
|
301
|
+
lifecycle: z.enum(["draft", "beta", "active", "deprecated", "archived"]).meta({ label: "Lifecycle", color: "teal" }).default("active")
|
|
302
|
+
});
|
|
303
|
+
var ActionsDomainSchema = z.record(z.string(), ActionSchema).refine((record) => Object.entries(record).every(([key, entry]) => entry.id === key), {
|
|
304
|
+
message: "Each action entry id must match its map key"
|
|
305
|
+
}).default({});
|
|
306
|
+
var LEAD_GEN_ACTION_ENTRY_INPUTS = [
|
|
307
|
+
{
|
|
308
|
+
id: "lead-gen.company.source",
|
|
309
|
+
order: 10,
|
|
310
|
+
label: "Source companies",
|
|
311
|
+
description: "Import source companies from a list provider.",
|
|
312
|
+
scope: { domain: "sales" },
|
|
313
|
+
resourceId: "lgn-import-workflow",
|
|
314
|
+
invocations: [{ kind: "api-endpoint", method: "POST", path: "/api/prospecting/companies/source" }]
|
|
315
|
+
},
|
|
316
|
+
{
|
|
317
|
+
id: "lead-gen.company.apollo-import",
|
|
318
|
+
order: 20,
|
|
319
|
+
label: "Import from Apollo",
|
|
320
|
+
description: "Pull companies and seed contact data from an Apollo search or list.",
|
|
321
|
+
scope: { domain: "sales" },
|
|
322
|
+
resourceId: "lgn-01c-apollo-import-workflow",
|
|
323
|
+
invocations: [{ kind: "api-endpoint", method: "POST", path: "/api/prospecting/companies/apollo-import" }]
|
|
324
|
+
},
|
|
325
|
+
{
|
|
326
|
+
id: "lead-gen.contact.discover",
|
|
327
|
+
order: 30,
|
|
328
|
+
label: "Discover contact emails",
|
|
329
|
+
description: "Find email addresses for contacts at qualified companies.",
|
|
330
|
+
scope: { domain: "sales" },
|
|
331
|
+
resourceId: "lgn-04-email-discovery-workflow",
|
|
332
|
+
invocations: [{ kind: "api-endpoint", method: "POST", path: "/api/prospecting/contacts/discover" }]
|
|
333
|
+
},
|
|
334
|
+
{
|
|
335
|
+
id: "lead-gen.contact.verify-email",
|
|
336
|
+
order: 40,
|
|
337
|
+
label: "Verify emails",
|
|
338
|
+
description: "Check email deliverability before outreach.",
|
|
339
|
+
scope: { domain: "sales" },
|
|
340
|
+
resourceId: "lgn-05-email-verification-workflow",
|
|
341
|
+
invocations: [{ kind: "api-endpoint", method: "POST", path: "/api/prospecting/contacts/verify-email" }]
|
|
342
|
+
},
|
|
343
|
+
{
|
|
344
|
+
id: "lead-gen.company.apify-crawl",
|
|
345
|
+
order: 50,
|
|
346
|
+
label: "Crawl websites",
|
|
347
|
+
description: "Crawl company websites via Apify and store raw page markdown in enrichmentData.websiteCrawl.pages for downstream LLM analysis.",
|
|
348
|
+
scope: { domain: "sales" },
|
|
349
|
+
resourceId: "lgn-02a-apify-website-crawl-workflow",
|
|
350
|
+
invocations: [{ kind: "api-endpoint", method: "POST", path: "/api/prospecting/companies/apify-crawl" }]
|
|
351
|
+
},
|
|
352
|
+
{
|
|
353
|
+
id: "lead-gen.company.website-extract",
|
|
354
|
+
order: 60,
|
|
355
|
+
label: "Extract website signals",
|
|
356
|
+
description: "Scrape and analyze company websites for qualification signals.",
|
|
357
|
+
scope: { domain: "sales" },
|
|
358
|
+
resourceId: "lgn-02-website-extract-workflow",
|
|
359
|
+
invocations: [{ kind: "api-endpoint", method: "POST", path: "/api/prospecting/companies/website-extract" }]
|
|
360
|
+
},
|
|
361
|
+
{
|
|
362
|
+
id: "lead-gen.company.qualify",
|
|
363
|
+
order: 70,
|
|
364
|
+
label: "Qualify companies",
|
|
365
|
+
description: "Score and filter companies against the ICP rubric.",
|
|
366
|
+
scope: { domain: "sales" },
|
|
367
|
+
resourceId: "lgn-03-company-qualification-workflow",
|
|
368
|
+
invocations: [{ kind: "api-endpoint", method: "POST", path: "/api/prospecting/companies/qualify" }]
|
|
369
|
+
},
|
|
370
|
+
{
|
|
371
|
+
id: "lead-gen.company.dtc-subscription-qualify",
|
|
372
|
+
order: 80,
|
|
373
|
+
label: "Qualify DTC subscription fit",
|
|
374
|
+
description: "Classify subscription potential and consumable-product fit for DTC brands.",
|
|
375
|
+
scope: { domain: "sales" },
|
|
376
|
+
resourceId: "lgn-03b-dtc-subscription-score-workflow",
|
|
377
|
+
invocations: [{ kind: "api-endpoint", method: "POST", path: "/api/prospecting/companies/dtc-subscription-qualify" }]
|
|
378
|
+
},
|
|
379
|
+
{
|
|
380
|
+
id: "lead-gen.contact.apollo-decision-maker-enrich",
|
|
381
|
+
order: 90,
|
|
382
|
+
label: "Enrich decision-makers",
|
|
383
|
+
description: "Find and enrich qualified contacts at qualified companies via Apollo.",
|
|
384
|
+
scope: { domain: "sales" },
|
|
385
|
+
resourceId: "lgn-04b-apollo-decision-maker-enrich-workflow",
|
|
386
|
+
invocations: [
|
|
387
|
+
{ kind: "api-endpoint", method: "POST", path: "/api/prospecting/contacts/apollo-decision-maker-enrich" }
|
|
388
|
+
]
|
|
389
|
+
},
|
|
390
|
+
{
|
|
391
|
+
id: "lead-gen.contact.personalize",
|
|
392
|
+
order: 100,
|
|
393
|
+
label: "Personalize outreach",
|
|
394
|
+
description: "Generate personalized opening lines for each contact.",
|
|
395
|
+
scope: { domain: "sales" },
|
|
396
|
+
resourceId: "ist-personalization-workflow",
|
|
397
|
+
invocations: [{ kind: "api-endpoint", method: "POST", path: "/api/prospecting/contacts/personalize" }]
|
|
398
|
+
},
|
|
399
|
+
{
|
|
400
|
+
id: "lead-gen.review.outreach-ready",
|
|
401
|
+
order: 110,
|
|
402
|
+
label: "Upload to outreach",
|
|
403
|
+
description: "Upload approved contacts to the outreach sequence after QC review.",
|
|
404
|
+
scope: { domain: "sales" },
|
|
405
|
+
resourceId: "ist-upload-contacts-workflow",
|
|
406
|
+
invocations: [{ kind: "api-endpoint", method: "POST", path: "/api/prospecting/review/outreach-ready" }]
|
|
407
|
+
},
|
|
408
|
+
{
|
|
409
|
+
id: "lead-gen.export.list",
|
|
410
|
+
order: 120,
|
|
411
|
+
label: "Export lead list",
|
|
412
|
+
description: "Export approved leads as a downloadable lead list.",
|
|
413
|
+
scope: { domain: "sales" },
|
|
414
|
+
resourceId: "lgn-06-export-list-workflow",
|
|
415
|
+
invocations: [{ kind: "api-endpoint", method: "POST", path: "/api/prospecting/export/list" }]
|
|
416
|
+
},
|
|
417
|
+
{
|
|
418
|
+
id: "lead-gen.company.cleanup",
|
|
419
|
+
order: 130,
|
|
420
|
+
label: "Clean up companies",
|
|
421
|
+
description: "Remove disqualified or duplicate companies from the list.",
|
|
422
|
+
scope: { domain: "sales" },
|
|
423
|
+
resourceId: "lgn-company-cleanup-workflow",
|
|
424
|
+
invocations: [{ kind: "api-endpoint", method: "POST", path: "/api/prospecting/companies/cleanup" }]
|
|
425
|
+
}
|
|
426
|
+
];
|
|
427
|
+
var LEAD_GEN_ACTION_ENTRIES = Object.fromEntries(
|
|
428
|
+
LEAD_GEN_ACTION_ENTRY_INPUTS.map((action) => {
|
|
429
|
+
const parsed = ActionSchema.parse(action);
|
|
430
|
+
return [parsed.id, parsed];
|
|
431
|
+
})
|
|
432
|
+
);
|
|
433
|
+
var DEFAULT_ORGANIZATION_MODEL_ACTIONS = LEAD_GEN_ACTION_ENTRIES;
|
|
434
|
+
var ContentNodeBaseSchema = z.object({
|
|
435
|
+
/** Human-readable label for the content node. */
|
|
436
|
+
label: z.string().trim().min(1).max(120).meta({ label: "Label" }),
|
|
437
|
+
/** Optional one-paragraph description. */
|
|
438
|
+
description: z.string().trim().min(1).max(2e3).optional().meta({ label: "Description" }),
|
|
439
|
+
/** Optional display order within the system content map. */
|
|
440
|
+
order: z.number().int().optional().meta({ label: "Order" }),
|
|
441
|
+
/**
|
|
442
|
+
* Local NodeId of the parent content node within the SAME system.
|
|
443
|
+
* Per B4/L9: MUST resolve to a sibling in the same `system.content` map.
|
|
444
|
+
* Per L19: parent and child MUST share the same `kind` (meta-category).
|
|
445
|
+
*/
|
|
446
|
+
parentContentId: z.string().trim().min(1).max(200).optional().meta({ label: "Parent content id" })
|
|
447
|
+
});
|
|
448
|
+
var ContentNodeSchema = ContentNodeBaseSchema.extend({
|
|
449
|
+
/** Meta-category (e.g. 'schema', 'config', 'knowledge', tenant-defined). */
|
|
450
|
+
kind: z.string().trim().min(1).max(100).meta({ label: "Kind" }),
|
|
451
|
+
/** Specific family within the meta-category (e.g. 'pipeline', 'kv'). */
|
|
452
|
+
type: z.string().trim().min(1).max(100).meta({ label: "Type" }),
|
|
453
|
+
/** Payload data; validated against registered payloadSchema when (kind, type) is known. */
|
|
454
|
+
data: z.record(z.string(), z.unknown()).optional().meta({ label: "Data" })
|
|
455
|
+
});
|
|
456
|
+
z.object({
|
|
457
|
+
/** Meta-category (tenant-defined or registry-shipped). */
|
|
458
|
+
kind: z.string().trim().min(1).max(100).meta({ label: "Kind" }),
|
|
459
|
+
/** Specific family within the meta-category. */
|
|
460
|
+
type: z.string().trim().min(1).max(100).meta({ label: "Type" }),
|
|
461
|
+
/** Human-readable label shown in the KB tree and describe views. */
|
|
462
|
+
label: z.string().trim().min(1).max(120).meta({ label: "Label" }),
|
|
463
|
+
/** Optional description. */
|
|
464
|
+
description: z.string().trim().min(1).max(2e3).optional().meta({ label: "Description" }),
|
|
465
|
+
/**
|
|
466
|
+
* Which KB tree group this extension renders in.
|
|
467
|
+
* Per L6: 'business-model' places it alongside Customers / Offerings / Goals.
|
|
468
|
+
*/
|
|
469
|
+
treeGroup: z.union([z.enum(["profile", "business-model", "systems", "graph", "governance-wiring"]), z.string().min(1).max(100)]).meta({ label: "Tree group" }),
|
|
470
|
+
/** Untyped payload; shape governed by the registered payloadSchema when available. */
|
|
471
|
+
data: z.record(z.string(), z.unknown()).optional().meta({ label: "Data" })
|
|
472
|
+
});
|
|
473
|
+
|
|
474
|
+
// ../core/src/organization-model/domains/systems.ts
|
|
475
|
+
var SystemKindSchema = z.enum(["product", "operational", "platform", "diagnostic"]).meta({ label: "System kind", color: "blue" });
|
|
476
|
+
var SystemLifecycleSchema = z.enum(["draft", "beta", "active", "deprecated", "archived"]).meta({ label: "Lifecycle", color: "teal" });
|
|
477
|
+
var SystemStatusSchema = z.enum(["active", "deprecated", "archived"]).meta({ label: "Status", color: "teal" });
|
|
478
|
+
var SystemIdSchema = ModelIdSchema;
|
|
479
|
+
var SystemPathSchema = z.string().trim().min(1).regex(
|
|
480
|
+
/^[a-z0-9][a-z0-9-]*(?:\.[a-z0-9][a-z0-9-]*)*$/,
|
|
481
|
+
'must be a dotted lowercase path (e.g. "sales.lead-gen" or "sales.crm")'
|
|
482
|
+
);
|
|
483
|
+
var UiPositionSchema = z.enum(["sidebar-primary", "sidebar-bottom"]).meta({ label: "UI position" });
|
|
484
|
+
var NodeIdStringSchema = z.string().trim().min(1).max(200).regex(
|
|
485
|
+
/^[a-z][a-z-]*:([a-z0-9-]+)(\.[a-z0-9-]+)*(:[a-z0-9.-]+)*$/,
|
|
486
|
+
"Node references must use kind:dotted-path (e.g. system:sales.crm or content-node:sales.crm:pipeline-id)"
|
|
487
|
+
);
|
|
488
|
+
var SystemUiSchema = z.object({
|
|
489
|
+
path: PathSchema,
|
|
490
|
+
surfaces: ReferenceIdsSchema,
|
|
491
|
+
icon: IconNameSchema.optional(),
|
|
492
|
+
order: z.number().int().optional()
|
|
493
|
+
});
|
|
494
|
+
var SystemEntrySchema = z.object({
|
|
495
|
+
/** Stable tenant-defined system id (e.g. "sys.lead-gen" or "sales.crm"). */
|
|
496
|
+
id: SystemIdSchema,
|
|
497
|
+
/** Human-readable system label shown in UI, governance, and operations surfaces. */
|
|
498
|
+
label: LabelSchema.optional(),
|
|
499
|
+
/** @deprecated Use label. Accepted for pre-consolidation System declarations. */
|
|
500
|
+
title: LabelSchema.optional(),
|
|
501
|
+
/** One-paragraph purpose statement for the bounded context. */
|
|
502
|
+
description: DescriptionSchema.optional(),
|
|
503
|
+
/** Closed system shape enum; catalog values remain tenant-defined. */
|
|
504
|
+
kind: SystemKindSchema.optional(),
|
|
505
|
+
/** Optional self-reference for System hierarchy. */
|
|
506
|
+
parentSystemId: SystemIdSchema.optional(),
|
|
507
|
+
/** Optional UI presence. Systems without UI omit this. */
|
|
508
|
+
ui: SystemUiSchema.optional(),
|
|
509
|
+
/** Canonical lifecycle state. Replaces Feature.enabled/devOnly and System.status. */
|
|
510
|
+
lifecycle: SystemLifecycleSchema.optional(),
|
|
511
|
+
/** Optional role responsible for this system. */
|
|
512
|
+
responsibleRoleId: ModelIdSchema.meta({ ref: "role" }).optional(),
|
|
513
|
+
/** Optional knowledge nodes that govern this system. */
|
|
514
|
+
governedByKnowledge: z.array(ModelIdSchema.meta({ ref: "knowledge" })).default([]).optional(),
|
|
515
|
+
/** Optional actions this system exposes or consumes. */
|
|
516
|
+
actions: z.array(ActionRefSchema).optional(),
|
|
517
|
+
/** Optional operational policies that apply to this system. */
|
|
518
|
+
policies: z.array(ModelIdSchema.meta({ ref: "policy" })).default([]).optional(),
|
|
519
|
+
/** Optional goals this system contributes to. */
|
|
520
|
+
drivesGoals: z.array(ModelIdSchema.meta({ ref: "goal" })).default([]).optional(),
|
|
521
|
+
/** @deprecated Use lifecycle. Accepted for one publish cycle. */
|
|
522
|
+
status: SystemStatusSchema.optional(),
|
|
523
|
+
/** @deprecated Use ui.path. Kept for one-cycle Feature compatibility. */
|
|
524
|
+
path: PathSchema.optional(),
|
|
525
|
+
/** @deprecated Use ui.icon. Kept for one-cycle Feature compatibility. */
|
|
526
|
+
icon: IconNameSchema.optional(),
|
|
527
|
+
/** @deprecated Feature color token, retained for one-cycle compatibility. */
|
|
528
|
+
color: ColorTokenSchema.optional(),
|
|
529
|
+
/** @deprecated UI placement hint, retained for one-cycle compatibility. */
|
|
530
|
+
uiPosition: UiPositionSchema.optional(),
|
|
531
|
+
/** @deprecated Use lifecycle. */
|
|
532
|
+
enabled: z.boolean().optional(),
|
|
533
|
+
/** @deprecated Use lifecycle: "beta". */
|
|
534
|
+
devOnly: z.boolean().optional(),
|
|
535
|
+
requiresAdmin: z.boolean().optional(),
|
|
536
|
+
/** Domain-map iteration order. Convention: multiples of 10 (10, 20, 30, ...) to allow easy insertion. */
|
|
537
|
+
order: z.number(),
|
|
538
|
+
/**
|
|
539
|
+
* System-scoped operational data, co-located with the owning system.
|
|
540
|
+
* Per L1, L3, L13: keyed by local NodeId (the key is the local id; qualified
|
|
541
|
+
* id is `<system-path>:<local-id>`, computed by graph projection).
|
|
542
|
+
* Per L14: every ContentNode carries both `kind` and `type`.
|
|
543
|
+
* Per D2: unregistered (kind, type) pairs parse successfully.
|
|
544
|
+
*/
|
|
545
|
+
content: z.record(z.string().trim().min(1).max(200), ContentNodeSchema).optional(),
|
|
546
|
+
/**
|
|
547
|
+
* Recursive child systems, authored via nesting (per L11).
|
|
548
|
+
* The key is the local system id; the full path is computed by joining
|
|
549
|
+
* ancestor keys with `.` (e.g. parent key `'sales'` + child key `'crm'` → `'sales.crm'`).
|
|
550
|
+
* Per Phase 4: `id` and `parentSystemId` fields will be removed in favour of
|
|
551
|
+
* position-derived paths. Both still exist on this schema for backward compat.
|
|
552
|
+
*/
|
|
553
|
+
subsystems: z.lazy(() => z.record(z.string().trim().min(1).max(100), SystemEntrySchema)).optional()
|
|
554
|
+
}).refine((system) => system.label !== void 0 || system.title !== void 0, {
|
|
555
|
+
path: ["label"],
|
|
556
|
+
message: "System must provide label or title"
|
|
557
|
+
}).transform((system) => {
|
|
558
|
+
if (system.status === void 0) return system;
|
|
559
|
+
console.warn("[organization-model] System.status is deprecated; use System.lifecycle instead.");
|
|
560
|
+
return system.lifecycle === void 0 ? { ...system, lifecycle: system.status } : system;
|
|
561
|
+
});
|
|
562
|
+
var SystemsDomainSchema = z.record(z.string(), SystemEntrySchema).refine((record) => Object.entries(record).every(([key, entry]) => entry.id === key), {
|
|
563
|
+
message: "Each system entry id must match its map key"
|
|
564
|
+
}).default({});
|
|
565
|
+
var DEFAULT_ORGANIZATION_MODEL_SYSTEMS = {};
|
|
566
|
+
var BusinessHoursDaySchema = z.object({
|
|
567
|
+
open: z.string().trim().regex(/^\d{2}:\d{2}$/, "Expected HH:MM format"),
|
|
568
|
+
close: z.string().trim().regex(/^\d{2}:\d{2}$/, "Expected HH:MM format")
|
|
569
|
+
});
|
|
570
|
+
var BusinessHoursSchema = z.object({
|
|
571
|
+
monday: BusinessHoursDaySchema.optional(),
|
|
572
|
+
tuesday: BusinessHoursDaySchema.optional(),
|
|
573
|
+
wednesday: BusinessHoursDaySchema.optional(),
|
|
574
|
+
thursday: BusinessHoursDaySchema.optional(),
|
|
575
|
+
friday: BusinessHoursDaySchema.optional(),
|
|
576
|
+
saturday: BusinessHoursDaySchema.optional(),
|
|
577
|
+
sunday: BusinessHoursDaySchema.optional()
|
|
578
|
+
}).default({});
|
|
579
|
+
var IdentityDomainSchema = z.object({
|
|
580
|
+
/** Why the organization exists — one or two plain-language sentences. */
|
|
581
|
+
mission: z.string().trim().max(1e3).default(""),
|
|
582
|
+
/** Long-term direction the organization is moving toward. */
|
|
583
|
+
vision: z.string().trim().max(1e3).default(""),
|
|
584
|
+
/** Legal registered name of the entity. */
|
|
585
|
+
legalName: z.string().trim().max(200).default(""),
|
|
586
|
+
/**
|
|
587
|
+
* Type of legal entity (e.g. "LLC", "Corporation", "Sole Proprietor",
|
|
588
|
+
* "Non-profit"). Free-form string so it covers any jurisdiction.
|
|
589
|
+
*/
|
|
590
|
+
entityType: z.string().trim().max(100).default(""),
|
|
591
|
+
/**
|
|
592
|
+
* Primary jurisdiction of registration or operation
|
|
593
|
+
* (e.g. "United States – Delaware", "Canada – Ontario").
|
|
594
|
+
*/
|
|
595
|
+
jurisdiction: z.string().trim().max(200).default(""),
|
|
596
|
+
/**
|
|
597
|
+
* Industry category — broad classification (e.g. "Marketing Agency",
|
|
598
|
+
* "Software / SaaS", "Professional Services").
|
|
599
|
+
*/
|
|
600
|
+
industryCategory: z.string().trim().max(200).default(""),
|
|
601
|
+
/**
|
|
602
|
+
* Geographic focus — where the organization primarily operates or serves
|
|
603
|
+
* (e.g. "North America", "Global", "Southeast Asia").
|
|
604
|
+
*/
|
|
605
|
+
geographicFocus: z.string().trim().max(200).default(""),
|
|
606
|
+
/**
|
|
607
|
+
* IANA timezone identifier for the organization's primary operating timezone
|
|
608
|
+
* (e.g. "America/Los_Angeles", "Europe/London", "UTC").
|
|
609
|
+
*/
|
|
610
|
+
timeZone: z.string().trim().max(100).default("UTC"),
|
|
611
|
+
/** Typical operating hours per day of week. Empty object means not configured. */
|
|
612
|
+
businessHours: BusinessHoursSchema,
|
|
613
|
+
/**
|
|
614
|
+
* Long-form markdown capturing client context, problem narrative, and domain
|
|
615
|
+
* background. Populated by /setup; surfaced to agents as organizational context.
|
|
616
|
+
* Optional — many projects have no external client.
|
|
617
|
+
*/
|
|
618
|
+
clientBrief: z.string().trim().default("")
|
|
619
|
+
});
|
|
620
|
+
var DEFAULT_ORGANIZATION_MODEL_IDENTITY = {
|
|
621
|
+
mission: "",
|
|
622
|
+
vision: "",
|
|
623
|
+
legalName: "",
|
|
624
|
+
entityType: "",
|
|
625
|
+
jurisdiction: "",
|
|
626
|
+
industryCategory: "",
|
|
627
|
+
geographicFocus: "",
|
|
628
|
+
timeZone: "UTC",
|
|
629
|
+
businessHours: {},
|
|
630
|
+
clientBrief: ""
|
|
631
|
+
};
|
|
632
|
+
z.enum(["workflow", "agent", "integration", "script"]).meta({ label: "Resource kind", color: "orange" });
|
|
633
|
+
var ResourceGovernanceStatusSchema = z.enum(["active", "deprecated", "archived"]).meta({ label: "Governance status", color: "teal" });
|
|
634
|
+
var AgentKindSchema = z.enum(["orchestrator", "specialist", "utility", "platform"]).meta({ label: "Agent kind", color: "violet" });
|
|
635
|
+
var ScriptResourceLanguageSchema = z.enum(["shell", "sql", "typescript", "python"]).meta({ label: "Language" });
|
|
636
|
+
var ResourceIdSchema = z.string().trim().min(1).max(255).regex(/^[A-Za-z0-9]+(?:[-._][A-Za-z0-9]+)*$/, "Resource IDs must use letters, numbers, -, _, or . separators");
|
|
637
|
+
var EventIdSchema = z.string().trim().min(1).max(300).regex(
|
|
638
|
+
/^[A-Za-z0-9]+(?:[-._][A-Za-z0-9]+)*:[a-z0-9]+(?:[-._][a-z0-9]+)*$/,
|
|
639
|
+
"Event IDs must use <owner-id>:<event-key>"
|
|
640
|
+
);
|
|
641
|
+
var EventKeySchema = ModelIdSchema;
|
|
642
|
+
var EventEmissionDescriptorSchema = z.object({
|
|
643
|
+
eventKey: EventKeySchema,
|
|
644
|
+
label: z.string().trim().min(1).max(120),
|
|
645
|
+
payloadSchema: ModelIdSchema.optional(),
|
|
646
|
+
lifecycle: SystemLifecycleSchema.optional()
|
|
647
|
+
});
|
|
648
|
+
EventEmissionDescriptorSchema.extend({
|
|
649
|
+
id: EventIdSchema,
|
|
650
|
+
ownerId: z.union([ResourceIdSchema, ModelIdSchema]),
|
|
651
|
+
ownerKind: z.enum(["resource", "entity"]).meta({ label: "Owner kind" })
|
|
652
|
+
});
|
|
653
|
+
var ResourceEntryBaseSchema = z.object({
|
|
654
|
+
/** Canonical resource id; runtime resourceId derives from this value. */
|
|
655
|
+
id: ResourceIdSchema,
|
|
656
|
+
/** Domain-map iteration order. Convention: multiples of 10 (10, 20, 30, ...) to allow easy insertion. */
|
|
657
|
+
order: z.number().default(0),
|
|
658
|
+
/** Required single System membership — value is a dot-separated system path (e.g. "sales.lead-gen"). */
|
|
659
|
+
systemPath: SystemPathSchema.meta({ ref: "system" }),
|
|
660
|
+
/** Optional role responsible for maintaining this resource. */
|
|
661
|
+
ownerRoleId: ModelIdSchema.meta({ ref: "role" }).optional(),
|
|
662
|
+
status: ResourceGovernanceStatusSchema
|
|
663
|
+
});
|
|
664
|
+
var WorkflowResourceEntrySchema = ResourceEntryBaseSchema.extend({
|
|
665
|
+
kind: z.literal("workflow"),
|
|
666
|
+
/** Mirrors WorkflowConfig.actionKey when the runtime workflow has one. */
|
|
667
|
+
actionKey: z.string().trim().min(1).max(255).optional(),
|
|
668
|
+
emits: z.array(EventEmissionDescriptorSchema).optional()
|
|
669
|
+
});
|
|
670
|
+
var AgentResourceEntrySchema = ResourceEntryBaseSchema.extend({
|
|
671
|
+
kind: z.literal("agent"),
|
|
672
|
+
/** Mirrors code-side AgentConfig.kind. */
|
|
673
|
+
agentKind: AgentKindSchema,
|
|
674
|
+
/** Role this agent embodies, if any. */
|
|
675
|
+
actsAsRoleId: ModelIdSchema.meta({ ref: "role" }).optional(),
|
|
676
|
+
/** Mirrors AgentConfig.sessionCapable. */
|
|
677
|
+
sessionCapable: z.boolean(),
|
|
678
|
+
/** Broad/composite callable entry points orchestrated by this agent. */
|
|
679
|
+
invocations: z.array(ActionInvocationSchema).default([]),
|
|
680
|
+
emits: z.array(EventEmissionDescriptorSchema).optional()
|
|
681
|
+
});
|
|
682
|
+
var IntegrationResourceEntrySchema = ResourceEntryBaseSchema.extend({
|
|
683
|
+
kind: z.literal("integration"),
|
|
684
|
+
provider: z.string().trim().min(1).max(100)
|
|
685
|
+
});
|
|
686
|
+
var ScriptResourceSourceSchema = z.union([
|
|
687
|
+
z.string().trim().min(1).max(5e4),
|
|
688
|
+
z.object({
|
|
689
|
+
file: z.string().trim().min(1).max(500)
|
|
690
|
+
})
|
|
691
|
+
]);
|
|
692
|
+
var ScriptResourceEntrySchema = ResourceEntryBaseSchema.extend({
|
|
693
|
+
kind: z.literal("script"),
|
|
694
|
+
language: ScriptResourceLanguageSchema,
|
|
695
|
+
source: ScriptResourceSourceSchema
|
|
696
|
+
});
|
|
697
|
+
var ResourceEntrySchema = z.discriminatedUnion("kind", [
|
|
698
|
+
WorkflowResourceEntrySchema,
|
|
699
|
+
AgentResourceEntrySchema,
|
|
700
|
+
IntegrationResourceEntrySchema,
|
|
701
|
+
ScriptResourceEntrySchema
|
|
702
|
+
]);
|
|
703
|
+
var ResourcesDomainSchema = z.record(z.string(), ResourceEntrySchema).refine((record) => Object.entries(record).every(([key, entry]) => entry.id === key), {
|
|
704
|
+
message: "Each resource entry id must match its map key"
|
|
705
|
+
}).default({});
|
|
706
|
+
var DEFAULT_ORGANIZATION_MODEL_RESOURCES = {};
|
|
707
|
+
|
|
708
|
+
// ../core/src/organization-model/helpers.ts
|
|
709
|
+
function defaultPathFor(id) {
|
|
710
|
+
return `/${id.replaceAll(".", "/")}`;
|
|
711
|
+
}
|
|
712
|
+
function parentIdOf(id) {
|
|
713
|
+
const index = id.lastIndexOf(".");
|
|
714
|
+
return index === -1 ? void 0 : id.slice(0, index);
|
|
715
|
+
}
|
|
716
|
+
function findById(systems, id) {
|
|
717
|
+
return systems[id];
|
|
718
|
+
}
|
|
719
|
+
function findByPath(systems, path) {
|
|
720
|
+
return Object.values(systems).find((system) => (system.path ?? system.ui?.path ?? defaultPathFor(system.id)) === path);
|
|
721
|
+
}
|
|
722
|
+
function childrenOf(systems, id) {
|
|
723
|
+
const prefix = `${id}.`;
|
|
724
|
+
return Object.values(systems).filter(
|
|
725
|
+
(system) => system.id.startsWith(prefix) && !system.id.slice(prefix.length).includes(".")
|
|
726
|
+
);
|
|
727
|
+
}
|
|
728
|
+
function topLevel(systems) {
|
|
729
|
+
return Object.values(systems).filter((system) => !system.id.includes("."));
|
|
730
|
+
}
|
|
731
|
+
function ancestorsOf(systems, id) {
|
|
732
|
+
const segments = id.split(".");
|
|
733
|
+
const ids = segments.map((_, index) => segments.slice(0, index + 1).join("."));
|
|
734
|
+
return ids.map((ancestorId) => findById(systems, ancestorId)).filter((system) => Boolean(system));
|
|
735
|
+
}
|
|
736
|
+
function parentOf(systems, id) {
|
|
737
|
+
const parentId = parentIdOf(id);
|
|
738
|
+
return parentId ? findById(systems, parentId) : void 0;
|
|
739
|
+
}
|
|
740
|
+
function inheritedValue(systems, id, getValue) {
|
|
741
|
+
return ancestorsOf(systems, id).slice().reverse().map(getValue).find((value) => value !== void 0);
|
|
742
|
+
}
|
|
743
|
+
function requiresAdminFor(systems, id) {
|
|
744
|
+
return inheritedValue(systems, id, (system) => system.requiresAdmin) ?? false;
|
|
745
|
+
}
|
|
746
|
+
function devOnlyFor(systems, id) {
|
|
747
|
+
return inheritedValue(systems, id, (system) => system.devOnly || system.lifecycle === "beta" || void 0) ?? false;
|
|
748
|
+
}
|
|
749
|
+
function getSystem(model, path) {
|
|
750
|
+
const segments = path.split(".");
|
|
751
|
+
let current = model.systems;
|
|
752
|
+
let node;
|
|
753
|
+
for (const seg of segments) {
|
|
754
|
+
node = current[seg];
|
|
755
|
+
if (node === void 0) return void 0;
|
|
756
|
+
current = node.subsystems ?? {};
|
|
757
|
+
}
|
|
758
|
+
return node;
|
|
759
|
+
}
|
|
760
|
+
function getSystemAncestors(model, path) {
|
|
761
|
+
const segments = path.split(".");
|
|
762
|
+
const result = [];
|
|
763
|
+
let current = model.systems;
|
|
764
|
+
for (const seg of segments) {
|
|
765
|
+
const node = current[seg];
|
|
766
|
+
if (node === void 0) return [];
|
|
767
|
+
result.push(node);
|
|
768
|
+
current = node.subsystems ?? {};
|
|
769
|
+
}
|
|
770
|
+
return result;
|
|
771
|
+
}
|
|
772
|
+
function listAllSystems(model) {
|
|
773
|
+
const results = [];
|
|
774
|
+
function walk(map, prefix) {
|
|
775
|
+
for (const [localId, system] of Object.entries(map)) {
|
|
776
|
+
const fullPath = prefix ? `${prefix}.${localId}` : localId;
|
|
777
|
+
results.push({ path: fullPath, system });
|
|
778
|
+
if (system.subsystems) {
|
|
779
|
+
walk(system.subsystems, fullPath);
|
|
780
|
+
}
|
|
781
|
+
}
|
|
782
|
+
}
|
|
783
|
+
walk(model.systems, "");
|
|
784
|
+
return results;
|
|
785
|
+
}
|
|
786
|
+
function getContent(model, qualifiedId) {
|
|
787
|
+
const colonIndex = qualifiedId.indexOf(":");
|
|
788
|
+
if (colonIndex === -1) return void 0;
|
|
789
|
+
const systemPath = qualifiedId.slice(0, colonIndex);
|
|
790
|
+
const localId = qualifiedId.slice(colonIndex + 1);
|
|
791
|
+
if (!systemPath || !localId) return void 0;
|
|
792
|
+
const system = getSystem(model, systemPath);
|
|
793
|
+
return system?.content?.[localId];
|
|
794
|
+
}
|
|
795
|
+
function getResourcesForSystem(model, systemPath, options = {}) {
|
|
796
|
+
const { includeDescendants = false } = options;
|
|
797
|
+
const prefix = systemPath + ".";
|
|
798
|
+
return Object.values(model.resources ?? {}).filter(
|
|
799
|
+
(r) => r.systemPath === systemPath || includeDescendants && r.systemPath.startsWith(prefix)
|
|
800
|
+
);
|
|
801
|
+
}
|
|
802
|
+
DisplayMetadataSchema.extend({
|
|
803
|
+
id: ModelIdSchema,
|
|
804
|
+
order: z.number().min(0)
|
|
805
|
+
});
|
|
806
|
+
var RecordColumnConfigSchema = z.object({
|
|
807
|
+
key: ModelIdSchema,
|
|
808
|
+
label: z.string().trim().min(1).max(120),
|
|
809
|
+
path: z.string().trim().min(1).max(500),
|
|
810
|
+
width: z.union([z.number().positive(), z.string().trim().min(1).max(100)]).optional(),
|
|
811
|
+
renderType: z.enum(["text", "badge", "datetime", "count", "json"]).optional(),
|
|
812
|
+
badgeColor: z.string().trim().min(1).max(40).optional()
|
|
813
|
+
});
|
|
814
|
+
var RecordColumnsConfigSchema = z.object({
|
|
815
|
+
company: z.array(RecordColumnConfigSchema).optional(),
|
|
816
|
+
contact: z.array(RecordColumnConfigSchema).optional()
|
|
817
|
+
}).refine((columns) => Boolean(columns.company?.length || columns.contact?.length), {
|
|
818
|
+
message: "recordColumns must include at least one entity column set"
|
|
819
|
+
});
|
|
820
|
+
var CredentialRequirementSchema = z.object({
|
|
821
|
+
key: ModelIdSchema,
|
|
822
|
+
provider: ModelIdSchema,
|
|
823
|
+
credentialType: z.enum(["api-key", "api-key-secret", "oauth", "webhook-secret"]),
|
|
824
|
+
label: z.string().trim().min(1).max(120),
|
|
825
|
+
required: z.boolean(),
|
|
826
|
+
selectionMode: z.enum(["single", "multiple"]).optional(),
|
|
827
|
+
inputPath: z.string().trim().min(1).max(500),
|
|
828
|
+
verifyOnRun: z.boolean().optional()
|
|
829
|
+
});
|
|
830
|
+
var ProspectingBuildTemplateStepSchema = DisplayMetadataSchema.extend({
|
|
831
|
+
id: ModelIdSchema,
|
|
832
|
+
primaryEntity: z.enum(["company", "contact"]),
|
|
833
|
+
outputs: z.array(z.enum(["company", "contact", "export"])).min(1),
|
|
834
|
+
stageKey: ModelIdSchema,
|
|
835
|
+
recordEntity: z.enum(["company", "contact"]).optional(),
|
|
836
|
+
recordsStageKey: ModelIdSchema.optional(),
|
|
837
|
+
recordSourceStageKey: ModelIdSchema.optional(),
|
|
838
|
+
dependsOn: z.array(ModelIdSchema).optional(),
|
|
839
|
+
dependencyMode: z.literal("per-record-eligibility"),
|
|
840
|
+
actionKey: ModelIdSchema,
|
|
841
|
+
defaultBatchSize: z.number().int().positive(),
|
|
842
|
+
maxBatchSize: z.number().int().positive(),
|
|
843
|
+
recordColumns: RecordColumnsConfigSchema.optional(),
|
|
844
|
+
credentialRequirements: z.array(CredentialRequirementSchema).optional()
|
|
845
|
+
}).refine((step) => step.defaultBatchSize <= step.maxBatchSize, {
|
|
846
|
+
message: "defaultBatchSize must be less than or equal to maxBatchSize",
|
|
847
|
+
path: ["defaultBatchSize"]
|
|
848
|
+
});
|
|
849
|
+
DisplayMetadataSchema.extend({
|
|
850
|
+
id: ModelIdSchema,
|
|
851
|
+
steps: z.array(ProspectingBuildTemplateStepSchema).min(1)
|
|
852
|
+
});
|
|
853
|
+
var DTC_RECORD_COLUMNS = {
|
|
854
|
+
populated: {
|
|
855
|
+
company: [
|
|
856
|
+
{ key: "name", label: "Company", path: "company.name" },
|
|
857
|
+
{ key: "domain", label: "Domain", path: "company.domain" },
|
|
858
|
+
{ key: "employee-count", label: "Employees", path: "company.numEmployees", renderType: "count" },
|
|
859
|
+
{ key: "apollo-industry", label: "Apollo industry", path: "company.category" },
|
|
860
|
+
{ key: "location", label: "Location", path: "company.locationState" }
|
|
861
|
+
]
|
|
862
|
+
},
|
|
863
|
+
crawled: {
|
|
864
|
+
company: [
|
|
865
|
+
{ key: "name", label: "Company", path: "company.name" },
|
|
866
|
+
{ key: "domain", label: "Domain", path: "company.domain" },
|
|
867
|
+
{ key: "page-count", label: "Pages", path: "company.enrichmentData.websiteCrawl.pageCount", renderType: "count" },
|
|
868
|
+
{ key: "crawl-status", label: "Crawl status", path: "processingState.crawled.status", renderType: "badge" }
|
|
869
|
+
]
|
|
870
|
+
},
|
|
871
|
+
extracted: {
|
|
872
|
+
company: [
|
|
873
|
+
{ key: "name", label: "Company", path: "company.name" },
|
|
874
|
+
{ key: "domain", label: "Domain", path: "company.domain" },
|
|
875
|
+
{ key: "description", label: "Description", path: "company.enrichmentData.websiteCrawl.companyDescription" },
|
|
876
|
+
{ key: "services", label: "Services", path: "company.enrichmentData.websiteCrawl.services", renderType: "json" },
|
|
877
|
+
{
|
|
878
|
+
key: "automation-gaps",
|
|
879
|
+
label: "Automation gaps",
|
|
880
|
+
path: "company.enrichmentData.websiteCrawl.automationGaps",
|
|
881
|
+
renderType: "json"
|
|
882
|
+
},
|
|
883
|
+
{
|
|
884
|
+
key: "contact-count",
|
|
885
|
+
label: "Contacts",
|
|
886
|
+
path: "company.enrichmentData.websiteCrawl.emailCount",
|
|
887
|
+
renderType: "count"
|
|
888
|
+
}
|
|
889
|
+
]
|
|
890
|
+
},
|
|
891
|
+
qualified: {
|
|
892
|
+
company: [
|
|
893
|
+
{ key: "name", label: "Company", path: "company.name" },
|
|
894
|
+
{ key: "domain", label: "Domain", path: "company.domain" },
|
|
895
|
+
{ key: "score", label: "Score", path: "company.qualificationScore", renderType: "badge", badgeColor: "green" },
|
|
896
|
+
{ key: "signals", label: "Signals", path: "company.qualificationSignals", renderType: "json" },
|
|
897
|
+
{
|
|
898
|
+
key: "disqualified-reason",
|
|
899
|
+
label: "Disqualified reason",
|
|
900
|
+
path: "processingState.qualified.data.disqualifiedReason"
|
|
901
|
+
}
|
|
902
|
+
]
|
|
903
|
+
},
|
|
904
|
+
decisionMakers: {
|
|
905
|
+
contact: [
|
|
906
|
+
{ key: "name", label: "Name", path: "contact.name" },
|
|
907
|
+
{ key: "title", label: "Title", path: "contact.title" },
|
|
908
|
+
{ key: "email", label: "Email", path: "contact.email" },
|
|
909
|
+
{ key: "linkedin", label: "LinkedIn", path: "contact.linkedinUrl" },
|
|
910
|
+
{
|
|
911
|
+
key: "priority-score",
|
|
912
|
+
label: "Priority",
|
|
913
|
+
path: "contact.enrichmentData.apollo.priorityScore",
|
|
914
|
+
renderType: "badge"
|
|
915
|
+
}
|
|
916
|
+
]
|
|
917
|
+
},
|
|
918
|
+
uploaded: {
|
|
919
|
+
company: [
|
|
920
|
+
{ key: "name", label: "Company", path: "company.name" },
|
|
921
|
+
{ key: "domain", label: "Domain", path: "company.domain" },
|
|
922
|
+
{
|
|
923
|
+
key: "contacts",
|
|
924
|
+
label: "Contacts",
|
|
925
|
+
path: "company.enrichmentData.approvedLeadListExport.contacts",
|
|
926
|
+
renderType: "json"
|
|
927
|
+
},
|
|
928
|
+
{ key: "score", label: "Score", path: "company.qualificationScore", renderType: "badge", badgeColor: "green" },
|
|
929
|
+
{
|
|
930
|
+
key: "approval",
|
|
931
|
+
label: "Approval",
|
|
932
|
+
path: "company.enrichmentData.approvedLeadListExport.approvalStatus",
|
|
933
|
+
renderType: "badge"
|
|
934
|
+
}
|
|
935
|
+
]
|
|
936
|
+
}
|
|
937
|
+
};
|
|
938
|
+
Object.values(LEAD_GEN_ACTION_ENTRIES);
|
|
939
|
+
var PROSPECTING_STEPS = {
|
|
940
|
+
localServices: {
|
|
941
|
+
sourceCompanies: {
|
|
942
|
+
id: "source-companies",
|
|
943
|
+
label: "Companies found",
|
|
944
|
+
primaryEntity: "company",
|
|
945
|
+
outputs: ["company"],
|
|
946
|
+
stageKey: "populated",
|
|
947
|
+
dependencyMode: "per-record-eligibility",
|
|
948
|
+
actionKey: "lead-gen.company.source",
|
|
949
|
+
defaultBatchSize: 100,
|
|
950
|
+
maxBatchSize: 250
|
|
951
|
+
},
|
|
952
|
+
analyzeWebsites: {
|
|
953
|
+
id: "analyze-websites",
|
|
954
|
+
label: "Websites analyzed",
|
|
955
|
+
primaryEntity: "company",
|
|
956
|
+
outputs: ["company"],
|
|
957
|
+
stageKey: "extracted",
|
|
958
|
+
dependsOn: ["source-companies"],
|
|
959
|
+
dependencyMode: "per-record-eligibility",
|
|
960
|
+
actionKey: "lead-gen.company.website-extract",
|
|
961
|
+
defaultBatchSize: 50,
|
|
962
|
+
maxBatchSize: 100
|
|
963
|
+
},
|
|
964
|
+
qualifyCompanies: {
|
|
965
|
+
id: "qualify-companies",
|
|
966
|
+
label: "Companies qualified",
|
|
967
|
+
primaryEntity: "company",
|
|
968
|
+
outputs: ["company"],
|
|
969
|
+
stageKey: "qualified",
|
|
970
|
+
dependsOn: ["analyze-websites"],
|
|
971
|
+
dependencyMode: "per-record-eligibility",
|
|
972
|
+
actionKey: "lead-gen.company.qualify",
|
|
973
|
+
defaultBatchSize: 100,
|
|
974
|
+
maxBatchSize: 250
|
|
975
|
+
},
|
|
976
|
+
findContacts: {
|
|
977
|
+
id: "find-contacts",
|
|
978
|
+
label: "Decision-makers found",
|
|
979
|
+
primaryEntity: "contact",
|
|
980
|
+
outputs: ["contact"],
|
|
981
|
+
stageKey: "discovered",
|
|
982
|
+
dependsOn: ["qualify-companies"],
|
|
983
|
+
dependencyMode: "per-record-eligibility",
|
|
984
|
+
actionKey: "lead-gen.contact.discover",
|
|
985
|
+
defaultBatchSize: 50,
|
|
986
|
+
maxBatchSize: 100
|
|
987
|
+
},
|
|
988
|
+
verifyEmails: {
|
|
989
|
+
id: "verify-emails",
|
|
990
|
+
label: "Emails verified",
|
|
991
|
+
primaryEntity: "contact",
|
|
992
|
+
outputs: ["contact"],
|
|
993
|
+
stageKey: "verified",
|
|
994
|
+
dependsOn: ["find-contacts"],
|
|
995
|
+
dependencyMode: "per-record-eligibility",
|
|
996
|
+
actionKey: "lead-gen.contact.verify-email",
|
|
997
|
+
defaultBatchSize: 100,
|
|
998
|
+
maxBatchSize: 500
|
|
999
|
+
},
|
|
1000
|
+
personalize: {
|
|
1001
|
+
id: "personalize",
|
|
1002
|
+
label: "Personalize",
|
|
1003
|
+
primaryEntity: "contact",
|
|
1004
|
+
outputs: ["contact"],
|
|
1005
|
+
stageKey: "personalized",
|
|
1006
|
+
dependsOn: ["verify-emails"],
|
|
1007
|
+
dependencyMode: "per-record-eligibility",
|
|
1008
|
+
actionKey: "lead-gen.contact.personalize",
|
|
1009
|
+
defaultBatchSize: 25,
|
|
1010
|
+
maxBatchSize: 100
|
|
1011
|
+
},
|
|
1012
|
+
review: {
|
|
1013
|
+
id: "review",
|
|
1014
|
+
label: "Reviewed and exported",
|
|
1015
|
+
primaryEntity: "contact",
|
|
1016
|
+
outputs: ["export"],
|
|
1017
|
+
stageKey: "uploaded",
|
|
1018
|
+
dependsOn: ["personalize"],
|
|
1019
|
+
dependencyMode: "per-record-eligibility",
|
|
1020
|
+
actionKey: "lead-gen.review.outreach-ready",
|
|
1021
|
+
defaultBatchSize: 25,
|
|
1022
|
+
maxBatchSize: 100
|
|
1023
|
+
}
|
|
1024
|
+
},
|
|
1025
|
+
dtcApolloClickup: {
|
|
1026
|
+
importApolloSearch: {
|
|
1027
|
+
id: "import-apollo-search",
|
|
1028
|
+
label: "Companies found",
|
|
1029
|
+
description: "Pull companies and seed contact data from a predefined Apollo search or list.",
|
|
1030
|
+
primaryEntity: "company",
|
|
1031
|
+
outputs: ["company", "contact"],
|
|
1032
|
+
stageKey: "populated",
|
|
1033
|
+
dependencyMode: "per-record-eligibility",
|
|
1034
|
+
actionKey: "lead-gen.company.apollo-import",
|
|
1035
|
+
defaultBatchSize: 250,
|
|
1036
|
+
maxBatchSize: 1e3,
|
|
1037
|
+
recordColumns: DTC_RECORD_COLUMNS.populated,
|
|
1038
|
+
credentialRequirements: [
|
|
1039
|
+
{
|
|
1040
|
+
key: "apollo",
|
|
1041
|
+
provider: "apollo",
|
|
1042
|
+
credentialType: "api-key-secret",
|
|
1043
|
+
label: "Apollo API key",
|
|
1044
|
+
required: true,
|
|
1045
|
+
selectionMode: "single",
|
|
1046
|
+
inputPath: "credential"
|
|
1047
|
+
}
|
|
1048
|
+
]
|
|
1049
|
+
},
|
|
1050
|
+
apifyCrawl: {
|
|
1051
|
+
id: "apify-crawl",
|
|
1052
|
+
label: "Websites crawled",
|
|
1053
|
+
description: "Crawl company websites via Apify and store raw page markdown in enrichmentData.websiteCrawl.pages for downstream LLM analysis. Overwrites the synthetic seed Apollo Import wrote with real page content.",
|
|
1054
|
+
primaryEntity: "company",
|
|
1055
|
+
outputs: ["company"],
|
|
1056
|
+
stageKey: "crawled",
|
|
1057
|
+
dependsOn: ["import-apollo-search"],
|
|
1058
|
+
dependencyMode: "per-record-eligibility",
|
|
1059
|
+
actionKey: "lead-gen.company.apify-crawl",
|
|
1060
|
+
defaultBatchSize: 50,
|
|
1061
|
+
maxBatchSize: 100,
|
|
1062
|
+
recordColumns: DTC_RECORD_COLUMNS.crawled,
|
|
1063
|
+
credentialRequirements: [
|
|
1064
|
+
{
|
|
1065
|
+
key: "apify",
|
|
1066
|
+
provider: "apify",
|
|
1067
|
+
credentialType: "api-key-secret",
|
|
1068
|
+
label: "Apify API token",
|
|
1069
|
+
required: true,
|
|
1070
|
+
selectionMode: "single",
|
|
1071
|
+
inputPath: "credential",
|
|
1072
|
+
verifyOnRun: true
|
|
1073
|
+
}
|
|
1074
|
+
]
|
|
1075
|
+
},
|
|
1076
|
+
analyzeWebsites: {
|
|
1077
|
+
id: "analyze-websites",
|
|
1078
|
+
label: "Websites analyzed",
|
|
1079
|
+
description: "Extract subscription, product, retention, and tech-stack signals from each brand website.",
|
|
1080
|
+
primaryEntity: "company",
|
|
1081
|
+
outputs: ["company"],
|
|
1082
|
+
stageKey: "extracted",
|
|
1083
|
+
dependsOn: ["apify-crawl"],
|
|
1084
|
+
dependencyMode: "per-record-eligibility",
|
|
1085
|
+
actionKey: "lead-gen.company.website-extract",
|
|
1086
|
+
defaultBatchSize: 50,
|
|
1087
|
+
maxBatchSize: 100,
|
|
1088
|
+
recordColumns: DTC_RECORD_COLUMNS.extracted
|
|
1089
|
+
},
|
|
1090
|
+
scoreDtcFit: {
|
|
1091
|
+
id: "score-dtc-fit",
|
|
1092
|
+
label: "Companies qualified",
|
|
1093
|
+
description: "Classify subscription potential, consumable-product fit, retention maturity, and disqualifiers.",
|
|
1094
|
+
primaryEntity: "company",
|
|
1095
|
+
outputs: ["company"],
|
|
1096
|
+
stageKey: "qualified",
|
|
1097
|
+
dependsOn: ["analyze-websites"],
|
|
1098
|
+
dependencyMode: "per-record-eligibility",
|
|
1099
|
+
actionKey: "lead-gen.company.dtc-subscription-qualify",
|
|
1100
|
+
defaultBatchSize: 100,
|
|
1101
|
+
maxBatchSize: 250,
|
|
1102
|
+
recordColumns: DTC_RECORD_COLUMNS.qualified
|
|
1103
|
+
},
|
|
1104
|
+
enrichDecisionMakers: {
|
|
1105
|
+
id: "enrich-decision-makers",
|
|
1106
|
+
label: "Decision-makers found",
|
|
1107
|
+
description: "Use Apollo to find qualified contacts at qualified companies - founders, retention leads, lifecycle leads, and marketing owners.",
|
|
1108
|
+
primaryEntity: "company",
|
|
1109
|
+
outputs: ["contact"],
|
|
1110
|
+
stageKey: "decision-makers-enriched",
|
|
1111
|
+
recordEntity: "contact",
|
|
1112
|
+
dependsOn: ["score-dtc-fit"],
|
|
1113
|
+
dependencyMode: "per-record-eligibility",
|
|
1114
|
+
actionKey: "lead-gen.contact.apollo-decision-maker-enrich",
|
|
1115
|
+
defaultBatchSize: 100,
|
|
1116
|
+
maxBatchSize: 250,
|
|
1117
|
+
recordColumns: DTC_RECORD_COLUMNS.decisionMakers,
|
|
1118
|
+
credentialRequirements: [
|
|
1119
|
+
{
|
|
1120
|
+
key: "apollo",
|
|
1121
|
+
provider: "apollo",
|
|
1122
|
+
credentialType: "api-key-secret",
|
|
1123
|
+
label: "Apollo API key",
|
|
1124
|
+
required: true,
|
|
1125
|
+
selectionMode: "single",
|
|
1126
|
+
inputPath: "credential"
|
|
1127
|
+
}
|
|
1128
|
+
]
|
|
1129
|
+
},
|
|
1130
|
+
reviewAndExport: {
|
|
1131
|
+
id: "review-and-export",
|
|
1132
|
+
label: "Reviewed and exported",
|
|
1133
|
+
description: "Operator QC approves or rejects qualified companies, then approved records are exported as a lead list with unverified emails.",
|
|
1134
|
+
primaryEntity: "company",
|
|
1135
|
+
outputs: ["export"],
|
|
1136
|
+
stageKey: "uploaded",
|
|
1137
|
+
recordsStageKey: "uploaded",
|
|
1138
|
+
recordSourceStageKey: "qualified",
|
|
1139
|
+
dependsOn: ["enrich-decision-makers"],
|
|
1140
|
+
dependencyMode: "per-record-eligibility",
|
|
1141
|
+
actionKey: "lead-gen.export.list",
|
|
1142
|
+
defaultBatchSize: 100,
|
|
1143
|
+
maxBatchSize: 250,
|
|
1144
|
+
recordColumns: DTC_RECORD_COLUMNS.uploaded,
|
|
1145
|
+
credentialRequirements: [
|
|
1146
|
+
{
|
|
1147
|
+
key: "clickup",
|
|
1148
|
+
provider: "clickup",
|
|
1149
|
+
credentialType: "api-key-secret",
|
|
1150
|
+
label: "ClickUp API token",
|
|
1151
|
+
required: true,
|
|
1152
|
+
selectionMode: "single",
|
|
1153
|
+
inputPath: "clickupCredential",
|
|
1154
|
+
verifyOnRun: true
|
|
1155
|
+
}
|
|
1156
|
+
]
|
|
1157
|
+
}
|
|
1158
|
+
}
|
|
1159
|
+
};
|
|
1160
|
+
|
|
1161
|
+
// ../core/src/organization-model/catalogs/lead-gen.ts
|
|
1162
|
+
var LEAD_GEN_STAGE_CATALOG = {
|
|
1163
|
+
// Prospecting - company population
|
|
1164
|
+
scraped: {
|
|
1165
|
+
key: "scraped",
|
|
1166
|
+
label: "Scraped",
|
|
1167
|
+
description: "Company was scraped from a source directory (Apify actor run).",
|
|
1168
|
+
order: 1,
|
|
1169
|
+
entity: "company"
|
|
1170
|
+
},
|
|
1171
|
+
populated: {
|
|
1172
|
+
key: "populated",
|
|
1173
|
+
label: "Companies found",
|
|
1174
|
+
description: "Companies have been found and added to the lead-gen list.",
|
|
1175
|
+
order: 2,
|
|
1176
|
+
entity: "company"
|
|
1177
|
+
},
|
|
1178
|
+
crawled: {
|
|
1179
|
+
key: "crawled",
|
|
1180
|
+
label: "Websites crawled",
|
|
1181
|
+
description: "Company websites have been crawled (e.g. via Apify) and raw page content stored for downstream LLM analysis.",
|
|
1182
|
+
order: 2.5,
|
|
1183
|
+
entity: "company"
|
|
1184
|
+
},
|
|
1185
|
+
extracted: {
|
|
1186
|
+
key: "extracted",
|
|
1187
|
+
label: "Websites analyzed",
|
|
1188
|
+
description: "Company websites have been analyzed for business signals.",
|
|
1189
|
+
order: 3,
|
|
1190
|
+
entity: "company"
|
|
1191
|
+
},
|
|
1192
|
+
enriched: {
|
|
1193
|
+
key: "enriched",
|
|
1194
|
+
label: "Enriched",
|
|
1195
|
+
description: "Company or contact enriched with third-party data (e.g. Tomba, Anymailfinder).",
|
|
1196
|
+
order: 4,
|
|
1197
|
+
entity: "company"
|
|
1198
|
+
},
|
|
1199
|
+
"decision-makers-enriched": {
|
|
1200
|
+
key: "decision-makers-enriched",
|
|
1201
|
+
label: "Decision-makers found",
|
|
1202
|
+
description: "Decision-maker contacts discovered and attached to a qualified company.",
|
|
1203
|
+
order: 6,
|
|
1204
|
+
entity: "company",
|
|
1205
|
+
recordEntity: "contact",
|
|
1206
|
+
recordStageKey: "discovered"
|
|
1207
|
+
},
|
|
1208
|
+
// Prospecting - contact discovery
|
|
1209
|
+
discovered: {
|
|
1210
|
+
key: "discovered",
|
|
1211
|
+
label: "Decision-makers found",
|
|
1212
|
+
description: "Decision-maker contact details have been found.",
|
|
1213
|
+
order: 5,
|
|
1214
|
+
entity: "contact"
|
|
1215
|
+
},
|
|
1216
|
+
verified: {
|
|
1217
|
+
key: "verified",
|
|
1218
|
+
label: "Emails verified",
|
|
1219
|
+
description: "Contact email addresses have been checked for deliverability.",
|
|
1220
|
+
order: 7,
|
|
1221
|
+
entity: "contact"
|
|
1222
|
+
},
|
|
1223
|
+
// Qualification
|
|
1224
|
+
qualified: {
|
|
1225
|
+
key: "qualified",
|
|
1226
|
+
label: "Companies qualified",
|
|
1227
|
+
description: "Companies have been scored against the qualification criteria.",
|
|
1228
|
+
order: 8,
|
|
1229
|
+
entity: "company"
|
|
1230
|
+
},
|
|
1231
|
+
// Outreach
|
|
1232
|
+
personalized: {
|
|
1233
|
+
key: "personalized",
|
|
1234
|
+
label: "Personalized",
|
|
1235
|
+
description: "Outreach message personalized for the contact (Instantly personalization workflow).",
|
|
1236
|
+
order: 9,
|
|
1237
|
+
entity: "contact"
|
|
1238
|
+
},
|
|
1239
|
+
uploaded: {
|
|
1240
|
+
key: "uploaded",
|
|
1241
|
+
label: "Reviewed and exported",
|
|
1242
|
+
description: "Approved records have been reviewed and exported for handoff.",
|
|
1243
|
+
order: 10,
|
|
1244
|
+
entity: "company",
|
|
1245
|
+
additionalEntities: ["contact"]
|
|
1246
|
+
},
|
|
1247
|
+
interested: {
|
|
1248
|
+
key: "interested",
|
|
1249
|
+
label: "Interested",
|
|
1250
|
+
description: "Contact replied with a positive signal (Instantly reply-handler transition).",
|
|
1251
|
+
order: 11,
|
|
1252
|
+
entity: "contact"
|
|
1253
|
+
}
|
|
1254
|
+
};
|
|
1255
|
+
var SalesStageSemanticClassSchema = z.enum(["open", "active", "nurturing", "closed_won", "closed_lost"]);
|
|
1256
|
+
var SalesStageSchema = DisplayMetadataSchema.extend({
|
|
1257
|
+
id: ModelIdSchema,
|
|
1258
|
+
order: z.number().int().min(0),
|
|
1259
|
+
semanticClass: SalesStageSemanticClassSchema,
|
|
1260
|
+
surfaceIds: ReferenceIdsSchema,
|
|
1261
|
+
resourceIds: ReferenceIdsSchema
|
|
1262
|
+
});
|
|
1263
|
+
z.object({
|
|
1264
|
+
id: ModelIdSchema,
|
|
1265
|
+
label: z.string().trim().min(1).max(120),
|
|
1266
|
+
description: DescriptionSchema.optional(),
|
|
1267
|
+
entityId: ModelIdSchema,
|
|
1268
|
+
stages: z.array(SalesStageSchema).min(1)
|
|
1269
|
+
});
|
|
1270
|
+
function findPipeline(definitions, pipelineKey) {
|
|
1271
|
+
return definitions.find((def) => def.pipelineKey === pipelineKey);
|
|
1272
|
+
}
|
|
1273
|
+
var CRM_DISCOVERY_REPLIED_STATE = {
|
|
1274
|
+
stateKey: "discovery_replied",
|
|
1275
|
+
label: "Discovery Replied"
|
|
1276
|
+
};
|
|
1277
|
+
var CRM_DISCOVERY_LINK_SENT_STATE = {
|
|
1278
|
+
stateKey: "discovery_link_sent",
|
|
1279
|
+
label: "Discovery Link Sent"
|
|
1280
|
+
};
|
|
1281
|
+
var CRM_DISCOVERY_NUDGING_STATE = {
|
|
1282
|
+
stateKey: "discovery_nudging",
|
|
1283
|
+
label: "Discovery Nudging"
|
|
1284
|
+
};
|
|
1285
|
+
var CRM_DISCOVERY_BOOKING_CANCELLED_STATE = {
|
|
1286
|
+
stateKey: "discovery_booking_cancelled",
|
|
1287
|
+
label: "Discovery Booking Cancelled"
|
|
1288
|
+
};
|
|
1289
|
+
var CRM_REPLY_SENT_STATE = {
|
|
1290
|
+
stateKey: "reply_sent",
|
|
1291
|
+
label: "Reply Sent"
|
|
1292
|
+
};
|
|
1293
|
+
var CRM_FOLLOWUP_1_SENT_STATE = {
|
|
1294
|
+
stateKey: "followup_1_sent",
|
|
1295
|
+
label: "Follow-up 1 Sent"
|
|
1296
|
+
};
|
|
1297
|
+
var CRM_FOLLOWUP_2_SENT_STATE = {
|
|
1298
|
+
stateKey: "followup_2_sent",
|
|
1299
|
+
label: "Follow-up 2 Sent"
|
|
1300
|
+
};
|
|
1301
|
+
var CRM_FOLLOWUP_3_SENT_STATE = {
|
|
1302
|
+
stateKey: "followup_3_sent",
|
|
1303
|
+
label: "Follow-up 3 Sent"
|
|
1304
|
+
};
|
|
1305
|
+
var CRM_PIPELINE_DEFINITION = {
|
|
1306
|
+
pipelineKey: "crm",
|
|
1307
|
+
label: "CRM",
|
|
1308
|
+
entityKey: "crm.deal",
|
|
1309
|
+
stages: [
|
|
1310
|
+
{
|
|
1311
|
+
stageKey: "interested",
|
|
1312
|
+
label: "Interested",
|
|
1313
|
+
color: "blue",
|
|
1314
|
+
states: [
|
|
1315
|
+
CRM_DISCOVERY_REPLIED_STATE,
|
|
1316
|
+
CRM_DISCOVERY_LINK_SENT_STATE,
|
|
1317
|
+
CRM_DISCOVERY_NUDGING_STATE,
|
|
1318
|
+
CRM_DISCOVERY_BOOKING_CANCELLED_STATE,
|
|
1319
|
+
CRM_REPLY_SENT_STATE,
|
|
1320
|
+
CRM_FOLLOWUP_1_SENT_STATE,
|
|
1321
|
+
CRM_FOLLOWUP_2_SENT_STATE,
|
|
1322
|
+
CRM_FOLLOWUP_3_SENT_STATE
|
|
1323
|
+
]
|
|
1324
|
+
},
|
|
1325
|
+
{ stageKey: "proposal", label: "Proposal", color: "yellow", states: [] },
|
|
1326
|
+
{ stageKey: "closing", label: "Closing", color: "orange", states: [] },
|
|
1327
|
+
{ stageKey: "closed_won", label: "Closed Won", color: "green", states: [] },
|
|
1328
|
+
{ stageKey: "closed_lost", label: "Closed Lost", color: "red", states: [] },
|
|
1329
|
+
{ stageKey: "nurturing", label: "Nurturing", color: "grape", states: [] }
|
|
1330
|
+
]
|
|
1331
|
+
};
|
|
1332
|
+
var CRM_PRIORITY_BUCKETS = [
|
|
1333
|
+
{ bucketKey: "needs_response", label: "Needs Response", rank: 10, color: "red" },
|
|
1334
|
+
{ bucketKey: "follow_up_due", label: "Follow-up Due", rank: 20, color: "orange" },
|
|
1335
|
+
{ bucketKey: "waiting", label: "Waiting", rank: 30, color: "blue" },
|
|
1336
|
+
{ bucketKey: "stale", label: "Stale", rank: 40, color: "gray" },
|
|
1337
|
+
{ bucketKey: "closed_low", label: "Closed", rank: 50, color: "dark" }
|
|
1338
|
+
];
|
|
1339
|
+
var DEFAULT_CRM_PRIORITY_RULE_CONFIG = {
|
|
1340
|
+
buckets: CRM_PRIORITY_BUCKETS,
|
|
1341
|
+
closedStageKeys: ["closed_won", "closed_lost"],
|
|
1342
|
+
followUpAfterDaysByStateKey: {
|
|
1343
|
+
discovery_link_sent: 3,
|
|
1344
|
+
discovery_nudging: 2,
|
|
1345
|
+
reply_sent: 3,
|
|
1346
|
+
followup_1_sent: 3,
|
|
1347
|
+
followup_2_sent: 5,
|
|
1348
|
+
followup_3_sent: 7
|
|
1349
|
+
},
|
|
1350
|
+
staleAfterDays: 14
|
|
1351
|
+
};
|
|
1352
|
+
var PENDING_STATE = { stateKey: "pending", label: "Pending" };
|
|
1353
|
+
var ACQ_LIST_MEMBERS_LEAD_GEN_PIPELINE = {
|
|
1354
|
+
pipelineKey: "lead-gen",
|
|
1355
|
+
label: "Lead Generation",
|
|
1356
|
+
entityKey: "acq.list-member",
|
|
1357
|
+
stages: [
|
|
1358
|
+
{
|
|
1359
|
+
stageKey: "outreach",
|
|
1360
|
+
label: "Outreach",
|
|
1361
|
+
states: [
|
|
1362
|
+
PENDING_STATE,
|
|
1363
|
+
{ stateKey: "personalized", label: "Personalized" },
|
|
1364
|
+
{ stateKey: "uploaded", label: "Uploaded" },
|
|
1365
|
+
{ stateKey: "interested", label: "Interested" }
|
|
1366
|
+
]
|
|
1367
|
+
},
|
|
1368
|
+
{
|
|
1369
|
+
stageKey: "prospecting",
|
|
1370
|
+
label: "Prospecting",
|
|
1371
|
+
states: [
|
|
1372
|
+
PENDING_STATE,
|
|
1373
|
+
{ stateKey: "discovered", label: "Discovered" },
|
|
1374
|
+
{ stateKey: "verified", label: "Verified" }
|
|
1375
|
+
]
|
|
1376
|
+
},
|
|
1377
|
+
{
|
|
1378
|
+
stageKey: "qualification",
|
|
1379
|
+
label: "Qualification",
|
|
1380
|
+
states: [PENDING_STATE]
|
|
1381
|
+
}
|
|
1382
|
+
]
|
|
1383
|
+
};
|
|
1384
|
+
var ACQ_LIST_COMPANIES_LEAD_GEN_PIPELINE = {
|
|
1385
|
+
pipelineKey: "lead-gen",
|
|
1386
|
+
label: "Lead Generation",
|
|
1387
|
+
entityKey: "acq.list-company",
|
|
1388
|
+
stages: [
|
|
1389
|
+
{
|
|
1390
|
+
stageKey: "outreach",
|
|
1391
|
+
label: "Outreach",
|
|
1392
|
+
states: [PENDING_STATE, { stateKey: "uploaded", label: "Uploaded" }]
|
|
1393
|
+
},
|
|
1394
|
+
{
|
|
1395
|
+
stageKey: "prospecting",
|
|
1396
|
+
label: "Prospecting",
|
|
1397
|
+
states: [
|
|
1398
|
+
PENDING_STATE,
|
|
1399
|
+
{ stateKey: "populated", label: "Populated" },
|
|
1400
|
+
{ stateKey: "extracted", label: "Extracted" }
|
|
1401
|
+
]
|
|
1402
|
+
},
|
|
1403
|
+
{
|
|
1404
|
+
stageKey: "qualification",
|
|
1405
|
+
label: "Qualification",
|
|
1406
|
+
states: [PENDING_STATE, { stateKey: "qualified", label: "Qualified" }]
|
|
1407
|
+
}
|
|
1408
|
+
]
|
|
1409
|
+
};
|
|
1410
|
+
var LEAD_GEN_PIPELINE_DEFINITIONS = {
|
|
1411
|
+
"acq.list-member": [ACQ_LIST_MEMBERS_LEAD_GEN_PIPELINE],
|
|
1412
|
+
"acq.list-company": [ACQ_LIST_COMPANIES_LEAD_GEN_PIPELINE]
|
|
1413
|
+
};
|
|
1414
|
+
|
|
1415
|
+
// ../core/src/organization-model/contracts.ts
|
|
1416
|
+
var PROJECTS_VIEW_ACTION_ID = "delivery.projects.view";
|
|
1417
|
+
|
|
1418
|
+
// ../core/src/organization-model/content-kinds/registry.ts
|
|
1419
|
+
function defineContentType(def) {
|
|
1420
|
+
return def;
|
|
1421
|
+
}
|
|
1422
|
+
var PipelinePayloadSchema = z.object({
|
|
1423
|
+
/**
|
|
1424
|
+
* Local NodeId of the entity this pipeline applies to (e.g. 'crm.deal').
|
|
1425
|
+
* `.meta({ ref: 'entity' })` enables SchemaDrivenFieldList to render a
|
|
1426
|
+
* clickable graph link to the referenced entity node.
|
|
1427
|
+
*/
|
|
1428
|
+
entityId: z.string().trim().min(1).max(200).meta({ label: "Entity", ref: "entity", hint: "The entity type this pipeline tracks" }),
|
|
1429
|
+
/**
|
|
1430
|
+
* Optional Kanban column color token for UI rendering.
|
|
1431
|
+
*/
|
|
1432
|
+
kanbanColor: z.string().trim().min(1).max(40).optional().meta({ label: "Kanban color", hint: "UI color token" })
|
|
1433
|
+
});
|
|
1434
|
+
var pipelineKind = defineContentType({
|
|
1435
|
+
kind: "schema",
|
|
1436
|
+
type: "pipeline",
|
|
1437
|
+
label: "Pipeline",
|
|
1438
|
+
description: "A named progression pipeline that applies to a specific entity type.",
|
|
1439
|
+
payloadSchema: PipelinePayloadSchema,
|
|
1440
|
+
parentTypes: []
|
|
1441
|
+
});
|
|
1442
|
+
var StagePayloadSchema = z.object({
|
|
1443
|
+
/**
|
|
1444
|
+
* Semantic classification for this stage.
|
|
1445
|
+
* Drives color, icon, and CRM-priority logic in consuming views.
|
|
1446
|
+
* Optional — prospecting stages use data.entityKind instead.
|
|
1447
|
+
* Enum aligned with SalesStageSemanticClassSchema (sales.ts).
|
|
1448
|
+
*/
|
|
1449
|
+
semanticClass: z.enum(["open", "active", "nurturing", "closed_won", "closed_lost", "won", "lost", "closed"]).optional().meta({ label: "Semantic class", hint: "Semantic meaning of this stage", color: "blue" })
|
|
1450
|
+
});
|
|
1451
|
+
var stageKind = defineContentType({
|
|
1452
|
+
kind: "schema",
|
|
1453
|
+
type: "stage",
|
|
1454
|
+
label: "Stage",
|
|
1455
|
+
description: "A stage within a pipeline. Must be parented under a schema:pipeline content node.",
|
|
1456
|
+
payloadSchema: StagePayloadSchema,
|
|
1457
|
+
parentTypes: ["schema:pipeline"]
|
|
1458
|
+
});
|
|
1459
|
+
var TemplatePayloadSchema = z.object({
|
|
1460
|
+
/**
|
|
1461
|
+
* Optional description surfaced in the KB describe view and tooling.
|
|
1462
|
+
*/
|
|
1463
|
+
description: z.string().trim().min(1).max(2e3).optional().meta({ label: "Description", hint: "What this template is used for" })
|
|
1464
|
+
});
|
|
1465
|
+
var templateKind = defineContentType({
|
|
1466
|
+
kind: "schema",
|
|
1467
|
+
type: "template",
|
|
1468
|
+
label: "Template",
|
|
1469
|
+
description: "A named build template (e.g. a prospecting pipeline sequence).",
|
|
1470
|
+
payloadSchema: TemplatePayloadSchema,
|
|
1471
|
+
parentTypes: []
|
|
1472
|
+
});
|
|
1473
|
+
var TemplateStepPayloadSchema = z.object({
|
|
1474
|
+
/**
|
|
1475
|
+
* Which entity type this step primarily operates on.
|
|
1476
|
+
*/
|
|
1477
|
+
primaryEntity: z.enum(["company", "contact"]).meta({ label: "Primary entity", hint: "Entity type this step processes", color: "blue" }),
|
|
1478
|
+
/**
|
|
1479
|
+
* Action key identifying the workflow action executed by this step.
|
|
1480
|
+
* `.meta({ ref: 'action' })` enables SchemaDrivenFieldList to render a
|
|
1481
|
+
* clickable graph link.
|
|
1482
|
+
*/
|
|
1483
|
+
actionKey: z.string().trim().min(1).max(200).meta({ label: "Action", ref: "action", hint: "Workflow action executed by this step" }),
|
|
1484
|
+
/**
|
|
1485
|
+
* IDs of sibling step local NodeIds this step depends on.
|
|
1486
|
+
*/
|
|
1487
|
+
dependsOn: z.array(z.string().trim().min(1).max(200)).optional().meta({ label: "Depends on", hint: "Local NodeIds of prerequisite steps" })
|
|
1488
|
+
});
|
|
1489
|
+
var templateStepKind = defineContentType({
|
|
1490
|
+
kind: "schema",
|
|
1491
|
+
type: "template-step",
|
|
1492
|
+
label: "Template Step",
|
|
1493
|
+
description: "A step within a build template. Must be parented under a schema:template content node.",
|
|
1494
|
+
payloadSchema: TemplateStepPayloadSchema,
|
|
1495
|
+
parentTypes: ["schema:template"]
|
|
1496
|
+
});
|
|
1497
|
+
var StatusFlowPayloadSchema = z.object({
|
|
1498
|
+
/**
|
|
1499
|
+
* Which entity scope this status flow governs.
|
|
1500
|
+
*/
|
|
1501
|
+
appliesTo: z.enum(["project", "milestone", "task"]).meta({ label: "Applies to", hint: "Entity scope governed by this status flow", color: "blue" })
|
|
1502
|
+
});
|
|
1503
|
+
var statusFlowKind = defineContentType({
|
|
1504
|
+
kind: "schema",
|
|
1505
|
+
type: "status-flow",
|
|
1506
|
+
label: "Status Flow",
|
|
1507
|
+
description: "A named set of statuses governing a project, milestone, or task entity.",
|
|
1508
|
+
payloadSchema: StatusFlowPayloadSchema,
|
|
1509
|
+
parentTypes: []
|
|
1510
|
+
});
|
|
1511
|
+
var StatusPayloadSchema = z.object({
|
|
1512
|
+
/**
|
|
1513
|
+
* Semantic classification string for this status.
|
|
1514
|
+
* Free-form to allow tenant-defined classifications (e.g. 'active', 'blocked',
|
|
1515
|
+
* 'completed'). Used by UI to apply color and icon fallbacks.
|
|
1516
|
+
* Optional — status nodes may omit this when the label is self-descriptive.
|
|
1517
|
+
*/
|
|
1518
|
+
semanticClass: z.string().trim().min(1).max(100).optional().meta({ label: "Semantic class", hint: "Semantic meaning of this status (e.g. active, blocked, completed)" }),
|
|
1519
|
+
/**
|
|
1520
|
+
* Optional UI color token override for this status.
|
|
1521
|
+
*/
|
|
1522
|
+
color: z.string().trim().min(1).max(40).optional().meta({ label: "Color", hint: "UI color token" })
|
|
1523
|
+
});
|
|
1524
|
+
var statusKind = defineContentType({
|
|
1525
|
+
kind: "schema",
|
|
1526
|
+
type: "status",
|
|
1527
|
+
label: "Status",
|
|
1528
|
+
description: "A single status within a status flow. Must be parented under a schema:status-flow content node.",
|
|
1529
|
+
payloadSchema: StatusPayloadSchema,
|
|
1530
|
+
parentTypes: ["schema:status-flow"]
|
|
1531
|
+
});
|
|
1532
|
+
var ConfigKvPayloadSchema = z.object({
|
|
1533
|
+
/**
|
|
1534
|
+
* Flat key-value entries. Values are JSON primitives.
|
|
1535
|
+
* Keys are short identifiers (e.g. 'maxBatchSize', 'featureEnabled').
|
|
1536
|
+
*/
|
|
1537
|
+
entries: z.record(z.string().trim().min(1).max(200), z.union([z.string(), z.number(), z.boolean(), z.null()])).meta({ label: "Entries", hint: "Key-value configuration entries (string, number, boolean, or null values)" })
|
|
1538
|
+
});
|
|
1539
|
+
var configKvKind = defineContentType({
|
|
1540
|
+
kind: "config",
|
|
1541
|
+
type: "kv",
|
|
1542
|
+
label: "Key-Value Config",
|
|
1543
|
+
description: "A flat key-value configuration store co-located with a system. Values are JSON primitives.",
|
|
1544
|
+
payloadSchema: ConfigKvPayloadSchema,
|
|
1545
|
+
parentTypes: []
|
|
1546
|
+
});
|
|
1547
|
+
|
|
1548
|
+
// ../core/src/organization-model/content-kinds/index.ts
|
|
1549
|
+
var CONTENT_KIND_REGISTRY = {
|
|
1550
|
+
"schema:pipeline": pipelineKind,
|
|
1551
|
+
"schema:stage": stageKind,
|
|
1552
|
+
"schema:template": templateKind,
|
|
1553
|
+
"schema:template-step": templateStepKind,
|
|
1554
|
+
"schema:status-flow": statusFlowKind,
|
|
1555
|
+
"schema:status": statusKind,
|
|
1556
|
+
"config:kv": configKvKind
|
|
1557
|
+
};
|
|
1558
|
+
function lookupContentType(kind, type) {
|
|
1559
|
+
const key = `${kind}:${type}`;
|
|
1560
|
+
return CONTENT_KIND_REGISTRY[key];
|
|
1561
|
+
}
|
|
1562
|
+
var OrganizationModelBrandingSchema = z.object({
|
|
1563
|
+
organizationName: LabelSchema,
|
|
1564
|
+
productName: LabelSchema,
|
|
1565
|
+
shortName: z.string().trim().min(1).max(40),
|
|
1566
|
+
description: DescriptionSchema.optional(),
|
|
1567
|
+
logos: z.object({
|
|
1568
|
+
light: z.string().trim().min(1).max(2048).optional(),
|
|
1569
|
+
dark: z.string().trim().min(1).max(2048).optional()
|
|
1570
|
+
}).default({})
|
|
1571
|
+
});
|
|
1572
|
+
var DEFAULT_ORGANIZATION_MODEL_BRANDING = {
|
|
1573
|
+
organizationName: "Default Organization",
|
|
1574
|
+
productName: "Elevasis",
|
|
1575
|
+
shortName: "Elevasis",
|
|
1576
|
+
logos: {}
|
|
1577
|
+
};
|
|
1578
|
+
var SurfaceTypeSchema = z.enum(["page", "dashboard", "graph", "detail", "list", "settings"]).meta({ label: "Surface type", color: "blue" });
|
|
1579
|
+
var SurfaceDefinitionSchema = z.object({
|
|
1580
|
+
id: ModelIdSchema,
|
|
1581
|
+
label: LabelSchema,
|
|
1582
|
+
path: PathSchema,
|
|
1583
|
+
surfaceType: SurfaceTypeSchema,
|
|
1584
|
+
description: DescriptionSchema.optional(),
|
|
1585
|
+
enabled: z.boolean().default(true),
|
|
1586
|
+
devOnly: z.boolean().optional(),
|
|
1587
|
+
icon: IconNameSchema.optional(),
|
|
1588
|
+
systemIds: z.array(ModelIdSchema.meta({ ref: "system" })).default([]),
|
|
1589
|
+
entityIds: z.array(ModelIdSchema.meta({ ref: "entity" })).default([]),
|
|
1590
|
+
resourceIds: z.array(ModelIdSchema.meta({ ref: "resource" })).default([]),
|
|
1591
|
+
actionIds: z.array(ModelIdSchema.meta({ ref: "action" })).default([]),
|
|
1592
|
+
parentId: ModelIdSchema.meta({ ref: "surface" }).optional()
|
|
1593
|
+
});
|
|
1594
|
+
var SidebarSurfaceTargetsSchema = z.object({
|
|
1595
|
+
systems: z.array(ModelIdSchema.meta({ ref: "system" })).default([]).optional(),
|
|
1596
|
+
entities: z.array(ModelIdSchema.meta({ ref: "entity" })).default([]).optional(),
|
|
1597
|
+
resources: z.array(ModelIdSchema.meta({ ref: "resource" })).default([]).optional(),
|
|
1598
|
+
actions: z.array(ModelIdSchema.meta({ ref: "action" })).default([]).optional()
|
|
1599
|
+
}).default({});
|
|
1600
|
+
var SidebarNodeSchema = z.lazy(
|
|
1601
|
+
() => z.discriminatedUnion("type", [
|
|
1602
|
+
z.object({
|
|
1603
|
+
type: z.literal("group"),
|
|
1604
|
+
label: LabelSchema,
|
|
1605
|
+
description: DescriptionSchema.optional(),
|
|
1606
|
+
icon: IconNameSchema.optional(),
|
|
1607
|
+
order: z.number().int().optional(),
|
|
1608
|
+
children: z.record(z.string(), SidebarNodeSchema).default({})
|
|
1609
|
+
}),
|
|
1610
|
+
z.object({
|
|
1611
|
+
type: z.literal("surface"),
|
|
1612
|
+
label: LabelSchema,
|
|
1613
|
+
path: PathSchema,
|
|
1614
|
+
surfaceType: SurfaceTypeSchema,
|
|
1615
|
+
description: DescriptionSchema.optional(),
|
|
1616
|
+
icon: IconNameSchema.optional(),
|
|
1617
|
+
order: z.number().int().optional(),
|
|
1618
|
+
targets: SidebarSurfaceTargetsSchema.optional(),
|
|
1619
|
+
devOnly: z.boolean().optional(),
|
|
1620
|
+
requiresAdmin: z.boolean().optional()
|
|
1621
|
+
})
|
|
1622
|
+
])
|
|
1623
|
+
);
|
|
1624
|
+
var SidebarSectionSchema = z.record(z.string(), SidebarNodeSchema).default({});
|
|
1625
|
+
var SidebarNavigationSchema = z.object({
|
|
1626
|
+
primary: SidebarSectionSchema,
|
|
1627
|
+
bottom: SidebarSectionSchema
|
|
1628
|
+
}).default({ primary: {}, bottom: {} });
|
|
1629
|
+
var OrganizationModelNavigationSchema = z.object({
|
|
1630
|
+
sidebar: SidebarNavigationSchema
|
|
1631
|
+
}).default({ sidebar: { primary: {}, bottom: {} } });
|
|
1632
|
+
function getSortedSidebarEntries(nodes) {
|
|
1633
|
+
return Object.entries(nodes).sort(([leftId, left], [rightId, right]) => {
|
|
1634
|
+
const orderDelta = (left.order ?? Number.MAX_SAFE_INTEGER) - (right.order ?? Number.MAX_SAFE_INTEGER);
|
|
1635
|
+
return orderDelta === 0 ? leftId.localeCompare(rightId) : orderDelta;
|
|
1636
|
+
});
|
|
1637
|
+
}
|
|
1638
|
+
z.object({
|
|
1639
|
+
id: ModelIdSchema,
|
|
1640
|
+
label: LabelSchema,
|
|
1641
|
+
placement: z.string().trim().min(1).max(50),
|
|
1642
|
+
surfaceIds: z.array(ModelIdSchema.meta({ ref: "surface" })).default([])
|
|
1643
|
+
});
|
|
1644
|
+
var FirmographicsSchema = z.object({
|
|
1645
|
+
/** Industry vertical (e.g. "Marketing Agency", "Legal", "Real Estate"). */
|
|
1646
|
+
industry: z.string().trim().max(200).optional(),
|
|
1647
|
+
/**
|
|
1648
|
+
* Company headcount band (e.g. "1–10", "11–50", "51–200", "200+").
|
|
1649
|
+
* Free-form string to accommodate any band notation.
|
|
1650
|
+
*/
|
|
1651
|
+
companySize: z.string().trim().max(100).optional(),
|
|
1652
|
+
/**
|
|
1653
|
+
* Primary geographic region the segment operates in or is targeted from
|
|
1654
|
+
* (e.g. "North America", "Europe", "Global").
|
|
1655
|
+
*/
|
|
1656
|
+
region: z.string().trim().max(200).optional()
|
|
1657
|
+
});
|
|
1658
|
+
var CustomerSegmentSchema = z.object({
|
|
1659
|
+
/** Stable unique identifier for the segment (e.g. "segment-smb-agencies"). */
|
|
1660
|
+
id: z.string().trim().min(1).max(100),
|
|
1661
|
+
/** Domain-map iteration order. Convention: multiples of 10 (10, 20, 30, ...) to allow easy insertion. */
|
|
1662
|
+
order: z.number(),
|
|
1663
|
+
/** Human-readable name shown to agents and in UI (e.g. "SMB Marketing Agencies"). */
|
|
1664
|
+
name: z.string().trim().max(200).default(""),
|
|
1665
|
+
/** One or two sentences describing who this segment is. */
|
|
1666
|
+
description: z.string().trim().max(2e3).default(""),
|
|
1667
|
+
/**
|
|
1668
|
+
* The primary job(s) this segment is trying to get done — the goal they hire
|
|
1669
|
+
* a product/service to accomplish. Plain-language narrative or bullet list.
|
|
1670
|
+
*/
|
|
1671
|
+
jobsToBeDone: z.string().trim().max(2e3).default(""),
|
|
1672
|
+
/**
|
|
1673
|
+
* Pains — frustrations, obstacles, and risks the segment experiences
|
|
1674
|
+
* when trying to accomplish their jobs-to-be-done.
|
|
1675
|
+
*/
|
|
1676
|
+
pains: z.array(z.string().trim().max(500)).default([]),
|
|
1677
|
+
/**
|
|
1678
|
+
* Gains — outcomes and benefits the segment desires; positive motivators
|
|
1679
|
+
* beyond merely resolving pains.
|
|
1680
|
+
*/
|
|
1681
|
+
gains: z.array(z.string().trim().max(500)).default([]),
|
|
1682
|
+
/** Firmographic profile for targeting and filtering. */
|
|
1683
|
+
firmographics: FirmographicsSchema.default({}),
|
|
1684
|
+
/**
|
|
1685
|
+
* Value proposition — one or two sentences stating why this organization's
|
|
1686
|
+
* offering is uniquely suited for this segment's needs.
|
|
1687
|
+
*/
|
|
1688
|
+
valueProp: z.string().trim().max(2e3).default("")
|
|
1689
|
+
});
|
|
1690
|
+
var CustomersDomainSchema = z.record(z.string(), CustomerSegmentSchema).refine((record) => Object.entries(record).every(([key, entry]) => entry.id === key), {
|
|
1691
|
+
message: "Each segment entry id must match its map key"
|
|
1692
|
+
}).default({});
|
|
1693
|
+
var DEFAULT_ORGANIZATION_MODEL_CUSTOMERS = {};
|
|
1694
|
+
var PricingModelSchema = z.enum(["one-time", "subscription", "usage-based", "custom"]).meta({ label: "Pricing model", color: "green" });
|
|
1695
|
+
var ProductSchema = z.object({
|
|
1696
|
+
/** Stable unique identifier for the product (e.g. "product-starter-plan"). */
|
|
1697
|
+
id: z.string().trim().min(1).max(100),
|
|
1698
|
+
/** Domain-map iteration order. Convention: multiples of 10 (10, 20, 30, ...) to allow easy insertion. */
|
|
1699
|
+
order: z.number(),
|
|
1700
|
+
/** Human-readable name shown to agents and in UI (e.g. "Starter Plan"). */
|
|
1701
|
+
name: z.string().trim().max(200).default(""),
|
|
1702
|
+
/** One or two sentences describing what this product/service delivers. */
|
|
1703
|
+
description: z.string().trim().max(2e3).default(""),
|
|
1704
|
+
/**
|
|
1705
|
+
* How this product is priced:
|
|
1706
|
+
* - "one-time" — single purchase (setup fee, project fee)
|
|
1707
|
+
* - "subscription" — recurring (monthly/annual SaaS, retainer)
|
|
1708
|
+
* - "usage-based" — metered by consumption (API calls, seats)
|
|
1709
|
+
* - "custom" — negotiated or bespoke pricing
|
|
1710
|
+
*/
|
|
1711
|
+
pricingModel: PricingModelSchema.default("custom"),
|
|
1712
|
+
/** Base price amount (≥ 0). Currency unit defined by `currency`. */
|
|
1713
|
+
price: z.number().min(0).default(0),
|
|
1714
|
+
/**
|
|
1715
|
+
* ISO 4217 currency code (e.g. "USD", "EUR", "GBP").
|
|
1716
|
+
* Free-form string to accommodate any currency; defaults to "USD".
|
|
1717
|
+
*/
|
|
1718
|
+
currency: z.string().trim().max(10).default("USD"),
|
|
1719
|
+
/**
|
|
1720
|
+
* IDs of customer segments this product targets.
|
|
1721
|
+
* Each id must reference a declared `customers.segments[].id`.
|
|
1722
|
+
* Cross-reference enforced in `OrganizationModelSchema.superRefine()`.
|
|
1723
|
+
*/
|
|
1724
|
+
targetSegmentIds: z.array(z.string().trim().min(1)).default([]),
|
|
1725
|
+
/**
|
|
1726
|
+
* Optional: ID of the platform system responsible for delivering this product.
|
|
1727
|
+
* When present, must reference a declared `systems.systems[].id`.
|
|
1728
|
+
* Cross-reference enforced in `OrganizationModelSchema.superRefine()`.
|
|
1729
|
+
*/
|
|
1730
|
+
deliveryFeatureId: z.string().trim().min(1).optional()
|
|
1731
|
+
});
|
|
1732
|
+
var OfferingsDomainSchema = z.record(z.string(), ProductSchema).refine((record) => Object.entries(record).every(([key, entry]) => entry.id === key), {
|
|
1733
|
+
message: "Each product entry id must match its map key"
|
|
1734
|
+
}).default({});
|
|
1735
|
+
var DEFAULT_ORGANIZATION_MODEL_OFFERINGS = {};
|
|
1736
|
+
var RoleIdSchema = ModelIdSchema;
|
|
1737
|
+
var HumanRoleHolderSchema = z.object({
|
|
1738
|
+
kind: z.literal("human"),
|
|
1739
|
+
userId: z.string().trim().min(1).max(200)
|
|
1740
|
+
});
|
|
1741
|
+
var AgentRoleHolderSchema = z.object({
|
|
1742
|
+
kind: z.literal("agent"),
|
|
1743
|
+
agentId: ResourceIdSchema.meta({ ref: "resource" })
|
|
1744
|
+
});
|
|
1745
|
+
var TeamRoleHolderSchema = z.object({
|
|
1746
|
+
kind: z.literal("team"),
|
|
1747
|
+
memberIds: z.array(z.string().trim().min(1).max(200)).min(1)
|
|
1748
|
+
});
|
|
1749
|
+
var RoleHolderSchema = z.discriminatedUnion("kind", [
|
|
1750
|
+
HumanRoleHolderSchema,
|
|
1751
|
+
AgentRoleHolderSchema,
|
|
1752
|
+
TeamRoleHolderSchema
|
|
1753
|
+
]);
|
|
1754
|
+
var RoleHoldersSchema = z.union([RoleHolderSchema, z.array(RoleHolderSchema).min(1)]);
|
|
1755
|
+
var RoleSchema = z.object({
|
|
1756
|
+
/** Stable unique identifier for the role (e.g. "role-ceo", "role-head-of-sales"). */
|
|
1757
|
+
id: RoleIdSchema,
|
|
1758
|
+
/** Domain-map iteration order. Convention: multiples of 10 (10, 20, 30, ...) to allow easy insertion. */
|
|
1759
|
+
order: z.number(),
|
|
1760
|
+
/** Human-readable title shown to agents and in UI (e.g. "CEO", "Head of Sales"). */
|
|
1761
|
+
title: z.string().trim().min(1).max(200),
|
|
1762
|
+
/**
|
|
1763
|
+
* List of responsibilities this role owns - plain-language descriptions of
|
|
1764
|
+
* what the person in this role is accountable for delivering.
|
|
1765
|
+
* Defaults to empty array so minimal role definitions stay concise.
|
|
1766
|
+
*/
|
|
1767
|
+
responsibilities: z.array(z.string().trim().max(500)).default([]),
|
|
1768
|
+
/**
|
|
1769
|
+
* Optional: ID of another role this role reports to.
|
|
1770
|
+
* When present, must reference another `roles[].id` in the same organization.
|
|
1771
|
+
*/
|
|
1772
|
+
reportsToId: RoleIdSchema.meta({ ref: "role" }).optional(),
|
|
1773
|
+
/**
|
|
1774
|
+
* Optional: human, agent, or team holder currently filling this role.
|
|
1775
|
+
* Agent holders reference OM Resource IDs and are validated at the model level.
|
|
1776
|
+
*/
|
|
1777
|
+
heldBy: RoleHoldersSchema.optional(),
|
|
1778
|
+
/**
|
|
1779
|
+
* Optional Systems this role is accountable for.
|
|
1780
|
+
* Cross-reference enforced in `OrganizationModelSchema.superRefine()`.
|
|
1781
|
+
*/
|
|
1782
|
+
responsibleFor: z.array(SystemIdSchema.meta({ ref: "system" })).optional()
|
|
1783
|
+
});
|
|
1784
|
+
var RolesDomainSchema = z.record(z.string(), RoleSchema).refine((record) => Object.entries(record).every(([key, entry]) => entry.id === key), {
|
|
1785
|
+
message: "Each role entry id must match its map key"
|
|
1786
|
+
}).default({});
|
|
1787
|
+
var DEFAULT_ORGANIZATION_MODEL_ROLES = {};
|
|
1788
|
+
var KeyResultSchema = z.object({
|
|
1789
|
+
/** Stable unique identifier for the measurable outcome (e.g. "kr-revenue-q1"). */
|
|
1790
|
+
id: z.string().trim().min(1).max(100),
|
|
1791
|
+
/** Plain-language description of this measurable outcome (e.g. "Increase trial-to-paid conversion"). */
|
|
1792
|
+
description: z.string().trim().min(1).max(500),
|
|
1793
|
+
/**
|
|
1794
|
+
* What is being measured — the metric name (e.g. "monthly revenue", "NPS score",
|
|
1795
|
+
* "trial-to-paid conversion rate"). Free-form string.
|
|
1796
|
+
*/
|
|
1797
|
+
targetMetric: z.string().trim().min(1).max(200),
|
|
1798
|
+
/** Current measured value. Defaults to 0 when not yet tracked. */
|
|
1799
|
+
currentValue: z.number().default(0),
|
|
1800
|
+
/**
|
|
1801
|
+
* Target value to reach for this measurable outcome to be considered achieved.
|
|
1802
|
+
* Optional — omit if the outcome is directional (e.g. "reduce churn") without
|
|
1803
|
+
* a hard numeric target.
|
|
1804
|
+
*/
|
|
1805
|
+
targetValue: z.number().optional()
|
|
1806
|
+
});
|
|
1807
|
+
var ISO_DATE_REGEX = /^\d{4}-\d{2}-\d{2}$/;
|
|
1808
|
+
var ObjectiveSchema = z.object({
|
|
1809
|
+
/** Stable unique identifier for the goal (e.g. "goal-grow-arr-q1-2026"). */
|
|
1810
|
+
id: z.string().trim().min(1).max(100),
|
|
1811
|
+
/** Domain-map iteration order. Convention: multiples of 10 (10, 20, 30, ...) to allow easy insertion. */
|
|
1812
|
+
order: z.number(),
|
|
1813
|
+
/** Plain-language description of what the organization wants to achieve. */
|
|
1814
|
+
description: z.string().trim().min(1).max(1e3),
|
|
1815
|
+
/**
|
|
1816
|
+
* Start of the period this goal is active for — ISO 8601 date string (YYYY-MM-DD).
|
|
1817
|
+
* Must be strictly before `periodEnd`.
|
|
1818
|
+
*/
|
|
1819
|
+
periodStart: z.string().regex(ISO_DATE_REGEX, "periodStart must be an ISO date string (YYYY-MM-DD)"),
|
|
1820
|
+
/**
|
|
1821
|
+
* End of the period this goal is active for — ISO 8601 date string (YYYY-MM-DD).
|
|
1822
|
+
* Must be strictly after `periodStart`.
|
|
1823
|
+
* Enforced via `OrganizationModelSchema.superRefine()`.
|
|
1824
|
+
*/
|
|
1825
|
+
periodEnd: z.string().regex(ISO_DATE_REGEX, "periodEnd must be an ISO date string (YYYY-MM-DD)"),
|
|
1826
|
+
/**
|
|
1827
|
+
* List of measurable outcomes that define success for this goal.
|
|
1828
|
+
* Defaults to empty array so goals can be declared before outcomes are defined.
|
|
1829
|
+
*/
|
|
1830
|
+
keyResults: z.array(KeyResultSchema).default([])
|
|
1831
|
+
});
|
|
1832
|
+
var GoalsDomainSchema = z.record(z.string(), ObjectiveSchema).refine((record) => Object.entries(record).every(([key, entry]) => entry.id === key), {
|
|
1833
|
+
message: "Each objective entry id must match its map key"
|
|
1834
|
+
}).default({});
|
|
1835
|
+
var DEFAULT_ORGANIZATION_MODEL_GOALS = {};
|
|
1836
|
+
var KnowledgeTargetKindSchema = z.enum([
|
|
1837
|
+
"system",
|
|
1838
|
+
"resource",
|
|
1839
|
+
"knowledge",
|
|
1840
|
+
"stage",
|
|
1841
|
+
"action",
|
|
1842
|
+
"role",
|
|
1843
|
+
"goal",
|
|
1844
|
+
"customer-segment",
|
|
1845
|
+
"offering",
|
|
1846
|
+
// D4: content nodes are a valid knowledge target after compound-domain data moved into system.content
|
|
1847
|
+
"content-node"
|
|
1848
|
+
]).meta({ label: "Target kind" });
|
|
1849
|
+
var KnowledgeTargetRefSchema = z.object({
|
|
1850
|
+
kind: KnowledgeTargetKindSchema,
|
|
1851
|
+
// D4: content-node targets use a qualified id format '<system-path>:<local-content-id>'
|
|
1852
|
+
// which contains a colon separator and cannot satisfy ModelIdSchema. Use a permissive
|
|
1853
|
+
// string schema here; business-logic validation of target existence is done in
|
|
1854
|
+
// OrganizationModelSchema.superRefine (knowledgeTargetExists).
|
|
1855
|
+
id: z.string().trim().min(1).max(300)
|
|
1856
|
+
});
|
|
1857
|
+
var LegacyKnowledgeLinkSchema = z.object({
|
|
1858
|
+
nodeId: NodeIdStringSchema
|
|
1859
|
+
});
|
|
1860
|
+
var CanonicalKnowledgeLinkSchema = z.object({
|
|
1861
|
+
target: KnowledgeTargetRefSchema
|
|
1862
|
+
});
|
|
1863
|
+
function nodeIdFromTarget(target) {
|
|
1864
|
+
return `${target.kind}:${target.id}`;
|
|
1865
|
+
}
|
|
1866
|
+
function targetFromNodeId(nodeId2) {
|
|
1867
|
+
const [kind, ...idParts] = nodeId2.split(":");
|
|
1868
|
+
return {
|
|
1869
|
+
kind: KnowledgeTargetKindSchema.parse(kind),
|
|
1870
|
+
id: idParts.join(":")
|
|
1871
|
+
};
|
|
1872
|
+
}
|
|
1873
|
+
var KnowledgeLinkSchema = z.union([CanonicalKnowledgeLinkSchema, LegacyKnowledgeLinkSchema]).transform((link) => {
|
|
1874
|
+
const target = "target" in link ? link.target : targetFromNodeId(link.nodeId);
|
|
1875
|
+
return {
|
|
1876
|
+
target,
|
|
1877
|
+
nodeId: nodeIdFromTarget(target)
|
|
1878
|
+
};
|
|
1879
|
+
});
|
|
1880
|
+
var OrgKnowledgeKindSchema = z.enum(["playbook", "strategy", "reference"]).meta({ label: "Knowledge kind", color: "grape" });
|
|
1881
|
+
var OrgKnowledgeNodeSchema = z.object({
|
|
1882
|
+
id: ModelIdSchema,
|
|
1883
|
+
kind: OrgKnowledgeKindSchema,
|
|
1884
|
+
title: z.string().trim().min(1).max(200),
|
|
1885
|
+
summary: z.string().trim().min(1).max(1e3),
|
|
1886
|
+
icon: IconNameSchema.optional(),
|
|
1887
|
+
/** Canonical documentation URL when body content is a local summary. */
|
|
1888
|
+
externalUrl: z.string().trim().url().max(500).optional(),
|
|
1889
|
+
/** Raw MDX string. Phase 2 will introduce a structured block format. */
|
|
1890
|
+
body: z.string().trim().min(1),
|
|
1891
|
+
/**
|
|
1892
|
+
* Graph links to other OM nodes this knowledge node governs.
|
|
1893
|
+
* Each link emits a `governs` edge: knowledge-node -> target node.
|
|
1894
|
+
*/
|
|
1895
|
+
links: z.array(KnowledgeLinkSchema).default([]),
|
|
1896
|
+
/** Role identifiers that own this knowledge node. */
|
|
1897
|
+
ownerIds: z.array(RoleIdSchema.meta({ ref: "role" })).default([]),
|
|
1898
|
+
/** ISO date string (YYYY-MM-DD or full ISO 8601) of last meaningful update. */
|
|
1899
|
+
updatedAt: z.string().trim().min(1).max(50)
|
|
1900
|
+
});
|
|
1901
|
+
var KnowledgeDomainSchema = z.record(ModelIdSchema, OrgKnowledgeNodeSchema).default({});
|
|
1902
|
+
var PolicyIdSchema = ModelIdSchema;
|
|
1903
|
+
var PolicyApplicabilitySchema = z.object({
|
|
1904
|
+
systemIds: z.array(ModelIdSchema.meta({ ref: "system" })).default([]),
|
|
1905
|
+
actionIds: z.array(ModelIdSchema.meta({ ref: "action" })).default([]),
|
|
1906
|
+
resourceIds: z.array(ModelIdSchema.meta({ ref: "resource" })).default([]),
|
|
1907
|
+
roleIds: z.array(ModelIdSchema.meta({ ref: "role" })).default([])
|
|
1908
|
+
});
|
|
1909
|
+
var PolicyTriggerSchema = z.discriminatedUnion("kind", [
|
|
1910
|
+
z.object({
|
|
1911
|
+
kind: z.literal("event"),
|
|
1912
|
+
eventId: EventIdSchema.meta({ ref: "event" })
|
|
1913
|
+
}),
|
|
1914
|
+
z.object({
|
|
1915
|
+
kind: z.literal("action-invocation"),
|
|
1916
|
+
actionId: ModelIdSchema.meta({ ref: "action" })
|
|
1917
|
+
}),
|
|
1918
|
+
z.object({
|
|
1919
|
+
kind: z.literal("schedule"),
|
|
1920
|
+
cron: z.string().trim().min(1).max(120)
|
|
1921
|
+
}),
|
|
1922
|
+
z.object({
|
|
1923
|
+
kind: z.literal("manual")
|
|
1924
|
+
})
|
|
1925
|
+
]);
|
|
1926
|
+
var PolicyPredicateSchema = z.discriminatedUnion("kind", [
|
|
1927
|
+
z.object({
|
|
1928
|
+
kind: z.literal("always")
|
|
1929
|
+
}),
|
|
1930
|
+
z.object({
|
|
1931
|
+
kind: z.literal("expression"),
|
|
1932
|
+
expression: z.string().trim().min(1).max(2e3)
|
|
1933
|
+
}),
|
|
1934
|
+
z.object({
|
|
1935
|
+
kind: z.literal("threshold"),
|
|
1936
|
+
metric: ModelIdSchema,
|
|
1937
|
+
operator: z.enum(["lt", "lte", "eq", "gte", "gt"]).meta({ label: "Operator" }),
|
|
1938
|
+
value: z.number()
|
|
1939
|
+
})
|
|
1940
|
+
]);
|
|
1941
|
+
var PolicyEffectSchema = z.discriminatedUnion("kind", [
|
|
1942
|
+
z.object({
|
|
1943
|
+
kind: z.literal("require-approval"),
|
|
1944
|
+
roleId: ModelIdSchema.meta({ ref: "role" }).optional()
|
|
1945
|
+
}),
|
|
1946
|
+
z.object({
|
|
1947
|
+
kind: z.literal("invoke-action"),
|
|
1948
|
+
actionId: ModelIdSchema.meta({ ref: "action" })
|
|
1949
|
+
}),
|
|
1950
|
+
z.object({
|
|
1951
|
+
kind: z.literal("notify-role"),
|
|
1952
|
+
roleId: ModelIdSchema.meta({ ref: "role" })
|
|
1953
|
+
}),
|
|
1954
|
+
z.object({
|
|
1955
|
+
kind: z.literal("block")
|
|
1956
|
+
})
|
|
1957
|
+
]);
|
|
1958
|
+
var PolicySchema = z.object({
|
|
1959
|
+
id: PolicyIdSchema,
|
|
1960
|
+
/** Domain-map iteration order. Convention: multiples of 10 (10, 20, 30, ...) to allow easy insertion. */
|
|
1961
|
+
order: z.number(),
|
|
1962
|
+
label: LabelSchema,
|
|
1963
|
+
description: DescriptionSchema.optional(),
|
|
1964
|
+
trigger: PolicyTriggerSchema,
|
|
1965
|
+
predicate: PolicyPredicateSchema.default({ kind: "always" }),
|
|
1966
|
+
actions: z.array(PolicyEffectSchema).min(1),
|
|
1967
|
+
appliesTo: PolicyApplicabilitySchema.default({
|
|
1968
|
+
systemIds: [],
|
|
1969
|
+
actionIds: [],
|
|
1970
|
+
resourceIds: [],
|
|
1971
|
+
roleIds: []
|
|
1972
|
+
}),
|
|
1973
|
+
lifecycle: z.enum(["draft", "beta", "active", "deprecated", "archived"]).meta({ label: "Lifecycle", color: "teal" }).default("active")
|
|
1974
|
+
});
|
|
1975
|
+
var PoliciesDomainSchema = z.record(z.string(), PolicySchema).refine((record) => Object.entries(record).every(([key, entry]) => entry.id === key), {
|
|
1976
|
+
message: "Each policy entry id must match its map key"
|
|
1977
|
+
}).default({});
|
|
1978
|
+
var DEFAULT_ORGANIZATION_MODEL_POLICIES = {};
|
|
1979
|
+
|
|
1980
|
+
// ../core/src/organization-model/schema.ts
|
|
1981
|
+
z.enum([
|
|
1982
|
+
"branding",
|
|
1983
|
+
"identity",
|
|
1984
|
+
"customers",
|
|
1985
|
+
"offerings",
|
|
1986
|
+
"roles",
|
|
1987
|
+
"goals",
|
|
1988
|
+
"systems",
|
|
1989
|
+
"resources",
|
|
1990
|
+
"actions",
|
|
1991
|
+
"entities",
|
|
1992
|
+
"policies",
|
|
1993
|
+
"knowledge"
|
|
1994
|
+
]);
|
|
1995
|
+
var OrganizationModelDomainMetadataSchema = z.object({
|
|
1996
|
+
version: z.literal(1).default(1),
|
|
1997
|
+
lastModified: z.string().regex(/^\d{4}-\d{2}-\d{2}$/, "lastModified must be an ISO date string (YYYY-MM-DD)")
|
|
1998
|
+
});
|
|
1999
|
+
var DEFAULT_ORGANIZATION_MODEL_DOMAIN_METADATA = {
|
|
2000
|
+
branding: { version: 1, lastModified: "2026-05-10" },
|
|
2001
|
+
identity: { version: 1, lastModified: "2026-05-10" },
|
|
2002
|
+
customers: { version: 1, lastModified: "2026-05-10" },
|
|
2003
|
+
offerings: { version: 1, lastModified: "2026-05-10" },
|
|
2004
|
+
roles: { version: 1, lastModified: "2026-05-10" },
|
|
2005
|
+
goals: { version: 1, lastModified: "2026-05-10" },
|
|
2006
|
+
systems: { version: 1, lastModified: "2026-05-10" },
|
|
2007
|
+
resources: { version: 1, lastModified: "2026-05-10" },
|
|
2008
|
+
actions: { version: 1, lastModified: "2026-05-10" },
|
|
2009
|
+
entities: { version: 1, lastModified: "2026-05-10" },
|
|
2010
|
+
policies: { version: 1, lastModified: "2026-05-10" },
|
|
2011
|
+
knowledge: { version: 1, lastModified: "2026-05-10" }
|
|
2012
|
+
};
|
|
2013
|
+
var OrganizationModelDomainMetadataByDomainSchema = z.object({
|
|
2014
|
+
branding: OrganizationModelDomainMetadataSchema,
|
|
2015
|
+
identity: OrganizationModelDomainMetadataSchema,
|
|
2016
|
+
customers: OrganizationModelDomainMetadataSchema,
|
|
2017
|
+
offerings: OrganizationModelDomainMetadataSchema,
|
|
2018
|
+
roles: OrganizationModelDomainMetadataSchema,
|
|
2019
|
+
goals: OrganizationModelDomainMetadataSchema,
|
|
2020
|
+
systems: OrganizationModelDomainMetadataSchema,
|
|
2021
|
+
resources: OrganizationModelDomainMetadataSchema,
|
|
2022
|
+
actions: OrganizationModelDomainMetadataSchema,
|
|
2023
|
+
entities: OrganizationModelDomainMetadataSchema,
|
|
2024
|
+
policies: OrganizationModelDomainMetadataSchema,
|
|
2025
|
+
knowledge: OrganizationModelDomainMetadataSchema
|
|
2026
|
+
}).partial().default(DEFAULT_ORGANIZATION_MODEL_DOMAIN_METADATA).transform((metadata) => ({ ...DEFAULT_ORGANIZATION_MODEL_DOMAIN_METADATA, ...metadata }));
|
|
2027
|
+
var OrganizationModelSchemaBase = z.object({
|
|
2028
|
+
version: z.literal(1).default(1),
|
|
2029
|
+
domainMetadata: OrganizationModelDomainMetadataByDomainSchema,
|
|
2030
|
+
branding: OrganizationModelBrandingSchema,
|
|
2031
|
+
navigation: OrganizationModelNavigationSchema,
|
|
2032
|
+
identity: IdentityDomainSchema.default(DEFAULT_ORGANIZATION_MODEL_IDENTITY),
|
|
2033
|
+
customers: CustomersDomainSchema.default(DEFAULT_ORGANIZATION_MODEL_CUSTOMERS),
|
|
2034
|
+
offerings: OfferingsDomainSchema.default(DEFAULT_ORGANIZATION_MODEL_OFFERINGS),
|
|
2035
|
+
roles: RolesDomainSchema.default(DEFAULT_ORGANIZATION_MODEL_ROLES),
|
|
2036
|
+
goals: GoalsDomainSchema.default(DEFAULT_ORGANIZATION_MODEL_GOALS),
|
|
2037
|
+
systems: SystemsDomainSchema.default(DEFAULT_ORGANIZATION_MODEL_SYSTEMS),
|
|
2038
|
+
resources: ResourcesDomainSchema.default(DEFAULT_ORGANIZATION_MODEL_RESOURCES),
|
|
2039
|
+
actions: ActionsDomainSchema.default(DEFAULT_ORGANIZATION_MODEL_ACTIONS),
|
|
2040
|
+
entities: EntitiesDomainSchema.default(DEFAULT_ORGANIZATION_MODEL_ENTITIES),
|
|
2041
|
+
policies: PoliciesDomainSchema.default(DEFAULT_ORGANIZATION_MODEL_POLICIES),
|
|
2042
|
+
// D3: flat Record<id, OrgKnowledgeNode> — no wrapper object
|
|
2043
|
+
knowledge: KnowledgeDomainSchema.default({})
|
|
2044
|
+
});
|
|
2045
|
+
function addIssue(ctx, path, message) {
|
|
2046
|
+
ctx.addIssue({
|
|
2047
|
+
code: z.ZodIssueCode.custom,
|
|
2048
|
+
path,
|
|
2049
|
+
message
|
|
2050
|
+
});
|
|
2051
|
+
}
|
|
2052
|
+
function isLifecycleEnabled(lifecycle, enabled) {
|
|
2053
|
+
if (enabled === false) return false;
|
|
2054
|
+
return lifecycle !== "deprecated" && lifecycle !== "archived";
|
|
2055
|
+
}
|
|
2056
|
+
function defaultSystemPathFor(id) {
|
|
2057
|
+
return `/${id.replaceAll(".", "/")}`;
|
|
2058
|
+
}
|
|
2059
|
+
function asRoleHolderArray(heldBy) {
|
|
2060
|
+
return Array.isArray(heldBy) ? heldBy : [heldBy];
|
|
2061
|
+
}
|
|
2062
|
+
function isKnowledgeKindCompatibleWithTarget(knowledgeKind, targetKind) {
|
|
2063
|
+
if (knowledgeKind === "reference") return true;
|
|
2064
|
+
if (knowledgeKind === "playbook") {
|
|
2065
|
+
return ["system", "resource", "stage", "action"].includes(targetKind);
|
|
2066
|
+
}
|
|
2067
|
+
if (knowledgeKind === "strategy") {
|
|
2068
|
+
return ["system", "goal", "offering", "customer-segment"].includes(targetKind);
|
|
2069
|
+
}
|
|
2070
|
+
return false;
|
|
2071
|
+
}
|
|
2072
|
+
var OrganizationModelSchema = OrganizationModelSchemaBase.superRefine((model, ctx) => {
|
|
2073
|
+
function collectAllSystems(systems, prefix = "", schemaPath = ["systems"]) {
|
|
2074
|
+
const result = [];
|
|
2075
|
+
for (const [key, system] of Object.entries(systems)) {
|
|
2076
|
+
const path = prefix ? `${prefix}.${key}` : key;
|
|
2077
|
+
const currentSchemaPath = [...schemaPath, key];
|
|
2078
|
+
result.push({ path, schemaPath: currentSchemaPath, system });
|
|
2079
|
+
if (system.subsystems !== void 0) {
|
|
2080
|
+
result.push(...collectAllSystems(system.subsystems, path, [...currentSchemaPath, "subsystems"]));
|
|
2081
|
+
}
|
|
2082
|
+
}
|
|
2083
|
+
return result;
|
|
2084
|
+
}
|
|
2085
|
+
const allSystems = collectAllSystems(model.systems);
|
|
2086
|
+
const systemsById = /* @__PURE__ */ new Map();
|
|
2087
|
+
for (const { path, system } of allSystems) {
|
|
2088
|
+
systemsById.set(path, system);
|
|
2089
|
+
systemsById.set(system.id, system);
|
|
2090
|
+
}
|
|
2091
|
+
const systemIdsByEffectivePath = /* @__PURE__ */ new Map();
|
|
2092
|
+
allSystems.forEach(({ path, schemaPath, system }) => {
|
|
2093
|
+
if (system.parentSystemId !== void 0 && !systemsById.has(system.parentSystemId)) {
|
|
2094
|
+
addIssue(
|
|
2095
|
+
ctx,
|
|
2096
|
+
[...schemaPath, "parentSystemId"],
|
|
2097
|
+
`System "${system.id}" references unknown parent "${system.parentSystemId}"`
|
|
2098
|
+
);
|
|
2099
|
+
}
|
|
2100
|
+
const hasChildren = Object.keys(system.subsystems ?? {}).length > 0 || allSystems.some((candidate) => candidate.path.startsWith(`${path}.`) && !candidate.path.slice(path.length + 1).includes("."));
|
|
2101
|
+
const contributesRoutePath = system.ui?.path !== void 0 || system.path !== void 0 || !hasChildren;
|
|
2102
|
+
if (contributesRoutePath) {
|
|
2103
|
+
const effectivePath = system.ui?.path ?? system.path ?? defaultSystemPathFor(path);
|
|
2104
|
+
const existingSystemId = systemIdsByEffectivePath.get(effectivePath);
|
|
2105
|
+
if (existingSystemId !== void 0) {
|
|
2106
|
+
addIssue(
|
|
2107
|
+
ctx,
|
|
2108
|
+
[...schemaPath, system.ui?.path !== void 0 ? "ui" : "path"],
|
|
2109
|
+
`System "${path}" effective path "${effectivePath}" duplicates system "${existingSystemId}"`
|
|
2110
|
+
);
|
|
2111
|
+
} else {
|
|
2112
|
+
systemIdsByEffectivePath.set(effectivePath, path);
|
|
2113
|
+
}
|
|
2114
|
+
}
|
|
2115
|
+
if (hasChildren && isLifecycleEnabled(system.lifecycle, system.enabled)) {
|
|
2116
|
+
const hasEnabledDescendant = Object.values(system.subsystems ?? {}).some(
|
|
2117
|
+
(candidate) => isLifecycleEnabled(candidate.lifecycle, candidate.enabled)
|
|
2118
|
+
) || allSystems.some(
|
|
2119
|
+
(candidate) => candidate.path.startsWith(`${path}.`) && !candidate.path.slice(path.length + 1).includes(".") && isLifecycleEnabled(candidate.system.lifecycle, candidate.system.enabled)
|
|
2120
|
+
);
|
|
2121
|
+
if (!hasEnabledDescendant) {
|
|
2122
|
+
addIssue(
|
|
2123
|
+
ctx,
|
|
2124
|
+
[...schemaPath, "lifecycle"],
|
|
2125
|
+
`System "${path}" is active but has no active descendants`
|
|
2126
|
+
);
|
|
2127
|
+
}
|
|
2128
|
+
}
|
|
2129
|
+
});
|
|
2130
|
+
allSystems.forEach(({ schemaPath, system }) => {
|
|
2131
|
+
const visited = /* @__PURE__ */ new Set();
|
|
2132
|
+
let currentParentId = system.parentSystemId;
|
|
2133
|
+
while (currentParentId !== void 0) {
|
|
2134
|
+
if (currentParentId === system.id || visited.has(currentParentId)) {
|
|
2135
|
+
addIssue(ctx, [...schemaPath, "parentSystemId"], `System "${system.id}" has a parent cycle`);
|
|
2136
|
+
return;
|
|
2137
|
+
}
|
|
2138
|
+
visited.add(currentParentId);
|
|
2139
|
+
currentParentId = systemsById.get(currentParentId)?.parentSystemId;
|
|
2140
|
+
}
|
|
2141
|
+
});
|
|
2142
|
+
function normalizeRoutePath(path) {
|
|
2143
|
+
return path.length > 1 ? path.replace(/\/+$/, "") : path;
|
|
2144
|
+
}
|
|
2145
|
+
const sidebarNodeIds = /* @__PURE__ */ new Map();
|
|
2146
|
+
const sidebarSurfacePaths = /* @__PURE__ */ new Map();
|
|
2147
|
+
const sidebarSurfaces = [];
|
|
2148
|
+
function collectSidebarNodes(nodes, schemaPath) {
|
|
2149
|
+
Object.entries(nodes).forEach(([nodeId2, node]) => {
|
|
2150
|
+
const nodePath = [...schemaPath, nodeId2];
|
|
2151
|
+
const existingNodePath = sidebarNodeIds.get(nodeId2);
|
|
2152
|
+
if (existingNodePath !== void 0) {
|
|
2153
|
+
addIssue(ctx, nodePath, `Sidebar node id "${nodeId2}" duplicates another sidebar node`);
|
|
2154
|
+
} else {
|
|
2155
|
+
sidebarNodeIds.set(nodeId2, nodePath);
|
|
2156
|
+
}
|
|
2157
|
+
if (node.type === "group") {
|
|
2158
|
+
collectSidebarNodes(node.children, [...nodePath, "children"]);
|
|
2159
|
+
return;
|
|
2160
|
+
}
|
|
2161
|
+
sidebarSurfaces.push({ id: nodeId2, node, path: nodePath });
|
|
2162
|
+
const normalizedPath = normalizeRoutePath(node.path);
|
|
2163
|
+
const existingSurfaceId = sidebarSurfacePaths.get(normalizedPath);
|
|
2164
|
+
if (existingSurfaceId !== void 0) {
|
|
2165
|
+
addIssue(
|
|
2166
|
+
ctx,
|
|
2167
|
+
[...nodePath, "path"],
|
|
2168
|
+
`Sidebar surface path "${node.path}" duplicates surface "${existingSurfaceId}"`
|
|
2169
|
+
);
|
|
2170
|
+
} else {
|
|
2171
|
+
sidebarSurfacePaths.set(normalizedPath, nodeId2);
|
|
2172
|
+
}
|
|
2173
|
+
node.targets?.systems?.forEach((systemId, systemIndex) => {
|
|
2174
|
+
if (!systemsById.has(systemId)) {
|
|
2175
|
+
addIssue(
|
|
2176
|
+
ctx,
|
|
2177
|
+
[...nodePath, "targets", "systems", systemIndex],
|
|
2178
|
+
`Sidebar surface "${nodeId2}" references unknown system "${systemId}"`
|
|
2179
|
+
);
|
|
2180
|
+
}
|
|
2181
|
+
});
|
|
2182
|
+
});
|
|
2183
|
+
}
|
|
2184
|
+
collectSidebarNodes(model.navigation.sidebar.primary, ["navigation", "sidebar", "primary"]);
|
|
2185
|
+
collectSidebarNodes(model.navigation.sidebar.bottom, ["navigation", "sidebar", "bottom"]);
|
|
2186
|
+
const segmentsById = new Map(Object.entries(model.customers));
|
|
2187
|
+
Object.values(model.offerings).forEach((product) => {
|
|
2188
|
+
product.targetSegmentIds.forEach((segmentId, segmentIndex) => {
|
|
2189
|
+
if (!segmentsById.has(segmentId)) {
|
|
2190
|
+
addIssue(
|
|
2191
|
+
ctx,
|
|
2192
|
+
["offerings", product.id, "targetSegmentIds", segmentIndex],
|
|
2193
|
+
`Product "${product.id}" references unknown customer segment "${segmentId}"`
|
|
2194
|
+
);
|
|
2195
|
+
}
|
|
2196
|
+
});
|
|
2197
|
+
if (product.deliveryFeatureId !== void 0 && !systemsById.has(product.deliveryFeatureId)) {
|
|
2198
|
+
addIssue(
|
|
2199
|
+
ctx,
|
|
2200
|
+
["offerings", product.id, "deliveryFeatureId"],
|
|
2201
|
+
`Product "${product.id}" references unknown delivery system "${product.deliveryFeatureId}"`
|
|
2202
|
+
);
|
|
2203
|
+
}
|
|
2204
|
+
});
|
|
2205
|
+
Object.values(model.goals).forEach((objective) => {
|
|
2206
|
+
if (objective.periodEnd <= objective.periodStart) {
|
|
2207
|
+
addIssue(
|
|
2208
|
+
ctx,
|
|
2209
|
+
["goals", objective.id, "periodEnd"],
|
|
2210
|
+
`Goal "${objective.id}" has periodEnd "${objective.periodEnd}" which must be strictly after periodStart "${objective.periodStart}"`
|
|
2211
|
+
);
|
|
2212
|
+
}
|
|
2213
|
+
});
|
|
2214
|
+
const goalsById = new Map(Object.entries(model.goals));
|
|
2215
|
+
const knowledgeById = new Map(Object.entries(model.knowledge));
|
|
2216
|
+
const actionsById = new Map(Object.entries(model.actions));
|
|
2217
|
+
const entitiesById = new Map(Object.entries(model.entities));
|
|
2218
|
+
const policiesById = new Map(Object.entries(model.policies));
|
|
2219
|
+
sidebarSurfaces.forEach(({ id, node, path }) => {
|
|
2220
|
+
node.targets?.entities?.forEach((entityId, entityIndex) => {
|
|
2221
|
+
if (!entitiesById.has(entityId)) {
|
|
2222
|
+
addIssue(
|
|
2223
|
+
ctx,
|
|
2224
|
+
[...path, "targets", "entities", entityIndex],
|
|
2225
|
+
`Sidebar surface "${id}" references unknown entity "${entityId}"`
|
|
2226
|
+
);
|
|
2227
|
+
}
|
|
2228
|
+
});
|
|
2229
|
+
node.targets?.actions?.forEach((actionId, actionIndex) => {
|
|
2230
|
+
if (!actionsById.has(actionId)) {
|
|
2231
|
+
addIssue(
|
|
2232
|
+
ctx,
|
|
2233
|
+
[...path, "targets", "actions", actionIndex],
|
|
2234
|
+
`Sidebar surface "${id}" references unknown action "${actionId}"`
|
|
2235
|
+
);
|
|
2236
|
+
}
|
|
2237
|
+
});
|
|
2238
|
+
});
|
|
2239
|
+
Object.values(model.entities).forEach((entity) => {
|
|
2240
|
+
if (!systemsById.has(entity.ownedBySystemId)) {
|
|
2241
|
+
addIssue(
|
|
2242
|
+
ctx,
|
|
2243
|
+
["entities", entity.id, "ownedBySystemId"],
|
|
2244
|
+
`Entity "${entity.id}" references unknown ownedBySystemId "${entity.ownedBySystemId}"`
|
|
2245
|
+
);
|
|
2246
|
+
}
|
|
2247
|
+
entity.links?.forEach((link, linkIndex) => {
|
|
2248
|
+
if (!entitiesById.has(link.toEntity)) {
|
|
2249
|
+
addIssue(
|
|
2250
|
+
ctx,
|
|
2251
|
+
["entities", entity.id, "links", linkIndex, "toEntity"],
|
|
2252
|
+
`Entity "${entity.id}" links to unknown entity "${link.toEntity}"`
|
|
2253
|
+
);
|
|
2254
|
+
}
|
|
2255
|
+
});
|
|
2256
|
+
});
|
|
2257
|
+
const rolesById = new Map(Object.entries(model.roles));
|
|
2258
|
+
Object.values(model.roles).forEach((role) => {
|
|
2259
|
+
if (role.reportsToId !== void 0 && !rolesById.has(role.reportsToId)) {
|
|
2260
|
+
addIssue(
|
|
2261
|
+
ctx,
|
|
2262
|
+
["roles", role.id, "reportsToId"],
|
|
2263
|
+
`Role "${role.id}" references unknown reportsToId "${role.reportsToId}"`
|
|
2264
|
+
);
|
|
2265
|
+
}
|
|
2266
|
+
});
|
|
2267
|
+
Object.values(model.roles).forEach((role) => {
|
|
2268
|
+
const visited = /* @__PURE__ */ new Set();
|
|
2269
|
+
let currentReportsToId = role.reportsToId;
|
|
2270
|
+
while (currentReportsToId !== void 0) {
|
|
2271
|
+
if (currentReportsToId === role.id || visited.has(currentReportsToId)) {
|
|
2272
|
+
addIssue(ctx, ["roles", role.id, "reportsToId"], `Role "${role.id}" has a reportsToId cycle`);
|
|
2273
|
+
return;
|
|
2274
|
+
}
|
|
2275
|
+
visited.add(currentReportsToId);
|
|
2276
|
+
currentReportsToId = rolesById.get(currentReportsToId)?.reportsToId;
|
|
2277
|
+
}
|
|
2278
|
+
});
|
|
2279
|
+
Object.values(model.roles).forEach((role) => {
|
|
2280
|
+
role.responsibleFor?.forEach((systemId, systemIndex) => {
|
|
2281
|
+
if (!systemsById.has(systemId)) {
|
|
2282
|
+
addIssue(
|
|
2283
|
+
ctx,
|
|
2284
|
+
["roles", role.id, "responsibleFor", systemIndex],
|
|
2285
|
+
`Role "${role.id}" references unknown responsibleFor system "${systemId}"`
|
|
2286
|
+
);
|
|
2287
|
+
}
|
|
2288
|
+
});
|
|
2289
|
+
});
|
|
2290
|
+
allSystems.forEach(({ schemaPath, system }) => {
|
|
2291
|
+
if (system.responsibleRoleId !== void 0 && !rolesById.has(system.responsibleRoleId)) {
|
|
2292
|
+
addIssue(
|
|
2293
|
+
ctx,
|
|
2294
|
+
[...schemaPath, "responsibleRoleId"],
|
|
2295
|
+
`System "${system.id}" references unknown responsibleRoleId "${system.responsibleRoleId}"`
|
|
2296
|
+
);
|
|
2297
|
+
}
|
|
2298
|
+
system.governedByKnowledge?.forEach((nodeId2, nodeIndex) => {
|
|
2299
|
+
if (!knowledgeById.has(nodeId2)) {
|
|
2300
|
+
addIssue(
|
|
2301
|
+
ctx,
|
|
2302
|
+
[...schemaPath, "governedByKnowledge", nodeIndex],
|
|
2303
|
+
`System "${system.id}" references unknown knowledge node "${nodeId2}"`
|
|
2304
|
+
);
|
|
2305
|
+
}
|
|
2306
|
+
});
|
|
2307
|
+
system.drivesGoals?.forEach((goalId, goalIndex) => {
|
|
2308
|
+
if (!goalsById.has(goalId)) {
|
|
2309
|
+
addIssue(
|
|
2310
|
+
ctx,
|
|
2311
|
+
[...schemaPath, "drivesGoals", goalIndex],
|
|
2312
|
+
`System "${system.id}" references unknown goal "${goalId}"`
|
|
2313
|
+
);
|
|
2314
|
+
}
|
|
2315
|
+
});
|
|
2316
|
+
system.actions?.forEach((actionRef, actionIndex) => {
|
|
2317
|
+
if (!actionsById.has(actionRef.actionId)) {
|
|
2318
|
+
addIssue(
|
|
2319
|
+
ctx,
|
|
2320
|
+
[...schemaPath, "actions", actionIndex, "actionId"],
|
|
2321
|
+
`System "${system.id}" references unknown action "${actionRef.actionId}"`
|
|
2322
|
+
);
|
|
2323
|
+
}
|
|
2324
|
+
});
|
|
2325
|
+
system.policies?.forEach((policyId, policyIndex) => {
|
|
2326
|
+
if (!policiesById.has(policyId)) {
|
|
2327
|
+
addIssue(
|
|
2328
|
+
ctx,
|
|
2329
|
+
[...schemaPath, "policies", policyIndex],
|
|
2330
|
+
`System "${system.id}" references unknown policy "${policyId}"`
|
|
2331
|
+
);
|
|
2332
|
+
}
|
|
2333
|
+
});
|
|
2334
|
+
});
|
|
2335
|
+
Object.values(model.actions).forEach((action) => {
|
|
2336
|
+
action.affects?.forEach((entityId, entityIndex) => {
|
|
2337
|
+
if (!entitiesById.has(entityId)) {
|
|
2338
|
+
addIssue(
|
|
2339
|
+
ctx,
|
|
2340
|
+
["actions", action.id, "affects", entityIndex],
|
|
2341
|
+
`Action "${action.id}" affects unknown entity "${entityId}"`
|
|
2342
|
+
);
|
|
2343
|
+
}
|
|
2344
|
+
});
|
|
2345
|
+
});
|
|
2346
|
+
const resourcesById = new Map(Object.entries(model.resources));
|
|
2347
|
+
sidebarSurfaces.forEach(({ id, node, path }) => {
|
|
2348
|
+
node.targets?.resources?.forEach((resourceId, resourceIndex) => {
|
|
2349
|
+
if (!resourcesById.has(resourceId)) {
|
|
2350
|
+
addIssue(
|
|
2351
|
+
ctx,
|
|
2352
|
+
[...path, "targets", "resources", resourceIndex],
|
|
2353
|
+
`Sidebar surface "${id}" references unknown resource "${resourceId}"`
|
|
2354
|
+
);
|
|
2355
|
+
}
|
|
2356
|
+
});
|
|
2357
|
+
});
|
|
2358
|
+
const stageIds = /* @__PURE__ */ new Set();
|
|
2359
|
+
const actionIds = new Set(Object.keys(model.actions));
|
|
2360
|
+
const offeringsById = new Map(Object.entries(model.offerings));
|
|
2361
|
+
Object.values(model.policies).forEach((policy) => {
|
|
2362
|
+
policy.appliesTo.systemIds.forEach((systemId, systemIndex) => {
|
|
2363
|
+
if (!systemsById.has(systemId)) {
|
|
2364
|
+
addIssue(
|
|
2365
|
+
ctx,
|
|
2366
|
+
["policies", policy.id, "appliesTo", "systemIds", systemIndex],
|
|
2367
|
+
`Policy "${policy.id}" applies to unknown system "${systemId}"`
|
|
2368
|
+
);
|
|
2369
|
+
}
|
|
2370
|
+
});
|
|
2371
|
+
policy.appliesTo.actionIds.forEach((actionId, actionIndex) => {
|
|
2372
|
+
if (!actionsById.has(actionId)) {
|
|
2373
|
+
addIssue(
|
|
2374
|
+
ctx,
|
|
2375
|
+
["policies", policy.id, "appliesTo", "actionIds", actionIndex],
|
|
2376
|
+
`Policy "${policy.id}" applies to unknown action "${actionId}"`
|
|
2377
|
+
);
|
|
2378
|
+
}
|
|
2379
|
+
});
|
|
2380
|
+
policy.actions.forEach((action, actionIndex) => {
|
|
2381
|
+
if (action.kind === "invoke-action" && !actionsById.has(action.actionId)) {
|
|
2382
|
+
addIssue(
|
|
2383
|
+
ctx,
|
|
2384
|
+
["policies", policy.id, "actions", actionIndex, "actionId"],
|
|
2385
|
+
`Policy "${policy.id}" invokes unknown action "${action.actionId}"`
|
|
2386
|
+
);
|
|
2387
|
+
}
|
|
2388
|
+
if ((action.kind === "notify-role" || action.kind === "require-approval") && action.roleId !== void 0 && !rolesById.has(action.roleId)) {
|
|
2389
|
+
addIssue(
|
|
2390
|
+
ctx,
|
|
2391
|
+
["policies", policy.id, "actions", actionIndex, "roleId"],
|
|
2392
|
+
`Policy "${policy.id}" references unknown role "${action.roleId}"`
|
|
2393
|
+
);
|
|
2394
|
+
}
|
|
2395
|
+
});
|
|
2396
|
+
if (policy.trigger.kind === "action-invocation" && !actionsById.has(policy.trigger.actionId)) {
|
|
2397
|
+
addIssue(
|
|
2398
|
+
ctx,
|
|
2399
|
+
["policies", policy.id, "trigger", "actionId"],
|
|
2400
|
+
`Policy "${policy.id}" references unknown trigger action "${policy.trigger.actionId}"`
|
|
2401
|
+
);
|
|
2402
|
+
}
|
|
2403
|
+
});
|
|
2404
|
+
function knowledgeTargetExists(kind, id) {
|
|
2405
|
+
if (kind === "system") return systemsById.has(id);
|
|
2406
|
+
if (kind === "resource") return resourcesById.has(id);
|
|
2407
|
+
if (kind === "knowledge") return knowledgeById.has(id);
|
|
2408
|
+
if (kind === "stage") return stageIds.has(id);
|
|
2409
|
+
if (kind === "action") return actionIds.has(id);
|
|
2410
|
+
if (kind === "role") return rolesById.has(id);
|
|
2411
|
+
if (kind === "goal") return goalsById.has(id);
|
|
2412
|
+
if (kind === "customer-segment") return segmentsById.has(id);
|
|
2413
|
+
if (kind === "offering") return offeringsById.has(id);
|
|
2414
|
+
return false;
|
|
2415
|
+
}
|
|
2416
|
+
Object.entries(model.knowledge).forEach(([nodeId2, node]) => {
|
|
2417
|
+
node.links.forEach((link, linkIndex) => {
|
|
2418
|
+
if (!knowledgeTargetExists(link.target.kind, link.target.id)) {
|
|
2419
|
+
addIssue(
|
|
2420
|
+
ctx,
|
|
2421
|
+
["knowledge", nodeId2, "links", linkIndex, "target"],
|
|
2422
|
+
`Knowledge node "${node.id}" references unknown ${link.target.kind} target "${link.target.id}"`
|
|
2423
|
+
);
|
|
2424
|
+
}
|
|
2425
|
+
if (!isKnowledgeKindCompatibleWithTarget(node.kind, link.target.kind)) {
|
|
2426
|
+
addIssue(
|
|
2427
|
+
ctx,
|
|
2428
|
+
["knowledge", nodeId2, "links", linkIndex, "target", "kind"],
|
|
2429
|
+
`Knowledge node "${node.id}" kind "${node.kind}" cannot govern ${link.target.kind} targets`
|
|
2430
|
+
);
|
|
2431
|
+
}
|
|
2432
|
+
});
|
|
2433
|
+
});
|
|
2434
|
+
Object.values(model.resources).forEach((resource) => {
|
|
2435
|
+
if (!systemsById.has(resource.systemPath)) {
|
|
2436
|
+
addIssue(
|
|
2437
|
+
ctx,
|
|
2438
|
+
["resources", resource.id, "systemPath"],
|
|
2439
|
+
`Resource "${resource.id}" references unknown system path "${resource.systemPath}"`
|
|
2440
|
+
);
|
|
2441
|
+
}
|
|
2442
|
+
if (resource.ownerRoleId !== void 0 && !rolesById.has(resource.ownerRoleId)) {
|
|
2443
|
+
addIssue(
|
|
2444
|
+
ctx,
|
|
2445
|
+
["resources", resource.id, "ownerRoleId"],
|
|
2446
|
+
`Resource "${resource.id}" references unknown ownerRoleId "${resource.ownerRoleId}"`
|
|
2447
|
+
);
|
|
2448
|
+
}
|
|
2449
|
+
if (resource.kind === "agent" && resource.actsAsRoleId !== void 0 && !rolesById.has(resource.actsAsRoleId)) {
|
|
2450
|
+
addIssue(
|
|
2451
|
+
ctx,
|
|
2452
|
+
["resources", resource.id, "actsAsRoleId"],
|
|
2453
|
+
`Agent resource "${resource.id}" references unknown actsAsRoleId "${resource.actsAsRoleId}"`
|
|
2454
|
+
);
|
|
2455
|
+
}
|
|
2456
|
+
});
|
|
2457
|
+
Object.values(model.roles).forEach((role) => {
|
|
2458
|
+
if (role.heldBy === void 0) return;
|
|
2459
|
+
asRoleHolderArray(role.heldBy).forEach((holder, holderIndex) => {
|
|
2460
|
+
if (holder.kind !== "agent") return;
|
|
2461
|
+
const resource = resourcesById.get(holder.agentId);
|
|
2462
|
+
if (resource === void 0) {
|
|
2463
|
+
addIssue(
|
|
2464
|
+
ctx,
|
|
2465
|
+
["roles", role.id, "heldBy", Array.isArray(role.heldBy) ? holderIndex : "agentId"],
|
|
2466
|
+
`Role "${role.id}" references unknown agent holder resource "${holder.agentId}"`
|
|
2467
|
+
);
|
|
2468
|
+
return;
|
|
2469
|
+
}
|
|
2470
|
+
if (resource.kind !== "agent") {
|
|
2471
|
+
addIssue(
|
|
2472
|
+
ctx,
|
|
2473
|
+
["roles", role.id, "heldBy", Array.isArray(role.heldBy) ? holderIndex : "agentId"],
|
|
2474
|
+
`Role "${role.id}" agent holder "${holder.agentId}" must reference an agent resource`
|
|
2475
|
+
);
|
|
2476
|
+
}
|
|
2477
|
+
});
|
|
2478
|
+
});
|
|
2479
|
+
Object.entries(model.knowledge).forEach(([nodeId2, node]) => {
|
|
2480
|
+
node.ownerIds.forEach((roleId, ownerIndex) => {
|
|
2481
|
+
if (!rolesById.has(roleId)) {
|
|
2482
|
+
addIssue(
|
|
2483
|
+
ctx,
|
|
2484
|
+
["knowledge", nodeId2, "ownerIds", ownerIndex],
|
|
2485
|
+
`Knowledge node "${node.id}" references unknown owner role "${roleId}"`
|
|
2486
|
+
);
|
|
2487
|
+
}
|
|
2488
|
+
});
|
|
2489
|
+
});
|
|
2490
|
+
function validateSystemContent(system, systemPath) {
|
|
2491
|
+
const content = system.content;
|
|
2492
|
+
if (content === void 0 || Object.keys(content).length === 0) {
|
|
2493
|
+
if (system.subsystems !== void 0) {
|
|
2494
|
+
Object.entries(system.subsystems).forEach(([childKey, child]) => {
|
|
2495
|
+
validateSystemContent(child, [...systemPath, "subsystems", childKey]);
|
|
2496
|
+
});
|
|
2497
|
+
}
|
|
2498
|
+
return;
|
|
2499
|
+
}
|
|
2500
|
+
Object.entries(content).forEach(([localId, node]) => {
|
|
2501
|
+
if (node.parentContentId !== void 0 && !(node.parentContentId in content)) {
|
|
2502
|
+
addIssue(
|
|
2503
|
+
ctx,
|
|
2504
|
+
[...systemPath, "content", localId, "parentContentId"],
|
|
2505
|
+
`Content node "${localId}" parentContentId "${node.parentContentId}" does not resolve within the same system`
|
|
2506
|
+
);
|
|
2507
|
+
}
|
|
2508
|
+
});
|
|
2509
|
+
Object.entries(content).forEach(([localId, node]) => {
|
|
2510
|
+
const visited = /* @__PURE__ */ new Set();
|
|
2511
|
+
let currentId = node.parentContentId;
|
|
2512
|
+
while (currentId !== void 0) {
|
|
2513
|
+
if (currentId === localId || visited.has(currentId)) {
|
|
2514
|
+
addIssue(
|
|
2515
|
+
ctx,
|
|
2516
|
+
[...systemPath, "content", localId, "parentContentId"],
|
|
2517
|
+
`Content node "${localId}" has a parentContentId cycle`
|
|
2518
|
+
);
|
|
2519
|
+
break;
|
|
2520
|
+
}
|
|
2521
|
+
visited.add(currentId);
|
|
2522
|
+
currentId = content[currentId]?.parentContentId;
|
|
2523
|
+
}
|
|
2524
|
+
});
|
|
2525
|
+
Object.entries(content).forEach(([localId, node]) => {
|
|
2526
|
+
const childDef = lookupContentType(node.kind, node.type);
|
|
2527
|
+
if (childDef !== void 0 && node.data !== void 0) {
|
|
2528
|
+
const result = childDef.payloadSchema.safeParse(node.data);
|
|
2529
|
+
if (!result.success) {
|
|
2530
|
+
addIssue(
|
|
2531
|
+
ctx,
|
|
2532
|
+
[...systemPath, "content", localId, "data"],
|
|
2533
|
+
`Content node "${localId}" (${node.kind}:${node.type}) data failed payload validation: ${result.error.message}`
|
|
2534
|
+
);
|
|
2535
|
+
}
|
|
2536
|
+
}
|
|
2537
|
+
if (node.parentContentId !== void 0 && childDef !== void 0) {
|
|
2538
|
+
const parentNode = content[node.parentContentId];
|
|
2539
|
+
if (parentNode !== void 0) {
|
|
2540
|
+
const parentDef = lookupContentType(parentNode.kind, parentNode.type);
|
|
2541
|
+
if (parentDef !== void 0 && childDef.kind !== parentDef.kind) {
|
|
2542
|
+
addIssue(
|
|
2543
|
+
ctx,
|
|
2544
|
+
[...systemPath, "content", localId, "parentContentId"],
|
|
2545
|
+
`Content node "${localId}" kind "${childDef.kind}" cannot parent under "${node.parentContentId}" kind "${parentDef.kind}": parentContentId must be same-meta-kind (per L19)`
|
|
2546
|
+
);
|
|
2547
|
+
}
|
|
2548
|
+
}
|
|
2549
|
+
}
|
|
2550
|
+
});
|
|
2551
|
+
if (system.subsystems !== void 0) {
|
|
2552
|
+
Object.entries(system.subsystems).forEach(([childKey, child]) => {
|
|
2553
|
+
validateSystemContent(child, [...systemPath, "subsystems", childKey]);
|
|
2554
|
+
});
|
|
2555
|
+
}
|
|
2556
|
+
}
|
|
2557
|
+
Object.entries(model.systems).forEach(([systemKey, system]) => {
|
|
2558
|
+
validateSystemContent(system, ["systems", systemKey]);
|
|
2559
|
+
});
|
|
2560
|
+
});
|
|
2561
|
+
|
|
2562
|
+
// ../core/src/organization-model/graph/schema.ts
|
|
2563
|
+
var OrganizationGraphNodeKindSchema = z.enum([
|
|
2564
|
+
"organization",
|
|
2565
|
+
"system",
|
|
2566
|
+
"role",
|
|
2567
|
+
"action",
|
|
2568
|
+
"entity",
|
|
2569
|
+
"event",
|
|
2570
|
+
"policy",
|
|
2571
|
+
"stage",
|
|
2572
|
+
"resource",
|
|
2573
|
+
"knowledge",
|
|
2574
|
+
"customer-segment",
|
|
2575
|
+
"offering",
|
|
2576
|
+
"goal",
|
|
2577
|
+
"surface",
|
|
2578
|
+
"navigation-group",
|
|
2579
|
+
// Phase 3 preview — Phase 4 populates via graph projection of system.content entries.
|
|
2580
|
+
"content-node"
|
|
2581
|
+
]);
|
|
2582
|
+
var OrganizationGraphEdgeKindSchema = z.enum([
|
|
2583
|
+
"contains",
|
|
2584
|
+
"references",
|
|
2585
|
+
"maps_to",
|
|
2586
|
+
"uses",
|
|
2587
|
+
"governs",
|
|
2588
|
+
"links",
|
|
2589
|
+
"affects",
|
|
2590
|
+
"emits",
|
|
2591
|
+
"originates_from",
|
|
2592
|
+
"triggers",
|
|
2593
|
+
"applies_to",
|
|
2594
|
+
"effects"
|
|
2595
|
+
]);
|
|
2596
|
+
var OrganizationGraphNodeSchema = z.object({
|
|
2597
|
+
id: z.string().trim().min(1).max(200),
|
|
2598
|
+
kind: OrganizationGraphNodeKindSchema,
|
|
2599
|
+
label: LabelSchema,
|
|
2600
|
+
sourceId: z.string().trim().min(1).max(255).optional(),
|
|
2601
|
+
description: DescriptionSchema.optional(),
|
|
2602
|
+
icon: IconNameSchema.optional(),
|
|
2603
|
+
enabled: z.boolean().optional(),
|
|
2604
|
+
resourceType: z.enum(["workflow", "agent", "trigger", "integration", "external", "human_checkpoint", "script"]).optional()
|
|
2605
|
+
});
|
|
2606
|
+
var OrganizationGraphEdgeSchema = z.object({
|
|
2607
|
+
id: z.string().trim().min(1).max(250),
|
|
2608
|
+
kind: OrganizationGraphEdgeKindSchema,
|
|
2609
|
+
sourceId: z.string().trim().min(1).max(200),
|
|
2610
|
+
targetId: z.string().trim().min(1).max(200),
|
|
2611
|
+
label: z.string().trim().min(1).max(120).optional(),
|
|
2612
|
+
relationshipType: z.enum(["triggers", "uses", "approval"]).optional()
|
|
2613
|
+
});
|
|
2614
|
+
var OrganizationGraphSchema = z.object({
|
|
2615
|
+
version: z.literal(1),
|
|
2616
|
+
organizationModelVersion: OrganizationModelSchema.shape.version,
|
|
2617
|
+
nodes: z.array(OrganizationGraphNodeSchema),
|
|
2618
|
+
edges: z.array(OrganizationGraphEdgeSchema)
|
|
2619
|
+
});
|
|
2620
|
+
var BuildOrganizationGraphInputSchema = z.object({
|
|
2621
|
+
organizationModel: OrganizationModelSchema,
|
|
2622
|
+
commandViewData: z.unknown().optional()
|
|
2623
|
+
});
|
|
2624
|
+
|
|
2625
|
+
// ../core/src/organization-model/migration-helpers.ts
|
|
2626
|
+
function getAllPipelines(model) {
|
|
2627
|
+
const results = [];
|
|
2628
|
+
for (const { path: systemPath, system } of listAllSystems(model)) {
|
|
2629
|
+
const content = system.content ?? {};
|
|
2630
|
+
for (const [localId, node] of Object.entries(content)) {
|
|
2631
|
+
if (node.kind !== "schema" || node.type !== "pipeline") continue;
|
|
2632
|
+
const data = node.data ?? {};
|
|
2633
|
+
const stages = Object.entries(content).filter(([, s]) => s.kind === "schema" && s.type === "stage" && s.parentContentId === localId).map(([stageLocalId, s]) => {
|
|
2634
|
+
const sd = s.data ?? {};
|
|
2635
|
+
return {
|
|
2636
|
+
id: stageLocalId,
|
|
2637
|
+
label: s.label ?? stageLocalId,
|
|
2638
|
+
order: typeof sd.order === "number" ? sd.order : 0,
|
|
2639
|
+
semanticClass: sd.semanticClass ?? "open",
|
|
2640
|
+
surfaceIds: Array.isArray(sd.surfaceIds) ? sd.surfaceIds : [],
|
|
2641
|
+
resourceIds: Array.isArray(sd.resourceIds) ? sd.resourceIds : [],
|
|
2642
|
+
color: typeof sd.color === "string" ? sd.color : void 0
|
|
2643
|
+
};
|
|
2644
|
+
}).sort((a, b) => a.order - b.order);
|
|
2645
|
+
const pipeline = {
|
|
2646
|
+
id: localId,
|
|
2647
|
+
label: node.label ?? localId,
|
|
2648
|
+
entityId: typeof data.entityId === "string" ? data.entityId : "",
|
|
2649
|
+
stages,
|
|
2650
|
+
...typeof node.description === "string" ? { description: node.description } : {}
|
|
2651
|
+
};
|
|
2652
|
+
results.push({ systemPath, pipeline });
|
|
2653
|
+
}
|
|
2654
|
+
}
|
|
2655
|
+
return results;
|
|
2656
|
+
}
|
|
2657
|
+
function getAllBuildTemplates(model) {
|
|
2658
|
+
const results = [];
|
|
2659
|
+
for (const { system } of listAllSystems(model)) {
|
|
2660
|
+
const content = system.content ?? {};
|
|
2661
|
+
for (const [localId, node] of Object.entries(content)) {
|
|
2662
|
+
if (node.kind !== "schema" || node.type !== "template") continue;
|
|
2663
|
+
const nd = node.data ?? {};
|
|
2664
|
+
const steps = Object.entries(content).filter(([, s]) => s.kind === "schema" && s.type === "template-step" && s.parentContentId === localId).map(([stepLocalId, s]) => {
|
|
2665
|
+
const sd = s.data ?? {};
|
|
2666
|
+
return {
|
|
2667
|
+
id: stepLocalId,
|
|
2668
|
+
label: s.label ?? stepLocalId,
|
|
2669
|
+
...s.description ? { description: s.description } : {},
|
|
2670
|
+
// Pass through all data fields — template-step payload is richer than Pipeline;
|
|
2671
|
+
// Wave 2 authors the canonical shape; Wave 4 verifies round-trip fidelity.
|
|
2672
|
+
...sd
|
|
2673
|
+
};
|
|
2674
|
+
});
|
|
2675
|
+
results.push({
|
|
2676
|
+
id: localId,
|
|
2677
|
+
label: node.label ?? localId,
|
|
2678
|
+
...node.description ? { description: node.description } : {},
|
|
2679
|
+
...typeof nd.color === "string" ? { color: nd.color } : {},
|
|
2680
|
+
// BuildTemplate requires steps array — cast via spread; Wave 4 adds type-safe assertions.
|
|
2681
|
+
steps
|
|
2682
|
+
});
|
|
2683
|
+
}
|
|
2684
|
+
}
|
|
2685
|
+
return results;
|
|
2686
|
+
}
|
|
2687
|
+
function getAllProspectingStages(model, kind) {
|
|
2688
|
+
const results = [];
|
|
2689
|
+
for (const { system } of listAllSystems(model)) {
|
|
2690
|
+
const content = system.content ?? {};
|
|
2691
|
+
for (const [localId, node] of Object.entries(content)) {
|
|
2692
|
+
if (node.kind !== "schema" || node.type !== "stage") continue;
|
|
2693
|
+
const sd = node.data ?? {};
|
|
2694
|
+
if (sd.entityKind !== kind) continue;
|
|
2695
|
+
results.push({
|
|
2696
|
+
id: localId,
|
|
2697
|
+
label: node.label ?? localId,
|
|
2698
|
+
order: typeof sd.order === "number" ? sd.order : 0,
|
|
2699
|
+
...typeof sd.color === "string" ? { color: sd.color } : {},
|
|
2700
|
+
...node.description ? { description: node.description } : {}
|
|
2701
|
+
});
|
|
2702
|
+
}
|
|
2703
|
+
}
|
|
2704
|
+
return results.sort((a, b) => a.order - b.order);
|
|
2705
|
+
}
|
|
2706
|
+
function getAllProjectStatuses(model, appliesTo) {
|
|
2707
|
+
const results = [];
|
|
2708
|
+
for (const { system } of listAllSystems(model)) {
|
|
2709
|
+
const content = system.content ?? {};
|
|
2710
|
+
for (const [flowLocalId, flowNode] of Object.entries(content)) {
|
|
2711
|
+
if (flowNode.kind !== "schema" || flowNode.type !== "status-flow") continue;
|
|
2712
|
+
const fd = flowNode.data ?? {};
|
|
2713
|
+
if (fd.appliesTo !== appliesTo) continue;
|
|
2714
|
+
for (const [statusLocalId, statusNode] of Object.entries(content)) {
|
|
2715
|
+
if (statusNode.kind !== "schema" || statusNode.type !== "status") continue;
|
|
2716
|
+
if (statusNode.parentContentId !== flowLocalId) continue;
|
|
2717
|
+
const sd = statusNode.data ?? {};
|
|
2718
|
+
results.push({
|
|
2719
|
+
id: statusLocalId,
|
|
2720
|
+
label: statusNode.label ?? statusLocalId,
|
|
2721
|
+
order: typeof sd.order === "number" ? sd.order : 0,
|
|
2722
|
+
...typeof sd.color === "string" ? { color: sd.color } : {},
|
|
2723
|
+
...statusNode.description ? { description: statusNode.description } : {}
|
|
2724
|
+
});
|
|
2725
|
+
}
|
|
2726
|
+
}
|
|
2727
|
+
}
|
|
2728
|
+
return results.sort((a, b) => a.order - b.order);
|
|
2729
|
+
}
|
|
2730
|
+
|
|
2731
|
+
// ../core/src/organization-model/graph/build.ts
|
|
2732
|
+
function nodeId(kind, sourceId) {
|
|
2733
|
+
return kind === "organization" ? "organization-model" : `${kind}:${sourceId ?? ""}`;
|
|
2734
|
+
}
|
|
2735
|
+
function edgeId(kind, sourceId, targetId, variant) {
|
|
2736
|
+
return variant ? `edge:${kind}:${variant}:${sourceId}:${targetId}` : `edge:${kind}:${sourceId}:${targetId}`;
|
|
2737
|
+
}
|
|
2738
|
+
function pushUniqueNode(nodes, seen, node) {
|
|
2739
|
+
if (seen.has(node.id)) return;
|
|
2740
|
+
seen.add(node.id);
|
|
2741
|
+
nodes.push(node);
|
|
2742
|
+
}
|
|
2743
|
+
function pushUniqueEdge(edges, seen, edge) {
|
|
2744
|
+
if (seen.has(edge.id)) return;
|
|
2745
|
+
seen.add(edge.id);
|
|
2746
|
+
edges.push(edge);
|
|
2747
|
+
}
|
|
2748
|
+
function collectSidebarGraphNodes(nodes, groups, surfaces, parentGroupId) {
|
|
2749
|
+
Object.entries(nodes).sort(([leftId, left], [rightId, right]) => {
|
|
2750
|
+
const orderDelta = (left.order ?? Number.MAX_SAFE_INTEGER) - (right.order ?? Number.MAX_SAFE_INTEGER);
|
|
2751
|
+
return orderDelta === 0 ? leftId.localeCompare(rightId) : orderDelta;
|
|
2752
|
+
}).forEach(([id, node]) => {
|
|
2753
|
+
if (node.type === "group") {
|
|
2754
|
+
groups.push({ id, node, ...parentGroupId !== void 0 ? { parentGroupId } : {} });
|
|
2755
|
+
collectSidebarGraphNodes(node.children, groups, surfaces, id);
|
|
2756
|
+
return;
|
|
2757
|
+
}
|
|
2758
|
+
surfaces.push({ id, node, ...parentGroupId !== void 0 ? { parentGroupId } : {} });
|
|
2759
|
+
});
|
|
2760
|
+
}
|
|
2761
|
+
function upsertResourceNode(nodes, seen, resourceNodesById, node) {
|
|
2762
|
+
const existing = resourceNodesById.get(node.id);
|
|
2763
|
+
if (existing) {
|
|
2764
|
+
if (!existing.label || existing.label === existing.sourceId) {
|
|
2765
|
+
existing.label = node.label;
|
|
2766
|
+
}
|
|
2767
|
+
if (!existing.description && node.description) {
|
|
2768
|
+
existing.description = node.description;
|
|
2769
|
+
}
|
|
2770
|
+
if (!existing.sourceId && node.sourceId) {
|
|
2771
|
+
existing.sourceId = node.sourceId;
|
|
2772
|
+
}
|
|
2773
|
+
if (!existing.resourceType && node.resourceType) {
|
|
2774
|
+
existing.resourceType = node.resourceType;
|
|
2775
|
+
}
|
|
2776
|
+
return existing;
|
|
2777
|
+
}
|
|
2778
|
+
resourceNodesById.set(node.id, node);
|
|
2779
|
+
pushUniqueNode(nodes, seen, node);
|
|
2780
|
+
return node;
|
|
2781
|
+
}
|
|
2782
|
+
function ensureResourceNode(nodes, seen, resourceNodesById, resourceId) {
|
|
2783
|
+
const existing = resourceNodesById.get(nodeId("resource", resourceId));
|
|
2784
|
+
if (existing) return existing;
|
|
2785
|
+
return upsertResourceNode(nodes, seen, resourceNodesById, {
|
|
2786
|
+
id: nodeId("resource", resourceId),
|
|
2787
|
+
kind: "resource",
|
|
2788
|
+
label: resourceId,
|
|
2789
|
+
sourceId: resourceId
|
|
2790
|
+
});
|
|
2791
|
+
}
|
|
2792
|
+
function normalizeCommandViewResourceType(resourceType) {
|
|
2793
|
+
return resourceType === "human" ? "human_checkpoint" : resourceType;
|
|
2794
|
+
}
|
|
2795
|
+
function normalizeOrganizationModelResourceType(resourceType) {
|
|
2796
|
+
return resourceType;
|
|
2797
|
+
}
|
|
2798
|
+
function collectCommandViewResources(commandViewData) {
|
|
2799
|
+
return [
|
|
2800
|
+
...commandViewData.workflows,
|
|
2801
|
+
...commandViewData.agents,
|
|
2802
|
+
...commandViewData.triggers,
|
|
2803
|
+
...commandViewData.integrations,
|
|
2804
|
+
...commandViewData.externalResources,
|
|
2805
|
+
...commandViewData.humanCheckpoints
|
|
2806
|
+
];
|
|
2807
|
+
}
|
|
2808
|
+
function invocationSignature(invocation) {
|
|
2809
|
+
switch (invocation.kind) {
|
|
2810
|
+
case "slash-command":
|
|
2811
|
+
return `${invocation.kind}:${invocation.command}`;
|
|
2812
|
+
case "mcp-tool":
|
|
2813
|
+
return `${invocation.kind}:${invocation.server}:${invocation.name}`;
|
|
2814
|
+
case "api-endpoint":
|
|
2815
|
+
return `${invocation.kind}:${invocation.method}:${invocation.path}`;
|
|
2816
|
+
case "script-execution":
|
|
2817
|
+
return `${invocation.kind}:${invocation.resourceId}`;
|
|
2818
|
+
}
|
|
2819
|
+
}
|
|
2820
|
+
function invocationLabel(invocation) {
|
|
2821
|
+
switch (invocation.kind) {
|
|
2822
|
+
case "slash-command":
|
|
2823
|
+
return invocation.command;
|
|
2824
|
+
case "mcp-tool":
|
|
2825
|
+
return `${invocation.server}.${invocation.name}`;
|
|
2826
|
+
case "api-endpoint":
|
|
2827
|
+
return `${invocation.method} ${invocation.path}`;
|
|
2828
|
+
case "script-execution":
|
|
2829
|
+
return `script ${invocation.resourceId}`;
|
|
2830
|
+
}
|
|
2831
|
+
}
|
|
2832
|
+
function eventNodeId(eventId) {
|
|
2833
|
+
return nodeId("event", eventId);
|
|
2834
|
+
}
|
|
2835
|
+
function buildResourceEventDescriptor(resourceId, emission) {
|
|
2836
|
+
return {
|
|
2837
|
+
...emission,
|
|
2838
|
+
id: `${resourceId}:${emission.eventKey}`,
|
|
2839
|
+
ownerId: resourceId,
|
|
2840
|
+
ownerKind: "resource"
|
|
2841
|
+
};
|
|
2842
|
+
}
|
|
2843
|
+
function buildEntityEventDescriptor(entity, eventKey, label) {
|
|
2844
|
+
return {
|
|
2845
|
+
id: `${entity.id}:${eventKey}`,
|
|
2846
|
+
ownerId: entity.id,
|
|
2847
|
+
ownerKind: "entity",
|
|
2848
|
+
eventKey,
|
|
2849
|
+
label
|
|
2850
|
+
};
|
|
2851
|
+
}
|
|
2852
|
+
function pushEventProjection(nodes, nodeIds, edges, edgeIds, eventNodeIdsByEventId, event, sourceNodeId, edgeKind) {
|
|
2853
|
+
const id = eventNodeId(event.id);
|
|
2854
|
+
eventNodeIdsByEventId.set(event.id, id);
|
|
2855
|
+
pushUniqueNode(nodes, nodeIds, {
|
|
2856
|
+
id,
|
|
2857
|
+
kind: "event",
|
|
2858
|
+
label: event.label,
|
|
2859
|
+
sourceId: event.id
|
|
2860
|
+
});
|
|
2861
|
+
const sourceId = edgeKind === "originates_from" ? id : sourceNodeId;
|
|
2862
|
+
const targetId = edgeKind === "originates_from" ? sourceNodeId : id;
|
|
2863
|
+
pushUniqueEdge(edges, edgeIds, {
|
|
2864
|
+
id: edgeId(edgeKind, sourceId, targetId),
|
|
2865
|
+
kind: edgeKind,
|
|
2866
|
+
sourceId,
|
|
2867
|
+
targetId
|
|
2868
|
+
});
|
|
2869
|
+
}
|
|
2870
|
+
function buildOrganizationGraph(input) {
|
|
2871
|
+
const parsed = BuildOrganizationGraphInputSchema.parse(input);
|
|
2872
|
+
const organizationModel = parsed.organizationModel;
|
|
2873
|
+
const commandViewData = parsed.commandViewData;
|
|
2874
|
+
const nodes = [];
|
|
2875
|
+
const edges = [];
|
|
2876
|
+
const nodeIds = /* @__PURE__ */ new Set();
|
|
2877
|
+
const edgeIds = /* @__PURE__ */ new Set();
|
|
2878
|
+
const resourceNodesById = /* @__PURE__ */ new Map();
|
|
2879
|
+
const organizationModelResourceIds = new Set(Object.keys(organizationModel.resources));
|
|
2880
|
+
const actionIdsByInvocation = /* @__PURE__ */ new Map();
|
|
2881
|
+
const projectedEventNodeIdsByEventId = /* @__PURE__ */ new Map();
|
|
2882
|
+
const organizationNode = {
|
|
2883
|
+
id: nodeId("organization"),
|
|
2884
|
+
kind: "organization",
|
|
2885
|
+
label: "Organization Model"
|
|
2886
|
+
};
|
|
2887
|
+
pushUniqueNode(nodes, nodeIds, organizationNode);
|
|
2888
|
+
const systemsWithPaths = listAllSystems(organizationModel);
|
|
2889
|
+
const systemPathByRef = /* @__PURE__ */ new Map();
|
|
2890
|
+
for (const { path, system } of systemsWithPaths) {
|
|
2891
|
+
systemPathByRef.set(path, path);
|
|
2892
|
+
systemPathByRef.set(system.id, path);
|
|
2893
|
+
}
|
|
2894
|
+
const validSystemRefs = new Set(systemPathByRef.keys());
|
|
2895
|
+
const systemNodeId = (systemRef) => nodeId("system", systemPathByRef.get(systemRef) ?? systemRef);
|
|
2896
|
+
for (const { path, system } of systemsWithPaths.sort((a, b) => a.path.localeCompare(b.path))) {
|
|
2897
|
+
const id = nodeId("system", path);
|
|
2898
|
+
pushUniqueNode(nodes, nodeIds, {
|
|
2899
|
+
id,
|
|
2900
|
+
kind: "system",
|
|
2901
|
+
label: system.label ?? system.title ?? system.id,
|
|
2902
|
+
sourceId: path,
|
|
2903
|
+
description: system.description,
|
|
2904
|
+
icon: system.ui?.icon ?? system.icon,
|
|
2905
|
+
enabled: system.enabled
|
|
2906
|
+
});
|
|
2907
|
+
pushUniqueEdge(edges, edgeIds, {
|
|
2908
|
+
id: edgeId("contains", organizationNode.id, id),
|
|
2909
|
+
kind: "contains",
|
|
2910
|
+
sourceId: organizationNode.id,
|
|
2911
|
+
targetId: id
|
|
2912
|
+
});
|
|
2913
|
+
const parentSystemId = path.includes(".") ? path.slice(0, path.lastIndexOf(".")) : void 0;
|
|
2914
|
+
if (parentSystemId !== void 0) {
|
|
2915
|
+
pushUniqueEdge(edges, edgeIds, {
|
|
2916
|
+
id: edgeId("contains", nodeId("system", parentSystemId), id),
|
|
2917
|
+
kind: "contains",
|
|
2918
|
+
sourceId: nodeId("system", parentSystemId),
|
|
2919
|
+
targetId: id
|
|
2920
|
+
});
|
|
2921
|
+
}
|
|
2922
|
+
}
|
|
2923
|
+
for (const role of Object.values(organizationModel.roles).sort((a, b) => a.id.localeCompare(b.id))) {
|
|
2924
|
+
const id = nodeId("role", role.id);
|
|
2925
|
+
pushUniqueNode(nodes, nodeIds, {
|
|
2926
|
+
id,
|
|
2927
|
+
kind: "role",
|
|
2928
|
+
label: role.title,
|
|
2929
|
+
sourceId: role.id,
|
|
2930
|
+
description: role.responsibilities.length > 0 ? role.responsibilities.join("; ") : void 0
|
|
2931
|
+
});
|
|
2932
|
+
pushUniqueEdge(edges, edgeIds, {
|
|
2933
|
+
id: edgeId("contains", organizationNode.id, id),
|
|
2934
|
+
kind: "contains",
|
|
2935
|
+
sourceId: organizationNode.id,
|
|
2936
|
+
targetId: id
|
|
2937
|
+
});
|
|
2938
|
+
if (role.reportsToId !== void 0) {
|
|
2939
|
+
pushUniqueEdge(edges, edgeIds, {
|
|
2940
|
+
id: edgeId("references", id, nodeId("role", role.reportsToId), "reports-to"),
|
|
2941
|
+
kind: "references",
|
|
2942
|
+
sourceId: id,
|
|
2943
|
+
targetId: nodeId("role", role.reportsToId),
|
|
2944
|
+
label: "reports to"
|
|
2945
|
+
});
|
|
2946
|
+
}
|
|
2947
|
+
for (const systemId of role.responsibleFor ?? []) {
|
|
2948
|
+
pushUniqueEdge(edges, edgeIds, {
|
|
2949
|
+
id: edgeId("governs", id, systemNodeId(systemId), "responsible-for"),
|
|
2950
|
+
kind: "governs",
|
|
2951
|
+
sourceId: id,
|
|
2952
|
+
targetId: systemNodeId(systemId),
|
|
2953
|
+
label: "responsible for"
|
|
2954
|
+
});
|
|
2955
|
+
}
|
|
2956
|
+
}
|
|
2957
|
+
for (const node of Object.values(organizationModel.knowledge).sort((a, b) => a.id.localeCompare(b.id))) {
|
|
2958
|
+
const id = nodeId("knowledge", node.id);
|
|
2959
|
+
pushUniqueNode(nodes, nodeIds, {
|
|
2960
|
+
id,
|
|
2961
|
+
kind: "knowledge",
|
|
2962
|
+
label: node.title,
|
|
2963
|
+
sourceId: node.id,
|
|
2964
|
+
description: node.summary,
|
|
2965
|
+
icon: node.icon
|
|
2966
|
+
});
|
|
2967
|
+
pushUniqueEdge(edges, edgeIds, {
|
|
2968
|
+
id: edgeId("contains", organizationNode.id, id),
|
|
2969
|
+
kind: "contains",
|
|
2970
|
+
sourceId: organizationNode.id,
|
|
2971
|
+
targetId: id
|
|
2972
|
+
});
|
|
2973
|
+
for (const link of node.links) {
|
|
2974
|
+
const targetId = link.target.kind === "system" ? systemNodeId(link.target.id) : link.nodeId;
|
|
2975
|
+
pushUniqueEdge(edges, edgeIds, {
|
|
2976
|
+
id: edgeId("governs", id, targetId),
|
|
2977
|
+
kind: "governs",
|
|
2978
|
+
sourceId: id,
|
|
2979
|
+
targetId
|
|
2980
|
+
});
|
|
2981
|
+
}
|
|
2982
|
+
}
|
|
2983
|
+
const allStages = [
|
|
2984
|
+
...getAllProspectingStages(organizationModel, "company"),
|
|
2985
|
+
...getAllProspectingStages(organizationModel, "contact")
|
|
2986
|
+
].sort((a, b) => a.order - b.order || a.id.localeCompare(b.id));
|
|
2987
|
+
for (const stage of allStages) {
|
|
2988
|
+
const id = nodeId("stage", stage.id);
|
|
2989
|
+
pushUniqueNode(nodes, nodeIds, {
|
|
2990
|
+
id,
|
|
2991
|
+
kind: "stage",
|
|
2992
|
+
label: stage.label,
|
|
2993
|
+
sourceId: stage.id,
|
|
2994
|
+
...stage.description ? { description: stage.description } : {},
|
|
2995
|
+
...stage.icon ? { icon: stage.icon } : {}
|
|
2996
|
+
});
|
|
2997
|
+
pushUniqueEdge(edges, edgeIds, {
|
|
2998
|
+
id: edgeId("contains", organizationNode.id, id),
|
|
2999
|
+
kind: "contains",
|
|
3000
|
+
sourceId: organizationNode.id,
|
|
3001
|
+
targetId: id
|
|
3002
|
+
});
|
|
3003
|
+
}
|
|
3004
|
+
for (const action of Object.values(organizationModel.actions).sort((a, b) => a.id.localeCompare(b.id))) {
|
|
3005
|
+
const id = nodeId("action", action.id);
|
|
3006
|
+
pushUniqueNode(nodes, nodeIds, {
|
|
3007
|
+
id,
|
|
3008
|
+
kind: "action",
|
|
3009
|
+
label: action.label,
|
|
3010
|
+
sourceId: action.id,
|
|
3011
|
+
description: action.description
|
|
3012
|
+
});
|
|
3013
|
+
pushUniqueEdge(edges, edgeIds, {
|
|
3014
|
+
id: edgeId("contains", organizationNode.id, id),
|
|
3015
|
+
kind: "contains",
|
|
3016
|
+
sourceId: organizationNode.id,
|
|
3017
|
+
targetId: id
|
|
3018
|
+
});
|
|
3019
|
+
if (action.resourceId !== void 0) {
|
|
3020
|
+
const resourceNode = ensureResourceNode(nodes, nodeIds, resourceNodesById, action.resourceId);
|
|
3021
|
+
pushUniqueEdge(edges, edgeIds, {
|
|
3022
|
+
id: edgeId("maps_to", id, resourceNode.id),
|
|
3023
|
+
kind: "maps_to",
|
|
3024
|
+
sourceId: id,
|
|
3025
|
+
targetId: resourceNode.id
|
|
3026
|
+
});
|
|
3027
|
+
}
|
|
3028
|
+
for (const entityId of action.affects ?? []) {
|
|
3029
|
+
pushUniqueEdge(edges, edgeIds, {
|
|
3030
|
+
id: edgeId("affects", id, nodeId("entity", entityId)),
|
|
3031
|
+
kind: "affects",
|
|
3032
|
+
sourceId: id,
|
|
3033
|
+
targetId: nodeId("entity", entityId)
|
|
3034
|
+
});
|
|
3035
|
+
}
|
|
3036
|
+
for (const invocation of action.invocations) {
|
|
3037
|
+
const key = invocationSignature(invocation);
|
|
3038
|
+
const existing = actionIdsByInvocation.get(key);
|
|
3039
|
+
if (existing) {
|
|
3040
|
+
existing.push(id);
|
|
3041
|
+
} else {
|
|
3042
|
+
actionIdsByInvocation.set(key, [id]);
|
|
3043
|
+
}
|
|
3044
|
+
}
|
|
3045
|
+
}
|
|
3046
|
+
for (const entity of Object.values(organizationModel.entities).sort(
|
|
3047
|
+
(a, b) => a.order - b.order || a.id.localeCompare(b.id)
|
|
3048
|
+
)) {
|
|
3049
|
+
const id = nodeId("entity", entity.id);
|
|
3050
|
+
pushUniqueNode(nodes, nodeIds, {
|
|
3051
|
+
id,
|
|
3052
|
+
kind: "entity",
|
|
3053
|
+
label: entity.label,
|
|
3054
|
+
sourceId: entity.id,
|
|
3055
|
+
description: entity.description
|
|
3056
|
+
});
|
|
3057
|
+
pushUniqueEdge(edges, edgeIds, {
|
|
3058
|
+
id: edgeId("contains", systemNodeId(entity.ownedBySystemId), id, "system-entity"),
|
|
3059
|
+
kind: "contains",
|
|
3060
|
+
sourceId: systemNodeId(entity.ownedBySystemId),
|
|
3061
|
+
targetId: id
|
|
3062
|
+
});
|
|
3063
|
+
for (const [linkIndex, link] of (entity.links ?? []).entries()) {
|
|
3064
|
+
pushUniqueEdge(edges, edgeIds, {
|
|
3065
|
+
id: edgeId("links", id, nodeId("entity", link.toEntity), `${link.kind}-${linkIndex}`),
|
|
3066
|
+
kind: "links",
|
|
3067
|
+
sourceId: id,
|
|
3068
|
+
targetId: nodeId("entity", link.toEntity),
|
|
3069
|
+
label: link.label ?? link.kind
|
|
3070
|
+
});
|
|
3071
|
+
}
|
|
3072
|
+
if (entity.stateCatalogId !== void 0) {
|
|
3073
|
+
const stateEvents = [];
|
|
3074
|
+
if (entity.stateCatalogId === "crm.pipeline") {
|
|
3075
|
+
for (const { pipeline } of getAllPipelines(organizationModel).filter(({ pipeline: p }) => p.entityId === entity.id).sort((a, b) => a.pipeline.id.localeCompare(b.pipeline.id))) {
|
|
3076
|
+
for (const stage of [...pipeline.stages].sort((a, b) => a.order - b.order || a.id.localeCompare(b.id))) {
|
|
3077
|
+
stateEvents.push(buildEntityEventDescriptor(entity, stage.id, stage.label));
|
|
3078
|
+
}
|
|
3079
|
+
}
|
|
3080
|
+
}
|
|
3081
|
+
if (entity.stateCatalogId === "delivery.task") {
|
|
3082
|
+
for (const status of getAllProjectStatuses(organizationModel, "task").sort(
|
|
3083
|
+
(a, b) => a.order - b.order || a.id.localeCompare(b.id)
|
|
3084
|
+
)) {
|
|
3085
|
+
stateEvents.push(buildEntityEventDescriptor(entity, status.id, status.label));
|
|
3086
|
+
}
|
|
3087
|
+
}
|
|
3088
|
+
if (entity.stateCatalogId === "lead-gen.company" || entity.stateCatalogId === "lead-gen.contact") {
|
|
3089
|
+
const leadGenEntity = entity.stateCatalogId === "lead-gen.company" ? "company" : "contact";
|
|
3090
|
+
for (const stage of Object.values(LEAD_GEN_STAGE_CATALOG).sort(
|
|
3091
|
+
(a, b) => a.order - b.order || a.key.localeCompare(b.key)
|
|
3092
|
+
)) {
|
|
3093
|
+
if (stage.entity !== leadGenEntity && !(stage.additionalEntities ?? []).includes(leadGenEntity)) continue;
|
|
3094
|
+
stateEvents.push(buildEntityEventDescriptor(entity, stage.key, stage.label));
|
|
3095
|
+
}
|
|
3096
|
+
}
|
|
3097
|
+
for (const event of stateEvents) {
|
|
3098
|
+
pushEventProjection(
|
|
3099
|
+
nodes,
|
|
3100
|
+
nodeIds,
|
|
3101
|
+
edges,
|
|
3102
|
+
edgeIds,
|
|
3103
|
+
projectedEventNodeIdsByEventId,
|
|
3104
|
+
event,
|
|
3105
|
+
id,
|
|
3106
|
+
"originates_from"
|
|
3107
|
+
);
|
|
3108
|
+
}
|
|
3109
|
+
}
|
|
3110
|
+
}
|
|
3111
|
+
for (const { path, system } of systemsWithPaths.sort((a, b) => a.path.localeCompare(b.path))) {
|
|
3112
|
+
for (const actionRef of system.actions ?? []) {
|
|
3113
|
+
pushUniqueEdge(edges, edgeIds, {
|
|
3114
|
+
id: edgeId("uses", nodeId("system", path), nodeId("action", actionRef.actionId), actionRef.intent),
|
|
3115
|
+
kind: "uses",
|
|
3116
|
+
sourceId: nodeId("system", path),
|
|
3117
|
+
targetId: nodeId("action", actionRef.actionId),
|
|
3118
|
+
label: actionRef.intent
|
|
3119
|
+
});
|
|
3120
|
+
}
|
|
3121
|
+
}
|
|
3122
|
+
const validSystemPaths = /* @__PURE__ */ new Set([...validSystemRefs]);
|
|
3123
|
+
for (const resource of Object.values(organizationModel.resources).sort((a, b) => a.id.localeCompare(b.id))) {
|
|
3124
|
+
const resourceNode = upsertResourceNode(nodes, nodeIds, resourceNodesById, {
|
|
3125
|
+
id: nodeId("resource", resource.id),
|
|
3126
|
+
kind: "resource",
|
|
3127
|
+
label: resource.id,
|
|
3128
|
+
sourceId: resource.id,
|
|
3129
|
+
resourceType: normalizeOrganizationModelResourceType(resource.kind)
|
|
3130
|
+
});
|
|
3131
|
+
if (validSystemPaths.has(resource.systemPath)) {
|
|
3132
|
+
pushUniqueEdge(edges, edgeIds, {
|
|
3133
|
+
id: edgeId("contains", systemNodeId(resource.systemPath), resourceNode.id, "system-resource"),
|
|
3134
|
+
kind: "contains",
|
|
3135
|
+
sourceId: systemNodeId(resource.systemPath),
|
|
3136
|
+
targetId: resourceNode.id
|
|
3137
|
+
});
|
|
3138
|
+
}
|
|
3139
|
+
if (resource.kind === "workflow" || resource.kind === "agent") {
|
|
3140
|
+
for (const emission of resource.emits ?? []) {
|
|
3141
|
+
pushEventProjection(
|
|
3142
|
+
nodes,
|
|
3143
|
+
nodeIds,
|
|
3144
|
+
edges,
|
|
3145
|
+
edgeIds,
|
|
3146
|
+
projectedEventNodeIdsByEventId,
|
|
3147
|
+
buildResourceEventDescriptor(resource.id, emission),
|
|
3148
|
+
resourceNode.id,
|
|
3149
|
+
"emits"
|
|
3150
|
+
);
|
|
3151
|
+
}
|
|
3152
|
+
}
|
|
3153
|
+
if (resource.kind === "agent") {
|
|
3154
|
+
for (const [index, invocation] of resource.invocations.entries()) {
|
|
3155
|
+
const label = invocationLabel(invocation);
|
|
3156
|
+
if (invocation.kind === "script-execution") {
|
|
3157
|
+
const targetNode = ensureResourceNode(nodes, nodeIds, resourceNodesById, invocation.resourceId);
|
|
3158
|
+
pushUniqueEdge(edges, edgeIds, {
|
|
3159
|
+
id: edgeId("uses", resourceNode.id, targetNode.id, `agent-invocation-${index}`),
|
|
3160
|
+
kind: "uses",
|
|
3161
|
+
sourceId: resourceNode.id,
|
|
3162
|
+
targetId: targetNode.id,
|
|
3163
|
+
label
|
|
3164
|
+
});
|
|
3165
|
+
continue;
|
|
3166
|
+
}
|
|
3167
|
+
for (const actionNodeId of actionIdsByInvocation.get(invocationSignature(invocation)) ?? []) {
|
|
3168
|
+
pushUniqueEdge(edges, edgeIds, {
|
|
3169
|
+
id: edgeId("references", resourceNode.id, actionNodeId, `agent-invocation-${index}`),
|
|
3170
|
+
kind: "references",
|
|
3171
|
+
sourceId: resourceNode.id,
|
|
3172
|
+
targetId: actionNodeId,
|
|
3173
|
+
label
|
|
3174
|
+
});
|
|
3175
|
+
}
|
|
3176
|
+
}
|
|
3177
|
+
}
|
|
3178
|
+
}
|
|
3179
|
+
for (const policy of Object.values(organizationModel.policies).sort(
|
|
3180
|
+
(a, b) => a.order - b.order || a.id.localeCompare(b.id)
|
|
3181
|
+
)) {
|
|
3182
|
+
const id = nodeId("policy", policy.id);
|
|
3183
|
+
pushUniqueNode(nodes, nodeIds, {
|
|
3184
|
+
id,
|
|
3185
|
+
kind: "policy",
|
|
3186
|
+
label: policy.label,
|
|
3187
|
+
sourceId: policy.id,
|
|
3188
|
+
description: policy.description
|
|
3189
|
+
});
|
|
3190
|
+
pushUniqueEdge(edges, edgeIds, {
|
|
3191
|
+
id: edgeId("contains", organizationNode.id, id),
|
|
3192
|
+
kind: "contains",
|
|
3193
|
+
sourceId: organizationNode.id,
|
|
3194
|
+
targetId: id
|
|
3195
|
+
});
|
|
3196
|
+
for (const systemId of policy.appliesTo.systemIds) {
|
|
3197
|
+
pushUniqueEdge(edges, edgeIds, {
|
|
3198
|
+
id: edgeId("applies_to", id, systemNodeId(systemId), "system"),
|
|
3199
|
+
kind: "applies_to",
|
|
3200
|
+
sourceId: id,
|
|
3201
|
+
targetId: systemNodeId(systemId)
|
|
3202
|
+
});
|
|
3203
|
+
}
|
|
3204
|
+
for (const actionId of policy.appliesTo.actionIds) {
|
|
3205
|
+
pushUniqueEdge(edges, edgeIds, {
|
|
3206
|
+
id: edgeId("applies_to", id, nodeId("action", actionId), "action"),
|
|
3207
|
+
kind: "applies_to",
|
|
3208
|
+
sourceId: id,
|
|
3209
|
+
targetId: nodeId("action", actionId)
|
|
3210
|
+
});
|
|
3211
|
+
}
|
|
3212
|
+
for (const resourceId of policy.appliesTo.resourceIds) {
|
|
3213
|
+
const resourceNode = ensureResourceNode(nodes, nodeIds, resourceNodesById, resourceId);
|
|
3214
|
+
pushUniqueEdge(edges, edgeIds, {
|
|
3215
|
+
id: edgeId("applies_to", id, resourceNode.id, "resource"),
|
|
3216
|
+
kind: "applies_to",
|
|
3217
|
+
sourceId: id,
|
|
3218
|
+
targetId: resourceNode.id
|
|
3219
|
+
});
|
|
3220
|
+
}
|
|
3221
|
+
for (const roleId of policy.appliesTo.roleIds) {
|
|
3222
|
+
pushUniqueEdge(edges, edgeIds, {
|
|
3223
|
+
id: edgeId("applies_to", id, nodeId("role", roleId), "role"),
|
|
3224
|
+
kind: "applies_to",
|
|
3225
|
+
sourceId: id,
|
|
3226
|
+
targetId: nodeId("role", roleId)
|
|
3227
|
+
});
|
|
3228
|
+
}
|
|
3229
|
+
if (policy.trigger.kind === "event") {
|
|
3230
|
+
const eventNode = projectedEventNodeIdsByEventId.get(policy.trigger.eventId);
|
|
3231
|
+
if (eventNode !== void 0) {
|
|
3232
|
+
pushUniqueEdge(edges, edgeIds, {
|
|
3233
|
+
id: edgeId("triggers", eventNode, id),
|
|
3234
|
+
kind: "triggers",
|
|
3235
|
+
sourceId: eventNode,
|
|
3236
|
+
targetId: id
|
|
3237
|
+
});
|
|
3238
|
+
}
|
|
3239
|
+
} else if (policy.trigger.kind === "action-invocation") {
|
|
3240
|
+
pushUniqueEdge(edges, edgeIds, {
|
|
3241
|
+
id: edgeId("triggers", nodeId("action", policy.trigger.actionId), id),
|
|
3242
|
+
kind: "triggers",
|
|
3243
|
+
sourceId: nodeId("action", policy.trigger.actionId),
|
|
3244
|
+
targetId: id
|
|
3245
|
+
});
|
|
3246
|
+
}
|
|
3247
|
+
for (const [effectIndex, effect] of policy.actions.entries()) {
|
|
3248
|
+
if (effect.kind === "invoke-action") {
|
|
3249
|
+
pushUniqueEdge(edges, edgeIds, {
|
|
3250
|
+
id: edgeId("effects", id, nodeId("action", effect.actionId), `invoke-action-${effectIndex}`),
|
|
3251
|
+
kind: "effects",
|
|
3252
|
+
sourceId: id,
|
|
3253
|
+
targetId: nodeId("action", effect.actionId),
|
|
3254
|
+
label: "invoke action"
|
|
3255
|
+
});
|
|
3256
|
+
}
|
|
3257
|
+
if ((effect.kind === "notify-role" || effect.kind === "require-approval") && effect.roleId !== void 0) {
|
|
3258
|
+
pushUniqueEdge(edges, edgeIds, {
|
|
3259
|
+
id: edgeId("effects", id, nodeId("role", effect.roleId), `${effect.kind}-${effectIndex}`),
|
|
3260
|
+
kind: "effects",
|
|
3261
|
+
sourceId: id,
|
|
3262
|
+
targetId: nodeId("role", effect.roleId),
|
|
3263
|
+
label: effect.kind
|
|
3264
|
+
});
|
|
3265
|
+
}
|
|
3266
|
+
}
|
|
3267
|
+
}
|
|
3268
|
+
for (const segment of Object.values(organizationModel.customers).sort(
|
|
3269
|
+
(a, b) => a.order - b.order || a.id.localeCompare(b.id)
|
|
3270
|
+
)) {
|
|
3271
|
+
const id = nodeId("customer-segment", segment.id);
|
|
3272
|
+
pushUniqueNode(nodes, nodeIds, {
|
|
3273
|
+
id,
|
|
3274
|
+
kind: "customer-segment",
|
|
3275
|
+
label: segment.name,
|
|
3276
|
+
sourceId: segment.id,
|
|
3277
|
+
description: segment.description || void 0
|
|
3278
|
+
});
|
|
3279
|
+
pushUniqueEdge(edges, edgeIds, {
|
|
3280
|
+
id: edgeId("contains", organizationNode.id, id),
|
|
3281
|
+
kind: "contains",
|
|
3282
|
+
sourceId: organizationNode.id,
|
|
3283
|
+
targetId: id
|
|
3284
|
+
});
|
|
3285
|
+
}
|
|
3286
|
+
for (const product of Object.values(organizationModel.offerings).sort(
|
|
3287
|
+
(a, b) => a.order - b.order || a.id.localeCompare(b.id)
|
|
3288
|
+
)) {
|
|
3289
|
+
const id = nodeId("offering", product.id);
|
|
3290
|
+
pushUniqueNode(nodes, nodeIds, {
|
|
3291
|
+
id,
|
|
3292
|
+
kind: "offering",
|
|
3293
|
+
label: product.name,
|
|
3294
|
+
sourceId: product.id,
|
|
3295
|
+
description: product.description || void 0
|
|
3296
|
+
});
|
|
3297
|
+
pushUniqueEdge(edges, edgeIds, {
|
|
3298
|
+
id: edgeId("contains", organizationNode.id, id),
|
|
3299
|
+
kind: "contains",
|
|
3300
|
+
sourceId: organizationNode.id,
|
|
3301
|
+
targetId: id
|
|
3302
|
+
});
|
|
3303
|
+
for (const segmentId of product.targetSegmentIds) {
|
|
3304
|
+
pushUniqueEdge(edges, edgeIds, {
|
|
3305
|
+
id: edgeId("applies_to", id, nodeId("customer-segment", segmentId), "targets-segment"),
|
|
3306
|
+
kind: "applies_to",
|
|
3307
|
+
sourceId: id,
|
|
3308
|
+
targetId: nodeId("customer-segment", segmentId),
|
|
3309
|
+
label: "targets"
|
|
3310
|
+
});
|
|
3311
|
+
}
|
|
3312
|
+
}
|
|
3313
|
+
for (const objective of Object.values(organizationModel.goals).sort(
|
|
3314
|
+
(a, b) => a.order - b.order || a.id.localeCompare(b.id)
|
|
3315
|
+
)) {
|
|
3316
|
+
const id = nodeId("goal", objective.id);
|
|
3317
|
+
pushUniqueNode(nodes, nodeIds, {
|
|
3318
|
+
id,
|
|
3319
|
+
kind: "goal",
|
|
3320
|
+
label: objective.description,
|
|
3321
|
+
sourceId: objective.id
|
|
3322
|
+
});
|
|
3323
|
+
pushUniqueEdge(edges, edgeIds, {
|
|
3324
|
+
id: edgeId("contains", organizationNode.id, id),
|
|
3325
|
+
kind: "contains",
|
|
3326
|
+
sourceId: organizationNode.id,
|
|
3327
|
+
targetId: id
|
|
3328
|
+
});
|
|
3329
|
+
}
|
|
3330
|
+
const sidebarGroups = [];
|
|
3331
|
+
const sidebarSurfaces = [];
|
|
3332
|
+
collectSidebarGraphNodes(organizationModel.navigation.sidebar.primary, sidebarGroups, sidebarSurfaces);
|
|
3333
|
+
collectSidebarGraphNodes(organizationModel.navigation.sidebar.bottom, sidebarGroups, sidebarSurfaces);
|
|
3334
|
+
for (const { id: surfaceSourceId, node: surface, parentGroupId } of sidebarSurfaces) {
|
|
3335
|
+
const id = nodeId("surface", surfaceSourceId);
|
|
3336
|
+
pushUniqueNode(nodes, nodeIds, {
|
|
3337
|
+
id,
|
|
3338
|
+
kind: "surface",
|
|
3339
|
+
label: surface.label,
|
|
3340
|
+
sourceId: surfaceSourceId,
|
|
3341
|
+
description: surface.description,
|
|
3342
|
+
icon: surface.icon,
|
|
3343
|
+
enabled: true
|
|
3344
|
+
});
|
|
3345
|
+
pushUniqueEdge(edges, edgeIds, {
|
|
3346
|
+
id: edgeId("contains", parentGroupId ? nodeId("navigation-group", parentGroupId) : organizationNode.id, id),
|
|
3347
|
+
kind: "contains",
|
|
3348
|
+
sourceId: parentGroupId ? nodeId("navigation-group", parentGroupId) : organizationNode.id,
|
|
3349
|
+
targetId: id
|
|
3350
|
+
});
|
|
3351
|
+
for (const systemId of surface.targets?.systems ?? []) {
|
|
3352
|
+
if (!validSystemRefs.has(systemId)) continue;
|
|
3353
|
+
pushUniqueEdge(edges, edgeIds, {
|
|
3354
|
+
id: edgeId("applies_to", id, systemNodeId(systemId), "surface-system"),
|
|
3355
|
+
kind: "applies_to",
|
|
3356
|
+
sourceId: id,
|
|
3357
|
+
targetId: systemNodeId(systemId)
|
|
3358
|
+
});
|
|
3359
|
+
}
|
|
3360
|
+
}
|
|
3361
|
+
for (const { id: groupSourceId, node: group, parentGroupId } of sidebarGroups) {
|
|
3362
|
+
const id = nodeId("navigation-group", groupSourceId);
|
|
3363
|
+
pushUniqueNode(nodes, nodeIds, {
|
|
3364
|
+
id,
|
|
3365
|
+
kind: "navigation-group",
|
|
3366
|
+
label: group.label,
|
|
3367
|
+
sourceId: groupSourceId
|
|
3368
|
+
});
|
|
3369
|
+
pushUniqueEdge(edges, edgeIds, {
|
|
3370
|
+
id: edgeId("contains", parentGroupId ? nodeId("navigation-group", parentGroupId) : organizationNode.id, id),
|
|
3371
|
+
kind: "contains",
|
|
3372
|
+
sourceId: parentGroupId ? nodeId("navigation-group", parentGroupId) : organizationNode.id,
|
|
3373
|
+
targetId: id
|
|
3374
|
+
});
|
|
3375
|
+
}
|
|
3376
|
+
for (const { path, system } of listAllSystems(organizationModel).sort((a, b) => a.path.localeCompare(b.path))) {
|
|
3377
|
+
const contentMap = system.content ?? {};
|
|
3378
|
+
const systemSpineId = nodeId("system", path);
|
|
3379
|
+
for (const [localId, contentNode] of Object.entries(contentMap).sort(([a], [b]) => a.localeCompare(b))) {
|
|
3380
|
+
const contentNodeGraphId = `content-node:${path}:${localId}`;
|
|
3381
|
+
pushUniqueNode(nodes, nodeIds, {
|
|
3382
|
+
id: contentNodeGraphId,
|
|
3383
|
+
kind: "content-node",
|
|
3384
|
+
label: contentNode.label,
|
|
3385
|
+
sourceId: `${path}:${localId}`,
|
|
3386
|
+
description: contentNode.description
|
|
3387
|
+
// Spread contentKind and contentType into attributes; the node schema
|
|
3388
|
+
// does not have custom attribute slots, so we encode them in the label
|
|
3389
|
+
// suffix for now. The actual kind/type are recoverable from sourceId +
|
|
3390
|
+
// the registry lookup by consumers.
|
|
3391
|
+
});
|
|
3392
|
+
pushUniqueEdge(edges, edgeIds, {
|
|
3393
|
+
id: edgeId("contains", systemSpineId, contentNodeGraphId, "system-content"),
|
|
3394
|
+
kind: "contains",
|
|
3395
|
+
sourceId: systemSpineId,
|
|
3396
|
+
targetId: contentNodeGraphId
|
|
3397
|
+
});
|
|
3398
|
+
if (contentNode.parentContentId) {
|
|
3399
|
+
const parentContentNodeGraphId = `content-node:${path}:${contentNode.parentContentId}`;
|
|
3400
|
+
pushUniqueEdge(edges, edgeIds, {
|
|
3401
|
+
id: edgeId("contains", parentContentNodeGraphId, contentNodeGraphId, "content-parent"),
|
|
3402
|
+
kind: "contains",
|
|
3403
|
+
sourceId: parentContentNodeGraphId,
|
|
3404
|
+
targetId: contentNodeGraphId
|
|
3405
|
+
});
|
|
3406
|
+
}
|
|
3407
|
+
if (contentNode.kind === "schema" && contentNode.type === "pipeline" && contentNode.data && typeof contentNode.data["entityId"] === "string") {
|
|
3408
|
+
const targetEntityId = nodeId("entity", contentNode.data["entityId"]);
|
|
3409
|
+
pushUniqueEdge(edges, edgeIds, {
|
|
3410
|
+
id: edgeId("references", contentNodeGraphId, targetEntityId, "pipeline-entity"),
|
|
3411
|
+
kind: "references",
|
|
3412
|
+
sourceId: contentNodeGraphId,
|
|
3413
|
+
targetId: targetEntityId,
|
|
3414
|
+
label: "applies to entity"
|
|
3415
|
+
});
|
|
3416
|
+
}
|
|
3417
|
+
}
|
|
3418
|
+
}
|
|
3419
|
+
for (const template of getAllBuildTemplates(organizationModel).sort((a, b) => a.id.localeCompare(b.id))) {
|
|
3420
|
+
const steps = template.steps;
|
|
3421
|
+
const stepById = new Map(steps.map((s) => [s.id, s]));
|
|
3422
|
+
for (const step of [...steps].sort((a, b) => a.id.localeCompare(b.id))) {
|
|
3423
|
+
const stageNodeId = nodeId("stage", step.stageKey);
|
|
3424
|
+
const actionNodeId = nodeId("action", step.actionKey);
|
|
3425
|
+
pushUniqueEdge(edges, edgeIds, {
|
|
3426
|
+
id: edgeId("uses", stageNodeId, actionNodeId, step.id),
|
|
3427
|
+
kind: "uses",
|
|
3428
|
+
sourceId: stageNodeId,
|
|
3429
|
+
targetId: actionNodeId
|
|
3430
|
+
});
|
|
3431
|
+
for (const depId of step.dependsOn ?? []) {
|
|
3432
|
+
const depStep = stepById.get(depId);
|
|
3433
|
+
if (depStep) {
|
|
3434
|
+
const depStageNodeId = nodeId("stage", depStep.stageKey);
|
|
3435
|
+
pushUniqueEdge(edges, edgeIds, {
|
|
3436
|
+
id: edgeId("references", stageNodeId, depStageNodeId, step.id),
|
|
3437
|
+
kind: "references",
|
|
3438
|
+
sourceId: stageNodeId,
|
|
3439
|
+
targetId: depStageNodeId
|
|
3440
|
+
});
|
|
3441
|
+
}
|
|
3442
|
+
}
|
|
3443
|
+
}
|
|
3444
|
+
}
|
|
3445
|
+
if (commandViewData) {
|
|
3446
|
+
const commandViewResources = collectCommandViewResources(commandViewData).sort(
|
|
3447
|
+
(a, b) => a.resourceId.localeCompare(b.resourceId)
|
|
3448
|
+
);
|
|
3449
|
+
for (const resource of commandViewResources) {
|
|
3450
|
+
const id = nodeId("resource", resource.resourceId);
|
|
3451
|
+
const resourceNode = upsertResourceNode(nodes, nodeIds, resourceNodesById, {
|
|
3452
|
+
id,
|
|
3453
|
+
kind: "resource",
|
|
3454
|
+
label: resource.name,
|
|
3455
|
+
sourceId: resource.resourceId,
|
|
3456
|
+
description: resource.description,
|
|
3457
|
+
resourceType: normalizeCommandViewResourceType(resource.type)
|
|
3458
|
+
});
|
|
3459
|
+
if (!organizationModelResourceIds.has(resource.resourceId)) {
|
|
3460
|
+
pushUniqueEdge(edges, edgeIds, {
|
|
3461
|
+
id: edgeId("contains", organizationNode.id, resourceNode.id),
|
|
3462
|
+
kind: "contains",
|
|
3463
|
+
sourceId: organizationNode.id,
|
|
3464
|
+
targetId: resourceNode.id
|
|
3465
|
+
});
|
|
3466
|
+
}
|
|
3467
|
+
}
|
|
3468
|
+
for (const relationship of [...commandViewData.edges].sort((a, b) => a.id.localeCompare(b.id))) {
|
|
3469
|
+
const sourceNode = ensureResourceNode(nodes, nodeIds, resourceNodesById, relationship.source);
|
|
3470
|
+
const targetNode = ensureResourceNode(nodes, nodeIds, resourceNodesById, relationship.target);
|
|
3471
|
+
pushUniqueEdge(edges, edgeIds, {
|
|
3472
|
+
id: edgeId("contains", organizationNode.id, sourceNode.id),
|
|
3473
|
+
kind: "contains",
|
|
3474
|
+
sourceId: organizationNode.id,
|
|
3475
|
+
targetId: sourceNode.id
|
|
3476
|
+
});
|
|
3477
|
+
pushUniqueEdge(edges, edgeIds, {
|
|
3478
|
+
id: edgeId("contains", organizationNode.id, targetNode.id),
|
|
3479
|
+
kind: "contains",
|
|
3480
|
+
sourceId: organizationNode.id,
|
|
3481
|
+
targetId: targetNode.id
|
|
3482
|
+
});
|
|
3483
|
+
pushUniqueEdge(edges, edgeIds, {
|
|
3484
|
+
id: edgeId("references", sourceNode.id, targetNode.id, relationship.relationship),
|
|
3485
|
+
kind: "references",
|
|
3486
|
+
sourceId: sourceNode.id,
|
|
3487
|
+
targetId: targetNode.id,
|
|
3488
|
+
label: relationship.relationship,
|
|
3489
|
+
relationshipType: relationship.relationship
|
|
3490
|
+
});
|
|
3491
|
+
}
|
|
3492
|
+
}
|
|
3493
|
+
const graph = {
|
|
3494
|
+
version: 1,
|
|
3495
|
+
organizationModelVersion: organizationModel.version,
|
|
3496
|
+
nodes,
|
|
3497
|
+
edges
|
|
3498
|
+
};
|
|
3499
|
+
return OrganizationGraphSchema.parse(graph);
|
|
3500
|
+
}
|
|
3501
|
+
|
|
3502
|
+
// ../core/src/organization-model/defaults.ts
|
|
3503
|
+
var DEFAULT_ORGANIZATION_MODEL_KNOWLEDGE = {};
|
|
3504
|
+
var DEFAULT_ORGANIZATION_MODEL_ENTITIES2 = DEFAULT_ORGANIZATION_MODEL_ENTITIES;
|
|
3505
|
+
var DEFAULT_ORGANIZATION_MODEL_NAVIGATION = {
|
|
3506
|
+
sidebar: {
|
|
3507
|
+
primary: {
|
|
3508
|
+
dashboard: {
|
|
3509
|
+
type: "surface",
|
|
3510
|
+
label: "Dashboard",
|
|
3511
|
+
path: "/",
|
|
3512
|
+
surfaceType: "dashboard",
|
|
3513
|
+
icon: "feature.dashboard",
|
|
3514
|
+
order: 10,
|
|
3515
|
+
targets: { systems: ["dashboard"] }
|
|
3516
|
+
},
|
|
3517
|
+
business: {
|
|
3518
|
+
type: "group",
|
|
3519
|
+
label: "Business",
|
|
3520
|
+
icon: "feature.business",
|
|
3521
|
+
order: 20,
|
|
3522
|
+
children: {
|
|
3523
|
+
sales: {
|
|
3524
|
+
type: "surface",
|
|
3525
|
+
label: "Sales",
|
|
3526
|
+
path: "/sales",
|
|
3527
|
+
surfaceType: "page",
|
|
3528
|
+
icon: "feature.sales",
|
|
3529
|
+
order: 10,
|
|
3530
|
+
targets: { systems: ["sales"] }
|
|
3531
|
+
},
|
|
3532
|
+
clients: {
|
|
3533
|
+
type: "surface",
|
|
3534
|
+
label: "Clients",
|
|
3535
|
+
path: "/clients",
|
|
3536
|
+
surfaceType: "list",
|
|
3537
|
+
icon: "feature.projects",
|
|
3538
|
+
order: 20,
|
|
3539
|
+
targets: { systems: ["clients"] }
|
|
3540
|
+
},
|
|
3541
|
+
projects: {
|
|
3542
|
+
type: "surface",
|
|
3543
|
+
label: "Projects",
|
|
3544
|
+
path: "/projects",
|
|
3545
|
+
surfaceType: "page",
|
|
3546
|
+
icon: "feature.projects",
|
|
3547
|
+
order: 30,
|
|
3548
|
+
targets: { systems: ["projects"] }
|
|
3549
|
+
}
|
|
3550
|
+
}
|
|
3551
|
+
},
|
|
3552
|
+
operations: {
|
|
3553
|
+
type: "group",
|
|
3554
|
+
label: "Operations",
|
|
3555
|
+
icon: "feature.operations",
|
|
3556
|
+
order: 30,
|
|
3557
|
+
children: {
|
|
3558
|
+
"operations-overview": {
|
|
3559
|
+
type: "surface",
|
|
3560
|
+
label: "Overview",
|
|
3561
|
+
path: "/operations",
|
|
3562
|
+
surfaceType: "page",
|
|
3563
|
+
order: 10,
|
|
3564
|
+
targets: { systems: ["operations.overview"] }
|
|
3565
|
+
},
|
|
3566
|
+
"operations-systems": {
|
|
3567
|
+
type: "surface",
|
|
3568
|
+
label: "Systems",
|
|
3569
|
+
path: "/operations/systems",
|
|
3570
|
+
surfaceType: "page",
|
|
3571
|
+
order: 20,
|
|
3572
|
+
targets: { systems: ["operations"] }
|
|
3573
|
+
},
|
|
3574
|
+
"operations-resources": {
|
|
3575
|
+
type: "surface",
|
|
3576
|
+
label: "Resources",
|
|
3577
|
+
path: "/operations/resources",
|
|
3578
|
+
surfaceType: "list",
|
|
3579
|
+
order: 30,
|
|
3580
|
+
targets: { systems: ["operations.resources"] }
|
|
3581
|
+
},
|
|
3582
|
+
"operations-command-queue": {
|
|
3583
|
+
type: "surface",
|
|
3584
|
+
label: "Command Queue",
|
|
3585
|
+
path: "/operations/command-queue",
|
|
3586
|
+
surfaceType: "list",
|
|
3587
|
+
order: 40,
|
|
3588
|
+
targets: { systems: ["operations.command-queue"] }
|
|
3589
|
+
},
|
|
3590
|
+
"operations-task-scheduler": {
|
|
3591
|
+
type: "surface",
|
|
3592
|
+
label: "Task Scheduler",
|
|
3593
|
+
path: "/operations/task-scheduler",
|
|
3594
|
+
surfaceType: "list",
|
|
3595
|
+
order: 50,
|
|
3596
|
+
targets: { systems: ["operations.task-scheduler"] }
|
|
3597
|
+
}
|
|
3598
|
+
}
|
|
3599
|
+
},
|
|
3600
|
+
monitoring: {
|
|
3601
|
+
type: "group",
|
|
3602
|
+
label: "Monitoring",
|
|
3603
|
+
icon: "feature.monitoring",
|
|
3604
|
+
order: 40,
|
|
3605
|
+
children: {
|
|
3606
|
+
"monitoring-overview": {
|
|
3607
|
+
type: "surface",
|
|
3608
|
+
label: "Overview",
|
|
3609
|
+
path: "/monitoring",
|
|
3610
|
+
surfaceType: "page",
|
|
3611
|
+
order: 10,
|
|
3612
|
+
targets: { systems: ["monitoring"] }
|
|
3613
|
+
},
|
|
3614
|
+
"monitoring-calendar": {
|
|
3615
|
+
type: "surface",
|
|
3616
|
+
label: "Calendar",
|
|
3617
|
+
path: "/monitoring/calendar",
|
|
3618
|
+
surfaceType: "page",
|
|
3619
|
+
order: 20,
|
|
3620
|
+
targets: { systems: ["monitoring.calendar"] }
|
|
3621
|
+
},
|
|
3622
|
+
"monitoring-activity-log": {
|
|
3623
|
+
type: "surface",
|
|
3624
|
+
label: "Activity Log",
|
|
3625
|
+
path: "/monitoring/activity-log",
|
|
3626
|
+
surfaceType: "list",
|
|
3627
|
+
order: 30,
|
|
3628
|
+
targets: { systems: ["monitoring.activity-log"] }
|
|
3629
|
+
},
|
|
3630
|
+
"monitoring-execution-logs": {
|
|
3631
|
+
type: "surface",
|
|
3632
|
+
label: "Execution Logs",
|
|
3633
|
+
path: "/monitoring/execution-logs",
|
|
3634
|
+
surfaceType: "list",
|
|
3635
|
+
order: 40,
|
|
3636
|
+
targets: { systems: ["monitoring.execution-logs"] }
|
|
3637
|
+
},
|
|
3638
|
+
"monitoring-execution-health": {
|
|
3639
|
+
type: "surface",
|
|
3640
|
+
label: "Execution Health",
|
|
3641
|
+
path: "/monitoring/execution-health",
|
|
3642
|
+
surfaceType: "dashboard",
|
|
3643
|
+
order: 50,
|
|
3644
|
+
targets: { systems: ["monitoring.execution-health"] }
|
|
3645
|
+
},
|
|
3646
|
+
"monitoring-notifications": {
|
|
3647
|
+
type: "surface",
|
|
3648
|
+
label: "Notifications",
|
|
3649
|
+
path: "/monitoring/notifications",
|
|
3650
|
+
surfaceType: "list",
|
|
3651
|
+
order: 60,
|
|
3652
|
+
targets: { systems: ["monitoring.notifications"] }
|
|
3653
|
+
},
|
|
3654
|
+
"monitoring-requests": {
|
|
3655
|
+
type: "surface",
|
|
3656
|
+
label: "Requests",
|
|
3657
|
+
path: "/monitoring/requests",
|
|
3658
|
+
surfaceType: "list",
|
|
3659
|
+
order: 70,
|
|
3660
|
+
targets: { systems: ["monitoring.submitted-requests"] }
|
|
3661
|
+
}
|
|
3662
|
+
}
|
|
3663
|
+
},
|
|
3664
|
+
knowledge: {
|
|
3665
|
+
type: "group",
|
|
3666
|
+
label: "Knowledge",
|
|
3667
|
+
icon: "feature.knowledge",
|
|
3668
|
+
order: 50,
|
|
3669
|
+
children: {
|
|
3670
|
+
"knowledge-base": {
|
|
3671
|
+
type: "surface",
|
|
3672
|
+
label: "Knowledge Base",
|
|
3673
|
+
path: "/knowledge",
|
|
3674
|
+
surfaceType: "page",
|
|
3675
|
+
order: 10,
|
|
3676
|
+
targets: { systems: ["knowledge.base"] }
|
|
3677
|
+
},
|
|
3678
|
+
"knowledge-command-view": {
|
|
3679
|
+
type: "surface",
|
|
3680
|
+
label: "Command View",
|
|
3681
|
+
path: "/knowledge/command-view",
|
|
3682
|
+
surfaceType: "graph",
|
|
3683
|
+
order: 20,
|
|
3684
|
+
targets: { systems: ["knowledge.command-view"] },
|
|
3685
|
+
devOnly: true
|
|
3686
|
+
}
|
|
3687
|
+
}
|
|
3688
|
+
}
|
|
3689
|
+
},
|
|
3690
|
+
bottom: {
|
|
3691
|
+
settings: {
|
|
3692
|
+
type: "group",
|
|
3693
|
+
label: "Settings",
|
|
3694
|
+
icon: "feature.settings",
|
|
3695
|
+
order: 10,
|
|
3696
|
+
children: {
|
|
3697
|
+
"settings-account": {
|
|
3698
|
+
type: "surface",
|
|
3699
|
+
label: "Account",
|
|
3700
|
+
path: "/settings/account",
|
|
3701
|
+
surfaceType: "settings",
|
|
3702
|
+
order: 10,
|
|
3703
|
+
targets: { systems: ["settings.account"] }
|
|
3704
|
+
},
|
|
3705
|
+
"settings-appearance": {
|
|
3706
|
+
type: "surface",
|
|
3707
|
+
label: "Appearance",
|
|
3708
|
+
path: "/settings/appearance",
|
|
3709
|
+
surfaceType: "settings",
|
|
3710
|
+
order: 20,
|
|
3711
|
+
targets: { systems: ["settings.appearance"] }
|
|
3712
|
+
},
|
|
3713
|
+
"settings-roles": {
|
|
3714
|
+
type: "surface",
|
|
3715
|
+
label: "My Roles",
|
|
3716
|
+
path: "/settings/roles",
|
|
3717
|
+
surfaceType: "settings",
|
|
3718
|
+
order: 30,
|
|
3719
|
+
targets: { systems: ["settings.roles"] }
|
|
3720
|
+
},
|
|
3721
|
+
"settings-organization": {
|
|
3722
|
+
type: "surface",
|
|
3723
|
+
label: "Organization",
|
|
3724
|
+
path: "/settings/organization",
|
|
3725
|
+
surfaceType: "settings",
|
|
3726
|
+
order: 40,
|
|
3727
|
+
targets: { systems: ["settings.organization"] }
|
|
3728
|
+
},
|
|
3729
|
+
"settings-credentials": {
|
|
3730
|
+
type: "surface",
|
|
3731
|
+
label: "Credentials",
|
|
3732
|
+
path: "/settings/credentials",
|
|
3733
|
+
surfaceType: "settings",
|
|
3734
|
+
order: 50,
|
|
3735
|
+
targets: { systems: ["settings.credentials"] }
|
|
3736
|
+
},
|
|
3737
|
+
"settings-api-keys": {
|
|
3738
|
+
type: "surface",
|
|
3739
|
+
label: "API Keys",
|
|
3740
|
+
path: "/settings/api-keys",
|
|
3741
|
+
surfaceType: "settings",
|
|
3742
|
+
order: 60,
|
|
3743
|
+
targets: { systems: ["settings.api-keys"] }
|
|
3744
|
+
},
|
|
3745
|
+
"settings-webhooks": {
|
|
3746
|
+
type: "surface",
|
|
3747
|
+
label: "Webhooks",
|
|
3748
|
+
path: "/settings/webhooks",
|
|
3749
|
+
surfaceType: "settings",
|
|
3750
|
+
order: 70,
|
|
3751
|
+
targets: { systems: ["settings.webhooks"] }
|
|
3752
|
+
},
|
|
3753
|
+
"settings-deployments": {
|
|
3754
|
+
type: "surface",
|
|
3755
|
+
label: "Deployments",
|
|
3756
|
+
path: "/settings/deployments",
|
|
3757
|
+
surfaceType: "settings",
|
|
3758
|
+
order: 80,
|
|
3759
|
+
targets: { systems: ["settings.deployments"] }
|
|
3760
|
+
}
|
|
3761
|
+
}
|
|
3762
|
+
},
|
|
3763
|
+
admin: {
|
|
3764
|
+
type: "group",
|
|
3765
|
+
label: "Admin",
|
|
3766
|
+
icon: "feature.admin",
|
|
3767
|
+
order: 20,
|
|
3768
|
+
children: {
|
|
3769
|
+
"admin-dashboard": {
|
|
3770
|
+
type: "surface",
|
|
3771
|
+
label: "Dashboard",
|
|
3772
|
+
path: "/admin/dashboard",
|
|
3773
|
+
surfaceType: "dashboard",
|
|
3774
|
+
order: 10,
|
|
3775
|
+
targets: { systems: ["admin"] },
|
|
3776
|
+
requiresAdmin: true
|
|
3777
|
+
},
|
|
3778
|
+
"admin-system-health": {
|
|
3779
|
+
type: "surface",
|
|
3780
|
+
label: "System Health",
|
|
3781
|
+
path: "/admin/system-health",
|
|
3782
|
+
surfaceType: "dashboard",
|
|
3783
|
+
order: 20,
|
|
3784
|
+
targets: { systems: ["admin.system-health"] },
|
|
3785
|
+
requiresAdmin: true
|
|
3786
|
+
},
|
|
3787
|
+
"admin-organizations": {
|
|
3788
|
+
type: "surface",
|
|
3789
|
+
label: "Organizations",
|
|
3790
|
+
path: "/admin/organizations",
|
|
3791
|
+
surfaceType: "list",
|
|
3792
|
+
order: 30,
|
|
3793
|
+
targets: { systems: ["admin.organizations"] },
|
|
3794
|
+
requiresAdmin: true
|
|
3795
|
+
},
|
|
3796
|
+
"admin-users": {
|
|
3797
|
+
type: "surface",
|
|
3798
|
+
label: "Users",
|
|
3799
|
+
path: "/admin/users",
|
|
3800
|
+
surfaceType: "list",
|
|
3801
|
+
order: 40,
|
|
3802
|
+
targets: { systems: ["admin.users"] },
|
|
3803
|
+
requiresAdmin: true
|
|
3804
|
+
},
|
|
3805
|
+
"admin-design-showcase": {
|
|
3806
|
+
type: "surface",
|
|
3807
|
+
label: "Design Showcase",
|
|
3808
|
+
path: "/admin/design-showcase",
|
|
3809
|
+
surfaceType: "page",
|
|
3810
|
+
order: 50,
|
|
3811
|
+
targets: { systems: ["admin.design-showcase"] },
|
|
3812
|
+
requiresAdmin: true
|
|
3813
|
+
},
|
|
3814
|
+
"admin-debug": {
|
|
3815
|
+
type: "surface",
|
|
3816
|
+
label: "Debug",
|
|
3817
|
+
path: "/admin/debug",
|
|
3818
|
+
surfaceType: "page",
|
|
3819
|
+
order: 60,
|
|
3820
|
+
targets: { systems: ["admin.debug"] },
|
|
3821
|
+
requiresAdmin: true
|
|
3822
|
+
}
|
|
3823
|
+
}
|
|
3824
|
+
}
|
|
3825
|
+
}
|
|
3826
|
+
}
|
|
3827
|
+
};
|
|
3828
|
+
var DEFAULT_ORGANIZATION_MODEL = {
|
|
3829
|
+
version: 1,
|
|
3830
|
+
domainMetadata: DEFAULT_ORGANIZATION_MODEL_DOMAIN_METADATA,
|
|
3831
|
+
branding: DEFAULT_ORGANIZATION_MODEL_BRANDING,
|
|
3832
|
+
navigation: DEFAULT_ORGANIZATION_MODEL_NAVIGATION,
|
|
3833
|
+
identity: DEFAULT_ORGANIZATION_MODEL_IDENTITY,
|
|
3834
|
+
customers: DEFAULT_ORGANIZATION_MODEL_CUSTOMERS,
|
|
3835
|
+
offerings: DEFAULT_ORGANIZATION_MODEL_OFFERINGS,
|
|
3836
|
+
roles: DEFAULT_ORGANIZATION_MODEL_ROLES,
|
|
3837
|
+
goals: DEFAULT_ORGANIZATION_MODEL_GOALS,
|
|
3838
|
+
systems: {
|
|
3839
|
+
dashboard: {
|
|
3840
|
+
id: "dashboard",
|
|
3841
|
+
order: 10,
|
|
3842
|
+
label: "Dashboard",
|
|
3843
|
+
enabled: true,
|
|
3844
|
+
lifecycle: "active",
|
|
3845
|
+
path: "/",
|
|
3846
|
+
icon: "feature.dashboard"
|
|
3847
|
+
},
|
|
3848
|
+
platform: {
|
|
3849
|
+
id: "platform",
|
|
3850
|
+
order: 30,
|
|
3851
|
+
label: "Platform",
|
|
3852
|
+
description: "Elevasis platform architecture, capabilities, and implementation patterns",
|
|
3853
|
+
enabled: true,
|
|
3854
|
+
lifecycle: "active",
|
|
3855
|
+
color: "cyan",
|
|
3856
|
+
icon: "feature.platform"
|
|
3857
|
+
},
|
|
3858
|
+
finance: {
|
|
3859
|
+
id: "finance",
|
|
3860
|
+
order: 40,
|
|
3861
|
+
label: "Finance",
|
|
3862
|
+
description: "Finance operations, accounting, billing, reconciliation, and tax prep",
|
|
3863
|
+
enabled: true,
|
|
3864
|
+
lifecycle: "active",
|
|
3865
|
+
color: "green",
|
|
3866
|
+
icon: "feature.finance"
|
|
3867
|
+
},
|
|
3868
|
+
sales: {
|
|
3869
|
+
id: "sales",
|
|
3870
|
+
order: 60,
|
|
3871
|
+
label: "Sales",
|
|
3872
|
+
description: "Revenue workflows and customer acquisition",
|
|
3873
|
+
enabled: true,
|
|
3874
|
+
lifecycle: "active",
|
|
3875
|
+
color: "blue",
|
|
3876
|
+
icon: "feature.sales",
|
|
3877
|
+
path: "/sales"
|
|
3878
|
+
},
|
|
3879
|
+
"sales.crm": {
|
|
3880
|
+
id: "sales.crm",
|
|
3881
|
+
order: 70,
|
|
3882
|
+
label: "CRM",
|
|
3883
|
+
description: "Relationship pipeline and deal management",
|
|
3884
|
+
enabled: true,
|
|
3885
|
+
lifecycle: "active",
|
|
3886
|
+
color: "blue",
|
|
3887
|
+
icon: "feature.crm",
|
|
3888
|
+
path: "/crm"
|
|
3889
|
+
},
|
|
3890
|
+
"sales.lead-gen": {
|
|
3891
|
+
id: "sales.lead-gen",
|
|
3892
|
+
order: 80,
|
|
3893
|
+
label: "Lead Gen",
|
|
3894
|
+
description: "Prospecting, qualification, and outreach preparation",
|
|
3895
|
+
enabled: true,
|
|
3896
|
+
lifecycle: "active",
|
|
3897
|
+
actions: Object.values(DEFAULT_ORGANIZATION_MODEL_ACTIONS).map((action) => ({
|
|
3898
|
+
actionId: action.id,
|
|
3899
|
+
intent: "exposes"
|
|
3900
|
+
})),
|
|
3901
|
+
color: "cyan",
|
|
3902
|
+
icon: "feature.lead-gen",
|
|
3903
|
+
path: "/lead-gen"
|
|
3904
|
+
},
|
|
3905
|
+
projects: {
|
|
3906
|
+
id: "projects",
|
|
3907
|
+
order: 90,
|
|
3908
|
+
label: "Projects",
|
|
3909
|
+
description: "Projects, milestones, and client work execution",
|
|
3910
|
+
enabled: true,
|
|
3911
|
+
lifecycle: "active",
|
|
3912
|
+
color: "orange",
|
|
3913
|
+
icon: "feature.projects",
|
|
3914
|
+
path: "/projects"
|
|
3915
|
+
},
|
|
3916
|
+
clients: {
|
|
3917
|
+
id: "clients",
|
|
3918
|
+
order: 100,
|
|
3919
|
+
label: "Clients",
|
|
3920
|
+
description: "Client relationships, accounts, and business context",
|
|
3921
|
+
enabled: true,
|
|
3922
|
+
lifecycle: "active",
|
|
3923
|
+
color: "orange",
|
|
3924
|
+
icon: "feature.projects",
|
|
3925
|
+
path: "/clients"
|
|
3926
|
+
},
|
|
3927
|
+
operations: {
|
|
3928
|
+
id: "operations",
|
|
3929
|
+
order: 110,
|
|
3930
|
+
label: "Operations",
|
|
3931
|
+
description: "Operational resources, topology, and orchestration visibility",
|
|
3932
|
+
enabled: true,
|
|
3933
|
+
lifecycle: "active",
|
|
3934
|
+
color: "violet",
|
|
3935
|
+
icon: "feature.operations"
|
|
3936
|
+
},
|
|
3937
|
+
"knowledge.command-view": {
|
|
3938
|
+
id: "knowledge.command-view",
|
|
3939
|
+
order: 120,
|
|
3940
|
+
label: "Command View",
|
|
3941
|
+
enabled: true,
|
|
3942
|
+
lifecycle: "active",
|
|
3943
|
+
path: "/knowledge/command-view",
|
|
3944
|
+
devOnly: true
|
|
3945
|
+
},
|
|
3946
|
+
"operations.overview": {
|
|
3947
|
+
id: "operations.overview",
|
|
3948
|
+
order: 130,
|
|
3949
|
+
label: "Overview",
|
|
3950
|
+
enabled: true,
|
|
3951
|
+
lifecycle: "active",
|
|
3952
|
+
path: "/operations"
|
|
3953
|
+
},
|
|
3954
|
+
"operations.resources": {
|
|
3955
|
+
id: "operations.resources",
|
|
3956
|
+
order: 140,
|
|
3957
|
+
label: "Resources",
|
|
3958
|
+
enabled: true,
|
|
3959
|
+
lifecycle: "active",
|
|
3960
|
+
path: "/operations/resources"
|
|
3961
|
+
},
|
|
3962
|
+
"operations.command-queue": {
|
|
3963
|
+
id: "operations.command-queue",
|
|
3964
|
+
order: 150,
|
|
3965
|
+
label: "Command Queue",
|
|
3966
|
+
enabled: true,
|
|
3967
|
+
lifecycle: "active",
|
|
3968
|
+
path: "/operations/command-queue"
|
|
3969
|
+
},
|
|
3970
|
+
"operations.sessions": {
|
|
3971
|
+
id: "operations.sessions",
|
|
3972
|
+
order: 160,
|
|
3973
|
+
label: "Sessions",
|
|
3974
|
+
enabled: false,
|
|
3975
|
+
lifecycle: "deprecated",
|
|
3976
|
+
path: "/operations/sessions"
|
|
3977
|
+
},
|
|
3978
|
+
"operations.task-scheduler": {
|
|
3979
|
+
id: "operations.task-scheduler",
|
|
3980
|
+
order: 170,
|
|
3981
|
+
label: "Task Scheduler",
|
|
3982
|
+
enabled: true,
|
|
3983
|
+
lifecycle: "active",
|
|
3984
|
+
path: "/operations/task-scheduler"
|
|
3985
|
+
},
|
|
3986
|
+
monitoring: {
|
|
3987
|
+
id: "monitoring",
|
|
3988
|
+
order: 180,
|
|
3989
|
+
label: "Monitoring",
|
|
3990
|
+
enabled: true,
|
|
3991
|
+
lifecycle: "active"
|
|
3992
|
+
},
|
|
3993
|
+
"monitoring.calendar": {
|
|
3994
|
+
id: "monitoring.calendar",
|
|
3995
|
+
order: 190,
|
|
3996
|
+
label: "Calendar",
|
|
3997
|
+
description: "Google Calendar events and agenda views",
|
|
3998
|
+
enabled: true,
|
|
3999
|
+
lifecycle: "active",
|
|
4000
|
+
path: "/monitoring/calendar",
|
|
4001
|
+
icon: "feature.calendar"
|
|
4002
|
+
},
|
|
4003
|
+
"monitoring.activity-log": {
|
|
4004
|
+
id: "monitoring.activity-log",
|
|
4005
|
+
order: 200,
|
|
4006
|
+
label: "Activity Log",
|
|
4007
|
+
enabled: true,
|
|
4008
|
+
lifecycle: "active",
|
|
4009
|
+
path: "/monitoring/activity-log"
|
|
4010
|
+
},
|
|
4011
|
+
"monitoring.execution-logs": {
|
|
4012
|
+
id: "monitoring.execution-logs",
|
|
4013
|
+
order: 210,
|
|
4014
|
+
label: "Execution Logs",
|
|
4015
|
+
enabled: true,
|
|
4016
|
+
lifecycle: "active",
|
|
4017
|
+
path: "/monitoring/execution-logs"
|
|
4018
|
+
},
|
|
4019
|
+
"monitoring.execution-health": {
|
|
4020
|
+
id: "monitoring.execution-health",
|
|
4021
|
+
order: 220,
|
|
4022
|
+
label: "Execution Health",
|
|
4023
|
+
enabled: true,
|
|
4024
|
+
lifecycle: "active",
|
|
4025
|
+
path: "/monitoring/execution-health"
|
|
4026
|
+
},
|
|
4027
|
+
"monitoring.cost-analytics": {
|
|
4028
|
+
id: "monitoring.cost-analytics",
|
|
4029
|
+
order: 230,
|
|
4030
|
+
label: "Cost Analytics",
|
|
4031
|
+
enabled: false,
|
|
4032
|
+
lifecycle: "deprecated",
|
|
4033
|
+
path: "/monitoring/cost-analytics"
|
|
4034
|
+
},
|
|
4035
|
+
"monitoring.notifications": {
|
|
4036
|
+
id: "monitoring.notifications",
|
|
4037
|
+
order: 240,
|
|
4038
|
+
label: "Notifications",
|
|
4039
|
+
enabled: true,
|
|
4040
|
+
lifecycle: "active",
|
|
4041
|
+
path: "/monitoring/notifications"
|
|
4042
|
+
},
|
|
4043
|
+
"monitoring.submitted-requests": {
|
|
4044
|
+
id: "monitoring.submitted-requests",
|
|
4045
|
+
order: 250,
|
|
4046
|
+
label: "Submitted Requests",
|
|
4047
|
+
enabled: true,
|
|
4048
|
+
lifecycle: "active",
|
|
4049
|
+
path: "/monitoring/requests"
|
|
4050
|
+
},
|
|
4051
|
+
settings: {
|
|
4052
|
+
id: "settings",
|
|
4053
|
+
order: 260,
|
|
4054
|
+
label: "Settings",
|
|
4055
|
+
enabled: true,
|
|
4056
|
+
lifecycle: "active",
|
|
4057
|
+
icon: "feature.settings"
|
|
4058
|
+
},
|
|
4059
|
+
"settings.account": {
|
|
4060
|
+
id: "settings.account",
|
|
4061
|
+
order: 270,
|
|
4062
|
+
label: "Account",
|
|
4063
|
+
enabled: true,
|
|
4064
|
+
lifecycle: "active",
|
|
4065
|
+
path: "/settings/account"
|
|
4066
|
+
},
|
|
4067
|
+
"settings.appearance": {
|
|
4068
|
+
id: "settings.appearance",
|
|
4069
|
+
order: 280,
|
|
4070
|
+
label: "Appearance",
|
|
4071
|
+
enabled: true,
|
|
4072
|
+
lifecycle: "active",
|
|
4073
|
+
path: "/settings/appearance"
|
|
4074
|
+
},
|
|
4075
|
+
"settings.roles": {
|
|
4076
|
+
id: "settings.roles",
|
|
4077
|
+
order: 290,
|
|
4078
|
+
label: "My Roles",
|
|
4079
|
+
enabled: true,
|
|
4080
|
+
lifecycle: "active",
|
|
4081
|
+
path: "/settings/roles"
|
|
4082
|
+
},
|
|
4083
|
+
"settings.organization": {
|
|
4084
|
+
id: "settings.organization",
|
|
4085
|
+
order: 300,
|
|
4086
|
+
label: "Organization",
|
|
4087
|
+
enabled: true,
|
|
4088
|
+
lifecycle: "active",
|
|
4089
|
+
path: "/settings/organization"
|
|
4090
|
+
},
|
|
4091
|
+
"settings.credentials": {
|
|
4092
|
+
id: "settings.credentials",
|
|
4093
|
+
order: 310,
|
|
4094
|
+
label: "Credentials",
|
|
4095
|
+
enabled: true,
|
|
4096
|
+
lifecycle: "active",
|
|
4097
|
+
path: "/settings/credentials"
|
|
4098
|
+
},
|
|
4099
|
+
"settings.api-keys": {
|
|
4100
|
+
id: "settings.api-keys",
|
|
4101
|
+
order: 320,
|
|
4102
|
+
label: "API Keys",
|
|
4103
|
+
enabled: true,
|
|
4104
|
+
lifecycle: "active",
|
|
4105
|
+
path: "/settings/api-keys"
|
|
4106
|
+
},
|
|
4107
|
+
"settings.webhooks": {
|
|
4108
|
+
id: "settings.webhooks",
|
|
4109
|
+
order: 330,
|
|
4110
|
+
label: "Webhooks",
|
|
4111
|
+
enabled: true,
|
|
4112
|
+
lifecycle: "active",
|
|
4113
|
+
path: "/settings/webhooks"
|
|
4114
|
+
},
|
|
4115
|
+
"settings.deployments": {
|
|
4116
|
+
id: "settings.deployments",
|
|
4117
|
+
order: 340,
|
|
4118
|
+
label: "Deployments",
|
|
4119
|
+
enabled: true,
|
|
4120
|
+
lifecycle: "active",
|
|
4121
|
+
path: "/settings/deployments"
|
|
4122
|
+
},
|
|
4123
|
+
admin: {
|
|
4124
|
+
id: "admin",
|
|
4125
|
+
order: 350,
|
|
4126
|
+
label: "Admin",
|
|
4127
|
+
enabled: true,
|
|
4128
|
+
lifecycle: "active",
|
|
4129
|
+
path: "/admin",
|
|
4130
|
+
icon: "feature.admin",
|
|
4131
|
+
requiresAdmin: true
|
|
4132
|
+
},
|
|
4133
|
+
"admin.system-health": {
|
|
4134
|
+
id: "admin.system-health",
|
|
4135
|
+
order: 360,
|
|
4136
|
+
label: "System Health",
|
|
4137
|
+
enabled: true,
|
|
4138
|
+
lifecycle: "active",
|
|
4139
|
+
path: "/admin/system-health"
|
|
4140
|
+
},
|
|
4141
|
+
"admin.organizations": {
|
|
4142
|
+
id: "admin.organizations",
|
|
4143
|
+
order: 370,
|
|
4144
|
+
label: "Organizations",
|
|
4145
|
+
enabled: true,
|
|
4146
|
+
lifecycle: "active",
|
|
4147
|
+
path: "/admin/organizations"
|
|
4148
|
+
},
|
|
4149
|
+
"admin.users": {
|
|
4150
|
+
id: "admin.users",
|
|
4151
|
+
order: 380,
|
|
4152
|
+
label: "Users",
|
|
4153
|
+
enabled: true,
|
|
4154
|
+
lifecycle: "active",
|
|
4155
|
+
path: "/admin/users"
|
|
4156
|
+
},
|
|
4157
|
+
"admin.design-showcase": {
|
|
4158
|
+
id: "admin.design-showcase",
|
|
4159
|
+
order: 390,
|
|
4160
|
+
label: "Design Showcase",
|
|
4161
|
+
enabled: true,
|
|
4162
|
+
lifecycle: "active",
|
|
4163
|
+
path: "/admin/design-showcase"
|
|
4164
|
+
},
|
|
4165
|
+
"admin.debug": {
|
|
4166
|
+
id: "admin.debug",
|
|
4167
|
+
order: 400,
|
|
4168
|
+
label: "Debug",
|
|
4169
|
+
enabled: true,
|
|
4170
|
+
lifecycle: "active",
|
|
4171
|
+
path: "/admin/debug"
|
|
4172
|
+
},
|
|
4173
|
+
archive: {
|
|
4174
|
+
id: "archive",
|
|
4175
|
+
order: 410,
|
|
4176
|
+
label: "Archive",
|
|
4177
|
+
enabled: true,
|
|
4178
|
+
lifecycle: "active",
|
|
4179
|
+
path: "/archive",
|
|
4180
|
+
icon: "feature.archive",
|
|
4181
|
+
devOnly: true
|
|
4182
|
+
},
|
|
4183
|
+
"archive.agent-chat": {
|
|
4184
|
+
id: "archive.agent-chat",
|
|
4185
|
+
order: 420,
|
|
4186
|
+
label: "Agent Chat",
|
|
4187
|
+
enabled: true,
|
|
4188
|
+
lifecycle: "active",
|
|
4189
|
+
path: "/archive/agent-chat"
|
|
4190
|
+
},
|
|
4191
|
+
"archive.execution-runner": {
|
|
4192
|
+
id: "archive.execution-runner",
|
|
4193
|
+
order: 430,
|
|
4194
|
+
label: "Execution Runner",
|
|
4195
|
+
enabled: true,
|
|
4196
|
+
lifecycle: "active",
|
|
4197
|
+
path: "/archive/execution-runner"
|
|
4198
|
+
},
|
|
4199
|
+
seo: {
|
|
4200
|
+
id: "seo",
|
|
4201
|
+
order: 440,
|
|
4202
|
+
label: "SEO",
|
|
4203
|
+
enabled: false,
|
|
4204
|
+
lifecycle: "deprecated",
|
|
4205
|
+
path: "/seo"
|
|
4206
|
+
},
|
|
4207
|
+
knowledge: {
|
|
4208
|
+
id: "knowledge",
|
|
4209
|
+
order: 450,
|
|
4210
|
+
label: "Knowledge",
|
|
4211
|
+
description: "Operational knowledge, playbooks, and strategy docs",
|
|
4212
|
+
enabled: true,
|
|
4213
|
+
lifecycle: "active",
|
|
4214
|
+
color: "teal",
|
|
4215
|
+
icon: "feature.knowledge"
|
|
4216
|
+
},
|
|
4217
|
+
"knowledge.base": {
|
|
4218
|
+
id: "knowledge.base",
|
|
4219
|
+
order: 460,
|
|
4220
|
+
label: "Knowledge Base",
|
|
4221
|
+
enabled: true,
|
|
4222
|
+
lifecycle: "active",
|
|
4223
|
+
path: "/knowledge"
|
|
4224
|
+
}
|
|
4225
|
+
},
|
|
4226
|
+
resources: DEFAULT_ORGANIZATION_MODEL_RESOURCES,
|
|
4227
|
+
actions: DEFAULT_ORGANIZATION_MODEL_ACTIONS,
|
|
4228
|
+
entities: DEFAULT_ORGANIZATION_MODEL_ENTITIES2,
|
|
4229
|
+
policies: DEFAULT_ORGANIZATION_MODEL_POLICIES,
|
|
4230
|
+
// Phase 4 (D1): statuses top-level field removed; status data lives in system.content.
|
|
4231
|
+
knowledge: DEFAULT_ORGANIZATION_MODEL_KNOWLEDGE
|
|
4232
|
+
};
|
|
4233
|
+
|
|
4234
|
+
// ../core/src/organization-model/resolve.ts
|
|
4235
|
+
function isPlainObject(value) {
|
|
4236
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
4237
|
+
}
|
|
4238
|
+
function deepMerge(base, override) {
|
|
4239
|
+
if (override === void 0) {
|
|
4240
|
+
return base;
|
|
4241
|
+
}
|
|
4242
|
+
if (Array.isArray(base)) {
|
|
4243
|
+
return override ?? base;
|
|
4244
|
+
}
|
|
4245
|
+
if (!isPlainObject(base) || !isPlainObject(override)) {
|
|
4246
|
+
return override ?? base;
|
|
4247
|
+
}
|
|
4248
|
+
const result = { ...base };
|
|
4249
|
+
for (const [key, value] of Object.entries(override)) {
|
|
4250
|
+
if (value === void 0) continue;
|
|
4251
|
+
const existing = result[key];
|
|
4252
|
+
result[key] = isPlainObject(existing) && isPlainObject(value) ? deepMerge(existing, value) : value;
|
|
4253
|
+
}
|
|
4254
|
+
return result;
|
|
4255
|
+
}
|
|
4256
|
+
function resolveOrganizationModel(override, organizationId) {
|
|
4257
|
+
const merged = deepMerge(DEFAULT_ORGANIZATION_MODEL, override);
|
|
4258
|
+
return OrganizationModelSchema.parse(merged);
|
|
4259
|
+
}
|
|
4260
|
+
|
|
4261
|
+
// ../core/src/organization-model/surface-projection.ts
|
|
4262
|
+
function collectSystemsById(model) {
|
|
4263
|
+
const systemsById = /* @__PURE__ */ new Map();
|
|
4264
|
+
for (const { path, system } of listAllSystems(model)) {
|
|
4265
|
+
systemsById.set(path, system);
|
|
4266
|
+
systemsById.set(system.id, system);
|
|
4267
|
+
}
|
|
4268
|
+
return systemsById;
|
|
4269
|
+
}
|
|
4270
|
+
function getSystemWithAncestors(systemsById, systemId) {
|
|
4271
|
+
const systems = [];
|
|
4272
|
+
let current = systemsById.get(systemId);
|
|
4273
|
+
while (current !== void 0) {
|
|
4274
|
+
systems.unshift(current);
|
|
4275
|
+
current = current.parentSystemId ? systemsById.get(current.parentSystemId) : void 0;
|
|
4276
|
+
}
|
|
4277
|
+
return systems;
|
|
4278
|
+
}
|
|
4279
|
+
function hasInheritedFlag(systemsById, systemIds, flag) {
|
|
4280
|
+
return systemIds.some(
|
|
4281
|
+
(systemId) => getSystemWithAncestors(systemsById, systemId).some((system) => system[flag] === true)
|
|
4282
|
+
);
|
|
4283
|
+
}
|
|
4284
|
+
function isLifecycleEnabled2(system) {
|
|
4285
|
+
if (system.enabled === false) return false;
|
|
4286
|
+
return system.lifecycle !== "deprecated" && system.lifecycle !== "archived";
|
|
4287
|
+
}
|
|
4288
|
+
function isLifecycleDevOnly(system) {
|
|
4289
|
+
return system.devOnly === true || system.lifecycle === "beta";
|
|
4290
|
+
}
|
|
4291
|
+
function isSystemEnabled(systemsById, systemId) {
|
|
4292
|
+
const systemLineage = getSystemWithAncestors(systemsById, systemId);
|
|
4293
|
+
return systemLineage.length > 0 && systemLineage.every(isLifecycleEnabled2);
|
|
4294
|
+
}
|
|
4295
|
+
function unique(values) {
|
|
4296
|
+
return [...new Set(values)];
|
|
4297
|
+
}
|
|
4298
|
+
function collectSidebarSurfaces(nodes, schemaPath, surfaces = []) {
|
|
4299
|
+
getSortedSidebarEntries(nodes).forEach(([id, node]) => {
|
|
4300
|
+
const nodePath = [...schemaPath, id];
|
|
4301
|
+
if (node.type === "group") {
|
|
4302
|
+
collectSidebarSurfaces(node.children, [...nodePath, "children"], surfaces);
|
|
4303
|
+
return;
|
|
4304
|
+
}
|
|
4305
|
+
surfaces.push({ id, surface: node, path: nodePath });
|
|
4306
|
+
});
|
|
4307
|
+
return surfaces;
|
|
4308
|
+
}
|
|
4309
|
+
function getSidebarSurfaces(model) {
|
|
4310
|
+
return [
|
|
4311
|
+
...collectSidebarSurfaces(model.navigation.sidebar.primary, ["navigation", "sidebar", "primary"]),
|
|
4312
|
+
...collectSidebarSurfaces(model.navigation.sidebar.bottom, ["navigation", "sidebar", "bottom"])
|
|
4313
|
+
];
|
|
4314
|
+
}
|
|
4315
|
+
function projectOrganizationSurfaces(model) {
|
|
4316
|
+
const systemsById = collectSystemsById(model);
|
|
4317
|
+
return getSidebarSurfaces(model).map(({ id, surface }) => {
|
|
4318
|
+
const targets = surface.targets ?? {};
|
|
4319
|
+
const systemIds = unique((targets.systems ?? []).filter((systemId) => systemsById.has(systemId)));
|
|
4320
|
+
const enabled = systemIds.every((candidate) => isSystemEnabled(systemsById, candidate));
|
|
4321
|
+
const devOnly = surface.devOnly === true || hasInheritedFlag(systemsById, systemIds, "devOnly") || systemIds.some((candidate) => getSystemWithAncestors(systemsById, candidate).some(isLifecycleDevOnly));
|
|
4322
|
+
const requiresAdmin = hasInheritedFlag(systemsById, systemIds, "requiresAdmin");
|
|
4323
|
+
return {
|
|
4324
|
+
id,
|
|
4325
|
+
label: surface.label,
|
|
4326
|
+
path: surface.path,
|
|
4327
|
+
surfaceType: surface.surfaceType,
|
|
4328
|
+
...surface.description !== void 0 ? { description: surface.description } : {},
|
|
4329
|
+
...surface.icon !== void 0 ? { icon: surface.icon } : {},
|
|
4330
|
+
...surface.order !== void 0 ? { order: surface.order } : {},
|
|
4331
|
+
systemIds,
|
|
4332
|
+
entityIds: [...targets.entities ?? []],
|
|
4333
|
+
resourceIds: [...targets.resources ?? []],
|
|
4334
|
+
actionIds: [...targets.actions ?? []],
|
|
4335
|
+
enabled,
|
|
4336
|
+
...devOnly ? { devOnly } : {},
|
|
4337
|
+
...surface.requiresAdmin === true || requiresAdmin ? { requiresAdmin: true } : {}
|
|
4338
|
+
};
|
|
4339
|
+
});
|
|
4340
|
+
}
|
|
4341
|
+
|
|
4342
|
+
export { ActionSchema, AgentResourceEntrySchema, CRM_DISCOVERY_BOOKING_CANCELLED_STATE, CRM_DISCOVERY_LINK_SENT_STATE, CRM_DISCOVERY_NUDGING_STATE, CRM_DISCOVERY_REPLIED_STATE, CRM_PIPELINE_DEFINITION, CRM_PRIORITY_BUCKETS, DEFAULT_CRM_PRIORITY_RULE_CONFIG, EntitySchema, IdentityDomainSchema, IntegrationResourceEntrySchema, LEAD_GEN_PIPELINE_DEFINITIONS, LEAD_GEN_STAGE_CATALOG, PROJECTS_VIEW_ACTION_ID, PROSPECTING_STEPS, PolicySchema, RoleSchema, SalesStageSchema, ScriptResourceEntrySchema, SurfaceDefinitionSchema, SystemEntrySchema, WorkflowResourceEntrySchema, ancestorsOf, buildOrganizationGraph, childrenOf, defaultPathFor, devOnlyFor, findById, findByPath, findPipeline, getContent, getResourcesForSystem, getSortedSidebarEntries, getSystem, getSystemAncestors, listAllSystems, lookupContentType, parentOf, projectOrganizationSurfaces, requiresAdminFor, resolveOrganizationModel, topLevel };
|