@elevasis/core 0.1.0 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +195 -3
- package/dist/organization-model/index.js +195 -3
- package/package.json +1 -1
- package/src/README.md +24 -17
- package/src/__tests__/template-foundations-compatibility.test.ts +95 -14
- package/src/auth/multi-tenancy/types.ts +2 -1
- package/src/execution/engine/__tests__/fixtures/test-agents.ts +4 -4
- package/src/execution/engine/index.ts +5 -19
- package/src/execution/engine/tools/platform/index.ts +9 -33
- package/src/execution/engine/tools/registry.ts +109 -2
- package/src/execution/engine/tools/tool-maps.ts +88 -0
- package/src/organization-model/README.md +19 -4
- package/src/organization-model/__tests__/graph.test.ts +612 -0
- package/src/organization-model/__tests__/resolve.test.ts +208 -0
- package/src/organization-model/defaults.ts +1 -1
- package/src/organization-model/organization-graph.mdx +262 -0
- package/src/organization-model/organization-model.mdx +257 -0
- package/src/organization-model/resolve.ts +26 -2
- package/src/organization-model/schema.ts +203 -1
- package/src/platform/constants/versions.ts +1 -1
- package/src/platform/registry/__tests__/resource-registry.integration.test.ts +24 -0
- package/src/platform/registry/__tests__/resource-registry.test.ts +63 -0
- package/src/platform/registry/resource-registry.ts +98 -10
- package/src/projects/api-schemas.ts +2 -1
- package/src/reference/_generated/contracts.md +1044 -0
- package/src/reference/glossary.md +88 -0
- package/src/server.ts +2 -3
- package/src/execution/engine/tools/platform/resource-invocation/__tests__/edge-cases.test.ts +0 -507
- package/src/execution/engine/tools/platform/resource-invocation/__tests__/resource-invocation-service.test.ts +0 -500
- package/src/execution/engine/tools/platform/resource-invocation/__tests__/tool.test.ts +0 -555
- package/src/execution/engine/tools/platform/resource-invocation/dynamic-tool.ts +0 -94
- package/src/execution/engine/tools/platform/resource-invocation/index.ts +0 -14
- package/src/execution/engine/tools/platform/resource-invocation/resource-invocation-service.ts +0 -147
- package/src/execution/engine/tools/platform/resource-invocation/tool.ts +0 -115
- package/src/execution/engine/tools/platform/resource-invocation/types.ts +0 -31
package/dist/index.js
CHANGED
|
@@ -304,7 +304,7 @@ var DEFAULT_ORGANIZATION_MODEL_NAVIGATION = {
|
|
|
304
304
|
};
|
|
305
305
|
|
|
306
306
|
// src/organization-model/schema.ts
|
|
307
|
-
var
|
|
307
|
+
var OrganizationModelSchemaBase = z.object({
|
|
308
308
|
version: z.literal(1).default(1),
|
|
309
309
|
domains: z.array(SemanticDomainSchema).default([]),
|
|
310
310
|
branding: OrganizationModelBrandingSchema,
|
|
@@ -315,6 +315,181 @@ var OrganizationModelSchema = z.object({
|
|
|
315
315
|
delivery: OrganizationModelDeliverySchema,
|
|
316
316
|
resourceMappings: z.array(ResourceMappingSchema).default([])
|
|
317
317
|
});
|
|
318
|
+
function addIssue(ctx, path, message) {
|
|
319
|
+
ctx.addIssue({
|
|
320
|
+
code: z.ZodIssueCode.custom,
|
|
321
|
+
path,
|
|
322
|
+
message
|
|
323
|
+
});
|
|
324
|
+
}
|
|
325
|
+
function collectIds(items, ctx, collectionPath, label) {
|
|
326
|
+
const itemsById = /* @__PURE__ */ new Map();
|
|
327
|
+
items.forEach((item, index) => {
|
|
328
|
+
if (itemsById.has(item.id)) {
|
|
329
|
+
addIssue(ctx, [...collectionPath, index, "id"], `${label} id "${item.id}" must be unique`);
|
|
330
|
+
return;
|
|
331
|
+
}
|
|
332
|
+
itemsById.set(item.id, item);
|
|
333
|
+
});
|
|
334
|
+
return itemsById;
|
|
335
|
+
}
|
|
336
|
+
var OrganizationModelSchema = OrganizationModelSchemaBase.superRefine((model, ctx) => {
|
|
337
|
+
const domainsById = collectIds(model.domains, ctx, ["domains"], "Domain");
|
|
338
|
+
const surfacesById = collectIds(model.navigation.surfaces, ctx, ["navigation", "surfaces"], "Surface");
|
|
339
|
+
collectIds(model.navigation.groups, ctx, ["navigation", "groups"], "Navigation group");
|
|
340
|
+
collectIds(model.resourceMappings, ctx, ["resourceMappings"], "Resource mapping");
|
|
341
|
+
const resourceMappingsByResourceId = /* @__PURE__ */ new Map();
|
|
342
|
+
model.resourceMappings.forEach((resourceMapping, index) => {
|
|
343
|
+
if (resourceMappingsByResourceId.has(resourceMapping.resourceId)) {
|
|
344
|
+
addIssue(
|
|
345
|
+
ctx,
|
|
346
|
+
["resourceMappings", index, "resourceId"],
|
|
347
|
+
`Resource mapping resourceId "${resourceMapping.resourceId}" must be unique`
|
|
348
|
+
);
|
|
349
|
+
return;
|
|
350
|
+
}
|
|
351
|
+
resourceMappingsByResourceId.set(resourceMapping.resourceId, resourceMapping);
|
|
352
|
+
});
|
|
353
|
+
if (model.navigation.defaultSurfaceId && !surfacesById.has(model.navigation.defaultSurfaceId)) {
|
|
354
|
+
addIssue(
|
|
355
|
+
ctx,
|
|
356
|
+
["navigation", "defaultSurfaceId"],
|
|
357
|
+
`Default surface "${model.navigation.defaultSurfaceId}" must reference a declared navigation surface`
|
|
358
|
+
);
|
|
359
|
+
}
|
|
360
|
+
model.navigation.groups.forEach((group, groupIndex) => {
|
|
361
|
+
group.surfaceIds.forEach((surfaceId, surfaceIndex) => {
|
|
362
|
+
if (!surfacesById.has(surfaceId)) {
|
|
363
|
+
addIssue(
|
|
364
|
+
ctx,
|
|
365
|
+
["navigation", "groups", groupIndex, "surfaceIds", surfaceIndex],
|
|
366
|
+
`Navigation group "${group.id}" references unknown surface "${surfaceId}"`
|
|
367
|
+
);
|
|
368
|
+
}
|
|
369
|
+
});
|
|
370
|
+
});
|
|
371
|
+
model.domains.forEach((domain, domainIndex) => {
|
|
372
|
+
domain.surfaceIds.forEach((surfaceId, surfaceIndex) => {
|
|
373
|
+
const surface = surfacesById.get(surfaceId);
|
|
374
|
+
if (!surface) {
|
|
375
|
+
addIssue(
|
|
376
|
+
ctx,
|
|
377
|
+
["domains", domainIndex, "surfaceIds", surfaceIndex],
|
|
378
|
+
`Domain "${domain.id}" references unknown surface "${surfaceId}"`
|
|
379
|
+
);
|
|
380
|
+
return;
|
|
381
|
+
}
|
|
382
|
+
if (!surface.domainIds.includes(domain.id)) {
|
|
383
|
+
addIssue(
|
|
384
|
+
ctx,
|
|
385
|
+
["domains", domainIndex, "surfaceIds", surfaceIndex],
|
|
386
|
+
`Domain "${domain.id}" references surface "${surfaceId}" but that surface does not include domain "${domain.id}"`
|
|
387
|
+
);
|
|
388
|
+
}
|
|
389
|
+
});
|
|
390
|
+
domain.resourceIds.forEach((resourceId, resourceIndex) => {
|
|
391
|
+
const resourceMapping = resourceMappingsByResourceId.get(resourceId);
|
|
392
|
+
if (!resourceMapping) {
|
|
393
|
+
addIssue(
|
|
394
|
+
ctx,
|
|
395
|
+
["domains", domainIndex, "resourceIds", resourceIndex],
|
|
396
|
+
`Domain "${domain.id}" references unknown resource "${resourceId}"`
|
|
397
|
+
);
|
|
398
|
+
return;
|
|
399
|
+
}
|
|
400
|
+
if (!resourceMapping.domainIds.includes(domain.id)) {
|
|
401
|
+
addIssue(
|
|
402
|
+
ctx,
|
|
403
|
+
["domains", domainIndex, "resourceIds", resourceIndex],
|
|
404
|
+
`Domain "${domain.id}" references resource "${resourceId}" but that resource mapping does not include domain "${domain.id}"`
|
|
405
|
+
);
|
|
406
|
+
}
|
|
407
|
+
});
|
|
408
|
+
});
|
|
409
|
+
model.navigation.surfaces.forEach((surface, surfaceIndex) => {
|
|
410
|
+
if (surface.parentId && !surfacesById.has(surface.parentId)) {
|
|
411
|
+
addIssue(
|
|
412
|
+
ctx,
|
|
413
|
+
["navigation", "surfaces", surfaceIndex, "parentId"],
|
|
414
|
+
`Surface "${surface.id}" references unknown parent surface "${surface.parentId}"`
|
|
415
|
+
);
|
|
416
|
+
}
|
|
417
|
+
surface.domainIds.forEach((domainId, domainIndex) => {
|
|
418
|
+
const domain = domainsById.get(domainId);
|
|
419
|
+
if (!domain) {
|
|
420
|
+
addIssue(
|
|
421
|
+
ctx,
|
|
422
|
+
["navigation", "surfaces", surfaceIndex, "domainIds", domainIndex],
|
|
423
|
+
`Surface "${surface.id}" references unknown domain "${domainId}"`
|
|
424
|
+
);
|
|
425
|
+
return;
|
|
426
|
+
}
|
|
427
|
+
if (!domain.surfaceIds.includes(surface.id)) {
|
|
428
|
+
addIssue(
|
|
429
|
+
ctx,
|
|
430
|
+
["navigation", "surfaces", surfaceIndex, "domainIds", domainIndex],
|
|
431
|
+
`Surface "${surface.id}" references domain "${domainId}" but that domain does not include surface "${surface.id}"`
|
|
432
|
+
);
|
|
433
|
+
}
|
|
434
|
+
});
|
|
435
|
+
surface.resourceIds.forEach((resourceId, resourceIndex) => {
|
|
436
|
+
const resourceMapping = resourceMappingsByResourceId.get(resourceId);
|
|
437
|
+
if (!resourceMapping) {
|
|
438
|
+
addIssue(
|
|
439
|
+
ctx,
|
|
440
|
+
["navigation", "surfaces", surfaceIndex, "resourceIds", resourceIndex],
|
|
441
|
+
`Surface "${surface.id}" references unknown resource "${resourceId}"`
|
|
442
|
+
);
|
|
443
|
+
return;
|
|
444
|
+
}
|
|
445
|
+
if (!resourceMapping.surfaceIds.includes(surface.id)) {
|
|
446
|
+
addIssue(
|
|
447
|
+
ctx,
|
|
448
|
+
["navigation", "surfaces", surfaceIndex, "resourceIds", resourceIndex],
|
|
449
|
+
`Surface "${surface.id}" references resource "${resourceId}" but that resource mapping does not include surface "${surface.id}"`
|
|
450
|
+
);
|
|
451
|
+
}
|
|
452
|
+
});
|
|
453
|
+
});
|
|
454
|
+
model.resourceMappings.forEach((resourceMapping, resourceIndex) => {
|
|
455
|
+
resourceMapping.domainIds.forEach((domainId, domainIndex) => {
|
|
456
|
+
const domain = domainsById.get(domainId);
|
|
457
|
+
if (!domain) {
|
|
458
|
+
addIssue(
|
|
459
|
+
ctx,
|
|
460
|
+
["resourceMappings", resourceIndex, "domainIds", domainIndex],
|
|
461
|
+
`Resource mapping "${resourceMapping.id}" references unknown domain "${domainId}"`
|
|
462
|
+
);
|
|
463
|
+
return;
|
|
464
|
+
}
|
|
465
|
+
if (!domain.resourceIds.includes(resourceMapping.resourceId)) {
|
|
466
|
+
addIssue(
|
|
467
|
+
ctx,
|
|
468
|
+
["resourceMappings", resourceIndex, "domainIds", domainIndex],
|
|
469
|
+
`Resource mapping "${resourceMapping.id}" references domain "${domainId}" but that domain does not include resource "${resourceMapping.resourceId}"`
|
|
470
|
+
);
|
|
471
|
+
}
|
|
472
|
+
});
|
|
473
|
+
resourceMapping.surfaceIds.forEach((surfaceId, surfaceIndex) => {
|
|
474
|
+
const surface = surfacesById.get(surfaceId);
|
|
475
|
+
if (!surface) {
|
|
476
|
+
addIssue(
|
|
477
|
+
ctx,
|
|
478
|
+
["resourceMappings", resourceIndex, "surfaceIds", surfaceIndex],
|
|
479
|
+
`Resource mapping "${resourceMapping.id}" references unknown surface "${surfaceId}"`
|
|
480
|
+
);
|
|
481
|
+
return;
|
|
482
|
+
}
|
|
483
|
+
if (!surface.resourceIds.includes(resourceMapping.resourceId)) {
|
|
484
|
+
addIssue(
|
|
485
|
+
ctx,
|
|
486
|
+
["resourceMappings", resourceIndex, "surfaceIds", surfaceIndex],
|
|
487
|
+
`Resource mapping "${resourceMapping.id}" references surface "${surfaceId}" but that surface does not include resource "${resourceMapping.resourceId}"`
|
|
488
|
+
);
|
|
489
|
+
}
|
|
490
|
+
});
|
|
491
|
+
});
|
|
492
|
+
});
|
|
318
493
|
|
|
319
494
|
// src/organization-model/defaults.ts
|
|
320
495
|
var DEFAULT_ORGANIZATION_MODEL = {
|
|
@@ -342,7 +517,7 @@ var DEFAULT_ORGANIZATION_MODEL = {
|
|
|
342
517
|
},
|
|
343
518
|
{
|
|
344
519
|
id: "delivery",
|
|
345
|
-
label: "
|
|
520
|
+
label: "Projects",
|
|
346
521
|
description: "Projects, milestones, and client work execution",
|
|
347
522
|
color: "orange",
|
|
348
523
|
entityIds: ["delivery.project", "delivery.milestone", "delivery.task"],
|
|
@@ -392,11 +567,28 @@ function deepMerge(base, override) {
|
|
|
392
567
|
}
|
|
393
568
|
return result;
|
|
394
569
|
}
|
|
570
|
+
function normalizeInheritedNavigationGroups(model, override) {
|
|
571
|
+
if (override?.navigation?.surfaces === void 0 || override.navigation.groups !== void 0) {
|
|
572
|
+
return model;
|
|
573
|
+
}
|
|
574
|
+
const validSurfaceIds = new Set(model.navigation.surfaces.map((surface) => surface.id));
|
|
575
|
+
const groups = model.navigation.groups.map((group) => ({
|
|
576
|
+
...group,
|
|
577
|
+
surfaceIds: group.surfaceIds.filter((surfaceId) => validSurfaceIds.has(surfaceId))
|
|
578
|
+
})).filter((group) => group.surfaceIds.length > 0);
|
|
579
|
+
return {
|
|
580
|
+
...model,
|
|
581
|
+
navigation: {
|
|
582
|
+
...model.navigation,
|
|
583
|
+
groups
|
|
584
|
+
}
|
|
585
|
+
};
|
|
586
|
+
}
|
|
395
587
|
function defineOrganizationModel(model) {
|
|
396
588
|
return model;
|
|
397
589
|
}
|
|
398
590
|
function resolveOrganizationModel(override) {
|
|
399
|
-
const merged = deepMerge(DEFAULT_ORGANIZATION_MODEL, override);
|
|
591
|
+
const merged = normalizeInheritedNavigationGroups(deepMerge(DEFAULT_ORGANIZATION_MODEL, override), override);
|
|
400
592
|
return OrganizationModelSchema.parse(merged);
|
|
401
593
|
}
|
|
402
594
|
|
|
@@ -304,7 +304,7 @@ var DEFAULT_ORGANIZATION_MODEL_NAVIGATION = {
|
|
|
304
304
|
};
|
|
305
305
|
|
|
306
306
|
// src/organization-model/schema.ts
|
|
307
|
-
var
|
|
307
|
+
var OrganizationModelSchemaBase = z.object({
|
|
308
308
|
version: z.literal(1).default(1),
|
|
309
309
|
domains: z.array(SemanticDomainSchema).default([]),
|
|
310
310
|
branding: OrganizationModelBrandingSchema,
|
|
@@ -315,6 +315,181 @@ var OrganizationModelSchema = z.object({
|
|
|
315
315
|
delivery: OrganizationModelDeliverySchema,
|
|
316
316
|
resourceMappings: z.array(ResourceMappingSchema).default([])
|
|
317
317
|
});
|
|
318
|
+
function addIssue(ctx, path, message) {
|
|
319
|
+
ctx.addIssue({
|
|
320
|
+
code: z.ZodIssueCode.custom,
|
|
321
|
+
path,
|
|
322
|
+
message
|
|
323
|
+
});
|
|
324
|
+
}
|
|
325
|
+
function collectIds(items, ctx, collectionPath, label) {
|
|
326
|
+
const itemsById = /* @__PURE__ */ new Map();
|
|
327
|
+
items.forEach((item, index) => {
|
|
328
|
+
if (itemsById.has(item.id)) {
|
|
329
|
+
addIssue(ctx, [...collectionPath, index, "id"], `${label} id "${item.id}" must be unique`);
|
|
330
|
+
return;
|
|
331
|
+
}
|
|
332
|
+
itemsById.set(item.id, item);
|
|
333
|
+
});
|
|
334
|
+
return itemsById;
|
|
335
|
+
}
|
|
336
|
+
var OrganizationModelSchema = OrganizationModelSchemaBase.superRefine((model, ctx) => {
|
|
337
|
+
const domainsById = collectIds(model.domains, ctx, ["domains"], "Domain");
|
|
338
|
+
const surfacesById = collectIds(model.navigation.surfaces, ctx, ["navigation", "surfaces"], "Surface");
|
|
339
|
+
collectIds(model.navigation.groups, ctx, ["navigation", "groups"], "Navigation group");
|
|
340
|
+
collectIds(model.resourceMappings, ctx, ["resourceMappings"], "Resource mapping");
|
|
341
|
+
const resourceMappingsByResourceId = /* @__PURE__ */ new Map();
|
|
342
|
+
model.resourceMappings.forEach((resourceMapping, index) => {
|
|
343
|
+
if (resourceMappingsByResourceId.has(resourceMapping.resourceId)) {
|
|
344
|
+
addIssue(
|
|
345
|
+
ctx,
|
|
346
|
+
["resourceMappings", index, "resourceId"],
|
|
347
|
+
`Resource mapping resourceId "${resourceMapping.resourceId}" must be unique`
|
|
348
|
+
);
|
|
349
|
+
return;
|
|
350
|
+
}
|
|
351
|
+
resourceMappingsByResourceId.set(resourceMapping.resourceId, resourceMapping);
|
|
352
|
+
});
|
|
353
|
+
if (model.navigation.defaultSurfaceId && !surfacesById.has(model.navigation.defaultSurfaceId)) {
|
|
354
|
+
addIssue(
|
|
355
|
+
ctx,
|
|
356
|
+
["navigation", "defaultSurfaceId"],
|
|
357
|
+
`Default surface "${model.navigation.defaultSurfaceId}" must reference a declared navigation surface`
|
|
358
|
+
);
|
|
359
|
+
}
|
|
360
|
+
model.navigation.groups.forEach((group, groupIndex) => {
|
|
361
|
+
group.surfaceIds.forEach((surfaceId, surfaceIndex) => {
|
|
362
|
+
if (!surfacesById.has(surfaceId)) {
|
|
363
|
+
addIssue(
|
|
364
|
+
ctx,
|
|
365
|
+
["navigation", "groups", groupIndex, "surfaceIds", surfaceIndex],
|
|
366
|
+
`Navigation group "${group.id}" references unknown surface "${surfaceId}"`
|
|
367
|
+
);
|
|
368
|
+
}
|
|
369
|
+
});
|
|
370
|
+
});
|
|
371
|
+
model.domains.forEach((domain, domainIndex) => {
|
|
372
|
+
domain.surfaceIds.forEach((surfaceId, surfaceIndex) => {
|
|
373
|
+
const surface = surfacesById.get(surfaceId);
|
|
374
|
+
if (!surface) {
|
|
375
|
+
addIssue(
|
|
376
|
+
ctx,
|
|
377
|
+
["domains", domainIndex, "surfaceIds", surfaceIndex],
|
|
378
|
+
`Domain "${domain.id}" references unknown surface "${surfaceId}"`
|
|
379
|
+
);
|
|
380
|
+
return;
|
|
381
|
+
}
|
|
382
|
+
if (!surface.domainIds.includes(domain.id)) {
|
|
383
|
+
addIssue(
|
|
384
|
+
ctx,
|
|
385
|
+
["domains", domainIndex, "surfaceIds", surfaceIndex],
|
|
386
|
+
`Domain "${domain.id}" references surface "${surfaceId}" but that surface does not include domain "${domain.id}"`
|
|
387
|
+
);
|
|
388
|
+
}
|
|
389
|
+
});
|
|
390
|
+
domain.resourceIds.forEach((resourceId, resourceIndex) => {
|
|
391
|
+
const resourceMapping = resourceMappingsByResourceId.get(resourceId);
|
|
392
|
+
if (!resourceMapping) {
|
|
393
|
+
addIssue(
|
|
394
|
+
ctx,
|
|
395
|
+
["domains", domainIndex, "resourceIds", resourceIndex],
|
|
396
|
+
`Domain "${domain.id}" references unknown resource "${resourceId}"`
|
|
397
|
+
);
|
|
398
|
+
return;
|
|
399
|
+
}
|
|
400
|
+
if (!resourceMapping.domainIds.includes(domain.id)) {
|
|
401
|
+
addIssue(
|
|
402
|
+
ctx,
|
|
403
|
+
["domains", domainIndex, "resourceIds", resourceIndex],
|
|
404
|
+
`Domain "${domain.id}" references resource "${resourceId}" but that resource mapping does not include domain "${domain.id}"`
|
|
405
|
+
);
|
|
406
|
+
}
|
|
407
|
+
});
|
|
408
|
+
});
|
|
409
|
+
model.navigation.surfaces.forEach((surface, surfaceIndex) => {
|
|
410
|
+
if (surface.parentId && !surfacesById.has(surface.parentId)) {
|
|
411
|
+
addIssue(
|
|
412
|
+
ctx,
|
|
413
|
+
["navigation", "surfaces", surfaceIndex, "parentId"],
|
|
414
|
+
`Surface "${surface.id}" references unknown parent surface "${surface.parentId}"`
|
|
415
|
+
);
|
|
416
|
+
}
|
|
417
|
+
surface.domainIds.forEach((domainId, domainIndex) => {
|
|
418
|
+
const domain = domainsById.get(domainId);
|
|
419
|
+
if (!domain) {
|
|
420
|
+
addIssue(
|
|
421
|
+
ctx,
|
|
422
|
+
["navigation", "surfaces", surfaceIndex, "domainIds", domainIndex],
|
|
423
|
+
`Surface "${surface.id}" references unknown domain "${domainId}"`
|
|
424
|
+
);
|
|
425
|
+
return;
|
|
426
|
+
}
|
|
427
|
+
if (!domain.surfaceIds.includes(surface.id)) {
|
|
428
|
+
addIssue(
|
|
429
|
+
ctx,
|
|
430
|
+
["navigation", "surfaces", surfaceIndex, "domainIds", domainIndex],
|
|
431
|
+
`Surface "${surface.id}" references domain "${domainId}" but that domain does not include surface "${surface.id}"`
|
|
432
|
+
);
|
|
433
|
+
}
|
|
434
|
+
});
|
|
435
|
+
surface.resourceIds.forEach((resourceId, resourceIndex) => {
|
|
436
|
+
const resourceMapping = resourceMappingsByResourceId.get(resourceId);
|
|
437
|
+
if (!resourceMapping) {
|
|
438
|
+
addIssue(
|
|
439
|
+
ctx,
|
|
440
|
+
["navigation", "surfaces", surfaceIndex, "resourceIds", resourceIndex],
|
|
441
|
+
`Surface "${surface.id}" references unknown resource "${resourceId}"`
|
|
442
|
+
);
|
|
443
|
+
return;
|
|
444
|
+
}
|
|
445
|
+
if (!resourceMapping.surfaceIds.includes(surface.id)) {
|
|
446
|
+
addIssue(
|
|
447
|
+
ctx,
|
|
448
|
+
["navigation", "surfaces", surfaceIndex, "resourceIds", resourceIndex],
|
|
449
|
+
`Surface "${surface.id}" references resource "${resourceId}" but that resource mapping does not include surface "${surface.id}"`
|
|
450
|
+
);
|
|
451
|
+
}
|
|
452
|
+
});
|
|
453
|
+
});
|
|
454
|
+
model.resourceMappings.forEach((resourceMapping, resourceIndex) => {
|
|
455
|
+
resourceMapping.domainIds.forEach((domainId, domainIndex) => {
|
|
456
|
+
const domain = domainsById.get(domainId);
|
|
457
|
+
if (!domain) {
|
|
458
|
+
addIssue(
|
|
459
|
+
ctx,
|
|
460
|
+
["resourceMappings", resourceIndex, "domainIds", domainIndex],
|
|
461
|
+
`Resource mapping "${resourceMapping.id}" references unknown domain "${domainId}"`
|
|
462
|
+
);
|
|
463
|
+
return;
|
|
464
|
+
}
|
|
465
|
+
if (!domain.resourceIds.includes(resourceMapping.resourceId)) {
|
|
466
|
+
addIssue(
|
|
467
|
+
ctx,
|
|
468
|
+
["resourceMappings", resourceIndex, "domainIds", domainIndex],
|
|
469
|
+
`Resource mapping "${resourceMapping.id}" references domain "${domainId}" but that domain does not include resource "${resourceMapping.resourceId}"`
|
|
470
|
+
);
|
|
471
|
+
}
|
|
472
|
+
});
|
|
473
|
+
resourceMapping.surfaceIds.forEach((surfaceId, surfaceIndex) => {
|
|
474
|
+
const surface = surfacesById.get(surfaceId);
|
|
475
|
+
if (!surface) {
|
|
476
|
+
addIssue(
|
|
477
|
+
ctx,
|
|
478
|
+
["resourceMappings", resourceIndex, "surfaceIds", surfaceIndex],
|
|
479
|
+
`Resource mapping "${resourceMapping.id}" references unknown surface "${surfaceId}"`
|
|
480
|
+
);
|
|
481
|
+
return;
|
|
482
|
+
}
|
|
483
|
+
if (!surface.resourceIds.includes(resourceMapping.resourceId)) {
|
|
484
|
+
addIssue(
|
|
485
|
+
ctx,
|
|
486
|
+
["resourceMappings", resourceIndex, "surfaceIds", surfaceIndex],
|
|
487
|
+
`Resource mapping "${resourceMapping.id}" references surface "${surfaceId}" but that surface does not include resource "${resourceMapping.resourceId}"`
|
|
488
|
+
);
|
|
489
|
+
}
|
|
490
|
+
});
|
|
491
|
+
});
|
|
492
|
+
});
|
|
318
493
|
|
|
319
494
|
// src/organization-model/defaults.ts
|
|
320
495
|
var DEFAULT_ORGANIZATION_MODEL = {
|
|
@@ -342,7 +517,7 @@ var DEFAULT_ORGANIZATION_MODEL = {
|
|
|
342
517
|
},
|
|
343
518
|
{
|
|
344
519
|
id: "delivery",
|
|
345
|
-
label: "
|
|
520
|
+
label: "Projects",
|
|
346
521
|
description: "Projects, milestones, and client work execution",
|
|
347
522
|
color: "orange",
|
|
348
523
|
entityIds: ["delivery.project", "delivery.milestone", "delivery.task"],
|
|
@@ -392,11 +567,28 @@ function deepMerge(base, override) {
|
|
|
392
567
|
}
|
|
393
568
|
return result;
|
|
394
569
|
}
|
|
570
|
+
function normalizeInheritedNavigationGroups(model, override) {
|
|
571
|
+
if (override?.navigation?.surfaces === void 0 || override.navigation.groups !== void 0) {
|
|
572
|
+
return model;
|
|
573
|
+
}
|
|
574
|
+
const validSurfaceIds = new Set(model.navigation.surfaces.map((surface) => surface.id));
|
|
575
|
+
const groups = model.navigation.groups.map((group) => ({
|
|
576
|
+
...group,
|
|
577
|
+
surfaceIds: group.surfaceIds.filter((surfaceId) => validSurfaceIds.has(surfaceId))
|
|
578
|
+
})).filter((group) => group.surfaceIds.length > 0);
|
|
579
|
+
return {
|
|
580
|
+
...model,
|
|
581
|
+
navigation: {
|
|
582
|
+
...model.navigation,
|
|
583
|
+
groups
|
|
584
|
+
}
|
|
585
|
+
};
|
|
586
|
+
}
|
|
395
587
|
function defineOrganizationModel(model) {
|
|
396
588
|
return model;
|
|
397
589
|
}
|
|
398
590
|
function resolveOrganizationModel(override) {
|
|
399
|
-
const merged = deepMerge(DEFAULT_ORGANIZATION_MODEL, override);
|
|
591
|
+
const merged = normalizeInheritedNavigationGroups(deepMerge(DEFAULT_ORGANIZATION_MODEL, override), override);
|
|
400
592
|
return OrganizationModelSchema.parse(merged);
|
|
401
593
|
}
|
|
402
594
|
|
package/package.json
CHANGED
package/src/README.md
CHANGED
|
@@ -6,26 +6,33 @@ This package is the source of truth for shared types, schemas, and contract help
|
|
|
6
6
|
|
|
7
7
|
## Import Rules
|
|
8
8
|
|
|
9
|
-
- Use `@elevasis/core` for browser-safe shared types and schemas.
|
|
10
|
-
- Use `@elevasis/core/
|
|
11
|
-
-
|
|
12
|
-
-
|
|
9
|
+
- Use `@elevasis/core` (root export) for browser-safe shared types and schemas.
|
|
10
|
+
- Use `@elevasis/core/organization-model` for the semantic contract layer.
|
|
11
|
+
- These are the only two subpaths available to external consumers of the published npm package.
|
|
12
|
+
- Paths like `@elevasis/core/server`, `@elevasis/core/test-utils`, `@elevasis/core/platform`, etc. are internal monorepo paths (`@repo/core/...`) and are NOT available to external consumers.
|
|
13
13
|
|
|
14
14
|
## Published Surface Groups
|
|
15
15
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
- `
|
|
19
|
-
- `
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
- `
|
|
24
|
-
- `
|
|
25
|
-
- `
|
|
26
|
-
- `
|
|
27
|
-
- `
|
|
28
|
-
- `
|
|
16
|
+
The published `@elevasis/core` npm package exposes exactly two subpaths:
|
|
17
|
+
|
|
18
|
+
- `.` (`@elevasis/core`) - browser-safe shared types, schemas, and constants.
|
|
19
|
+
- `./organization-model` (`@elevasis/core/organization-model`) - the semantic contract layer for CRM, lead gen, delivery, features, branding, and navigation.
|
|
20
|
+
|
|
21
|
+
Within the monorepo, the internal `@repo/core` package exposes additional subpaths for use by `apps/` and other packages:
|
|
22
|
+
|
|
23
|
+
- `@repo/core/server` - Node.js-only helpers and services.
|
|
24
|
+
- `@repo/core/platform` - shared constants, utilities, registry, SSE, and API types.
|
|
25
|
+
- `@repo/core/auth` - multi-tenancy types for organizations, users, memberships, invitations, and credentials.
|
|
26
|
+
- `@repo/core/execution` - workflow, agent, scheduler, calibration, and execution-interface contracts.
|
|
27
|
+
- `@repo/core/commands` - command queue types and schemas.
|
|
28
|
+
- `@repo/core/operations` - sessions, notifications, observability, activities, triggers, and debug logs.
|
|
29
|
+
- `@repo/core/supabase` - generated database types and helpers.
|
|
30
|
+
- `@repo/core/integrations/...` - OAuth and credential contracts.
|
|
31
|
+
- `@repo/core/projects/api-schemas` - project management request and response schemas.
|
|
32
|
+
- `@repo/core/content` - published content metadata types.
|
|
33
|
+
- `@repo/core/test-utils` - test fixtures and mocks (internal use only).
|
|
34
|
+
|
|
35
|
+
These `@repo/core/*` subpaths are NOT available in the published `@elevasis/core` package.
|
|
29
36
|
|
|
30
37
|
## When To Read Deeper
|
|
31
38
|
|
|
@@ -5,22 +5,13 @@ import {
|
|
|
5
5
|
organizationModel as foundationOrganizationModel,
|
|
6
6
|
quickAccessSurfaceIds
|
|
7
7
|
} from '../../../../external/_template/foundations/config/organization-model'
|
|
8
|
-
import { resolveOrganizationModel } from '../published'
|
|
9
8
|
|
|
10
9
|
describe('template foundations compatibility', () => {
|
|
11
|
-
it('
|
|
12
|
-
const resolved = resolveOrganizationModel(foundationOrganizationModel)
|
|
13
|
-
|
|
10
|
+
it('preserves the adapter-level shell helpers on top of the canonical model', () => {
|
|
14
11
|
expect(foundationOrganizationModel.navigation.homeLabel).toBe(homeLabel)
|
|
15
12
|
expect(foundationOrganizationModel.navigation.quickAccessSurfaceIds).toEqual(quickAccessSurfaceIds)
|
|
16
|
-
expect(
|
|
17
|
-
expect(
|
|
18
|
-
expect(resolved.navigation.defaultSurfaceId).toBe('operations')
|
|
19
|
-
expect(resolved.navigation.surfaces.map((surface) => surface.id)).toEqual(
|
|
20
|
-
foundationOrganizationModel.navigation.surfaces.map((surface) => surface.id)
|
|
21
|
-
)
|
|
22
|
-
expect(resolved.features.enabled.acquisition).toBe(true)
|
|
23
|
-
expect(resolved.features.enabled.calibration).toBe(false)
|
|
13
|
+
expect(foundationOrganizationModel.version).toBe(1)
|
|
14
|
+
expect(foundationOrganizationModel.navigation.defaultSurfaceId).toBe('operations')
|
|
24
15
|
expect(getOrganizationSurface('operations')).toMatchObject({
|
|
25
16
|
id: 'operations',
|
|
26
17
|
label: 'Operations',
|
|
@@ -28,7 +19,97 @@ describe('template foundations compatibility', () => {
|
|
|
28
19
|
surfaceType: 'graph',
|
|
29
20
|
featureKey: 'operations'
|
|
30
21
|
})
|
|
31
|
-
|
|
32
|
-
expect(
|
|
22
|
+
|
|
23
|
+
expect(getOrganizationSurface('operations.organization-graph')).toMatchObject({
|
|
24
|
+
id: 'operations.organization-graph',
|
|
25
|
+
label: 'Operations',
|
|
26
|
+
path: '/operations',
|
|
27
|
+
surfaceType: 'graph',
|
|
28
|
+
featureKey: 'operations'
|
|
29
|
+
})
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
it('projects legacy template aliases with canonical navigation metadata', () => {
|
|
33
|
+
const legacySurfaces = [
|
|
34
|
+
{
|
|
35
|
+
id: 'operations',
|
|
36
|
+
label: 'Operations',
|
|
37
|
+
surfaceType: 'graph',
|
|
38
|
+
expectedFeatureKey: 'operations',
|
|
39
|
+
expectedIcon: 'operations',
|
|
40
|
+
expectedPath: '/operations',
|
|
41
|
+
expectedDomainIds: ['operations'],
|
|
42
|
+
expectedEntityIds: [],
|
|
43
|
+
expectedCapabilityIds: ['operations.organization-graph', 'operations.command-view']
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
id: 'projects',
|
|
47
|
+
label: 'Projects',
|
|
48
|
+
surfaceType: 'list',
|
|
49
|
+
expectedFeatureKey: 'projects',
|
|
50
|
+
expectedIcon: 'projects',
|
|
51
|
+
expectedPath: '/projects',
|
|
52
|
+
expectedDomainIds: ['delivery'],
|
|
53
|
+
expectedEntityIds: ['delivery.project'],
|
|
54
|
+
expectedCapabilityIds: ['delivery.projects.view']
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
id: 'lead-gen',
|
|
58
|
+
label: 'Lead Gen',
|
|
59
|
+
surfaceType: 'list',
|
|
60
|
+
expectedFeatureKey: 'lead-gen',
|
|
61
|
+
expectedIcon: 'lead-gen',
|
|
62
|
+
expectedPath: '/lead-gen',
|
|
63
|
+
expectedDomainIds: ['lead-gen'],
|
|
64
|
+
expectedEntityIds: ['leadgen.list'],
|
|
65
|
+
expectedCapabilityIds: ['leadgen.lists.manage']
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
id: 'crm',
|
|
69
|
+
label: 'CRM',
|
|
70
|
+
surfaceType: 'graph',
|
|
71
|
+
expectedFeatureKey: 'crm',
|
|
72
|
+
expectedIcon: 'crm',
|
|
73
|
+
expectedPath: '/crm',
|
|
74
|
+
expectedDomainIds: ['crm'],
|
|
75
|
+
expectedEntityIds: ['crm.deal'],
|
|
76
|
+
expectedCapabilityIds: ['crm.pipeline.manage']
|
|
77
|
+
}
|
|
78
|
+
] as const
|
|
79
|
+
|
|
80
|
+
expect(getOrganizationSurface('operations.organization-graph')).toBeDefined()
|
|
81
|
+
|
|
82
|
+
for (const surface of legacySurfaces) {
|
|
83
|
+
expect(getOrganizationSurface(surface.id)).toMatchObject({
|
|
84
|
+
id: surface.id,
|
|
85
|
+
label: surface.label,
|
|
86
|
+
path: surface.expectedPath,
|
|
87
|
+
surfaceType: surface.surfaceType,
|
|
88
|
+
icon: surface.expectedIcon,
|
|
89
|
+
featureKey: surface.expectedFeatureKey,
|
|
90
|
+
domainIds: surface.expectedDomainIds,
|
|
91
|
+
entityIds: surface.expectedEntityIds,
|
|
92
|
+
resourceIds: [],
|
|
93
|
+
capabilityIds: surface.expectedCapabilityIds
|
|
94
|
+
})
|
|
95
|
+
}
|
|
96
|
+
})
|
|
97
|
+
|
|
98
|
+
it('maps grouped core features onto the legacy template feature vocabulary', () => {
|
|
99
|
+
expect(foundationOrganizationModel.features.enabled.acquisition).toBe(true)
|
|
100
|
+
expect(foundationOrganizationModel.features.enabled.delivery).toBe(true)
|
|
101
|
+
expect(foundationOrganizationModel.features.enabled.crm).toBe(
|
|
102
|
+
foundationOrganizationModel.features.enabled.acquisition
|
|
103
|
+
)
|
|
104
|
+
expect(foundationOrganizationModel.features.enabled['lead-gen']).toBe(
|
|
105
|
+
foundationOrganizationModel.features.enabled.acquisition
|
|
106
|
+
)
|
|
107
|
+
expect(foundationOrganizationModel.features.enabled.projects).toBe(
|
|
108
|
+
foundationOrganizationModel.features.enabled.delivery
|
|
109
|
+
)
|
|
110
|
+
|
|
111
|
+
expect(foundationOrganizationModel.features.labels.crm).toBe('CRM')
|
|
112
|
+
expect(foundationOrganizationModel.features.labels['lead-gen']).toBe('Lead Gen')
|
|
113
|
+
expect(foundationOrganizationModel.features.labels.projects).toBe('Projects')
|
|
33
114
|
})
|
|
34
115
|
})
|
|
@@ -10,13 +10,14 @@
|
|
|
10
10
|
/**
|
|
11
11
|
* Per-user-per-org config (stored in org_memberships.config)
|
|
12
12
|
* Controls which features a specific member can access within their org
|
|
13
|
-
* Valid feature keys: operations, monitoring, acquisition, calibration, seo
|
|
13
|
+
* Valid feature keys: operations, monitoring, acquisition, delivery, calibration, seo
|
|
14
14
|
*/
|
|
15
15
|
export interface MembershipFeatureConfig {
|
|
16
16
|
features?: {
|
|
17
17
|
operations?: boolean
|
|
18
18
|
monitoring?: boolean
|
|
19
19
|
acquisition?: boolean
|
|
20
|
+
delivery?: boolean
|
|
20
21
|
calibration?: boolean
|
|
21
22
|
seo?: boolean
|
|
22
23
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { z } from 'zod'
|
|
2
|
-
import type { AgentDefinition } from '../../agent/core/types'
|
|
3
|
-
import type { KnowledgeMap } from '../../agent/knowledge-map/types'
|
|
4
|
-
import { createApprovalTool } from '../../tools/platform'
|
|
1
|
+
import { z } from 'zod'
|
|
2
|
+
import type { AgentDefinition } from '../../agent/core/types'
|
|
3
|
+
import type { KnowledgeMap } from '../../agent/knowledge-map/types'
|
|
4
|
+
import { createApprovalTool } from '../../tools/platform/approval/tool'
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* Create test agent with platform tools
|