@synap-core/workspace-templates 0.7.1 → 0.7.3

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 (50) hide show
  1. package/dist/index.d.ts +266 -8
  2. package/dist/index.js +2314 -1440
  3. package/dist/index.js.map +1 -1
  4. package/package.json +4 -3
  5. package/src/agent-fleet.yaml +666 -108
  6. package/src/blockchain-ecosystem.yaml +1 -0
  7. package/src/brand-library.yaml +127 -12
  8. package/src/builder.yaml +116 -12
  9. package/src/business-developer.yaml +110 -18
  10. package/src/catalog.test.ts +2 -2
  11. package/src/catalog.ts +13 -3
  12. package/src/communication.yaml +23 -453
  13. package/src/composition-graph.test.ts +28 -2
  14. package/src/concept-guard.test.ts +176 -0
  15. package/src/concept-guard.ts +219 -0
  16. package/src/content-os.yaml +103 -10
  17. package/src/content-studio.yaml +1 -0
  18. package/src/crm.yaml +1 -0
  19. package/src/define.ts +8 -8
  20. package/src/dev-dashboard.yaml +43 -9
  21. package/src/domains.test.ts +117 -0
  22. package/src/domains.ts +102 -0
  23. package/src/ecosystem.yaml +25 -5
  24. package/src/enterprise-os.yaml +1 -0
  25. package/src/finance.yaml +46 -5
  26. package/src/foundation.yaml +13 -1
  27. package/src/generate.d.mts +15 -0
  28. package/src/generate.mjs +86 -0
  29. package/src/grants.yaml +1 -0
  30. package/src/hr.yaml +61 -8
  31. package/src/index.ts +40 -0
  32. package/src/internal-runbook.yaml +36 -5
  33. package/src/legal.yaml +97 -12
  34. package/src/life-os.yaml +188 -27
  35. package/src/marketing.yaml +15 -2
  36. package/src/meetings-knowledge.yaml +143 -23
  37. package/src/operations.yaml +347 -0
  38. package/src/outreach-comms.yaml +11 -3
  39. package/src/project-management.yaml +840 -111
  40. package/src/research-base.yaml +516 -0
  41. package/src/research-decision.yaml +158 -0
  42. package/src/shared-role-ssot.test.ts +268 -0
  43. package/src/social.yaml +105 -37
  44. package/src/templates-freshness.test.ts +55 -0
  45. package/src/templates.ts +4620 -4278
  46. package/src/the-arch.yaml +1 -0
  47. package/src/types.ts +9 -0
  48. package/src/validate.test.ts +81 -0
  49. package/src/validate.ts +561 -0
  50. package/src/personal.yaml +0 -177
package/dist/index.d.ts CHANGED
@@ -393,6 +393,15 @@ interface TemplateMeta {
393
393
  color: string;
394
394
  tags?: string[];
395
395
  isPublic?: boolean;
396
+ /**
397
+ * Human-facing subject area used to SECTION the marketplace (CLI `market
398
+ * list`, browser New Space + catalog). Authored here so grouping is a
399
+ * property of the template, read by every surface — never re-derived from a
400
+ * hardcoded slug→group map in a consumer. NOT `category` (that is the
401
+ * PACKAGE TYPE — `workspace`/`capability`/…). Optional and open: an unknown
402
+ * or missing value is grouped, never dropped — see `./domains.ts`.
403
+ */
404
+ domain?: string;
396
405
  }
397
406
  interface WorkspaceYaml {
398
407
  /** Template metadata — not sent to backend, used for listing/UI */
@@ -550,6 +559,8 @@ interface RemoteEntry {
550
559
  description?: string;
551
560
  /** CP package category / type (e.g. `"workspace"`, `"view"`). */
552
561
  category?: string;
562
+ /** Human-facing subject area for display grouping — authored on `meta.domain`. See `./domains.ts`. */
563
+ domain?: string;
553
564
  tags?: string[];
554
565
  icon?: string | null;
555
566
  /**
@@ -612,6 +623,8 @@ interface CpPackageRow {
612
623
  description?: string | null;
613
624
  /** CP package category / type (e.g. `"workspace"`, `"view"`). */
614
625
  category?: string;
626
+ /** Human-facing subject area for display grouping — from the package's `meta.domain`. */
627
+ domain?: string | null;
615
628
  tags?: string[] | null;
616
629
  icon?: string | null;
617
630
  /** Present only on `/mine` rows. `false` ⇒ private. Browse rows omit it. */
@@ -635,6 +648,8 @@ interface CatalogEntryBase {
635
648
  description?: string;
636
649
  /** Package category / type. Bundled templates are always `"workspace"`. */
637
650
  category?: string;
651
+ /** Human-facing subject area for display grouping — authored `meta.domain`. See ./domains. */
652
+ domain?: string;
638
653
  tags: string[];
639
654
  icon?: string | null;
640
655
  /** `true` ⇒ not publicly listed (internal bundled template, or private CP row). */
@@ -863,6 +878,250 @@ interface LayerTemplateGraphInput {
863
878
  declare function bundledEdgesOf(slug: string): readonly TemplateDependency[];
864
879
  declare function layerTemplateGraph(input: LayerTemplateGraphInput): CompositionGraph;
865
880
 
881
+ /**
882
+ * Cross-template CONCEPT guard — catches vocabulary forks between templates.
883
+ *
884
+ * WHY THIS EXISTS (read before weakening or deleting it):
885
+ * `business-developer.yaml` introduced workspace-scoped `crm-lead`/`crm-client`
886
+ * for the same real-world concept that `foundation.yaml`/`crm.yaml` declare as
887
+ * pod-wide shared `lead`/`client`. Nothing failed. Three reasons:
888
+ *
889
+ * 1. `build.mjs`'s `validate()` runs PER FILE, inside the read loop, so it
890
+ * structurally cannot see that another template already owns `lead`.
891
+ * 2. The only vocabulary rule that exists (`template-shared-role-ssot.test.ts`
892
+ * in synap-backend) polices a HARDCODED five-slug set — and it FORBIDS
893
+ * declaring one of those slugs workspace-scoped, which is exactly what the
894
+ * two-tier design legitimately needed. So RENAMING was the path of least
895
+ * resistance: `crm-lead` is outside the set and passes silently. That rule
896
+ * polices SPELLING, not MEANING.
897
+ * 3. That test also cannot run in CI — it resolves this package across a
898
+ * sibling-repo relative path that CI never checks out. It is green on a dev
899
+ * machine and mute everywhere else.
900
+ *
901
+ * This guard lives HERE, in the repo that owns the template source, and runs in
902
+ * this repo's CI (`pnpm test`) and in `pnpm build` / `prepublishOnly` via
903
+ * `scripts/check-concepts.mjs`. It is deliberately NOT a hardcoded slug list —
904
+ * that is the pattern that failed.
905
+ *
906
+ * WHAT IT DOES NOT DO: it does not guess. There is no fuzzy name matching, no
907
+ * edit distance, no synonym table. A guesser nobody trusts is worse than no
908
+ * guard. It uses two exact, falsifiable signals only — see the rules below.
909
+ */
910
+
911
+ interface ConceptViolation {
912
+ rule: "concept-collision" | "alias-shape-divergence" | "stale-allowlist";
913
+ /** The concept term or semantic slug the finding is about. */
914
+ concept: string;
915
+ message: string;
916
+ }
917
+ /**
918
+ * DECLARED, INTENTIONAL divergences — the escape hatch, and deliberately the
919
+ * SECONDARY mechanism. An entry here is an author saying "yes, two spellings of
920
+ * one concept, on purpose, and here is why". Keep it tiny; every entry must
921
+ * carry its WHY. A key that stops matching anything FAILS the guard, so this
922
+ * list cannot rot into a graveyard.
923
+ *
924
+ * Key = the two colliding profile slugs, sorted, joined by "|".
925
+ */
926
+ declare const DECLARED_DIVERGENCES: Record<string, string>;
927
+ /**
928
+ * The bare noun a concept identifier ends in: `crm.lead` → `lead`,
929
+ * `crm-lead` → `lead`, `lead` → `lead`.
930
+ *
931
+ * This is EXACT terminal-token equality on the author's own qualified name —
932
+ * not a similarity heuristic. `crm-lead` and `lead` collide because the author
933
+ * literally wrote the same noun; `prospect` and `lead` do not collide, and that
934
+ * is honest: no guard can know they mean the same thing.
935
+ */
936
+ declare function conceptTerm(semanticSlug: string): string;
937
+ declare function findConceptViolations(templates?: Record<string, WorkspaceYaml>): ConceptViolation[];
938
+ declare function formatConceptViolations(violations: ConceptViolation[]): string;
939
+
940
+ /**
941
+ * Template DOMAIN taxonomy — the authored, cross-surface grouping that sections
942
+ * the marketplace (CLI `market list`, browser New Space + catalog, marketplace).
943
+ *
944
+ * WHY A FIELD, NOT DERIVED FROM TAGS. Grouping is a property of the template, so
945
+ * it lives ON the template (`meta.domain`) — authored once, read by every
946
+ * surface. The alternative was a hardcoded slug→group map (or a tag heuristic)
947
+ * inside each consumer; that map drifts the instant a template is added, and no
948
+ * one authoring a template can see it. Same lesson as the vocabulary work: a
949
+ * declared relationship should live where it can be verified, not re-guessed.
950
+ *
951
+ * NOT `category`. The catalog already uses `category` for the PACKAGE TYPE
952
+ * (`workspace`/`capability`/`skill`/…). `domain` is the human subject area.
953
+ *
954
+ * WORKS FOR ANY TEMPLATE. A template may declare a domain absent from this
955
+ * registry, or none at all — `groupByDomain` never drops one. Known domains
956
+ * render first in registry order; an unknown-but-declared domain renders after
957
+ * them (its id title-cased); a missing domain falls into the `other` bucket,
958
+ * always last. So a NEW template appears correctly without touching this file —
959
+ * adding it here only controls a domain's ORDER and LABEL.
960
+ */
961
+ interface TemplateDomain {
962
+ id: string;
963
+ label: string;
964
+ }
965
+ declare const OTHER_DOMAIN_ID = "other";
966
+ declare const OTHER_DOMAIN_LABEL = "More";
967
+ /** Known domains, in display order (the order sections appear in a listing). */
968
+ declare const TEMPLATE_DOMAINS: readonly TemplateDomain[];
969
+ /** Every valid domain id the registry knows about (excludes `other`). */
970
+ declare function isKnownDomain(id: string | undefined | null): boolean;
971
+ /** Display label for a domain id. Missing → "More"; unknown-declared → title-cased id. */
972
+ declare function domainLabel(id: string | undefined | null): string;
973
+ interface DomainGroup<T> {
974
+ id: string;
975
+ label: string;
976
+ items: T[];
977
+ }
978
+ /**
979
+ * Partition `items` into ordered domain sections: known domains first (registry
980
+ * order), then unknown-but-declared domains (alphabetical), then the missing
981
+ * "More" bucket, always last. Empty sections are omitted; nothing is dropped.
982
+ * Item order WITHIN a section is preserved from the input.
983
+ */
984
+ declare function groupByDomain<T>(items: readonly T[], domainOf: (item: T) => string | undefined | null): DomainGroup<T>[];
985
+
986
+ /**
987
+ * The ONE importable template validator.
988
+ * ======================================
989
+ *
990
+ * Historically the only real per-template guards lived in build-only scripts
991
+ * OUTSIDE `src/` — `build.mjs`'s `validate()` and `scripts/check-converters.mjs`
992
+ * — so no other repo could call them. The CP publish path, the pod install/apply
993
+ * path, and the CLI all re-implemented (or skipped) these checks. This module
994
+ * moves the per-template rule logic into `src/`, as a PURE function that
995
+ * RETURNS structured results (never `process.exit`), so all four callers share
996
+ * ONE validator:
997
+ *
998
+ * • `build.mjs` — loops the corpus, exits non-zero on errors.
999
+ * • `scripts/check-converters.mjs` — injects the real converters, exits non-zero.
1000
+ * • CP / pod / CLI (from dist) — import `validateTemplate` + `SYSTEM_PROFILES`.
1001
+ *
1002
+ * ZERO RUNTIME IMPORTS BY DESIGN. `build.mjs` loads this file directly under
1003
+ * Node's type-stripping BEFORE `tsup` builds `dist/`. A static
1004
+ * `import { toWorkspaceDefinition } from "./define.js"` would fail to resolve at
1005
+ * that moment (define → templates.js does not exist pre-build, and Node's
1006
+ * type-stripper does not remap a `.js` specifier to its `.ts` source). So the
1007
+ * converters are INJECTED via `opts.converters` rather than imported: the pure
1008
+ * YAML/bento rules run everywhere; the converter-parity rules run wherever the
1009
+ * caller can supply the compiled converters (check-converters.mjs, from dist).
1010
+ * `import type` lines are fully erased by the type-stripper, so they are safe.
1011
+ */
1012
+
1013
+ interface ValidationError {
1014
+ /** Stable machine code for the rule that fired (e.g. "profile-ref-unknown"). */
1015
+ rule: string;
1016
+ /** Dotted location inside the template, for error messages. */
1017
+ path: string;
1018
+ /** Human-readable description of the violation. */
1019
+ message: string;
1020
+ }
1021
+ interface ValidateResult {
1022
+ ok: boolean;
1023
+ errors: ValidationError[];
1024
+ }
1025
+ /**
1026
+ * Structural view of the two converters, INJECTED (not imported) — see the file
1027
+ * header. `check-converters.mjs` passes the real `toWorkspaceDefinition` /
1028
+ * `toPackageDefinition` from `dist/`; their concrete types are structurally
1029
+ * compatible with these minimal shapes.
1030
+ */
1031
+ interface TemplateConverters {
1032
+ toWorkspaceDefinition: (tpl: WorkspaceYaml) => {
1033
+ definition: {
1034
+ bentoLayout?: Array<{
1035
+ widgetType?: unknown;
1036
+ }>;
1037
+ bentoViewBlocks?: Array<{
1038
+ viewName?: unknown;
1039
+ kind?: unknown;
1040
+ }>;
1041
+ bentoViewName?: string;
1042
+ capabilities?: unknown[];
1043
+ };
1044
+ };
1045
+ toPackageDefinition: (tpl: WorkspaceYaml) => {
1046
+ bentoLayout?: Array<{
1047
+ widgetType?: unknown;
1048
+ }>;
1049
+ bentoViewBlocks?: Array<{
1050
+ viewName?: unknown;
1051
+ kind?: unknown;
1052
+ }>;
1053
+ bentoViewName?: string;
1054
+ capabilities?: unknown[];
1055
+ };
1056
+ }
1057
+ interface ValidateOptions {
1058
+ /**
1059
+ * The whole corpus (parsed template data objects). Used to resolve a
1060
+ * `compose`/`require` base's profile vocabulary. Keyed by `meta.slug`. Ignored
1061
+ * when `resolveDep` is given.
1062
+ */
1063
+ corpus?: WorkspaceYaml[];
1064
+ /** Direct dependency resolver — supersedes `corpus` when provided. */
1065
+ resolveDep?: (slug: string) => WorkspaceYaml | undefined;
1066
+ /**
1067
+ * Compiled converters. When present, the converter-parity rules run (bento
1068
+ * union split, wire-field shape, bentoViewName + capabilities parity across
1069
+ * both install doors). When absent, only the pure YAML/bento rules run.
1070
+ */
1071
+ converters?: TemplateConverters;
1072
+ }
1073
+ declare const REQUIRED_META_FIELDS: readonly ["slug", "name", "description", "icon", "color"];
1074
+ declare const REQUIRED_WORKSPACE_FIELDS: readonly ["name", "description"];
1075
+ /**
1076
+ * System profiles a template may reference without defining. This MUST mirror
1077
+ * the profiles seeded by synap-backend `ensure-system-profiles.ts` (the
1078
+ * `profiles` array) — that seeder is the ground truth for what exists on every
1079
+ * pod. A slug present here but NOT seeded lets a dangling ref validate green (the
1080
+ * old bug: `project`/`document` were listed here after both were removed from the
1081
+ * seeder — `project` became a first-class table in migration 0151, `document`
1082
+ * never existed as a profile). A slug seeded but MISSING here forces every
1083
+ * template to re-declare it, which is the exact pressure that spawns vocabulary
1084
+ * forks. Keep the two lists in lockstep.
1085
+ *
1086
+ * SINGLE SOURCE OF TRUTH: this set lived in build.mjs; it now lives HERE and
1087
+ * build.mjs imports it, so there is one list to keep in lockstep with the seeder.
1088
+ */
1089
+ declare const SYSTEM_PROFILES: Set<string>;
1090
+ /**
1091
+ * Profile slugs a template may reference by virtue of its dependencies.
1092
+ *
1093
+ * `compose` and `require` are NOT the same for what a consumer may reference:
1094
+ * • `compose` MERGES the overlay into the base's ONE workspace, so the consumer
1095
+ * legitimately references ALL of the base's profiles (workspace-scoped ones
1096
+ * included) — that is the point of composing.
1097
+ * • `require` creates a SEPARATE workspace (installed first). Only the base's
1098
+ * POD-WIDE profiles (`scope: shared`; system profiles are handled separately)
1099
+ * cross that boundary and are visible to the consumer. The base's
1100
+ * `scope: WORKSPACE` profiles live in the base's OWN workspace and resolve
1101
+ * against NOTHING when referenced across a `require` — that is the class of
1102
+ * bug the social→content-os fork hit (a view/link/prop pointing at the base's
1103
+ * workspace-scoped profile provisions dangling and throws at runtime).
1104
+ *
1105
+ * Resolved TRANSITIVELY (a base's own bases count too, each by its own relation).
1106
+ * Without this the validator is per-file and a real overlay can only reference
1107
+ * system profiles + its own (blocks e.g. communication composing on brand-library).
1108
+ *
1109
+ * Moved verbatim out of build.mjs (semantics unchanged); it now resolves bases
1110
+ * through the injected `resolveDep` rather than a hand-built `dataBySlug` map, so
1111
+ * the same closure serves every caller.
1112
+ */
1113
+ declare function collectBaseProfileSlugs(data: WorkspaceYaml, resolveDep: (slug: string) => WorkspaceYaml | undefined, seen?: Set<string>): Set<string>;
1114
+ /**
1115
+ * Validate ONE template. Pure: returns `{ ok, errors }`, never exits. Covers the
1116
+ * per-template rules formerly split across build.mjs `validate()` (required
1117
+ * fields, ≥1 profile, structured-view-needs-scope, profileSlug referential
1118
+ * integrity against `own ∪ SYSTEM_PROFILES ∪ dependency-vocab`, overlay safety,
1119
+ * entityLink `type`) and check-converters.mjs (bento union split, widgetType /
1120
+ * viewName present, bentoViewName + capabilities parity — the last group only
1121
+ * when `opts.converters` is supplied).
1122
+ */
1123
+ declare function validateTemplate(tpl: WorkspaceYaml, opts?: ValidateOptions): ValidateResult;
1124
+
866
1125
  /**
867
1126
  * @synap-core/workspace-templates — Definition adapter
868
1127
  *
@@ -1008,6 +1267,7 @@ interface PackageDefinitionOutput {
1008
1267
  slug: string;
1009
1268
  icon?: string;
1010
1269
  color?: string;
1270
+ domain?: string;
1011
1271
  tags?: string[];
1012
1272
  isPublic?: boolean;
1013
1273
  requiredTier?: string | null;
@@ -1046,13 +1306,11 @@ interface PackageDefinitionOutput {
1046
1306
  automations?: PackageAutomationWire[];
1047
1307
  /**
1048
1308
  * Entity-detail action placements — carried verbatim (authored form IS the
1049
- * wire form). NOTE: the Hub `PackageApplySchema` (synap-backend
1050
- * `hub-protocol/rest/packages.ts`) is a plain `z.object` and does not yet
1051
- * declare `actionPlacements`, so on the CLI/Hub install path this field is
1052
- * STRIPPED before `applyPackagePostWorkspace` sees it. The tRPC
1053
- * `createFromDefinition` door DOES carry it. Named follow-up: add an
1054
- * `ActionPlacementSchema` field to `PackageApplySchema` to close the Hub half
1055
- * (out of the T2 fence — flagged in the handoff).
1309
+ * wire form). The Hub `PackageApplySchema` (synap-backend
1310
+ * `hub-protocol/rest/packages.ts`) now declares `actionPlacements`
1311
+ * (`z.array(ActionPlacementSchema).optional()`), so BOTH the tRPC
1312
+ * `createFromDefinition` door and the CLI/Hub install path carry it through to
1313
+ * `applyPackagePostWorkspace` — the parity is closed.
1056
1314
  */
1057
1315
  actionPlacements?: WorkspaceYaml['actionPlacements'];
1058
1316
  onboarding?: WorkspaceYaml['onboarding'];
@@ -1067,4 +1325,4 @@ interface PackageDefinitionOutput {
1067
1325
  */
1068
1326
  declare function toPackageDefinition(slugOrYaml: string | WorkspaceYaml): PackageDefinitionOutput;
1069
1327
 
1070
- export { type AssembleCatalogInput, type BentoViewBlockWire, type BentoWidgetBlockWire, type BundledCatalogEntry, type BundledEntry, type CatalogEntry, type CompositionEdge, type CompositionGraph, type CompositionInstalledEntry, type CompositionNode, type CompositionOverlay, type CpPackageRow, type InstalledTemplate, type LayerTemplateGraphInput, type MergeCatalogInput, type MergeCatalogResult, PACKAGE_DEPENDENCY_KINDS, type PackageDefinitionOutput, type PackageDependencyKind, type RemoteCatalogEntry, type RemoteEntry, type RemoteSourceStatus, type SplitBentoBlocks, type TemplateActionPlacement, type TemplateAppKind, type TemplateAppRef, type TemplateAutomation, type TemplateBentoBlock, type TemplateDefaultSource, type TemplateDependency, type TemplateDisplayTemplate, type TemplateEntityLink, type TemplateExtendsRef, type TemplateIntegration, type TemplateLayoutConfig, type TemplateMeta, type TemplateOnboarding, type TemplateOnboardingCollectTarget, type TemplatePlaybook, type TemplatePlaybookParam, type TemplateProfile, type TemplateProfileEntityBentoTemplates, type TemplateProperty, type TemplateSeedEntity, type TemplateSidebarItem, type TemplateSidebarSurface, type TemplateSourceRole, type TemplateSuggestedRelation, type TemplateUpdateCheck, type TemplateView, type ToDefinitionResult, WORKSPACE_TEMPLATES, type WorkspaceDefinitionInput, type WorkspaceTemplateSlug, type WorkspaceYaml, assembleCatalog, bundledEdgesOf, computeTemplateUpdates, getWorkspaceTemplate, isHashVersion, layerTemplateGraph, listPublicTemplates, listWorkspaceTemplates, mergeCatalog, rowToRemoteEntry, splitBentoBlocks, toPackageDefinition, toWorkspaceDefinition };
1328
+ export { type AssembleCatalogInput, type BentoViewBlockWire, type BentoWidgetBlockWire, type BundledCatalogEntry, type BundledEntry, type CatalogEntry, type CompositionEdge, type CompositionGraph, type CompositionInstalledEntry, type CompositionNode, type CompositionOverlay, type ConceptViolation, type CpPackageRow, DECLARED_DIVERGENCES, type DomainGroup, type InstalledTemplate, type LayerTemplateGraphInput, type MergeCatalogInput, type MergeCatalogResult, OTHER_DOMAIN_ID, OTHER_DOMAIN_LABEL, PACKAGE_DEPENDENCY_KINDS, type PackageDefinitionOutput, type PackageDependencyKind, REQUIRED_META_FIELDS, REQUIRED_WORKSPACE_FIELDS, type RemoteCatalogEntry, type RemoteEntry, type RemoteSourceStatus, SYSTEM_PROFILES, type SplitBentoBlocks, TEMPLATE_DOMAINS, type TemplateActionPlacement, type TemplateAppKind, type TemplateAppRef, type TemplateAutomation, type TemplateBentoBlock, type TemplateConverters, type TemplateDefaultSource, type TemplateDependency, type TemplateDisplayTemplate, type TemplateDomain, type TemplateEntityLink, type TemplateExtendsRef, type TemplateIntegration, type TemplateLayoutConfig, type TemplateMeta, type TemplateOnboarding, type TemplateOnboardingCollectTarget, type TemplatePlaybook, type TemplatePlaybookParam, type TemplateProfile, type TemplateProfileEntityBentoTemplates, type TemplateProperty, type TemplateSeedEntity, type TemplateSidebarItem, type TemplateSidebarSurface, type TemplateSourceRole, type TemplateSuggestedRelation, type TemplateUpdateCheck, type TemplateView, type ToDefinitionResult, type ValidateOptions, type ValidateResult, type ValidationError, WORKSPACE_TEMPLATES, type WorkspaceDefinitionInput, type WorkspaceTemplateSlug, type WorkspaceYaml, assembleCatalog, bundledEdgesOf, collectBaseProfileSlugs, computeTemplateUpdates, conceptTerm, domainLabel, findConceptViolations, formatConceptViolations, getWorkspaceTemplate, groupByDomain, isHashVersion, isKnownDomain, layerTemplateGraph, listPublicTemplates, listWorkspaceTemplates, mergeCatalog, rowToRemoteEntry, splitBentoBlocks, toPackageDefinition, toWorkspaceDefinition, validateTemplate };