@synap-core/workspace-templates 0.6.1 → 0.6.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.
package/dist/index.d.ts CHANGED
@@ -150,13 +150,6 @@ interface TemplateProfileEntityBentoTemplates {
150
150
  blocks: Array<Record<string, unknown>>;
151
151
  };
152
152
  }
153
- interface TemplateAutomation {
154
- name: string;
155
- description?: string;
156
- trigger: string;
157
- action: string;
158
- config?: Record<string, unknown>;
159
- }
160
153
  /** Mirrors `WorkspaceSourceRole` in synap-backend `schema/workspaces.ts`. */
161
154
  type TemplateSourceRole = 'provider' | 'consumer' | 'provider-consumer';
162
155
  /** Mirrors `WorkspaceDefaultSource` in synap-backend `schema/workspaces.ts`. */
@@ -238,6 +231,16 @@ interface TemplatePlaybook {
238
231
  } | null;
239
232
  /** tool/skill keys this playbook grants. */
240
233
  grants?: string[];
234
+ /**
235
+ * The entity kind this playbook operates over, persisted to
236
+ * `playbooks.subject_profile`. Makes the playbook matchable by
237
+ * `playbooks.matchForEntity` (filters `subject_profile->>'profileSlug'`), so a
238
+ * captured entity of this kind can auto-launch the playbook as a session.
239
+ */
240
+ subjectProfile?: {
241
+ profileSlug: string;
242
+ filter?: Record<string, unknown>;
243
+ };
241
244
  status?: 'draft' | 'active' | 'paused';
242
245
  }
243
246
  interface TemplateIntegration {
@@ -401,8 +404,6 @@ interface WorkspaceYaml {
401
404
  };
402
405
  /** Per-profile entity bento layouts */
403
406
  profileEntityBentoTemplates?: TemplateProfileEntityBentoTemplates;
404
- /** Automations to install on workspace creation */
405
- automations?: TemplateAutomation[];
406
407
  /** Playbooks (session templates) seeded with the workspace */
407
408
  playbooks?: TemplatePlaybook[];
408
409
  /** Capability templates (tools/connectors) to install on provisioning */
@@ -536,6 +537,42 @@ interface MergeCatalogInput {
536
537
  */
537
538
  remoteStatus?: RemoteSourceStatus;
538
539
  }
540
+ /**
541
+ * A control-plane package LIST row, as returned by `GET /api/packages` and
542
+ * `GET /api/packages/mine`. This is the raw JSON shape BEFORE it is projected
543
+ * into a `RemoteEntry`. Both list routes STRIP `definition`, so it is absent
544
+ * here (the install path fetches the full row per-slug on demand).
545
+ *
546
+ * `isPublic` is present ONLY on `/mine` rows (`false` ⇒ private). Public browse
547
+ * rows omit it BY CONSTRUCTION (the list route hard-filters `WHERE is_public =
548
+ * true`), so its absence means "public", never "unknown".
549
+ *
550
+ * Consumers used to hand-copy this shape + `rowToRemoteEntry` (browser
551
+ * `useMarketplaceCatalog`, CLI `cp-packages`); this is the ONE canonical copy.
552
+ */
553
+ interface CpPackageRow {
554
+ slug: string;
555
+ displayName: string;
556
+ description?: string | null;
557
+ /** CP package category / type (e.g. `"workspace"`, `"view"`). */
558
+ category?: string;
559
+ tags?: string[] | null;
560
+ icon?: string | null;
561
+ /** Present only on `/mine` rows. `false` ⇒ private. Browse rows omit it. */
562
+ isPublic?: boolean;
563
+ }
564
+ /**
565
+ * Map a CP list row into the merge door's `RemoteEntry`. THE canonical mapping —
566
+ * browser + CLI import this instead of hand-copying it (the two copies had
567
+ * already drifted in `description`/`isPrivate` handling).
568
+ *
569
+ * `isPrivate` is passed EXPLICITLY by the caller because it depends on WHICH
570
+ * route the row came from: browse rows are all-public (pass `undefined`), `/mine`
571
+ * rows carry the real flag (pass `row.isPublic === false`). Keeping it a param —
572
+ * not derived here — lets a caller that fetches the two routes separately control
573
+ * it per-source; `assembleCatalog` derives it from the row for the common case.
574
+ */
575
+ declare function rowToRemoteEntry(row: CpPackageRow, isPrivate?: boolean): RemoteEntry;
539
576
  interface CatalogEntryBase {
540
577
  slug: string;
541
578
  name: string;
@@ -592,6 +629,29 @@ interface MergeCatalogResult {
592
629
  * entry (a private or third-party package) and is always kept.
593
630
  */
594
631
  declare function mergeCatalog(input: MergeCatalogInput): MergeCatalogResult;
632
+ interface AssembleCatalogInput {
633
+ /** Bundled templates (this package). Always in-process. */
634
+ bundled: BundledEntry[];
635
+ /**
636
+ * Raw CP list rows (browse and/or `/mine`, concatenated). Mapped to
637
+ * `RemoteEntry` via `rowToRemoteEntry`; `isPrivate` is DERIVED per-row from
638
+ * `isPublic` (`false` ⇒ private; absent/`true` ⇒ public), which handles both
639
+ * browse rows (no `isPublic`) and `/mine` rows uniformly.
640
+ */
641
+ remoteRows?: CpPackageRow[];
642
+ /** This client's bundled-package version (the winner signal vs each row). */
643
+ bundleVersion: string;
644
+ /** The transport's verdict on the remote fetch. Default `"ok"`. */
645
+ remoteStatus?: RemoteSourceStatus;
646
+ }
647
+ /**
648
+ * Convenience wrapper over `mergeCatalog`: maps raw CP rows through the canonical
649
+ * `rowToRemoteEntry` and merges them with the bundled templates. Still PURE — the
650
+ * caller fetches the rows (its own transport/auth) and passes them in; this only
651
+ * maps + merges. Use `mergeCatalog` + `rowToRemoteEntry` directly when you need
652
+ * per-source `isPrivate` control (e.g. keeping browse and `/mine` distinct).
653
+ */
654
+ declare function assembleCatalog(input: AssembleCatalogInput): MergeCatalogResult;
595
655
 
596
656
  /**
597
657
  * @synap-core/workspace-templates — Definition adapter
@@ -647,6 +707,18 @@ interface WorkspaceDefinitionInput {
647
707
  /** VIEW half of the authored bento union — resolved against the viewMap. */
648
708
  bentoViewBlocks?: BentoViewBlockWire[];
649
709
  profileEntityBentoTemplates?: WorkspaceYaml['profileEntityBentoTemplates'];
710
+ /**
711
+ * Capability integrations (→ tools + skills + vault + capability-embedded
712
+ * automations/playbooks). Emitted from the template's `integrations:` list —
713
+ * IDENTICAL to what `toPackageDefinition` puts in its `capabilities` field. The
714
+ * tRPC door (`workspaces.createFromDefinition`) now declares `capabilities` in
715
+ * its zod input and installs them via the SHARED `applyPackagePostWorkspace`
716
+ * door (same as Hub `/packages/apply`). It was missing from this interface, so
717
+ * `toWorkspaceDefinition` had nowhere to put integrations and the browser
718
+ * BUNDLED install path carried NO capabilities — every capability's
719
+ * tools/skills/automations silently dropped on that door.
720
+ */
721
+ capabilities?: WorkspaceYaml['integrations'];
650
722
  workspaceSubtype?: string;
651
723
  workspaceType?: NonNullable<WorkspaceYaml['workspace']>['workspaceType'];
652
724
  workspaceVisibility?: string;
@@ -738,4 +810,4 @@ interface PackageDefinitionOutput {
738
810
  */
739
811
  declare function toPackageDefinition(slugOrYaml: string | WorkspaceYaml): PackageDefinitionOutput;
740
812
 
741
- export { type BentoViewBlockWire, type BentoWidgetBlockWire, type BundledCatalogEntry, type BundledEntry, type CatalogEntry, type MergeCatalogInput, type MergeCatalogResult, PACKAGE_DEPENDENCY_KINDS, type PackageDefinitionOutput, type PackageDependencyKind, type RemoteCatalogEntry, type RemoteEntry, type RemoteSourceStatus, type SplitBentoBlocks, 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 TemplateView, type ToDefinitionResult, WORKSPACE_TEMPLATES, type WorkspaceDefinitionInput, type WorkspaceTemplateSlug, type WorkspaceYaml, getWorkspaceTemplate, listPublicTemplates, listWorkspaceTemplates, mergeCatalog, splitBentoBlocks, toPackageDefinition, toWorkspaceDefinition };
813
+ export { type AssembleCatalogInput, type BentoViewBlockWire, type BentoWidgetBlockWire, type BundledCatalogEntry, type BundledEntry, type CatalogEntry, type CpPackageRow, 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 TemplateView, type ToDefinitionResult, WORKSPACE_TEMPLATES, type WorkspaceDefinitionInput, type WorkspaceTemplateSlug, type WorkspaceYaml, assembleCatalog, getWorkspaceTemplate, listPublicTemplates, listWorkspaceTemplates, mergeCatalog, rowToRemoteEntry, splitBentoBlocks, toPackageDefinition, toWorkspaceDefinition };
package/dist/index.js CHANGED
@@ -6518,6 +6518,26 @@ var DATA = {
6518
6518
  "label": "Depends on"
6519
6519
  }
6520
6520
  ],
6521
+ "playbooks": [
6522
+ {
6523
+ "name": "Evaluate Feature",
6524
+ "description": "Assess a feature \u2014 its current state, whether it's worth building, and how it fits the rest of the system.",
6525
+ "goalTemplate": "Evaluate this feature ({feature}): where it stands today (its status, progress, and any blockers), whether it is actually useful (the problem it solves and for whom), and how it integrates with the existing apps, packages, services, and environments in this workspace. Finish with a clear recommendation \u2014 continue, cut, or reshape \u2014 and the reasoning behind it.",
6526
+ "subjectProfile": {
6527
+ "profileSlug": "devplane_feature"
6528
+ },
6529
+ "params": [
6530
+ {
6531
+ "name": "feature",
6532
+ "type": "entity",
6533
+ "label": "Feature",
6534
+ "required": true
6535
+ }
6536
+ ],
6537
+ "executor": "is-agent",
6538
+ "status": "active"
6539
+ }
6540
+ ],
6521
6541
  "onboarding": {
6522
6542
  "goal": "Capture the real engineering surface \u2014 the apps that are shipped, where their code lives, what runs behind them, where they deploy, and what's in flight \u2014 so the workspace mirrors what the team actually builds and runs, not a generic template.",
6523
6543
  "framing": "THE STAFF ENGINEER: Act as a pragmatic, precise staff/platform engineer standing up a developer command center. Tease out what's actually shipped vs. planned, where the code lives (repos + local paths), what runs behind each app, where it deploys, and what's on the bench right now. Prefer concrete over aspirational \u2014 a repo URL beats a wish. Tie the roadmap back to the Foundation's mission and audiences: the surface exists to serve them.\n",
@@ -8465,6 +8485,16 @@ var DATA = {
8465
8485
  "groupBy": "post-status",
8466
8486
  "description": "Content posts by status."
8467
8487
  },
8488
+ {
8489
+ "name": "Content Calendar",
8490
+ "slug": "content-calendar",
8491
+ "type": "calendar",
8492
+ "scopeProfileSlug": "post",
8493
+ "description": "Your editorial calendar \u2014 every post on the day it publishes.",
8494
+ "config": {
8495
+ "dateField": "properties.publish-date"
8496
+ }
8497
+ },
8468
8498
  {
8469
8499
  "name": "Pillars",
8470
8500
  "slug": "content-pillars",
@@ -8506,6 +8536,12 @@ var DATA = {
8506
8536
  "label": "Posts",
8507
8537
  "icon": "file-edit"
8508
8538
  },
8539
+ {
8540
+ "kind": "view",
8541
+ "viewName": "Content Calendar",
8542
+ "label": "Calendar",
8543
+ "icon": "calendar"
8544
+ },
8509
8545
  {
8510
8546
  "kind": "view",
8511
8547
  "viewName": "Pillars",
@@ -8531,10 +8567,20 @@ var DATA = {
8531
8567
  "blocks": [
8532
8568
  {
8533
8569
  "kind": "view",
8534
- "viewName": "Pillars",
8570
+ "viewName": "Content Calendar",
8535
8571
  "pos": {
8536
8572
  "x": 0,
8537
8573
  "y": 0,
8574
+ "w": 12,
8575
+ "h": 6
8576
+ }
8577
+ },
8578
+ {
8579
+ "kind": "view",
8580
+ "viewName": "Pillars",
8581
+ "pos": {
8582
+ "x": 0,
8583
+ "y": 6,
8538
8584
  "w": 6,
8539
8585
  "h": 5
8540
8586
  }
@@ -8544,7 +8590,7 @@ var DATA = {
8544
8590
  "viewName": "Newsletters",
8545
8591
  "pos": {
8546
8592
  "x": 6,
8547
- "y": 0,
8593
+ "y": 6,
8548
8594
  "w": 6,
8549
8595
  "h": 5
8550
8596
  }
@@ -8571,6 +8617,37 @@ var DATA = {
8571
8617
  "label": "Sponsor"
8572
8618
  }
8573
8619
  ],
8620
+ "playbooks": [
8621
+ {
8622
+ "name": "Produce Content",
8623
+ "description": "Take a captured post idea and carry it from spark to a scheduled, platform-ready draft.",
8624
+ "goalTemplate": "Produce content for {platform} from this idea ({post}). Take the raw idea, shape it into a {format} draft with a scroll-stopping hook and a clear CTA, keep it aligned to the post's pillar and the operator's brand voice, then move it to Scheduled with a publish date.",
8625
+ "subjectProfile": {
8626
+ "profileSlug": "post"
8627
+ },
8628
+ "params": [
8629
+ {
8630
+ "name": "post",
8631
+ "type": "entity",
8632
+ "label": "Post",
8633
+ "required": true
8634
+ },
8635
+ {
8636
+ "name": "platform",
8637
+ "type": "text",
8638
+ "label": "Platform",
8639
+ "required": true
8640
+ },
8641
+ {
8642
+ "name": "format",
8643
+ "type": "text",
8644
+ "label": "Format"
8645
+ }
8646
+ ],
8647
+ "executor": "is-agent",
8648
+ "status": "active"
8649
+ }
8650
+ ],
8574
8651
  "onboarding": {
8575
8652
  "goal": "Stand up the editorial engine \u2014 the pillars you're known for, the platforms you publish on, the cadence you can actually sustain, and a first post placed in the system \u2014 so the workspace mirrors how you turn thinking into published content, not a blank calendar.\n",
8576
8653
  "framing": `THE EDITOR-IN-CHIEF: Act as a seasoned content strategist who has grown owned audiences from zero. Anchor everything on PILLARS \u2014 the two-to-four recurring themes an audience comes to you for \u2014 because pillars are what make a content engine compound instead of drift. Pull voice and identity from Brand and the target audience from Foundation so every piece lands on-strategy. Push for a cadence they can hold for a year, not a heroic month. Be concrete: real platforms, real formats, a real first post \u2014 a fuzzy "I'll post more" helps no one.
@@ -9693,6 +9770,62 @@ var DATA = {
9693
9770
  "targetProfileSlug": "deal",
9694
9771
  "type": "linked_to_deal"
9695
9772
  }
9773
+ ],
9774
+ "playbooks": [
9775
+ {
9776
+ "name": "Enrich this lead",
9777
+ "description": "Take a thin, freshly-captured lead and fill it out \u2014 company, title, LinkedIn, and the relationships around it.",
9778
+ "goalTemplate": "Enrich this lead ({lead}). Starting from whatever is known, fill out the missing detail \u2014 company, job title, LinkedIn URL, location, and the people and companies around them \u2014 and record it on the lead. Draw on whatever enrichment capability this workspace has connected (e.g. an Apify or Unipile/LinkedIn tool); if none is available, enrich from the public web and what is already in the pod. Link the lead to its company and any related contacts, and note where information is still missing.",
9779
+ "subjectProfile": {
9780
+ "profileSlug": "lead"
9781
+ },
9782
+ "params": [
9783
+ {
9784
+ "name": "lead",
9785
+ "type": "entity",
9786
+ "label": "Lead",
9787
+ "required": true
9788
+ }
9789
+ ],
9790
+ "executor": "is-agent",
9791
+ "status": "active"
9792
+ },
9793
+ {
9794
+ "name": "Qualify this lead",
9795
+ "description": "Assess a lead against the ICP, score the fit, and decide the next step \u2014 advance, nurture, or disqualify.",
9796
+ "goalTemplate": "Qualify this lead ({lead}). Assess how well they fit our ideal customer profile \u2014 company, role, industry, size, and the signals of intent or need \u2014 and set an ICP score. Decide the next step: advance them toward a deal, keep nurturing, or disqualify. Write the reasoning and the decision back onto the lead (its stage, score, and next step) so the call is auditable.",
9797
+ "subjectProfile": {
9798
+ "profileSlug": "lead"
9799
+ },
9800
+ "params": [
9801
+ {
9802
+ "name": "lead",
9803
+ "type": "entity",
9804
+ "label": "Lead",
9805
+ "required": true
9806
+ }
9807
+ ],
9808
+ "executor": "is-agent",
9809
+ "status": "active"
9810
+ },
9811
+ {
9812
+ "name": "Work this deal",
9813
+ "description": "Move a deal toward Won \u2014 read the current stage, find the blocker, and propose the next step and owner.",
9814
+ "goalTemplate": "Work this deal ({deal}) toward Won. Assess where it stands \u2014 its current stage, value, and close date \u2014 and identify the single thing blocking it from advancing. Propose the concrete next step, who owns it, and by when, and update the deal's next step accordingly. If the stage should change, say so and why.",
9815
+ "subjectProfile": {
9816
+ "profileSlug": "deal"
9817
+ },
9818
+ "params": [
9819
+ {
9820
+ "name": "deal",
9821
+ "type": "entity",
9822
+ "label": "Deal",
9823
+ "required": true
9824
+ }
9825
+ ],
9826
+ "executor": "is-agent",
9827
+ "status": "active"
9828
+ }
9696
9829
  ]
9697
9830
  },
9698
9831
  "dev-dashboard": {
@@ -11941,6 +12074,79 @@ var DATA = {
11941
12074
  "label": "Involves"
11942
12075
  }
11943
12076
  ],
12077
+ "playbooks": [
12078
+ {
12079
+ "name": "Research Competitor",
12080
+ "description": "Deep-research a competitor and position it against us \u2014 strengths, weaknesses, pricing, and the gaps we can exploit.",
12081
+ "goalTemplate": "Research this competitor ({competitor}) and compare them to us. Investigate their {focus}: positioning, strengths, weaknesses, pricing, and recent moves. Use the provided company context where relevant: {companyContext}. Produce: {outputTypes}. Update the competitor entity with what you find and make clear where we win and where we are exposed.",
12082
+ "subjectProfile": {
12083
+ "profileSlug": "competitor"
12084
+ },
12085
+ "params": [
12086
+ {
12087
+ "name": "competitor",
12088
+ "type": "entity",
12089
+ "label": "Competitor",
12090
+ "required": true
12091
+ },
12092
+ {
12093
+ "name": "focus",
12094
+ "type": "text",
12095
+ "label": "Focus area",
12096
+ "defaultValue": "product, pricing, and positioning"
12097
+ },
12098
+ {
12099
+ "name": "companyContext",
12100
+ "type": "text",
12101
+ "label": "Our company context"
12102
+ },
12103
+ {
12104
+ "name": "outputTypes",
12105
+ "type": "text",
12106
+ "label": "Outputs",
12107
+ "defaultValue": "a head-to-head comparison summary and an updated competitor profile"
12108
+ }
12109
+ ],
12110
+ "executor": "is-agent",
12111
+ "schedule": {
12112
+ "cron": "0 9 * * 1",
12113
+ "enabled": false
12114
+ },
12115
+ "grants": [
12116
+ "Web Search",
12117
+ "Entity Creator"
12118
+ ],
12119
+ "status": "active"
12120
+ },
12121
+ {
12122
+ "name": "Discover Competitors",
12123
+ "description": "Scan the market for competitors we don't track yet and add them to the ecosystem \u2014 the self-generating half of the radar.",
12124
+ "goalTemplate": 'Find companies that compete with us in {ourSpace}. Use neural web search (the exa_search skill with category "company") to surface real, named companies \u2014 direct competitors, adjacent tools that solve the same job a different way, and emerging players. For each genuinely NEW one (not already a competitor in our ecosystem), propose it as a `competitor` entity and ALWAYS include its `website` (its canonical URL) so it de-duplicates against what we already track \u2014 never create a company that already exists. Skip anything already known. Report what you added and why each one matters.',
12125
+ "schedule": {
12126
+ "cron": "0 9 * * 1",
12127
+ "enabled": false
12128
+ },
12129
+ "params": [
12130
+ {
12131
+ "name": "ourSpace",
12132
+ "type": "text",
12133
+ "label": "Our market / category",
12134
+ "required": true
12135
+ }
12136
+ ],
12137
+ "executor": "is-agent",
12138
+ "grants": [
12139
+ "exa_search",
12140
+ "Entity Creator"
12141
+ ],
12142
+ "status": "active"
12143
+ }
12144
+ ],
12145
+ "integrations": [
12146
+ {
12147
+ "templateKey": "exa"
12148
+ }
12149
+ ],
11944
12150
  "onboarding": {
11945
12151
  "goal": 'Map the real ecosystem \u2014 the key players (companies and people), who partners and competes with whom, and the segments and trends that matter \u2014 so strategy is grounded in the actual market, not a vague "the market".\n',
11946
12152
  "framing": 'THE ECOSYSTEM LEAD: Act as a sharp ecosystem lead who maps the market\nlandscape AND the relationships inside it. Push for REAL named players \u2014 not\n"the incumbents", but the actual companies \u2014 and for the concrete edges\nbetween them: who partners with whom, who competes, who invested in whom.\nA map with no edges is just a list; the value is in the relationships.\n',
@@ -12116,6 +12322,12 @@ var DATA = {
12116
12322
  "kind": "workspace",
12117
12323
  "relation": "require",
12118
12324
  "reason": "The pipeline \u2014 contacts, leads, clients, and deals."
12325
+ },
12326
+ {
12327
+ "slug": "content-os",
12328
+ "kind": "workspace",
12329
+ "relation": "require",
12330
+ "reason": "The editorial engine \u2014 pillars, posts, platforms, and newsletters \u2014 so the company's content operation is part of the operating core."
12119
12331
  }
12120
12332
  ],
12121
12333
  "workspace": {
@@ -24826,6 +25038,19 @@ function listPublicTemplates() {
24826
25038
  }
24827
25039
 
24828
25040
  // src/catalog.ts
25041
+ function rowToRemoteEntry(row, isPrivate) {
25042
+ return {
25043
+ slug: row.slug,
25044
+ name: row.displayName,
25045
+ description: row.description ?? void 0,
25046
+ category: row.category,
25047
+ tags: row.tags ?? [],
25048
+ icon: row.icon ?? null,
25049
+ isPrivate
25050
+ // Both list routes strip `definition`; absence ⇒ bundle wins a slug conflict,
25051
+ // and the install path fetches the full definition per-slug when needed.
25052
+ };
25053
+ }
24829
25054
  function parseSemver(v) {
24830
25055
  if (!v) return null;
24831
25056
  const m = /^\s*v?(\d+)\.(\d+)\.(\d+)/.exec(v);
@@ -24900,6 +25125,17 @@ function mergeCatalog(input) {
24900
25125
  sources: { bundled: "ok", remote: remoteStatus }
24901
25126
  };
24902
25127
  }
25128
+ function assembleCatalog(input) {
25129
+ const remote = (input.remoteRows ?? []).map(
25130
+ (row) => rowToRemoteEntry(row, row.isPublic === false ? true : void 0)
25131
+ );
25132
+ return mergeCatalog({
25133
+ bundled: input.bundled,
25134
+ remote,
25135
+ bundleVersion: input.bundleVersion,
25136
+ remoteStatus: input.remoteStatus
25137
+ });
25138
+ }
24903
25139
 
24904
25140
  // src/define.ts
24905
25141
  function resolveBlockKind(block) {
@@ -24956,6 +25192,13 @@ function toWorkspaceDefinition(slugOrYaml, nameOverride) {
24956
25192
  bentoLayout: bento.bentoLayout,
24957
25193
  bentoViewBlocks: bento.bentoViewBlocks,
24958
25194
  profileEntityBentoTemplates: tpl.profileEntityBentoTemplates,
25195
+ // Capability integrations — forwarded so the tRPC/UI (bundled) install door
25196
+ // seeds the SAME operational payload (tools + skills + capability-embedded
25197
+ // automations/playbooks) the CLI/Hub door gets via `toPackageDefinition`.
25198
+ // `workspaces.createFromDefinition` declares `capabilities` in its zod input
25199
+ // and routes it through the shared `applyPackagePostWorkspace` door. Omitting
25200
+ // it here made the browser bundled-install path carry no capabilities at all.
25201
+ capabilities: tpl.integrations,
24959
25202
  workspaceSubtype: ws.subtype,
24960
25203
  workspaceType: ws.workspaceType,
24961
25204
  workspaceVisibility: ws.visibility,
@@ -25020,10 +25263,12 @@ function toPackageDefinition(slugOrYaml) {
25020
25263
  export {
25021
25264
  PACKAGE_DEPENDENCY_KINDS,
25022
25265
  WORKSPACE_TEMPLATES,
25266
+ assembleCatalog,
25023
25267
  getWorkspaceTemplate,
25024
25268
  listPublicTemplates,
25025
25269
  listWorkspaceTemplates,
25026
25270
  mergeCatalog,
25271
+ rowToRemoteEntry,
25027
25272
  splitBentoBlocks,
25028
25273
  toPackageDefinition,
25029
25274
  toWorkspaceDefinition