@elevasis/core 0.20.0 → 0.22.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (77) hide show
  1. package/dist/index.d.ts +524 -6
  2. package/dist/index.js +417 -42
  3. package/dist/knowledge/index.d.ts +151 -1
  4. package/dist/organization-model/index.d.ts +524 -6
  5. package/dist/organization-model/index.js +417 -42
  6. package/dist/test-utils/index.d.ts +270 -1
  7. package/dist/test-utils/index.js +407 -41
  8. package/package.json +5 -5
  9. package/src/_gen/__tests__/__snapshots__/contracts.md.snap +501 -303
  10. package/src/auth/multi-tenancy/permissions.ts +20 -8
  11. package/src/business/README.md +2 -2
  12. package/src/business/acquisition/api-schemas.test.ts +198 -0
  13. package/src/business/acquisition/api-schemas.ts +250 -9
  14. package/src/business/acquisition/build-templates.test.ts +28 -0
  15. package/src/business/acquisition/build-templates.ts +20 -8
  16. package/src/business/acquisition/index.ts +12 -0
  17. package/src/business/acquisition/types.ts +6 -1
  18. package/src/business/clients/api-schemas.test.ts +115 -0
  19. package/src/business/clients/api-schemas.ts +158 -0
  20. package/src/business/clients/index.ts +1 -0
  21. package/src/business/deals/api-schemas.ts +8 -0
  22. package/src/business/index.ts +5 -2
  23. package/src/business/projects/types.ts +19 -0
  24. package/src/execution/engine/__tests__/fixtures/test-agents.ts +10 -8
  25. package/src/execution/engine/agent/core/__tests__/agent.test.ts +16 -12
  26. package/src/execution/engine/agent/core/__tests__/error-passthrough.test.ts +4 -3
  27. package/src/execution/engine/agent/core/types.ts +25 -15
  28. package/src/execution/engine/agent/index.ts +6 -4
  29. package/src/execution/engine/agent/reasoning/__tests__/request-builder.test.ts +24 -18
  30. package/src/execution/engine/index.ts +3 -0
  31. package/src/execution/engine/tools/integration/server/adapters/apify/apify-adapter.test.ts +55 -0
  32. package/src/execution/engine/tools/integration/server/adapters/apify/apify-adapter.ts +107 -41
  33. package/src/execution/engine/tools/integration/server/adapters/apollo/apollo-adapter.test.ts +48 -0
  34. package/src/execution/engine/tools/integration/server/adapters/apollo/apollo-adapter.ts +99 -0
  35. package/src/execution/engine/tools/integration/server/adapters/apollo/index.ts +1 -0
  36. package/src/execution/engine/tools/integration/server/adapters/clickup/clickup-adapter.test.ts +18 -0
  37. package/src/execution/engine/tools/integration/server/adapters/clickup/clickup-adapter.ts +194 -0
  38. package/src/execution/engine/tools/integration/server/adapters/clickup/index.ts +7 -0
  39. package/src/execution/engine/workflow/types.ts +7 -0
  40. package/src/integrations/credentials/api-schemas.ts +21 -2
  41. package/src/integrations/credentials/schemas.ts +200 -164
  42. package/src/organization-model/README.md +10 -3
  43. package/src/organization-model/__tests__/defaults.test.ts +6 -0
  44. package/src/organization-model/__tests__/domains/resources.test.ts +188 -0
  45. package/src/organization-model/__tests__/domains/roles.test.ts +402 -347
  46. package/src/organization-model/__tests__/domains/systems.test.ts +193 -0
  47. package/src/organization-model/__tests__/knowledge.test.ts +39 -0
  48. package/src/organization-model/__tests__/prospecting-ssot.test.ts +7 -4
  49. package/src/organization-model/__tests__/resolve.test.ts +1 -1
  50. package/src/organization-model/defaults.ts +24 -3
  51. package/src/organization-model/domains/knowledge.ts +3 -2
  52. package/src/organization-model/domains/prospecting.ts +182 -25
  53. package/src/organization-model/domains/resources.ts +88 -0
  54. package/src/organization-model/domains/roles.ts +93 -55
  55. package/src/organization-model/domains/sales.ts +24 -3
  56. package/src/organization-model/domains/systems.ts +46 -0
  57. package/src/organization-model/icons.ts +1 -0
  58. package/src/organization-model/index.ts +2 -0
  59. package/src/organization-model/organization-model.mdx +33 -14
  60. package/src/organization-model/published.ts +52 -1
  61. package/src/organization-model/schema.ts +121 -0
  62. package/src/organization-model/types.ts +46 -1
  63. package/src/platform/api/types.ts +38 -35
  64. package/src/platform/constants/versions.ts +1 -1
  65. package/src/platform/registry/__tests__/resource-registry.test.ts +2051 -2005
  66. package/src/platform/registry/__tests__/validation.test.ts +1343 -1086
  67. package/src/platform/registry/index.ts +14 -0
  68. package/src/platform/registry/resource-registry.ts +40 -2
  69. package/src/platform/registry/serialization.ts +241 -202
  70. package/src/platform/registry/serialized-types.ts +1 -0
  71. package/src/platform/registry/types.ts +411 -361
  72. package/src/platform/registry/validation.ts +743 -513
  73. package/src/projects/api-schemas.ts +290 -267
  74. package/src/reference/_generated/contracts.md +501 -303
  75. package/src/reference/glossary.md +8 -3
  76. package/src/server.ts +2 -0
  77. package/src/supabase/database.types.ts +121 -0
@@ -19,6 +19,7 @@ var ORGANIZATION_MODEL_ICON_TOKENS = [
19
19
  "knowledge.reference",
20
20
  "feature.dashboard",
21
21
  "feature.calendar",
22
+ "feature.business",
22
23
  "feature.sales",
23
24
  "feature.crm",
24
25
  "feature.finance",
@@ -239,6 +240,13 @@ var LEAD_GEN_STAGE_CATALOG = {
239
240
  order: 2,
240
241
  entity: "company"
241
242
  },
243
+ crawled: {
244
+ key: "crawled",
245
+ label: "Websites crawled",
246
+ description: "Company websites have been crawled (e.g. via Apify) and raw page content stored for downstream LLM analysis.",
247
+ order: 2.5,
248
+ entity: "company"
249
+ },
242
250
  extracted: {
243
251
  key: "extracted",
244
252
  label: "Websites analyzed",
@@ -258,7 +266,9 @@ var LEAD_GEN_STAGE_CATALOG = {
258
266
  label: "Decision-makers found",
259
267
  description: "Decision-maker contacts discovered and attached to a qualified company.",
260
268
  order: 6,
261
- entity: "company"
269
+ entity: "company",
270
+ recordEntity: "contact",
271
+ recordStageKey: "discovered"
262
272
  },
263
273
  // Prospecting — contact discovery
264
274
  discovered: {
@@ -296,7 +306,8 @@ var LEAD_GEN_STAGE_CATALOG = {
296
306
  label: "Reviewed and exported",
297
307
  description: "Approved records have been reviewed and exported for handoff.",
298
308
  order: 10,
299
- entity: "contact"
309
+ entity: "company",
310
+ additionalEntities: ["contact"]
300
311
  },
301
312
  interested: {
302
313
  key: "interested",
@@ -366,18 +377,47 @@ var FeatureSchema = z.object({
366
377
  });
367
378
  var ProspectingLifecycleStageSchema = DisplayMetadataSchema.extend({
368
379
  id: ModelIdSchema,
369
- order: z.number().int().min(0)
380
+ order: z.number().min(0)
381
+ });
382
+ var RecordColumnConfigSchema = z.object({
383
+ key: ModelIdSchema,
384
+ label: z.string().trim().min(1).max(120),
385
+ path: z.string().trim().min(1).max(500),
386
+ width: z.union([z.number().positive(), z.string().trim().min(1).max(100)]).optional(),
387
+ renderType: z.enum(["text", "badge", "datetime", "count", "json"]).optional(),
388
+ badgeColor: z.string().trim().min(1).max(40).optional()
389
+ });
390
+ var RecordColumnsConfigSchema = z.object({
391
+ company: z.array(RecordColumnConfigSchema).optional(),
392
+ contact: z.array(RecordColumnConfigSchema).optional()
393
+ }).refine((columns) => Boolean(columns.company?.length || columns.contact?.length), {
394
+ message: "recordColumns must include at least one entity column set"
395
+ });
396
+ var CredentialRequirementSchema = z.object({
397
+ key: ModelIdSchema,
398
+ provider: ModelIdSchema,
399
+ credentialType: z.enum(["api-key", "api-key-secret", "oauth", "webhook-secret"]),
400
+ label: z.string().trim().min(1).max(120),
401
+ required: z.boolean(),
402
+ selectionMode: z.enum(["single", "multiple"]).optional(),
403
+ inputPath: z.string().trim().min(1).max(500),
404
+ verifyOnRun: z.boolean().optional()
370
405
  });
371
406
  var ProspectingBuildTemplateStepSchema = DisplayMetadataSchema.extend({
372
407
  id: ModelIdSchema,
373
408
  primaryEntity: z.enum(["company", "contact"]),
374
409
  outputs: z.array(z.enum(["company", "contact", "export"])).min(1),
375
410
  stageKey: ModelIdSchema,
411
+ recordEntity: z.enum(["company", "contact"]).optional(),
412
+ recordsStageKey: ModelIdSchema.optional(),
413
+ recordSourceStageKey: ModelIdSchema.optional(),
376
414
  dependsOn: z.array(ModelIdSchema).optional(),
377
415
  dependencyMode: z.literal("per-record-eligibility"),
378
416
  capabilityKey: ModelIdSchema,
379
417
  defaultBatchSize: z.number().int().positive(),
380
- maxBatchSize: z.number().int().positive()
418
+ maxBatchSize: z.number().int().positive(),
419
+ recordColumns: RecordColumnsConfigSchema.optional(),
420
+ credentialRequirements: z.array(CredentialRequirementSchema).optional()
381
421
  }).refine((step) => step.defaultBatchSize <= step.maxBatchSize, {
382
422
  message: "defaultBatchSize must be less than or equal to maxBatchSize",
383
423
  path: ["defaultBatchSize"]
@@ -386,6 +426,62 @@ var ProspectingBuildTemplateSchema = DisplayMetadataSchema.extend({
386
426
  id: ModelIdSchema,
387
427
  steps: z.array(ProspectingBuildTemplateStepSchema).min(1)
388
428
  });
429
+ var DTC_RECORD_COLUMNS = {
430
+ populated: {
431
+ company: [
432
+ { key: "name", label: "Company", path: "company.name" },
433
+ { key: "domain", label: "Domain", path: "company.domain" },
434
+ { key: "employee-count", label: "Employees", path: "company.numEmployees", renderType: "count" },
435
+ { key: "apollo-industry", label: "Apollo industry", path: "company.category" },
436
+ { key: "location", label: "Location", path: "company.locationState" }
437
+ ]
438
+ },
439
+ crawled: {
440
+ company: [
441
+ { key: "name", label: "Company", path: "company.name" },
442
+ { key: "domain", label: "Domain", path: "company.domain" },
443
+ { key: "page-count", label: "Pages", path: "company.enrichmentData.websiteCrawl.pageCount", renderType: "count" },
444
+ { key: "crawl-status", label: "Crawl status", path: "processingState.crawled.status", renderType: "badge" }
445
+ ]
446
+ },
447
+ extracted: {
448
+ company: [
449
+ { key: "name", label: "Company", path: "company.name" },
450
+ { key: "domain", label: "Domain", path: "company.domain" },
451
+ { key: "description", label: "Description", path: "company.enrichmentData.websiteCrawl.companyDescription" },
452
+ { key: "services", label: "Services", path: "company.enrichmentData.websiteCrawl.services", renderType: "json" },
453
+ { key: "automation-gaps", label: "Automation gaps", path: "company.enrichmentData.websiteCrawl.automationGaps", renderType: "json" },
454
+ { key: "contact-count", label: "Contacts", path: "company.enrichmentData.websiteCrawl.emailCount", renderType: "count" }
455
+ ]
456
+ },
457
+ qualified: {
458
+ company: [
459
+ { key: "name", label: "Company", path: "company.name" },
460
+ { key: "domain", label: "Domain", path: "company.domain" },
461
+ { key: "score", label: "Score", path: "company.qualificationScore", renderType: "badge", badgeColor: "green" },
462
+ { key: "signals", label: "Signals", path: "company.qualificationSignals", renderType: "json" },
463
+ { key: "disqualified-reason", label: "Disqualified reason", path: "processingState.qualified.data.disqualifiedReason" }
464
+ ]
465
+ },
466
+ decisionMakers: {
467
+ contact: [
468
+ { key: "name", label: "Name", path: "contact.name" },
469
+ { key: "title", label: "Title", path: "contact.title" },
470
+ { key: "email", label: "Email", path: "contact.email" },
471
+ { key: "linkedin", label: "LinkedIn", path: "contact.linkedinUrl" },
472
+ { key: "priority-score", label: "Priority", path: "contact.enrichmentData.apollo.priorityScore", renderType: "badge" }
473
+ ]
474
+ },
475
+ uploaded: {
476
+ company: [
477
+ { key: "name", label: "Company", path: "company.name" },
478
+ { key: "domain", label: "Domain", path: "company.domain" },
479
+ { key: "contacts", label: "Contacts", path: "company.enrichmentData.approvedLeadListExport.contacts", renderType: "json" },
480
+ { key: "score", label: "Score", path: "company.qualificationScore", renderType: "badge", badgeColor: "green" },
481
+ { key: "approval", label: "Approval", path: "company.enrichmentData.approvedLeadListExport.approvalStatus", renderType: "badge" }
482
+ ]
483
+ }
484
+ };
389
485
  z.object({
390
486
  id: ModelIdSchema,
391
487
  label: z.string(),
@@ -489,7 +585,45 @@ var PROSPECTING_STEPS = {
489
585
  dependencyMode: "per-record-eligibility",
490
586
  capabilityKey: "lead-gen.company.apollo-import",
491
587
  defaultBatchSize: 250,
492
- maxBatchSize: 1e3
588
+ maxBatchSize: 1e3,
589
+ recordColumns: DTC_RECORD_COLUMNS.populated,
590
+ credentialRequirements: [
591
+ {
592
+ key: "apollo",
593
+ provider: "apollo",
594
+ credentialType: "api-key-secret",
595
+ label: "Apollo API key",
596
+ required: true,
597
+ selectionMode: "single",
598
+ inputPath: "credential"
599
+ }
600
+ ]
601
+ },
602
+ apifyCrawl: {
603
+ id: "apify-crawl",
604
+ label: "Websites crawled",
605
+ description: "Crawl company websites via Apify and store raw page markdown in enrichmentData.websiteCrawl.pages for downstream LLM analysis. Overwrites the synthetic seed Apollo Import wrote with real page content.",
606
+ primaryEntity: "company",
607
+ outputs: ["company"],
608
+ stageKey: "crawled",
609
+ dependsOn: ["import-apollo-search"],
610
+ dependencyMode: "per-record-eligibility",
611
+ capabilityKey: "lead-gen.company.apify-crawl",
612
+ defaultBatchSize: 50,
613
+ maxBatchSize: 100,
614
+ recordColumns: DTC_RECORD_COLUMNS.crawled,
615
+ credentialRequirements: [
616
+ {
617
+ key: "apify",
618
+ provider: "apify",
619
+ credentialType: "api-key-secret",
620
+ label: "Apify API token",
621
+ required: true,
622
+ selectionMode: "single",
623
+ inputPath: "credential",
624
+ verifyOnRun: true
625
+ }
626
+ ]
493
627
  },
494
628
  analyzeWebsites: {
495
629
  id: "analyze-websites",
@@ -498,11 +632,12 @@ var PROSPECTING_STEPS = {
498
632
  primaryEntity: "company",
499
633
  outputs: ["company"],
500
634
  stageKey: "extracted",
501
- dependsOn: ["import-apollo-search"],
635
+ dependsOn: ["apify-crawl"],
502
636
  dependencyMode: "per-record-eligibility",
503
637
  capabilityKey: "lead-gen.company.website-extract",
504
638
  defaultBatchSize: 50,
505
- maxBatchSize: 100
639
+ maxBatchSize: 100,
640
+ recordColumns: DTC_RECORD_COLUMNS.extracted
506
641
  },
507
642
  scoreDtcFit: {
508
643
  id: "score-dtc-fit",
@@ -515,7 +650,8 @@ var PROSPECTING_STEPS = {
515
650
  dependencyMode: "per-record-eligibility",
516
651
  capabilityKey: "lead-gen.company.dtc-subscription-qualify",
517
652
  defaultBatchSize: 100,
518
- maxBatchSize: 250
653
+ maxBatchSize: 250,
654
+ recordColumns: DTC_RECORD_COLUMNS.qualified
519
655
  },
520
656
  enrichDecisionMakers: {
521
657
  id: "enrich-decision-makers",
@@ -524,37 +660,52 @@ var PROSPECTING_STEPS = {
524
660
  primaryEntity: "company",
525
661
  outputs: ["contact"],
526
662
  stageKey: "decision-makers-enriched",
663
+ recordEntity: "contact",
527
664
  dependsOn: ["score-dtc-fit"],
528
665
  dependencyMode: "per-record-eligibility",
529
666
  capabilityKey: "lead-gen.contact.apollo-decision-maker-enrich",
530
667
  defaultBatchSize: 100,
531
- maxBatchSize: 250
532
- },
533
- verifyEmails: {
534
- id: "verify-emails",
535
- label: "Emails verified",
536
- description: "Verify deliverability before the QC and handoff step.",
537
- primaryEntity: "contact",
538
- outputs: ["contact"],
539
- stageKey: "verified",
540
- dependsOn: ["enrich-decision-makers"],
541
- dependencyMode: "per-record-eligibility",
542
- capabilityKey: "lead-gen.contact.verify-email",
543
- defaultBatchSize: 250,
544
- maxBatchSize: 500
668
+ maxBatchSize: 250,
669
+ recordColumns: DTC_RECORD_COLUMNS.decisionMakers,
670
+ credentialRequirements: [
671
+ {
672
+ key: "apollo",
673
+ provider: "apollo",
674
+ credentialType: "api-key-secret",
675
+ label: "Apollo API key",
676
+ required: true,
677
+ selectionMode: "single",
678
+ inputPath: "credential"
679
+ }
680
+ ]
545
681
  },
546
682
  reviewAndExport: {
547
683
  id: "review-and-export",
548
684
  label: "Reviewed and exported",
549
- description: "Operator QC approves or rejects leads, then approved records are exported as a lead list.",
685
+ description: "Operator QC approves or rejects qualified companies, then approved records are exported as a lead list with unverified emails.",
550
686
  primaryEntity: "company",
551
687
  outputs: ["export"],
552
688
  stageKey: "uploaded",
553
- dependsOn: ["verify-emails"],
689
+ recordsStageKey: "uploaded",
690
+ recordSourceStageKey: "qualified",
691
+ dependsOn: ["enrich-decision-makers"],
554
692
  dependencyMode: "per-record-eligibility",
555
693
  capabilityKey: "lead-gen.export.list",
556
694
  defaultBatchSize: 100,
557
- maxBatchSize: 250
695
+ maxBatchSize: 250,
696
+ recordColumns: DTC_RECORD_COLUMNS.uploaded,
697
+ credentialRequirements: [
698
+ {
699
+ key: "clickup",
700
+ provider: "clickup",
701
+ credentialType: "api-key-secret",
702
+ label: "ClickUp API token",
703
+ required: true,
704
+ selectionMode: "single",
705
+ inputPath: "clickupCredential",
706
+ verifyOnRun: true
707
+ }
708
+ ]
558
709
  }
559
710
  }
560
711
  };
@@ -576,7 +727,7 @@ function toProspectingLifecycleStage(stage) {
576
727
  };
577
728
  }
578
729
  function leadGenStagesForEntity(entity) {
579
- return Object.values(LEAD_GEN_STAGE_CATALOG).filter((stage) => stage.entity === entity).sort((a, b) => a.order - b.order).map(toProspectingLifecycleStage);
730
+ return Object.values(LEAD_GEN_STAGE_CATALOG).filter((stage) => stage.entity === entity || stage.additionalEntities?.includes(entity)).sort((a, b) => a.order - b.order).map(toProspectingLifecycleStage);
580
731
  }
581
732
  var DEFAULT_ORGANIZATION_MODEL_PROSPECTING = {
582
733
  listEntityId: "leadgen.list",
@@ -606,10 +757,10 @@ var DEFAULT_ORGANIZATION_MODEL_PROSPECTING = {
606
757
  description: "Prospecting pipeline for DTC subscription or subscription-ready brands where Apollo is the source and contact-enrichment layer, Elevasis handles company research and fit scoring, and approved leads export as an approved lead list.",
607
758
  steps: [
608
759
  PROSPECTING_STEPS.dtcApolloClickup.importApolloSearch,
760
+ PROSPECTING_STEPS.dtcApolloClickup.apifyCrawl,
609
761
  PROSPECTING_STEPS.dtcApolloClickup.analyzeWebsites,
610
762
  PROSPECTING_STEPS.dtcApolloClickup.scoreDtcFit,
611
763
  PROSPECTING_STEPS.dtcApolloClickup.enrichDecisionMakers,
612
- PROSPECTING_STEPS.dtcApolloClickup.verifyEmails,
613
764
  PROSPECTING_STEPS.dtcApolloClickup.reviewAndExport
614
765
  ]
615
766
  }
@@ -819,13 +970,113 @@ var OfferingsDomainSchema = z.object({
819
970
  var DEFAULT_ORGANIZATION_MODEL_OFFERINGS = {
820
971
  products: []
821
972
  };
973
+ var SystemKindSchema = z.enum(["product", "operational", "platform", "diagnostic"]);
974
+ var SystemStatusSchema = z.enum(["active", "deprecated", "archived"]);
975
+ var SystemIdSchema = ModelIdSchema;
976
+ var SystemEntrySchema = z.object({
977
+ /** Stable tenant-defined system id (e.g. "sys.lead-gen"). */
978
+ id: SystemIdSchema,
979
+ /** Human-readable system title shown in governance and operations UI. */
980
+ title: LabelSchema,
981
+ /** One-paragraph purpose statement for the bounded context. */
982
+ description: DescriptionSchema,
983
+ /** Closed system shape enum; catalog values remain tenant-defined. */
984
+ kind: SystemKindSchema,
985
+ /** Optional role responsible for this system. */
986
+ responsibleRoleId: ModelIdSchema.optional(),
987
+ /** Optional knowledge nodes that govern this system. */
988
+ governedByKnowledge: ReferenceIdsSchema,
989
+ /** Optional goals this system contributes to. */
990
+ drivesGoals: ReferenceIdsSchema,
991
+ status: SystemStatusSchema
992
+ });
993
+ var SystemsDomainSchema = z.object({
994
+ systems: z.array(SystemEntrySchema).default([])
995
+ });
996
+ var DEFAULT_ORGANIZATION_MODEL_SYSTEMS = {
997
+ systems: []
998
+ };
999
+
1000
+ // src/organization-model/domains/resources.ts
1001
+ var ResourceKindSchema = z.enum(["workflow", "agent", "integration"]);
1002
+ var ResourceGovernanceStatusSchema = z.enum(["active", "deprecated", "archived"]);
1003
+ var AgentKindSchema = z.enum(["orchestrator", "specialist", "utility", "system"]);
1004
+ var ResourceIdSchema = z.string().trim().min(1).max(255).regex(/^[A-Za-z0-9]+(?:[-._][A-Za-z0-9]+)*$/, "Resource IDs must use letters, numbers, -, _, or . separators");
1005
+ var ResourceEntryBaseSchema = z.object({
1006
+ /** Canonical resource id; runtime resourceId derives from this value. */
1007
+ id: ResourceIdSchema,
1008
+ /** Required single System membership. */
1009
+ systemId: SystemIdSchema,
1010
+ /** Optional role responsible for maintaining this resource. */
1011
+ ownerRoleId: ModelIdSchema.optional(),
1012
+ status: ResourceGovernanceStatusSchema
1013
+ });
1014
+ var WorkflowResourceEntrySchema = ResourceEntryBaseSchema.extend({
1015
+ kind: z.literal("workflow"),
1016
+ /** Mirrors WorkflowConfig.capabilityKey when the runtime workflow has one. */
1017
+ capabilityKey: z.string().trim().min(1).max(255).optional()
1018
+ });
1019
+ var AgentResourceEntrySchema = ResourceEntryBaseSchema.extend({
1020
+ kind: z.literal("agent"),
1021
+ /** Mirrors code-side AgentConfig.kind. */
1022
+ agentKind: AgentKindSchema,
1023
+ /** Role this agent embodies, if any. */
1024
+ actsAsRoleId: ModelIdSchema.optional(),
1025
+ /** Mirrors AgentConfig.sessionCapable. */
1026
+ sessionCapable: z.boolean()
1027
+ });
1028
+ var IntegrationResourceEntrySchema = ResourceEntryBaseSchema.extend({
1029
+ kind: z.literal("integration"),
1030
+ provider: z.string().trim().min(1).max(100)
1031
+ });
1032
+ var ResourceEntrySchema = z.discriminatedUnion("kind", [
1033
+ WorkflowResourceEntrySchema,
1034
+ AgentResourceEntrySchema,
1035
+ IntegrationResourceEntrySchema
1036
+ ]);
1037
+ var ResourcesDomainSchema = z.object({
1038
+ entries: z.array(ResourceEntrySchema).default([])
1039
+ });
1040
+ var DEFAULT_ORGANIZATION_MODEL_RESOURCES = {
1041
+ entries: []
1042
+ };
1043
+ function defineResource(resource) {
1044
+ return ResourceEntrySchema.parse(resource);
1045
+ }
1046
+ function defineResources(resources) {
1047
+ for (const resource of Object.values(resources)) {
1048
+ ResourceEntrySchema.parse(resource);
1049
+ }
1050
+ return resources;
1051
+ }
1052
+
1053
+ // src/organization-model/domains/roles.ts
1054
+ var RoleIdSchema = ModelIdSchema;
1055
+ var HumanRoleHolderSchema = z.object({
1056
+ kind: z.literal("human"),
1057
+ userId: z.string().trim().min(1).max(200)
1058
+ });
1059
+ var AgentRoleHolderSchema = z.object({
1060
+ kind: z.literal("agent"),
1061
+ agentId: ResourceIdSchema
1062
+ });
1063
+ var TeamRoleHolderSchema = z.object({
1064
+ kind: z.literal("team"),
1065
+ memberIds: z.array(z.string().trim().min(1).max(200)).min(1)
1066
+ });
1067
+ var RoleHolderSchema = z.discriminatedUnion("kind", [
1068
+ HumanRoleHolderSchema,
1069
+ AgentRoleHolderSchema,
1070
+ TeamRoleHolderSchema
1071
+ ]);
1072
+ var RoleHoldersSchema = z.union([RoleHolderSchema, z.array(RoleHolderSchema).min(1)]);
822
1073
  var RoleSchema = z.object({
823
1074
  /** Stable unique identifier for the role (e.g. "role-ceo", "role-head-of-sales"). */
824
- id: z.string().trim().min(1).max(100),
1075
+ id: RoleIdSchema,
825
1076
  /** Human-readable title shown to agents and in UI (e.g. "CEO", "Head of Sales"). */
826
1077
  title: z.string().trim().min(1).max(200),
827
1078
  /**
828
- * List of responsibilities this role owns plain-language descriptions of
1079
+ * List of responsibilities this role owns - plain-language descriptions of
829
1080
  * what the person in this role is accountable for delivering.
830
1081
  * Defaults to empty array so minimal role definitions stay concise.
831
1082
  */
@@ -833,16 +1084,18 @@ var RoleSchema = z.object({
833
1084
  /**
834
1085
  * Optional: ID of another role this role reports to.
835
1086
  * When present, must reference another `roles[].id` in the same organization.
836
- * Cross-reference enforced in `OrganizationModelSchema.superRefine()`.
837
- * Absence indicates a top-level role (no reporting line).
838
1087
  */
839
- reportsToId: z.string().trim().min(1).max(100).optional(),
1088
+ reportsToId: RoleIdSchema.optional(),
840
1089
  /**
841
- * Optional: name or email of the person currently holding this role.
842
- * Free-form string supports "Alice Johnson", "alice@example.com", or
843
- * any human-readable identifier. Not validated against any user registry.
1090
+ * Optional: human, agent, or team holder currently filling this role.
1091
+ * Agent holders reference OM Resource IDs and are validated at the model level.
844
1092
  */
845
- heldBy: z.string().trim().max(200).optional()
1093
+ heldBy: RoleHoldersSchema.optional(),
1094
+ /**
1095
+ * Optional Systems this role is accountable for.
1096
+ * Cross-reference enforced in `OrganizationModelSchema.superRefine()`.
1097
+ */
1098
+ responsibleFor: z.array(SystemIdSchema).optional()
846
1099
  });
847
1100
  var RolesDomainSchema = z.object({
848
1101
  roles: z.array(RoleSchema).default([])
@@ -1077,8 +1330,8 @@ var OrgKnowledgeNodeSchema = z.object({
1077
1330
  skills: z.array(KnowledgeSkillBindingSchema).optional(),
1078
1331
  /** Domain key used to derive fast graph->skill registries. */
1079
1332
  domain: KnowledgeDomainBindingSchema.optional(),
1080
- /** Identifiers of the roles or members who own this knowledge node. */
1081
- ownerIds: z.array(ModelIdSchema).default([]),
1333
+ /** Role identifiers that own this knowledge node. */
1334
+ ownerIds: z.array(RoleIdSchema).default([]),
1082
1335
  /** ISO date string (YYYY-MM-DD or full ISO 8601) of last meaningful update. */
1083
1336
  updatedAt: z.string().trim().min(1).max(50)
1084
1337
  });
@@ -1100,6 +1353,8 @@ var OrganizationModelSchemaBase = z.object({
1100
1353
  offerings: OfferingsDomainSchema.default(DEFAULT_ORGANIZATION_MODEL_OFFERINGS),
1101
1354
  roles: RolesDomainSchema.default(DEFAULT_ORGANIZATION_MODEL_ROLES),
1102
1355
  goals: GoalsDomainSchema.default(DEFAULT_ORGANIZATION_MODEL_GOALS),
1356
+ systems: SystemsDomainSchema.default(DEFAULT_ORGANIZATION_MODEL_SYSTEMS),
1357
+ resources: ResourcesDomainSchema.default(DEFAULT_ORGANIZATION_MODEL_RESOURCES),
1103
1358
  statuses: StatusesDomainSchema.default({ entries: [] }),
1104
1359
  operations: OperationsDomainSchema.default({ entries: [] }),
1105
1360
  knowledge: KnowledgeDomainSchema.default({ nodes: [] })
@@ -1133,6 +1388,9 @@ function hasFeature(featuresById, featureId) {
1133
1388
  function defaultFeaturePathFor(id) {
1134
1389
  return `/${id.replaceAll(".", "/")}`;
1135
1390
  }
1391
+ function asRoleHolderArray(heldBy) {
1392
+ return Array.isArray(heldBy) ? heldBy : [heldBy];
1393
+ }
1136
1394
  var OrganizationModelSchema = OrganizationModelSchemaBase.superRefine((model, ctx) => {
1137
1395
  const featuresById = collectIds(model.features, ctx, ["features"], "Feature");
1138
1396
  const featureIdsByEffectivePath = /* @__PURE__ */ new Map();
@@ -1243,6 +1501,8 @@ var OrganizationModelSchema = OrganizationModelSchemaBase.superRefine((model, ct
1243
1501
  );
1244
1502
  }
1245
1503
  });
1504
+ const goalsById = new Map(model.goals.objectives.map((objective) => [objective.id, objective]));
1505
+ const knowledgeById = new Map(model.knowledge.nodes.map((node) => [node.id, node]));
1246
1506
  const rolesById = new Map(model.roles.roles.map((role) => [role.id, role]));
1247
1507
  model.roles.roles.forEach((role, roleIndex) => {
1248
1508
  if (role.reportsToId !== void 0 && !rolesById.has(role.reportsToId)) {
@@ -1253,6 +1513,102 @@ var OrganizationModelSchema = OrganizationModelSchemaBase.superRefine((model, ct
1253
1513
  );
1254
1514
  }
1255
1515
  });
1516
+ const systemsById = collectIds(model.systems.systems, ctx, ["systems", "systems"], "System");
1517
+ model.roles.roles.forEach((role, roleIndex) => {
1518
+ role.responsibleFor?.forEach((systemId, systemIndex) => {
1519
+ if (!systemsById.has(systemId)) {
1520
+ addIssue(
1521
+ ctx,
1522
+ ["roles", "roles", roleIndex, "responsibleFor", systemIndex],
1523
+ `Role "${role.id}" references unknown responsibleFor system "${systemId}"`
1524
+ );
1525
+ }
1526
+ });
1527
+ });
1528
+ model.systems.systems.forEach((system, systemIndex) => {
1529
+ if (system.responsibleRoleId !== void 0 && !rolesById.has(system.responsibleRoleId)) {
1530
+ addIssue(
1531
+ ctx,
1532
+ ["systems", "systems", systemIndex, "responsibleRoleId"],
1533
+ `System "${system.id}" references unknown responsibleRoleId "${system.responsibleRoleId}"`
1534
+ );
1535
+ }
1536
+ system.governedByKnowledge.forEach((nodeId, nodeIndex) => {
1537
+ if (!knowledgeById.has(nodeId)) {
1538
+ addIssue(
1539
+ ctx,
1540
+ ["systems", "systems", systemIndex, "governedByKnowledge", nodeIndex],
1541
+ `System "${system.id}" references unknown knowledge node "${nodeId}"`
1542
+ );
1543
+ }
1544
+ });
1545
+ system.drivesGoals.forEach((goalId, goalIndex) => {
1546
+ if (!goalsById.has(goalId)) {
1547
+ addIssue(
1548
+ ctx,
1549
+ ["systems", "systems", systemIndex, "drivesGoals", goalIndex],
1550
+ `System "${system.id}" references unknown goal "${goalId}"`
1551
+ );
1552
+ }
1553
+ });
1554
+ });
1555
+ const resourcesById = collectIds(model.resources.entries, ctx, ["resources", "entries"], "Resource");
1556
+ model.resources.entries.forEach((resource, resourceIndex) => {
1557
+ if (!systemsById.has(resource.systemId)) {
1558
+ addIssue(
1559
+ ctx,
1560
+ ["resources", "entries", resourceIndex, "systemId"],
1561
+ `Resource "${resource.id}" references unknown systemId "${resource.systemId}"`
1562
+ );
1563
+ }
1564
+ if (resource.ownerRoleId !== void 0 && !rolesById.has(resource.ownerRoleId)) {
1565
+ addIssue(
1566
+ ctx,
1567
+ ["resources", "entries", resourceIndex, "ownerRoleId"],
1568
+ `Resource "${resource.id}" references unknown ownerRoleId "${resource.ownerRoleId}"`
1569
+ );
1570
+ }
1571
+ if (resource.kind === "agent" && resource.actsAsRoleId !== void 0 && !rolesById.has(resource.actsAsRoleId)) {
1572
+ addIssue(
1573
+ ctx,
1574
+ ["resources", "entries", resourceIndex, "actsAsRoleId"],
1575
+ `Agent resource "${resource.id}" references unknown actsAsRoleId "${resource.actsAsRoleId}"`
1576
+ );
1577
+ }
1578
+ });
1579
+ model.roles.roles.forEach((role, roleIndex) => {
1580
+ if (role.heldBy === void 0) return;
1581
+ asRoleHolderArray(role.heldBy).forEach((holder, holderIndex) => {
1582
+ if (holder.kind !== "agent") return;
1583
+ const resource = resourcesById.get(holder.agentId);
1584
+ if (resource === void 0) {
1585
+ addIssue(
1586
+ ctx,
1587
+ ["roles", "roles", roleIndex, "heldBy", Array.isArray(role.heldBy) ? holderIndex : "agentId"],
1588
+ `Role "${role.id}" references unknown agent holder resource "${holder.agentId}"`
1589
+ );
1590
+ return;
1591
+ }
1592
+ if (resource.kind !== "agent") {
1593
+ addIssue(
1594
+ ctx,
1595
+ ["roles", "roles", roleIndex, "heldBy", Array.isArray(role.heldBy) ? holderIndex : "agentId"],
1596
+ `Role "${role.id}" agent holder "${holder.agentId}" must reference an agent resource`
1597
+ );
1598
+ }
1599
+ });
1600
+ });
1601
+ model.knowledge.nodes.forEach((node, nodeIndex) => {
1602
+ node.ownerIds.forEach((roleId, ownerIndex) => {
1603
+ if (!rolesById.has(roleId)) {
1604
+ addIssue(
1605
+ ctx,
1606
+ ["knowledge", "nodes", nodeIndex, "ownerIds", ownerIndex],
1607
+ `Knowledge node "${node.id}" references unknown owner role "${roleId}"`
1608
+ );
1609
+ }
1610
+ });
1611
+ });
1256
1612
  });
1257
1613
  var OrganizationGraphNodeKindSchema = z.enum([
1258
1614
  "organization",
@@ -1347,6 +1703,15 @@ var DEFAULT_ORGANIZATION_MODEL = {
1347
1703
  color: "green",
1348
1704
  icon: "feature.finance"
1349
1705
  },
1706
+ {
1707
+ id: "business",
1708
+ label: "Business",
1709
+ description: "Revenue, client relationships, and project delivery",
1710
+ enabled: true,
1711
+ color: "blue",
1712
+ icon: "feature.business",
1713
+ uiPosition: "sidebar-primary"
1714
+ },
1350
1715
  {
1351
1716
  id: "sales",
1352
1717
  label: "Sales",
@@ -1354,7 +1719,7 @@ var DEFAULT_ORGANIZATION_MODEL = {
1354
1719
  enabled: true,
1355
1720
  color: "blue",
1356
1721
  icon: "feature.sales",
1357
- uiPosition: "sidebar-primary"
1722
+ path: "/sales"
1358
1723
  },
1359
1724
  {
1360
1725
  id: "sales.crm",
@@ -1381,8 +1746,16 @@ var DEFAULT_ORGANIZATION_MODEL = {
1381
1746
  enabled: true,
1382
1747
  color: "orange",
1383
1748
  icon: "feature.projects",
1384
- path: "/projects",
1385
- uiPosition: "sidebar-primary"
1749
+ path: "/projects"
1750
+ },
1751
+ {
1752
+ id: "clients",
1753
+ label: "Clients",
1754
+ description: "Client relationships, accounts, and business context",
1755
+ enabled: true,
1756
+ color: "orange",
1757
+ icon: "feature.projects",
1758
+ path: "/business/clients"
1386
1759
  },
1387
1760
  {
1388
1761
  id: "operations",
@@ -1627,6 +2000,8 @@ var DEFAULT_ORGANIZATION_MODEL = {
1627
2000
  offerings: DEFAULT_ORGANIZATION_MODEL_OFFERINGS,
1628
2001
  roles: DEFAULT_ORGANIZATION_MODEL_ROLES,
1629
2002
  goals: DEFAULT_ORGANIZATION_MODEL_GOALS,
2003
+ systems: DEFAULT_ORGANIZATION_MODEL_SYSTEMS,
2004
+ resources: DEFAULT_ORGANIZATION_MODEL_RESOURCES,
1630
2005
  statuses: DEFAULT_ORGANIZATION_MODEL_STATUSES,
1631
2006
  operations: DEFAULT_ORGANIZATION_MODEL_OPERATIONS,
1632
2007
  knowledge: DEFAULT_ORGANIZATION_MODEL_KNOWLEDGE
@@ -1713,4 +2088,4 @@ function createFoundationOrganizationModel(override) {
1713
2088
  };
1714
2089
  }
1715
2090
 
1716
- export { CustomerSegmentSchema, CustomersDomainSchema, DEFAULT_ORGANIZATION_MODEL, DEFAULT_ORGANIZATION_MODEL_CUSTOMERS, DEFAULT_ORGANIZATION_MODEL_GOALS, DEFAULT_ORGANIZATION_MODEL_OFFERINGS, DEFAULT_ORGANIZATION_MODEL_OPERATIONS, DEFAULT_ORGANIZATION_MODEL_ROLES, DEFAULT_ORGANIZATION_MODEL_STATUSES, FeatureSchema, FirmographicsSchema, GoalsDomainSchema, IconNameSchema, KNOWLEDGE_FEATURE_ID, KeyResultSchema, KnowledgeDomainSchema, KnowledgeLinkSchema, LinkSchema, MONITORING_FEATURE_ID, NodeIdPathSchema, NodeIdStringSchema, OPERATIONS_COMMAND_VIEW_SURFACE_ID, OPERATIONS_FEATURE_ID, ORGANIZATION_MODEL_ICON_TOKENS, ObjectiveSchema, OfferingsDomainSchema, OperationEntrySchema, OperationSemanticClassSchema, OperationsDomainSchema, OrgKnowledgeKindSchema, OrgKnowledgeNodeSchema, OrganizationModelBuiltinIconTokenSchema, OrganizationModelIconTokenSchema, OrganizationModelSchema, PROJECTS_FEATURE_ID, PROJECTS_INDEX_SURFACE_ID, PROJECTS_VIEW_CAPABILITY_ID, PROSPECTING_FEATURE_ID, PROSPECTING_LISTS_SURFACE_ID, PricingModelSchema, ProductSchema, RoleSchema, RolesDomainSchema, SALES_FEATURE_ID, SALES_PIPELINE_SURFACE_ID, SEO_FEATURE_ID, SETTINGS_FEATURE_ID, SETTINGS_ROLES_SURFACE_ID, StatusEntrySchema, StatusSemanticClassSchema, StatusesDomainSchema, TechStackEntrySchema, UiPositionSchema, createFoundationOrganizationModel, defineOrganizationModel, resolveOrganizationModel };
2091
+ export { AgentKindSchema, AgentResourceEntrySchema, AgentRoleHolderSchema, CustomerSegmentSchema, CustomersDomainSchema, DEFAULT_ORGANIZATION_MODEL, DEFAULT_ORGANIZATION_MODEL_CUSTOMERS, DEFAULT_ORGANIZATION_MODEL_GOALS, DEFAULT_ORGANIZATION_MODEL_OFFERINGS, DEFAULT_ORGANIZATION_MODEL_OPERATIONS, DEFAULT_ORGANIZATION_MODEL_RESOURCES, DEFAULT_ORGANIZATION_MODEL_ROLES, DEFAULT_ORGANIZATION_MODEL_STATUSES, DEFAULT_ORGANIZATION_MODEL_SYSTEMS, FeatureSchema, FirmographicsSchema, GoalsDomainSchema, HumanRoleHolderSchema, IconNameSchema, IntegrationResourceEntrySchema, KNOWLEDGE_FEATURE_ID, KeyResultSchema, KnowledgeDomainSchema, KnowledgeLinkSchema, LinkSchema, MONITORING_FEATURE_ID, NodeIdPathSchema, NodeIdStringSchema, OPERATIONS_COMMAND_VIEW_SURFACE_ID, OPERATIONS_FEATURE_ID, ORGANIZATION_MODEL_ICON_TOKENS, ObjectiveSchema, OfferingsDomainSchema, OperationEntrySchema, OperationSemanticClassSchema, OperationsDomainSchema, OrgKnowledgeKindSchema, OrgKnowledgeNodeSchema, OrganizationModelBuiltinIconTokenSchema, OrganizationModelIconTokenSchema, OrganizationModelSchema, PROJECTS_FEATURE_ID, PROJECTS_INDEX_SURFACE_ID, PROJECTS_VIEW_CAPABILITY_ID, PROSPECTING_FEATURE_ID, PROSPECTING_LISTS_SURFACE_ID, PricingModelSchema, ProductSchema, ResourceEntrySchema, ResourceGovernanceStatusSchema, ResourceIdSchema, ResourceKindSchema, ResourcesDomainSchema, RoleHolderSchema, RoleHoldersSchema, RoleIdSchema, RoleSchema, RolesDomainSchema, SALES_FEATURE_ID, SALES_PIPELINE_SURFACE_ID, SEO_FEATURE_ID, SETTINGS_FEATURE_ID, SETTINGS_ROLES_SURFACE_ID, StatusEntrySchema, StatusSemanticClassSchema, StatusesDomainSchema, SystemEntrySchema, SystemIdSchema, SystemKindSchema, SystemStatusSchema, SystemsDomainSchema, TeamRoleHolderSchema, TechStackEntrySchema, UiPositionSchema, WorkflowResourceEntrySchema, createFoundationOrganizationModel, defineOrganizationModel, defineResource, defineResources, resolveOrganizationModel };