@synap-core/workspace-templates 0.6.4 → 0.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -243,6 +243,52 @@ interface TemplatePlaybook {
243
243
  };
244
244
  status?: 'draft' | 'active' | 'paused';
245
245
  }
246
+ interface TemplateAutomation {
247
+ /** Stable local key (unused on the wire today — reserved for dedup/refs). */
248
+ key?: string;
249
+ name: string;
250
+ description?: string;
251
+ triggerType: 'event' | 'cron' | 'webhook' | 'manual';
252
+ triggerConfig?: Record<string, unknown>;
253
+ flow: {
254
+ nodes: unknown[];
255
+ edges: unknown[];
256
+ precondition?: string;
257
+ };
258
+ status?: 'draft' | 'active' | 'paused';
259
+ }
260
+ interface TemplateActionPlacement {
261
+ /** Entity kind whose detail surface this action appears on. */
262
+ profileSlug: string;
263
+ /** Where the action renders. Only "entity-detail" is consumed today. */
264
+ surface: 'entity-detail' | string;
265
+ /** What the action does when clicked. */
266
+ kind: 'capability' | 'playbook' | 'automation';
267
+ /**
268
+ * Reference to the thing to run: a capability verb key, or a playbook /
269
+ * automation NAME (resolved to a row id at apply time).
270
+ */
271
+ ref: string;
272
+ /** Human label shown on the action button. */
273
+ label: string;
274
+ /** Additional entity-state requirements, evaluated by the rendering surface. */
275
+ when?: {
276
+ /** All listed workspace facets must be present on the entity. */
277
+ requiredFacetSlugs?: string[];
278
+ /** Entity property values that must equal their configured literal values. */
279
+ propertyEquals?: Record<string, unknown>;
280
+ /** Any configured property/value match makes the action applicable. */
281
+ propertyAnyEquals?: Record<string, unknown[]>;
282
+ /** Entity property values that must not equal their configured literal values. */
283
+ propertyNotEquals?: Record<string, unknown>;
284
+ };
285
+ /** Explicit intent required before a consequential action is launched. */
286
+ confirmation?: {
287
+ title: string;
288
+ description?: string;
289
+ confirmLabel?: string;
290
+ };
291
+ }
246
292
  interface TemplateIntegration {
247
293
  /** Capability template key to install (matches a capability template). */
248
294
  templateKey: string;
@@ -406,6 +452,16 @@ interface WorkspaceYaml {
406
452
  profileEntityBentoTemplates?: TemplateProfileEntityBentoTemplates;
407
453
  /** Playbooks (session templates) seeded with the workspace */
408
454
  playbooks?: TemplatePlaybook[];
455
+ /**
456
+ * Flow-based automations (WHEN→THEN triggers) seeded with the workspace.
457
+ * Applier-only — see {@link TemplateAutomation}.
458
+ */
459
+ automations?: TemplateAutomation[];
460
+ /**
461
+ * Entity-detail action placements seeded into `settings.actionPlacements`.
462
+ * See {@link TemplateActionPlacement}.
463
+ */
464
+ actionPlacements?: TemplateActionPlacement[];
409
465
  /** Capability templates (tools/connectors) to install on provisioning */
410
466
  integrations?: TemplateIntegration[];
411
467
  /**
@@ -695,6 +751,118 @@ declare function isHashVersion(version: string | undefined): boolean;
695
751
  */
696
752
  declare function computeTemplateUpdates(installed: InstalledTemplate[], catalog: CatalogEntry[], bundleVersion?: string): TemplateUpdateCheck[];
697
753
 
754
+ /**
755
+ * layerTemplateGraph — the KEYSTONE composition-graph engine.
756
+ * ============================================================
757
+ *
758
+ * Today the CLI (`synap-cli/src/commands/market.ts` `buildCompositionTrees`)
759
+ * renders template composition as a nested TREE: `buildDependencyNode`
760
+ * rebuilds a fresh `TreeNode` for every OCCURRENCE of a slug on every path, so
761
+ * a widely-required base (e.g. `foundation`) prints once per branch that
762
+ * reaches it (6× under a suite like `enterprise-os`). Its "shared" tag is only
763
+ * top-level-package granularity — there is no true fan-in count.
764
+ *
765
+ * This module replaces that with a LAYERED DAG: every node appears EXACTLY
766
+ * ONCE, positioned at its longest-path depth, with edges converging on it —
767
+ * so `foundation` sinks to the bedrock row with N inbound edges instead of
768
+ * being redrawn N times. It is the single source of truth for template
769
+ * composition; the CLI, browser dialogs, backend boot-ordering, and (later)
770
+ * the Atlas all consume it.
771
+ *
772
+ * PURE + TRANSPORT-AGNOSTIC (same discipline as `catalog.ts`): this is the
773
+ * ONLY module `synap-cli`, `browser`, `synap-control-plane-api`, and
774
+ * `synap-backend` can all resolve. No React, no dagre/d3, no fetch, no
775
+ * Node-only APIs. Pixel layout lives elsewhere (browser-only) — this module
776
+ * only computes topology (layers + edges + memoized nodes), never coordinates.
777
+ *
778
+ * CONSUMES drift, never recomputes it: `installed` / `updates` are read
779
+ * straight off `catalog.ts`'s `InstalledTemplate`-shaped rows and
780
+ * `computeTemplateUpdates()` output — this module does no semver comparison
781
+ * of its own.
782
+ */
783
+
784
+ /**
785
+ * An installed template row, keyed by slug — the shape this engine needs to
786
+ * mark a node `installed` and populate `workspaceIds`.
787
+ *
788
+ * NOTE ON NAMING: `catalog.ts`'s `InstalledTemplate` is `{ slug, version }`
789
+ * only — it was built for `computeTemplateUpdates`'s narrower need (a version
790
+ * to diff) and carries no `workspaceId`. `CompositionNode.workspaceIds` is
791
+ * part of the ratified API and cannot be populated from that shape, so this
792
+ * is a REAL conflict, not a preference: this module declares its own,
793
+ * slightly richer row instead of importing `catalog.ts`'s `InstalledTemplate`
794
+ * under that name. Every field of `catalog.ts`'s `InstalledTemplate` is a
795
+ * subset of this one, so a caller building `InstalledTemplate[]` for
796
+ * `computeTemplateUpdates` can build ONE array of `CompositionInstalledEntry`
797
+ * and pass it to both doors.
798
+ */
799
+ interface CompositionInstalledEntry {
800
+ slug: string;
801
+ workspaceId: string;
802
+ workspaceName?: string;
803
+ /** `settings.packageVersion`, when the pod stamped one. Omit when unknown. */
804
+ version?: string;
805
+ }
806
+ /** One compose-relation dependency, attached to the BASE node it overlays onto. */
807
+ interface CompositionOverlay {
808
+ slug: string;
809
+ name: string;
810
+ installed: boolean;
811
+ }
812
+ /** One edge in the raw dependency graph, exactly as declared (kept even when broken by a cycle). */
813
+ interface CompositionEdge {
814
+ from: string;
815
+ to: string;
816
+ relation: "compose" | "require";
817
+ depKind?: string;
818
+ }
819
+ interface CompositionNode {
820
+ slug: string;
821
+ name: string;
822
+ /** Longest-path depth: `1 + max(layer of every node that depends on this one)`. Roots = 0, bedrock = max. */
823
+ layer: number;
824
+ /** TRUE fan-in — every slug (node or compose-only overlay source) that declares a dependency on this one. */
825
+ dependents: string[];
826
+ /** Which of the input `roots` transitively reach this node (self-inclusive for a root). */
827
+ roots: string[];
828
+ installed: boolean;
829
+ workspaceIds: string[];
830
+ installedVersion?: string;
831
+ latestVersion?: string | null;
832
+ updateAvailable: boolean;
833
+ noVersionInfo: boolean;
834
+ /** `compose`-relation deps that overlay onto THIS node (see rule 2 — the overlay source itself is never a layer node). */
835
+ overlays: CompositionOverlay[];
836
+ }
837
+ interface CompositionGraph {
838
+ nodes: Map<string, CompositionNode>;
839
+ edges: CompositionEdge[];
840
+ /** `layers[0]` = roots … `layers[n]` = bedrock. Compose-overlay SOURCES never appear here (rule 2). */
841
+ layers: CompositionNode[][];
842
+ /** Broken back-edges `[from, to]` — surfaced, never silently swallowed (rule 4). */
843
+ cycles: string[][];
844
+ }
845
+ interface LayerTemplateGraphInput {
846
+ /** Top-level slugs to walk from. Always land at `layer: 0`. */
847
+ roots: string[];
848
+ /** INJECTED edge source (rule 5) — never hardcoded to the bundled map. See `bundledEdgesOf`. */
849
+ edgesOf: (slug: string) => readonly TemplateDependency[];
850
+ nameOf?: (slug: string) => string | undefined;
851
+ installed?: CompositionInstalledEntry[];
852
+ updates?: TemplateUpdateCheck[];
853
+ }
854
+ /**
855
+ * Default `edgesOf` — reads `dependencies[]` off the BUNDLED template map
856
+ * only. This is what the current CLI walker is hardcoded to, which is
857
+ * precisely the live bug rule 5 fixes: a remote/private CP-only package's
858
+ * `definition.dependencies` are invisible to it, so its subtree silently
859
+ * renders empty. Callers with a remote catalog entry available should pass
860
+ * their OWN `edgesOf` that falls back to `entry.remote.definition.dependencies`
861
+ * (or similar) for slugs this default can't see.
862
+ */
863
+ declare function bundledEdgesOf(slug: string): readonly TemplateDependency[];
864
+ declare function layerTemplateGraph(input: LayerTemplateGraphInput): CompositionGraph;
865
+
698
866
  /**
699
867
  * @synap-core/workspace-templates — Definition adapter
700
868
  *
@@ -707,6 +875,25 @@ declare function computeTemplateUpdates(installed: InstalledTemplate[], catalog:
707
875
  * shape never drifts per call-site.
708
876
  */
709
877
 
878
+ /**
879
+ * A `TemplateAutomation` as the apply door expects it: `flowDefinition`, not
880
+ * the authored `flow` (mirrors `PackagePostWorkspaceBody['automations'][number]`
881
+ * / the Hub `POST /packages/apply` `AutomationSchema`).
882
+ */
883
+ interface PackageAutomationWire {
884
+ /** Stable template identity; names may be edited without orphaning the flow. */
885
+ key?: string;
886
+ name: string;
887
+ description?: string;
888
+ triggerType: TemplateAutomation['triggerType'];
889
+ triggerConfig?: Record<string, unknown>;
890
+ flowDefinition?: {
891
+ nodes: unknown[];
892
+ edges: unknown[];
893
+ precondition?: string;
894
+ };
895
+ status?: TemplateAutomation['status'];
896
+ }
710
897
  /** A widget block as the wire expects it: `bentoLayout[]`, keyed by `widgetType`. */
711
898
  interface BentoWidgetBlockWire {
712
899
  widgetType: string;
@@ -761,6 +948,21 @@ interface WorkspaceDefinitionInput {
761
948
  * tools/skills/automations silently dropped on that door.
762
949
  */
763
950
  capabilities?: WorkspaceYaml['integrations'];
951
+ /** Playbooks normalized to the workspace-create input contract. */
952
+ playbooks?: Array<Record<string, unknown>>;
953
+ /**
954
+ * Entity-detail action placements — forwarded verbatim to
955
+ * `applyPackagePostWorkspace`, which merges them into
956
+ * `settings.actionPlacements`. The tRPC door (`createFromDefinition`)
957
+ * declares `actionPlacements` in its zod input and carries them through the
958
+ * shared apply door. No shape transform: the authored form IS the wire form.
959
+ */
960
+ actionPlacements?: WorkspaceYaml['actionPlacements'];
961
+ /**
962
+ * Graph-based automations. Deliberately distinct from the legacy
963
+ * `automations` loop/playbook-trigger wire shape accepted by this door.
964
+ */
965
+ flowAutomations?: PackageAutomationWire[];
764
966
  workspaceSubtype?: string;
765
967
  workspaceType?: NonNullable<WorkspaceYaml['workspace']>['workspaceType'];
766
968
  workspaceVisibility?: string;
@@ -840,6 +1042,19 @@ interface PackageDefinitionOutput {
840
1042
  layoutConfig?: WorkspaceYaml['layout'];
841
1043
  capabilities?: WorkspaceYaml['integrations'];
842
1044
  playbooks?: WorkspaceYaml['playbooks'];
1045
+ /** Flow-based automations — mapped to the apply door's `flowDefinition` field. */
1046
+ automations?: PackageAutomationWire[];
1047
+ /**
1048
+ * 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).
1056
+ */
1057
+ actionPlacements?: WorkspaceYaml['actionPlacements'];
843
1058
  onboarding?: WorkspaceYaml['onboarding'];
844
1059
  /** Template-composition dependencies — resolved by the apply endpoint. */
845
1060
  dependencies?: WorkspaceYaml['dependencies'];
@@ -852,4 +1067,4 @@ interface PackageDefinitionOutput {
852
1067
  */
853
1068
  declare function toPackageDefinition(slugOrYaml: string | WorkspaceYaml): PackageDefinitionOutput;
854
1069
 
855
- export { type AssembleCatalogInput, type BentoViewBlockWire, type BentoWidgetBlockWire, type BundledCatalogEntry, type BundledEntry, type CatalogEntry, type CpPackageRow, type InstalledTemplate, type MergeCatalogInput, type MergeCatalogResult, PACKAGE_DEPENDENCY_KINDS, type PackageDefinitionOutput, type PackageDependencyKind, type RemoteCatalogEntry, type RemoteEntry, type RemoteSourceStatus, type SplitBentoBlocks, type TemplateAppKind, type TemplateAppRef, 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, computeTemplateUpdates, getWorkspaceTemplate, isHashVersion, listPublicTemplates, listWorkspaceTemplates, mergeCatalog, rowToRemoteEntry, splitBentoBlocks, toPackageDefinition, toWorkspaceDefinition };
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 };