@synap-core/workspace-templates 0.5.0 → 0.6.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 +734 -17
- package/dist/index.js +25031 -20
- package/dist/index.js.map +1 -0
- package/package.json +7 -5
- package/src/agent-fleet.yaml +16 -8
- package/src/blockchain-ecosystem.yaml +372 -0
- package/src/catalog.test.ts +156 -0
- package/src/catalog.ts +285 -0
- package/src/communication.yaml +689 -0
- package/src/content-os.yaml +252 -771
- package/src/crm.yaml +181 -2071
- package/src/define.ts +292 -6
- package/src/dev-dashboard.yaml +3 -0
- package/src/ecosystem.yaml +478 -0
- package/src/enterprise-os.yaml +183 -0
- package/src/foundation.yaml +226 -0
- package/src/grants.yaml +1096 -0
- package/src/hr.yaml +6 -0
- package/src/index.ts +32 -5
- package/src/internal-runbook.yaml +499 -0
- package/src/legal.yaml +6 -6
- package/src/marketing.yaml +48 -12
- package/src/operations.yaml +146 -420
- package/src/social.yaml +246 -0
- package/src/templates.ts +12812 -12260
- package/src/the-arch.yaml +182 -0
- package/src/types.ts +105 -0
- package/dist/define.d.ts +0 -97
- package/dist/define.d.ts.map +0 -1
- package/dist/define.js +0 -91
- package/dist/index.d.ts.map +0 -1
- package/dist/templates.d.ts +0 -7
- package/dist/templates.d.ts.map +0 -1
- package/dist/templates.js +0 -24237
- package/dist/types.d.ts +0 -350
- package/dist/types.d.ts.map +0 -1
- package/dist/types.js +0 -8
- package/src/radar.yaml +0 -297
package/src/define.ts
CHANGED
|
@@ -10,8 +10,106 @@
|
|
|
10
10
|
* shape never drifts per call-site.
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
|
-
import type { WorkspaceYaml } from
|
|
14
|
-
import { getWorkspaceTemplate } from
|
|
13
|
+
import type { TemplateBentoBlock, WorkspaceYaml } from "./types.js";
|
|
14
|
+
import { getWorkspaceTemplate } from "./templates.js";
|
|
15
|
+
|
|
16
|
+
/** A widget block as the wire expects it: `bentoLayout[]`, keyed by `widgetType`. */
|
|
17
|
+
export interface BentoWidgetBlockWire {
|
|
18
|
+
widgetType: string;
|
|
19
|
+
pos: TemplateBentoBlock['pos'];
|
|
20
|
+
config?: Record<string, unknown>;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/** A view block as the wire expects it: `bentoViewBlocks[]`, keyed by `viewName`. */
|
|
24
|
+
export interface BentoViewBlockWire {
|
|
25
|
+
kind: 'view';
|
|
26
|
+
viewName: string;
|
|
27
|
+
pos: TemplateBentoBlock['pos'];
|
|
28
|
+
overrides?: Record<string, unknown>;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export interface SplitBentoBlocks {
|
|
32
|
+
bentoLayout: BentoWidgetBlockWire[];
|
|
33
|
+
bentoViewBlocks: BentoViewBlockWire[];
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Split the authored `bento.blocks` DISCRIMINATED UNION into the TWO wire
|
|
38
|
+
* fields the pod expects. This is the whole point: `TemplateBentoBlock` is one
|
|
39
|
+
* array discriminated by `kind`, but the pod does NOT read `kind` — it splits by
|
|
40
|
+
* FIELD (`create-workspace-from-definition.ts`):
|
|
41
|
+
*
|
|
42
|
+
* - `bentoLayout` → mapped as widgets, reads `widget.widgetType`
|
|
43
|
+
* - `bentoViewBlocks` → filtered against `viewMap[vb.viewSlug ?? vb.viewName]`,
|
|
44
|
+
* unknown entries DROPPED with a logger.warn
|
|
45
|
+
*
|
|
46
|
+
* Dumping the whole union into either single field silently mis-routes the other
|
|
47
|
+
* half — which is exactly what both converters used to do:
|
|
48
|
+
* - `toWorkspaceDefinition` sent all blocks as `bentoViewBlocks`, so widgets
|
|
49
|
+
* (no `viewName`) hit `viewMap[undefined]` and were filtered out.
|
|
50
|
+
* - `toPackageDefinition` sent all blocks as `bentoLayout`, so view blocks
|
|
51
|
+
* (no `widgetType`) became widgets with `widgetType: undefined`.
|
|
52
|
+
* Net: nobody had ever seen an authored bento render as authored.
|
|
53
|
+
*
|
|
54
|
+
* Blocks are emitted in the EXACT shape each sink declares (the tRPC
|
|
55
|
+
* `createFromDefinition` zod is strict: `bentoLayout` requires `widgetType`,
|
|
56
|
+
* `bentoViewBlocks` requires `kind: 'view'` + `viewName`), so a widget's
|
|
57
|
+
* `overrides` and a view's `config` are not smuggled into the wrong sink.
|
|
58
|
+
* Authored order is preserved WITHIN each kind; the pod concatenates
|
|
59
|
+
* `[...widgetBlocks, ...viewBlocks]`, so cross-kind order is the pod's to define.
|
|
60
|
+
*
|
|
61
|
+
* `kind` is INFERRED from field presence when absent. `TemplateBentoBlock.kind`
|
|
62
|
+
* is a required field in TypeScript, but the generated `templates.ts` casts the
|
|
63
|
+
* parsed YAML `as unknown as Record<string, WorkspaceYaml>` — so the compiler
|
|
64
|
+
* never checks the authored data against the type, and `agent-fleet.yaml`
|
|
65
|
+
* authored 8 widget blocks with no `kind:` at all (bare `widgetType`). Routing
|
|
66
|
+
* strictly on `kind` would silently DROP those — the exact failure mode this
|
|
67
|
+
* function exists to end. Inferring by field mirrors what the pod itself does
|
|
68
|
+
* (it splits by field and never reads `kind`), so the seam is total: a block
|
|
69
|
+
* that CAN be materialized always is. `scripts/check-converters.mjs` is the
|
|
70
|
+
* strict half — it fails the build if an authored block omits `kind` — so this
|
|
71
|
+
* leniency is a safety net, not a place for drift to hide.
|
|
72
|
+
*/
|
|
73
|
+
function resolveBlockKind(block: TemplateBentoBlock): 'widget' | 'view' | null {
|
|
74
|
+
if (block.kind === 'widget' || block.kind === 'view') return block.kind;
|
|
75
|
+
if (block.widgetType) return 'widget';
|
|
76
|
+
if (block.viewName) return 'view';
|
|
77
|
+
return null;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export function splitBentoBlocks(
|
|
81
|
+
blocks: TemplateBentoBlock[] | undefined
|
|
82
|
+
): SplitBentoBlocks {
|
|
83
|
+
const bentoLayout: BentoWidgetBlockWire[] = [];
|
|
84
|
+
const bentoViewBlocks: BentoViewBlockWire[] = [];
|
|
85
|
+
|
|
86
|
+
for (const block of blocks ?? []) {
|
|
87
|
+
const kind = resolveBlockKind(block);
|
|
88
|
+
if (kind === 'widget') {
|
|
89
|
+
// A widget block without `widgetType` cannot be rendered — the pod would
|
|
90
|
+
// create a `widgetType: undefined` block. Drop it loudly rather than ship
|
|
91
|
+
// a broken block; the build-time guard asserts this never happens in the
|
|
92
|
+
// authored templates.
|
|
93
|
+
if (!block.widgetType) continue;
|
|
94
|
+
bentoLayout.push({
|
|
95
|
+
widgetType: block.widgetType,
|
|
96
|
+
pos: block.pos,
|
|
97
|
+
...(block.config ? { config: block.config } : {}),
|
|
98
|
+
});
|
|
99
|
+
} else if (kind === 'view') {
|
|
100
|
+
// Same reasoning: the pod filters unknown/absent view names anyway.
|
|
101
|
+
if (!block.viewName) continue;
|
|
102
|
+
bentoViewBlocks.push({
|
|
103
|
+
kind: 'view',
|
|
104
|
+
viewName: block.viewName,
|
|
105
|
+
pos: block.pos,
|
|
106
|
+
...(block.overrides ? { overrides: block.overrides } : {}),
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
return { bentoLayout, bentoViewBlocks };
|
|
112
|
+
}
|
|
15
113
|
|
|
16
114
|
/** The flat definition object accepted by createFromDefinition. */
|
|
17
115
|
export interface WorkspaceDefinitionInput {
|
|
@@ -26,7 +124,16 @@ export interface WorkspaceDefinitionInput {
|
|
|
26
124
|
displayTemplates?: WorkspaceYaml['displayTemplates'];
|
|
27
125
|
layoutConfig: WorkspaceYaml['layout'] | undefined;
|
|
28
126
|
bentoViewName?: string;
|
|
29
|
-
|
|
127
|
+
/**
|
|
128
|
+
* WIDGET half of the authored bento union. The door declares this field
|
|
129
|
+
* (`workspaces.createFromDefinition` zod) and the pod maps it as widgets via
|
|
130
|
+
* `widget.widgetType`. It was missing from this interface entirely, which is
|
|
131
|
+
* why `toWorkspaceDefinition` had nowhere to put widgets and dumped the whole
|
|
132
|
+
* union into `bentoViewBlocks` — where every widget was silently filtered out.
|
|
133
|
+
*/
|
|
134
|
+
bentoLayout?: BentoWidgetBlockWire[];
|
|
135
|
+
/** VIEW half of the authored bento union — resolved against the viewMap. */
|
|
136
|
+
bentoViewBlocks?: BentoViewBlockWire[];
|
|
30
137
|
profileEntityBentoTemplates?: WorkspaceYaml['profileEntityBentoTemplates'];
|
|
31
138
|
// Workspace-level metadata (flattened from the `workspace` block)
|
|
32
139
|
workspaceSubtype?: string;
|
|
@@ -37,6 +144,15 @@ export interface WorkspaceDefinitionInput {
|
|
|
37
144
|
defaultSources?: NonNullable<WorkspaceYaml['workspace']>['defaultSources'];
|
|
38
145
|
/** Per-workspace onboarding context — written to settings.onboarding. */
|
|
39
146
|
onboarding?: WorkspaceYaml['onboarding'];
|
|
147
|
+
/**
|
|
148
|
+
* Template-composition dependencies. MUST be forwarded: the backend resolves
|
|
149
|
+
* these BEFORE materializing this workspace (`workspaces.createFromDefinition`
|
|
150
|
+
* → `materializeWorkspaceCore` Step 0 → `resolvePackageDependencies`), which
|
|
151
|
+
* is what installs a `require`d base FIRST and makes shared-profile base
|
|
152
|
+
* seeding deterministic. Dropping this field silently de-orders provisioning
|
|
153
|
+
* on the tRPC/UI door — see the note in `toWorkspaceDefinition`.
|
|
154
|
+
*/
|
|
155
|
+
dependencies?: WorkspaceYaml['dependencies'];
|
|
40
156
|
}
|
|
41
157
|
|
|
42
158
|
export interface ToDefinitionResult {
|
|
@@ -68,6 +184,10 @@ export function toWorkspaceDefinition(
|
|
|
68
184
|
const name = nameOverride ?? ws.name;
|
|
69
185
|
const proposalId = ws.proposalId ?? `${tpl.meta.slug}-v1`;
|
|
70
186
|
|
|
187
|
+
// The authored `bento.blocks` union must be ROUTED, not forwarded: the pod
|
|
188
|
+
// splits by field, not by `kind`. See `splitBentoBlocks`.
|
|
189
|
+
const bento = splitBentoBlocks(tpl.bento?.blocks);
|
|
190
|
+
|
|
71
191
|
const definition: WorkspaceDefinitionInput = {
|
|
72
192
|
workspaceName: name,
|
|
73
193
|
description: ws.description,
|
|
@@ -80,7 +200,8 @@ export function toWorkspaceDefinition(
|
|
|
80
200
|
displayTemplates: tpl.displayTemplates,
|
|
81
201
|
layoutConfig: tpl.layout,
|
|
82
202
|
bentoViewName: tpl.bento?.viewName,
|
|
83
|
-
|
|
203
|
+
bentoLayout: bento.bentoLayout,
|
|
204
|
+
bentoViewBlocks: bento.bentoViewBlocks,
|
|
84
205
|
profileEntityBentoTemplates: tpl.profileEntityBentoTemplates,
|
|
85
206
|
workspaceSubtype: ws.subtype,
|
|
86
207
|
workspaceType: ws.workspaceType,
|
|
@@ -89,11 +210,106 @@ export function toWorkspaceDefinition(
|
|
|
89
210
|
sourceRoles: ws.sourceRoles,
|
|
90
211
|
defaultSources: ws.defaultSources,
|
|
91
212
|
onboarding: tpl.onboarding,
|
|
213
|
+
// Template-composition dependencies — forwarded so the tRPC/UI door gets the
|
|
214
|
+
// SAME deps-first ordering the CLI/Hub door gets via `toPackageDefinition`.
|
|
215
|
+
// `workspaces.createFromDefinition` declares `dependencies` in its zod input
|
|
216
|
+
// and branches on `input.definition.dependencies?.length` to run
|
|
217
|
+
// `materializeWorkspaceCore` (Step 0 = `resolvePackageDependencies`) BEFORE
|
|
218
|
+
// creating this workspace. Omitting it here made that branch dead on every
|
|
219
|
+
// frontend call-site, so a `require: foundation` dep was silently dropped and
|
|
220
|
+
// shared-profile bases were seeded by whichever template happened to apply
|
|
221
|
+
// first. This function is documented as "the single canonical seam" — it only
|
|
222
|
+
// is one if it forwards the fields the wire shape declares.
|
|
223
|
+
dependencies: tpl.dependencies,
|
|
92
224
|
};
|
|
93
225
|
|
|
94
226
|
return { definition, proposalId, workspaceName: name, templateId: tpl.meta.slug };
|
|
95
227
|
}
|
|
96
228
|
|
|
229
|
+
// ─── Exhaustiveness ledger: toWorkspaceDefinition ────────────────────────────
|
|
230
|
+
// `WorkspaceYaml` is read by two converters and nothing forced either to be
|
|
231
|
+
// total — which is how `dependencies` was silently dropped here for months.
|
|
232
|
+
// Every key of `WorkspaceYaml` must be classified below as either FORWARDED
|
|
233
|
+
// onto the wire or explicitly DROPPED with a reason. Adding a field to
|
|
234
|
+
// `WorkspaceYaml` FAILS THE BUILD until it is classified, forcing the author
|
|
235
|
+
// to make the forward-or-drop decision instead of defaulting to silent loss.
|
|
236
|
+
//
|
|
237
|
+
// ⚠️ KNOW WHAT THIS LEDGER DOES NOT CATCH. It is FIELD-PRESENCE-exhaustive, not
|
|
238
|
+
// SEMANTICS-exhaustive. It asks "is every key classified?" — not "does the value
|
|
239
|
+
// reach the right sink?". `bento` was classified as forwarded, and it WAS
|
|
240
|
+
// forwarded: the whole discriminated union was dumped into ONE field on each
|
|
241
|
+
// door (`bentoViewBlocks` here, `bentoLayout` in `toPackageDefinition`). The
|
|
242
|
+
// ledger passed while widgets were filtered out on one door and views became
|
|
243
|
+
// `widgetType: undefined` widgets on the other. A ledger entry is a CLAIM about
|
|
244
|
+
// routing; only a runtime assertion can check the claim.
|
|
245
|
+
// → The counterpart guard for that class is `scripts/check-converters.mjs`,
|
|
246
|
+
// which RUNS both converters over all templates and asserts the per-kind
|
|
247
|
+
// block counts survive the split. Any future union-shaped field (one authored
|
|
248
|
+
// array fanning out to N wire fields) needs an assertion there too — do not
|
|
249
|
+
// let a ledger comment stand in for one.
|
|
250
|
+
|
|
251
|
+
/** Keys `toWorkspaceDefinition` reads and carries onto the wire. */
|
|
252
|
+
type WorkspaceDefinitionForwarded =
|
|
253
|
+
| 'meta' // → proposalId (meta.slug) + templateId; not a wire field itself
|
|
254
|
+
| 'workspace' // flattened into workspaceName/description/workspaceType/…
|
|
255
|
+
| 'profiles'
|
|
256
|
+
| 'views'
|
|
257
|
+
| 'entityLinks'
|
|
258
|
+
| 'seedEntities'
|
|
259
|
+
| 'suggestedRelations'
|
|
260
|
+
| 'displayTemplates'
|
|
261
|
+
| 'layout' // → layoutConfig
|
|
262
|
+
| 'bento' // → bentoViewName + bentoLayout (widgets) + bentoViewBlocks (views)
|
|
263
|
+
| 'profileEntityBentoTemplates'
|
|
264
|
+
| 'onboarding'
|
|
265
|
+
| 'dependencies';
|
|
266
|
+
|
|
267
|
+
/**
|
|
268
|
+
* Keys deliberately NOT forwarded by `toWorkspaceDefinition`. Each needs a
|
|
269
|
+
* one-line WHY. "The door has no such field" = forwarding is a no-op; anything
|
|
270
|
+
* else is a real gap and should say so.
|
|
271
|
+
*/
|
|
272
|
+
type WorkspaceDefinitionDropped =
|
|
273
|
+
// UI-only: `workspaces.createFromDefinition` has no `app` field. Consumers
|
|
274
|
+
// read `template.app` straight off the YAML to pick the first screen, so this
|
|
275
|
+
// never belonged on the wire.
|
|
276
|
+
| 'app'
|
|
277
|
+
// The door DOES accept `extends`, but no template declares it today (0/21).
|
|
278
|
+
// Forwarding is a no-op until one does — wire it then.
|
|
279
|
+
| 'extends'
|
|
280
|
+
// The door DOES accept `automations`, but no template declares it today
|
|
281
|
+
// (0/21), and its zod shape ({trigger,action:{playbook_run}}) is not
|
|
282
|
+
// `TemplateAutomation`. Needs a mapper if a template ever uses it.
|
|
283
|
+
// The browser install path installs automations via its own createAutomation door.
|
|
284
|
+
| 'automations'
|
|
285
|
+
// The door has no `integrations` field. Its `tools` field is a DIFFERENT
|
|
286
|
+
// shape ({name,kind,inputSchema} vs {templateKey,params,mode}). Capability
|
|
287
|
+
// templates are seeded via the packages/apply path, not createFromDefinition
|
|
288
|
+
// — see the note on `TemplateIntegration` in types.ts. Forwarding = no-op.
|
|
289
|
+
| 'integrations'
|
|
290
|
+
// REAL GAP (agent-fleet, project-management declare playbooks). The door
|
|
291
|
+
// accepts `playbooks`, but the shapes disagree: template param `type` allows
|
|
292
|
+
// 'text'|'entity'|'choice', the tRPC enum accepts only string|number|boolean
|
|
293
|
+
// (and defaultValue↔default, grants: string[]↔{kind,ref}[]). Raw forwarding =
|
|
294
|
+
// zod BAD_REQUEST. Needs a param mapper — separate wave, not a silent drop.
|
|
295
|
+
| 'playbooks';
|
|
296
|
+
|
|
297
|
+
type UnclassifiedWorkspaceDefinitionKey = Exclude<
|
|
298
|
+
keyof WorkspaceYaml,
|
|
299
|
+
WorkspaceDefinitionForwarded | WorkspaceDefinitionDropped
|
|
300
|
+
>;
|
|
301
|
+
|
|
302
|
+
// If this errors, a new `WorkspaceYaml` field is unclassified. Forward it in
|
|
303
|
+
// `toWorkspaceDefinition` and add it to `WorkspaceDefinitionForwarded`, or add
|
|
304
|
+
// it to `WorkspaceDefinitionDropped` with a one-line WHY.
|
|
305
|
+
const _workspaceDefinitionLedger: [UnclassifiedWorkspaceDefinitionKey] extends [never]
|
|
306
|
+
? true
|
|
307
|
+
: [
|
|
308
|
+
'UNCLASSIFIED YAML FIELD — forward it or add it to WorkspaceDefinitionDropped:',
|
|
309
|
+
UnclassifiedWorkspaceDefinitionKey,
|
|
310
|
+
] = true;
|
|
311
|
+
void _workspaceDefinitionLedger;
|
|
312
|
+
|
|
97
313
|
/**
|
|
98
314
|
* The unified `PackageDefinition` shape consumed by `POST /api/hub/packages/apply`
|
|
99
315
|
* (CLI `synap launch`) and the CP package registry seeder. It composes the
|
|
@@ -125,13 +341,25 @@ export interface PackageDefinitionOutput {
|
|
|
125
341
|
suggestedRelations?: WorkspaceYaml['suggestedRelations'];
|
|
126
342
|
displayTemplates?: WorkspaceYaml['displayTemplates'];
|
|
127
343
|
entityLinks?: WorkspaceYaml['entityLinks'];
|
|
128
|
-
|
|
344
|
+
/** WIDGET half of the authored bento union — mapped by the pod via `widgetType`. */
|
|
345
|
+
bentoLayout?: BentoWidgetBlockWire[];
|
|
346
|
+
/**
|
|
347
|
+
* VIEW half of the authored bento union. Widgets go to `bentoLayout`, views
|
|
348
|
+
* here — the pod splits by field (create-workspace-from-definition.ts:1373
|
|
349
|
+
* reads `bentoViewBlocks`), so both wire fields must be carried. The apply
|
|
350
|
+
* door's `PackageApplySchema` now declares this field (it is a plain
|
|
351
|
+
* `z.object`, so an undeclared field would be silently stripped) — the inbound
|
|
352
|
+
* seam is closed to match this outbound emit.
|
|
353
|
+
*/
|
|
354
|
+
bentoViewBlocks?: BentoViewBlockWire[];
|
|
129
355
|
bentoViewName?: string;
|
|
130
356
|
profileEntityBentoTemplates?: WorkspaceYaml['profileEntityBentoTemplates'];
|
|
131
357
|
layoutConfig?: WorkspaceYaml['layout'];
|
|
132
358
|
capabilities?: WorkspaceYaml['integrations'];
|
|
133
359
|
playbooks?: WorkspaceYaml['playbooks'];
|
|
134
360
|
onboarding?: WorkspaceYaml['onboarding'];
|
|
361
|
+
/** Template-composition dependencies — resolved by the apply endpoint. */
|
|
362
|
+
dependencies?: WorkspaceYaml['dependencies'];
|
|
135
363
|
}
|
|
136
364
|
|
|
137
365
|
/**
|
|
@@ -151,6 +379,9 @@ export function toPackageDefinition(
|
|
|
151
379
|
}
|
|
152
380
|
|
|
153
381
|
const ws = tpl.workspace;
|
|
382
|
+
// Same routing as the tRPC door — the union is split by `kind`, never dumped
|
|
383
|
+
// whole into one field. See `splitBentoBlocks`.
|
|
384
|
+
const bento = splitBentoBlocks(tpl.bento?.blocks);
|
|
154
385
|
return {
|
|
155
386
|
_meta: {
|
|
156
387
|
slug: tpl.meta.slug,
|
|
@@ -173,12 +404,67 @@ export function toPackageDefinition(
|
|
|
173
404
|
suggestedRelations: tpl.suggestedRelations,
|
|
174
405
|
displayTemplates: tpl.displayTemplates,
|
|
175
406
|
entityLinks: tpl.entityLinks,
|
|
176
|
-
bentoLayout:
|
|
407
|
+
bentoLayout: bento.bentoLayout,
|
|
408
|
+
bentoViewBlocks: bento.bentoViewBlocks,
|
|
177
409
|
bentoViewName: tpl.bento?.viewName,
|
|
178
410
|
profileEntityBentoTemplates: tpl.profileEntityBentoTemplates,
|
|
179
411
|
layoutConfig: tpl.layout,
|
|
180
412
|
capabilities: tpl.integrations,
|
|
181
413
|
playbooks: tpl.playbooks,
|
|
182
414
|
onboarding: tpl.onboarding,
|
|
415
|
+
dependencies: tpl.dependencies,
|
|
183
416
|
};
|
|
184
417
|
}
|
|
418
|
+
|
|
419
|
+
// ─── Exhaustiveness ledger: toPackageDefinition ──────────────────────────────
|
|
420
|
+
// Same forcing function as above, for the OTHER converter. These two are NOT
|
|
421
|
+
// merged on purpose: they target different endpoints with different contracts
|
|
422
|
+
// (`PackageDefinition` is a superset with renames — seedEntities→suggestedEntities,
|
|
423
|
+
// bento.blocks→bentoLayout, integrations→capabilities, plus `_meta`). Keeping
|
|
424
|
+
// two converters is fine; keeping either one lossy-by-accident is not.
|
|
425
|
+
|
|
426
|
+
/** Keys `toPackageDefinition` reads and carries onto the wire. */
|
|
427
|
+
type PackageDefinitionForwarded =
|
|
428
|
+
| 'meta' // → _meta
|
|
429
|
+
| 'workspace' // flattened into workspaceName/description/workspaceType/…
|
|
430
|
+
| 'profiles'
|
|
431
|
+
| 'views'
|
|
432
|
+
| 'seedEntities' // → suggestedEntities
|
|
433
|
+
| 'suggestedRelations'
|
|
434
|
+
| 'displayTemplates'
|
|
435
|
+
| 'entityLinks'
|
|
436
|
+
| 'bento' // → bentoViewName + bentoLayout (widgets) + bentoViewBlocks (views)
|
|
437
|
+
| 'profileEntityBentoTemplates'
|
|
438
|
+
| 'layout' // → layoutConfig
|
|
439
|
+
| 'integrations' // → capabilities
|
|
440
|
+
| 'playbooks'
|
|
441
|
+
| 'onboarding'
|
|
442
|
+
| 'dependencies';
|
|
443
|
+
|
|
444
|
+
/** Keys deliberately NOT forwarded by `toPackageDefinition`. */
|
|
445
|
+
type PackageDefinitionDropped =
|
|
446
|
+
// UI-only, same as the definition door: `PackageDefinition` has no `app`.
|
|
447
|
+
| 'app'
|
|
448
|
+
// REAL GAP: backend `PackageDefinition` DOES declare `extends`
|
|
449
|
+
// (package-definition.ts:262) and `automations` (:268), but
|
|
450
|
+
// `PackageDefinitionOutput` omits both. No template declares either today
|
|
451
|
+
// (0/21), so this is latent, not live — wire them when a template first uses
|
|
452
|
+
// one.
|
|
453
|
+
| 'extends'
|
|
454
|
+
| 'automations';
|
|
455
|
+
|
|
456
|
+
type UnclassifiedPackageDefinitionKey = Exclude<
|
|
457
|
+
keyof WorkspaceYaml,
|
|
458
|
+
PackageDefinitionForwarded | PackageDefinitionDropped
|
|
459
|
+
>;
|
|
460
|
+
|
|
461
|
+
// If this errors, a new `WorkspaceYaml` field is unclassified. Forward it in
|
|
462
|
+
// `toPackageDefinition` and add it to `PackageDefinitionForwarded`, or add it
|
|
463
|
+
// to `PackageDefinitionDropped` with a one-line WHY.
|
|
464
|
+
const _packageDefinitionLedger: [UnclassifiedPackageDefinitionKey] extends [never]
|
|
465
|
+
? true
|
|
466
|
+
: [
|
|
467
|
+
'UNCLASSIFIED YAML FIELD — forward it or add it to PackageDefinitionDropped:',
|
|
468
|
+
UnclassifiedPackageDefinitionKey,
|
|
469
|
+
] = true;
|
|
470
|
+
void _packageDefinitionLedger;
|
package/src/dev-dashboard.yaml
CHANGED
|
@@ -115,6 +115,9 @@ profiles:
|
|
|
115
115
|
color: "#8B5CF6"
|
|
116
116
|
description: "External services, tools, and providers used by the Synap platform."
|
|
117
117
|
scope: WORKSPACE
|
|
118
|
+
profileKind: role
|
|
119
|
+
applicableKinds:
|
|
120
|
+
- company
|
|
118
121
|
properties:
|
|
119
122
|
- slug: vendor-type
|
|
120
123
|
label: Vendor Type
|