@synap-core/workspace-templates 0.2.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/src/types.ts ADDED
@@ -0,0 +1,426 @@
1
+ /**
2
+ * @synap-core/workspace-templates — Types
3
+ *
4
+ * Canonical shape of a workspace template.
5
+ * YAML source files validate against these types.
6
+ * Every consumer (browser, backend, CLI, marketplace) imports from here.
7
+ */
8
+
9
+ // ============================================================================
10
+ // App Reference — what opens as first screen when entering this workspace
11
+ // ============================================================================
12
+
13
+ export type TemplateAppKind = 'native' | 'stored' | 'url';
14
+
15
+ export interface TemplateAppRef {
16
+ kind: TemplateAppKind;
17
+ /** For kind='native': the appId registered in the browser manifest */
18
+ appId?: string;
19
+ /** For kind='native': how the platform renders the app */
20
+ rendererType?: 'native' | 'external' | 'iframe-srcdoc';
21
+ /** For kind='stored': the cell key registered in the cell registry */
22
+ cellKey?: string;
23
+ /** For kind='stored': default props passed to the cell */
24
+ props?: Record<string, unknown>;
25
+ /** For kind='url': external URL to open */
26
+ url?: string;
27
+ /** Human label */
28
+ title?: string;
29
+ }
30
+
31
+ // ============================================================================
32
+ // Property / Profile / View (mirrors WorkspaceProposal from onboarding)
33
+ // ============================================================================
34
+
35
+ export interface TemplateProperty {
36
+ slug: string;
37
+ label: string;
38
+ valueType: string;
39
+ inputType?: string;
40
+ placeholder?: string;
41
+ enumValues?: string[];
42
+ constraints?: Record<string, unknown>;
43
+ targetProfileSlug?: string;
44
+ }
45
+
46
+ export interface TemplateProfile {
47
+ slug: string;
48
+ displayName: string;
49
+ icon?: string;
50
+ color?: string;
51
+ description?: string;
52
+ /** Visibility scope. Omit or "WORKSPACE" for workspace-scoped. */
53
+ scope?: string;
54
+ /** Semantic slug for system profiles. */
55
+ semanticSlug?: string;
56
+ properties: TemplateProperty[];
57
+ }
58
+
59
+ export interface TemplateView {
60
+ name: string;
61
+ slug?: string;
62
+ type: string;
63
+ scopeProfileSlug?: string;
64
+ scopeProfileSlugs?: string[];
65
+ config?: Record<string, unknown>;
66
+ /** If true, this view auto-selected as the default view for this workspace */
67
+ defaultView?: boolean;
68
+ description?: string;
69
+ groupBy?: string;
70
+ }
71
+
72
+ export interface TemplateEntityLink {
73
+ sourceProfileSlug: string;
74
+ targetProfileSlug: string;
75
+ type: string;
76
+ label?: string;
77
+ }
78
+
79
+ export interface TemplateSeedEntity {
80
+ profileSlug: string;
81
+ title: string;
82
+ properties?: Record<string, unknown>;
83
+ content?: string;
84
+ }
85
+
86
+ /**
87
+ * Relations between seed entities, created on provisioning. `sourceRef`/
88
+ * `targetRef` reference seed-entity titles (or refs) defined in `seedEntities`.
89
+ * Mirrors `suggestedRelations` in synap-backend `create-workspace-from-definition.ts`.
90
+ */
91
+ export interface TemplateSuggestedRelation {
92
+ sourceRef: string;
93
+ targetRef: string;
94
+ type: string;
95
+ metadata?: Record<string, unknown>;
96
+ }
97
+
98
+ /**
99
+ * Entity-card display templates. Mirrors `displayTemplates` in synap-backend
100
+ * `create-workspace-from-definition.ts`.
101
+ */
102
+ export interface TemplateDisplayTemplate {
103
+ name: string;
104
+ description?: string;
105
+ entityType?: string;
106
+ targetType?: string;
107
+ isDefault?: boolean;
108
+ config: Record<string, unknown>;
109
+ }
110
+
111
+ // ============================================================================
112
+ // Sidebar / Layout
113
+ // ============================================================================
114
+
115
+ export interface TemplateSidebarSurface {
116
+ kind: 'cell' | 'view' | 'entity' | 'document' | 'channel' | 'app' | 'url';
117
+ cellKey?: string;
118
+ viewId?: string;
119
+ viewName?: string;
120
+ appId?: string;
121
+ url?: string;
122
+ rendererType?: 'native' | 'external' | 'iframe-srcdoc';
123
+ placement?: 'main' | 'side' | 'floating' | 'modal' | 'popover' | 'embed';
124
+ displayMode?: 'compact' | 'medium' | 'full';
125
+ props?: Record<string, unknown>;
126
+ title?: string;
127
+ meta?: Record<string, unknown>;
128
+ }
129
+
130
+ export interface TemplateSidebarItem {
131
+ kind: 'app' | 'view' | 'profile' | 'external' | 'cell';
132
+ appId?: string;
133
+ viewName?: string;
134
+ viewId?: string;
135
+ profileSlug?: string;
136
+ url?: string;
137
+ cellKey?: string;
138
+ cellProps?: Record<string, unknown>;
139
+ /** When present, bypasses kind-based dispatch — full surface control */
140
+ surface?: TemplateSidebarSurface;
141
+ label?: string;
142
+ icon?: string;
143
+ section?: string;
144
+ matchUrls?: string[];
145
+ }
146
+
147
+ export interface TemplateLayoutConfig {
148
+ pinnedApps?: string[];
149
+ defaultView?: string;
150
+ /** The first-screen app — auto-opened on workspace switch */
151
+ defaultApp?: string | null;
152
+ theme?: string;
153
+ sidebarItems?: TemplateSidebarItem[];
154
+ }
155
+
156
+ // ============================================================================
157
+ // Bento dashboard
158
+ // ============================================================================
159
+
160
+ export interface TemplateBentoBlock {
161
+ kind: 'view' | 'widget';
162
+ viewName?: string;
163
+ widgetType?: string;
164
+ pos: { x: number; y: number; w: number; h: number };
165
+ config?: Record<string, unknown>;
166
+ overrides?: Record<string, unknown>;
167
+ }
168
+
169
+ export interface TemplateProfileEntityBentoTemplates {
170
+ [profileSlug: string]: {
171
+ blocks: Array<Record<string, unknown>>;
172
+ };
173
+ }
174
+
175
+ // ============================================================================
176
+ // Automations
177
+ // ============================================================================
178
+
179
+ export interface TemplateAutomation {
180
+ name: string;
181
+ description?: string;
182
+ trigger: string;
183
+ action: string;
184
+ config?: Record<string, unknown>;
185
+ }
186
+
187
+ // ============================================================================
188
+ // Cross-workspace source pinning
189
+ // ============================================================================
190
+
191
+ /** Mirrors `WorkspaceSourceRole` in synap-backend `schema/workspaces.ts`. */
192
+ export type TemplateSourceRole = 'provider' | 'consumer' | 'provider-consumer';
193
+
194
+ /** Mirrors `WorkspaceDefaultSource` in synap-backend `schema/workspaces.ts`. */
195
+ export interface TemplateDefaultSource {
196
+ /** The workspace id that supplies this capability domain. */
197
+ workspaceId: string;
198
+ /** The capability domain this source satisfies (e.g. "brand", "strategy"). */
199
+ capability?: string;
200
+ /** Optional profile slug the source resolves to. */
201
+ profileSlug?: string;
202
+ /** Human label for the source. */
203
+ label?: string;
204
+ }
205
+
206
+ // ============================================================================
207
+ // Onboarding spec — the per-workspace dynamic onboarding CONTEXT
208
+ //
209
+ // Written to workspace.settings.onboarding. The SHARED `onboard` skill (the
210
+ // reusable adaptive interview PROCESS) reads this to know WHAT a given
211
+ // workspace needs — without a per-domain skill file. The domain knowledge
212
+ // lives here as data, declared by each template. Mirrors `OnboardingSpec` in
213
+ // synap-backend `package-definition.ts` so the wire shape never drifts.
214
+ // ============================================================================
215
+
216
+ export interface TemplateOnboardingCollectTarget {
217
+ /** Profile slug to populate (e.g. "audience", "competitor"). */
218
+ profileSlug: string;
219
+ /** Human description of what to capture for this target. */
220
+ what: string;
221
+ /** Roughly how many to expect — guides interview depth. */
222
+ cardinality?: 'one' | 'few' | 'several';
223
+ /** Key fields the agent should make sure to fill. */
224
+ keyFields?: string[];
225
+ }
226
+
227
+ export interface TemplateOnboarding {
228
+ /** The outcome this onboarding achieves, in one sentence. */
229
+ goal: string;
230
+ /** Domain framing/voice the agent adopts for THIS workspace (the persona). */
231
+ framing: string;
232
+ /** What structured data to collect (entities to create + their key fields). */
233
+ collect: TemplateOnboardingCollectTarget[];
234
+ /** A few opening questions — the agent adapts from here, never rigid. */
235
+ openingQuestions?: string[];
236
+ /** "Done" signal the agent self-evaluates against. */
237
+ doneWhen?: string;
238
+ }
239
+
240
+ // ============================================================================
241
+ // Playbooks — session templates seeded with the workspace
242
+ //
243
+ // Mirrors `PackagePlaybook` in synap-backend `package-definition.ts`. Seeded
244
+ // via the packages/apply provisioning path (not createFromDefinition), so they
245
+ // are carried on the template but not part of WorkspaceDefinitionInput.
246
+ // ============================================================================
247
+
248
+ export interface TemplatePlaybookParam {
249
+ name: string;
250
+ type: 'text' | 'number' | 'entity' | 'choice' | 'boolean';
251
+ label?: string;
252
+ required?: boolean;
253
+ defaultValue?: unknown;
254
+ }
255
+
256
+ export interface TemplatePlaybook {
257
+ name: string;
258
+ description?: string;
259
+ goalTemplate: string;
260
+ params?: TemplatePlaybookParam[];
261
+ executor?: 'is-agent' | 'external-agent' | 'hybrid';
262
+ inputStrategy?: 'none' | 'static' | 'rotating' | 'query';
263
+ channelSpec?: {
264
+ type: 'GROUP' | 'AGENT_COLLAB' | 'THREAD';
265
+ members?: string[];
266
+ aiReactionMode?: 'on_mention' | 'always' | 'never';
267
+ };
268
+ schedule?: { cron: string } | null;
269
+ /** tool/skill keys this playbook grants. */
270
+ grants?: string[];
271
+ status?: 'draft' | 'active' | 'paused';
272
+ }
273
+
274
+ // ============================================================================
275
+ // Integrations — capability templates (tools/connectors) to install
276
+ //
277
+ // Distinct from `workspace.capabilities` (the capability slugs a workspace
278
+ // ADVERTISES). This is the list of capability TEMPLATES to INSTALL on
279
+ // provisioning (e.g. "nango-google", "agency-skills"). Mirrors
280
+ // `PackageCapability` in synap-backend `package-definition.ts`. Seeded via the
281
+ // packages/apply path (not createFromDefinition), so carried on the template.
282
+ // ============================================================================
283
+
284
+ export interface TemplateIntegration {
285
+ /** Capability template key to install (matches a capability template). */
286
+ templateKey: string;
287
+ /** Override default params with {{var}} interpolation. */
288
+ params?: Record<string, string>;
289
+ /** "apply" (create+update) or "install" (create only). */
290
+ mode?: 'apply' | 'install';
291
+ }
292
+
293
+ // ============================================================================
294
+ // Extends — inherit profiles/views from another workspace
295
+ // ============================================================================
296
+
297
+ export interface TemplateExtendsRef {
298
+ source: string;
299
+ import?: {
300
+ profiles?: string[];
301
+ views?: string[];
302
+ };
303
+ }
304
+
305
+ // ============================================================================
306
+ // Top-level template definition (YAML shape)
307
+ // ============================================================================
308
+
309
+ export interface TemplateMeta {
310
+ slug: string;
311
+ name: string;
312
+ description: string;
313
+ icon: string;
314
+ color: string;
315
+ tags?: string[];
316
+ isPublic?: boolean;
317
+ }
318
+
319
+ export interface WorkspaceYaml {
320
+ /** Template metadata — not sent to backend, used for listing/UI */
321
+ meta: TemplateMeta;
322
+
323
+ /** The workspace definition sent to createFromDefinition */
324
+ workspace: {
325
+ name: string;
326
+ description: string;
327
+ proposalId?: string;
328
+ subtype?: string;
329
+ /**
330
+ * Workspace classifier — consumed by createFromDefinition (settings.workspaceType,
331
+ * creator-role + agent-workspace behavior). Mirrors the backend union.
332
+ */
333
+ workspaceType?: 'personal' | 'agent' | 'project' | 'operational';
334
+ visibility?: string;
335
+ /** Capabilities this workspace provides (e.g. "brand.library", "content.pipeline") */
336
+ capabilities?: string[];
337
+ /**
338
+ * Cross-workspace dependency roles.
339
+ * E.g. { brand: "consumer", content: "provider" }
340
+ * "consumer" = this workspace reads from another workspace of that capability
341
+ * "provider" = this workspace provides that capability to others
342
+ */
343
+ sourceRoles?: Record<string, TemplateSourceRole>;
344
+ /**
345
+ * Pins which workspace supplies each capability domain for this workspace.
346
+ * E.g. { brand: { workspaceId: "..." } } — read by the IS source resolver
347
+ * (resolveBrandWorkspaceId / resolveFoundationWorkspaceId) before falling
348
+ * back to provider role. Usually set at runtime, not in a template, but
349
+ * carried here so it round-trips through the canonical seam.
350
+ */
351
+ defaultSources?: Record<string, TemplateDefaultSource>;
352
+ };
353
+
354
+ /** Entity profiles — the data schema */
355
+ profiles: TemplateProfile[];
356
+
357
+ /** Curated views — only the ones that add value */
358
+ views?: TemplateView[];
359
+
360
+ /** Schema-level links between entity types */
361
+ entityLinks?: TemplateEntityLink[];
362
+
363
+ /** Initial data to seed on workspace creation */
364
+ seedEntities?: TemplateSeedEntity[];
365
+
366
+ /** Relations between seed entities, created on provisioning */
367
+ suggestedRelations?: TemplateSuggestedRelation[];
368
+
369
+ /** Entity-card display templates */
370
+ displayTemplates?: TemplateDisplayTemplate[];
371
+
372
+ /** App reference — what opens as first screen */
373
+ app?: TemplateAppRef;
374
+
375
+ /** Browser sidebar + layout config */
376
+ layout?: TemplateLayoutConfig;
377
+
378
+ /** Bento dashboard */
379
+ bento?: {
380
+ viewName?: string;
381
+ blocks?: TemplateBentoBlock[];
382
+ };
383
+
384
+ /** Per-profile entity bento layouts */
385
+ profileEntityBentoTemplates?: TemplateProfileEntityBentoTemplates;
386
+
387
+ /** Automations to install on workspace creation */
388
+ automations?: TemplateAutomation[];
389
+
390
+ /** Playbooks (session templates) seeded with the workspace */
391
+ playbooks?: TemplatePlaybook[];
392
+
393
+ /** Capability templates (tools/connectors) to install on provisioning */
394
+ integrations?: TemplateIntegration[];
395
+
396
+ /**
397
+ * Per-workspace onboarding context. Written to workspace.settings.onboarding
398
+ * and read by the shared `onboard` skill to run a domain-specific adaptive
399
+ * interview — no per-domain skill file needed.
400
+ */
401
+ onboarding?: TemplateOnboarding;
402
+
403
+ /** Inherit profiles/views from other workspaces */
404
+ extends?: TemplateExtendsRef[];
405
+ }
406
+
407
+ // ============================================================================
408
+ // Resolved template — meta + fully typed definition ready for provisioning
409
+ // ============================================================================
410
+
411
+ export interface ResolvedWorkspaceTemplate {
412
+ meta: TemplateMeta;
413
+ definition: WorkspaceYaml['workspace'] & {
414
+ profiles: TemplateProfile[];
415
+ views: TemplateView[];
416
+ entityLinks: TemplateEntityLink[];
417
+ seedEntities: TemplateSeedEntity[];
418
+ app: TemplateAppRef | null;
419
+ layoutConfig: TemplateLayoutConfig | null;
420
+ bentoViewName?: string;
421
+ bentoViewBlocks?: TemplateBentoBlock[];
422
+ profileEntityBentoTemplates?: TemplateProfileEntityBentoTemplates;
423
+ automations: TemplateAutomation[];
424
+ extends?: TemplateExtendsRef[];
425
+ };
426
+ }