@teamix-evo/registry 0.2.0 → 0.3.0

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.js CHANGED
@@ -82,7 +82,20 @@ var SkillEntrySchema = z.object({
82
82
  /** Managed region IDs to maintain on update */
83
83
  managedRegions: z.array(z.string()).optional(),
84
84
  /** Whether the source is a Handlebars template */
85
- template: z.boolean().optional()
85
+ template: z.boolean().optional(),
86
+ /**
87
+ * Variant identifier when this skill is bound to a specific design variant
88
+ * (e.g. `"opentrek"`, `"uni-manager"`). Optional — neutral skills (manage,
89
+ * coding-conventions, baseline design-rules) leave it unset.
90
+ *
91
+ * When present, the CLI installs this skill ONLY if the consumer's
92
+ * `.teamix-evo/design/pack.lock.json` records the same variant. MUST equal
93
+ * the variant directory name in `@teamix-evo/design/variants/<name>/`.
94
+ *
95
+ * Mirrors `UiEntrySchema.variant` semantics in @teamix-evo/biz-ui &
96
+ * @teamix-evo/templates per ADR 0014.
97
+ */
98
+ variant: z.string().optional()
86
99
  });
87
100
  var SkillsPackageManifestSchema = z.object({
88
101
  $schema: z.string().optional(),
@@ -102,9 +115,17 @@ var UiEntryTypeSchema = z.enum([
102
115
  "component",
103
116
  "hook",
104
117
  "util",
105
- "block"
118
+ "block",
119
+ "template"
120
+ ]);
121
+ var UiAliasSchema = z.enum([
122
+ "components",
123
+ "hooks",
124
+ "utils",
125
+ "lib",
126
+ "business",
127
+ "templates"
106
128
  ]);
107
- var UiAliasSchema = z.enum(["components", "hooks", "utils", "lib"]);
108
129
  var UiEntryStatusSchema = z.enum([
109
130
  "stable",
110
131
  "experimental",
@@ -167,7 +188,14 @@ var UiEntrySchema = z.object({
167
188
  * If this entry is `deprecated`, the id of the entry that supersedes it.
168
189
  * Consumers (and AI) should migrate to `replacedBy` rather than this entry.
169
190
  */
170
- replacedBy: z.string().optional()
191
+ replacedBy: z.string().optional(),
192
+ /**
193
+ * Variant identifier when this entry is shipped from a variant-aware
194
+ * package (`@teamix-evo/biz-ui` or `@teamix-evo/templates` per ADR 0014).
195
+ * Optional — entries from `@teamix-evo/ui` (variant-agnostic) leave it unset.
196
+ * MUST equal the variant directory name when present.
197
+ */
198
+ variant: z.string().optional()
171
199
  });
172
200
  var UiPackageManifestSchema = z.object({
173
201
  $schema: z.string().optional(),
@@ -184,24 +212,148 @@ var UiPackageManifestSchema = z.object({
184
212
  entries: z.array(UiEntrySchema)
185
213
  });
186
214
 
187
- // src/schema/config.ts
215
+ // src/schema/design-pack.ts
188
216
  import { z as z2 } from "zod";
189
- var TailwindVersionSchema = z2.enum(["v3", "v4"]);
190
- var UiAliasesSchema = z2.object({
191
- components: z2.string().min(1),
192
- hooks: z2.string().min(1),
193
- utils: z2.string().min(1),
194
- lib: z2.string().min(1)
217
+ var VARIANT_NAME_RE = /^[a-z][a-z0-9-]*$/;
218
+ var SEMVER_RE = /^\d+\.\d+\.\d+/;
219
+ var DesignPackLinkedSchema = z2.object({
220
+ "biz-ui": z2.string().optional(),
221
+ templates: z2.string().optional()
222
+ });
223
+ var DesignPackManifestSchema = z2.object({
224
+ $schema: z2.string().optional(),
225
+ schemaVersion: z2.literal(1),
226
+ /**
227
+ * Pack identifier.
228
+ * - `"default"` for the built-in baseline (only valid name when `extends` is absent)
229
+ * - lowercase kebab-case for variants (`opentrek`, `uni-manager`, `acme-erp`, `_template`)
230
+ */
231
+ name: z2.string().min(1).regex(
232
+ VARIANT_NAME_RE,
233
+ 'Pack name must be lowercase letters/digits/hyphens (no leading hyphen). Special: "_template" allowed for the variant scaffold.'
234
+ ).or(z2.literal("_template")).or(z2.literal("default")),
235
+ /** Human-readable display name (e.g. "OpenTrek" for variant id "opentrek"). */
236
+ displayName: z2.string().min(1),
237
+ /** Semver. */
238
+ version: z2.string().regex(SEMVER_RE, "Invalid semver version"),
239
+ /**
240
+ * Parent pack name. Required for variants, must be omitted for `default`.
241
+ * Currently only `"default"` is a valid parent.
242
+ */
243
+ extends: z2.string().optional(),
244
+ /** Optional one-liner; useful for `design list-variants` output. */
245
+ description: z2.string().optional(),
246
+ /** Soft cross-package links (biz-ui / templates with same variant name). */
247
+ linked: DesignPackLinkedSchema.optional()
248
+ });
249
+ var DesignPackageManifestSchema = z2.object({
250
+ $schema: z2.string().optional(),
251
+ schemaVersion: z2.literal(1),
252
+ /** Always `"design"` for this package. */
253
+ package: z2.literal("design"),
254
+ /** Semver of the entire design package. */
255
+ version: z2.string().regex(SEMVER_RE, "Invalid semver version"),
256
+ /** Engine compatibility. */
257
+ engines: z2.object({ "teamix-evo": z2.string().min(1) }),
258
+ /** The default baseline pack — always present. */
259
+ default: DesignPackManifestSchema,
260
+ /** All shipped variants (excluding `_template/`). */
261
+ variants: z2.array(DesignPackManifestSchema)
262
+ });
263
+ var DesignPackLockSchema = z2.object({
264
+ $schema: z2.string().optional(),
265
+ schemaVersion: z2.literal(1),
266
+ default: z2.object({
267
+ version: z2.string().regex(SEMVER_RE),
268
+ from: z2.string().min(1)
269
+ // e.g. "@teamix-evo/design"
270
+ }),
271
+ variant: z2.object({
272
+ name: z2.string().min(1),
273
+ displayName: z2.string().min(1),
274
+ version: z2.string().regex(SEMVER_RE),
275
+ from: z2.string().min(1)
276
+ }),
277
+ linked: DesignPackLinkedSchema.optional(),
278
+ installedAt: z2.string().datetime()
279
+ });
280
+
281
+ // src/schema/variant-ui-pack.ts
282
+ import { z as z3 } from "zod";
283
+ var SEMVER_RE2 = /^\d+\.\d+\.\d+/;
284
+ var VARIANT_NAME_RE2 = /^[a-z][a-z0-9-]*$/;
285
+ var VariantUiPackageNameSchema = z3.enum(["biz-ui", "templates"]);
286
+ var VariantUiPackageManifestSchema = z3.object({
287
+ $schema: z3.string().optional(),
288
+ schemaVersion: z3.literal(1),
289
+ /** Discriminator. */
290
+ package: VariantUiPackageNameSchema,
291
+ /**
292
+ * Variant identifier — lowercase kebab-case, MUST match the parent
293
+ * directory name (e.g. `opentrek` for `variants/opentrek/manifest.json`).
294
+ * `_template` is also accepted for the variant scaffold.
295
+ */
296
+ variant: z3.string().min(1).regex(
297
+ VARIANT_NAME_RE2,
298
+ 'Variant id must be lowercase letters/digits/hyphens (no leading hyphen). Special: "_template" allowed.'
299
+ ).or(z3.literal("_template")),
300
+ /** Semver of this variant. */
301
+ version: z3.string().regex(SEMVER_RE2, "Invalid semver version"),
302
+ /** Engine compatibility. */
303
+ engines: z3.object({ "teamix-evo": z3.string().min(1) }),
304
+ /** Flat list of entries shipped by this variant. */
305
+ entries: z3.array(UiEntrySchema)
306
+ }).superRefine((data, ctx) => {
307
+ for (const [i, entry] of data.entries.entries()) {
308
+ if (entry.variant !== void 0 && entry.variant !== data.variant) {
309
+ ctx.addIssue({
310
+ code: z3.ZodIssueCode.custom,
311
+ path: ["entries", i, "variant"],
312
+ message: `Entry "${entry.id}" declares variant "${entry.variant}" but lives in manifest of variant "${data.variant}".`
313
+ });
314
+ }
315
+ }
316
+ });
317
+ var VariantUiPackageCatalogSchema = z3.object({
318
+ $schema: z3.string().optional(),
319
+ schemaVersion: z3.literal(1),
320
+ package: VariantUiPackageNameSchema,
321
+ /** Semver of the entire package. */
322
+ version: z3.string().regex(SEMVER_RE2, "Invalid semver version"),
323
+ engines: z3.object({ "teamix-evo": z3.string().min(1) }),
324
+ /** Variants this package ships (excluding `_template`). */
325
+ variants: z3.array(
326
+ z3.object({
327
+ name: z3.string().min(1).regex(VARIANT_NAME_RE2),
328
+ displayName: z3.string().min(1),
329
+ version: z3.string().regex(SEMVER_RE2),
330
+ description: z3.string().optional()
331
+ })
332
+ )
333
+ });
334
+
335
+ // src/schema/config.ts
336
+ import { z as z4 } from "zod";
337
+ var TailwindVersionSchema = z4.literal("v4");
338
+ var UiAliasesSchema = z4.object({
339
+ components: z4.string().min(1),
340
+ hooks: z4.string().min(1),
341
+ utils: z4.string().min(1),
342
+ lib: z4.string().min(1),
343
+ /** Biz-ui components (variant-bound). Defaults to `src/components/business/`. */
344
+ business: z4.string().min(1).default("src/components/business"),
345
+ /** Page templates (variant-bound). Defaults to `src/templates/`. */
346
+ templates: z4.string().min(1).default("src/templates")
195
347
  });
196
- var PackageEntrySchema = z2.object({
348
+ var PackageEntrySchema = z4.object({
197
349
  /** Variant identifier (e.g. "opentrek"; use "_flat" for skills/ui) */
198
- variant: z2.string().min(1),
350
+ variant: z4.string().min(1),
199
351
  /** Semver version string */
200
- version: z2.string().min(1),
352
+ version: z4.string().min(1),
201
353
  /** Tailwind CSS version this project uses (only meaningful for design package). */
202
354
  tailwind: TailwindVersionSchema.optional(),
203
355
  /** IDEs this package was installed for (only meaningful for skills package). */
204
- ides: z2.array(SkillIdeSchema).optional(),
356
+ ides: z4.array(SkillIdeSchema).optional(),
205
357
  /** Install scope (only meaningful for skills package). */
206
358
  scope: SkillScopeSchema.optional(),
207
359
  /** Path aliases for ui entry installation (only meaningful for ui package). */
@@ -210,53 +362,79 @@ var PackageEntrySchema = z2.object({
210
362
  * Default icon library declared by the project (only meaningful for ui).
211
363
  * Declarative only — does NOT trigger code rewrites; ui entries hardcode imports.
212
364
  */
213
- iconLibrary: z2.string().min(1).optional(),
365
+ iconLibrary: z4.string().min(1).optional(),
214
366
  /** Whether the project uses TSX (true) or JSX (false). ui-specific. */
215
- tsx: z2.boolean().optional(),
367
+ tsx: z4.boolean().optional(),
216
368
  /** Whether to emit React Server Components markers (`"use client"`). ui-specific. */
217
- rsc: z2.boolean().optional()
369
+ rsc: z4.boolean().optional()
218
370
  });
219
- var ProjectConfigSchema = z2.object({
220
- $schema: z2.string().optional(),
221
- schemaVersion: z2.literal(1),
371
+ var ProjectConfigSchema = z4.object({
372
+ $schema: z4.string().optional(),
373
+ schemaVersion: z4.literal(1),
222
374
  /** IDE identifier */
223
- ide: z2.string().min(1),
375
+ ide: z4.string().min(1),
224
376
  /** Installed packages keyed by package name */
225
- packages: z2.record(z2.string(), PackageEntrySchema)
377
+ packages: z4.record(z4.string(), PackageEntrySchema)
226
378
  });
227
379
 
228
380
  // src/schema/installed.ts
229
- import { z as z3 } from "zod";
230
- var InstalledResourceSchema = z3.object({
381
+ import { z as z5 } from "zod";
382
+ var InstalledResourceSchema = z5.object({
231
383
  /** Resource identifier matching the variant manifest */
232
- id: z3.string().min(1),
384
+ id: z5.string().min(1),
233
385
  /** Target path where the resource was installed (absolute or project-relative) */
234
- target: z3.string().min(1),
386
+ target: z5.string().min(1),
235
387
  /** Content hash for change detection (e.g. "sha256:...") */
236
- hash: z3.string().min(1),
388
+ hash: z5.string().min(1),
237
389
  /** Update strategy that was applied */
238
- strategy: z3.enum(["frozen", "regenerable", "managed"]),
390
+ strategy: z5.enum(["frozen", "regenerable", "managed"]),
239
391
  /** IDE this resource was installed for (skill resources only) */
240
392
  ide: SkillIdeSchema.optional(),
241
393
  /** Install scope (skill resources only) */
242
394
  scope: SkillScopeSchema.optional()
243
395
  });
244
- var InstalledPackageSchema = z3.object({
396
+ var InstalledPackageSchema = z5.object({
245
397
  /** Full package name (e.g. "@teamix-evo/design") */
246
- package: z3.string().min(1),
398
+ package: z5.string().min(1),
247
399
  /** Variant identifier (use "_flat" for non-variant packages such as skills) */
248
- variant: z3.string().min(1),
400
+ variant: z5.string().min(1),
249
401
  /** Installed version */
250
- version: z3.string().min(1),
402
+ version: z5.string().min(1),
251
403
  /** ISO 8601 timestamp of installation */
252
- installedAt: z3.string().min(1),
404
+ installedAt: z5.string().min(1),
253
405
  /** List of installed resources */
254
- resources: z3.array(InstalledResourceSchema)
406
+ resources: z5.array(InstalledResourceSchema)
255
407
  });
256
- var InstalledManifestSchema = z3.object({
257
- schemaVersion: z3.literal(1),
408
+ var InstalledManifestSchema = z5.object({
409
+ schemaVersion: z5.literal(1),
258
410
  /** List of installed packages */
259
- installed: z3.array(InstalledPackageSchema)
411
+ installed: z5.array(InstalledPackageSchema)
412
+ });
413
+
414
+ // src/schema/skills-lock.ts
415
+ import { z as z6 } from "zod";
416
+ var SkillsLockEntrySchema = z6.object({
417
+ /** Semver version installed from upstream */
418
+ version: z6.string().min(1),
419
+ /** Upstream package name (typically `@teamix-evo/skills`) */
420
+ from: z6.string().min(1),
421
+ /** ISO 8601 install / last-sync timestamp */
422
+ installedAt: z6.string().min(1),
423
+ /** Install scope at time of mirror */
424
+ scope: SkillScopeSchema,
425
+ /**
426
+ * IDEs this skill was mirrored to. Each ide ↔ a mirror path under
427
+ * `<projectRoot>/.<ide>/skills/<id>/` (project) or `~/.<ide>/skills/<id>/`
428
+ * (global). The path itself is reconstructed from `scope` + adapter; we
429
+ * record the ide identifier rather than the full path to keep the lock
430
+ * portable across machines.
431
+ */
432
+ mirroredTo: z6.array(SkillIdeSchema)
433
+ });
434
+ var SkillsLockSchema = z6.object({
435
+ schemaVersion: z6.literal(1),
436
+ /** Map of skill id → lock entry */
437
+ skills: z6.record(z6.string().min(1), SkillsLockEntrySchema)
260
438
  });
261
439
 
262
440
  // src/loader.ts
@@ -266,8 +444,8 @@ import * as path from "path";
266
444
  // src/validator.ts
267
445
  function formatZodError(error) {
268
446
  return error.issues.map((issue) => {
269
- const path2 = issue.path.length > 0 ? issue.path.join(".") : "(root)";
270
- return ` - ${path2}: ${issue.message}`;
447
+ const path4 = issue.path.length > 0 ? issue.path.join(".") : "(root)";
448
+ return ` - ${path4}: ${issue.message}`;
271
449
  }).join("\n");
272
450
  }
273
451
  function validateManifest(data) {
@@ -303,6 +481,17 @@ function validateInstalled(data) {
303
481
  ${formatZodError(result.error)}`
304
482
  };
305
483
  }
484
+ function validateSkillsLock(data) {
485
+ const result = SkillsLockSchema.safeParse(data);
486
+ if (result.success) {
487
+ return { success: true, data: result.data };
488
+ }
489
+ return {
490
+ success: false,
491
+ error: `Invalid skills lock:
492
+ ${formatZodError(result.error)}`
493
+ };
494
+ }
306
495
  function validateSkillsPackage(data) {
307
496
  const result = SkillsPackageManifestSchema.safeParse(data);
308
497
  if (result.success) {
@@ -359,22 +548,22 @@ function validateUiDependencyGraph(entries) {
359
548
  const color = /* @__PURE__ */ new Map();
360
549
  for (const id of idToEntry.keys()) color.set(id, WHITE);
361
550
  const cycles = [];
362
- function dfs(id, path2) {
551
+ function dfs(id, path4) {
363
552
  color.set(id, GRAY);
364
- path2.push(id);
553
+ path4.push(id);
365
554
  const entry = idToEntry.get(id);
366
555
  const deps = entry?.registryDependencies ?? [];
367
556
  for (const dep of deps) {
368
557
  if (!idToEntry.has(dep)) continue;
369
558
  const c = color.get(dep);
370
559
  if (c === GRAY) {
371
- const startIdx = path2.indexOf(dep);
372
- cycles.push([...path2.slice(startIdx), dep]);
560
+ const startIdx = path4.indexOf(dep);
561
+ cycles.push([...path4.slice(startIdx), dep]);
373
562
  } else if (c === WHITE) {
374
- dfs(dep, path2);
563
+ dfs(dep, path4);
375
564
  }
376
565
  }
377
- path2.pop();
566
+ path4.pop();
378
567
  color.set(id, BLACK);
379
568
  }
380
569
  for (const id of idToEntry.keys()) {
@@ -496,6 +685,200 @@ async function loadUiPackageManifest(packageDir) {
496
685
  return result.data;
497
686
  }
498
687
 
688
+ // src/design-pack-loader.ts
689
+ import * as fs2 from "fs/promises";
690
+ import * as path2 from "path";
691
+ var PACK_METADATA_FILES = /* @__PURE__ */ new Set(["pack.json"]);
692
+ async function loadDesignPack(packDir) {
693
+ const manifestPath = path2.join(packDir, "pack.json");
694
+ let raw;
695
+ try {
696
+ raw = await fs2.readFile(manifestPath, "utf-8");
697
+ } catch (err) {
698
+ const code = err.code;
699
+ if (code === "ENOENT") {
700
+ throw new Error(`Design pack manifest not found: ${manifestPath}`);
701
+ }
702
+ throw new Error(
703
+ `Failed to read design pack manifest at ${manifestPath}: ${err.message}`
704
+ );
705
+ }
706
+ let parsed;
707
+ try {
708
+ parsed = JSON.parse(raw);
709
+ } catch {
710
+ throw new Error(`Invalid JSON in design pack manifest at ${manifestPath}`);
711
+ }
712
+ const result = DesignPackManifestSchema.safeParse(parsed);
713
+ if (!result.success) {
714
+ throw new Error(
715
+ `Invalid design pack manifest:
716
+ ${result.error.message}
717
+ File: ${manifestPath}`
718
+ );
719
+ }
720
+ if (result.data.name === "default" && result.data.extends !== void 0) {
721
+ throw new Error(
722
+ `Pack "default" must not have "extends" field: ${manifestPath}`
723
+ );
724
+ }
725
+ if (result.data.name !== "default" && result.data.extends !== "default") {
726
+ throw new Error(
727
+ `Variant pack "${result.data.name}" must declare extends: "default" (got ${JSON.stringify(
728
+ result.data.extends
729
+ )}): ${manifestPath}`
730
+ );
731
+ }
732
+ return result.data;
733
+ }
734
+ async function loadDesignPackageManifest(packageDir) {
735
+ const manifestPath = path2.join(packageDir, "manifest.json");
736
+ let raw;
737
+ try {
738
+ raw = await fs2.readFile(manifestPath, "utf-8");
739
+ } catch (err) {
740
+ const code = err.code;
741
+ if (code === "ENOENT") {
742
+ throw new Error(`Design package manifest not found: ${manifestPath}`);
743
+ }
744
+ throw new Error(
745
+ `Failed to read design package manifest at ${manifestPath}: ${err.message}`
746
+ );
747
+ }
748
+ let parsed;
749
+ try {
750
+ parsed = JSON.parse(raw);
751
+ } catch {
752
+ throw new Error(`Invalid JSON in design package manifest at ${manifestPath}`);
753
+ }
754
+ const result = DesignPackageManifestSchema.safeParse(parsed);
755
+ if (!result.success) {
756
+ throw new Error(
757
+ `Invalid design package manifest:
758
+ ${result.error.message}
759
+ File: ${manifestPath}`
760
+ );
761
+ }
762
+ return result.data;
763
+ }
764
+ async function walkPackTree(packDir) {
765
+ const out = [];
766
+ async function recurse(absDir, relDir) {
767
+ const entries = await fs2.readdir(absDir, { withFileTypes: true });
768
+ for (const entry of entries) {
769
+ const abs = path2.join(absDir, entry.name);
770
+ const rel = relDir ? path2.posix.join(relDir, entry.name) : entry.name;
771
+ if (entry.isDirectory()) {
772
+ await recurse(abs, rel);
773
+ } else if (entry.isFile()) {
774
+ if (relDir === "" && PACK_METADATA_FILES.has(entry.name)) continue;
775
+ out.push(rel);
776
+ }
777
+ }
778
+ }
779
+ try {
780
+ await recurse(packDir, "");
781
+ } catch (err) {
782
+ const code = err.code;
783
+ if (code === "ENOENT") {
784
+ throw new Error(`Pack directory not found: ${packDir}`);
785
+ }
786
+ throw err;
787
+ }
788
+ return out.sort();
789
+ }
790
+ async function mergeDefaultAndVariant(defaultDir, variantDir) {
791
+ const defaultFiles = new Set(await walkPackTree(defaultDir));
792
+ const variantFiles = new Set(await walkPackTree(variantDir));
793
+ const overrides = [];
794
+ const variantAdds = [];
795
+ const defaultPassThrough = [];
796
+ const files = [];
797
+ const allPaths = Array.from(/* @__PURE__ */ new Set([...defaultFiles, ...variantFiles])).sort();
798
+ for (const rel of allPaths) {
799
+ const inDefault = defaultFiles.has(rel);
800
+ const inVariant = variantFiles.has(rel);
801
+ if (inVariant && inDefault) {
802
+ overrides.push(rel);
803
+ files.push({
804
+ relPath: rel,
805
+ sourcePath: path2.join(variantDir, rel),
806
+ origin: "variant"
807
+ });
808
+ } else if (inVariant) {
809
+ variantAdds.push(rel);
810
+ files.push({
811
+ relPath: rel,
812
+ sourcePath: path2.join(variantDir, rel),
813
+ origin: "variant"
814
+ });
815
+ } else {
816
+ defaultPassThrough.push(rel);
817
+ files.push({
818
+ relPath: rel,
819
+ sourcePath: path2.join(defaultDir, rel),
820
+ origin: "default"
821
+ });
822
+ }
823
+ }
824
+ return { files, overrides, variantAdds, defaultPassThrough };
825
+ }
826
+
827
+ // src/variant-ui-pack-loader.ts
828
+ import * as fs3 from "fs/promises";
829
+ import * as path3 from "path";
830
+ async function readJson(filePath, kind) {
831
+ let raw;
832
+ try {
833
+ raw = await fs3.readFile(filePath, "utf-8");
834
+ } catch (err) {
835
+ const code = err.code;
836
+ if (code === "ENOENT") {
837
+ throw new Error(`${kind} not found: ${filePath}`);
838
+ }
839
+ throw new Error(
840
+ `Failed to read ${kind} at ${filePath}: ${err.message}`
841
+ );
842
+ }
843
+ try {
844
+ return JSON.parse(raw);
845
+ } catch {
846
+ throw new Error(`Invalid JSON in ${kind} at ${filePath}`);
847
+ }
848
+ }
849
+ async function loadVariantUiPackageCatalog(packageDir) {
850
+ const manifestPath = path3.join(packageDir, "manifest.json");
851
+ const data = await readJson(manifestPath, "variant-ui catalog");
852
+ const result = VariantUiPackageCatalogSchema.safeParse(data);
853
+ if (!result.success) {
854
+ throw new Error(
855
+ `Invalid catalog:
856
+ ${result.error.message}
857
+ File: ${manifestPath}`
858
+ );
859
+ }
860
+ return result.data;
861
+ }
862
+ async function loadVariantUiPackageManifest(variantDir) {
863
+ const manifestPath = path3.join(variantDir, "manifest.json");
864
+ const data = await readJson(manifestPath, "variant-ui manifest");
865
+ const result = VariantUiPackageManifestSchema.safeParse(data);
866
+ if (!result.success) {
867
+ throw new Error(
868
+ `Invalid variant manifest:
869
+ ${result.error.message}
870
+ File: ${manifestPath}`
871
+ );
872
+ }
873
+ const dirName = path3.basename(variantDir);
874
+ if (result.data.variant !== dirName) {
875
+ throw new Error(
876
+ `Variant manifest mismatch: variants/${dirName}/manifest.json declares variant="${result.data.variant}". Names must match.`
877
+ );
878
+ }
879
+ return result.data;
880
+ }
881
+
499
882
  // src/managed-regions.ts
500
883
  var REGION_PATTERN = /<!-- teamix-evo:managed:start id="([^"]+)" -->([\s\S]*?)<!-- teamix-evo:managed:end id="\1" -->/g;
501
884
  var START_MARKER_PATTERN = /<!-- teamix-evo:managed:start id="([^"]+)" -->/g;
@@ -617,6 +1000,10 @@ function getUpdateAction(strategy, options) {
617
1000
  }
618
1001
  }
619
1002
  export {
1003
+ DesignPackLinkedSchema,
1004
+ DesignPackLockSchema,
1005
+ DesignPackManifestSchema,
1006
+ DesignPackageManifestSchema,
620
1007
  InstalledManifestSchema,
621
1008
  InstalledPackageSchema,
622
1009
  InstalledResourceSchema,
@@ -627,6 +1014,8 @@ export {
627
1014
  SkillEntrySchema,
628
1015
  SkillIdeSchema,
629
1016
  SkillScopeSchema,
1017
+ SkillsLockEntrySchema,
1018
+ SkillsLockSchema,
630
1019
  SkillsPackageManifestSchema,
631
1020
  TailwindVersionSchema,
632
1021
  UiAliasSchema,
@@ -637,11 +1026,19 @@ export {
637
1026
  UiPackageManifestSchema,
638
1027
  UpdateStrategySchema,
639
1028
  VariantManifestSchema,
1029
+ VariantUiPackageCatalogSchema,
1030
+ VariantUiPackageManifestSchema,
1031
+ VariantUiPackageNameSchema,
640
1032
  getUpdateAction,
641
1033
  hasManagedRegion,
1034
+ loadDesignPack,
1035
+ loadDesignPackageManifest,
642
1036
  loadSkillsPackageManifest,
643
1037
  loadUiPackageManifest,
644
1038
  loadVariantManifest,
1039
+ loadVariantUiPackageCatalog,
1040
+ loadVariantUiPackageManifest,
1041
+ mergeDefaultAndVariant,
645
1042
  parseManagedRegions,
646
1043
  replaceManagedRegion,
647
1044
  resolveUiEntryOrder,
@@ -649,8 +1046,10 @@ export {
649
1046
  validateConfig,
650
1047
  validateInstalled,
651
1048
  validateManifest,
1049
+ validateSkillsLock,
652
1050
  validateSkillsPackage,
653
1051
  validateUiDependencyGraph,
654
- validateUiPackage
1052
+ validateUiPackage,
1053
+ walkPackTree
655
1054
  };
656
1055
  //# sourceMappingURL=index.js.map