@teamix-evo/registry 0.1.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.cjs CHANGED
@@ -30,6 +30,10 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
30
30
  // src/index.ts
31
31
  var index_exports = {};
32
32
  __export(index_exports, {
33
+ DesignPackLinkedSchema: () => DesignPackLinkedSchema,
34
+ DesignPackLockSchema: () => DesignPackLockSchema,
35
+ DesignPackManifestSchema: () => DesignPackManifestSchema,
36
+ DesignPackageManifestSchema: () => DesignPackageManifestSchema,
33
37
  InstalledManifestSchema: () => InstalledManifestSchema,
34
38
  InstalledPackageSchema: () => InstalledPackageSchema,
35
39
  InstalledResourceSchema: () => InstalledResourceSchema,
@@ -37,17 +41,46 @@ __export(index_exports, {
37
41
  ProjectConfigSchema: () => ProjectConfigSchema,
38
42
  ResourceSchema: () => ResourceSchema,
39
43
  ResourceTypeSchema: () => ResourceTypeSchema,
44
+ SkillEntrySchema: () => SkillEntrySchema,
45
+ SkillIdeSchema: () => SkillIdeSchema,
46
+ SkillScopeSchema: () => SkillScopeSchema,
47
+ SkillsLockEntrySchema: () => SkillsLockEntrySchema,
48
+ SkillsLockSchema: () => SkillsLockSchema,
49
+ SkillsPackageManifestSchema: () => SkillsPackageManifestSchema,
50
+ TailwindVersionSchema: () => TailwindVersionSchema,
51
+ UiAliasSchema: () => UiAliasSchema,
52
+ UiAliasesSchema: () => UiAliasesSchema,
53
+ UiEntryFileSchema: () => UiEntryFileSchema,
54
+ UiEntrySchema: () => UiEntrySchema,
55
+ UiEntryTypeSchema: () => UiEntryTypeSchema,
56
+ UiPackageManifestSchema: () => UiPackageManifestSchema,
40
57
  UpdateStrategySchema: () => UpdateStrategySchema,
41
58
  VariantManifestSchema: () => VariantManifestSchema,
59
+ VariantUiPackageCatalogSchema: () => VariantUiPackageCatalogSchema,
60
+ VariantUiPackageManifestSchema: () => VariantUiPackageManifestSchema,
61
+ VariantUiPackageNameSchema: () => VariantUiPackageNameSchema,
42
62
  getUpdateAction: () => getUpdateAction,
43
63
  hasManagedRegion: () => hasManagedRegion,
64
+ loadDesignPack: () => loadDesignPack,
65
+ loadDesignPackageManifest: () => loadDesignPackageManifest,
66
+ loadSkillsPackageManifest: () => loadSkillsPackageManifest,
67
+ loadUiPackageManifest: () => loadUiPackageManifest,
44
68
  loadVariantManifest: () => loadVariantManifest,
69
+ loadVariantUiPackageCatalog: () => loadVariantUiPackageCatalog,
70
+ loadVariantUiPackageManifest: () => loadVariantUiPackageManifest,
71
+ mergeDefaultAndVariant: () => mergeDefaultAndVariant,
45
72
  parseManagedRegions: () => parseManagedRegions,
46
73
  replaceManagedRegion: () => replaceManagedRegion,
74
+ resolveUiEntryOrder: () => resolveUiEntryOrder,
47
75
  shouldUpdate: () => shouldUpdate,
48
76
  validateConfig: () => validateConfig,
49
77
  validateInstalled: () => validateInstalled,
50
- validateManifest: () => validateManifest
78
+ validateManifest: () => validateManifest,
79
+ validateSkillsLock: () => validateSkillsLock,
80
+ validateSkillsPackage: () => validateSkillsPackage,
81
+ validateUiDependencyGraph: () => validateUiDependencyGraph,
82
+ validateUiPackage: () => validateUiPackage,
83
+ walkPackTree: () => walkPackTree
51
84
  });
52
85
  module.exports = __toCommonJS(index_exports);
53
86
 
@@ -62,8 +95,11 @@ var ResourceTypeSchema = import_zod.z.enum([
62
95
  "doc",
63
96
  "tokens",
64
97
  "ai-rules",
65
- "config"
98
+ "config",
99
+ "skill"
66
100
  ]);
101
+ var SkillIdeSchema = import_zod.z.enum(["qoder", "claude"]);
102
+ var SkillScopeSchema = import_zod.z.enum(["project", "global"]);
67
103
  var ResourceSchema = import_zod.z.object({
68
104
  /** Unique identifier for the resource within the manifest */
69
105
  id: import_zod.z.string().min(1),
@@ -71,7 +107,10 @@ var ResourceSchema = import_zod.z.object({
71
107
  type: ResourceTypeSchema,
72
108
  /** Source path (relative to variant root), typically a template */
73
109
  source: import_zod.z.string().min(1),
74
- /** Target path (relative to project root) where the resource is installed */
110
+ /**
111
+ * Target path (relative to project root) where the resource is installed.
112
+ * For type="skill" this is ignored: the path is computed from skill name + ide + scope.
113
+ */
75
114
  target: import_zod.z.string().min(1),
76
115
  /** How the resource is updated */
77
116
  updateStrategy: UpdateStrategySchema,
@@ -80,7 +119,11 @@ var ResourceSchema = import_zod.z.object({
80
119
  /** IDs of managed regions (only relevant when updateStrategy is "managed") */
81
120
  managedRegions: import_zod.z.array(import_zod.z.string()).optional(),
82
121
  /** Whether to recursively process directory contents */
83
- recursive: import_zod.z.boolean().optional()
122
+ recursive: import_zod.z.boolean().optional(),
123
+ /** Supported IDEs (only meaningful when type="skill"; defaults to all when omitted) */
124
+ ides: import_zod.z.array(SkillIdeSchema).optional(),
125
+ /** Default install scope (only meaningful when type="skill"; user can override at install time) */
126
+ scope: SkillScopeSchema.optional()
84
127
  });
85
128
  var VariantManifestSchema = import_zod.z.object({
86
129
  $schema: import_zod.z.string().optional(),
@@ -104,52 +147,380 @@ var VariantManifestSchema = import_zod.z.object({
104
147
  /** List of resources provided by this variant */
105
148
  resources: import_zod.z.array(ResourceSchema)
106
149
  });
150
+ var SkillEntrySchema = import_zod.z.object({
151
+ /** Skill identifier (matches name/folder) */
152
+ id: import_zod.z.string().min(1),
153
+ /** Skill name — must match the directory name and frontmatter `name` */
154
+ name: import_zod.z.string().min(1).regex(
155
+ /^[a-z0-9][a-z0-9-]*$/,
156
+ "Skill name must be lowercase letters, digits, hyphens (no leading hyphen)"
157
+ ),
158
+ /** One-line description for skill discovery */
159
+ description: import_zod.z.string().min(1),
160
+ /** Semver version */
161
+ version: import_zod.z.string().regex(/^\d+\.\d+\.\d+/, "Invalid semver version"),
162
+ /** Source path relative to package root — file or directory */
163
+ source: import_zod.z.string().min(1),
164
+ /** Supported IDEs (defaults to both when omitted) */
165
+ ides: import_zod.z.array(SkillIdeSchema).default(["qoder", "claude"]),
166
+ /** Update strategy (defaults to managed) */
167
+ updateStrategy: UpdateStrategySchema.default("managed"),
168
+ /** Managed region IDs to maintain on update */
169
+ managedRegions: import_zod.z.array(import_zod.z.string()).optional(),
170
+ /** Whether the source is a Handlebars template */
171
+ template: import_zod.z.boolean().optional(),
172
+ /**
173
+ * Variant identifier when this skill is bound to a specific design variant
174
+ * (e.g. `"opentrek"`, `"uni-manager"`). Optional — neutral skills (manage,
175
+ * coding-conventions, baseline design-rules) leave it unset.
176
+ *
177
+ * When present, the CLI installs this skill ONLY if the consumer's
178
+ * `.teamix-evo/design/pack.lock.json` records the same variant. MUST equal
179
+ * the variant directory name in `@teamix-evo/design/variants/<name>/`.
180
+ *
181
+ * Mirrors `UiEntrySchema.variant` semantics in @teamix-evo/biz-ui &
182
+ * @teamix-evo/templates per ADR 0014.
183
+ */
184
+ variant: import_zod.z.string().optional()
185
+ });
186
+ var SkillsPackageManifestSchema = import_zod.z.object({
187
+ $schema: import_zod.z.string().optional(),
188
+ schemaVersion: import_zod.z.literal(1),
189
+ /** Always "skills" for this package */
190
+ package: import_zod.z.literal("skills"),
191
+ /** Semver version of the skills package */
192
+ version: import_zod.z.string().regex(/^\d+\.\d+\.\d+/, "Invalid semver version"),
193
+ /** Engine compatibility */
194
+ engines: import_zod.z.object({
195
+ "teamix-evo": import_zod.z.string().min(1)
196
+ }),
197
+ /** Flat list of skills shipped by this package */
198
+ skills: import_zod.z.array(SkillEntrySchema)
199
+ });
200
+ var UiEntryTypeSchema = import_zod.z.enum([
201
+ "component",
202
+ "hook",
203
+ "util",
204
+ "block",
205
+ "template"
206
+ ]);
207
+ var UiAliasSchema = import_zod.z.enum([
208
+ "components",
209
+ "hooks",
210
+ "utils",
211
+ "lib",
212
+ "business",
213
+ "templates"
214
+ ]);
215
+ var UiEntryStatusSchema = import_zod.z.enum([
216
+ "stable",
217
+ "experimental",
218
+ "deprecated"
219
+ ]);
220
+ var UiEntryFileSchema = import_zod.z.object({
221
+ /** Source path relative to the ui package root (e.g. "src/components/button/button.tsx") */
222
+ source: import_zod.z.string().min(1),
223
+ /** Which alias this file resolves under in the consumer project */
224
+ targetAlias: UiAliasSchema,
225
+ /** Filename written under the alias directory (e.g. "button.tsx") */
226
+ targetName: import_zod.z.string().min(1)
227
+ });
228
+ var UiEntrySchema = import_zod.z.object({
229
+ /** Unique entry identifier within the ui package (e.g. "button") */
230
+ id: import_zod.z.string().min(1).regex(
231
+ /^[a-z0-9][a-z0-9-]*$/,
232
+ "UI entry id must be lowercase letters, digits, hyphens (no leading hyphen)"
233
+ ),
234
+ /** Display name (e.g. "Button") */
235
+ name: import_zod.z.string().min(1),
236
+ /** Entry type */
237
+ type: UiEntryTypeSchema,
238
+ /** One-line description for entry discovery and AI guidance */
239
+ description: import_zod.z.string().min(1),
240
+ /** Files this entry ships (typically 1) */
241
+ files: import_zod.z.array(UiEntryFileSchema).min(1),
242
+ /**
243
+ * Optional path to an AI-readable meta document (frontmatter + Markdown).
244
+ * When set, CLI install drops it at `.teamix-evo/design/components/<id>.meta.md`
245
+ * for design's ai-rules to consume.
246
+ */
247
+ meta: import_zod.z.string().optional(),
248
+ /** Other UI entries this one depends on (e.g. "button" depends on "cn") */
249
+ registryDependencies: import_zod.z.array(import_zod.z.string()).optional(),
250
+ /** npm dependencies required by this entry (name → semver range) */
251
+ dependencies: import_zod.z.record(import_zod.z.string(), import_zod.z.string()).optional(),
252
+ /**
253
+ * How CLI handles this entry on `ui upgrade`.
254
+ * Defaults to `frozen` — user-owned source code, untouched after first install.
255
+ * Upgrade is handled by AI + skill flow (no CLI rewrite). See PLAN §10.9.
256
+ */
257
+ updateStrategy: UpdateStrategySchema.default("frozen"),
258
+ /**
259
+ * Whether the source file should be passed through Handlebars before write.
260
+ * Most entries don't need templating (use import-rewrite transformer instead).
261
+ */
262
+ template: import_zod.z.boolean().optional(),
263
+ /**
264
+ * Maturity / lifecycle status of this entry. Defaults to `stable`.
265
+ * See {@link UiEntryStatusSchema} for semantics.
266
+ */
267
+ status: UiEntryStatusSchema.default("stable"),
268
+ /**
269
+ * Free-text rationale shown to consumers when `status` is `deprecated`.
270
+ * Should explain why the entry is going away and what replaces it.
271
+ */
272
+ deprecatedReason: import_zod.z.string().optional(),
273
+ /**
274
+ * If this entry is `deprecated`, the id of the entry that supersedes it.
275
+ * Consumers (and AI) should migrate to `replacedBy` rather than this entry.
276
+ */
277
+ replacedBy: import_zod.z.string().optional(),
278
+ /**
279
+ * Variant identifier when this entry is shipped from a variant-aware
280
+ * package (`@teamix-evo/biz-ui` or `@teamix-evo/templates` per ADR 0014).
281
+ * Optional — entries from `@teamix-evo/ui` (variant-agnostic) leave it unset.
282
+ * MUST equal the variant directory name when present.
283
+ */
284
+ variant: import_zod.z.string().optional()
285
+ });
286
+ var UiPackageManifestSchema = import_zod.z.object({
287
+ $schema: import_zod.z.string().optional(),
288
+ schemaVersion: import_zod.z.literal(1),
289
+ /** Always "ui" for this package */
290
+ package: import_zod.z.literal("ui"),
291
+ /** Semver version of the ui package */
292
+ version: import_zod.z.string().regex(/^\d+\.\d+\.\d+/, "Invalid semver version"),
293
+ /** Engine compatibility */
294
+ engines: import_zod.z.object({
295
+ "teamix-evo": import_zod.z.string().min(1)
296
+ }),
297
+ /** Flat list of entries shipped by this package */
298
+ entries: import_zod.z.array(UiEntrySchema)
299
+ });
107
300
 
108
- // src/schema/config.ts
301
+ // src/schema/design-pack.ts
109
302
  var import_zod2 = require("zod");
110
- var PackageEntrySchema = import_zod2.z.object({
111
- /** Variant identifier (e.g. "opentrek") */
112
- variant: import_zod2.z.string().min(1),
113
- /** Semver version string */
114
- version: import_zod2.z.string().min(1)
303
+ var VARIANT_NAME_RE = /^[a-z][a-z0-9-]*$/;
304
+ var SEMVER_RE = /^\d+\.\d+\.\d+/;
305
+ var DesignPackLinkedSchema = import_zod2.z.object({
306
+ "biz-ui": import_zod2.z.string().optional(),
307
+ templates: import_zod2.z.string().optional()
115
308
  });
116
- var ProjectConfigSchema = import_zod2.z.object({
309
+ var DesignPackManifestSchema = import_zod2.z.object({
117
310
  $schema: import_zod2.z.string().optional(),
118
311
  schemaVersion: import_zod2.z.literal(1),
312
+ /**
313
+ * Pack identifier.
314
+ * - `"default"` for the built-in baseline (only valid name when `extends` is absent)
315
+ * - lowercase kebab-case for variants (`opentrek`, `uni-manager`, `acme-erp`, `_template`)
316
+ */
317
+ name: import_zod2.z.string().min(1).regex(
318
+ VARIANT_NAME_RE,
319
+ 'Pack name must be lowercase letters/digits/hyphens (no leading hyphen). Special: "_template" allowed for the variant scaffold.'
320
+ ).or(import_zod2.z.literal("_template")).or(import_zod2.z.literal("default")),
321
+ /** Human-readable display name (e.g. "OpenTrek" for variant id "opentrek"). */
322
+ displayName: import_zod2.z.string().min(1),
323
+ /** Semver. */
324
+ version: import_zod2.z.string().regex(SEMVER_RE, "Invalid semver version"),
325
+ /**
326
+ * Parent pack name. Required for variants, must be omitted for `default`.
327
+ * Currently only `"default"` is a valid parent.
328
+ */
329
+ extends: import_zod2.z.string().optional(),
330
+ /** Optional one-liner; useful for `design list-variants` output. */
331
+ description: import_zod2.z.string().optional(),
332
+ /** Soft cross-package links (biz-ui / templates with same variant name). */
333
+ linked: DesignPackLinkedSchema.optional()
334
+ });
335
+ var DesignPackageManifestSchema = import_zod2.z.object({
336
+ $schema: import_zod2.z.string().optional(),
337
+ schemaVersion: import_zod2.z.literal(1),
338
+ /** Always `"design"` for this package. */
339
+ package: import_zod2.z.literal("design"),
340
+ /** Semver of the entire design package. */
341
+ version: import_zod2.z.string().regex(SEMVER_RE, "Invalid semver version"),
342
+ /** Engine compatibility. */
343
+ engines: import_zod2.z.object({ "teamix-evo": import_zod2.z.string().min(1) }),
344
+ /** The default baseline pack — always present. */
345
+ default: DesignPackManifestSchema,
346
+ /** All shipped variants (excluding `_template/`). */
347
+ variants: import_zod2.z.array(DesignPackManifestSchema)
348
+ });
349
+ var DesignPackLockSchema = import_zod2.z.object({
350
+ $schema: import_zod2.z.string().optional(),
351
+ schemaVersion: import_zod2.z.literal(1),
352
+ default: import_zod2.z.object({
353
+ version: import_zod2.z.string().regex(SEMVER_RE),
354
+ from: import_zod2.z.string().min(1)
355
+ // e.g. "@teamix-evo/design"
356
+ }),
357
+ variant: import_zod2.z.object({
358
+ name: import_zod2.z.string().min(1),
359
+ displayName: import_zod2.z.string().min(1),
360
+ version: import_zod2.z.string().regex(SEMVER_RE),
361
+ from: import_zod2.z.string().min(1)
362
+ }),
363
+ linked: DesignPackLinkedSchema.optional(),
364
+ installedAt: import_zod2.z.string().datetime()
365
+ });
366
+
367
+ // src/schema/variant-ui-pack.ts
368
+ var import_zod3 = require("zod");
369
+ var SEMVER_RE2 = /^\d+\.\d+\.\d+/;
370
+ var VARIANT_NAME_RE2 = /^[a-z][a-z0-9-]*$/;
371
+ var VariantUiPackageNameSchema = import_zod3.z.enum(["biz-ui", "templates"]);
372
+ var VariantUiPackageManifestSchema = import_zod3.z.object({
373
+ $schema: import_zod3.z.string().optional(),
374
+ schemaVersion: import_zod3.z.literal(1),
375
+ /** Discriminator. */
376
+ package: VariantUiPackageNameSchema,
377
+ /**
378
+ * Variant identifier — lowercase kebab-case, MUST match the parent
379
+ * directory name (e.g. `opentrek` for `variants/opentrek/manifest.json`).
380
+ * `_template` is also accepted for the variant scaffold.
381
+ */
382
+ variant: import_zod3.z.string().min(1).regex(
383
+ VARIANT_NAME_RE2,
384
+ 'Variant id must be lowercase letters/digits/hyphens (no leading hyphen). Special: "_template" allowed.'
385
+ ).or(import_zod3.z.literal("_template")),
386
+ /** Semver of this variant. */
387
+ version: import_zod3.z.string().regex(SEMVER_RE2, "Invalid semver version"),
388
+ /** Engine compatibility. */
389
+ engines: import_zod3.z.object({ "teamix-evo": import_zod3.z.string().min(1) }),
390
+ /** Flat list of entries shipped by this variant. */
391
+ entries: import_zod3.z.array(UiEntrySchema)
392
+ }).superRefine((data, ctx) => {
393
+ for (const [i, entry] of data.entries.entries()) {
394
+ if (entry.variant !== void 0 && entry.variant !== data.variant) {
395
+ ctx.addIssue({
396
+ code: import_zod3.z.ZodIssueCode.custom,
397
+ path: ["entries", i, "variant"],
398
+ message: `Entry "${entry.id}" declares variant "${entry.variant}" but lives in manifest of variant "${data.variant}".`
399
+ });
400
+ }
401
+ }
402
+ });
403
+ var VariantUiPackageCatalogSchema = import_zod3.z.object({
404
+ $schema: import_zod3.z.string().optional(),
405
+ schemaVersion: import_zod3.z.literal(1),
406
+ package: VariantUiPackageNameSchema,
407
+ /** Semver of the entire package. */
408
+ version: import_zod3.z.string().regex(SEMVER_RE2, "Invalid semver version"),
409
+ engines: import_zod3.z.object({ "teamix-evo": import_zod3.z.string().min(1) }),
410
+ /** Variants this package ships (excluding `_template`). */
411
+ variants: import_zod3.z.array(
412
+ import_zod3.z.object({
413
+ name: import_zod3.z.string().min(1).regex(VARIANT_NAME_RE2),
414
+ displayName: import_zod3.z.string().min(1),
415
+ version: import_zod3.z.string().regex(SEMVER_RE2),
416
+ description: import_zod3.z.string().optional()
417
+ })
418
+ )
419
+ });
420
+
421
+ // src/schema/config.ts
422
+ var import_zod4 = require("zod");
423
+ var TailwindVersionSchema = import_zod4.z.literal("v4");
424
+ var UiAliasesSchema = import_zod4.z.object({
425
+ components: import_zod4.z.string().min(1),
426
+ hooks: import_zod4.z.string().min(1),
427
+ utils: import_zod4.z.string().min(1),
428
+ lib: import_zod4.z.string().min(1),
429
+ /** Biz-ui components (variant-bound). Defaults to `src/components/business/`. */
430
+ business: import_zod4.z.string().min(1).default("src/components/business"),
431
+ /** Page templates (variant-bound). Defaults to `src/templates/`. */
432
+ templates: import_zod4.z.string().min(1).default("src/templates")
433
+ });
434
+ var PackageEntrySchema = import_zod4.z.object({
435
+ /** Variant identifier (e.g. "opentrek"; use "_flat" for skills/ui) */
436
+ variant: import_zod4.z.string().min(1),
437
+ /** Semver version string */
438
+ version: import_zod4.z.string().min(1),
439
+ /** Tailwind CSS version this project uses (only meaningful for design package). */
440
+ tailwind: TailwindVersionSchema.optional(),
441
+ /** IDEs this package was installed for (only meaningful for skills package). */
442
+ ides: import_zod4.z.array(SkillIdeSchema).optional(),
443
+ /** Install scope (only meaningful for skills package). */
444
+ scope: SkillScopeSchema.optional(),
445
+ /** Path aliases for ui entry installation (only meaningful for ui package). */
446
+ aliases: UiAliasesSchema.optional(),
447
+ /**
448
+ * Default icon library declared by the project (only meaningful for ui).
449
+ * Declarative only — does NOT trigger code rewrites; ui entries hardcode imports.
450
+ */
451
+ iconLibrary: import_zod4.z.string().min(1).optional(),
452
+ /** Whether the project uses TSX (true) or JSX (false). ui-specific. */
453
+ tsx: import_zod4.z.boolean().optional(),
454
+ /** Whether to emit React Server Components markers (`"use client"`). ui-specific. */
455
+ rsc: import_zod4.z.boolean().optional()
456
+ });
457
+ var ProjectConfigSchema = import_zod4.z.object({
458
+ $schema: import_zod4.z.string().optional(),
459
+ schemaVersion: import_zod4.z.literal(1),
119
460
  /** IDE identifier */
120
- ide: import_zod2.z.string().min(1),
461
+ ide: import_zod4.z.string().min(1),
121
462
  /** Installed packages keyed by package name */
122
- packages: import_zod2.z.record(import_zod2.z.string(), PackageEntrySchema)
463
+ packages: import_zod4.z.record(import_zod4.z.string(), PackageEntrySchema)
123
464
  });
124
465
 
125
466
  // src/schema/installed.ts
126
- var import_zod3 = require("zod");
127
- var InstalledResourceSchema = import_zod3.z.object({
467
+ var import_zod5 = require("zod");
468
+ var InstalledResourceSchema = import_zod5.z.object({
128
469
  /** Resource identifier matching the variant manifest */
129
- id: import_zod3.z.string().min(1),
130
- /** Target path where the resource was installed */
131
- target: import_zod3.z.string().min(1),
470
+ id: import_zod5.z.string().min(1),
471
+ /** Target path where the resource was installed (absolute or project-relative) */
472
+ target: import_zod5.z.string().min(1),
132
473
  /** Content hash for change detection (e.g. "sha256:...") */
133
- hash: import_zod3.z.string().min(1),
474
+ hash: import_zod5.z.string().min(1),
134
475
  /** Update strategy that was applied */
135
- strategy: import_zod3.z.enum(["frozen", "regenerable", "managed"])
476
+ strategy: import_zod5.z.enum(["frozen", "regenerable", "managed"]),
477
+ /** IDE this resource was installed for (skill resources only) */
478
+ ide: SkillIdeSchema.optional(),
479
+ /** Install scope (skill resources only) */
480
+ scope: SkillScopeSchema.optional()
136
481
  });
137
- var InstalledPackageSchema = import_zod3.z.object({
482
+ var InstalledPackageSchema = import_zod5.z.object({
138
483
  /** Full package name (e.g. "@teamix-evo/design") */
139
- package: import_zod3.z.string().min(1),
140
- /** Variant identifier */
141
- variant: import_zod3.z.string().min(1),
484
+ package: import_zod5.z.string().min(1),
485
+ /** Variant identifier (use "_flat" for non-variant packages such as skills) */
486
+ variant: import_zod5.z.string().min(1),
142
487
  /** Installed version */
143
- version: import_zod3.z.string().min(1),
488
+ version: import_zod5.z.string().min(1),
144
489
  /** ISO 8601 timestamp of installation */
145
- installedAt: import_zod3.z.string().min(1),
490
+ installedAt: import_zod5.z.string().min(1),
146
491
  /** List of installed resources */
147
- resources: import_zod3.z.array(InstalledResourceSchema)
492
+ resources: import_zod5.z.array(InstalledResourceSchema)
148
493
  });
149
- var InstalledManifestSchema = import_zod3.z.object({
150
- schemaVersion: import_zod3.z.literal(1),
494
+ var InstalledManifestSchema = import_zod5.z.object({
495
+ schemaVersion: import_zod5.z.literal(1),
151
496
  /** List of installed packages */
152
- installed: import_zod3.z.array(InstalledPackageSchema)
497
+ installed: import_zod5.z.array(InstalledPackageSchema)
498
+ });
499
+
500
+ // src/schema/skills-lock.ts
501
+ var import_zod6 = require("zod");
502
+ var SkillsLockEntrySchema = import_zod6.z.object({
503
+ /** Semver version installed from upstream */
504
+ version: import_zod6.z.string().min(1),
505
+ /** Upstream package name (typically `@teamix-evo/skills`) */
506
+ from: import_zod6.z.string().min(1),
507
+ /** ISO 8601 install / last-sync timestamp */
508
+ installedAt: import_zod6.z.string().min(1),
509
+ /** Install scope at time of mirror */
510
+ scope: SkillScopeSchema,
511
+ /**
512
+ * IDEs this skill was mirrored to. Each ide ↔ a mirror path under
513
+ * `<projectRoot>/.<ide>/skills/<id>/` (project) or `~/.<ide>/skills/<id>/`
514
+ * (global). The path itself is reconstructed from `scope` + adapter; we
515
+ * record the ide identifier rather than the full path to keep the lock
516
+ * portable across machines.
517
+ */
518
+ mirroredTo: import_zod6.z.array(SkillIdeSchema)
519
+ });
520
+ var SkillsLockSchema = import_zod6.z.object({
521
+ schemaVersion: import_zod6.z.literal(1),
522
+ /** Map of skill id → lock entry */
523
+ skills: import_zod6.z.record(import_zod6.z.string().min(1), SkillsLockEntrySchema)
153
524
  });
154
525
 
155
526
  // src/loader.ts
@@ -159,8 +530,8 @@ var path = __toESM(require("path"), 1);
159
530
  // src/validator.ts
160
531
  function formatZodError(error) {
161
532
  return error.issues.map((issue) => {
162
- const path2 = issue.path.length > 0 ? issue.path.join(".") : "(root)";
163
- return ` - ${path2}: ${issue.message}`;
533
+ const path4 = issue.path.length > 0 ? issue.path.join(".") : "(root)";
534
+ return ` - ${path4}: ${issue.message}`;
164
535
  }).join("\n");
165
536
  }
166
537
  function validateManifest(data) {
@@ -196,6 +567,126 @@ function validateInstalled(data) {
196
567
  ${formatZodError(result.error)}`
197
568
  };
198
569
  }
570
+ function validateSkillsLock(data) {
571
+ const result = SkillsLockSchema.safeParse(data);
572
+ if (result.success) {
573
+ return { success: true, data: result.data };
574
+ }
575
+ return {
576
+ success: false,
577
+ error: `Invalid skills lock:
578
+ ${formatZodError(result.error)}`
579
+ };
580
+ }
581
+ function validateSkillsPackage(data) {
582
+ const result = SkillsPackageManifestSchema.safeParse(data);
583
+ if (result.success) {
584
+ return { success: true, data: result.data };
585
+ }
586
+ return {
587
+ success: false,
588
+ error: `Invalid skills package manifest:
589
+ ${formatZodError(result.error)}`
590
+ };
591
+ }
592
+ function validateUiPackage(data) {
593
+ const parsed = UiPackageManifestSchema.safeParse(data);
594
+ if (!parsed.success) {
595
+ return {
596
+ success: false,
597
+ error: `Invalid ui package manifest:
598
+ ${formatZodError(parsed.error)}`
599
+ };
600
+ }
601
+ const graphIssues = validateUiDependencyGraph(parsed.data.entries);
602
+ if (graphIssues.length > 0) {
603
+ return {
604
+ success: false,
605
+ error: `Invalid ui package manifest dependency graph:
606
+ ${graphIssues.map((i) => ` - ${i}`).join("\n")}`
607
+ };
608
+ }
609
+ return { success: true, data: parsed.data };
610
+ }
611
+ function validateUiDependencyGraph(entries) {
612
+ const issues = [];
613
+ const idToEntry = /* @__PURE__ */ new Map();
614
+ for (const entry of entries) {
615
+ if (idToEntry.has(entry.id)) {
616
+ issues.push(`duplicate entry id: "${entry.id}"`);
617
+ } else {
618
+ idToEntry.set(entry.id, entry);
619
+ }
620
+ }
621
+ for (const entry of entries) {
622
+ const deps = entry.registryDependencies ?? [];
623
+ for (const dep of deps) {
624
+ if (!idToEntry.has(dep)) {
625
+ issues.push(
626
+ `entry "${entry.id}" depends on unknown entry "${dep}"`
627
+ );
628
+ }
629
+ }
630
+ }
631
+ const WHITE = 0;
632
+ const GRAY = 1;
633
+ const BLACK = 2;
634
+ const color = /* @__PURE__ */ new Map();
635
+ for (const id of idToEntry.keys()) color.set(id, WHITE);
636
+ const cycles = [];
637
+ function dfs(id, path4) {
638
+ color.set(id, GRAY);
639
+ path4.push(id);
640
+ const entry = idToEntry.get(id);
641
+ const deps = entry?.registryDependencies ?? [];
642
+ for (const dep of deps) {
643
+ if (!idToEntry.has(dep)) continue;
644
+ const c = color.get(dep);
645
+ if (c === GRAY) {
646
+ const startIdx = path4.indexOf(dep);
647
+ cycles.push([...path4.slice(startIdx), dep]);
648
+ } else if (c === WHITE) {
649
+ dfs(dep, path4);
650
+ }
651
+ }
652
+ path4.pop();
653
+ color.set(id, BLACK);
654
+ }
655
+ for (const id of idToEntry.keys()) {
656
+ if (color.get(id) === WHITE) dfs(id, []);
657
+ }
658
+ for (const cycle of cycles) {
659
+ issues.push(`cyclic registryDependencies: ${cycle.join(" \u2192 ")}`);
660
+ }
661
+ return issues;
662
+ }
663
+ function resolveUiEntryOrder(entries, requested) {
664
+ const idToEntry = new Map(entries.map((e) => [e.id, e]));
665
+ for (const id of requested) {
666
+ if (!idToEntry.has(id)) {
667
+ throw new Error(`Unknown ui entry: "${id}"`);
668
+ }
669
+ }
670
+ const graphIssues = validateUiDependencyGraph(entries);
671
+ if (graphIssues.length > 0) {
672
+ throw new Error(
673
+ `UI dependency graph has issues:
674
+ ${graphIssues.map((i) => ` - ${i}`).join("\n")}`
675
+ );
676
+ }
677
+ const visited = /* @__PURE__ */ new Set();
678
+ const order = [];
679
+ function visit(id) {
680
+ if (visited.has(id)) return;
681
+ visited.add(id);
682
+ const entry = idToEntry.get(id);
683
+ const deps = entry?.registryDependencies ?? [];
684
+ for (const dep of deps) visit(dep);
685
+ order.push(id);
686
+ }
687
+ for (const id of requested) visit(id);
688
+ return order;
689
+ }
199
690
 
200
691
  // src/loader.ts
201
692
  async function loadVariantManifest(packageDir) {
@@ -225,6 +716,254 @@ async function loadVariantManifest(packageDir) {
225
716
  }
226
717
  return result.data;
227
718
  }
719
+ async function loadSkillsPackageManifest(packageDir) {
720
+ const manifestPath = path.join(packageDir, "manifest.json");
721
+ let raw;
722
+ try {
723
+ raw = await fs.readFile(manifestPath, "utf-8");
724
+ } catch (err) {
725
+ const code = err.code;
726
+ if (code === "ENOENT") {
727
+ throw new Error(`Skills manifest not found: ${manifestPath}`);
728
+ }
729
+ throw new Error(
730
+ `Failed to read skills manifest at ${manifestPath}: ${err.message}`
731
+ );
732
+ }
733
+ let data;
734
+ try {
735
+ data = JSON.parse(raw);
736
+ } catch {
737
+ throw new Error(`Invalid JSON in skills manifest at ${manifestPath}`);
738
+ }
739
+ const result = validateSkillsPackage(data);
740
+ if (!result.success) {
741
+ throw new Error(`${result.error}
742
+ File: ${manifestPath}`);
743
+ }
744
+ return result.data;
745
+ }
746
+ async function loadUiPackageManifest(packageDir) {
747
+ const manifestPath = path.join(packageDir, "manifest.json");
748
+ let raw;
749
+ try {
750
+ raw = await fs.readFile(manifestPath, "utf-8");
751
+ } catch (err) {
752
+ const code = err.code;
753
+ if (code === "ENOENT") {
754
+ throw new Error(`UI manifest not found: ${manifestPath}`);
755
+ }
756
+ throw new Error(
757
+ `Failed to read ui manifest at ${manifestPath}: ${err.message}`
758
+ );
759
+ }
760
+ let data;
761
+ try {
762
+ data = JSON.parse(raw);
763
+ } catch {
764
+ throw new Error(`Invalid JSON in ui manifest at ${manifestPath}`);
765
+ }
766
+ const result = validateUiPackage(data);
767
+ if (!result.success) {
768
+ throw new Error(`${result.error}
769
+ File: ${manifestPath}`);
770
+ }
771
+ return result.data;
772
+ }
773
+
774
+ // src/design-pack-loader.ts
775
+ var fs2 = __toESM(require("fs/promises"), 1);
776
+ var path2 = __toESM(require("path"), 1);
777
+ var PACK_METADATA_FILES = /* @__PURE__ */ new Set(["pack.json"]);
778
+ async function loadDesignPack(packDir) {
779
+ const manifestPath = path2.join(packDir, "pack.json");
780
+ let raw;
781
+ try {
782
+ raw = await fs2.readFile(manifestPath, "utf-8");
783
+ } catch (err) {
784
+ const code = err.code;
785
+ if (code === "ENOENT") {
786
+ throw new Error(`Design pack manifest not found: ${manifestPath}`);
787
+ }
788
+ throw new Error(
789
+ `Failed to read design pack manifest at ${manifestPath}: ${err.message}`
790
+ );
791
+ }
792
+ let parsed;
793
+ try {
794
+ parsed = JSON.parse(raw);
795
+ } catch {
796
+ throw new Error(`Invalid JSON in design pack manifest at ${manifestPath}`);
797
+ }
798
+ const result = DesignPackManifestSchema.safeParse(parsed);
799
+ if (!result.success) {
800
+ throw new Error(
801
+ `Invalid design pack manifest:
802
+ ${result.error.message}
803
+ File: ${manifestPath}`
804
+ );
805
+ }
806
+ if (result.data.name === "default" && result.data.extends !== void 0) {
807
+ throw new Error(
808
+ `Pack "default" must not have "extends" field: ${manifestPath}`
809
+ );
810
+ }
811
+ if (result.data.name !== "default" && result.data.extends !== "default") {
812
+ throw new Error(
813
+ `Variant pack "${result.data.name}" must declare extends: "default" (got ${JSON.stringify(
814
+ result.data.extends
815
+ )}): ${manifestPath}`
816
+ );
817
+ }
818
+ return result.data;
819
+ }
820
+ async function loadDesignPackageManifest(packageDir) {
821
+ const manifestPath = path2.join(packageDir, "manifest.json");
822
+ let raw;
823
+ try {
824
+ raw = await fs2.readFile(manifestPath, "utf-8");
825
+ } catch (err) {
826
+ const code = err.code;
827
+ if (code === "ENOENT") {
828
+ throw new Error(`Design package manifest not found: ${manifestPath}`);
829
+ }
830
+ throw new Error(
831
+ `Failed to read design package manifest at ${manifestPath}: ${err.message}`
832
+ );
833
+ }
834
+ let parsed;
835
+ try {
836
+ parsed = JSON.parse(raw);
837
+ } catch {
838
+ throw new Error(`Invalid JSON in design package manifest at ${manifestPath}`);
839
+ }
840
+ const result = DesignPackageManifestSchema.safeParse(parsed);
841
+ if (!result.success) {
842
+ throw new Error(
843
+ `Invalid design package manifest:
844
+ ${result.error.message}
845
+ File: ${manifestPath}`
846
+ );
847
+ }
848
+ return result.data;
849
+ }
850
+ async function walkPackTree(packDir) {
851
+ const out = [];
852
+ async function recurse(absDir, relDir) {
853
+ const entries = await fs2.readdir(absDir, { withFileTypes: true });
854
+ for (const entry of entries) {
855
+ const abs = path2.join(absDir, entry.name);
856
+ const rel = relDir ? path2.posix.join(relDir, entry.name) : entry.name;
857
+ if (entry.isDirectory()) {
858
+ await recurse(abs, rel);
859
+ } else if (entry.isFile()) {
860
+ if (relDir === "" && PACK_METADATA_FILES.has(entry.name)) continue;
861
+ out.push(rel);
862
+ }
863
+ }
864
+ }
865
+ try {
866
+ await recurse(packDir, "");
867
+ } catch (err) {
868
+ const code = err.code;
869
+ if (code === "ENOENT") {
870
+ throw new Error(`Pack directory not found: ${packDir}`);
871
+ }
872
+ throw err;
873
+ }
874
+ return out.sort();
875
+ }
876
+ async function mergeDefaultAndVariant(defaultDir, variantDir) {
877
+ const defaultFiles = new Set(await walkPackTree(defaultDir));
878
+ const variantFiles = new Set(await walkPackTree(variantDir));
879
+ const overrides = [];
880
+ const variantAdds = [];
881
+ const defaultPassThrough = [];
882
+ const files = [];
883
+ const allPaths = Array.from(/* @__PURE__ */ new Set([...defaultFiles, ...variantFiles])).sort();
884
+ for (const rel of allPaths) {
885
+ const inDefault = defaultFiles.has(rel);
886
+ const inVariant = variantFiles.has(rel);
887
+ if (inVariant && inDefault) {
888
+ overrides.push(rel);
889
+ files.push({
890
+ relPath: rel,
891
+ sourcePath: path2.join(variantDir, rel),
892
+ origin: "variant"
893
+ });
894
+ } else if (inVariant) {
895
+ variantAdds.push(rel);
896
+ files.push({
897
+ relPath: rel,
898
+ sourcePath: path2.join(variantDir, rel),
899
+ origin: "variant"
900
+ });
901
+ } else {
902
+ defaultPassThrough.push(rel);
903
+ files.push({
904
+ relPath: rel,
905
+ sourcePath: path2.join(defaultDir, rel),
906
+ origin: "default"
907
+ });
908
+ }
909
+ }
910
+ return { files, overrides, variantAdds, defaultPassThrough };
911
+ }
912
+
913
+ // src/variant-ui-pack-loader.ts
914
+ var fs3 = __toESM(require("fs/promises"), 1);
915
+ var path3 = __toESM(require("path"), 1);
916
+ async function readJson(filePath, kind) {
917
+ let raw;
918
+ try {
919
+ raw = await fs3.readFile(filePath, "utf-8");
920
+ } catch (err) {
921
+ const code = err.code;
922
+ if (code === "ENOENT") {
923
+ throw new Error(`${kind} not found: ${filePath}`);
924
+ }
925
+ throw new Error(
926
+ `Failed to read ${kind} at ${filePath}: ${err.message}`
927
+ );
928
+ }
929
+ try {
930
+ return JSON.parse(raw);
931
+ } catch {
932
+ throw new Error(`Invalid JSON in ${kind} at ${filePath}`);
933
+ }
934
+ }
935
+ async function loadVariantUiPackageCatalog(packageDir) {
936
+ const manifestPath = path3.join(packageDir, "manifest.json");
937
+ const data = await readJson(manifestPath, "variant-ui catalog");
938
+ const result = VariantUiPackageCatalogSchema.safeParse(data);
939
+ if (!result.success) {
940
+ throw new Error(
941
+ `Invalid catalog:
942
+ ${result.error.message}
943
+ File: ${manifestPath}`
944
+ );
945
+ }
946
+ return result.data;
947
+ }
948
+ async function loadVariantUiPackageManifest(variantDir) {
949
+ const manifestPath = path3.join(variantDir, "manifest.json");
950
+ const data = await readJson(manifestPath, "variant-ui manifest");
951
+ const result = VariantUiPackageManifestSchema.safeParse(data);
952
+ if (!result.success) {
953
+ throw new Error(
954
+ `Invalid variant manifest:
955
+ ${result.error.message}
956
+ File: ${manifestPath}`
957
+ );
958
+ }
959
+ const dirName = path3.basename(variantDir);
960
+ if (result.data.variant !== dirName) {
961
+ throw new Error(
962
+ `Variant manifest mismatch: variants/${dirName}/manifest.json declares variant="${result.data.variant}". Names must match.`
963
+ );
964
+ }
965
+ return result.data;
966
+ }
228
967
 
229
968
  // src/managed-regions.ts
230
969
  var REGION_PATTERN = /<!-- teamix-evo:managed:start id="([^"]+)" -->([\s\S]*?)<!-- teamix-evo:managed:end id="\1" -->/g;
@@ -233,15 +972,25 @@ var END_MARKER_PATTERN = /<!-- teamix-evo:managed:end id="([^"]+)" -->/g;
233
972
  function parseManagedRegions(content) {
234
973
  const startIds = /* @__PURE__ */ new Set();
235
974
  const endIds = /* @__PURE__ */ new Set();
975
+ const startCounts = /* @__PURE__ */ new Map();
236
976
  let match;
237
977
  const startRe = new RegExp(START_MARKER_PATTERN.source, "g");
238
978
  while ((match = startRe.exec(content)) !== null) {
239
- startIds.add(match[1]);
979
+ const id = match[1];
980
+ startIds.add(id);
981
+ startCounts.set(id, (startCounts.get(id) ?? 0) + 1);
240
982
  }
241
983
  const endRe = new RegExp(END_MARKER_PATTERN.source, "g");
242
984
  while ((match = endRe.exec(content)) !== null) {
243
985
  endIds.add(match[1]);
244
986
  }
987
+ for (const [id, count] of startCounts) {
988
+ if (count > 1) {
989
+ throw new Error(
990
+ `Duplicate managed region: found ${count} start markers for "${id}". Each id must be unique within a file.`
991
+ );
992
+ }
993
+ }
245
994
  for (const id of startIds) {
246
995
  if (!endIds.has(id)) {
247
996
  throw new Error(
@@ -274,7 +1023,9 @@ function replaceManagedRegion(content, id, newContent) {
274
1023
  const startMarker = `<!-- teamix-evo:managed:start id="${id}" -->`;
275
1024
  const endMarker = `<!-- teamix-evo:managed:end id="${id}" -->`;
276
1025
  const pattern = new RegExp(
277
- `<!-- teamix-evo:managed:start id="${escapeRegExp(id)}" -->[\\s\\S]*?<!-- teamix-evo:managed:end id="${escapeRegExp(id)}" -->`,
1026
+ `<!-- teamix-evo:managed:start id="${escapeRegExp(
1027
+ id
1028
+ )}" -->[\\s\\S]*?<!-- teamix-evo:managed:end id="${escapeRegExp(id)}" -->`,
278
1029
  "g"
279
1030
  );
280
1031
  if (!pattern.test(content)) {
@@ -290,7 +1041,9 @@ ${endMarker}`
290
1041
  }
291
1042
  function hasManagedRegion(content, id) {
292
1043
  const pattern = new RegExp(
293
- `<!-- teamix-evo:managed:start id="${escapeRegExp(id)}" -->[\\s\\S]*?<!-- teamix-evo:managed:end id="${escapeRegExp(id)}" -->`
1044
+ `<!-- teamix-evo:managed:start id="${escapeRegExp(
1045
+ id
1046
+ )}" -->[\\s\\S]*?<!-- teamix-evo:managed:end id="${escapeRegExp(id)}" -->`
294
1047
  );
295
1048
  return pattern.test(content);
296
1049
  }
@@ -334,6 +1087,10 @@ function getUpdateAction(strategy, options) {
334
1087
  }
335
1088
  // Annotate the CommonJS export names for ESM import in node:
336
1089
  0 && (module.exports = {
1090
+ DesignPackLinkedSchema,
1091
+ DesignPackLockSchema,
1092
+ DesignPackManifestSchema,
1093
+ DesignPackageManifestSchema,
337
1094
  InstalledManifestSchema,
338
1095
  InstalledPackageSchema,
339
1096
  InstalledResourceSchema,
@@ -341,16 +1098,45 @@ function getUpdateAction(strategy, options) {
341
1098
  ProjectConfigSchema,
342
1099
  ResourceSchema,
343
1100
  ResourceTypeSchema,
1101
+ SkillEntrySchema,
1102
+ SkillIdeSchema,
1103
+ SkillScopeSchema,
1104
+ SkillsLockEntrySchema,
1105
+ SkillsLockSchema,
1106
+ SkillsPackageManifestSchema,
1107
+ TailwindVersionSchema,
1108
+ UiAliasSchema,
1109
+ UiAliasesSchema,
1110
+ UiEntryFileSchema,
1111
+ UiEntrySchema,
1112
+ UiEntryTypeSchema,
1113
+ UiPackageManifestSchema,
344
1114
  UpdateStrategySchema,
345
1115
  VariantManifestSchema,
1116
+ VariantUiPackageCatalogSchema,
1117
+ VariantUiPackageManifestSchema,
1118
+ VariantUiPackageNameSchema,
346
1119
  getUpdateAction,
347
1120
  hasManagedRegion,
1121
+ loadDesignPack,
1122
+ loadDesignPackageManifest,
1123
+ loadSkillsPackageManifest,
1124
+ loadUiPackageManifest,
348
1125
  loadVariantManifest,
1126
+ loadVariantUiPackageCatalog,
1127
+ loadVariantUiPackageManifest,
1128
+ mergeDefaultAndVariant,
349
1129
  parseManagedRegions,
350
1130
  replaceManagedRegion,
1131
+ resolveUiEntryOrder,
351
1132
  shouldUpdate,
352
1133
  validateConfig,
353
1134
  validateInstalled,
354
- validateManifest
1135
+ validateManifest,
1136
+ validateSkillsLock,
1137
+ validateSkillsPackage,
1138
+ validateUiDependencyGraph,
1139
+ validateUiPackage,
1140
+ walkPackTree
355
1141
  });
356
1142
  //# sourceMappingURL=index.cjs.map