@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.
Files changed (35) hide show
  1. package/dist/index.js +195 -3
  2. package/dist/organization-model/index.js +195 -3
  3. package/package.json +1 -1
  4. package/src/README.md +24 -17
  5. package/src/__tests__/template-foundations-compatibility.test.ts +95 -14
  6. package/src/auth/multi-tenancy/types.ts +2 -1
  7. package/src/execution/engine/__tests__/fixtures/test-agents.ts +4 -4
  8. package/src/execution/engine/index.ts +5 -19
  9. package/src/execution/engine/tools/platform/index.ts +9 -33
  10. package/src/execution/engine/tools/registry.ts +109 -2
  11. package/src/execution/engine/tools/tool-maps.ts +88 -0
  12. package/src/organization-model/README.md +19 -4
  13. package/src/organization-model/__tests__/graph.test.ts +612 -0
  14. package/src/organization-model/__tests__/resolve.test.ts +208 -0
  15. package/src/organization-model/defaults.ts +1 -1
  16. package/src/organization-model/organization-graph.mdx +262 -0
  17. package/src/organization-model/organization-model.mdx +257 -0
  18. package/src/organization-model/resolve.ts +26 -2
  19. package/src/organization-model/schema.ts +203 -1
  20. package/src/platform/constants/versions.ts +1 -1
  21. package/src/platform/registry/__tests__/resource-registry.integration.test.ts +24 -0
  22. package/src/platform/registry/__tests__/resource-registry.test.ts +63 -0
  23. package/src/platform/registry/resource-registry.ts +98 -10
  24. package/src/projects/api-schemas.ts +2 -1
  25. package/src/reference/_generated/contracts.md +1044 -0
  26. package/src/reference/glossary.md +88 -0
  27. package/src/server.ts +2 -3
  28. package/src/execution/engine/tools/platform/resource-invocation/__tests__/edge-cases.test.ts +0 -507
  29. package/src/execution/engine/tools/platform/resource-invocation/__tests__/resource-invocation-service.test.ts +0 -500
  30. package/src/execution/engine/tools/platform/resource-invocation/__tests__/tool.test.ts +0 -555
  31. package/src/execution/engine/tools/platform/resource-invocation/dynamic-tool.ts +0 -94
  32. package/src/execution/engine/tools/platform/resource-invocation/index.ts +0 -14
  33. package/src/execution/engine/tools/platform/resource-invocation/resource-invocation-service.ts +0 -147
  34. package/src/execution/engine/tools/platform/resource-invocation/tool.ts +0 -115
  35. 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 OrganizationModelSchema = z.object({
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: "Delivery",
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 OrganizationModelSchema = z.object({
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: "Delivery",
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@elevasis/core",
3
- "version": "0.1.0",
3
+ "version": "0.2.1",
4
4
  "license": "MIT",
5
5
  "description": "Minimal shared constants across Elevasis monorepo",
6
6
  "sideEffects": false,
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/server` only for Node.js-only helpers and services.
11
- - Use `@elevasis/core/test-utils` for test fixtures and mocks.
12
- - Prefer the narrowest published subpath that matches the work you are doing.
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
- - `platform` - shared constants, utilities, registry, SSE, and API types.
17
- - `auth` - multi-tenancy types for organizations, users, memberships, invitations, and credentials.
18
- - `execution` - workflow, agent, scheduler, calibration, and execution-interface contracts.
19
- - `commands` - command queue types and schemas.
20
- - `deployments` - deployment response types.
21
- - `operations` - sessions, notifications, observability, activities, triggers, and debug logs.
22
- - `business` - acquisition and SEO contracts, plus the PDF surface under its own subpaths.
23
- - `organization-model` - the semantic contract layer for CRM, lead gen, delivery, features, branding, and navigation.
24
- - `supabase` - generated database types and helpers.
25
- - `forms` - shared form schemas and form-facing types.
26
- - `integrations` - OAuth and credential contracts.
27
- - `projects` - project management request and response schemas.
28
- - `content` - published content metadata types.
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('adapts the foundations organization model onto the published core contract while preserving UI helpers', () => {
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(resolved.branding.organizationName).toBe(foundationOrganizationModel.branding.organizationName)
17
- expect(resolved.branding.productName).toBe(foundationOrganizationModel.branding.productName)
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
- expect(resolved.crm.pipelines.length).toBeGreaterThan(0)
32
- expect(resolved.delivery.projectStatuses.length).toBeGreaterThan(0)
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