@synap-core/workspace-templates 0.7.2 → 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.
- package/dist/index.d.ts +207 -8
- package/dist/index.js +2148 -1480
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/agent-fleet.yaml +666 -108
- package/src/blockchain-ecosystem.yaml +1 -0
- package/src/brand-library.yaml +127 -12
- package/src/builder.yaml +116 -12
- package/src/business-developer.yaml +102 -18
- package/src/catalog.ts +13 -3
- package/src/communication.yaml +23 -453
- package/src/composition-graph.test.ts +26 -0
- package/src/content-os.yaml +103 -10
- package/src/content-studio.yaml +1 -0
- package/src/crm.yaml +1 -0
- package/src/define.ts +8 -8
- package/src/dev-dashboard.yaml +43 -9
- package/src/domains.test.ts +117 -0
- package/src/domains.ts +102 -0
- package/src/ecosystem.yaml +21 -4
- package/src/enterprise-os.yaml +1 -0
- package/src/finance.yaml +46 -5
- package/src/foundation.yaml +13 -1
- package/src/grants.yaml +1 -0
- package/src/hr.yaml +61 -8
- package/src/index.ts +29 -0
- package/src/internal-runbook.yaml +36 -5
- package/src/legal.yaml +97 -12
- package/src/life-os.yaml +188 -27
- package/src/marketing.yaml +15 -2
- package/src/meetings-knowledge.yaml +7 -1
- package/src/operations.yaml +347 -0
- package/src/outreach-comms.yaml +6 -1
- package/src/project-management.yaml +840 -111
- package/src/research-base.yaml +516 -0
- package/src/research-decision.yaml +158 -0
- package/src/shared-role-ssot.test.ts +268 -0
- package/src/social.yaml +105 -37
- package/src/templates.ts +4548 -4304
- package/src/the-arch.yaml +1 -0
- package/src/types.ts +9 -0
- package/src/validate.test.ts +81 -0
- package/src/validate.ts +561 -0
- package/src/personal.yaml +0 -177
package/src/communication.yaml
CHANGED
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
meta:
|
|
10
10
|
slug: communication
|
|
11
|
+
domain: content
|
|
11
12
|
name: Communication
|
|
12
13
|
description: "Owns brand identity, voice, and narrative/positioning — the on-brand source of truth every downstream domain (Content, Marketing, Social) reads from so everything ships on-brand and on-message."
|
|
13
14
|
icon: messages-square
|
|
@@ -15,469 +16,32 @@ meta:
|
|
|
15
16
|
tags: [communication, brand, narrative, voice, positioning]
|
|
16
17
|
isPublic: true
|
|
17
18
|
|
|
19
|
+
# Compose onto Brand Library — the canonical brand SSOT owns the brand-* profiles
|
|
20
|
+
# (identity, colors, fonts, assets, voice guide, rules, templates, components).
|
|
21
|
+
# This overlay adds the STRATEGIC MESSAGING layer (positioning, narrative,
|
|
22
|
+
# audience, differentiator) on top, so there is ONE brand vocabulary, not two.
|
|
23
|
+
dependencies:
|
|
24
|
+
- slug: brand-library
|
|
25
|
+
kind: workspace
|
|
26
|
+
relation: compose
|
|
27
|
+
reason: "Layers positioning, narrative, and audience onto your Brand Library."
|
|
28
|
+
|
|
18
29
|
workspace:
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
30
|
+
# Composes onto Brand Library: name + subtype MATCH the base (overlay contract),
|
|
31
|
+
# visibility OMITTED (the additive reconcile would clobber the base's).
|
|
32
|
+
name: Brand Library
|
|
33
|
+
description: "The strategic messaging layer — positioning, narrative, audience, and differentiators — layered onto your Brand Library."
|
|
34
|
+
subtype: brand-library
|
|
23
35
|
capabilities:
|
|
24
|
-
- brand.library
|
|
25
|
-
- brand.identity
|
|
26
36
|
- brand.voice
|
|
27
|
-
- brand.assets
|
|
28
|
-
- brand.templates
|
|
29
|
-
- brand.components
|
|
30
37
|
- narrative.positioning
|
|
31
|
-
# Communication CONSUMES brand and PROVIDES narrative.
|
|
32
|
-
#
|
|
33
|
-
# `brand: provider` here was a LIVE bug, not dead metadata. brand-library.yaml
|
|
34
|
-
# also declares `brand: provider`, and the IS reads this to pick which
|
|
35
|
-
# workspace supplies brand for EVERY agent's system prompt
|
|
36
|
-
# (`resolveWorkspaceForCapability` in agents/utils/context-manager.ts): it
|
|
37
|
-
# filters candidates by the `brand.library` capability, then takes the FIRST
|
|
38
|
-
# workspace whose sourceRoles.brand is a provider. With both installed, "first"
|
|
39
|
-
# is whatever order listWorkspaces returned — an arbitrary, non-deterministic
|
|
40
|
-
# brand voice across turns. brand-library is the canonical brand source (this
|
|
41
|
-
# file's brand profiles are, by its own admission below, verbatim from it);
|
|
42
|
-
# Communication is the narrative/voice layer that reads from it.
|
|
43
|
-
#
|
|
44
|
-
# Every other domain in this template set has exactly ONE provider and names
|
|
45
|
-
# its consumers (content-studio: `brand: consumer`; marketing: `brand: consumer`).
|
|
46
|
-
# `brand` was the only domain with two. This restores that invariant.
|
|
47
|
-
#
|
|
48
|
-
# Expressed as a source ROLE, not `defaultSources.brand`, because a
|
|
49
|
-
# TemplateDefaultSource requires a concrete `workspaceId` (types.ts) that does
|
|
50
|
-
# not exist until provisioning — a template cannot know it. finance.yaml makes
|
|
51
|
-
# the same call for `strategy` and says so. `defaultSources` remains the
|
|
52
|
-
# correct RUNTIME override (`synap_declare_workspace_source`).
|
|
53
|
-
#
|
|
54
|
-
# The `brand.library` capability above is deliberately KEPT: it is what the
|
|
55
|
-
# resolver filters candidates on, and it makes this workspace a graceful
|
|
56
|
-
# fallback (step 3) when brand-library is not installed — in which case the
|
|
57
|
-
# local brand profiles below are exactly what the agent should read.
|
|
58
38
|
sourceRoles:
|
|
59
|
-
brand: consumer
|
|
60
39
|
narrative: provider
|
|
61
40
|
|
|
62
41
|
profiles:
|
|
63
42
|
# ═══════════════════════════════════════════════════════════════════════════
|
|
64
43
|
# BRAND KINDS — verbatim from brand-library.yaml
|
|
65
44
|
# ═══════════════════════════════════════════════════════════════════════════
|
|
66
|
-
- slug: brand-identity
|
|
67
|
-
displayName: Brand Identity
|
|
68
|
-
icon: fingerprint
|
|
69
|
-
color: amber
|
|
70
|
-
description: "Root brand context: positioning, audience, website, voice summary, and generation intent."
|
|
71
|
-
semanticSlug: brand.identity
|
|
72
|
-
properties:
|
|
73
|
-
- slug: brand-type
|
|
74
|
-
label: Brand type
|
|
75
|
-
valueType: string
|
|
76
|
-
inputType: select
|
|
77
|
-
enumValues: [product-digital, product-physical, agency, personal-brand, nonprofit, institutional, universal]
|
|
78
|
-
constraints: { defaultValue: universal }
|
|
79
|
-
- slug: brand-status
|
|
80
|
-
label: Status
|
|
81
|
-
valueType: string
|
|
82
|
-
inputType: select
|
|
83
|
-
enumValues: [draft, active, archived]
|
|
84
|
-
constraints: { defaultValue: active }
|
|
85
|
-
- slug: brand-tagline
|
|
86
|
-
label: Tagline
|
|
87
|
-
valueType: string
|
|
88
|
-
inputType: text
|
|
89
|
-
- slug: brand-website
|
|
90
|
-
label: Website
|
|
91
|
-
valueType: string
|
|
92
|
-
inputType: url
|
|
93
|
-
- slug: brand-industry
|
|
94
|
-
label: Industry
|
|
95
|
-
valueType: string
|
|
96
|
-
inputType: text
|
|
97
|
-
- slug: brand-positioning
|
|
98
|
-
label: Positioning
|
|
99
|
-
valueType: string
|
|
100
|
-
inputType: textarea
|
|
101
|
-
- slug: brand-audience-primary
|
|
102
|
-
label: Primary audience
|
|
103
|
-
valueType: string
|
|
104
|
-
inputType: textarea
|
|
105
|
-
- slug: brand-audience-secondary
|
|
106
|
-
label: Secondary audience
|
|
107
|
-
valueType: string
|
|
108
|
-
inputType: textarea
|
|
109
|
-
- slug: brand-voice-summary
|
|
110
|
-
label: Voice summary
|
|
111
|
-
valueType: string
|
|
112
|
-
inputType: textarea
|
|
113
|
-
- slug: brand-notes
|
|
114
|
-
label: Notes
|
|
115
|
-
valueType: string
|
|
116
|
-
inputType: textarea
|
|
117
|
-
|
|
118
|
-
- slug: brand-color
|
|
119
|
-
displayName: Brand Color
|
|
120
|
-
icon: swatch-book
|
|
121
|
-
color: violet
|
|
122
|
-
description: Approved palette entry with semantic role, usage notes, and print references.
|
|
123
|
-
semanticSlug: brand.color
|
|
124
|
-
properties:
|
|
125
|
-
- slug: color-role
|
|
126
|
-
label: Role
|
|
127
|
-
valueType: string
|
|
128
|
-
inputType: select
|
|
129
|
-
enumValues: [primary, secondary, accent, background, surface, surface-elevated, text, text-muted, border, success, warning, error, info, neutral, campaign, custom]
|
|
130
|
-
constraints: { defaultValue: custom }
|
|
131
|
-
- slug: color-group
|
|
132
|
-
label: Group
|
|
133
|
-
valueType: string
|
|
134
|
-
inputType: select
|
|
135
|
-
enumValues: [core, extended, semantic, neutral, seasonal, campaign]
|
|
136
|
-
constraints: { defaultValue: core }
|
|
137
|
-
- slug: color-hex
|
|
138
|
-
label: Hex
|
|
139
|
-
valueType: string
|
|
140
|
-
inputType: color
|
|
141
|
-
- slug: color-rgb
|
|
142
|
-
label: RGB
|
|
143
|
-
valueType: string
|
|
144
|
-
inputType: text
|
|
145
|
-
- slug: color-cmyk
|
|
146
|
-
label: CMYK
|
|
147
|
-
valueType: string
|
|
148
|
-
inputType: text
|
|
149
|
-
- slug: color-pantone
|
|
150
|
-
label: Pantone
|
|
151
|
-
valueType: string
|
|
152
|
-
inputType: text
|
|
153
|
-
- slug: color-ral
|
|
154
|
-
label: RAL
|
|
155
|
-
valueType: string
|
|
156
|
-
inputType: text
|
|
157
|
-
- slug: color-token-name
|
|
158
|
-
label: Token name
|
|
159
|
-
valueType: string
|
|
160
|
-
inputType: text
|
|
161
|
-
- slug: color-usage
|
|
162
|
-
label: Usage note
|
|
163
|
-
valueType: string
|
|
164
|
-
inputType: textarea
|
|
165
|
-
- slug: color-status
|
|
166
|
-
label: Status
|
|
167
|
-
valueType: string
|
|
168
|
-
inputType: select
|
|
169
|
-
enumValues: [draft, approved, deprecated]
|
|
170
|
-
constraints: { defaultValue: approved }
|
|
171
|
-
|
|
172
|
-
- slug: brand-font
|
|
173
|
-
displayName: Brand Typeface
|
|
174
|
-
icon: type
|
|
175
|
-
color: blue
|
|
176
|
-
description: Typeface with role, family, licensing, import URL, weights, and fallback stack.
|
|
177
|
-
semanticSlug: brand.font
|
|
178
|
-
properties:
|
|
179
|
-
- slug: font-role
|
|
180
|
-
label: Role
|
|
181
|
-
valueType: string
|
|
182
|
-
inputType: select
|
|
183
|
-
enumValues: [heading, body, display, mono, accent, ui, caption]
|
|
184
|
-
constraints: { defaultValue: body }
|
|
185
|
-
- slug: font-family
|
|
186
|
-
label: Family
|
|
187
|
-
valueType: string
|
|
188
|
-
inputType: text
|
|
189
|
-
- slug: font-foundry
|
|
190
|
-
label: Foundry
|
|
191
|
-
valueType: string
|
|
192
|
-
inputType: text
|
|
193
|
-
- slug: font-license
|
|
194
|
-
label: License
|
|
195
|
-
valueType: string
|
|
196
|
-
inputType: select
|
|
197
|
-
enumValues: [open-source, google-fonts, adobe-fonts, licensed, custom, system]
|
|
198
|
-
constraints: { defaultValue: google-fonts }
|
|
199
|
-
- slug: font-weights
|
|
200
|
-
label: Weights
|
|
201
|
-
valueType: string
|
|
202
|
-
inputType: text
|
|
203
|
-
- slug: font-fallback
|
|
204
|
-
label: Fallback stack
|
|
205
|
-
valueType: string
|
|
206
|
-
inputType: text
|
|
207
|
-
- slug: font-url
|
|
208
|
-
label: Import URL
|
|
209
|
-
valueType: string
|
|
210
|
-
inputType: url
|
|
211
|
-
- slug: font-document-id
|
|
212
|
-
label: Font document ID
|
|
213
|
-
valueType: string
|
|
214
|
-
inputType: text
|
|
215
|
-
- slug: font-status
|
|
216
|
-
label: Status
|
|
217
|
-
valueType: string
|
|
218
|
-
inputType: select
|
|
219
|
-
enumValues: [active, draft, deprecated]
|
|
220
|
-
constraints: { defaultValue: active }
|
|
221
|
-
|
|
222
|
-
- slug: brand-asset
|
|
223
|
-
displayName: Brand Asset
|
|
224
|
-
icon: image
|
|
225
|
-
color: green
|
|
226
|
-
description: "Document-backed or URL-backed reusable media: logos, imagery, icons, fonts, video, references, and documents."
|
|
227
|
-
semanticSlug: brand.asset
|
|
228
|
-
properties:
|
|
229
|
-
- slug: asset-kind
|
|
230
|
-
label: Kind
|
|
231
|
-
valueType: string
|
|
232
|
-
inputType: select
|
|
233
|
-
enumValues: [logo, wordmark, symbol, monogram, pattern, texture, icon-set, illustration, photo, video, document, font, 3d-model, print-ready, reference, other]
|
|
234
|
-
- slug: asset-variant
|
|
235
|
-
label: Variant
|
|
236
|
-
valueType: string
|
|
237
|
-
inputType: select
|
|
238
|
-
enumValues: [primary, secondary, horizontal, stacked, mono-dark, mono-light, white, reversed, favicon, social-avatar, og-image, other]
|
|
239
|
-
- slug: asset-status
|
|
240
|
-
label: Status
|
|
241
|
-
valueType: string
|
|
242
|
-
inputType: select
|
|
243
|
-
enumValues: [draft, approved, deprecated]
|
|
244
|
-
constraints: { defaultValue: approved }
|
|
245
|
-
- slug: asset-usage
|
|
246
|
-
label: Usage notes
|
|
247
|
-
valueType: string
|
|
248
|
-
inputType: textarea
|
|
249
|
-
- slug: asset-tags
|
|
250
|
-
label: Tags
|
|
251
|
-
valueType: string
|
|
252
|
-
inputType: text
|
|
253
|
-
- slug: asset-url
|
|
254
|
-
label: External URL
|
|
255
|
-
valueType: string
|
|
256
|
-
inputType: url
|
|
257
|
-
- slug: asset-document-id
|
|
258
|
-
label: Document ID
|
|
259
|
-
valueType: string
|
|
260
|
-
inputType: text
|
|
261
|
-
- slug: asset-file-id
|
|
262
|
-
label: Legacy file ID
|
|
263
|
-
valueType: string
|
|
264
|
-
inputType: text
|
|
265
|
-
- slug: asset-alt-text
|
|
266
|
-
label: Alt text
|
|
267
|
-
valueType: string
|
|
268
|
-
inputType: textarea
|
|
269
|
-
|
|
270
|
-
- slug: brand-reference
|
|
271
|
-
displayName: Brand Reference
|
|
272
|
-
icon: bookmark
|
|
273
|
-
color: teal
|
|
274
|
-
description: Website, competitor, campaign, moodboard, or example used as source context for generation.
|
|
275
|
-
semanticSlug: brand.reference
|
|
276
|
-
properties:
|
|
277
|
-
- slug: reference-kind
|
|
278
|
-
label: Kind
|
|
279
|
-
valueType: string
|
|
280
|
-
inputType: select
|
|
281
|
-
enumValues: [website, competitor, campaign, moodboard, copy-example, design-example, customer-example, other]
|
|
282
|
-
- slug: reference-url
|
|
283
|
-
label: URL
|
|
284
|
-
valueType: string
|
|
285
|
-
inputType: url
|
|
286
|
-
- slug: reference-notes
|
|
287
|
-
label: Notes
|
|
288
|
-
valueType: string
|
|
289
|
-
inputType: textarea
|
|
290
|
-
- slug: reference-status
|
|
291
|
-
label: Status
|
|
292
|
-
valueType: string
|
|
293
|
-
inputType: select
|
|
294
|
-
enumValues: [draft, approved, archived]
|
|
295
|
-
constraints: { defaultValue: approved }
|
|
296
|
-
|
|
297
|
-
- slug: brand-token-set
|
|
298
|
-
displayName: Token Set
|
|
299
|
-
icon: code-2
|
|
300
|
-
color: violet
|
|
301
|
-
description: Generated or curated design tokens for color, typography, spacing, radii, and exported CSS variables.
|
|
302
|
-
semanticSlug: brand.tokens
|
|
303
|
-
properties:
|
|
304
|
-
- slug: token-status
|
|
305
|
-
label: Status
|
|
306
|
-
valueType: string
|
|
307
|
-
inputType: select
|
|
308
|
-
enumValues: [draft, active, archived]
|
|
309
|
-
constraints: { defaultValue: active }
|
|
310
|
-
- slug: token-mode
|
|
311
|
-
label: Mode
|
|
312
|
-
valueType: string
|
|
313
|
-
inputType: select
|
|
314
|
-
enumValues: [base, light, dark, high-contrast, campaign, experimental]
|
|
315
|
-
constraints: { defaultValue: base }
|
|
316
|
-
- slug: token-source-ids
|
|
317
|
-
label: Source IDs
|
|
318
|
-
valueType: string
|
|
319
|
-
inputType: textarea
|
|
320
|
-
- slug: token-json
|
|
321
|
-
label: Tokens JSON
|
|
322
|
-
valueType: string
|
|
323
|
-
inputType: textarea
|
|
324
|
-
- slug: token-css
|
|
325
|
-
label: CSS variables
|
|
326
|
-
valueType: string
|
|
327
|
-
inputType: textarea
|
|
328
|
-
- slug: token-notes
|
|
329
|
-
label: Notes
|
|
330
|
-
valueType: string
|
|
331
|
-
inputType: textarea
|
|
332
|
-
|
|
333
|
-
- slug: brand-voice-guide
|
|
334
|
-
displayName: Voice Guide
|
|
335
|
-
icon: message-circle
|
|
336
|
-
color: orange
|
|
337
|
-
description: "Generated or curated voice guidance by context: traits, tone, vocabulary, and copy examples."
|
|
338
|
-
semanticSlug: brand.voice
|
|
339
|
-
properties:
|
|
340
|
-
- slug: voice-context
|
|
341
|
-
label: Context
|
|
342
|
-
valueType: string
|
|
343
|
-
inputType: select
|
|
344
|
-
enumValues: [general, marketing, product, support, social, legal, editorial, investor]
|
|
345
|
-
constraints: { defaultValue: general }
|
|
346
|
-
- slug: voice-status
|
|
347
|
-
label: Status
|
|
348
|
-
valueType: string
|
|
349
|
-
inputType: select
|
|
350
|
-
enumValues: [draft, approved, deprecated]
|
|
351
|
-
constraints: { defaultValue: approved }
|
|
352
|
-
- slug: voice-personality-traits
|
|
353
|
-
label: Personality
|
|
354
|
-
valueType: string
|
|
355
|
-
inputType: textarea
|
|
356
|
-
- slug: voice-tone-descriptors
|
|
357
|
-
label: Tone
|
|
358
|
-
valueType: string
|
|
359
|
-
inputType: text
|
|
360
|
-
- slug: voice-vocabulary
|
|
361
|
-
label: Vocabulary
|
|
362
|
-
valueType: string
|
|
363
|
-
inputType: textarea
|
|
364
|
-
- slug: voice-example-do
|
|
365
|
-
label: Do
|
|
366
|
-
valueType: string
|
|
367
|
-
inputType: textarea
|
|
368
|
-
- slug: voice-example-dont
|
|
369
|
-
label: Don't
|
|
370
|
-
valueType: string
|
|
371
|
-
inputType: textarea
|
|
372
|
-
- slug: voice-source-ids
|
|
373
|
-
label: Source IDs
|
|
374
|
-
valueType: string
|
|
375
|
-
inputType: textarea
|
|
376
|
-
|
|
377
|
-
- slug: brand-rule
|
|
378
|
-
displayName: Brand Rule
|
|
379
|
-
icon: shield-check
|
|
380
|
-
color: red
|
|
381
|
-
description: Usage constraints, accessibility requirements, do/don't examples, and generation guidance.
|
|
382
|
-
semanticSlug: brand.rule
|
|
383
|
-
properties:
|
|
384
|
-
- slug: rule-kind
|
|
385
|
-
label: Kind
|
|
386
|
-
valueType: string
|
|
387
|
-
inputType: select
|
|
388
|
-
enumValues: [visual, voice, legal, accessibility, sizing, clearance, color-usage, typography-usage, do, dont, generation, other]
|
|
389
|
-
- slug: rule-subject
|
|
390
|
-
label: Subject
|
|
391
|
-
valueType: string
|
|
392
|
-
inputType: select
|
|
393
|
-
enumValues: [logo, color, typography, pattern, asset, voice, general, digital, print, packaging]
|
|
394
|
-
- slug: rule-severity
|
|
395
|
-
label: Severity
|
|
396
|
-
valueType: string
|
|
397
|
-
inputType: select
|
|
398
|
-
enumValues: [guideline, important, mandatory]
|
|
399
|
-
constraints: { defaultValue: important }
|
|
400
|
-
- slug: rule-content
|
|
401
|
-
label: Rule
|
|
402
|
-
valueType: string
|
|
403
|
-
inputType: textarea
|
|
404
|
-
- slug: rule-example
|
|
405
|
-
label: Example
|
|
406
|
-
valueType: string
|
|
407
|
-
inputType: textarea
|
|
408
|
-
- slug: rule-source-ids
|
|
409
|
-
label: Source IDs
|
|
410
|
-
valueType: string
|
|
411
|
-
inputType: textarea
|
|
412
|
-
|
|
413
|
-
- slug: brand-template
|
|
414
|
-
displayName: Brand Template
|
|
415
|
-
icon: layout-template
|
|
416
|
-
color: pink
|
|
417
|
-
description: Reusable output template for artboards, decks, carousels, banners, documents, or generated HTML.
|
|
418
|
-
semanticSlug: brand.template
|
|
419
|
-
properties:
|
|
420
|
-
- slug: template-kind
|
|
421
|
-
label: Kind
|
|
422
|
-
valueType: string
|
|
423
|
-
inputType: select
|
|
424
|
-
enumValues: [artboard, deck, carousel, banner, document, html, social, other]
|
|
425
|
-
- slug: template-status
|
|
426
|
-
label: Status
|
|
427
|
-
valueType: string
|
|
428
|
-
inputType: select
|
|
429
|
-
enumValues: [draft, approved, deprecated]
|
|
430
|
-
constraints: { defaultValue: approved }
|
|
431
|
-
- slug: template-format
|
|
432
|
-
label: Format
|
|
433
|
-
valueType: string
|
|
434
|
-
inputType: select
|
|
435
|
-
enumValues: [tldraw, html, json, markdown, image, mixed]
|
|
436
|
-
- slug: template-config
|
|
437
|
-
label: Config JSON
|
|
438
|
-
valueType: string
|
|
439
|
-
inputType: textarea
|
|
440
|
-
- slug: template-usage
|
|
441
|
-
label: Usage notes
|
|
442
|
-
valueType: string
|
|
443
|
-
inputType: textarea
|
|
444
|
-
|
|
445
|
-
- slug: brand-component
|
|
446
|
-
displayName: Brand Component
|
|
447
|
-
icon: component
|
|
448
|
-
color: green
|
|
449
|
-
description: "Reusable branded UI or content component: hero, CTA, card, quote, banner, section, or HTML snippet."
|
|
450
|
-
semanticSlug: brand.component
|
|
451
|
-
properties:
|
|
452
|
-
- slug: component-kind
|
|
453
|
-
label: Kind
|
|
454
|
-
valueType: string
|
|
455
|
-
inputType: select
|
|
456
|
-
enumValues: [hero, card, cta, quote, banner, section, layout, html, other]
|
|
457
|
-
- slug: component-status
|
|
458
|
-
label: Status
|
|
459
|
-
valueType: string
|
|
460
|
-
inputType: select
|
|
461
|
-
enumValues: [draft, approved, deprecated]
|
|
462
|
-
constraints: { defaultValue: approved }
|
|
463
|
-
- slug: component-html
|
|
464
|
-
label: HTML
|
|
465
|
-
valueType: string
|
|
466
|
-
inputType: textarea
|
|
467
|
-
- slug: component-props
|
|
468
|
-
label: Props JSON
|
|
469
|
-
valueType: string
|
|
470
|
-
inputType: textarea
|
|
471
|
-
- slug: component-usage
|
|
472
|
-
label: Usage notes
|
|
473
|
-
valueType: string
|
|
474
|
-
inputType: textarea
|
|
475
|
-
|
|
476
|
-
# ═══════════════════════════════════════════════════════════════════════════
|
|
477
|
-
# NARRATIVE KINDS — verbatim from foundation.yaml
|
|
478
|
-
# (Communication owns the narrative ARTIFACTS: positioning, story arc,
|
|
479
|
-
# audiences, and differentiators — NOT mission/vision/values.)
|
|
480
|
-
# ═══════════════════════════════════════════════════════════════════════════
|
|
481
45
|
- slug: positioning
|
|
482
46
|
displayName: Positioning
|
|
483
47
|
icon: crosshair
|
|
@@ -630,7 +194,13 @@ onboarding:
|
|
|
630
194
|
- profileSlug: brand-voice-guide
|
|
631
195
|
what: Voice guides — tone, personality traits, vocabulary, and do/don't examples per context.
|
|
632
196
|
cardinality: few
|
|
633
|
-
keyFields:
|
|
197
|
+
keyFields:
|
|
198
|
+
[
|
|
199
|
+
voice-personality-traits,
|
|
200
|
+
voice-tone-descriptors,
|
|
201
|
+
voice-example-do,
|
|
202
|
+
voice-example-dont,
|
|
203
|
+
]
|
|
634
204
|
- profileSlug: brand-rule
|
|
635
205
|
what: Usage and voice rules (mandatory / important / guideline).
|
|
636
206
|
cardinality: several
|
|
@@ -11,6 +11,7 @@ import { test } from "vitest";
|
|
|
11
11
|
import assert from "node:assert/strict";
|
|
12
12
|
import { layerTemplateGraph, type CompositionGraph } from "./composition-graph.js";
|
|
13
13
|
import type { TemplateDependency } from "./types.js";
|
|
14
|
+
import { readYamlTemplates } from "./generate.mjs";
|
|
14
15
|
|
|
15
16
|
/** Build a small `edgesOf` from a plain adjacency map, for test fixtures. */
|
|
16
17
|
function edgesFrom(map: Record<string, TemplateDependency[]>) {
|
|
@@ -120,6 +121,31 @@ test("cycle: A→B→A terminates and reports the broken edge in cycles[]", () =
|
|
|
120
121
|
assert.equal(graph.nodes.get("A")!.layer, 0);
|
|
121
122
|
});
|
|
122
123
|
|
|
124
|
+
// ── Corpus invariant: the SHIPPED template graph is acyclic ───────────────────
|
|
125
|
+
// `build.mjs` catches dangling deps at authoring time, but a `compose`/`require`
|
|
126
|
+
// CYCLE among real templates would sink each node to layer 0 and (at install)
|
|
127
|
+
// have the resolver chase its own tail. The engine already surfaces broken
|
|
128
|
+
// back-edges in `cycles[]` — assert the real corpus has none, reading YAML
|
|
129
|
+
// straight off disk (not the committed templates.ts) so a stale snapshot can't
|
|
130
|
+
// hide a freshly-introduced loop.
|
|
131
|
+
test("corpus: the shipped template dependency graph has no cycles", () => {
|
|
132
|
+
const templates = readYamlTemplates() as Array<{
|
|
133
|
+
slug: string;
|
|
134
|
+
data: { dependencies?: TemplateDependency[] };
|
|
135
|
+
}>;
|
|
136
|
+
const bySlug = new Map(templates.map((t) => [t.slug, t.data]));
|
|
137
|
+
const roots = templates.map((t) => t.slug);
|
|
138
|
+
const edgesOf = (slug: string): readonly TemplateDependency[] =>
|
|
139
|
+
bySlug.get(slug)?.dependencies ?? [];
|
|
140
|
+
|
|
141
|
+
const graph = layerTemplateGraph({ roots, edgesOf });
|
|
142
|
+
assert.deepEqual(
|
|
143
|
+
graph.cycles,
|
|
144
|
+
[],
|
|
145
|
+
`template dependency graph must be acyclic — broken back-edges: ${JSON.stringify(graph.cycles)}`,
|
|
146
|
+
);
|
|
147
|
+
});
|
|
148
|
+
|
|
123
149
|
// ── edgesOf injection ─────────────────────────────────────────────────────────
|
|
124
150
|
test("edgesOf injection: deps supplied for a slug NOT in the bundled map are still walked", () => {
|
|
125
151
|
// "private-remote-pkg" does not exist in the bundled WORKSPACE_TEMPLATES map
|