@elevasis/core 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +195 -3
- package/dist/organization-model/index.js +195 -3
- package/package.json +1 -1
- 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
|
@@ -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
|
|
@@ -244,6 +244,8 @@ export {
|
|
|
244
244
|
type INotificationsService,
|
|
245
245
|
type ICredentialsService,
|
|
246
246
|
type IIntegrationService,
|
|
247
|
+
type ICrmService,
|
|
248
|
+
type IProjectsService,
|
|
247
249
|
// Email Service types
|
|
248
250
|
type IEmailService,
|
|
249
251
|
type SendPlatformEmailParams,
|
|
@@ -321,24 +323,8 @@ export {
|
|
|
321
323
|
} from './tools/registry'
|
|
322
324
|
|
|
323
325
|
// Platform Tools (server-side only)
|
|
326
|
+
// Retained internal/compatibility surface. Deployed SDK workers use platform.call() -> dispatcher.
|
|
324
327
|
export {
|
|
325
|
-
createApprovalTool,
|
|
326
|
-
createSchedulerTool,
|
|
327
|
-
createNotificationTool,
|
|
328
|
-
type ApprovalToolConfig,
|
|
329
|
-
type SchedulerToolConfig,
|
|
330
|
-
type NotificationToolConfig,
|
|
331
|
-
// Resource Invocation (service, types, and tool factories)
|
|
332
|
-
ResourceInvocationService,
|
|
333
|
-
createResourceInvocationService,
|
|
334
|
-
type ResourceExecutionRequest,
|
|
335
|
-
type ResourceInvocationResult,
|
|
336
|
-
// Tool factories (Wave 2a)
|
|
337
|
-
createResourceInvocationTool,
|
|
338
|
-
createDynamicResourceInvocationTool,
|
|
339
|
-
type ResourceInvocationToolConfig,
|
|
340
|
-
dynamicResourceInvocationSchema,
|
|
341
|
-
dynamicResourceInvocationOutputSchema,
|
|
342
328
|
// Storage Tools
|
|
343
329
|
createStorageUploadTool,
|
|
344
330
|
createStorageSignedUrlTool,
|
|
@@ -387,8 +373,6 @@ export {
|
|
|
387
373
|
CancelScheduleByKeyOutputSchema,
|
|
388
374
|
DeleteScheduleByKeyInputSchema,
|
|
389
375
|
DeleteScheduleByKeyOutputSchema,
|
|
390
|
-
// HITL Cancel by Metadata Tool
|
|
391
|
-
createHitlCancelByMetadataTool,
|
|
392
376
|
type HitlCancelByMetadataInput,
|
|
393
377
|
type HitlCancelByMetadataOutput,
|
|
394
378
|
HitlCancelByMetadataInputSchema,
|
|
@@ -428,6 +412,8 @@ export type {
|
|
|
428
412
|
StorageToolMap,
|
|
429
413
|
NotificationToolMap,
|
|
430
414
|
NotificationSDKInput,
|
|
415
|
+
ProjectsToolMap,
|
|
416
|
+
CrmToolMap,
|
|
431
417
|
LeadToolMap,
|
|
432
418
|
ListToolMap,
|
|
433
419
|
PdfToolMap,
|