@elevasis/core 0.21.0 → 0.23.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 (132) hide show
  1. package/dist/index.d.ts +2518 -2169
  2. package/dist/index.js +2495 -1095
  3. package/dist/knowledge/index.d.ts +706 -1044
  4. package/dist/knowledge/index.js +9 -9
  5. package/dist/organization-model/index.d.ts +2518 -2169
  6. package/dist/organization-model/index.js +2495 -1095
  7. package/dist/test-utils/index.d.ts +826 -1014
  8. package/dist/test-utils/index.js +1894 -1032
  9. package/package.json +3 -3
  10. package/src/__tests__/template-core-compatibility.test.ts +11 -79
  11. package/src/_gen/__tests__/__snapshots__/contracts.md.snap +852 -397
  12. package/src/auth/multi-tenancy/permissions.ts +20 -8
  13. package/src/business/README.md +2 -2
  14. package/src/business/acquisition/api-schemas.test.ts +175 -2
  15. package/src/business/acquisition/api-schemas.ts +132 -16
  16. package/src/business/acquisition/build-templates.test.ts +4 -4
  17. package/src/business/acquisition/build-templates.ts +72 -30
  18. package/src/business/acquisition/crm-state-actions.test.ts +13 -11
  19. package/src/business/acquisition/index.ts +12 -0
  20. package/src/business/acquisition/types.ts +7 -3
  21. package/src/business/clients/api-schemas.test.ts +115 -0
  22. package/src/business/clients/api-schemas.ts +158 -0
  23. package/src/business/clients/index.ts +1 -0
  24. package/src/business/deals/api-schemas.ts +8 -0
  25. package/src/business/index.ts +5 -2
  26. package/src/business/projects/types.ts +19 -0
  27. package/src/execution/engine/__tests__/fixtures/test-agents.ts +10 -8
  28. package/src/execution/engine/agent/core/__tests__/agent.test.ts +16 -12
  29. package/src/execution/engine/agent/core/__tests__/error-passthrough.test.ts +4 -3
  30. package/src/execution/engine/agent/core/types.ts +25 -15
  31. package/src/execution/engine/agent/index.ts +6 -4
  32. package/src/execution/engine/agent/reasoning/__tests__/request-builder.test.ts +24 -18
  33. package/src/execution/engine/index.ts +3 -0
  34. package/src/execution/engine/workflow/types.ts +9 -2
  35. package/src/knowledge/README.md +8 -7
  36. package/src/knowledge/__tests__/queries.test.ts +74 -73
  37. package/src/knowledge/format.ts +10 -9
  38. package/src/knowledge/index.ts +1 -1
  39. package/src/knowledge/published.ts +1 -1
  40. package/src/knowledge/queries.ts +26 -25
  41. package/src/organization-model/README.md +73 -26
  42. package/src/organization-model/__tests__/content-kinds-registry.test.ts +210 -0
  43. package/src/organization-model/__tests__/defaults.test.ts +76 -96
  44. package/src/organization-model/__tests__/domains/actions.test.ts +56 -0
  45. package/src/organization-model/__tests__/domains/customers.test.ts +299 -295
  46. package/src/organization-model/__tests__/domains/entities.test.ts +56 -0
  47. package/src/organization-model/__tests__/domains/goals.test.ts +493 -479
  48. package/src/organization-model/__tests__/domains/identity.test.ts +280 -279
  49. package/src/organization-model/__tests__/domains/navigation.test.ts +268 -212
  50. package/src/organization-model/__tests__/domains/offerings.test.ts +414 -419
  51. package/src/organization-model/__tests__/domains/policies.test.ts +323 -0
  52. package/src/organization-model/__tests__/domains/resource-mappings.test.ts +271 -271
  53. package/src/organization-model/__tests__/domains/resources.test.ts +310 -0
  54. package/src/organization-model/__tests__/domains/roles.test.ts +463 -347
  55. package/src/organization-model/__tests__/domains/statuses.test.ts +246 -243
  56. package/src/organization-model/__tests__/domains/systems.test.ts +209 -0
  57. package/src/organization-model/__tests__/flatten-additive-merge.test.ts +361 -0
  58. package/src/organization-model/__tests__/foundation.test.ts +74 -102
  59. package/src/organization-model/__tests__/get-resources-for-system.test.ts +144 -0
  60. package/src/organization-model/__tests__/graph.test.ts +899 -71
  61. package/src/organization-model/__tests__/knowledge.test.ts +209 -49
  62. package/src/organization-model/__tests__/lookup-helpers.test.ts +438 -0
  63. package/src/organization-model/__tests__/migration-helpers.test.ts +591 -0
  64. package/src/organization-model/__tests__/prospecting-ssot.test.ts +36 -27
  65. package/src/organization-model/__tests__/recursive-system-schema.test.ts +520 -0
  66. package/src/organization-model/__tests__/resolve.test.ts +174 -23
  67. package/src/organization-model/__tests__/schema.test.ts +291 -114
  68. package/src/organization-model/__tests__/surface-projection.test.ts +207 -97
  69. package/src/organization-model/catalogs/lead-gen.ts +144 -0
  70. package/src/organization-model/content-kinds/config.ts +36 -0
  71. package/src/organization-model/content-kinds/index.ts +74 -0
  72. package/src/organization-model/content-kinds/pipeline.ts +68 -0
  73. package/src/organization-model/content-kinds/registry.ts +44 -0
  74. package/src/organization-model/content-kinds/status.ts +71 -0
  75. package/src/organization-model/content-kinds/template.ts +83 -0
  76. package/src/organization-model/content-kinds/types.ts +117 -0
  77. package/src/organization-model/contracts.ts +13 -3
  78. package/src/organization-model/defaults.ts +499 -86
  79. package/src/organization-model/domains/actions.ts +239 -0
  80. package/src/organization-model/domains/customers.ts +78 -75
  81. package/src/organization-model/domains/entities.ts +144 -0
  82. package/src/organization-model/domains/goals.ts +83 -80
  83. package/src/organization-model/domains/knowledge.ts +76 -17
  84. package/src/organization-model/domains/navigation.ts +107 -384
  85. package/src/organization-model/domains/offerings.ts +71 -66
  86. package/src/organization-model/domains/policies.ts +102 -0
  87. package/src/organization-model/domains/projects.ts +14 -48
  88. package/src/organization-model/domains/prospecting.ts +62 -181
  89. package/src/organization-model/domains/resources.ts +145 -0
  90. package/src/organization-model/domains/roles.ts +96 -55
  91. package/src/organization-model/domains/sales.ts +10 -219
  92. package/src/organization-model/domains/shared.ts +57 -57
  93. package/src/organization-model/domains/statuses.ts +339 -130
  94. package/src/organization-model/domains/systems.ts +203 -0
  95. package/src/organization-model/foundation.ts +54 -67
  96. package/src/organization-model/graph/build.ts +682 -54
  97. package/src/organization-model/graph/link.ts +1 -1
  98. package/src/organization-model/graph/schema.ts +24 -9
  99. package/src/organization-model/graph/types.ts +20 -7
  100. package/src/organization-model/helpers.ts +231 -26
  101. package/src/organization-model/icons.ts +1 -0
  102. package/src/organization-model/index.ts +118 -5
  103. package/src/organization-model/migration-helpers.ts +249 -0
  104. package/src/organization-model/organization-graph.mdx +16 -15
  105. package/src/organization-model/organization-model.mdx +111 -44
  106. package/src/organization-model/published.ts +172 -19
  107. package/src/organization-model/resolve.ts +117 -54
  108. package/src/organization-model/schema.ts +654 -112
  109. package/src/organization-model/surface-projection.ts +116 -122
  110. package/src/organization-model/types.ts +146 -20
  111. package/src/platform/api/types.ts +38 -35
  112. package/src/platform/constants/versions.ts +1 -1
  113. package/src/platform/registry/__tests__/command-view.test.ts +6 -8
  114. package/src/platform/registry/__tests__/resource-link.test.ts +13 -8
  115. package/src/platform/registry/__tests__/resource-registry.integration.test.ts +16 -31
  116. package/src/platform/registry/__tests__/resource-registry.nested-systems.test.ts +245 -0
  117. package/src/platform/registry/__tests__/resource-registry.test.ts +2053 -2005
  118. package/src/platform/registry/__tests__/validation.test.ts +1347 -1086
  119. package/src/platform/registry/index.ts +14 -0
  120. package/src/platform/registry/resource-registry.ts +52 -2
  121. package/src/platform/registry/serialization.ts +241 -202
  122. package/src/platform/registry/serialized-types.ts +1 -0
  123. package/src/platform/registry/types.ts +411 -361
  124. package/src/platform/registry/validation.ts +745 -513
  125. package/src/projects/api-schemas.ts +290 -267
  126. package/src/reference/_generated/contracts.md +853 -397
  127. package/src/reference/glossary.md +23 -18
  128. package/src/supabase/database.types.ts +181 -0
  129. package/src/test-utils/test-utils.test.ts +1 -6
  130. package/src/organization-model/__tests__/domains/operations.test.ts +0 -203
  131. package/src/organization-model/domains/features.ts +0 -31
  132. package/src/organization-model/domains/operations.ts +0 -85
@@ -19416,6 +19416,190 @@ function makeTask(overrides = {}) {
19416
19416
  ...overrides
19417
19417
  });
19418
19418
  }
19419
+
19420
+ // src/organization-model/content-kinds/registry.ts
19421
+ function defineContentType(def) {
19422
+ return def;
19423
+ }
19424
+ var ContentNodeBaseSchema = z.object({
19425
+ /** Human-readable label for the content node. */
19426
+ label: z.string().trim().min(1).max(120).meta({ label: "Label" }),
19427
+ /** Optional one-paragraph description. */
19428
+ description: z.string().trim().min(1).max(2e3).optional().meta({ label: "Description" }),
19429
+ /** Optional display order within the system content map. */
19430
+ order: z.number().int().optional().meta({ label: "Order" }),
19431
+ /**
19432
+ * Local NodeId of the parent content node within the SAME system.
19433
+ * Per B4/L9: MUST resolve to a sibling in the same `system.content` map.
19434
+ * Per L19: parent and child MUST share the same `kind` (meta-category).
19435
+ */
19436
+ parentContentId: z.string().trim().min(1).max(200).optional().meta({ label: "Parent content id" })
19437
+ });
19438
+ var ContentNodeSchema = ContentNodeBaseSchema.extend({
19439
+ /** Meta-category (e.g. 'schema', 'config', 'knowledge', tenant-defined). */
19440
+ kind: z.string().trim().min(1).max(100).meta({ label: "Kind" }),
19441
+ /** Specific family within the meta-category (e.g. 'pipeline', 'kv'). */
19442
+ type: z.string().trim().min(1).max(100).meta({ label: "Type" }),
19443
+ /** Payload data; validated against registered payloadSchema when (kind, type) is known. */
19444
+ data: z.record(z.string(), z.unknown()).optional().meta({ label: "Data" })
19445
+ });
19446
+ z.object({
19447
+ /** Meta-category (tenant-defined or registry-shipped). */
19448
+ kind: z.string().trim().min(1).max(100).meta({ label: "Kind" }),
19449
+ /** Specific family within the meta-category. */
19450
+ type: z.string().trim().min(1).max(100).meta({ label: "Type" }),
19451
+ /** Human-readable label shown in the KB tree and describe views. */
19452
+ label: z.string().trim().min(1).max(120).meta({ label: "Label" }),
19453
+ /** Optional description. */
19454
+ description: z.string().trim().min(1).max(2e3).optional().meta({ label: "Description" }),
19455
+ /**
19456
+ * Which KB tree group this extension renders in.
19457
+ * Per L6: 'business-model' places it alongside Customers / Offerings / Goals.
19458
+ */
19459
+ treeGroup: z.union([z.enum(["profile", "business-model", "systems", "graph", "governance-wiring"]), z.string().min(1).max(100)]).meta({ label: "Tree group" }),
19460
+ /** Untyped payload; shape governed by the registered payloadSchema when available. */
19461
+ data: z.record(z.string(), z.unknown()).optional().meta({ label: "Data" })
19462
+ });
19463
+ var PipelinePayloadSchema = z.object({
19464
+ /**
19465
+ * Local NodeId of the entity this pipeline applies to (e.g. 'crm.deal').
19466
+ * `.meta({ ref: 'entity' })` enables SchemaDrivenFieldList to render a
19467
+ * clickable graph link to the referenced entity node.
19468
+ */
19469
+ entityId: z.string().trim().min(1).max(200).meta({ label: "Entity", ref: "entity", hint: "The entity type this pipeline tracks" }),
19470
+ /**
19471
+ * Optional Kanban column color token for UI rendering.
19472
+ */
19473
+ kanbanColor: z.string().trim().min(1).max(40).optional().meta({ label: "Kanban color", hint: "UI color token" })
19474
+ });
19475
+ var pipelineKind = defineContentType({
19476
+ kind: "schema",
19477
+ type: "pipeline",
19478
+ label: "Pipeline",
19479
+ description: "A named progression pipeline that applies to a specific entity type.",
19480
+ payloadSchema: PipelinePayloadSchema,
19481
+ parentTypes: []
19482
+ });
19483
+ var StagePayloadSchema = z.object({
19484
+ /**
19485
+ * Semantic classification for this stage.
19486
+ * Drives color, icon, and CRM-priority logic in consuming views.
19487
+ * Optional — prospecting stages use data.entityKind instead.
19488
+ * Enum aligned with SalesStageSemanticClassSchema (sales.ts).
19489
+ */
19490
+ semanticClass: z.enum(["open", "active", "nurturing", "closed_won", "closed_lost", "won", "lost", "closed"]).optional().meta({ label: "Semantic class", hint: "Semantic meaning of this stage", color: "blue" })
19491
+ });
19492
+ var stageKind = defineContentType({
19493
+ kind: "schema",
19494
+ type: "stage",
19495
+ label: "Stage",
19496
+ description: "A stage within a pipeline. Must be parented under a schema:pipeline content node.",
19497
+ payloadSchema: StagePayloadSchema,
19498
+ parentTypes: ["schema:pipeline"]
19499
+ });
19500
+ var TemplatePayloadSchema = z.object({
19501
+ /**
19502
+ * Optional description surfaced in the KB describe view and tooling.
19503
+ */
19504
+ description: z.string().trim().min(1).max(2e3).optional().meta({ label: "Description", hint: "What this template is used for" })
19505
+ });
19506
+ var templateKind = defineContentType({
19507
+ kind: "schema",
19508
+ type: "template",
19509
+ label: "Template",
19510
+ description: "A named build template (e.g. a prospecting pipeline sequence).",
19511
+ payloadSchema: TemplatePayloadSchema,
19512
+ parentTypes: []
19513
+ });
19514
+ var TemplateStepPayloadSchema = z.object({
19515
+ /**
19516
+ * Which entity type this step primarily operates on.
19517
+ */
19518
+ primaryEntity: z.enum(["company", "contact"]).meta({ label: "Primary entity", hint: "Entity type this step processes", color: "blue" }),
19519
+ /**
19520
+ * Action key identifying the workflow action executed by this step.
19521
+ * `.meta({ ref: 'action' })` enables SchemaDrivenFieldList to render a
19522
+ * clickable graph link.
19523
+ */
19524
+ actionKey: z.string().trim().min(1).max(200).meta({ label: "Action", ref: "action", hint: "Workflow action executed by this step" }),
19525
+ /**
19526
+ * IDs of sibling step local NodeIds this step depends on.
19527
+ */
19528
+ dependsOn: z.array(z.string().trim().min(1).max(200)).optional().meta({ label: "Depends on", hint: "Local NodeIds of prerequisite steps" })
19529
+ });
19530
+ var templateStepKind = defineContentType({
19531
+ kind: "schema",
19532
+ type: "template-step",
19533
+ label: "Template Step",
19534
+ description: "A step within a build template. Must be parented under a schema:template content node.",
19535
+ payloadSchema: TemplateStepPayloadSchema,
19536
+ parentTypes: ["schema:template"]
19537
+ });
19538
+ var StatusFlowPayloadSchema = z.object({
19539
+ /**
19540
+ * Which entity scope this status flow governs.
19541
+ */
19542
+ appliesTo: z.enum(["project", "milestone", "task"]).meta({ label: "Applies to", hint: "Entity scope governed by this status flow", color: "blue" })
19543
+ });
19544
+ var statusFlowKind = defineContentType({
19545
+ kind: "schema",
19546
+ type: "status-flow",
19547
+ label: "Status Flow",
19548
+ description: "A named set of statuses governing a project, milestone, or task entity.",
19549
+ payloadSchema: StatusFlowPayloadSchema,
19550
+ parentTypes: []
19551
+ });
19552
+ var StatusPayloadSchema = z.object({
19553
+ /**
19554
+ * Semantic classification string for this status.
19555
+ * Free-form to allow tenant-defined classifications (e.g. 'active', 'blocked',
19556
+ * 'completed'). Used by UI to apply color and icon fallbacks.
19557
+ * Optional — status nodes may omit this when the label is self-descriptive.
19558
+ */
19559
+ semanticClass: z.string().trim().min(1).max(100).optional().meta({ label: "Semantic class", hint: "Semantic meaning of this status (e.g. active, blocked, completed)" }),
19560
+ /**
19561
+ * Optional UI color token override for this status.
19562
+ */
19563
+ color: z.string().trim().min(1).max(40).optional().meta({ label: "Color", hint: "UI color token" })
19564
+ });
19565
+ var statusKind = defineContentType({
19566
+ kind: "schema",
19567
+ type: "status",
19568
+ label: "Status",
19569
+ description: "A single status within a status flow. Must be parented under a schema:status-flow content node.",
19570
+ payloadSchema: StatusPayloadSchema,
19571
+ parentTypes: ["schema:status-flow"]
19572
+ });
19573
+ var ConfigKvPayloadSchema = z.object({
19574
+ /**
19575
+ * Flat key-value entries. Values are JSON primitives.
19576
+ * Keys are short identifiers (e.g. 'maxBatchSize', 'featureEnabled').
19577
+ */
19578
+ entries: z.record(z.string().trim().min(1).max(200), z.union([z.string(), z.number(), z.boolean(), z.null()])).meta({ label: "Entries", hint: "Key-value configuration entries (string, number, boolean, or null values)" })
19579
+ });
19580
+ var configKvKind = defineContentType({
19581
+ kind: "config",
19582
+ type: "kv",
19583
+ label: "Key-Value Config",
19584
+ description: "A flat key-value configuration store co-located with a system. Values are JSON primitives.",
19585
+ payloadSchema: ConfigKvPayloadSchema,
19586
+ parentTypes: []
19587
+ });
19588
+
19589
+ // src/organization-model/content-kinds/index.ts
19590
+ var CONTENT_KIND_REGISTRY = {
19591
+ "schema:pipeline": pipelineKind,
19592
+ "schema:stage": stageKind,
19593
+ "schema:template": templateKind,
19594
+ "schema:template-step": templateStepKind,
19595
+ "schema:status-flow": statusFlowKind,
19596
+ "schema:status": statusKind,
19597
+ "config:kv": configKvKind
19598
+ };
19599
+ function lookupContentType(kind, type3) {
19600
+ const key = `${kind}:${type3}`;
19601
+ return CONTENT_KIND_REGISTRY[key];
19602
+ }
19419
19603
  var ORGANIZATION_MODEL_ICON_TOKENS = [
19420
19604
  "nav.dashboard",
19421
19605
  "nav.calendar",
@@ -19434,6 +19618,7 @@ var ORGANIZATION_MODEL_ICON_TOKENS = [
19434
19618
  "knowledge.reference",
19435
19619
  "feature.dashboard",
19436
19620
  "feature.calendar",
19621
+ "feature.business",
19437
19622
  "feature.sales",
19438
19623
  "feature.crm",
19439
19624
  "feature.finance",
@@ -19526,10 +19711,10 @@ DisplayMetadataSchema.extend({
19526
19711
  id: ModelIdSchema,
19527
19712
  resourceId: z.string().trim().min(1).max(255),
19528
19713
  resourceType: z.enum(["workflow", "agent", "trigger", "integration", "external", "human_checkpoint"]),
19529
- featureIds: ReferenceIdsSchema,
19714
+ systemIds: ReferenceIdsSchema,
19530
19715
  entityIds: ReferenceIdsSchema,
19531
19716
  surfaceIds: ReferenceIdsSchema,
19532
- capabilityIds: ReferenceIdsSchema,
19717
+ actionIds: ReferenceIdsSchema,
19533
19718
  /** Optional tech-stack metadata for external-SaaS integrations. */
19534
19719
  techStack: TechStackEntrySchema.optional()
19535
19720
  });
@@ -19551,637 +19736,8 @@ var DEFAULT_ORGANIZATION_MODEL_BRANDING = {
19551
19736
  shortName: "Elevasis",
19552
19737
  logos: {}
19553
19738
  };
19554
- var SalesStageSemanticClassSchema = z.enum(["open", "active", "nurturing", "closed_won", "closed_lost"]);
19555
- var SalesStageSchema = DisplayMetadataSchema.extend({
19556
- id: ModelIdSchema,
19557
- order: z.number().int().min(0),
19558
- semanticClass: SalesStageSemanticClassSchema,
19559
- surfaceIds: ReferenceIdsSchema,
19560
- resourceIds: ReferenceIdsSchema
19561
- });
19562
- var SalesPipelineSchema = z.object({
19563
- id: ModelIdSchema,
19564
- label: z.string().trim().min(1).max(120),
19565
- description: DescriptionSchema.optional(),
19566
- entityId: ModelIdSchema,
19567
- stages: z.array(SalesStageSchema).min(1)
19568
- });
19569
- var OrganizationModelSalesSchema = z.object({
19570
- entityId: ModelIdSchema,
19571
- defaultPipelineId: ModelIdSchema,
19572
- pipelines: z.array(SalesPipelineSchema).min(1)
19573
- });
19574
- var DEFAULT_ORGANIZATION_MODEL_SALES = {
19575
- entityId: "crm.deal",
19576
- defaultPipelineId: "default",
19577
- pipelines: [
19578
- {
19579
- id: "default",
19580
- label: "Default Pipeline",
19581
- entityId: "crm.deal",
19582
- stages: [
19583
- {
19584
- id: "interested",
19585
- label: "Interested",
19586
- color: "blue",
19587
- order: 1,
19588
- semanticClass: "open",
19589
- surfaceIds: ["crm.pipeline"],
19590
- resourceIds: []
19591
- },
19592
- {
19593
- id: "proposal",
19594
- label: "Proposal",
19595
- color: "yellow",
19596
- order: 2,
19597
- semanticClass: "active",
19598
- surfaceIds: ["crm.pipeline"],
19599
- resourceIds: []
19600
- },
19601
- {
19602
- id: "closing",
19603
- label: "Closing",
19604
- color: "lime",
19605
- order: 3,
19606
- semanticClass: "active",
19607
- surfaceIds: ["crm.pipeline"],
19608
- resourceIds: []
19609
- },
19610
- {
19611
- id: "closed_won",
19612
- label: "Closed Won",
19613
- color: "green",
19614
- order: 4,
19615
- semanticClass: "closed_won",
19616
- surfaceIds: ["crm.pipeline"],
19617
- resourceIds: []
19618
- },
19619
- {
19620
- id: "closed_lost",
19621
- label: "Closed Lost",
19622
- color: "red",
19623
- order: 5,
19624
- semanticClass: "closed_lost",
19625
- surfaceIds: ["crm.pipeline"],
19626
- resourceIds: []
19627
- },
19628
- {
19629
- id: "nurturing",
19630
- label: "Nurturing",
19631
- color: "grape",
19632
- order: 6,
19633
- semanticClass: "nurturing",
19634
- surfaceIds: ["crm.pipeline"],
19635
- resourceIds: []
19636
- }
19637
- ]
19638
- }
19639
- ]
19640
- };
19641
- var LEAD_GEN_STAGE_CATALOG = {
19642
- // Prospecting — company population
19643
- scraped: {
19644
- key: "scraped",
19645
- label: "Scraped",
19646
- description: "Company was scraped from a source directory (Apify actor run).",
19647
- order: 1,
19648
- entity: "company"
19649
- },
19650
- populated: {
19651
- key: "populated",
19652
- label: "Companies found",
19653
- description: "Companies have been found and added to the lead-gen list.",
19654
- order: 2,
19655
- entity: "company"
19656
- },
19657
- crawled: {
19658
- key: "crawled",
19659
- label: "Websites crawled",
19660
- description: "Company websites have been crawled (e.g. via Apify) and raw page content stored for downstream LLM analysis.",
19661
- order: 2.5,
19662
- entity: "company"
19663
- },
19664
- extracted: {
19665
- key: "extracted",
19666
- label: "Websites analyzed",
19667
- description: "Company websites have been analyzed for business signals.",
19668
- order: 3,
19669
- entity: "company"
19670
- },
19671
- enriched: {
19672
- key: "enriched",
19673
- label: "Enriched",
19674
- description: "Company or contact enriched with third-party data (e.g. Tomba, Anymailfinder).",
19675
- order: 4,
19676
- entity: "company"
19677
- },
19678
- "decision-makers-enriched": {
19679
- key: "decision-makers-enriched",
19680
- label: "Decision-makers found",
19681
- description: "Decision-maker contacts discovered and attached to a qualified company.",
19682
- order: 6,
19683
- entity: "company",
19684
- recordEntity: "contact",
19685
- recordStageKey: "discovered"
19686
- },
19687
- // Prospecting — contact discovery
19688
- discovered: {
19689
- key: "discovered",
19690
- label: "Decision-makers found",
19691
- description: "Decision-maker contact details have been found.",
19692
- order: 5,
19693
- entity: "contact"
19694
- },
19695
- verified: {
19696
- key: "verified",
19697
- label: "Emails verified",
19698
- description: "Contact email addresses have been checked for deliverability.",
19699
- order: 7,
19700
- entity: "contact"
19701
- },
19702
- // Qualification
19703
- qualified: {
19704
- key: "qualified",
19705
- label: "Companies qualified",
19706
- description: "Companies have been scored against the qualification criteria.",
19707
- order: 8,
19708
- entity: "company"
19709
- },
19710
- // Outreach
19711
- personalized: {
19712
- key: "personalized",
19713
- label: "Personalized",
19714
- description: "Outreach message personalized for the contact (Instantly personalization workflow).",
19715
- order: 9,
19716
- entity: "contact"
19717
- },
19718
- uploaded: {
19719
- key: "uploaded",
19720
- label: "Reviewed and exported",
19721
- description: "Approved records have been reviewed and exported for handoff.",
19722
- order: 10,
19723
- entity: "company",
19724
- additionalEntities: ["contact"]
19725
- },
19726
- interested: {
19727
- key: "interested",
19728
- label: "Interested",
19729
- description: "Contact replied with a positive signal (Instantly reply-handler transition).",
19730
- order: 11,
19731
- entity: "contact"
19732
- }
19733
- };
19734
- var ProjectsDomainStateSchema = DisplayMetadataSchema.extend({
19735
- id: ModelIdSchema,
19736
- order: z.number().int().min(0)
19737
- });
19738
- var OrganizationModelProjectsSchema = z.object({
19739
- projectEntityId: ModelIdSchema,
19740
- milestoneEntityId: ModelIdSchema,
19741
- taskEntityId: ModelIdSchema,
19742
- projectStatuses: z.array(ProjectsDomainStateSchema).min(1),
19743
- milestoneStatuses: z.array(ProjectsDomainStateSchema).min(1),
19744
- taskStatuses: z.array(ProjectsDomainStateSchema).min(1)
19745
- });
19746
- var DEFAULT_ORGANIZATION_MODEL_PROJECTS = {
19747
- projectEntityId: "delivery.project",
19748
- milestoneEntityId: "delivery.milestone",
19749
- taskEntityId: "delivery.task",
19750
- projectStatuses: [
19751
- { id: "active", label: "Active", order: 1 },
19752
- { id: "on_track", label: "On Track", order: 2 },
19753
- { id: "at_risk", label: "At Risk", order: 3 },
19754
- { id: "blocked", label: "Blocked", order: 4 },
19755
- { id: "paused", label: "Paused", order: 5 },
19756
- { id: "completed", label: "Completed", order: 6 }
19757
- ],
19758
- milestoneStatuses: [
19759
- { id: "upcoming", label: "Upcoming", order: 1 },
19760
- { id: "in_progress", label: "In Progress", order: 2 },
19761
- { id: "blocked", label: "Blocked", order: 3 },
19762
- { id: "overdue", label: "Overdue", order: 4 },
19763
- { id: "completed", label: "Completed", order: 5 }
19764
- ],
19765
- taskStatuses: [
19766
- { id: "planned", label: "Planned", order: 1 },
19767
- { id: "in_progress", label: "In Progress", order: 2 },
19768
- { id: "blocked", label: "Blocked", order: 3 },
19769
- { id: "submitted", label: "Submitted", order: 4 },
19770
- { id: "approved", label: "Approved", order: 5 },
19771
- { id: "revision_requested", label: "Revision Requested", order: 6 },
19772
- { id: "rejected", label: "Rejected", order: 7 },
19773
- { id: "cancelled", label: "Cancelled", order: 8 },
19774
- { id: "completed", label: "Completed", order: 9 }
19775
- ]
19776
- };
19777
- var NodeIdPathSchema = z.string().trim().min(1).max(100).regex(/^([a-z0-9-]+)(\.[a-z0-9-]+)*$/, "Node IDs must be lowercase dotted paths");
19778
- var NodeIdStringSchema = z.string().trim().min(1).max(200).regex(/^[a-z]+:([a-z0-9-]+)(\.[a-z0-9-]+)*$/, "Node references must use kind:dotted-path");
19779
- var UiPositionSchema = z.enum(["sidebar-primary", "sidebar-bottom"]);
19780
- var FeatureSchema = z.object({
19781
- id: NodeIdPathSchema,
19782
- label: LabelSchema,
19783
- description: DescriptionSchema.optional(),
19784
- enabled: z.boolean().default(true),
19785
- path: PathSchema.optional(),
19786
- icon: IconNameSchema.optional(),
19787
- color: ColorTokenSchema.optional(),
19788
- uiPosition: UiPositionSchema.optional(),
19789
- requiresAdmin: z.boolean().optional(),
19790
- devOnly: z.boolean().optional()
19791
- });
19792
- var ProspectingLifecycleStageSchema = DisplayMetadataSchema.extend({
19793
- id: ModelIdSchema,
19794
- order: z.number().min(0)
19795
- });
19796
- var RecordColumnConfigSchema = z.object({
19797
- key: ModelIdSchema,
19798
- label: z.string().trim().min(1).max(120),
19799
- path: z.string().trim().min(1).max(500),
19800
- width: z.union([z.number().positive(), z.string().trim().min(1).max(100)]).optional(),
19801
- renderType: z.enum(["text", "badge", "datetime", "count", "json"]).optional(),
19802
- badgeColor: z.string().trim().min(1).max(40).optional()
19803
- });
19804
- var RecordColumnsConfigSchema = z.object({
19805
- company: z.array(RecordColumnConfigSchema).optional(),
19806
- contact: z.array(RecordColumnConfigSchema).optional()
19807
- }).refine((columns) => Boolean(columns.company?.length || columns.contact?.length), {
19808
- message: "recordColumns must include at least one entity column set"
19809
- });
19810
- var CredentialRequirementSchema = z.object({
19811
- key: ModelIdSchema,
19812
- provider: ModelIdSchema,
19813
- credentialType: z.enum(["api-key", "api-key-secret", "oauth", "webhook-secret"]),
19814
- label: z.string().trim().min(1).max(120),
19815
- required: z.boolean(),
19816
- selectionMode: z.enum(["single", "multiple"]).optional(),
19817
- inputPath: z.string().trim().min(1).max(500),
19818
- verifyOnRun: z.boolean().optional()
19819
- });
19820
- var ProspectingBuildTemplateStepSchema = DisplayMetadataSchema.extend({
19821
- id: ModelIdSchema,
19822
- primaryEntity: z.enum(["company", "contact"]),
19823
- outputs: z.array(z.enum(["company", "contact", "export"])).min(1),
19824
- stageKey: ModelIdSchema,
19825
- recordEntity: z.enum(["company", "contact"]).optional(),
19826
- recordsStageKey: ModelIdSchema.optional(),
19827
- recordSourceStageKey: ModelIdSchema.optional(),
19828
- dependsOn: z.array(ModelIdSchema).optional(),
19829
- dependencyMode: z.literal("per-record-eligibility"),
19830
- capabilityKey: ModelIdSchema,
19831
- defaultBatchSize: z.number().int().positive(),
19832
- maxBatchSize: z.number().int().positive(),
19833
- recordColumns: RecordColumnsConfigSchema.optional(),
19834
- credentialRequirements: z.array(CredentialRequirementSchema).optional()
19835
- }).refine((step) => step.defaultBatchSize <= step.maxBatchSize, {
19836
- message: "defaultBatchSize must be less than or equal to maxBatchSize",
19837
- path: ["defaultBatchSize"]
19838
- });
19839
- var ProspectingBuildTemplateSchema = DisplayMetadataSchema.extend({
19840
- id: ModelIdSchema,
19841
- steps: z.array(ProspectingBuildTemplateStepSchema).min(1)
19842
- });
19843
- var DTC_RECORD_COLUMNS = {
19844
- populated: {
19845
- company: [
19846
- { key: "name", label: "Company", path: "company.name" },
19847
- { key: "domain", label: "Domain", path: "company.domain" },
19848
- { key: "employee-count", label: "Employees", path: "company.numEmployees", renderType: "count" },
19849
- { key: "apollo-industry", label: "Apollo industry", path: "company.category" },
19850
- { key: "location", label: "Location", path: "company.locationState" }
19851
- ]
19852
- },
19853
- crawled: {
19854
- company: [
19855
- { key: "name", label: "Company", path: "company.name" },
19856
- { key: "domain", label: "Domain", path: "company.domain" },
19857
- { key: "page-count", label: "Pages", path: "company.enrichmentData.websiteCrawl.pageCount", renderType: "count" },
19858
- { key: "crawl-status", label: "Crawl status", path: "processingState.crawled.status", renderType: "badge" }
19859
- ]
19860
- },
19861
- extracted: {
19862
- company: [
19863
- { key: "name", label: "Company", path: "company.name" },
19864
- { key: "domain", label: "Domain", path: "company.domain" },
19865
- { key: "description", label: "Description", path: "company.enrichmentData.websiteCrawl.companyDescription" },
19866
- { key: "services", label: "Services", path: "company.enrichmentData.websiteCrawl.services", renderType: "json" },
19867
- { key: "automation-gaps", label: "Automation gaps", path: "company.enrichmentData.websiteCrawl.automationGaps", renderType: "json" },
19868
- { key: "contact-count", label: "Contacts", path: "company.enrichmentData.websiteCrawl.emailCount", renderType: "count" }
19869
- ]
19870
- },
19871
- qualified: {
19872
- company: [
19873
- { key: "name", label: "Company", path: "company.name" },
19874
- { key: "domain", label: "Domain", path: "company.domain" },
19875
- { key: "score", label: "Score", path: "company.qualificationScore", renderType: "badge", badgeColor: "green" },
19876
- { key: "signals", label: "Signals", path: "company.qualificationSignals", renderType: "json" },
19877
- { key: "disqualified-reason", label: "Disqualified reason", path: "processingState.qualified.data.disqualifiedReason" }
19878
- ]
19879
- },
19880
- decisionMakers: {
19881
- contact: [
19882
- { key: "name", label: "Name", path: "contact.name" },
19883
- { key: "title", label: "Title", path: "contact.title" },
19884
- { key: "email", label: "Email", path: "contact.email" },
19885
- { key: "linkedin", label: "LinkedIn", path: "contact.linkedinUrl" },
19886
- { key: "priority-score", label: "Priority", path: "contact.enrichmentData.apollo.priorityScore", renderType: "badge" }
19887
- ]
19888
- },
19889
- uploaded: {
19890
- company: [
19891
- { key: "name", label: "Company", path: "company.name" },
19892
- { key: "domain", label: "Domain", path: "company.domain" },
19893
- { key: "contacts", label: "Contacts", path: "company.enrichmentData.approvedLeadListExport.contacts", renderType: "json" },
19894
- { key: "score", label: "Score", path: "company.qualificationScore", renderType: "badge", badgeColor: "green" },
19895
- { key: "approval", label: "Approval", path: "company.enrichmentData.approvedLeadListExport.approvalStatus", renderType: "badge" }
19896
- ]
19897
- }
19898
- };
19739
+ var SurfaceTypeSchema = z.enum(["page", "dashboard", "graph", "detail", "list", "settings"]).meta({ label: "Surface type", color: "blue" });
19899
19740
  z.object({
19900
- id: ModelIdSchema,
19901
- label: z.string(),
19902
- description: z.string(),
19903
- resourceId: ModelIdSchema
19904
- });
19905
- var PROSPECTING_STEPS = {
19906
- localServices: {
19907
- sourceCompanies: {
19908
- id: "source-companies",
19909
- label: "Companies found",
19910
- primaryEntity: "company",
19911
- outputs: ["company"],
19912
- stageKey: "populated",
19913
- dependencyMode: "per-record-eligibility",
19914
- capabilityKey: "lead-gen.company.source",
19915
- defaultBatchSize: 100,
19916
- maxBatchSize: 250
19917
- },
19918
- analyzeWebsites: {
19919
- id: "analyze-websites",
19920
- label: "Websites analyzed",
19921
- primaryEntity: "company",
19922
- outputs: ["company"],
19923
- stageKey: "extracted",
19924
- dependsOn: ["source-companies"],
19925
- dependencyMode: "per-record-eligibility",
19926
- capabilityKey: "lead-gen.company.website-extract",
19927
- defaultBatchSize: 50,
19928
- maxBatchSize: 100
19929
- },
19930
- qualifyCompanies: {
19931
- id: "qualify-companies",
19932
- label: "Companies qualified",
19933
- primaryEntity: "company",
19934
- outputs: ["company"],
19935
- stageKey: "qualified",
19936
- dependsOn: ["analyze-websites"],
19937
- dependencyMode: "per-record-eligibility",
19938
- capabilityKey: "lead-gen.company.qualify",
19939
- defaultBatchSize: 100,
19940
- maxBatchSize: 250
19941
- },
19942
- findContacts: {
19943
- id: "find-contacts",
19944
- label: "Decision-makers found",
19945
- primaryEntity: "contact",
19946
- outputs: ["contact"],
19947
- stageKey: "discovered",
19948
- dependsOn: ["qualify-companies"],
19949
- dependencyMode: "per-record-eligibility",
19950
- capabilityKey: "lead-gen.contact.discover",
19951
- defaultBatchSize: 50,
19952
- maxBatchSize: 100
19953
- },
19954
- verifyEmails: {
19955
- id: "verify-emails",
19956
- label: "Emails verified",
19957
- primaryEntity: "contact",
19958
- outputs: ["contact"],
19959
- stageKey: "verified",
19960
- dependsOn: ["find-contacts"],
19961
- dependencyMode: "per-record-eligibility",
19962
- capabilityKey: "lead-gen.contact.verify-email",
19963
- defaultBatchSize: 100,
19964
- maxBatchSize: 500
19965
- },
19966
- personalize: {
19967
- id: "personalize",
19968
- label: "Personalize",
19969
- primaryEntity: "contact",
19970
- outputs: ["contact"],
19971
- stageKey: "personalized",
19972
- dependsOn: ["verify-emails"],
19973
- dependencyMode: "per-record-eligibility",
19974
- capabilityKey: "lead-gen.contact.personalize",
19975
- defaultBatchSize: 25,
19976
- maxBatchSize: 100
19977
- },
19978
- review: {
19979
- id: "review",
19980
- label: "Reviewed and exported",
19981
- primaryEntity: "contact",
19982
- outputs: ["export"],
19983
- stageKey: "uploaded",
19984
- dependsOn: ["personalize"],
19985
- dependencyMode: "per-record-eligibility",
19986
- capabilityKey: "lead-gen.review.outreach-ready",
19987
- defaultBatchSize: 25,
19988
- maxBatchSize: 100
19989
- }
19990
- },
19991
- dtcApolloClickup: {
19992
- importApolloSearch: {
19993
- id: "import-apollo-search",
19994
- label: "Companies found",
19995
- description: "Pull companies and seed contact data from a predefined Apollo search or list.",
19996
- primaryEntity: "company",
19997
- outputs: ["company", "contact"],
19998
- stageKey: "populated",
19999
- dependencyMode: "per-record-eligibility",
20000
- capabilityKey: "lead-gen.company.apollo-import",
20001
- defaultBatchSize: 250,
20002
- maxBatchSize: 1e3,
20003
- recordColumns: DTC_RECORD_COLUMNS.populated,
20004
- credentialRequirements: [
20005
- {
20006
- key: "apollo",
20007
- provider: "apollo",
20008
- credentialType: "api-key-secret",
20009
- label: "Apollo API key",
20010
- required: true,
20011
- selectionMode: "single",
20012
- inputPath: "credential"
20013
- }
20014
- ]
20015
- },
20016
- apifyCrawl: {
20017
- id: "apify-crawl",
20018
- label: "Websites crawled",
20019
- 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.",
20020
- primaryEntity: "company",
20021
- outputs: ["company"],
20022
- stageKey: "crawled",
20023
- dependsOn: ["import-apollo-search"],
20024
- dependencyMode: "per-record-eligibility",
20025
- capabilityKey: "lead-gen.company.apify-crawl",
20026
- defaultBatchSize: 50,
20027
- maxBatchSize: 100,
20028
- recordColumns: DTC_RECORD_COLUMNS.crawled,
20029
- credentialRequirements: [
20030
- {
20031
- key: "apify",
20032
- provider: "apify",
20033
- credentialType: "api-key-secret",
20034
- label: "Apify API token",
20035
- required: true,
20036
- selectionMode: "single",
20037
- inputPath: "credential",
20038
- verifyOnRun: true
20039
- }
20040
- ]
20041
- },
20042
- analyzeWebsites: {
20043
- id: "analyze-websites",
20044
- label: "Websites analyzed",
20045
- description: "Extract subscription, product, retention, and tech-stack signals from each brand website.",
20046
- primaryEntity: "company",
20047
- outputs: ["company"],
20048
- stageKey: "extracted",
20049
- dependsOn: ["apify-crawl"],
20050
- dependencyMode: "per-record-eligibility",
20051
- capabilityKey: "lead-gen.company.website-extract",
20052
- defaultBatchSize: 50,
20053
- maxBatchSize: 100,
20054
- recordColumns: DTC_RECORD_COLUMNS.extracted
20055
- },
20056
- scoreDtcFit: {
20057
- id: "score-dtc-fit",
20058
- label: "Companies qualified",
20059
- description: "Classify subscription potential, consumable-product fit, retention maturity, and disqualifiers.",
20060
- primaryEntity: "company",
20061
- outputs: ["company"],
20062
- stageKey: "qualified",
20063
- dependsOn: ["analyze-websites"],
20064
- dependencyMode: "per-record-eligibility",
20065
- capabilityKey: "lead-gen.company.dtc-subscription-qualify",
20066
- defaultBatchSize: 100,
20067
- maxBatchSize: 250,
20068
- recordColumns: DTC_RECORD_COLUMNS.qualified
20069
- },
20070
- enrichDecisionMakers: {
20071
- id: "enrich-decision-makers",
20072
- label: "Decision-makers found",
20073
- description: "Use Apollo to find qualified contacts at qualified companies - founders, retention leads, lifecycle leads, and marketing owners.",
20074
- primaryEntity: "company",
20075
- outputs: ["contact"],
20076
- stageKey: "decision-makers-enriched",
20077
- recordEntity: "contact",
20078
- dependsOn: ["score-dtc-fit"],
20079
- dependencyMode: "per-record-eligibility",
20080
- capabilityKey: "lead-gen.contact.apollo-decision-maker-enrich",
20081
- defaultBatchSize: 100,
20082
- maxBatchSize: 250,
20083
- recordColumns: DTC_RECORD_COLUMNS.decisionMakers,
20084
- credentialRequirements: [
20085
- {
20086
- key: "apollo",
20087
- provider: "apollo",
20088
- credentialType: "api-key-secret",
20089
- label: "Apollo API key",
20090
- required: true,
20091
- selectionMode: "single",
20092
- inputPath: "credential"
20093
- }
20094
- ]
20095
- },
20096
- reviewAndExport: {
20097
- id: "review-and-export",
20098
- label: "Reviewed and exported",
20099
- description: "Operator QC approves or rejects qualified companies, then approved records are exported as a lead list with unverified emails.",
20100
- primaryEntity: "company",
20101
- outputs: ["export"],
20102
- stageKey: "uploaded",
20103
- recordsStageKey: "uploaded",
20104
- recordSourceStageKey: "qualified",
20105
- dependsOn: ["enrich-decision-makers"],
20106
- dependencyMode: "per-record-eligibility",
20107
- capabilityKey: "lead-gen.export.list",
20108
- defaultBatchSize: 100,
20109
- maxBatchSize: 250,
20110
- recordColumns: DTC_RECORD_COLUMNS.uploaded,
20111
- credentialRequirements: [
20112
- {
20113
- key: "clickup",
20114
- provider: "clickup",
20115
- credentialType: "api-key-secret",
20116
- label: "ClickUp API token",
20117
- required: true,
20118
- selectionMode: "single",
20119
- inputPath: "clickupCredential",
20120
- verifyOnRun: true
20121
- }
20122
- ]
20123
- }
20124
- }
20125
- };
20126
- var OrganizationModelProspectingSchema = z.object({
20127
- listEntityId: ModelIdSchema,
20128
- companyEntityId: ModelIdSchema,
20129
- contactEntityId: ModelIdSchema,
20130
- description: DescriptionSchema.optional(),
20131
- companyStages: z.array(ProspectingLifecycleStageSchema).min(1),
20132
- contactStages: z.array(ProspectingLifecycleStageSchema).min(1),
20133
- defaultBuildTemplateId: ModelIdSchema,
20134
- buildTemplates: z.array(ProspectingBuildTemplateSchema).min(1)
20135
- });
20136
- function toProspectingLifecycleStage(stage) {
20137
- return {
20138
- id: stage.key,
20139
- label: stage.label,
20140
- order: stage.order
20141
- };
20142
- }
20143
- function leadGenStagesForEntity(entity) {
20144
- return Object.values(LEAD_GEN_STAGE_CATALOG).filter((stage) => stage.entity === entity || stage.additionalEntities?.includes(entity)).sort((a3, b2) => a3.order - b2.order).map(toProspectingLifecycleStage);
20145
- }
20146
- var DEFAULT_ORGANIZATION_MODEL_PROSPECTING = {
20147
- listEntityId: "leadgen.list",
20148
- companyEntityId: "leadgen.company",
20149
- contactEntityId: "leadgen.contact",
20150
- companyStages: leadGenStagesForEntity("company"),
20151
- contactStages: leadGenStagesForEntity("contact"),
20152
- defaultBuildTemplateId: "local-services",
20153
- buildTemplates: [
20154
- {
20155
- id: "local-services",
20156
- label: "Local Services Prospecting",
20157
- description: "Curated local-services list build using company sourcing, website analysis, qualification, contact discovery, verification, personalization, and review.",
20158
- steps: [
20159
- PROSPECTING_STEPS.localServices.sourceCompanies,
20160
- PROSPECTING_STEPS.localServices.analyzeWebsites,
20161
- PROSPECTING_STEPS.localServices.qualifyCompanies,
20162
- PROSPECTING_STEPS.localServices.findContacts,
20163
- PROSPECTING_STEPS.localServices.verifyEmails,
20164
- PROSPECTING_STEPS.localServices.personalize,
20165
- PROSPECTING_STEPS.localServices.review
20166
- ]
20167
- },
20168
- {
20169
- id: "dtc-subscription-apollo-clickup",
20170
- label: "DTC Subscription Apollo Export",
20171
- 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.",
20172
- steps: [
20173
- PROSPECTING_STEPS.dtcApolloClickup.importApolloSearch,
20174
- PROSPECTING_STEPS.dtcApolloClickup.apifyCrawl,
20175
- PROSPECTING_STEPS.dtcApolloClickup.analyzeWebsites,
20176
- PROSPECTING_STEPS.dtcApolloClickup.scoreDtcFit,
20177
- PROSPECTING_STEPS.dtcApolloClickup.enrichDecisionMakers,
20178
- PROSPECTING_STEPS.dtcApolloClickup.reviewAndExport
20179
- ]
20180
- }
20181
- ]
20182
- };
20183
- var SurfaceTypeSchema = z.enum(["page", "dashboard", "graph", "detail", "list", "settings"]);
20184
- var SurfaceDefinitionSchema = z.object({
20185
19741
  id: ModelIdSchema,
20186
19742
  label: LabelSchema,
20187
19743
  path: PathSchema,
@@ -20190,23 +19746,55 @@ var SurfaceDefinitionSchema = z.object({
20190
19746
  enabled: z.boolean().default(true),
20191
19747
  devOnly: z.boolean().optional(),
20192
19748
  icon: IconNameSchema.optional(),
20193
- featureId: ModelIdSchema.optional(),
20194
- featureIds: ReferenceIdsSchema,
20195
- entityIds: ReferenceIdsSchema,
20196
- resourceIds: ReferenceIdsSchema,
20197
- capabilityIds: ReferenceIdsSchema,
20198
- parentId: ModelIdSchema.optional()
19749
+ systemIds: z.array(ModelIdSchema.meta({ ref: "system" })).default([]),
19750
+ entityIds: z.array(ModelIdSchema.meta({ ref: "entity" })).default([]),
19751
+ resourceIds: z.array(ModelIdSchema.meta({ ref: "resource" })).default([]),
19752
+ actionIds: z.array(ModelIdSchema.meta({ ref: "action" })).default([]),
19753
+ parentId: ModelIdSchema.meta({ ref: "surface" }).optional()
20199
19754
  });
20200
- var NavigationGroupSchema = z.object({
19755
+ var SidebarSurfaceTargetsSchema = z.object({
19756
+ systems: z.array(ModelIdSchema.meta({ ref: "system" })).default([]).optional(),
19757
+ entities: z.array(ModelIdSchema.meta({ ref: "entity" })).default([]).optional(),
19758
+ resources: z.array(ModelIdSchema.meta({ ref: "resource" })).default([]).optional(),
19759
+ actions: z.array(ModelIdSchema.meta({ ref: "action" })).default([]).optional()
19760
+ }).default({});
19761
+ var SidebarNodeSchema = z.lazy(
19762
+ () => z.discriminatedUnion("type", [
19763
+ z.object({
19764
+ type: z.literal("group"),
19765
+ label: LabelSchema,
19766
+ description: DescriptionSchema.optional(),
19767
+ icon: IconNameSchema.optional(),
19768
+ order: z.number().int().optional(),
19769
+ children: z.record(z.string(), SidebarNodeSchema).default({})
19770
+ }),
19771
+ z.object({
19772
+ type: z.literal("surface"),
19773
+ label: LabelSchema,
19774
+ path: PathSchema,
19775
+ surfaceType: SurfaceTypeSchema,
19776
+ description: DescriptionSchema.optional(),
19777
+ icon: IconNameSchema.optional(),
19778
+ order: z.number().int().optional(),
19779
+ targets: SidebarSurfaceTargetsSchema.optional(),
19780
+ devOnly: z.boolean().optional(),
19781
+ requiresAdmin: z.boolean().optional()
19782
+ })
19783
+ ])
19784
+ );
19785
+ var SidebarSectionSchema = z.record(z.string(), SidebarNodeSchema).default({});
19786
+ var SidebarNavigationSchema = z.object({
19787
+ primary: SidebarSectionSchema,
19788
+ bottom: SidebarSectionSchema
19789
+ }).default({ primary: {}, bottom: {} });
19790
+ var OrganizationModelNavigationSchema = z.object({
19791
+ sidebar: SidebarNavigationSchema
19792
+ }).default({ sidebar: { primary: {}, bottom: {} } });
19793
+ z.object({
20201
19794
  id: ModelIdSchema,
20202
19795
  label: LabelSchema,
20203
19796
  placement: z.string().trim().min(1).max(50),
20204
- surfaceIds: z.array(ModelIdSchema).default([])
20205
- });
20206
- var OrganizationModelNavigationSchema = z.object({
20207
- defaultSurfaceId: ModelIdSchema.optional(),
20208
- surfaces: z.array(SurfaceDefinitionSchema).default([]),
20209
- groups: z.array(NavigationGroupSchema).default([])
19797
+ surfaceIds: z.array(ModelIdSchema.meta({ ref: "surface" })).default([])
20210
19798
  });
20211
19799
  var BusinessHoursDaySchema = z.object({
20212
19800
  open: z.string().trim().regex(/^\d{2}:\d{2}$/, "Expected HH:MM format"),
@@ -20291,6 +19879,8 @@ var FirmographicsSchema = z.object({
20291
19879
  var CustomerSegmentSchema = z.object({
20292
19880
  /** Stable unique identifier for the segment (e.g. "segment-smb-agencies"). */
20293
19881
  id: z.string().trim().min(1).max(100),
19882
+ /** Domain-map iteration order. Convention: multiples of 10 (10, 20, 30, ...) to allow easy insertion. */
19883
+ order: z.number(),
20294
19884
  /** Human-readable name shown to agents and in UI (e.g. "SMB Marketing Agencies"). */
20295
19885
  name: z.string().trim().max(200).default(""),
20296
19886
  /** One or two sentences describing who this segment is. */
@@ -20318,16 +19908,16 @@ var CustomerSegmentSchema = z.object({
20318
19908
  */
20319
19909
  valueProp: z.string().trim().max(2e3).default("")
20320
19910
  });
20321
- var CustomersDomainSchema = z.object({
20322
- segments: z.array(CustomerSegmentSchema).default([])
20323
- });
20324
- var DEFAULT_ORGANIZATION_MODEL_CUSTOMERS = {
20325
- segments: []
20326
- };
20327
- var PricingModelSchema = z.enum(["one-time", "subscription", "usage-based", "custom"]);
19911
+ var CustomersDomainSchema = z.record(z.string(), CustomerSegmentSchema).refine((record) => Object.entries(record).every(([key, entry]) => entry.id === key), {
19912
+ message: "Each segment entry id must match its map key"
19913
+ }).default({});
19914
+ var DEFAULT_ORGANIZATION_MODEL_CUSTOMERS = {};
19915
+ var PricingModelSchema = z.enum(["one-time", "subscription", "usage-based", "custom"]).meta({ label: "Pricing model", color: "green" });
20328
19916
  var ProductSchema = z.object({
20329
19917
  /** Stable unique identifier for the product (e.g. "product-starter-plan"). */
20330
19918
  id: z.string().trim().min(1).max(100),
19919
+ /** Domain-map iteration order. Convention: multiples of 10 (10, 20, 30, ...) to allow easy insertion. */
19920
+ order: z.number(),
20331
19921
  /** Human-readable name shown to agents and in UI (e.g. "Starter Plan"). */
20332
19922
  name: z.string().trim().max(200).default(""),
20333
19923
  /** One or two sentences describing what this product/service delivers. */
@@ -20354,25 +19944,526 @@ var ProductSchema = z.object({
20354
19944
  */
20355
19945
  targetSegmentIds: z.array(z.string().trim().min(1)).default([]),
20356
19946
  /**
20357
- * Optional: ID of the platform feature responsible for delivering this product.
20358
- * When present, must reference a declared `features[].id`.
19947
+ * Optional: ID of the platform system responsible for delivering this product.
19948
+ * When present, must reference a declared `systems.systems[].id`.
20359
19949
  * Cross-reference enforced in `OrganizationModelSchema.superRefine()`.
20360
19950
  */
20361
19951
  deliveryFeatureId: z.string().trim().min(1).optional()
20362
19952
  });
20363
- var OfferingsDomainSchema = z.object({
20364
- products: z.array(ProductSchema).default([])
19953
+ var OfferingsDomainSchema = z.record(z.string(), ProductSchema).refine((record) => Object.entries(record).every(([key, entry]) => entry.id === key), {
19954
+ message: "Each product entry id must match its map key"
19955
+ }).default({});
19956
+ var DEFAULT_ORGANIZATION_MODEL_OFFERINGS = {};
19957
+ var EntityIdSchema = ModelIdSchema;
19958
+ var EntityLinkKindSchema = z.enum(["belongs-to", "has-many", "has-one", "many-to-many"]).meta({ label: "Link kind" });
19959
+ var EntityLinkSchema = z.object({
19960
+ toEntity: EntityIdSchema.meta({ ref: "entity" }),
19961
+ kind: EntityLinkKindSchema,
19962
+ via: z.string().trim().min(1).max(255).optional(),
19963
+ label: LabelSchema.optional()
20365
19964
  });
20366
- var DEFAULT_ORGANIZATION_MODEL_OFFERINGS = {
20367
- products: []
20368
- };
19965
+ var EntitySchema = z.object({
19966
+ id: EntityIdSchema,
19967
+ /** Domain-map iteration order. Convention: multiples of 10 (10, 20, 30, ...) to allow easy insertion. */
19968
+ order: z.number(),
19969
+ label: LabelSchema,
19970
+ description: DescriptionSchema.optional(),
19971
+ ownedBySystemId: ModelIdSchema.meta({ ref: "system" }),
19972
+ table: z.string().trim().min(1).max(255).optional(),
19973
+ rowSchema: ModelIdSchema.optional(),
19974
+ stateCatalogId: ModelIdSchema.optional(),
19975
+ links: z.array(EntityLinkSchema).optional()
19976
+ });
19977
+ var EntitiesDomainSchema = z.record(z.string(), EntitySchema).refine((record) => Object.entries(record).every(([key, entry]) => entry.id === key), {
19978
+ message: "Each entity entry id must match its map key"
19979
+ }).default({});
19980
+ var ENTITY_ENTRY_INPUTS = [
19981
+ {
19982
+ id: "crm.deal",
19983
+ order: 10,
19984
+ label: "Deal",
19985
+ description: "A CRM opportunity or sales pipeline record.",
19986
+ ownedBySystemId: "sales.crm",
19987
+ table: "crm_deals",
19988
+ stateCatalogId: "crm.pipeline",
19989
+ links: [{ toEntity: "crm.contact", kind: "has-many", via: "deal_contacts", label: "contacts" }]
19990
+ },
19991
+ {
19992
+ id: "crm.contact",
19993
+ order: 20,
19994
+ label: "CRM Contact",
19995
+ description: "A person associated with a CRM relationship or deal.",
19996
+ ownedBySystemId: "sales.crm",
19997
+ table: "crm_contacts"
19998
+ },
19999
+ {
20000
+ id: "leadgen.list",
20001
+ order: 30,
20002
+ label: "Lead List",
20003
+ description: "A prospecting list that groups companies and contacts for acquisition workflows.",
20004
+ ownedBySystemId: "sales.lead-gen",
20005
+ table: "acq_lists",
20006
+ links: [
20007
+ { toEntity: "leadgen.company", kind: "has-many", via: "acq_list_companies", label: "companies" },
20008
+ { toEntity: "leadgen.contact", kind: "has-many", via: "acq_list_members", label: "contacts" }
20009
+ ]
20010
+ },
20011
+ {
20012
+ id: "leadgen.company",
20013
+ order: 40,
20014
+ label: "Lead Company",
20015
+ description: "A company record sourced, enriched, and qualified during prospecting.",
20016
+ ownedBySystemId: "sales.lead-gen",
20017
+ table: "acq_list_companies",
20018
+ stateCatalogId: "lead-gen.company",
20019
+ links: [
20020
+ { toEntity: "leadgen.list", kind: "belongs-to", via: "list_id", label: "list" },
20021
+ { toEntity: "leadgen.contact", kind: "has-many", via: "company_id", label: "contacts" }
20022
+ ]
20023
+ },
20024
+ {
20025
+ id: "leadgen.contact",
20026
+ order: 50,
20027
+ label: "Lead Contact",
20028
+ description: "A prospect contact discovered or enriched during lead generation.",
20029
+ ownedBySystemId: "sales.lead-gen",
20030
+ table: "acq_list_members",
20031
+ stateCatalogId: "lead-gen.contact",
20032
+ links: [
20033
+ { toEntity: "leadgen.list", kind: "belongs-to", via: "list_id", label: "list" },
20034
+ { toEntity: "leadgen.company", kind: "belongs-to", via: "company_id", label: "company" }
20035
+ ]
20036
+ },
20037
+ {
20038
+ id: "delivery.project",
20039
+ order: 60,
20040
+ label: "Project",
20041
+ description: "A client delivery project.",
20042
+ ownedBySystemId: "projects",
20043
+ table: "projects",
20044
+ links: [
20045
+ { toEntity: "delivery.milestone", kind: "has-many", via: "project_id", label: "milestones" },
20046
+ { toEntity: "delivery.task", kind: "has-many", via: "project_id", label: "tasks" }
20047
+ ]
20048
+ },
20049
+ {
20050
+ id: "delivery.milestone",
20051
+ order: 70,
20052
+ label: "Milestone",
20053
+ description: "A delivery checkpoint within a project.",
20054
+ ownedBySystemId: "projects",
20055
+ table: "project_milestones",
20056
+ links: [
20057
+ { toEntity: "delivery.project", kind: "belongs-to", via: "project_id", label: "project" },
20058
+ { toEntity: "delivery.task", kind: "has-many", via: "milestone_id", label: "tasks" }
20059
+ ]
20060
+ },
20061
+ {
20062
+ id: "delivery.task",
20063
+ order: 80,
20064
+ label: "Task",
20065
+ description: "A delivery task that can move through the task status catalog.",
20066
+ ownedBySystemId: "projects",
20067
+ table: "project_tasks",
20068
+ stateCatalogId: "delivery.task",
20069
+ links: [
20070
+ { toEntity: "delivery.project", kind: "belongs-to", via: "project_id", label: "project" },
20071
+ { toEntity: "delivery.milestone", kind: "belongs-to", via: "milestone_id", label: "milestone" }
20072
+ ]
20073
+ }
20074
+ ];
20075
+ var DEFAULT_ORGANIZATION_MODEL_ENTITIES = Object.fromEntries(
20076
+ ENTITY_ENTRY_INPUTS.map((entity) => {
20077
+ const parsed = EntitySchema.parse(entity);
20078
+ return [parsed.id, parsed];
20079
+ })
20080
+ );
20081
+
20082
+ // src/organization-model/domains/actions.ts
20083
+ var ActionResourceIdSchema = z.string().trim().min(1).max(255).regex(/^[A-Za-z0-9]+(?:[-._][A-Za-z0-9]+)*$/, "Resource IDs must use letters, numbers, -, _, or . separators");
20084
+ z.enum(["slash-command", "mcp-tool", "api-endpoint", "script-execution"]).meta({ label: "Invocation kind" });
20085
+ var ActionIdSchema = ModelIdSchema;
20086
+ var ActionScopeSchema = z.union([
20087
+ z.literal("global"),
20088
+ z.object({
20089
+ domain: ModelIdSchema
20090
+ })
20091
+ ]);
20092
+ var ActionRefSchema = z.object({
20093
+ actionId: ActionIdSchema.meta({ ref: "action" }),
20094
+ intent: z.enum(["exposes", "consumes"]).meta({ label: "Intent" })
20095
+ });
20096
+ var SlashCommandInvocationSchema = z.object({
20097
+ kind: z.literal("slash-command"),
20098
+ command: z.string().trim().min(1).max(200).regex(/^\/[^\s].*$/, "Slash commands must start with /"),
20099
+ toolFactory: ModelIdSchema.optional()
20100
+ });
20101
+ var McpToolInvocationSchema = z.object({
20102
+ kind: z.literal("mcp-tool"),
20103
+ server: ModelIdSchema,
20104
+ name: ModelIdSchema
20105
+ });
20106
+ var ApiEndpointInvocationSchema = z.object({
20107
+ kind: z.literal("api-endpoint"),
20108
+ method: z.enum(["GET", "POST", "PATCH", "DELETE"]).meta({ label: "HTTP method" }),
20109
+ path: z.string().trim().startsWith("/").max(500),
20110
+ requestSchema: ModelIdSchema.optional(),
20111
+ responseSchema: ModelIdSchema.optional()
20112
+ });
20113
+ var ScriptExecutionInvocationSchema = z.object({
20114
+ kind: z.literal("script-execution"),
20115
+ resourceId: ActionResourceIdSchema
20116
+ });
20117
+ var ActionInvocationSchema = z.discriminatedUnion("kind", [
20118
+ SlashCommandInvocationSchema,
20119
+ McpToolInvocationSchema,
20120
+ ApiEndpointInvocationSchema,
20121
+ ScriptExecutionInvocationSchema
20122
+ ]);
20123
+ var ActionSchema = z.object({
20124
+ id: ActionIdSchema,
20125
+ /** Domain-map iteration order. Convention: multiples of 10 (10, 20, 30, ...) to allow easy insertion. */
20126
+ order: z.number(),
20127
+ label: LabelSchema,
20128
+ description: DescriptionSchema.optional(),
20129
+ scope: ActionScopeSchema.default("global"),
20130
+ resourceId: ActionResourceIdSchema.optional(),
20131
+ affects: z.array(EntityIdSchema.meta({ ref: "entity" })).optional(),
20132
+ invocations: z.array(ActionInvocationSchema).default([]),
20133
+ knowledge: z.array(ModelIdSchema.meta({ ref: "knowledge" })).default([]).optional(),
20134
+ lifecycle: z.enum(["draft", "beta", "active", "deprecated", "archived"]).meta({ label: "Lifecycle", color: "teal" }).default("active")
20135
+ });
20136
+ var ActionsDomainSchema = z.record(z.string(), ActionSchema).refine((record) => Object.entries(record).every(([key, entry]) => entry.id === key), {
20137
+ message: "Each action entry id must match its map key"
20138
+ }).default({});
20139
+ var LEAD_GEN_ACTION_ENTRY_INPUTS = [
20140
+ {
20141
+ id: "lead-gen.company.source",
20142
+ order: 10,
20143
+ label: "Source companies",
20144
+ description: "Import source companies from a list provider.",
20145
+ scope: { domain: "sales" },
20146
+ resourceId: "lgn-import-workflow",
20147
+ invocations: [{ kind: "api-endpoint", method: "POST", path: "/api/prospecting/companies/source" }]
20148
+ },
20149
+ {
20150
+ id: "lead-gen.company.apollo-import",
20151
+ order: 20,
20152
+ label: "Import from Apollo",
20153
+ description: "Pull companies and seed contact data from an Apollo search or list.",
20154
+ scope: { domain: "sales" },
20155
+ resourceId: "lgn-01c-apollo-import-workflow",
20156
+ invocations: [{ kind: "api-endpoint", method: "POST", path: "/api/prospecting/companies/apollo-import" }]
20157
+ },
20158
+ {
20159
+ id: "lead-gen.contact.discover",
20160
+ order: 30,
20161
+ label: "Discover contact emails",
20162
+ description: "Find email addresses for contacts at qualified companies.",
20163
+ scope: { domain: "sales" },
20164
+ resourceId: "lgn-04-email-discovery-workflow",
20165
+ invocations: [{ kind: "api-endpoint", method: "POST", path: "/api/prospecting/contacts/discover" }]
20166
+ },
20167
+ {
20168
+ id: "lead-gen.contact.verify-email",
20169
+ order: 40,
20170
+ label: "Verify emails",
20171
+ description: "Check email deliverability before outreach.",
20172
+ scope: { domain: "sales" },
20173
+ resourceId: "lgn-05-email-verification-workflow",
20174
+ invocations: [{ kind: "api-endpoint", method: "POST", path: "/api/prospecting/contacts/verify-email" }]
20175
+ },
20176
+ {
20177
+ id: "lead-gen.company.apify-crawl",
20178
+ order: 50,
20179
+ label: "Crawl websites",
20180
+ description: "Crawl company websites via Apify and store raw page markdown in enrichmentData.websiteCrawl.pages for downstream LLM analysis.",
20181
+ scope: { domain: "sales" },
20182
+ resourceId: "lgn-02a-apify-website-crawl-workflow",
20183
+ invocations: [{ kind: "api-endpoint", method: "POST", path: "/api/prospecting/companies/apify-crawl" }]
20184
+ },
20185
+ {
20186
+ id: "lead-gen.company.website-extract",
20187
+ order: 60,
20188
+ label: "Extract website signals",
20189
+ description: "Scrape and analyze company websites for qualification signals.",
20190
+ scope: { domain: "sales" },
20191
+ resourceId: "lgn-02-website-extract-workflow",
20192
+ invocations: [{ kind: "api-endpoint", method: "POST", path: "/api/prospecting/companies/website-extract" }]
20193
+ },
20194
+ {
20195
+ id: "lead-gen.company.qualify",
20196
+ order: 70,
20197
+ label: "Qualify companies",
20198
+ description: "Score and filter companies against the ICP rubric.",
20199
+ scope: { domain: "sales" },
20200
+ resourceId: "lgn-03-company-qualification-workflow",
20201
+ invocations: [{ kind: "api-endpoint", method: "POST", path: "/api/prospecting/companies/qualify" }]
20202
+ },
20203
+ {
20204
+ id: "lead-gen.company.dtc-subscription-qualify",
20205
+ order: 80,
20206
+ label: "Qualify DTC subscription fit",
20207
+ description: "Classify subscription potential and consumable-product fit for DTC brands.",
20208
+ scope: { domain: "sales" },
20209
+ resourceId: "lgn-03b-dtc-subscription-score-workflow",
20210
+ invocations: [{ kind: "api-endpoint", method: "POST", path: "/api/prospecting/companies/dtc-subscription-qualify" }]
20211
+ },
20212
+ {
20213
+ id: "lead-gen.contact.apollo-decision-maker-enrich",
20214
+ order: 90,
20215
+ label: "Enrich decision-makers",
20216
+ description: "Find and enrich qualified contacts at qualified companies via Apollo.",
20217
+ scope: { domain: "sales" },
20218
+ resourceId: "lgn-04b-apollo-decision-maker-enrich-workflow",
20219
+ invocations: [
20220
+ { kind: "api-endpoint", method: "POST", path: "/api/prospecting/contacts/apollo-decision-maker-enrich" }
20221
+ ]
20222
+ },
20223
+ {
20224
+ id: "lead-gen.contact.personalize",
20225
+ order: 100,
20226
+ label: "Personalize outreach",
20227
+ description: "Generate personalized opening lines for each contact.",
20228
+ scope: { domain: "sales" },
20229
+ resourceId: "ist-personalization-workflow",
20230
+ invocations: [{ kind: "api-endpoint", method: "POST", path: "/api/prospecting/contacts/personalize" }]
20231
+ },
20232
+ {
20233
+ id: "lead-gen.review.outreach-ready",
20234
+ order: 110,
20235
+ label: "Upload to outreach",
20236
+ description: "Upload approved contacts to the outreach sequence after QC review.",
20237
+ scope: { domain: "sales" },
20238
+ resourceId: "ist-upload-contacts-workflow",
20239
+ invocations: [{ kind: "api-endpoint", method: "POST", path: "/api/prospecting/review/outreach-ready" }]
20240
+ },
20241
+ {
20242
+ id: "lead-gen.export.list",
20243
+ order: 120,
20244
+ label: "Export lead list",
20245
+ description: "Export approved leads as a downloadable lead list.",
20246
+ scope: { domain: "sales" },
20247
+ resourceId: "lgn-06-export-list-workflow",
20248
+ invocations: [{ kind: "api-endpoint", method: "POST", path: "/api/prospecting/export/list" }]
20249
+ },
20250
+ {
20251
+ id: "lead-gen.company.cleanup",
20252
+ order: 130,
20253
+ label: "Clean up companies",
20254
+ description: "Remove disqualified or duplicate companies from the list.",
20255
+ scope: { domain: "sales" },
20256
+ resourceId: "lgn-company-cleanup-workflow",
20257
+ invocations: [{ kind: "api-endpoint", method: "POST", path: "/api/prospecting/companies/cleanup" }]
20258
+ }
20259
+ ];
20260
+ var LEAD_GEN_ACTION_ENTRIES = Object.fromEntries(
20261
+ LEAD_GEN_ACTION_ENTRY_INPUTS.map((action) => {
20262
+ const parsed = ActionSchema.parse(action);
20263
+ return [parsed.id, parsed];
20264
+ })
20265
+ );
20266
+ var DEFAULT_ORGANIZATION_MODEL_ACTIONS = LEAD_GEN_ACTION_ENTRIES;
20267
+
20268
+ // src/organization-model/domains/systems.ts
20269
+ var SystemKindSchema = z.enum(["product", "operational", "platform", "diagnostic"]).meta({ label: "System kind", color: "blue" });
20270
+ var SystemLifecycleSchema = z.enum(["draft", "beta", "active", "deprecated", "archived"]).meta({ label: "Lifecycle", color: "teal" });
20271
+ var SystemStatusSchema = z.enum(["active", "deprecated", "archived"]).meta({ label: "Status", color: "teal" });
20272
+ var SystemIdSchema = ModelIdSchema;
20273
+ var SystemPathSchema = z.string().trim().min(1).regex(
20274
+ /^[a-z0-9][a-z0-9-]*(?:\.[a-z0-9][a-z0-9-]*)*$/,
20275
+ 'must be a dotted lowercase path (e.g. "sales.lead-gen" or "sales.crm")'
20276
+ );
20277
+ var UiPositionSchema = z.enum(["sidebar-primary", "sidebar-bottom"]).meta({ label: "UI position" });
20278
+ var NodeIdStringSchema = z.string().trim().min(1).max(200).regex(
20279
+ /^[a-z][a-z-]*:([a-z0-9-]+)(\.[a-z0-9-]+)*(:[a-z0-9.-]+)*$/,
20280
+ "Node references must use kind:dotted-path (e.g. system:sales.crm or content-node:sales.crm:pipeline-id)"
20281
+ );
20282
+ var SystemUiSchema = z.object({
20283
+ path: PathSchema,
20284
+ surfaces: ReferenceIdsSchema,
20285
+ icon: IconNameSchema.optional(),
20286
+ order: z.number().int().optional()
20287
+ });
20288
+ var SystemEntrySchema = z.object({
20289
+ /** Stable tenant-defined system id (e.g. "sys.lead-gen" or "sales.crm"). */
20290
+ id: SystemIdSchema,
20291
+ /** Human-readable system label shown in UI, governance, and operations surfaces. */
20292
+ label: LabelSchema.optional(),
20293
+ /** @deprecated Use label. Accepted for pre-consolidation System declarations. */
20294
+ title: LabelSchema.optional(),
20295
+ /** One-paragraph purpose statement for the bounded context. */
20296
+ description: DescriptionSchema.optional(),
20297
+ /** Closed system shape enum; catalog values remain tenant-defined. */
20298
+ kind: SystemKindSchema.optional(),
20299
+ /** Optional self-reference for System hierarchy. */
20300
+ parentSystemId: SystemIdSchema.optional(),
20301
+ /** Optional UI presence. Systems without UI omit this. */
20302
+ ui: SystemUiSchema.optional(),
20303
+ /** Canonical lifecycle state. Replaces Feature.enabled/devOnly and System.status. */
20304
+ lifecycle: SystemLifecycleSchema.optional(),
20305
+ /** Optional role responsible for this system. */
20306
+ responsibleRoleId: ModelIdSchema.meta({ ref: "role" }).optional(),
20307
+ /** Optional knowledge nodes that govern this system. */
20308
+ governedByKnowledge: z.array(ModelIdSchema.meta({ ref: "knowledge" })).default([]).optional(),
20309
+ /** Optional actions this system exposes or consumes. */
20310
+ actions: z.array(ActionRefSchema).optional(),
20311
+ /** Optional operational policies that apply to this system. */
20312
+ policies: z.array(ModelIdSchema.meta({ ref: "policy" })).default([]).optional(),
20313
+ /** Optional goals this system contributes to. */
20314
+ drivesGoals: z.array(ModelIdSchema.meta({ ref: "goal" })).default([]).optional(),
20315
+ /** @deprecated Use lifecycle. Accepted for one publish cycle. */
20316
+ status: SystemStatusSchema.optional(),
20317
+ /** @deprecated Use ui.path. Kept for one-cycle Feature compatibility. */
20318
+ path: PathSchema.optional(),
20319
+ /** @deprecated Use ui.icon. Kept for one-cycle Feature compatibility. */
20320
+ icon: IconNameSchema.optional(),
20321
+ /** @deprecated Feature color token, retained for one-cycle compatibility. */
20322
+ color: ColorTokenSchema.optional(),
20323
+ /** @deprecated UI placement hint, retained for one-cycle compatibility. */
20324
+ uiPosition: UiPositionSchema.optional(),
20325
+ /** @deprecated Use lifecycle. */
20326
+ enabled: z.boolean().optional(),
20327
+ /** @deprecated Use lifecycle: "beta". */
20328
+ devOnly: z.boolean().optional(),
20329
+ requiresAdmin: z.boolean().optional(),
20330
+ /** Domain-map iteration order. Convention: multiples of 10 (10, 20, 30, ...) to allow easy insertion. */
20331
+ order: z.number(),
20332
+ /**
20333
+ * System-scoped operational data, co-located with the owning system.
20334
+ * Per L1, L3, L13: keyed by local NodeId (the key is the local id; qualified
20335
+ * id is `<system-path>:<local-id>`, computed by graph projection).
20336
+ * Per L14: every ContentNode carries both `kind` and `type`.
20337
+ * Per D2: unregistered (kind, type) pairs parse successfully.
20338
+ */
20339
+ content: z.record(z.string().trim().min(1).max(200), ContentNodeSchema).optional(),
20340
+ /**
20341
+ * Recursive child systems, authored via nesting (per L11).
20342
+ * The key is the local system id; the full path is computed by joining
20343
+ * ancestor keys with `.` (e.g. parent key `'sales'` + child key `'crm'` → `'sales.crm'`).
20344
+ * Per Phase 4: `id` and `parentSystemId` fields will be removed in favour of
20345
+ * position-derived paths. Both still exist on this schema for backward compat.
20346
+ */
20347
+ subsystems: z.lazy(() => z.record(z.string().trim().min(1).max(100), SystemEntrySchema)).optional()
20348
+ }).refine((system) => system.label !== void 0 || system.title !== void 0, {
20349
+ path: ["label"],
20350
+ message: "System must provide label or title"
20351
+ }).transform((system) => {
20352
+ if (system.status === void 0) return system;
20353
+ console.warn("[organization-model] System.status is deprecated; use System.lifecycle instead.");
20354
+ return system.lifecycle === void 0 ? { ...system, lifecycle: system.status } : system;
20355
+ });
20356
+ var SystemsDomainSchema = z.record(z.string(), SystemEntrySchema).refine((record) => Object.entries(record).every(([key, entry]) => entry.id === key), {
20357
+ message: "Each system entry id must match its map key"
20358
+ }).default({});
20359
+ var DEFAULT_ORGANIZATION_MODEL_SYSTEMS = {};
20360
+
20361
+ // src/organization-model/domains/resources.ts
20362
+ z.enum(["workflow", "agent", "integration", "script"]).meta({ label: "Resource kind", color: "orange" });
20363
+ var ResourceGovernanceStatusSchema = z.enum(["active", "deprecated", "archived"]).meta({ label: "Governance status", color: "teal" });
20364
+ var AgentKindSchema = z.enum(["orchestrator", "specialist", "utility", "platform"]).meta({ label: "Agent kind", color: "violet" });
20365
+ var ScriptResourceLanguageSchema = z.enum(["shell", "sql", "typescript", "python"]).meta({ label: "Language" });
20366
+ 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");
20367
+ var EventIdSchema = z.string().trim().min(1).max(300).regex(
20368
+ /^[A-Za-z0-9]+(?:[-._][A-Za-z0-9]+)*:[a-z0-9]+(?:[-._][a-z0-9]+)*$/,
20369
+ "Event IDs must use <owner-id>:<event-key>"
20370
+ );
20371
+ var EventKeySchema = ModelIdSchema;
20372
+ var EventEmissionDescriptorSchema = z.object({
20373
+ eventKey: EventKeySchema,
20374
+ label: z.string().trim().min(1).max(120),
20375
+ payloadSchema: ModelIdSchema.optional(),
20376
+ lifecycle: SystemLifecycleSchema.optional()
20377
+ });
20378
+ EventEmissionDescriptorSchema.extend({
20379
+ id: EventIdSchema,
20380
+ ownerId: z.union([ResourceIdSchema, ModelIdSchema]),
20381
+ ownerKind: z.enum(["resource", "entity"]).meta({ label: "Owner kind" })
20382
+ });
20383
+ var ResourceEntryBaseSchema = z.object({
20384
+ /** Canonical resource id; runtime resourceId derives from this value. */
20385
+ id: ResourceIdSchema,
20386
+ /** Domain-map iteration order. Convention: multiples of 10 (10, 20, 30, ...) to allow easy insertion. */
20387
+ order: z.number().default(0),
20388
+ /** Required single System membership — value is a dot-separated system path (e.g. "sales.lead-gen"). */
20389
+ systemPath: SystemPathSchema.meta({ ref: "system" }),
20390
+ /** Optional role responsible for maintaining this resource. */
20391
+ ownerRoleId: ModelIdSchema.meta({ ref: "role" }).optional(),
20392
+ status: ResourceGovernanceStatusSchema
20393
+ });
20394
+ var WorkflowResourceEntrySchema = ResourceEntryBaseSchema.extend({
20395
+ kind: z.literal("workflow"),
20396
+ /** Mirrors WorkflowConfig.actionKey when the runtime workflow has one. */
20397
+ actionKey: z.string().trim().min(1).max(255).optional(),
20398
+ emits: z.array(EventEmissionDescriptorSchema).optional()
20399
+ });
20400
+ var AgentResourceEntrySchema = ResourceEntryBaseSchema.extend({
20401
+ kind: z.literal("agent"),
20402
+ /** Mirrors code-side AgentConfig.kind. */
20403
+ agentKind: AgentKindSchema,
20404
+ /** Role this agent embodies, if any. */
20405
+ actsAsRoleId: ModelIdSchema.meta({ ref: "role" }).optional(),
20406
+ /** Mirrors AgentConfig.sessionCapable. */
20407
+ sessionCapable: z.boolean(),
20408
+ /** Broad/composite callable entry points orchestrated by this agent. */
20409
+ invocations: z.array(ActionInvocationSchema).default([]),
20410
+ emits: z.array(EventEmissionDescriptorSchema).optional()
20411
+ });
20412
+ var IntegrationResourceEntrySchema = ResourceEntryBaseSchema.extend({
20413
+ kind: z.literal("integration"),
20414
+ provider: z.string().trim().min(1).max(100)
20415
+ });
20416
+ var ScriptResourceSourceSchema = z.union([
20417
+ z.string().trim().min(1).max(5e4),
20418
+ z.object({
20419
+ file: z.string().trim().min(1).max(500)
20420
+ })
20421
+ ]);
20422
+ var ScriptResourceEntrySchema = ResourceEntryBaseSchema.extend({
20423
+ kind: z.literal("script"),
20424
+ language: ScriptResourceLanguageSchema,
20425
+ source: ScriptResourceSourceSchema
20426
+ });
20427
+ var ResourceEntrySchema = z.discriminatedUnion("kind", [
20428
+ WorkflowResourceEntrySchema,
20429
+ AgentResourceEntrySchema,
20430
+ IntegrationResourceEntrySchema,
20431
+ ScriptResourceEntrySchema
20432
+ ]);
20433
+ var ResourcesDomainSchema = z.record(z.string(), ResourceEntrySchema).refine((record) => Object.entries(record).every(([key, entry]) => entry.id === key), {
20434
+ message: "Each resource entry id must match its map key"
20435
+ }).default({});
20436
+ var DEFAULT_ORGANIZATION_MODEL_RESOURCES = {};
20437
+
20438
+ // src/organization-model/domains/roles.ts
20439
+ var RoleIdSchema = ModelIdSchema;
20440
+ var HumanRoleHolderSchema = z.object({
20441
+ kind: z.literal("human"),
20442
+ userId: z.string().trim().min(1).max(200)
20443
+ });
20444
+ var AgentRoleHolderSchema = z.object({
20445
+ kind: z.literal("agent"),
20446
+ agentId: ResourceIdSchema.meta({ ref: "resource" })
20447
+ });
20448
+ var TeamRoleHolderSchema = z.object({
20449
+ kind: z.literal("team"),
20450
+ memberIds: z.array(z.string().trim().min(1).max(200)).min(1)
20451
+ });
20452
+ var RoleHolderSchema = z.discriminatedUnion("kind", [
20453
+ HumanRoleHolderSchema,
20454
+ AgentRoleHolderSchema,
20455
+ TeamRoleHolderSchema
20456
+ ]);
20457
+ var RoleHoldersSchema = z.union([RoleHolderSchema, z.array(RoleHolderSchema).min(1)]);
20369
20458
  var RoleSchema = z.object({
20370
20459
  /** Stable unique identifier for the role (e.g. "role-ceo", "role-head-of-sales"). */
20371
- id: z.string().trim().min(1).max(100),
20460
+ id: RoleIdSchema,
20461
+ /** Domain-map iteration order. Convention: multiples of 10 (10, 20, 30, ...) to allow easy insertion. */
20462
+ order: z.number(),
20372
20463
  /** Human-readable title shown to agents and in UI (e.g. "CEO", "Head of Sales"). */
20373
20464
  title: z.string().trim().min(1).max(200),
20374
20465
  /**
20375
- * List of responsibilities this role owns plain-language descriptions of
20466
+ * List of responsibilities this role owns - plain-language descriptions of
20376
20467
  * what the person in this role is accountable for delivering.
20377
20468
  * Defaults to empty array so minimal role definitions stay concise.
20378
20469
  */
@@ -20380,23 +20471,23 @@ var RoleSchema = z.object({
20380
20471
  /**
20381
20472
  * Optional: ID of another role this role reports to.
20382
20473
  * When present, must reference another `roles[].id` in the same organization.
20383
- * Cross-reference enforced in `OrganizationModelSchema.superRefine()`.
20384
- * Absence indicates a top-level role (no reporting line).
20385
20474
  */
20386
- reportsToId: z.string().trim().min(1).max(100).optional(),
20475
+ reportsToId: RoleIdSchema.meta({ ref: "role" }).optional(),
20387
20476
  /**
20388
- * Optional: name or email of the person currently holding this role.
20389
- * Free-form string supports "Alice Johnson", "alice@example.com", or
20390
- * any human-readable identifier. Not validated against any user registry.
20477
+ * Optional: human, agent, or team holder currently filling this role.
20478
+ * Agent holders reference OM Resource IDs and are validated at the model level.
20391
20479
  */
20392
- heldBy: z.string().trim().max(200).optional()
20393
- });
20394
- var RolesDomainSchema = z.object({
20395
- roles: z.array(RoleSchema).default([])
20480
+ heldBy: RoleHoldersSchema.optional(),
20481
+ /**
20482
+ * Optional Systems this role is accountable for.
20483
+ * Cross-reference enforced in `OrganizationModelSchema.superRefine()`.
20484
+ */
20485
+ responsibleFor: z.array(SystemIdSchema.meta({ ref: "system" })).optional()
20396
20486
  });
20397
- var DEFAULT_ORGANIZATION_MODEL_ROLES = {
20398
- roles: []
20399
- };
20487
+ var RolesDomainSchema = z.record(z.string(), RoleSchema).refine((record) => Object.entries(record).every(([key, entry]) => entry.id === key), {
20488
+ message: "Each role entry id must match its map key"
20489
+ }).default({});
20490
+ var DEFAULT_ORGANIZATION_MODEL_ROLES = {};
20400
20491
  var KeyResultSchema = z.object({
20401
20492
  /** Stable unique identifier for the measurable outcome (e.g. "kr-revenue-q1"). */
20402
20493
  id: z.string().trim().min(1).max(100),
@@ -20420,6 +20511,8 @@ var ISO_DATE_REGEX = /^\d{4}-\d{2}-\d{2}$/;
20420
20511
  var ObjectiveSchema = z.object({
20421
20512
  /** Stable unique identifier for the goal (e.g. "goal-grow-arr-q1-2026"). */
20422
20513
  id: z.string().trim().min(1).max(100),
20514
+ /** Domain-map iteration order. Convention: multiples of 10 (10, 20, 30, ...) to allow easy insertion. */
20515
+ order: z.number(),
20423
20516
  /** Plain-language description of what the organization wants to achieve. */
20424
20517
  description: z.string().trim().min(1).max(1e3),
20425
20518
  /**
@@ -20439,180 +20532,63 @@ var ObjectiveSchema = z.object({
20439
20532
  */
20440
20533
  keyResults: z.array(KeyResultSchema).default([])
20441
20534
  });
20442
- var GoalsDomainSchema = z.object({
20443
- objectives: z.array(ObjectiveSchema).default([])
20444
- });
20445
- var DEFAULT_ORGANIZATION_MODEL_GOALS = {
20446
- objectives: []
20447
- };
20448
- var OperationSemanticClassSchema = z.enum(["queue", "executions", "sessions", "notifications", "schedules"]);
20449
- var OperationEntrySchema = z.object({
20450
- id: z.string().trim().min(1).max(100),
20451
- label: z.string().trim().min(1).max(120),
20452
- semanticClass: OperationSemanticClassSchema,
20453
- /** Optional reference to the feature that owns this runtime entity. */
20454
- featureId: z.string().trim().min(1).max(100).optional(),
20455
- /**
20456
- * Optional pointer to the status semanticClass values that apply to this
20457
- * entity — ties operations back to the statuses domain for vibe rendering.
20458
- */
20459
- supportedStatusSemanticClass: z.array(z.string().trim().min(1).max(80)).optional()
20460
- });
20461
- var OperationsDomainSchema = z.object({
20462
- entries: z.array(OperationEntrySchema).default([])
20535
+ var GoalsDomainSchema = z.record(z.string(), ObjectiveSchema).refine((record) => Object.entries(record).every(([key, entry]) => entry.id === key), {
20536
+ message: "Each objective entry id must match its map key"
20537
+ }).default({});
20538
+ var DEFAULT_ORGANIZATION_MODEL_GOALS = {};
20539
+ var KnowledgeTargetKindSchema = z.enum([
20540
+ "system",
20541
+ "resource",
20542
+ "knowledge",
20543
+ "stage",
20544
+ "action",
20545
+ "role",
20546
+ "goal",
20547
+ "customer-segment",
20548
+ "offering",
20549
+ // D4: content nodes are a valid knowledge target after compound-domain data moved into system.content
20550
+ "content-node"
20551
+ ]).meta({ label: "Target kind" });
20552
+ var KnowledgeTargetRefSchema = z.object({
20553
+ kind: KnowledgeTargetKindSchema,
20554
+ // D4: content-node targets use a qualified id format '<system-path>:<local-content-id>'
20555
+ // which contains a colon separator and cannot satisfy ModelIdSchema. Use a permissive
20556
+ // string schema here; business-logic validation of target existence is done in
20557
+ // OrganizationModelSchema.superRefine (knowledgeTargetExists).
20558
+ id: z.string().trim().min(1).max(300)
20463
20559
  });
20464
- var DEFAULT_ORGANIZATION_MODEL_OPERATIONS = {
20465
- entries: [
20466
- // --- queue (HITL command queue) ---
20467
- {
20468
- id: "operations.queue",
20469
- label: "HITL Queue",
20470
- semanticClass: "queue",
20471
- featureId: "operations",
20472
- supportedStatusSemanticClass: ["queue"]
20473
- },
20474
- // --- executions (workflow / agent executions) ---
20475
- {
20476
- id: "operations.executions",
20477
- label: "Executions",
20478
- semanticClass: "executions",
20479
- featureId: "operations",
20480
- supportedStatusSemanticClass: ["execution"]
20481
- },
20482
- // --- sessions (agent conversation sessions) ---
20483
- {
20484
- id: "operations.sessions",
20485
- label: "Sessions",
20486
- semanticClass: "sessions",
20487
- featureId: "operations"
20488
- },
20489
- // --- notifications (platform in-app notifications) ---
20490
- {
20491
- id: "operations.notifications",
20492
- label: "Notifications",
20493
- semanticClass: "notifications",
20494
- featureId: "monitoring"
20495
- },
20496
- // --- schedules (task scheduler) ---
20497
- {
20498
- id: "operations.schedules",
20499
- label: "Schedules",
20500
- semanticClass: "schedules",
20501
- featureId: "operations",
20502
- supportedStatusSemanticClass: ["schedule", "schedule.run"]
20503
- }
20504
- ]
20505
- };
20506
- var StatusSemanticClassSchema = z.enum([
20507
- "delivery.task",
20508
- "delivery.project",
20509
- "delivery.milestone",
20510
- "queue",
20511
- "execution",
20512
- "schedule",
20513
- "schedule.run",
20514
- "request"
20515
- ]);
20516
- var StatusEntrySchema = z.object({
20517
- id: z.string().trim().min(1).max(100),
20518
- label: z.string().trim().min(1).max(120),
20519
- semanticClass: StatusSemanticClassSchema,
20520
- category: z.string().trim().min(1).max(80).optional()
20560
+ var LegacyKnowledgeLinkSchema = z.object({
20561
+ nodeId: NodeIdStringSchema
20521
20562
  });
20522
- var StatusesDomainSchema = z.object({
20523
- entries: z.array(StatusEntrySchema).default([])
20563
+ var CanonicalKnowledgeLinkSchema = z.object({
20564
+ target: KnowledgeTargetRefSchema
20524
20565
  });
20525
- var DEFAULT_ORGANIZATION_MODEL_STATUSES = {
20526
- entries: [
20527
- // --- delivery.task (TaskStatus — 9 values) ---
20528
- { id: "delivery.task.planned", label: "Planned", semanticClass: "delivery.task", category: "delivery" },
20529
- { id: "delivery.task.in_progress", label: "In Progress", semanticClass: "delivery.task", category: "delivery" },
20530
- { id: "delivery.task.blocked", label: "Blocked", semanticClass: "delivery.task", category: "delivery" },
20531
- { id: "delivery.task.submitted", label: "Submitted", semanticClass: "delivery.task", category: "delivery" },
20532
- { id: "delivery.task.approved", label: "Approved", semanticClass: "delivery.task", category: "delivery" },
20533
- {
20534
- id: "delivery.task.revision_requested",
20535
- label: "Revision Requested",
20536
- semanticClass: "delivery.task",
20537
- category: "delivery"
20538
- },
20539
- { id: "delivery.task.rejected", label: "Rejected", semanticClass: "delivery.task", category: "delivery" },
20540
- { id: "delivery.task.cancelled", label: "Cancelled", semanticClass: "delivery.task", category: "delivery" },
20541
- { id: "delivery.task.completed", label: "Completed", semanticClass: "delivery.task", category: "delivery" },
20542
- // --- delivery.project (ProjectStatus — 6 values) ---
20543
- { id: "delivery.project.active", label: "Active", semanticClass: "delivery.project", category: "delivery" },
20544
- { id: "delivery.project.on_track", label: "On Track", semanticClass: "delivery.project", category: "delivery" },
20545
- { id: "delivery.project.at_risk", label: "At Risk", semanticClass: "delivery.project", category: "delivery" },
20546
- { id: "delivery.project.blocked", label: "Blocked", semanticClass: "delivery.project", category: "delivery" },
20547
- { id: "delivery.project.paused", label: "Paused", semanticClass: "delivery.project", category: "delivery" },
20548
- { id: "delivery.project.completed", label: "Completed", semanticClass: "delivery.project", category: "delivery" },
20549
- // --- delivery.milestone (MilestoneStatus — 5 values) ---
20550
- {
20551
- id: "delivery.milestone.upcoming",
20552
- label: "Upcoming",
20553
- semanticClass: "delivery.milestone",
20554
- category: "delivery"
20555
- },
20556
- {
20557
- id: "delivery.milestone.in_progress",
20558
- label: "In Progress",
20559
- semanticClass: "delivery.milestone",
20560
- category: "delivery"
20561
- },
20562
- {
20563
- id: "delivery.milestone.blocked",
20564
- label: "Blocked",
20565
- semanticClass: "delivery.milestone",
20566
- category: "delivery"
20567
- },
20568
- { id: "delivery.milestone.overdue", label: "Overdue", semanticClass: "delivery.milestone", category: "delivery" },
20569
- {
20570
- id: "delivery.milestone.completed",
20571
- label: "Completed",
20572
- semanticClass: "delivery.milestone",
20573
- category: "delivery"
20574
- },
20575
- // --- queue (QueueTaskStatus — 5 values, maps hitl/command-queue tasks) ---
20576
- { id: "queue.pending", label: "Pending", semanticClass: "queue", category: "queue" },
20577
- { id: "queue.processing", label: "Processing", semanticClass: "queue", category: "queue" },
20578
- { id: "queue.completed", label: "Completed", semanticClass: "queue", category: "queue" },
20579
- { id: "queue.failed", label: "Failed", semanticClass: "queue", category: "queue" },
20580
- { id: "queue.expired", label: "Expired", semanticClass: "queue", category: "queue" },
20581
- // --- execution (ExecutionStatus — 5 values) ---
20582
- { id: "execution.pending", label: "Pending", semanticClass: "execution", category: "execution" },
20583
- { id: "execution.running", label: "Running", semanticClass: "execution", category: "execution" },
20584
- { id: "execution.completed", label: "Completed", semanticClass: "execution", category: "execution" },
20585
- { id: "execution.failed", label: "Failed", semanticClass: "execution", category: "execution" },
20586
- { id: "execution.warning", label: "Warning", semanticClass: "execution", category: "execution" },
20587
- // --- schedule (schedule status — 4 values) ---
20588
- { id: "schedule.active", label: "Active", semanticClass: "schedule", category: "schedule" },
20589
- { id: "schedule.paused", label: "Paused", semanticClass: "schedule", category: "schedule" },
20590
- { id: "schedule.completed", label: "Completed", semanticClass: "schedule", category: "schedule" },
20591
- { id: "schedule.cancelled", label: "Cancelled", semanticClass: "schedule", category: "schedule" },
20592
- // --- schedule.run (schedule run status — 4 values) ---
20593
- { id: "schedule.run.running", label: "Running", semanticClass: "schedule.run", category: "schedule" },
20594
- { id: "schedule.run.completed", label: "Completed", semanticClass: "schedule.run", category: "schedule" },
20595
- { id: "schedule.run.failed", label: "Failed", semanticClass: "schedule.run", category: "schedule" },
20596
- { id: "schedule.run.cancelled", label: "Cancelled", semanticClass: "schedule.run", category: "schedule" },
20597
- // --- request (RequestStatus — 4 values, maps reported_requests) ---
20598
- { id: "request.open", label: "Open", semanticClass: "request", category: "request" },
20599
- { id: "request.investigating", label: "Investigating", semanticClass: "request", category: "request" },
20600
- { id: "request.resolved", label: "Resolved", semanticClass: "request", category: "request" },
20601
- { id: "request.wont_fix", label: "Won't Fix", semanticClass: "request", category: "request" }
20602
- ]
20603
- };
20604
- var KnowledgeLinkSchema = z.object({
20605
- nodeId: NodeIdStringSchema
20566
+ function nodeIdFromTarget(target) {
20567
+ return `${target.kind}:${target.id}`;
20568
+ }
20569
+ function targetFromNodeId(nodeId) {
20570
+ const [kind, ...idParts] = nodeId.split(":");
20571
+ return {
20572
+ kind: KnowledgeTargetKindSchema.parse(kind),
20573
+ id: idParts.join(":")
20574
+ };
20575
+ }
20576
+ var KnowledgeLinkSchema = z.union([CanonicalKnowledgeLinkSchema, LegacyKnowledgeLinkSchema]).transform((link) => {
20577
+ const target = "target" in link ? link.target : targetFromNodeId(link.nodeId);
20578
+ return {
20579
+ target,
20580
+ nodeId: nodeIdFromTarget(target)
20581
+ };
20606
20582
  });
20607
- var KnowledgeSkillBindingSchema = z.string().trim().min(1).max(120);
20608
- var KnowledgeDomainBindingSchema = z.string().trim().min(1).max(80);
20609
- var OrgKnowledgeKindSchema = z.enum(["playbook", "strategy", "reference"]);
20583
+ var OrgKnowledgeKindSchema = z.enum(["playbook", "strategy", "reference"]).meta({ label: "Knowledge kind", color: "grape" });
20610
20584
  var OrgKnowledgeNodeSchema = z.object({
20611
20585
  id: ModelIdSchema,
20612
20586
  kind: OrgKnowledgeKindSchema,
20613
20587
  title: z.string().trim().min(1).max(200),
20614
20588
  summary: z.string().trim().min(1).max(1e3),
20615
20589
  icon: IconNameSchema.optional(),
20590
+ /** Canonical documentation URL when body content is a local summary. */
20591
+ externalUrl: z.string().trim().url().max(500).optional(),
20616
20592
  /** Raw MDX string. Phase 2 will introduce a structured block format. */
20617
20593
  body: z.string().trim().min(1),
20618
20594
  /**
@@ -20620,36 +20596,154 @@ var OrgKnowledgeNodeSchema = z.object({
20620
20596
  * Each link emits a `governs` edge: knowledge-node -> target node.
20621
20597
  */
20622
20598
  links: z.array(KnowledgeLinkSchema).default([]),
20623
- /** Operator skill or command bindings relevant to this node. */
20624
- skills: z.array(KnowledgeSkillBindingSchema).optional(),
20625
- /** Domain key used to derive fast graph->skill registries. */
20626
- domain: KnowledgeDomainBindingSchema.optional(),
20627
- /** Identifiers of the roles or members who own this knowledge node. */
20628
- ownerIds: z.array(ModelIdSchema).default([]),
20599
+ /** Role identifiers that own this knowledge node. */
20600
+ ownerIds: z.array(RoleIdSchema.meta({ ref: "role" })).default([]),
20629
20601
  /** ISO date string (YYYY-MM-DD or full ISO 8601) of last meaningful update. */
20630
20602
  updatedAt: z.string().trim().min(1).max(50)
20631
20603
  });
20632
- var KnowledgeDomainSchema = z.object({
20633
- nodes: z.array(OrgKnowledgeNodeSchema).default([])
20604
+ var KnowledgeDomainSchema = z.record(ModelIdSchema, OrgKnowledgeNodeSchema).default({});
20605
+ var PolicyIdSchema = ModelIdSchema;
20606
+ var PolicyApplicabilitySchema = z.object({
20607
+ systemIds: z.array(ModelIdSchema.meta({ ref: "system" })).default([]),
20608
+ actionIds: z.array(ModelIdSchema.meta({ ref: "action" })).default([]),
20609
+ resourceIds: z.array(ModelIdSchema.meta({ ref: "resource" })).default([]),
20610
+ roleIds: z.array(ModelIdSchema.meta({ ref: "role" })).default([])
20634
20611
  });
20612
+ var PolicyTriggerSchema = z.discriminatedUnion("kind", [
20613
+ z.object({
20614
+ kind: z.literal("event"),
20615
+ eventId: EventIdSchema.meta({ ref: "event" })
20616
+ }),
20617
+ z.object({
20618
+ kind: z.literal("action-invocation"),
20619
+ actionId: ModelIdSchema.meta({ ref: "action" })
20620
+ }),
20621
+ z.object({
20622
+ kind: z.literal("schedule"),
20623
+ cron: z.string().trim().min(1).max(120)
20624
+ }),
20625
+ z.object({
20626
+ kind: z.literal("manual")
20627
+ })
20628
+ ]);
20629
+ var PolicyPredicateSchema = z.discriminatedUnion("kind", [
20630
+ z.object({
20631
+ kind: z.literal("always")
20632
+ }),
20633
+ z.object({
20634
+ kind: z.literal("expression"),
20635
+ expression: z.string().trim().min(1).max(2e3)
20636
+ }),
20637
+ z.object({
20638
+ kind: z.literal("threshold"),
20639
+ metric: ModelIdSchema,
20640
+ operator: z.enum(["lt", "lte", "eq", "gte", "gt"]).meta({ label: "Operator" }),
20641
+ value: z.number()
20642
+ })
20643
+ ]);
20644
+ var PolicyEffectSchema = z.discriminatedUnion("kind", [
20645
+ z.object({
20646
+ kind: z.literal("require-approval"),
20647
+ roleId: ModelIdSchema.meta({ ref: "role" }).optional()
20648
+ }),
20649
+ z.object({
20650
+ kind: z.literal("invoke-action"),
20651
+ actionId: ModelIdSchema.meta({ ref: "action" })
20652
+ }),
20653
+ z.object({
20654
+ kind: z.literal("notify-role"),
20655
+ roleId: ModelIdSchema.meta({ ref: "role" })
20656
+ }),
20657
+ z.object({
20658
+ kind: z.literal("block")
20659
+ })
20660
+ ]);
20661
+ var PolicySchema = z.object({
20662
+ id: PolicyIdSchema,
20663
+ /** Domain-map iteration order. Convention: multiples of 10 (10, 20, 30, ...) to allow easy insertion. */
20664
+ order: z.number(),
20665
+ label: LabelSchema,
20666
+ description: DescriptionSchema.optional(),
20667
+ trigger: PolicyTriggerSchema,
20668
+ predicate: PolicyPredicateSchema.default({ kind: "always" }),
20669
+ actions: z.array(PolicyEffectSchema).min(1),
20670
+ appliesTo: PolicyApplicabilitySchema.default({
20671
+ systemIds: [],
20672
+ actionIds: [],
20673
+ resourceIds: [],
20674
+ roleIds: []
20675
+ }),
20676
+ lifecycle: z.enum(["draft", "beta", "active", "deprecated", "archived"]).meta({ label: "Lifecycle", color: "teal" }).default("active")
20677
+ });
20678
+ var PoliciesDomainSchema = z.record(z.string(), PolicySchema).refine((record) => Object.entries(record).every(([key, entry]) => entry.id === key), {
20679
+ message: "Each policy entry id must match its map key"
20680
+ }).default({});
20681
+ var DEFAULT_ORGANIZATION_MODEL_POLICIES = {};
20635
20682
 
20636
20683
  // src/organization-model/schema.ts
20684
+ z.enum([
20685
+ "branding",
20686
+ "identity",
20687
+ "customers",
20688
+ "offerings",
20689
+ "roles",
20690
+ "goals",
20691
+ "systems",
20692
+ "resources",
20693
+ "actions",
20694
+ "entities",
20695
+ "policies",
20696
+ "knowledge"
20697
+ ]);
20698
+ var OrganizationModelDomainMetadataSchema = z.object({
20699
+ version: z.literal(1).default(1),
20700
+ lastModified: z.string().regex(/^\d{4}-\d{2}-\d{2}$/, "lastModified must be an ISO date string (YYYY-MM-DD)")
20701
+ });
20702
+ var DEFAULT_ORGANIZATION_MODEL_DOMAIN_METADATA = {
20703
+ branding: { version: 1, lastModified: "2026-05-10" },
20704
+ identity: { version: 1, lastModified: "2026-05-10" },
20705
+ customers: { version: 1, lastModified: "2026-05-10" },
20706
+ offerings: { version: 1, lastModified: "2026-05-10" },
20707
+ roles: { version: 1, lastModified: "2026-05-10" },
20708
+ goals: { version: 1, lastModified: "2026-05-10" },
20709
+ systems: { version: 1, lastModified: "2026-05-10" },
20710
+ resources: { version: 1, lastModified: "2026-05-10" },
20711
+ actions: { version: 1, lastModified: "2026-05-10" },
20712
+ entities: { version: 1, lastModified: "2026-05-10" },
20713
+ policies: { version: 1, lastModified: "2026-05-10" },
20714
+ knowledge: { version: 1, lastModified: "2026-05-10" }
20715
+ };
20716
+ var OrganizationModelDomainMetadataByDomainSchema = z.object({
20717
+ branding: OrganizationModelDomainMetadataSchema,
20718
+ identity: OrganizationModelDomainMetadataSchema,
20719
+ customers: OrganizationModelDomainMetadataSchema,
20720
+ offerings: OrganizationModelDomainMetadataSchema,
20721
+ roles: OrganizationModelDomainMetadataSchema,
20722
+ goals: OrganizationModelDomainMetadataSchema,
20723
+ systems: OrganizationModelDomainMetadataSchema,
20724
+ resources: OrganizationModelDomainMetadataSchema,
20725
+ actions: OrganizationModelDomainMetadataSchema,
20726
+ entities: OrganizationModelDomainMetadataSchema,
20727
+ policies: OrganizationModelDomainMetadataSchema,
20728
+ knowledge: OrganizationModelDomainMetadataSchema
20729
+ }).partial().default(DEFAULT_ORGANIZATION_MODEL_DOMAIN_METADATA).transform((metadata) => ({ ...DEFAULT_ORGANIZATION_MODEL_DOMAIN_METADATA, ...metadata }));
20637
20730
  var OrganizationModelSchemaBase = z.object({
20638
20731
  version: z.literal(1).default(1),
20639
- features: z.array(FeatureSchema).default([]),
20732
+ domainMetadata: OrganizationModelDomainMetadataByDomainSchema,
20640
20733
  branding: OrganizationModelBrandingSchema,
20641
- navigation: OrganizationModelNavigationSchema.default({ surfaces: [], groups: [] }),
20642
- sales: OrganizationModelSalesSchema,
20643
- prospecting: OrganizationModelProspectingSchema,
20644
- projects: OrganizationModelProjectsSchema,
20734
+ navigation: OrganizationModelNavigationSchema,
20645
20735
  identity: IdentityDomainSchema.default(DEFAULT_ORGANIZATION_MODEL_IDENTITY),
20646
20736
  customers: CustomersDomainSchema.default(DEFAULT_ORGANIZATION_MODEL_CUSTOMERS),
20647
20737
  offerings: OfferingsDomainSchema.default(DEFAULT_ORGANIZATION_MODEL_OFFERINGS),
20648
20738
  roles: RolesDomainSchema.default(DEFAULT_ORGANIZATION_MODEL_ROLES),
20649
20739
  goals: GoalsDomainSchema.default(DEFAULT_ORGANIZATION_MODEL_GOALS),
20650
- statuses: StatusesDomainSchema.default({ entries: [] }),
20651
- operations: OperationsDomainSchema.default({ entries: [] }),
20652
- knowledge: KnowledgeDomainSchema.default({ nodes: [] })
20740
+ systems: SystemsDomainSchema.default(DEFAULT_ORGANIZATION_MODEL_SYSTEMS),
20741
+ resources: ResourcesDomainSchema.default(DEFAULT_ORGANIZATION_MODEL_RESOURCES),
20742
+ actions: ActionsDomainSchema.default(DEFAULT_ORGANIZATION_MODEL_ACTIONS),
20743
+ entities: EntitiesDomainSchema.default(DEFAULT_ORGANIZATION_MODEL_ENTITIES),
20744
+ policies: PoliciesDomainSchema.default(DEFAULT_ORGANIZATION_MODEL_POLICIES),
20745
+ // D3: flat Record<id, OrgKnowledgeNode> — no wrapper object
20746
+ knowledge: KnowledgeDomainSchema.default({})
20653
20747
  });
20654
20748
  function addIssue(ctx, path, message) {
20655
20749
  ctx.addIssue({
@@ -20658,470 +20752,1245 @@ function addIssue(ctx, path, message) {
20658
20752
  message
20659
20753
  });
20660
20754
  }
20661
- function collectIds(items, ctx, collectionPath, label) {
20662
- const itemsById = /* @__PURE__ */ new Map();
20663
- items.forEach((item, index2) => {
20664
- if (itemsById.has(item.id)) {
20665
- addIssue(ctx, [...collectionPath, index2, "id"], `${label} id "${item.id}" must be unique`);
20666
- return;
20755
+ function isLifecycleEnabled(lifecycle, enabled) {
20756
+ if (enabled === false) return false;
20757
+ return lifecycle !== "deprecated" && lifecycle !== "archived";
20758
+ }
20759
+ function defaultSystemPathFor(id) {
20760
+ return `/${id.replaceAll(".", "/")}`;
20761
+ }
20762
+ function asRoleHolderArray(heldBy) {
20763
+ return Array.isArray(heldBy) ? heldBy : [heldBy];
20764
+ }
20765
+ function isKnowledgeKindCompatibleWithTarget(knowledgeKind, targetKind) {
20766
+ if (knowledgeKind === "reference") return true;
20767
+ if (knowledgeKind === "playbook") {
20768
+ return ["system", "resource", "stage", "action"].includes(targetKind);
20769
+ }
20770
+ if (knowledgeKind === "strategy") {
20771
+ return ["system", "goal", "offering", "customer-segment"].includes(targetKind);
20772
+ }
20773
+ return false;
20774
+ }
20775
+ var OrganizationModelSchema = OrganizationModelSchemaBase.superRefine((model, ctx) => {
20776
+ function collectAllSystems(systems, prefix = "", schemaPath = ["systems"]) {
20777
+ const result = [];
20778
+ for (const [key, system] of Object.entries(systems)) {
20779
+ const path = prefix ? `${prefix}.${key}` : key;
20780
+ const currentSchemaPath = [...schemaPath, key];
20781
+ result.push({ path, schemaPath: currentSchemaPath, system });
20782
+ if (system.subsystems !== void 0) {
20783
+ result.push(...collectAllSystems(system.subsystems, path, [...currentSchemaPath, "subsystems"]));
20784
+ }
20785
+ }
20786
+ return result;
20787
+ }
20788
+ const allSystems = collectAllSystems(model.systems);
20789
+ const systemsById = /* @__PURE__ */ new Map();
20790
+ for (const { path, system } of allSystems) {
20791
+ systemsById.set(path, system);
20792
+ systemsById.set(system.id, system);
20793
+ }
20794
+ const systemIdsByEffectivePath = /* @__PURE__ */ new Map();
20795
+ allSystems.forEach(({ path, schemaPath, system }) => {
20796
+ if (system.parentSystemId !== void 0 && !systemsById.has(system.parentSystemId)) {
20797
+ addIssue(
20798
+ ctx,
20799
+ [...schemaPath, "parentSystemId"],
20800
+ `System "${system.id}" references unknown parent "${system.parentSystemId}"`
20801
+ );
20802
+ }
20803
+ const hasChildren = Object.keys(system.subsystems ?? {}).length > 0 || allSystems.some((candidate) => candidate.path.startsWith(`${path}.`) && !candidate.path.slice(path.length + 1).includes("."));
20804
+ const contributesRoutePath = system.ui?.path !== void 0 || system.path !== void 0 || !hasChildren;
20805
+ if (contributesRoutePath) {
20806
+ const effectivePath = system.ui?.path ?? system.path ?? defaultSystemPathFor(path);
20807
+ const existingSystemId = systemIdsByEffectivePath.get(effectivePath);
20808
+ if (existingSystemId !== void 0) {
20809
+ addIssue(
20810
+ ctx,
20811
+ [...schemaPath, system.ui?.path !== void 0 ? "ui" : "path"],
20812
+ `System "${path}" effective path "${effectivePath}" duplicates system "${existingSystemId}"`
20813
+ );
20814
+ } else {
20815
+ systemIdsByEffectivePath.set(effectivePath, path);
20816
+ }
20817
+ }
20818
+ if (hasChildren && isLifecycleEnabled(system.lifecycle, system.enabled)) {
20819
+ const hasEnabledDescendant = Object.values(system.subsystems ?? {}).some(
20820
+ (candidate) => isLifecycleEnabled(candidate.lifecycle, candidate.enabled)
20821
+ ) || allSystems.some(
20822
+ (candidate) => candidate.path.startsWith(`${path}.`) && !candidate.path.slice(path.length + 1).includes(".") && isLifecycleEnabled(candidate.system.lifecycle, candidate.system.enabled)
20823
+ );
20824
+ if (!hasEnabledDescendant) {
20825
+ addIssue(
20826
+ ctx,
20827
+ [...schemaPath, "lifecycle"],
20828
+ `System "${path}" is active but has no active descendants`
20829
+ );
20830
+ }
20831
+ }
20832
+ });
20833
+ allSystems.forEach(({ schemaPath, system }) => {
20834
+ const visited = /* @__PURE__ */ new Set();
20835
+ let currentParentId = system.parentSystemId;
20836
+ while (currentParentId !== void 0) {
20837
+ if (currentParentId === system.id || visited.has(currentParentId)) {
20838
+ addIssue(ctx, [...schemaPath, "parentSystemId"], `System "${system.id}" has a parent cycle`);
20839
+ return;
20840
+ }
20841
+ visited.add(currentParentId);
20842
+ currentParentId = systemsById.get(currentParentId)?.parentSystemId;
20843
+ }
20844
+ });
20845
+ function normalizeRoutePath(path) {
20846
+ return path.length > 1 ? path.replace(/\/+$/, "") : path;
20847
+ }
20848
+ const sidebarNodeIds = /* @__PURE__ */ new Map();
20849
+ const sidebarSurfacePaths = /* @__PURE__ */ new Map();
20850
+ const sidebarSurfaces = [];
20851
+ function collectSidebarNodes(nodes, schemaPath) {
20852
+ Object.entries(nodes).forEach(([nodeId, node]) => {
20853
+ const nodePath = [...schemaPath, nodeId];
20854
+ const existingNodePath = sidebarNodeIds.get(nodeId);
20855
+ if (existingNodePath !== void 0) {
20856
+ addIssue(ctx, nodePath, `Sidebar node id "${nodeId}" duplicates another sidebar node`);
20857
+ } else {
20858
+ sidebarNodeIds.set(nodeId, nodePath);
20859
+ }
20860
+ if (node.type === "group") {
20861
+ collectSidebarNodes(node.children, [...nodePath, "children"]);
20862
+ return;
20863
+ }
20864
+ sidebarSurfaces.push({ id: nodeId, node, path: nodePath });
20865
+ const normalizedPath = normalizeRoutePath(node.path);
20866
+ const existingSurfaceId = sidebarSurfacePaths.get(normalizedPath);
20867
+ if (existingSurfaceId !== void 0) {
20868
+ addIssue(
20869
+ ctx,
20870
+ [...nodePath, "path"],
20871
+ `Sidebar surface path "${node.path}" duplicates surface "${existingSurfaceId}"`
20872
+ );
20873
+ } else {
20874
+ sidebarSurfacePaths.set(normalizedPath, nodeId);
20875
+ }
20876
+ node.targets?.systems?.forEach((systemId, systemIndex) => {
20877
+ if (!systemsById.has(systemId)) {
20878
+ addIssue(
20879
+ ctx,
20880
+ [...nodePath, "targets", "systems", systemIndex],
20881
+ `Sidebar surface "${nodeId}" references unknown system "${systemId}"`
20882
+ );
20883
+ }
20884
+ });
20885
+ });
20886
+ }
20887
+ collectSidebarNodes(model.navigation.sidebar.primary, ["navigation", "sidebar", "primary"]);
20888
+ collectSidebarNodes(model.navigation.sidebar.bottom, ["navigation", "sidebar", "bottom"]);
20889
+ const segmentsById = new Map(Object.entries(model.customers));
20890
+ Object.values(model.offerings).forEach((product) => {
20891
+ product.targetSegmentIds.forEach((segmentId, segmentIndex) => {
20892
+ if (!segmentsById.has(segmentId)) {
20893
+ addIssue(
20894
+ ctx,
20895
+ ["offerings", product.id, "targetSegmentIds", segmentIndex],
20896
+ `Product "${product.id}" references unknown customer segment "${segmentId}"`
20897
+ );
20898
+ }
20899
+ });
20900
+ if (product.deliveryFeatureId !== void 0 && !systemsById.has(product.deliveryFeatureId)) {
20901
+ addIssue(
20902
+ ctx,
20903
+ ["offerings", product.id, "deliveryFeatureId"],
20904
+ `Product "${product.id}" references unknown delivery system "${product.deliveryFeatureId}"`
20905
+ );
20906
+ }
20907
+ });
20908
+ Object.values(model.goals).forEach((objective) => {
20909
+ if (objective.periodEnd <= objective.periodStart) {
20910
+ addIssue(
20911
+ ctx,
20912
+ ["goals", objective.id, "periodEnd"],
20913
+ `Goal "${objective.id}" has periodEnd "${objective.periodEnd}" which must be strictly after periodStart "${objective.periodStart}"`
20914
+ );
20667
20915
  }
20668
- itemsById.set(item.id, item);
20669
20916
  });
20670
- return itemsById;
20671
- }
20672
- var LEGACY_FEATURE_ALIASES = /* @__PURE__ */ new Map([
20673
- ["crm", "sales.crm"],
20674
- ["lead-gen", "sales.lead-gen"],
20675
- ["submitted-requests", "monitoring.submitted-requests"]
20676
- ]);
20677
- function hasFeature(featuresById, featureId) {
20678
- return featuresById.has(featureId) || featuresById.has(LEGACY_FEATURE_ALIASES.get(featureId) ?? "");
20679
- }
20680
- function defaultFeaturePathFor(id) {
20681
- return `/${id.replaceAll(".", "/")}`;
20682
- }
20683
- var OrganizationModelSchema = OrganizationModelSchemaBase.superRefine((model, ctx) => {
20684
- const featuresById = collectIds(model.features, ctx, ["features"], "Feature");
20685
- const featureIdsByEffectivePath = /* @__PURE__ */ new Map();
20686
- model.features.forEach((feature, featureIndex) => {
20687
- const segments = feature.id.split(".");
20688
- if (segments.length > 1) {
20689
- const parentId = segments.slice(0, -1).join(".");
20690
- if (!featuresById.has(parentId)) {
20917
+ const goalsById = new Map(Object.entries(model.goals));
20918
+ const knowledgeById = new Map(Object.entries(model.knowledge));
20919
+ const actionsById = new Map(Object.entries(model.actions));
20920
+ const entitiesById = new Map(Object.entries(model.entities));
20921
+ const policiesById = new Map(Object.entries(model.policies));
20922
+ sidebarSurfaces.forEach(({ id, node, path }) => {
20923
+ node.targets?.entities?.forEach((entityId, entityIndex) => {
20924
+ if (!entitiesById.has(entityId)) {
20691
20925
  addIssue(
20692
20926
  ctx,
20693
- ["features", featureIndex, "id"],
20694
- `Feature "${feature.id}" references unknown parent "${parentId}"`
20927
+ [...path, "targets", "entities", entityIndex],
20928
+ `Sidebar surface "${id}" references unknown entity "${entityId}"`
20695
20929
  );
20696
20930
  }
20697
- }
20698
- const hasChildren = model.features.some(
20699
- (candidate) => candidate.id.startsWith(`${feature.id}.`) && candidate.id !== feature.id
20700
- );
20701
- const contributesRoutePath = feature.path !== void 0 || !hasChildren;
20702
- if (contributesRoutePath) {
20703
- const effectivePath = feature.path ?? defaultFeaturePathFor(feature.id);
20704
- const existingFeatureId = featureIdsByEffectivePath.get(effectivePath);
20705
- if (existingFeatureId !== void 0) {
20931
+ });
20932
+ node.targets?.actions?.forEach((actionId, actionIndex) => {
20933
+ if (!actionsById.has(actionId)) {
20706
20934
  addIssue(
20707
20935
  ctx,
20708
- ["features", featureIndex, feature.path === void 0 ? "id" : "path"],
20709
- `Feature "${feature.id}" effective path "${effectivePath}" duplicates feature "${existingFeatureId}"`
20936
+ [...path, "targets", "actions", actionIndex],
20937
+ `Sidebar surface "${id}" references unknown action "${actionId}"`
20710
20938
  );
20711
- } else {
20712
- featureIdsByEffectivePath.set(effectivePath, feature.id);
20713
20939
  }
20714
- }
20715
- if (hasChildren && feature.enabled) {
20716
- const hasEnabledDescendant = model.features.some(
20717
- (candidate) => candidate.id.startsWith(`${feature.id}.`) && candidate.enabled
20940
+ });
20941
+ });
20942
+ Object.values(model.entities).forEach((entity) => {
20943
+ if (!systemsById.has(entity.ownedBySystemId)) {
20944
+ addIssue(
20945
+ ctx,
20946
+ ["entities", entity.id, "ownedBySystemId"],
20947
+ `Entity "${entity.id}" references unknown ownedBySystemId "${entity.ownedBySystemId}"`
20718
20948
  );
20719
- if (!hasEnabledDescendant) {
20949
+ }
20950
+ entity.links?.forEach((link, linkIndex) => {
20951
+ if (!entitiesById.has(link.toEntity)) {
20720
20952
  addIssue(
20721
20953
  ctx,
20722
- ["features", featureIndex, "enabled"],
20723
- `Feature "${feature.id}" is enabled but has no enabled descendants`
20954
+ ["entities", entity.id, "links", linkIndex, "toEntity"],
20955
+ `Entity "${entity.id}" links to unknown entity "${link.toEntity}"`
20724
20956
  );
20725
20957
  }
20958
+ });
20959
+ });
20960
+ const rolesById = new Map(Object.entries(model.roles));
20961
+ Object.values(model.roles).forEach((role) => {
20962
+ if (role.reportsToId !== void 0 && !rolesById.has(role.reportsToId)) {
20963
+ addIssue(
20964
+ ctx,
20965
+ ["roles", role.id, "reportsToId"],
20966
+ `Role "${role.id}" references unknown reportsToId "${role.reportsToId}"`
20967
+ );
20726
20968
  }
20727
20969
  });
20728
- const surfacesById = collectIds(model.navigation.surfaces, ctx, ["navigation", "surfaces"], "Navigation surface");
20729
- if (model.navigation.defaultSurfaceId !== void 0 && !surfacesById.has(model.navigation.defaultSurfaceId)) {
20730
- addIssue(
20731
- ctx,
20732
- ["navigation", "defaultSurfaceId"],
20733
- `Navigation defaultSurfaceId references unknown surface "${model.navigation.defaultSurfaceId}"`
20734
- );
20735
- }
20736
- model.navigation.groups.forEach((group, groupIndex) => {
20737
- group.surfaceIds.forEach((surfaceId, surfaceIndex) => {
20738
- if (!surfacesById.has(surfaceId)) {
20970
+ Object.values(model.roles).forEach((role) => {
20971
+ const visited = /* @__PURE__ */ new Set();
20972
+ let currentReportsToId = role.reportsToId;
20973
+ while (currentReportsToId !== void 0) {
20974
+ if (currentReportsToId === role.id || visited.has(currentReportsToId)) {
20975
+ addIssue(ctx, ["roles", role.id, "reportsToId"], `Role "${role.id}" has a reportsToId cycle`);
20976
+ return;
20977
+ }
20978
+ visited.add(currentReportsToId);
20979
+ currentReportsToId = rolesById.get(currentReportsToId)?.reportsToId;
20980
+ }
20981
+ });
20982
+ Object.values(model.roles).forEach((role) => {
20983
+ role.responsibleFor?.forEach((systemId, systemIndex) => {
20984
+ if (!systemsById.has(systemId)) {
20739
20985
  addIssue(
20740
20986
  ctx,
20741
- ["navigation", "groups", groupIndex, "surfaceIds", surfaceIndex],
20742
- `Navigation group "${group.id}" references unknown surface "${surfaceId}"`
20987
+ ["roles", role.id, "responsibleFor", systemIndex],
20988
+ `Role "${role.id}" references unknown responsibleFor system "${systemId}"`
20743
20989
  );
20744
20990
  }
20745
20991
  });
20746
20992
  });
20747
- model.navigation.surfaces.forEach((surface, surfaceIndex) => {
20748
- if (surface.featureId !== void 0 && !hasFeature(featuresById, surface.featureId)) {
20993
+ allSystems.forEach(({ schemaPath, system }) => {
20994
+ if (system.responsibleRoleId !== void 0 && !rolesById.has(system.responsibleRoleId)) {
20749
20995
  addIssue(
20750
20996
  ctx,
20751
- ["navigation", "surfaces", surfaceIndex, "featureId"],
20752
- `Navigation surface "${surface.id}" references unknown feature "${surface.featureId}"`
20997
+ [...schemaPath, "responsibleRoleId"],
20998
+ `System "${system.id}" references unknown responsibleRoleId "${system.responsibleRoleId}"`
20753
20999
  );
20754
21000
  }
20755
- surface.featureIds.forEach((featureId, featureIndex) => {
20756
- if (!hasFeature(featuresById, featureId)) {
21001
+ system.governedByKnowledge?.forEach((nodeId, nodeIndex) => {
21002
+ if (!knowledgeById.has(nodeId)) {
21003
+ addIssue(
21004
+ ctx,
21005
+ [...schemaPath, "governedByKnowledge", nodeIndex],
21006
+ `System "${system.id}" references unknown knowledge node "${nodeId}"`
21007
+ );
21008
+ }
21009
+ });
21010
+ system.drivesGoals?.forEach((goalId, goalIndex) => {
21011
+ if (!goalsById.has(goalId)) {
21012
+ addIssue(
21013
+ ctx,
21014
+ [...schemaPath, "drivesGoals", goalIndex],
21015
+ `System "${system.id}" references unknown goal "${goalId}"`
21016
+ );
21017
+ }
21018
+ });
21019
+ system.actions?.forEach((actionRef, actionIndex) => {
21020
+ if (!actionsById.has(actionRef.actionId)) {
21021
+ addIssue(
21022
+ ctx,
21023
+ [...schemaPath, "actions", actionIndex, "actionId"],
21024
+ `System "${system.id}" references unknown action "${actionRef.actionId}"`
21025
+ );
21026
+ }
21027
+ });
21028
+ system.policies?.forEach((policyId, policyIndex) => {
21029
+ if (!policiesById.has(policyId)) {
20757
21030
  addIssue(
20758
21031
  ctx,
20759
- ["navigation", "surfaces", surfaceIndex, "featureIds", featureIndex],
20760
- `Navigation surface "${surface.id}" references unknown feature "${featureId}"`
21032
+ [...schemaPath, "policies", policyIndex],
21033
+ `System "${system.id}" references unknown policy "${policyId}"`
20761
21034
  );
20762
21035
  }
20763
21036
  });
20764
21037
  });
20765
- const segmentsById = new Map(model.customers.segments.map((seg) => [seg.id, seg]));
20766
- model.offerings.products.forEach((product, productIndex) => {
20767
- product.targetSegmentIds.forEach((segmentId, segmentIndex) => {
20768
- if (!segmentsById.has(segmentId)) {
21038
+ Object.values(model.actions).forEach((action) => {
21039
+ action.affects?.forEach((entityId, entityIndex) => {
21040
+ if (!entitiesById.has(entityId)) {
20769
21041
  addIssue(
20770
21042
  ctx,
20771
- ["offerings", "products", productIndex, "targetSegmentIds", segmentIndex],
20772
- `Product "${product.id}" references unknown customer segment "${segmentId}"`
21043
+ ["actions", action.id, "affects", entityIndex],
21044
+ `Action "${action.id}" affects unknown entity "${entityId}"`
21045
+ );
21046
+ }
21047
+ });
21048
+ });
21049
+ const resourcesById = new Map(Object.entries(model.resources));
21050
+ sidebarSurfaces.forEach(({ id, node, path }) => {
21051
+ node.targets?.resources?.forEach((resourceId, resourceIndex) => {
21052
+ if (!resourcesById.has(resourceId)) {
21053
+ addIssue(
21054
+ ctx,
21055
+ [...path, "targets", "resources", resourceIndex],
21056
+ `Sidebar surface "${id}" references unknown resource "${resourceId}"`
21057
+ );
21058
+ }
21059
+ });
21060
+ });
21061
+ const stageIds = /* @__PURE__ */ new Set();
21062
+ const actionIds = new Set(Object.keys(model.actions));
21063
+ const offeringsById = new Map(Object.entries(model.offerings));
21064
+ Object.values(model.policies).forEach((policy) => {
21065
+ policy.appliesTo.systemIds.forEach((systemId, systemIndex) => {
21066
+ if (!systemsById.has(systemId)) {
21067
+ addIssue(
21068
+ ctx,
21069
+ ["policies", policy.id, "appliesTo", "systemIds", systemIndex],
21070
+ `Policy "${policy.id}" applies to unknown system "${systemId}"`
20773
21071
  );
20774
21072
  }
20775
21073
  });
20776
- if (product.deliveryFeatureId !== void 0 && !hasFeature(featuresById, product.deliveryFeatureId)) {
21074
+ policy.appliesTo.actionIds.forEach((actionId, actionIndex) => {
21075
+ if (!actionsById.has(actionId)) {
21076
+ addIssue(
21077
+ ctx,
21078
+ ["policies", policy.id, "appliesTo", "actionIds", actionIndex],
21079
+ `Policy "${policy.id}" applies to unknown action "${actionId}"`
21080
+ );
21081
+ }
21082
+ });
21083
+ policy.actions.forEach((action, actionIndex) => {
21084
+ if (action.kind === "invoke-action" && !actionsById.has(action.actionId)) {
21085
+ addIssue(
21086
+ ctx,
21087
+ ["policies", policy.id, "actions", actionIndex, "actionId"],
21088
+ `Policy "${policy.id}" invokes unknown action "${action.actionId}"`
21089
+ );
21090
+ }
21091
+ if ((action.kind === "notify-role" || action.kind === "require-approval") && action.roleId !== void 0 && !rolesById.has(action.roleId)) {
21092
+ addIssue(
21093
+ ctx,
21094
+ ["policies", policy.id, "actions", actionIndex, "roleId"],
21095
+ `Policy "${policy.id}" references unknown role "${action.roleId}"`
21096
+ );
21097
+ }
21098
+ });
21099
+ if (policy.trigger.kind === "action-invocation" && !actionsById.has(policy.trigger.actionId)) {
20777
21100
  addIssue(
20778
21101
  ctx,
20779
- ["offerings", "products", productIndex, "deliveryFeatureId"],
20780
- `Product "${product.id}" references unknown delivery feature "${product.deliveryFeatureId}"`
21102
+ ["policies", policy.id, "trigger", "actionId"],
21103
+ `Policy "${policy.id}" references unknown trigger action "${policy.trigger.actionId}"`
20781
21104
  );
20782
21105
  }
20783
21106
  });
20784
- model.goals.objectives.forEach((objective, index2) => {
20785
- if (objective.periodEnd <= objective.periodStart) {
21107
+ function knowledgeTargetExists(kind, id) {
21108
+ if (kind === "system") return systemsById.has(id);
21109
+ if (kind === "resource") return resourcesById.has(id);
21110
+ if (kind === "knowledge") return knowledgeById.has(id);
21111
+ if (kind === "stage") return stageIds.has(id);
21112
+ if (kind === "action") return actionIds.has(id);
21113
+ if (kind === "role") return rolesById.has(id);
21114
+ if (kind === "goal") return goalsById.has(id);
21115
+ if (kind === "customer-segment") return segmentsById.has(id);
21116
+ if (kind === "offering") return offeringsById.has(id);
21117
+ return false;
21118
+ }
21119
+ Object.entries(model.knowledge).forEach(([nodeId, node]) => {
21120
+ node.links.forEach((link, linkIndex) => {
21121
+ if (!knowledgeTargetExists(link.target.kind, link.target.id)) {
21122
+ addIssue(
21123
+ ctx,
21124
+ ["knowledge", nodeId, "links", linkIndex, "target"],
21125
+ `Knowledge node "${node.id}" references unknown ${link.target.kind} target "${link.target.id}"`
21126
+ );
21127
+ }
21128
+ if (!isKnowledgeKindCompatibleWithTarget(node.kind, link.target.kind)) {
21129
+ addIssue(
21130
+ ctx,
21131
+ ["knowledge", nodeId, "links", linkIndex, "target", "kind"],
21132
+ `Knowledge node "${node.id}" kind "${node.kind}" cannot govern ${link.target.kind} targets`
21133
+ );
21134
+ }
21135
+ });
21136
+ });
21137
+ Object.values(model.resources).forEach((resource) => {
21138
+ if (!systemsById.has(resource.systemPath)) {
20786
21139
  addIssue(
20787
21140
  ctx,
20788
- ["goals", "objectives", index2, "periodEnd"],
20789
- `Goal "${objective.id}" has periodEnd "${objective.periodEnd}" which must be strictly after periodStart "${objective.periodStart}"`
21141
+ ["resources", resource.id, "systemPath"],
21142
+ `Resource "${resource.id}" references unknown system path "${resource.systemPath}"`
20790
21143
  );
20791
21144
  }
20792
- });
20793
- const rolesById = new Map(model.roles.roles.map((role) => [role.id, role]));
20794
- model.roles.roles.forEach((role, roleIndex) => {
20795
- if (role.reportsToId !== void 0 && !rolesById.has(role.reportsToId)) {
21145
+ if (resource.ownerRoleId !== void 0 && !rolesById.has(resource.ownerRoleId)) {
20796
21146
  addIssue(
20797
21147
  ctx,
20798
- ["roles", "roles", roleIndex, "reportsToId"],
20799
- `Role "${role.id}" references unknown reportsToId "${role.reportsToId}"`
21148
+ ["resources", resource.id, "ownerRoleId"],
21149
+ `Resource "${resource.id}" references unknown ownerRoleId "${resource.ownerRoleId}"`
21150
+ );
21151
+ }
21152
+ if (resource.kind === "agent" && resource.actsAsRoleId !== void 0 && !rolesById.has(resource.actsAsRoleId)) {
21153
+ addIssue(
21154
+ ctx,
21155
+ ["resources", resource.id, "actsAsRoleId"],
21156
+ `Agent resource "${resource.id}" references unknown actsAsRoleId "${resource.actsAsRoleId}"`
20800
21157
  );
20801
21158
  }
20802
21159
  });
21160
+ Object.values(model.roles).forEach((role) => {
21161
+ if (role.heldBy === void 0) return;
21162
+ asRoleHolderArray(role.heldBy).forEach((holder, holderIndex) => {
21163
+ if (holder.kind !== "agent") return;
21164
+ const resource = resourcesById.get(holder.agentId);
21165
+ if (resource === void 0) {
21166
+ addIssue(
21167
+ ctx,
21168
+ ["roles", role.id, "heldBy", Array.isArray(role.heldBy) ? holderIndex : "agentId"],
21169
+ `Role "${role.id}" references unknown agent holder resource "${holder.agentId}"`
21170
+ );
21171
+ return;
21172
+ }
21173
+ if (resource.kind !== "agent") {
21174
+ addIssue(
21175
+ ctx,
21176
+ ["roles", role.id, "heldBy", Array.isArray(role.heldBy) ? holderIndex : "agentId"],
21177
+ `Role "${role.id}" agent holder "${holder.agentId}" must reference an agent resource`
21178
+ );
21179
+ }
21180
+ });
21181
+ });
21182
+ Object.entries(model.knowledge).forEach(([nodeId, node]) => {
21183
+ node.ownerIds.forEach((roleId, ownerIndex) => {
21184
+ if (!rolesById.has(roleId)) {
21185
+ addIssue(
21186
+ ctx,
21187
+ ["knowledge", nodeId, "ownerIds", ownerIndex],
21188
+ `Knowledge node "${node.id}" references unknown owner role "${roleId}"`
21189
+ );
21190
+ }
21191
+ });
21192
+ });
21193
+ function validateSystemContent(system, systemPath) {
21194
+ const content = system.content;
21195
+ if (content === void 0 || Object.keys(content).length === 0) {
21196
+ if (system.subsystems !== void 0) {
21197
+ Object.entries(system.subsystems).forEach(([childKey, child]) => {
21198
+ validateSystemContent(child, [...systemPath, "subsystems", childKey]);
21199
+ });
21200
+ }
21201
+ return;
21202
+ }
21203
+ Object.entries(content).forEach(([localId, node]) => {
21204
+ if (node.parentContentId !== void 0 && !(node.parentContentId in content)) {
21205
+ addIssue(
21206
+ ctx,
21207
+ [...systemPath, "content", localId, "parentContentId"],
21208
+ `Content node "${localId}" parentContentId "${node.parentContentId}" does not resolve within the same system`
21209
+ );
21210
+ }
21211
+ });
21212
+ Object.entries(content).forEach(([localId, node]) => {
21213
+ const visited = /* @__PURE__ */ new Set();
21214
+ let currentId = node.parentContentId;
21215
+ while (currentId !== void 0) {
21216
+ if (currentId === localId || visited.has(currentId)) {
21217
+ addIssue(
21218
+ ctx,
21219
+ [...systemPath, "content", localId, "parentContentId"],
21220
+ `Content node "${localId}" has a parentContentId cycle`
21221
+ );
21222
+ break;
21223
+ }
21224
+ visited.add(currentId);
21225
+ currentId = content[currentId]?.parentContentId;
21226
+ }
21227
+ });
21228
+ Object.entries(content).forEach(([localId, node]) => {
21229
+ const childDef = lookupContentType(node.kind, node.type);
21230
+ if (childDef !== void 0 && node.data !== void 0) {
21231
+ const result = childDef.payloadSchema.safeParse(node.data);
21232
+ if (!result.success) {
21233
+ addIssue(
21234
+ ctx,
21235
+ [...systemPath, "content", localId, "data"],
21236
+ `Content node "${localId}" (${node.kind}:${node.type}) data failed payload validation: ${result.error.message}`
21237
+ );
21238
+ }
21239
+ }
21240
+ if (node.parentContentId !== void 0 && childDef !== void 0) {
21241
+ const parentNode = content[node.parentContentId];
21242
+ if (parentNode !== void 0) {
21243
+ const parentDef = lookupContentType(parentNode.kind, parentNode.type);
21244
+ if (parentDef !== void 0 && childDef.kind !== parentDef.kind) {
21245
+ addIssue(
21246
+ ctx,
21247
+ [...systemPath, "content", localId, "parentContentId"],
21248
+ `Content node "${localId}" kind "${childDef.kind}" cannot parent under "${node.parentContentId}" kind "${parentDef.kind}": parentContentId must be same-meta-kind (per L19)`
21249
+ );
21250
+ }
21251
+ }
21252
+ }
21253
+ });
21254
+ if (system.subsystems !== void 0) {
21255
+ Object.entries(system.subsystems).forEach(([childKey, child]) => {
21256
+ validateSystemContent(child, [...systemPath, "subsystems", childKey]);
21257
+ });
21258
+ }
21259
+ }
21260
+ Object.entries(model.systems).forEach(([systemKey, system]) => {
21261
+ validateSystemContent(system, ["systems", systemKey]);
21262
+ });
20803
21263
  });
20804
21264
 
20805
21265
  // src/organization-model/defaults.ts
20806
- var DEFAULT_ORGANIZATION_MODEL_KNOWLEDGE = {
20807
- nodes: []
21266
+ var DEFAULT_ORGANIZATION_MODEL_KNOWLEDGE = {};
21267
+ var DEFAULT_ORGANIZATION_MODEL_ENTITIES2 = DEFAULT_ORGANIZATION_MODEL_ENTITIES;
21268
+ var DEFAULT_ORGANIZATION_MODEL_NAVIGATION = {
21269
+ sidebar: {
21270
+ primary: {
21271
+ dashboard: {
21272
+ type: "surface",
21273
+ label: "Dashboard",
21274
+ path: "/",
21275
+ surfaceType: "dashboard",
21276
+ icon: "feature.dashboard",
21277
+ order: 10,
21278
+ targets: { systems: ["dashboard"] }
21279
+ },
21280
+ business: {
21281
+ type: "group",
21282
+ label: "Business",
21283
+ icon: "feature.business",
21284
+ order: 20,
21285
+ children: {
21286
+ sales: {
21287
+ type: "surface",
21288
+ label: "Sales",
21289
+ path: "/sales",
21290
+ surfaceType: "page",
21291
+ icon: "feature.sales",
21292
+ order: 10,
21293
+ targets: { systems: ["sales"] }
21294
+ },
21295
+ clients: {
21296
+ type: "surface",
21297
+ label: "Clients",
21298
+ path: "/clients",
21299
+ surfaceType: "list",
21300
+ icon: "feature.projects",
21301
+ order: 20,
21302
+ targets: { systems: ["clients"] }
21303
+ },
21304
+ projects: {
21305
+ type: "surface",
21306
+ label: "Projects",
21307
+ path: "/projects",
21308
+ surfaceType: "page",
21309
+ icon: "feature.projects",
21310
+ order: 30,
21311
+ targets: { systems: ["projects"] }
21312
+ }
21313
+ }
21314
+ },
21315
+ operations: {
21316
+ type: "group",
21317
+ label: "Operations",
21318
+ icon: "feature.operations",
21319
+ order: 30,
21320
+ children: {
21321
+ "operations-overview": {
21322
+ type: "surface",
21323
+ label: "Overview",
21324
+ path: "/operations",
21325
+ surfaceType: "page",
21326
+ order: 10,
21327
+ targets: { systems: ["operations.overview"] }
21328
+ },
21329
+ "operations-systems": {
21330
+ type: "surface",
21331
+ label: "Systems",
21332
+ path: "/operations/systems",
21333
+ surfaceType: "page",
21334
+ order: 20,
21335
+ targets: { systems: ["operations"] }
21336
+ },
21337
+ "operations-resources": {
21338
+ type: "surface",
21339
+ label: "Resources",
21340
+ path: "/operations/resources",
21341
+ surfaceType: "list",
21342
+ order: 30,
21343
+ targets: { systems: ["operations.resources"] }
21344
+ },
21345
+ "operations-command-queue": {
21346
+ type: "surface",
21347
+ label: "Command Queue",
21348
+ path: "/operations/command-queue",
21349
+ surfaceType: "list",
21350
+ order: 40,
21351
+ targets: { systems: ["operations.command-queue"] }
21352
+ },
21353
+ "operations-task-scheduler": {
21354
+ type: "surface",
21355
+ label: "Task Scheduler",
21356
+ path: "/operations/task-scheduler",
21357
+ surfaceType: "list",
21358
+ order: 50,
21359
+ targets: { systems: ["operations.task-scheduler"] }
21360
+ }
21361
+ }
21362
+ },
21363
+ monitoring: {
21364
+ type: "group",
21365
+ label: "Monitoring",
21366
+ icon: "feature.monitoring",
21367
+ order: 40,
21368
+ children: {
21369
+ "monitoring-overview": {
21370
+ type: "surface",
21371
+ label: "Overview",
21372
+ path: "/monitoring",
21373
+ surfaceType: "page",
21374
+ order: 10,
21375
+ targets: { systems: ["monitoring"] }
21376
+ },
21377
+ "monitoring-calendar": {
21378
+ type: "surface",
21379
+ label: "Calendar",
21380
+ path: "/monitoring/calendar",
21381
+ surfaceType: "page",
21382
+ order: 20,
21383
+ targets: { systems: ["monitoring.calendar"] }
21384
+ },
21385
+ "monitoring-activity-log": {
21386
+ type: "surface",
21387
+ label: "Activity Log",
21388
+ path: "/monitoring/activity-log",
21389
+ surfaceType: "list",
21390
+ order: 30,
21391
+ targets: { systems: ["monitoring.activity-log"] }
21392
+ },
21393
+ "monitoring-execution-logs": {
21394
+ type: "surface",
21395
+ label: "Execution Logs",
21396
+ path: "/monitoring/execution-logs",
21397
+ surfaceType: "list",
21398
+ order: 40,
21399
+ targets: { systems: ["monitoring.execution-logs"] }
21400
+ },
21401
+ "monitoring-execution-health": {
21402
+ type: "surface",
21403
+ label: "Execution Health",
21404
+ path: "/monitoring/execution-health",
21405
+ surfaceType: "dashboard",
21406
+ order: 50,
21407
+ targets: { systems: ["monitoring.execution-health"] }
21408
+ },
21409
+ "monitoring-notifications": {
21410
+ type: "surface",
21411
+ label: "Notifications",
21412
+ path: "/monitoring/notifications",
21413
+ surfaceType: "list",
21414
+ order: 60,
21415
+ targets: { systems: ["monitoring.notifications"] }
21416
+ },
21417
+ "monitoring-requests": {
21418
+ type: "surface",
21419
+ label: "Requests",
21420
+ path: "/monitoring/requests",
21421
+ surfaceType: "list",
21422
+ order: 70,
21423
+ targets: { systems: ["monitoring.submitted-requests"] }
21424
+ }
21425
+ }
21426
+ },
21427
+ knowledge: {
21428
+ type: "group",
21429
+ label: "Knowledge",
21430
+ icon: "feature.knowledge",
21431
+ order: 50,
21432
+ children: {
21433
+ "knowledge-base": {
21434
+ type: "surface",
21435
+ label: "Knowledge Base",
21436
+ path: "/knowledge",
21437
+ surfaceType: "page",
21438
+ order: 10,
21439
+ targets: { systems: ["knowledge.base"] }
21440
+ },
21441
+ "knowledge-command-view": {
21442
+ type: "surface",
21443
+ label: "Command View",
21444
+ path: "/knowledge/command-view",
21445
+ surfaceType: "graph",
21446
+ order: 20,
21447
+ targets: { systems: ["knowledge.command-view"] },
21448
+ devOnly: true
21449
+ }
21450
+ }
21451
+ }
21452
+ },
21453
+ bottom: {
21454
+ settings: {
21455
+ type: "group",
21456
+ label: "Settings",
21457
+ icon: "feature.settings",
21458
+ order: 10,
21459
+ children: {
21460
+ "settings-account": {
21461
+ type: "surface",
21462
+ label: "Account",
21463
+ path: "/settings/account",
21464
+ surfaceType: "settings",
21465
+ order: 10,
21466
+ targets: { systems: ["settings.account"] }
21467
+ },
21468
+ "settings-appearance": {
21469
+ type: "surface",
21470
+ label: "Appearance",
21471
+ path: "/settings/appearance",
21472
+ surfaceType: "settings",
21473
+ order: 20,
21474
+ targets: { systems: ["settings.appearance"] }
21475
+ },
21476
+ "settings-roles": {
21477
+ type: "surface",
21478
+ label: "My Roles",
21479
+ path: "/settings/roles",
21480
+ surfaceType: "settings",
21481
+ order: 30,
21482
+ targets: { systems: ["settings.roles"] }
21483
+ },
21484
+ "settings-organization": {
21485
+ type: "surface",
21486
+ label: "Organization",
21487
+ path: "/settings/organization",
21488
+ surfaceType: "settings",
21489
+ order: 40,
21490
+ targets: { systems: ["settings.organization"] }
21491
+ },
21492
+ "settings-credentials": {
21493
+ type: "surface",
21494
+ label: "Credentials",
21495
+ path: "/settings/credentials",
21496
+ surfaceType: "settings",
21497
+ order: 50,
21498
+ targets: { systems: ["settings.credentials"] }
21499
+ },
21500
+ "settings-api-keys": {
21501
+ type: "surface",
21502
+ label: "API Keys",
21503
+ path: "/settings/api-keys",
21504
+ surfaceType: "settings",
21505
+ order: 60,
21506
+ targets: { systems: ["settings.api-keys"] }
21507
+ },
21508
+ "settings-webhooks": {
21509
+ type: "surface",
21510
+ label: "Webhooks",
21511
+ path: "/settings/webhooks",
21512
+ surfaceType: "settings",
21513
+ order: 70,
21514
+ targets: { systems: ["settings.webhooks"] }
21515
+ },
21516
+ "settings-deployments": {
21517
+ type: "surface",
21518
+ label: "Deployments",
21519
+ path: "/settings/deployments",
21520
+ surfaceType: "settings",
21521
+ order: 80,
21522
+ targets: { systems: ["settings.deployments"] }
21523
+ }
21524
+ }
21525
+ },
21526
+ admin: {
21527
+ type: "group",
21528
+ label: "Admin",
21529
+ icon: "feature.admin",
21530
+ order: 20,
21531
+ children: {
21532
+ "admin-dashboard": {
21533
+ type: "surface",
21534
+ label: "Dashboard",
21535
+ path: "/admin/dashboard",
21536
+ surfaceType: "dashboard",
21537
+ order: 10,
21538
+ targets: { systems: ["admin"] },
21539
+ requiresAdmin: true
21540
+ },
21541
+ "admin-system-health": {
21542
+ type: "surface",
21543
+ label: "System Health",
21544
+ path: "/admin/system-health",
21545
+ surfaceType: "dashboard",
21546
+ order: 20,
21547
+ targets: { systems: ["admin.system-health"] },
21548
+ requiresAdmin: true
21549
+ },
21550
+ "admin-organizations": {
21551
+ type: "surface",
21552
+ label: "Organizations",
21553
+ path: "/admin/organizations",
21554
+ surfaceType: "list",
21555
+ order: 30,
21556
+ targets: { systems: ["admin.organizations"] },
21557
+ requiresAdmin: true
21558
+ },
21559
+ "admin-users": {
21560
+ type: "surface",
21561
+ label: "Users",
21562
+ path: "/admin/users",
21563
+ surfaceType: "list",
21564
+ order: 40,
21565
+ targets: { systems: ["admin.users"] },
21566
+ requiresAdmin: true
21567
+ },
21568
+ "admin-design-showcase": {
21569
+ type: "surface",
21570
+ label: "Design Showcase",
21571
+ path: "/admin/design-showcase",
21572
+ surfaceType: "page",
21573
+ order: 50,
21574
+ targets: { systems: ["admin.design-showcase"] },
21575
+ requiresAdmin: true
21576
+ },
21577
+ "admin-debug": {
21578
+ type: "surface",
21579
+ label: "Debug",
21580
+ path: "/admin/debug",
21581
+ surfaceType: "page",
21582
+ order: 60,
21583
+ targets: { systems: ["admin.debug"] },
21584
+ requiresAdmin: true
21585
+ }
21586
+ }
21587
+ }
21588
+ }
21589
+ }
20808
21590
  };
20809
21591
  var DEFAULT_ORGANIZATION_MODEL = {
20810
21592
  version: 1,
20811
- features: [
20812
- {
21593
+ domainMetadata: DEFAULT_ORGANIZATION_MODEL_DOMAIN_METADATA,
21594
+ branding: DEFAULT_ORGANIZATION_MODEL_BRANDING,
21595
+ navigation: DEFAULT_ORGANIZATION_MODEL_NAVIGATION,
21596
+ identity: DEFAULT_ORGANIZATION_MODEL_IDENTITY,
21597
+ customers: DEFAULT_ORGANIZATION_MODEL_CUSTOMERS,
21598
+ offerings: DEFAULT_ORGANIZATION_MODEL_OFFERINGS,
21599
+ roles: DEFAULT_ORGANIZATION_MODEL_ROLES,
21600
+ goals: DEFAULT_ORGANIZATION_MODEL_GOALS,
21601
+ systems: {
21602
+ dashboard: {
20813
21603
  id: "dashboard",
21604
+ order: 10,
20814
21605
  label: "Dashboard",
20815
21606
  enabled: true,
21607
+ lifecycle: "active",
20816
21608
  path: "/",
20817
- icon: "feature.dashboard",
20818
- uiPosition: "sidebar-primary"
21609
+ icon: "feature.dashboard"
20819
21610
  },
20820
- {
20821
- id: "identity",
20822
- label: "Identity",
20823
- description: "Company identity, positioning, and market context",
20824
- enabled: true,
20825
- color: "indigo"
20826
- },
20827
- {
21611
+ platform: {
20828
21612
  id: "platform",
21613
+ order: 30,
20829
21614
  label: "Platform",
20830
21615
  description: "Elevasis platform architecture, capabilities, and implementation patterns",
20831
21616
  enabled: true,
21617
+ lifecycle: "active",
20832
21618
  color: "cyan",
20833
21619
  icon: "feature.platform"
20834
21620
  },
20835
- {
21621
+ finance: {
20836
21622
  id: "finance",
21623
+ order: 40,
20837
21624
  label: "Finance",
20838
21625
  description: "Finance operations, accounting, billing, reconciliation, and tax prep",
20839
21626
  enabled: true,
21627
+ lifecycle: "active",
20840
21628
  color: "green",
20841
21629
  icon: "feature.finance"
20842
21630
  },
20843
- {
21631
+ sales: {
20844
21632
  id: "sales",
21633
+ order: 60,
20845
21634
  label: "Sales",
20846
21635
  description: "Revenue workflows and customer acquisition",
20847
21636
  enabled: true,
21637
+ lifecycle: "active",
20848
21638
  color: "blue",
20849
21639
  icon: "feature.sales",
20850
- uiPosition: "sidebar-primary"
21640
+ path: "/sales"
20851
21641
  },
20852
- {
21642
+ "sales.crm": {
20853
21643
  id: "sales.crm",
21644
+ order: 70,
20854
21645
  label: "CRM",
20855
21646
  description: "Relationship pipeline and deal management",
20856
21647
  enabled: true,
21648
+ lifecycle: "active",
20857
21649
  color: "blue",
20858
21650
  icon: "feature.crm",
20859
21651
  path: "/crm"
20860
21652
  },
20861
- {
21653
+ "sales.lead-gen": {
20862
21654
  id: "sales.lead-gen",
21655
+ order: 80,
20863
21656
  label: "Lead Gen",
20864
21657
  description: "Prospecting, qualification, and outreach preparation",
20865
21658
  enabled: true,
21659
+ lifecycle: "active",
21660
+ actions: Object.values(DEFAULT_ORGANIZATION_MODEL_ACTIONS).map((action) => ({
21661
+ actionId: action.id,
21662
+ intent: "exposes"
21663
+ })),
20866
21664
  color: "cyan",
20867
21665
  icon: "feature.lead-gen",
20868
21666
  path: "/lead-gen"
20869
21667
  },
20870
- {
21668
+ projects: {
20871
21669
  id: "projects",
21670
+ order: 90,
20872
21671
  label: "Projects",
20873
21672
  description: "Projects, milestones, and client work execution",
20874
21673
  enabled: true,
21674
+ lifecycle: "active",
20875
21675
  color: "orange",
20876
21676
  icon: "feature.projects",
20877
- path: "/projects",
20878
- uiPosition: "sidebar-primary"
21677
+ path: "/projects"
20879
21678
  },
20880
- {
21679
+ clients: {
21680
+ id: "clients",
21681
+ order: 100,
21682
+ label: "Clients",
21683
+ description: "Client relationships, accounts, and business context",
21684
+ enabled: true,
21685
+ lifecycle: "active",
21686
+ color: "orange",
21687
+ icon: "feature.projects",
21688
+ path: "/clients"
21689
+ },
21690
+ operations: {
20881
21691
  id: "operations",
21692
+ order: 110,
20882
21693
  label: "Operations",
20883
21694
  description: "Operational resources, topology, and orchestration visibility",
20884
21695
  enabled: true,
21696
+ lifecycle: "active",
20885
21697
  color: "violet",
20886
- icon: "feature.operations",
20887
- uiPosition: "sidebar-primary"
21698
+ icon: "feature.operations"
20888
21699
  },
20889
- {
21700
+ "knowledge.command-view": {
20890
21701
  id: "knowledge.command-view",
21702
+ order: 120,
20891
21703
  label: "Command View",
20892
21704
  enabled: true,
21705
+ lifecycle: "active",
20893
21706
  path: "/knowledge/command-view",
20894
21707
  devOnly: true
20895
21708
  },
20896
- {
21709
+ "operations.overview": {
20897
21710
  id: "operations.overview",
21711
+ order: 130,
20898
21712
  label: "Overview",
20899
21713
  enabled: true,
21714
+ lifecycle: "active",
20900
21715
  path: "/operations"
20901
21716
  },
20902
- {
21717
+ "operations.resources": {
20903
21718
  id: "operations.resources",
21719
+ order: 140,
20904
21720
  label: "Resources",
20905
21721
  enabled: true,
21722
+ lifecycle: "active",
20906
21723
  path: "/operations/resources"
20907
21724
  },
20908
- {
21725
+ "operations.command-queue": {
20909
21726
  id: "operations.command-queue",
21727
+ order: 150,
20910
21728
  label: "Command Queue",
20911
21729
  enabled: true,
21730
+ lifecycle: "active",
20912
21731
  path: "/operations/command-queue"
20913
21732
  },
20914
- {
21733
+ "operations.sessions": {
20915
21734
  id: "operations.sessions",
21735
+ order: 160,
20916
21736
  label: "Sessions",
20917
21737
  enabled: false,
21738
+ lifecycle: "deprecated",
20918
21739
  path: "/operations/sessions"
20919
21740
  },
20920
- {
21741
+ "operations.task-scheduler": {
20921
21742
  id: "operations.task-scheduler",
21743
+ order: 170,
20922
21744
  label: "Task Scheduler",
20923
21745
  enabled: true,
21746
+ lifecycle: "active",
20924
21747
  path: "/operations/task-scheduler"
20925
21748
  },
20926
- {
21749
+ monitoring: {
20927
21750
  id: "monitoring",
21751
+ order: 180,
20928
21752
  label: "Monitoring",
20929
21753
  enabled: true,
20930
- uiPosition: "sidebar-primary"
21754
+ lifecycle: "active"
20931
21755
  },
20932
- {
21756
+ "monitoring.calendar": {
20933
21757
  id: "monitoring.calendar",
21758
+ order: 190,
20934
21759
  label: "Calendar",
20935
21760
  description: "Google Calendar events and agenda views",
20936
21761
  enabled: true,
21762
+ lifecycle: "active",
20937
21763
  path: "/monitoring/calendar",
20938
21764
  icon: "feature.calendar"
20939
21765
  },
20940
- {
21766
+ "monitoring.activity-log": {
20941
21767
  id: "monitoring.activity-log",
21768
+ order: 200,
20942
21769
  label: "Activity Log",
20943
21770
  enabled: true,
21771
+ lifecycle: "active",
20944
21772
  path: "/monitoring/activity-log"
20945
21773
  },
20946
- {
21774
+ "monitoring.execution-logs": {
20947
21775
  id: "monitoring.execution-logs",
21776
+ order: 210,
20948
21777
  label: "Execution Logs",
20949
21778
  enabled: true,
21779
+ lifecycle: "active",
20950
21780
  path: "/monitoring/execution-logs"
20951
21781
  },
20952
- {
21782
+ "monitoring.execution-health": {
20953
21783
  id: "monitoring.execution-health",
21784
+ order: 220,
20954
21785
  label: "Execution Health",
20955
21786
  enabled: true,
21787
+ lifecycle: "active",
20956
21788
  path: "/monitoring/execution-health"
20957
21789
  },
20958
- {
21790
+ "monitoring.cost-analytics": {
20959
21791
  id: "monitoring.cost-analytics",
21792
+ order: 230,
20960
21793
  label: "Cost Analytics",
20961
21794
  enabled: false,
21795
+ lifecycle: "deprecated",
20962
21796
  path: "/monitoring/cost-analytics"
20963
21797
  },
20964
- {
21798
+ "monitoring.notifications": {
20965
21799
  id: "monitoring.notifications",
21800
+ order: 240,
20966
21801
  label: "Notifications",
20967
21802
  enabled: true,
21803
+ lifecycle: "active",
20968
21804
  path: "/monitoring/notifications"
20969
21805
  },
20970
- {
21806
+ "monitoring.submitted-requests": {
20971
21807
  id: "monitoring.submitted-requests",
21808
+ order: 250,
20972
21809
  label: "Submitted Requests",
20973
21810
  enabled: true,
21811
+ lifecycle: "active",
20974
21812
  path: "/monitoring/requests"
20975
21813
  },
20976
- {
21814
+ settings: {
20977
21815
  id: "settings",
21816
+ order: 260,
20978
21817
  label: "Settings",
20979
21818
  enabled: true,
20980
- icon: "feature.settings",
20981
- uiPosition: "sidebar-bottom"
21819
+ lifecycle: "active",
21820
+ icon: "feature.settings"
20982
21821
  },
20983
- {
21822
+ "settings.account": {
20984
21823
  id: "settings.account",
21824
+ order: 270,
20985
21825
  label: "Account",
20986
21826
  enabled: true,
21827
+ lifecycle: "active",
20987
21828
  path: "/settings/account"
20988
21829
  },
20989
- {
21830
+ "settings.appearance": {
20990
21831
  id: "settings.appearance",
21832
+ order: 280,
20991
21833
  label: "Appearance",
20992
21834
  enabled: true,
21835
+ lifecycle: "active",
20993
21836
  path: "/settings/appearance"
20994
21837
  },
20995
- {
21838
+ "settings.roles": {
20996
21839
  id: "settings.roles",
21840
+ order: 290,
20997
21841
  label: "My Roles",
20998
21842
  enabled: true,
21843
+ lifecycle: "active",
20999
21844
  path: "/settings/roles"
21000
21845
  },
21001
- {
21846
+ "settings.organization": {
21002
21847
  id: "settings.organization",
21848
+ order: 300,
21003
21849
  label: "Organization",
21004
21850
  enabled: true,
21851
+ lifecycle: "active",
21005
21852
  path: "/settings/organization"
21006
21853
  },
21007
- {
21854
+ "settings.credentials": {
21008
21855
  id: "settings.credentials",
21856
+ order: 310,
21009
21857
  label: "Credentials",
21010
21858
  enabled: true,
21859
+ lifecycle: "active",
21011
21860
  path: "/settings/credentials"
21012
21861
  },
21013
- {
21862
+ "settings.api-keys": {
21014
21863
  id: "settings.api-keys",
21864
+ order: 320,
21015
21865
  label: "API Keys",
21016
21866
  enabled: true,
21867
+ lifecycle: "active",
21017
21868
  path: "/settings/api-keys"
21018
21869
  },
21019
- {
21870
+ "settings.webhooks": {
21020
21871
  id: "settings.webhooks",
21872
+ order: 330,
21021
21873
  label: "Webhooks",
21022
21874
  enabled: true,
21875
+ lifecycle: "active",
21023
21876
  path: "/settings/webhooks"
21024
21877
  },
21025
- {
21878
+ "settings.deployments": {
21026
21879
  id: "settings.deployments",
21880
+ order: 340,
21027
21881
  label: "Deployments",
21028
21882
  enabled: true,
21883
+ lifecycle: "active",
21029
21884
  path: "/settings/deployments"
21030
21885
  },
21031
- {
21886
+ admin: {
21032
21887
  id: "admin",
21888
+ order: 350,
21033
21889
  label: "Admin",
21034
21890
  enabled: true,
21891
+ lifecycle: "active",
21035
21892
  path: "/admin",
21036
21893
  icon: "feature.admin",
21037
- uiPosition: "sidebar-bottom",
21038
21894
  requiresAdmin: true
21039
21895
  },
21040
- {
21896
+ "admin.system-health": {
21041
21897
  id: "admin.system-health",
21898
+ order: 360,
21042
21899
  label: "System Health",
21043
21900
  enabled: true,
21901
+ lifecycle: "active",
21044
21902
  path: "/admin/system-health"
21045
21903
  },
21046
- {
21904
+ "admin.organizations": {
21047
21905
  id: "admin.organizations",
21906
+ order: 370,
21048
21907
  label: "Organizations",
21049
21908
  enabled: true,
21909
+ lifecycle: "active",
21050
21910
  path: "/admin/organizations"
21051
21911
  },
21052
- {
21912
+ "admin.users": {
21053
21913
  id: "admin.users",
21914
+ order: 380,
21054
21915
  label: "Users",
21055
21916
  enabled: true,
21917
+ lifecycle: "active",
21056
21918
  path: "/admin/users"
21057
21919
  },
21058
- {
21920
+ "admin.design-showcase": {
21059
21921
  id: "admin.design-showcase",
21922
+ order: 390,
21060
21923
  label: "Design Showcase",
21061
21924
  enabled: true,
21925
+ lifecycle: "active",
21062
21926
  path: "/admin/design-showcase"
21063
21927
  },
21064
- {
21928
+ "admin.debug": {
21065
21929
  id: "admin.debug",
21930
+ order: 400,
21066
21931
  label: "Debug",
21067
21932
  enabled: true,
21933
+ lifecycle: "active",
21068
21934
  path: "/admin/debug"
21069
21935
  },
21070
- {
21936
+ archive: {
21071
21937
  id: "archive",
21938
+ order: 410,
21072
21939
  label: "Archive",
21073
21940
  enabled: true,
21941
+ lifecycle: "active",
21074
21942
  path: "/archive",
21075
21943
  icon: "feature.archive",
21076
- uiPosition: "sidebar-bottom",
21077
21944
  devOnly: true
21078
21945
  },
21079
- {
21946
+ "archive.agent-chat": {
21080
21947
  id: "archive.agent-chat",
21948
+ order: 420,
21081
21949
  label: "Agent Chat",
21082
21950
  enabled: true,
21951
+ lifecycle: "active",
21083
21952
  path: "/archive/agent-chat"
21084
21953
  },
21085
- {
21954
+ "archive.execution-runner": {
21086
21955
  id: "archive.execution-runner",
21956
+ order: 430,
21087
21957
  label: "Execution Runner",
21088
21958
  enabled: true,
21959
+ lifecycle: "active",
21089
21960
  path: "/archive/execution-runner"
21090
21961
  },
21091
- {
21962
+ seo: {
21092
21963
  id: "seo",
21964
+ order: 440,
21093
21965
  label: "SEO",
21094
21966
  enabled: false,
21967
+ lifecycle: "deprecated",
21095
21968
  path: "/seo"
21096
21969
  },
21097
- {
21970
+ knowledge: {
21098
21971
  id: "knowledge",
21972
+ order: 450,
21099
21973
  label: "Knowledge",
21100
21974
  description: "Operational knowledge, playbooks, and strategy docs",
21101
21975
  enabled: true,
21976
+ lifecycle: "active",
21102
21977
  color: "teal",
21103
- icon: "feature.knowledge",
21104
- uiPosition: "sidebar-primary"
21978
+ icon: "feature.knowledge"
21105
21979
  },
21106
- {
21980
+ "knowledge.base": {
21107
21981
  id: "knowledge.base",
21982
+ order: 460,
21108
21983
  label: "Knowledge Base",
21109
21984
  enabled: true,
21985
+ lifecycle: "active",
21110
21986
  path: "/knowledge"
21111
21987
  }
21112
- ],
21113
- branding: DEFAULT_ORGANIZATION_MODEL_BRANDING,
21114
- navigation: { surfaces: [], groups: [] },
21115
- sales: DEFAULT_ORGANIZATION_MODEL_SALES,
21116
- prospecting: DEFAULT_ORGANIZATION_MODEL_PROSPECTING,
21117
- projects: DEFAULT_ORGANIZATION_MODEL_PROJECTS,
21118
- identity: DEFAULT_ORGANIZATION_MODEL_IDENTITY,
21119
- customers: DEFAULT_ORGANIZATION_MODEL_CUSTOMERS,
21120
- offerings: DEFAULT_ORGANIZATION_MODEL_OFFERINGS,
21121
- roles: DEFAULT_ORGANIZATION_MODEL_ROLES,
21122
- goals: DEFAULT_ORGANIZATION_MODEL_GOALS,
21123
- statuses: DEFAULT_ORGANIZATION_MODEL_STATUSES,
21124
- operations: DEFAULT_ORGANIZATION_MODEL_OPERATIONS,
21988
+ },
21989
+ resources: DEFAULT_ORGANIZATION_MODEL_RESOURCES,
21990
+ actions: DEFAULT_ORGANIZATION_MODEL_ACTIONS,
21991
+ entities: DEFAULT_ORGANIZATION_MODEL_ENTITIES2,
21992
+ policies: DEFAULT_ORGANIZATION_MODEL_POLICIES,
21993
+ // Phase 4 (D1): statuses top-level field removed; status data lives in system.content.
21125
21994
  knowledge: DEFAULT_ORGANIZATION_MODEL_KNOWLEDGE
21126
21995
  };
21127
21996
 
@@ -21149,14 +22018,7 @@ function deepMerge2(base, override) {
21149
22018
  }
21150
22019
  function resolveOrganizationModel(override, organizationId) {
21151
22020
  const merged = deepMerge2(DEFAULT_ORGANIZATION_MODEL, override);
21152
- const model = OrganizationModelSchema.parse(merged);
21153
- if (!model.sales?.pipelines || model.sales.pipelines.length === 0) {
21154
- const orgLabel = "Organization";
21155
- throw new Error(
21156
- `${orgLabel} has no sales pipeline configuration. This indicates an incomplete provisioning state. Run org provisioning to seed defaults.`
21157
- );
21158
- }
21159
- return model;
22021
+ return OrganizationModelSchema.parse(merged);
21160
22022
  }
21161
22023
 
21162
22024
  // src/test-utils/organization-model.ts