@teamix-evo/registry 0.1.0 → 0.2.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
@@ -9,8 +9,11 @@ var ResourceTypeSchema = z.enum([
9
9
  "doc",
10
10
  "tokens",
11
11
  "ai-rules",
12
- "config"
12
+ "config",
13
+ "skill"
13
14
  ]);
15
+ var SkillIdeSchema = z.enum(["qoder", "claude"]);
16
+ var SkillScopeSchema = z.enum(["project", "global"]);
14
17
  var ResourceSchema = z.object({
15
18
  /** Unique identifier for the resource within the manifest */
16
19
  id: z.string().min(1),
@@ -18,7 +21,10 @@ var ResourceSchema = z.object({
18
21
  type: ResourceTypeSchema,
19
22
  /** Source path (relative to variant root), typically a template */
20
23
  source: z.string().min(1),
21
- /** Target path (relative to project root) where the resource is installed */
24
+ /**
25
+ * Target path (relative to project root) where the resource is installed.
26
+ * For type="skill" this is ignored: the path is computed from skill name + ide + scope.
27
+ */
22
28
  target: z.string().min(1),
23
29
  /** How the resource is updated */
24
30
  updateStrategy: UpdateStrategySchema,
@@ -27,7 +33,11 @@ var ResourceSchema = z.object({
27
33
  /** IDs of managed regions (only relevant when updateStrategy is "managed") */
28
34
  managedRegions: z.array(z.string()).optional(),
29
35
  /** Whether to recursively process directory contents */
30
- recursive: z.boolean().optional()
36
+ recursive: z.boolean().optional(),
37
+ /** Supported IDEs (only meaningful when type="skill"; defaults to all when omitted) */
38
+ ides: z.array(SkillIdeSchema).optional(),
39
+ /** Default install scope (only meaningful when type="skill"; user can override at install time) */
40
+ scope: SkillScopeSchema.optional()
31
41
  });
32
42
  var VariantManifestSchema = z.object({
33
43
  $schema: z.string().optional(),
@@ -51,14 +61,160 @@ var VariantManifestSchema = z.object({
51
61
  /** List of resources provided by this variant */
52
62
  resources: z.array(ResourceSchema)
53
63
  });
64
+ var SkillEntrySchema = z.object({
65
+ /** Skill identifier (matches name/folder) */
66
+ id: z.string().min(1),
67
+ /** Skill name — must match the directory name and frontmatter `name` */
68
+ name: z.string().min(1).regex(
69
+ /^[a-z0-9][a-z0-9-]*$/,
70
+ "Skill name must be lowercase letters, digits, hyphens (no leading hyphen)"
71
+ ),
72
+ /** One-line description for skill discovery */
73
+ description: z.string().min(1),
74
+ /** Semver version */
75
+ version: z.string().regex(/^\d+\.\d+\.\d+/, "Invalid semver version"),
76
+ /** Source path relative to package root — file or directory */
77
+ source: z.string().min(1),
78
+ /** Supported IDEs (defaults to both when omitted) */
79
+ ides: z.array(SkillIdeSchema).default(["qoder", "claude"]),
80
+ /** Update strategy (defaults to managed) */
81
+ updateStrategy: UpdateStrategySchema.default("managed"),
82
+ /** Managed region IDs to maintain on update */
83
+ managedRegions: z.array(z.string()).optional(),
84
+ /** Whether the source is a Handlebars template */
85
+ template: z.boolean().optional()
86
+ });
87
+ var SkillsPackageManifestSchema = z.object({
88
+ $schema: z.string().optional(),
89
+ schemaVersion: z.literal(1),
90
+ /** Always "skills" for this package */
91
+ package: z.literal("skills"),
92
+ /** Semver version of the skills package */
93
+ version: z.string().regex(/^\d+\.\d+\.\d+/, "Invalid semver version"),
94
+ /** Engine compatibility */
95
+ engines: z.object({
96
+ "teamix-evo": z.string().min(1)
97
+ }),
98
+ /** Flat list of skills shipped by this package */
99
+ skills: z.array(SkillEntrySchema)
100
+ });
101
+ var UiEntryTypeSchema = z.enum([
102
+ "component",
103
+ "hook",
104
+ "util",
105
+ "block"
106
+ ]);
107
+ var UiAliasSchema = z.enum(["components", "hooks", "utils", "lib"]);
108
+ var UiEntryStatusSchema = z.enum([
109
+ "stable",
110
+ "experimental",
111
+ "deprecated"
112
+ ]);
113
+ var UiEntryFileSchema = z.object({
114
+ /** Source path relative to the ui package root (e.g. "src/components/button/button.tsx") */
115
+ source: z.string().min(1),
116
+ /** Which alias this file resolves under in the consumer project */
117
+ targetAlias: UiAliasSchema,
118
+ /** Filename written under the alias directory (e.g. "button.tsx") */
119
+ targetName: z.string().min(1)
120
+ });
121
+ var UiEntrySchema = z.object({
122
+ /** Unique entry identifier within the ui package (e.g. "button") */
123
+ id: z.string().min(1).regex(
124
+ /^[a-z0-9][a-z0-9-]*$/,
125
+ "UI entry id must be lowercase letters, digits, hyphens (no leading hyphen)"
126
+ ),
127
+ /** Display name (e.g. "Button") */
128
+ name: z.string().min(1),
129
+ /** Entry type */
130
+ type: UiEntryTypeSchema,
131
+ /** One-line description for entry discovery and AI guidance */
132
+ description: z.string().min(1),
133
+ /** Files this entry ships (typically 1) */
134
+ files: z.array(UiEntryFileSchema).min(1),
135
+ /**
136
+ * Optional path to an AI-readable meta document (frontmatter + Markdown).
137
+ * When set, CLI install drops it at `.teamix-evo/design/components/<id>.meta.md`
138
+ * for design's ai-rules to consume.
139
+ */
140
+ meta: z.string().optional(),
141
+ /** Other UI entries this one depends on (e.g. "button" depends on "cn") */
142
+ registryDependencies: z.array(z.string()).optional(),
143
+ /** npm dependencies required by this entry (name → semver range) */
144
+ dependencies: z.record(z.string(), z.string()).optional(),
145
+ /**
146
+ * How CLI handles this entry on `ui upgrade`.
147
+ * Defaults to `frozen` — user-owned source code, untouched after first install.
148
+ * Upgrade is handled by AI + skill flow (no CLI rewrite). See PLAN §10.9.
149
+ */
150
+ updateStrategy: UpdateStrategySchema.default("frozen"),
151
+ /**
152
+ * Whether the source file should be passed through Handlebars before write.
153
+ * Most entries don't need templating (use import-rewrite transformer instead).
154
+ */
155
+ template: z.boolean().optional(),
156
+ /**
157
+ * Maturity / lifecycle status of this entry. Defaults to `stable`.
158
+ * See {@link UiEntryStatusSchema} for semantics.
159
+ */
160
+ status: UiEntryStatusSchema.default("stable"),
161
+ /**
162
+ * Free-text rationale shown to consumers when `status` is `deprecated`.
163
+ * Should explain why the entry is going away and what replaces it.
164
+ */
165
+ deprecatedReason: z.string().optional(),
166
+ /**
167
+ * If this entry is `deprecated`, the id of the entry that supersedes it.
168
+ * Consumers (and AI) should migrate to `replacedBy` rather than this entry.
169
+ */
170
+ replacedBy: z.string().optional()
171
+ });
172
+ var UiPackageManifestSchema = z.object({
173
+ $schema: z.string().optional(),
174
+ schemaVersion: z.literal(1),
175
+ /** Always "ui" for this package */
176
+ package: z.literal("ui"),
177
+ /** Semver version of the ui package */
178
+ version: z.string().regex(/^\d+\.\d+\.\d+/, "Invalid semver version"),
179
+ /** Engine compatibility */
180
+ engines: z.object({
181
+ "teamix-evo": z.string().min(1)
182
+ }),
183
+ /** Flat list of entries shipped by this package */
184
+ entries: z.array(UiEntrySchema)
185
+ });
54
186
 
55
187
  // src/schema/config.ts
56
188
  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)
195
+ });
57
196
  var PackageEntrySchema = z2.object({
58
- /** Variant identifier (e.g. "opentrek") */
197
+ /** Variant identifier (e.g. "opentrek"; use "_flat" for skills/ui) */
59
198
  variant: z2.string().min(1),
60
199
  /** Semver version string */
61
- version: z2.string().min(1)
200
+ version: z2.string().min(1),
201
+ /** Tailwind CSS version this project uses (only meaningful for design package). */
202
+ tailwind: TailwindVersionSchema.optional(),
203
+ /** IDEs this package was installed for (only meaningful for skills package). */
204
+ ides: z2.array(SkillIdeSchema).optional(),
205
+ /** Install scope (only meaningful for skills package). */
206
+ scope: SkillScopeSchema.optional(),
207
+ /** Path aliases for ui entry installation (only meaningful for ui package). */
208
+ aliases: UiAliasesSchema.optional(),
209
+ /**
210
+ * Default icon library declared by the project (only meaningful for ui).
211
+ * Declarative only — does NOT trigger code rewrites; ui entries hardcode imports.
212
+ */
213
+ iconLibrary: z2.string().min(1).optional(),
214
+ /** Whether the project uses TSX (true) or JSX (false). ui-specific. */
215
+ tsx: z2.boolean().optional(),
216
+ /** Whether to emit React Server Components markers (`"use client"`). ui-specific. */
217
+ rsc: z2.boolean().optional()
62
218
  });
63
219
  var ProjectConfigSchema = z2.object({
64
220
  $schema: z2.string().optional(),
@@ -74,17 +230,21 @@ import { z as z3 } from "zod";
74
230
  var InstalledResourceSchema = z3.object({
75
231
  /** Resource identifier matching the variant manifest */
76
232
  id: z3.string().min(1),
77
- /** Target path where the resource was installed */
233
+ /** Target path where the resource was installed (absolute or project-relative) */
78
234
  target: z3.string().min(1),
79
235
  /** Content hash for change detection (e.g. "sha256:...") */
80
236
  hash: z3.string().min(1),
81
237
  /** Update strategy that was applied */
82
- strategy: z3.enum(["frozen", "regenerable", "managed"])
238
+ strategy: z3.enum(["frozen", "regenerable", "managed"]),
239
+ /** IDE this resource was installed for (skill resources only) */
240
+ ide: SkillIdeSchema.optional(),
241
+ /** Install scope (skill resources only) */
242
+ scope: SkillScopeSchema.optional()
83
243
  });
84
244
  var InstalledPackageSchema = z3.object({
85
245
  /** Full package name (e.g. "@teamix-evo/design") */
86
246
  package: z3.string().min(1),
87
- /** Variant identifier */
247
+ /** Variant identifier (use "_flat" for non-variant packages such as skills) */
88
248
  variant: z3.string().min(1),
89
249
  /** Installed version */
90
250
  version: z3.string().min(1),
@@ -143,6 +303,115 @@ function validateInstalled(data) {
143
303
  ${formatZodError(result.error)}`
144
304
  };
145
305
  }
306
+ function validateSkillsPackage(data) {
307
+ const result = SkillsPackageManifestSchema.safeParse(data);
308
+ if (result.success) {
309
+ return { success: true, data: result.data };
310
+ }
311
+ return {
312
+ success: false,
313
+ error: `Invalid skills package manifest:
314
+ ${formatZodError(result.error)}`
315
+ };
316
+ }
317
+ function validateUiPackage(data) {
318
+ const parsed = UiPackageManifestSchema.safeParse(data);
319
+ if (!parsed.success) {
320
+ return {
321
+ success: false,
322
+ error: `Invalid ui package manifest:
323
+ ${formatZodError(parsed.error)}`
324
+ };
325
+ }
326
+ const graphIssues = validateUiDependencyGraph(parsed.data.entries);
327
+ if (graphIssues.length > 0) {
328
+ return {
329
+ success: false,
330
+ error: `Invalid ui package manifest dependency graph:
331
+ ${graphIssues.map((i) => ` - ${i}`).join("\n")}`
332
+ };
333
+ }
334
+ return { success: true, data: parsed.data };
335
+ }
336
+ function validateUiDependencyGraph(entries) {
337
+ const issues = [];
338
+ const idToEntry = /* @__PURE__ */ new Map();
339
+ for (const entry of entries) {
340
+ if (idToEntry.has(entry.id)) {
341
+ issues.push(`duplicate entry id: "${entry.id}"`);
342
+ } else {
343
+ idToEntry.set(entry.id, entry);
344
+ }
345
+ }
346
+ for (const entry of entries) {
347
+ const deps = entry.registryDependencies ?? [];
348
+ for (const dep of deps) {
349
+ if (!idToEntry.has(dep)) {
350
+ issues.push(
351
+ `entry "${entry.id}" depends on unknown entry "${dep}"`
352
+ );
353
+ }
354
+ }
355
+ }
356
+ const WHITE = 0;
357
+ const GRAY = 1;
358
+ const BLACK = 2;
359
+ const color = /* @__PURE__ */ new Map();
360
+ for (const id of idToEntry.keys()) color.set(id, WHITE);
361
+ const cycles = [];
362
+ function dfs(id, path2) {
363
+ color.set(id, GRAY);
364
+ path2.push(id);
365
+ const entry = idToEntry.get(id);
366
+ const deps = entry?.registryDependencies ?? [];
367
+ for (const dep of deps) {
368
+ if (!idToEntry.has(dep)) continue;
369
+ const c = color.get(dep);
370
+ if (c === GRAY) {
371
+ const startIdx = path2.indexOf(dep);
372
+ cycles.push([...path2.slice(startIdx), dep]);
373
+ } else if (c === WHITE) {
374
+ dfs(dep, path2);
375
+ }
376
+ }
377
+ path2.pop();
378
+ color.set(id, BLACK);
379
+ }
380
+ for (const id of idToEntry.keys()) {
381
+ if (color.get(id) === WHITE) dfs(id, []);
382
+ }
383
+ for (const cycle of cycles) {
384
+ issues.push(`cyclic registryDependencies: ${cycle.join(" \u2192 ")}`);
385
+ }
386
+ return issues;
387
+ }
388
+ function resolveUiEntryOrder(entries, requested) {
389
+ const idToEntry = new Map(entries.map((e) => [e.id, e]));
390
+ for (const id of requested) {
391
+ if (!idToEntry.has(id)) {
392
+ throw new Error(`Unknown ui entry: "${id}"`);
393
+ }
394
+ }
395
+ const graphIssues = validateUiDependencyGraph(entries);
396
+ if (graphIssues.length > 0) {
397
+ throw new Error(
398
+ `UI dependency graph has issues:
399
+ ${graphIssues.map((i) => ` - ${i}`).join("\n")}`
400
+ );
401
+ }
402
+ const visited = /* @__PURE__ */ new Set();
403
+ const order = [];
404
+ function visit(id) {
405
+ if (visited.has(id)) return;
406
+ visited.add(id);
407
+ const entry = idToEntry.get(id);
408
+ const deps = entry?.registryDependencies ?? [];
409
+ for (const dep of deps) visit(dep);
410
+ order.push(id);
411
+ }
412
+ for (const id of requested) visit(id);
413
+ return order;
414
+ }
146
415
 
147
416
  // src/loader.ts
148
417
  async function loadVariantManifest(packageDir) {
@@ -172,6 +441,60 @@ async function loadVariantManifest(packageDir) {
172
441
  }
173
442
  return result.data;
174
443
  }
444
+ async function loadSkillsPackageManifest(packageDir) {
445
+ const manifestPath = path.join(packageDir, "manifest.json");
446
+ let raw;
447
+ try {
448
+ raw = await fs.readFile(manifestPath, "utf-8");
449
+ } catch (err) {
450
+ const code = err.code;
451
+ if (code === "ENOENT") {
452
+ throw new Error(`Skills manifest not found: ${manifestPath}`);
453
+ }
454
+ throw new Error(
455
+ `Failed to read skills manifest at ${manifestPath}: ${err.message}`
456
+ );
457
+ }
458
+ let data;
459
+ try {
460
+ data = JSON.parse(raw);
461
+ } catch {
462
+ throw new Error(`Invalid JSON in skills manifest at ${manifestPath}`);
463
+ }
464
+ const result = validateSkillsPackage(data);
465
+ if (!result.success) {
466
+ throw new Error(`${result.error}
467
+ File: ${manifestPath}`);
468
+ }
469
+ return result.data;
470
+ }
471
+ async function loadUiPackageManifest(packageDir) {
472
+ const manifestPath = path.join(packageDir, "manifest.json");
473
+ let raw;
474
+ try {
475
+ raw = await fs.readFile(manifestPath, "utf-8");
476
+ } catch (err) {
477
+ const code = err.code;
478
+ if (code === "ENOENT") {
479
+ throw new Error(`UI manifest not found: ${manifestPath}`);
480
+ }
481
+ throw new Error(
482
+ `Failed to read ui manifest at ${manifestPath}: ${err.message}`
483
+ );
484
+ }
485
+ let data;
486
+ try {
487
+ data = JSON.parse(raw);
488
+ } catch {
489
+ throw new Error(`Invalid JSON in ui manifest at ${manifestPath}`);
490
+ }
491
+ const result = validateUiPackage(data);
492
+ if (!result.success) {
493
+ throw new Error(`${result.error}
494
+ File: ${manifestPath}`);
495
+ }
496
+ return result.data;
497
+ }
175
498
 
176
499
  // src/managed-regions.ts
177
500
  var REGION_PATTERN = /<!-- teamix-evo:managed:start id="([^"]+)" -->([\s\S]*?)<!-- teamix-evo:managed:end id="\1" -->/g;
@@ -180,15 +503,25 @@ var END_MARKER_PATTERN = /<!-- teamix-evo:managed:end id="([^"]+)" -->/g;
180
503
  function parseManagedRegions(content) {
181
504
  const startIds = /* @__PURE__ */ new Set();
182
505
  const endIds = /* @__PURE__ */ new Set();
506
+ const startCounts = /* @__PURE__ */ new Map();
183
507
  let match;
184
508
  const startRe = new RegExp(START_MARKER_PATTERN.source, "g");
185
509
  while ((match = startRe.exec(content)) !== null) {
186
- startIds.add(match[1]);
510
+ const id = match[1];
511
+ startIds.add(id);
512
+ startCounts.set(id, (startCounts.get(id) ?? 0) + 1);
187
513
  }
188
514
  const endRe = new RegExp(END_MARKER_PATTERN.source, "g");
189
515
  while ((match = endRe.exec(content)) !== null) {
190
516
  endIds.add(match[1]);
191
517
  }
518
+ for (const [id, count] of startCounts) {
519
+ if (count > 1) {
520
+ throw new Error(
521
+ `Duplicate managed region: found ${count} start markers for "${id}". Each id must be unique within a file.`
522
+ );
523
+ }
524
+ }
192
525
  for (const id of startIds) {
193
526
  if (!endIds.has(id)) {
194
527
  throw new Error(
@@ -221,7 +554,9 @@ function replaceManagedRegion(content, id, newContent) {
221
554
  const startMarker = `<!-- teamix-evo:managed:start id="${id}" -->`;
222
555
  const endMarker = `<!-- teamix-evo:managed:end id="${id}" -->`;
223
556
  const pattern = new RegExp(
224
- `<!-- teamix-evo:managed:start id="${escapeRegExp(id)}" -->[\\s\\S]*?<!-- teamix-evo:managed:end id="${escapeRegExp(id)}" -->`,
557
+ `<!-- teamix-evo:managed:start id="${escapeRegExp(
558
+ id
559
+ )}" -->[\\s\\S]*?<!-- teamix-evo:managed:end id="${escapeRegExp(id)}" -->`,
225
560
  "g"
226
561
  );
227
562
  if (!pattern.test(content)) {
@@ -237,7 +572,9 @@ ${endMarker}`
237
572
  }
238
573
  function hasManagedRegion(content, id) {
239
574
  const pattern = new RegExp(
240
- `<!-- teamix-evo:managed:start id="${escapeRegExp(id)}" -->[\\s\\S]*?<!-- teamix-evo:managed:end id="${escapeRegExp(id)}" -->`
575
+ `<!-- teamix-evo:managed:start id="${escapeRegExp(
576
+ id
577
+ )}" -->[\\s\\S]*?<!-- teamix-evo:managed:end id="${escapeRegExp(id)}" -->`
241
578
  );
242
579
  return pattern.test(content);
243
580
  }
@@ -287,16 +624,33 @@ export {
287
624
  ProjectConfigSchema,
288
625
  ResourceSchema,
289
626
  ResourceTypeSchema,
627
+ SkillEntrySchema,
628
+ SkillIdeSchema,
629
+ SkillScopeSchema,
630
+ SkillsPackageManifestSchema,
631
+ TailwindVersionSchema,
632
+ UiAliasSchema,
633
+ UiAliasesSchema,
634
+ UiEntryFileSchema,
635
+ UiEntrySchema,
636
+ UiEntryTypeSchema,
637
+ UiPackageManifestSchema,
290
638
  UpdateStrategySchema,
291
639
  VariantManifestSchema,
292
640
  getUpdateAction,
293
641
  hasManagedRegion,
642
+ loadSkillsPackageManifest,
643
+ loadUiPackageManifest,
294
644
  loadVariantManifest,
295
645
  parseManagedRegions,
296
646
  replaceManagedRegion,
647
+ resolveUiEntryOrder,
297
648
  shouldUpdate,
298
649
  validateConfig,
299
650
  validateInstalled,
300
- validateManifest
651
+ validateManifest,
652
+ validateSkillsPackage,
653
+ validateUiDependencyGraph,
654
+ validateUiPackage
301
655
  };
302
656
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/schema/manifest.ts","../src/schema/config.ts","../src/schema/installed.ts","../src/loader.ts","../src/validator.ts","../src/managed-regions.ts","../src/strategy.ts"],"sourcesContent":["import { z } from \"zod\";\n\n/**\n * Update strategy for a resource.\n * - frozen: CLI will not modify after first install\n * - regenerable: Entire file is rewritten on update\n * - managed: Only managed regions are rewritten, rest is preserved\n */\nexport const UpdateStrategySchema = z.enum([\n \"frozen\",\n \"regenerable\",\n \"managed\",\n]);\n\n/**\n * Resource type discriminator.\n */\nexport const ResourceTypeSchema = z.enum([\n \"doc\",\n \"tokens\",\n \"ai-rules\",\n \"config\",\n]);\n\n/**\n * A single resource entry within a variant manifest.\n */\nexport const ResourceSchema = z.object({\n /** Unique identifier for the resource within the manifest */\n id: z.string().min(1),\n /** Resource type */\n type: ResourceTypeSchema,\n /** Source path (relative to variant root), typically a template */\n source: z.string().min(1),\n /** Target path (relative to project root) where the resource is installed */\n target: z.string().min(1),\n /** How the resource is updated */\n updateStrategy: UpdateStrategySchema,\n /** Whether the source is a Handlebars template */\n template: z.boolean().optional(),\n /** IDs of managed regions (only relevant when updateStrategy is \"managed\") */\n managedRegions: z.array(z.string()).optional(),\n /** Whether to recursively process directory contents */\n recursive: z.boolean().optional(),\n});\n\n/**\n * Variant manifest schema — describes a variant package and its resources.\n */\nexport const VariantManifestSchema = z.object({\n $schema: z.string().optional(),\n schemaVersion: z.literal(1),\n /** Package name (e.g. \"design\") */\n package: z.string().min(1),\n /** Variant identifier (e.g. \"opentrek\") */\n variant: z.string().min(1),\n /** Human-readable name */\n displayName: z.string().min(1),\n /** Description of the variant */\n description: z.string(),\n /** Semver version string */\n version: z.string().regex(/^\\d+\\.\\d+\\.\\d+/, \"Invalid semver version\"),\n /** Engine compatibility */\n engines: z.object({\n \"teamix-evo\": z.string().min(1),\n }),\n /** Supported IDE identifiers */\n ide: z.array(z.string().min(1)),\n /** List of resources provided by this variant */\n resources: z.array(ResourceSchema),\n});\n","import { z } from \"zod\";\n\n/**\n * Package entry within a project config.\n */\nexport const PackageEntrySchema = z.object({\n /** Variant identifier (e.g. \"opentrek\") */\n variant: z.string().min(1),\n /** Semver version string */\n version: z.string().min(1),\n});\n\n/**\n * Project configuration schema — teamix-evo config.json at project root.\n */\nexport const ProjectConfigSchema = z.object({\n $schema: z.string().optional(),\n schemaVersion: z.literal(1),\n /** IDE identifier */\n ide: z.string().min(1),\n /** Installed packages keyed by package name */\n packages: z.record(z.string(), PackageEntrySchema),\n});\n","import { z } from \"zod\";\n\n/**\n * An installed resource entry — tracks individual resource installation state.\n */\nexport const InstalledResourceSchema = z.object({\n /** Resource identifier matching the variant manifest */\n id: z.string().min(1),\n /** Target path where the resource was installed */\n target: z.string().min(1),\n /** Content hash for change detection (e.g. \"sha256:...\") */\n hash: z.string().min(1),\n /** Update strategy that was applied */\n strategy: z.enum([\"frozen\", \"regenerable\", \"managed\"]),\n});\n\n/**\n * An installed package entry — tracks a single package installation.\n */\nexport const InstalledPackageSchema = z.object({\n /** Full package name (e.g. \"@teamix-evo/design\") */\n package: z.string().min(1),\n /** Variant identifier */\n variant: z.string().min(1),\n /** Installed version */\n version: z.string().min(1),\n /** ISO 8601 timestamp of installation */\n installedAt: z.string().min(1),\n /** List of installed resources */\n resources: z.array(InstalledResourceSchema),\n});\n\n/**\n * Installed manifest schema — tracks all installed packages in a project.\n * Stored at `.teamix-evo/manifest.json`.\n */\nexport const InstalledManifestSchema = z.object({\n schemaVersion: z.literal(1),\n /** List of installed packages */\n installed: z.array(InstalledPackageSchema),\n});\n","import * as fs from \"node:fs/promises\";\nimport * as path from \"node:path\";\nimport { validateManifest } from \"./validator.js\";\nimport type { VariantManifest } from \"./types.js\";\n\n/**\n * Load and validate a variant manifest from a package directory.\n *\n * Reads `manifest.json` from the given directory, parses it as JSON,\n * and validates it against the VariantManifest schema.\n *\n * @param packageDir - Absolute or relative path to the variant package directory\n * @returns The validated VariantManifest\n * @throws Error if the file cannot be read or the manifest is invalid\n */\nexport async function loadVariantManifest(\n packageDir: string,\n): Promise<VariantManifest> {\n const manifestPath = path.join(packageDir, \"manifest.json\");\n\n let raw: string;\n try {\n raw = await fs.readFile(manifestPath, \"utf-8\");\n } catch (err) {\n const code = (err as NodeJS.ErrnoException).code;\n if (code === \"ENOENT\") {\n throw new Error(`Manifest not found: ${manifestPath}`);\n }\n throw new Error(\n `Failed to read manifest at ${manifestPath}: ${(err as Error).message}`,\n );\n }\n\n let data: unknown;\n try {\n data = JSON.parse(raw);\n } catch {\n throw new Error(`Invalid JSON in manifest at ${manifestPath}`);\n }\n\n const result = validateManifest(data);\n if (!result.success) {\n throw new Error(`${result.error}\\n File: ${manifestPath}`);\n }\n\n return result.data;\n}\n","import { ZodError } from \"zod\";\nimport { VariantManifestSchema } from \"./schema/manifest.js\";\nimport { ProjectConfigSchema } from \"./schema/config.js\";\nimport { InstalledManifestSchema } from \"./schema/installed.js\";\nimport type {\n VariantManifest,\n ProjectConfig,\n InstalledManifest,\n Result,\n} from \"./types.js\";\n\n/**\n * Format a ZodError into a human-readable error message.\n */\nfunction formatZodError(error: ZodError): string {\n return error.issues\n .map((issue) => {\n const path = issue.path.length > 0 ? issue.path.join(\".\") : \"(root)\";\n return ` - ${path}: ${issue.message}`;\n })\n .join(\"\\n\");\n}\n\n/**\n * Validate unknown data against the VariantManifest schema.\n * Returns a discriminated Result with either the parsed data or a friendly error message.\n */\nexport function validateManifest(data: unknown): Result<VariantManifest> {\n const result = VariantManifestSchema.safeParse(data);\n if (result.success) {\n return { success: true, data: result.data };\n }\n return {\n success: false,\n error: `Invalid variant manifest:\\n${formatZodError(result.error)}`,\n };\n}\n\n/**\n * Validate unknown data against the ProjectConfig schema.\n */\nexport function validateConfig(data: unknown): Result<ProjectConfig> {\n const result = ProjectConfigSchema.safeParse(data);\n if (result.success) {\n return { success: true, data: result.data };\n }\n return {\n success: false,\n error: `Invalid project config:\\n${formatZodError(result.error)}`,\n };\n}\n\n/**\n * Validate unknown data against the InstalledManifest schema.\n */\nexport function validateInstalled(data: unknown): Result<InstalledManifest> {\n const result = InstalledManifestSchema.safeParse(data);\n if (result.success) {\n return { success: true, data: result.data };\n }\n return {\n success: false,\n error: `Invalid installed manifest:\\n${formatZodError(result.error)}`,\n };\n}\n","import type { ManagedRegion } from \"./types.js\";\n\n/**\n * Regex pattern for matching managed region markers.\n * Captures the region id and the content between start/end markers.\n */\nconst REGION_PATTERN =\n /<!-- teamix-evo:managed:start id=\"([^\"]+)\" -->([\\s\\S]*?)<!-- teamix-evo:managed:end id=\"\\1\" -->/g;\n\n/**\n * Regex for a start marker without a matching end marker — used for error detection.\n */\nconst START_MARKER_PATTERN =\n /<!-- teamix-evo:managed:start id=\"([^\"]+)\" -->/g;\n\nconst END_MARKER_PATTERN =\n /<!-- teamix-evo:managed:end id=\"([^\"]+)\" -->/g;\n\n/**\n * Parse all managed regions from document content.\n *\n * @param content - The full document content\n * @returns Array of parsed ManagedRegion objects\n * @throws Error if there are unmatched start/end markers\n */\nexport function parseManagedRegions(content: string): ManagedRegion[] {\n // First, check for unmatched markers\n const startIds = new Set<string>();\n const endIds = new Set<string>();\n\n let match: RegExpExecArray | null;\n\n const startRe = new RegExp(START_MARKER_PATTERN.source, \"g\");\n while ((match = startRe.exec(content)) !== null) {\n startIds.add(match[1]);\n }\n\n const endRe = new RegExp(END_MARKER_PATTERN.source, \"g\");\n while ((match = endRe.exec(content)) !== null) {\n endIds.add(match[1]);\n }\n\n // Check for start markers without matching end markers\n for (const id of startIds) {\n if (!endIds.has(id)) {\n throw new Error(\n `Unmatched managed region: found start marker for \"${id}\" but no matching end marker`,\n );\n }\n }\n\n // Check for end markers without matching start markers\n for (const id of endIds) {\n if (!startIds.has(id)) {\n throw new Error(\n `Unmatched managed region: found end marker for \"${id}\" but no matching start marker`,\n );\n }\n }\n\n // Now parse matched regions\n const regions: ManagedRegion[] = [];\n const regionRe = new RegExp(REGION_PATTERN.source, \"g\");\n\n while ((match = regionRe.exec(content)) !== null) {\n const id = match[1];\n const regionContent = match[2];\n regions.push({\n id,\n startMarker: `<!-- teamix-evo:managed:start id=\"${id}\" -->`,\n endMarker: `<!-- teamix-evo:managed:end id=\"${id}\" -->`,\n content: regionContent,\n });\n }\n\n return regions;\n}\n\n/**\n * Replace the content of a specific managed region by id.\n * Content outside managed regions is preserved.\n *\n * @param content - The full document content\n * @param id - The region id to replace\n * @param newContent - The new content for the region\n * @returns The updated document content\n * @throws Error if the region id is not found\n */\nexport function replaceManagedRegion(\n content: string,\n id: string,\n newContent: string,\n): string {\n const startMarker = `<!-- teamix-evo:managed:start id=\"${id}\" -->`;\n const endMarker = `<!-- teamix-evo:managed:end id=\"${id}\" -->`;\n\n const pattern = new RegExp(\n `<!-- teamix-evo:managed:start id=\"${escapeRegExp(id)}\" -->[\\\\s\\\\S]*?<!-- teamix-evo:managed:end id=\"${escapeRegExp(id)}\" -->`,\n \"g\",\n );\n\n // First check if the region actually exists\n if (!pattern.test(content)) {\n throw new Error(`Managed region \"${id}\" not found in content`);\n }\n\n // Reset lastIndex after test() with global flag\n pattern.lastIndex = 0;\n\n return content.replace(\n pattern,\n `${startMarker}\\n${newContent}\\n${endMarker}`,\n );\n}\n\n/**\n * Check whether a managed region with the given id exists in the content.\n *\n * @param content - The full document content\n * @param id - The region id to check\n * @returns true if the region exists\n */\nexport function hasManagedRegion(content: string, id: string): boolean {\n const pattern = new RegExp(\n `<!-- teamix-evo:managed:start id=\"${escapeRegExp(id)}\" -->[\\\\s\\\\S]*?<!-- teamix-evo:managed:end id=\"${escapeRegExp(id)}\" -->`,\n );\n return pattern.test(content);\n}\n\n/**\n * Escape special regex characters in a string.\n */\nfunction escapeRegExp(str: string): string {\n return str.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n}\n","import type { UpdateStrategy } from \"./types.js\";\n\n/**\n * Determine whether a resource should be updated based on its strategy\n * and whether it already exists.\n *\n * @param strategy - The update strategy for the resource\n * @param resourceExists - Whether the resource file already exists\n * @returns true if the resource should be updated/created\n */\nexport function shouldUpdate(\n strategy: UpdateStrategy,\n resourceExists: boolean,\n): boolean {\n switch (strategy) {\n case \"frozen\":\n // Only install if it doesn't exist yet\n return !resourceExists;\n case \"regenerable\":\n // Always overwrite\n return true;\n case \"managed\":\n // Always update (managed regions only)\n return true;\n default:\n return false;\n }\n}\n\n/** Possible actions returned by getUpdateAction */\nexport type UpdateAction = \"skip\" | \"overwrite\" | \"managed-update\";\n\nexport interface UpdateActionOptions {\n /** Whether the resource file already exists */\n exists: boolean;\n /** Hash of the new content to be written */\n hash?: string;\n /** Hash of the currently installed content */\n currentHash?: string;\n}\n\n/**\n * Determine the specific update action to take for a resource.\n *\n * @param strategy - The update strategy for the resource\n * @param options - Context about the resource's current state\n * @returns The action to perform\n */\nexport function getUpdateAction(\n strategy: UpdateStrategy,\n options: UpdateActionOptions,\n): UpdateAction {\n switch (strategy) {\n case \"frozen\":\n if (!options.exists) {\n // First-time install\n return \"overwrite\";\n }\n // File exists, never modify\n return \"skip\";\n\n case \"regenerable\":\n if (\n options.exists &&\n options.hash &&\n options.currentHash &&\n options.hash === options.currentHash\n ) {\n // Content unchanged, skip\n return \"skip\";\n }\n return \"overwrite\";\n\n case \"managed\":\n if (!options.exists) {\n // First-time install — write the whole file\n return \"overwrite\";\n }\n return \"managed-update\";\n\n default:\n return \"skip\";\n }\n}\n"],"mappings":"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","names":["z","z","path"]}
1
+ {"version":3,"sources":["../src/schema/manifest.ts","../src/schema/config.ts","../src/schema/installed.ts","../src/loader.ts","../src/validator.ts","../src/managed-regions.ts","../src/strategy.ts"],"sourcesContent":["import { z } from 'zod';\n\n/**\n * Update strategy for a resource.\n * - frozen: CLI will not modify after first install\n * - regenerable: Entire file is rewritten on update\n * - managed: Only managed regions are rewritten, rest is preserved\n */\nexport const UpdateStrategySchema = z.enum([\n 'frozen',\n 'regenerable',\n 'managed',\n]);\n\n/**\n * Resource type discriminator.\n */\nexport const ResourceTypeSchema = z.enum([\n 'doc',\n 'tokens',\n 'ai-rules',\n 'config',\n 'skill',\n]);\n\n/**\n * Supported AI IDE identifiers for skill resources.\n * Qoder and Claude Code share the same SKILL.md format; differ only by install path.\n */\nexport const SkillIdeSchema = z.enum(['qoder', 'claude']);\n\n/**\n * Skill installation scope.\n * - project: install under project root (.qoder/skills/, .claude/skills/)\n * - global: install under user home (~/.qoder/skills/, ~/.claude/skills/)\n */\nexport const SkillScopeSchema = z.enum(['project', 'global']);\n\n/**\n * A single resource entry within a variant manifest.\n */\nexport const ResourceSchema = z.object({\n /** Unique identifier for the resource within the manifest */\n id: z.string().min(1),\n /** Resource type */\n type: ResourceTypeSchema,\n /** Source path (relative to variant root), typically a template */\n source: z.string().min(1),\n /**\n * Target path (relative to project root) where the resource is installed.\n * For type=\"skill\" this is ignored: the path is computed from skill name + ide + scope.\n */\n target: z.string().min(1),\n /** How the resource is updated */\n updateStrategy: UpdateStrategySchema,\n /** Whether the source is a Handlebars template */\n template: z.boolean().optional(),\n /** IDs of managed regions (only relevant when updateStrategy is \"managed\") */\n managedRegions: z.array(z.string()).optional(),\n /** Whether to recursively process directory contents */\n recursive: z.boolean().optional(),\n /** Supported IDEs (only meaningful when type=\"skill\"; defaults to all when omitted) */\n ides: z.array(SkillIdeSchema).optional(),\n /** Default install scope (only meaningful when type=\"skill\"; user can override at install time) */\n scope: SkillScopeSchema.optional(),\n});\n\n/**\n * Variant manifest schema — describes a variant package and its resources.\n */\nexport const VariantManifestSchema = z.object({\n $schema: z.string().optional(),\n schemaVersion: z.literal(1),\n /** Package name (e.g. \"design\") */\n package: z.string().min(1),\n /** Variant identifier (e.g. \"opentrek\") */\n variant: z.string().min(1),\n /** Human-readable name */\n displayName: z.string().min(1),\n /** Description of the variant */\n description: z.string(),\n /** Semver version string */\n version: z.string().regex(/^\\d+\\.\\d+\\.\\d+/, 'Invalid semver version'),\n /** Engine compatibility */\n engines: z.object({\n 'teamix-evo': z.string().min(1),\n }),\n /** Supported IDE identifiers */\n ide: z.array(z.string().min(1)),\n /** List of resources provided by this variant */\n resources: z.array(ResourceSchema),\n});\n\n/**\n * A single skill entry within a skills package manifest.\n */\nexport const SkillEntrySchema = z.object({\n /** Skill identifier (matches name/folder) */\n id: z.string().min(1),\n /** Skill name — must match the directory name and frontmatter `name` */\n name: z\n .string()\n .min(1)\n .regex(\n /^[a-z0-9][a-z0-9-]*$/,\n 'Skill name must be lowercase letters, digits, hyphens (no leading hyphen)',\n ),\n /** One-line description for skill discovery */\n description: z.string().min(1),\n /** Semver version */\n version: z.string().regex(/^\\d+\\.\\d+\\.\\d+/, 'Invalid semver version'),\n /** Source path relative to package root — file or directory */\n source: z.string().min(1),\n /** Supported IDEs (defaults to both when omitted) */\n ides: z.array(SkillIdeSchema).default(['qoder', 'claude']),\n /** Update strategy (defaults to managed) */\n updateStrategy: UpdateStrategySchema.default('managed'),\n /** Managed region IDs to maintain on update */\n managedRegions: z.array(z.string()).optional(),\n /** Whether the source is a Handlebars template */\n template: z.boolean().optional(),\n});\n\n/**\n * Skills package manifest schema — top-level manifest of `@teamix-evo/skills`.\n * Unlike design which is variant-based, skills are flat (no variants).\n */\nexport const SkillsPackageManifestSchema = z.object({\n $schema: z.string().optional(),\n schemaVersion: z.literal(1),\n /** Always \"skills\" for this package */\n package: z.literal('skills'),\n /** Semver version of the skills package */\n version: z.string().regex(/^\\d+\\.\\d+\\.\\d+/, 'Invalid semver version'),\n /** Engine compatibility */\n engines: z.object({\n 'teamix-evo': z.string().min(1),\n }),\n /** Flat list of skills shipped by this package */\n skills: z.array(SkillEntrySchema),\n});\n\n// ─── UI package (source-injected components, shadcn-style) ────────────────────\n\n/**\n * UI entry types.\n * - component: a React component (e.g. button.tsx)\n * - hook: a React hook (e.g. use-controllable.ts)\n * - util: a utility function (e.g. cn.ts)\n * - block: a higher-level composition (login-form, dashboard-shell). v0.x.\n */\nexport const UiEntryTypeSchema = z.enum([\n 'component',\n 'hook',\n 'util',\n 'block',\n]);\n\n/**\n * Alias keys used to resolve where an entry file lands in the user's project.\n * Each key maps to a path configured in `config.json` `packages.ui.aliases`.\n */\nexport const UiAliasSchema = z.enum(['components', 'hooks', 'utils', 'lib']);\n\n/**\n * Maturity / lifecycle status of a UI entry.\n *\n * Drives consumer trust signal (e.g. shown in `ui list` output, registry-mcp\n * `list_components` tool, autodocs page) so AI / humans know whether to depend\n * on it for production code.\n *\n * - **stable** (default): API committed; breaking changes only via major bump\n * - **experimental** : API may change; do not use in production\n * - **deprecated** : Slated for removal; consumers should migrate to `replacedBy`\n *\n * See ADR 0001-three-layer-alignment and PLAN §12.3 P0-3.\n */\nexport const UiEntryStatusSchema = z.enum([\n 'stable',\n 'experimental',\n 'deprecated',\n]);\nexport type UiEntryStatus = z.infer<typeof UiEntryStatusSchema>;\n\n/**\n * A single file shipped by a UI entry.\n * Multiple files form one logical entry (rare, but supported).\n */\nexport const UiEntryFileSchema = z.object({\n /** Source path relative to the ui package root (e.g. \"src/components/button/button.tsx\") */\n source: z.string().min(1),\n /** Which alias this file resolves under in the consumer project */\n targetAlias: UiAliasSchema,\n /** Filename written under the alias directory (e.g. \"button.tsx\") */\n targetName: z.string().min(1),\n});\n\n/**\n * A single UI entry (component / hook / util / block).\n */\nexport const UiEntrySchema = z.object({\n /** Unique entry identifier within the ui package (e.g. \"button\") */\n id: z\n .string()\n .min(1)\n .regex(\n /^[a-z0-9][a-z0-9-]*$/,\n 'UI entry id must be lowercase letters, digits, hyphens (no leading hyphen)',\n ),\n /** Display name (e.g. \"Button\") */\n name: z.string().min(1),\n /** Entry type */\n type: UiEntryTypeSchema,\n /** One-line description for entry discovery and AI guidance */\n description: z.string().min(1),\n /** Files this entry ships (typically 1) */\n files: z.array(UiEntryFileSchema).min(1),\n /**\n * Optional path to an AI-readable meta document (frontmatter + Markdown).\n * When set, CLI install drops it at `.teamix-evo/design/components/<id>.meta.md`\n * for design's ai-rules to consume.\n */\n meta: z.string().optional(),\n /** Other UI entries this one depends on (e.g. \"button\" depends on \"cn\") */\n registryDependencies: z.array(z.string()).optional(),\n /** npm dependencies required by this entry (name → semver range) */\n dependencies: z.record(z.string(), z.string()).optional(),\n /**\n * How CLI handles this entry on `ui upgrade`.\n * Defaults to `frozen` — user-owned source code, untouched after first install.\n * Upgrade is handled by AI + skill flow (no CLI rewrite). See PLAN §10.9.\n */\n updateStrategy: UpdateStrategySchema.default('frozen'),\n /**\n * Whether the source file should be passed through Handlebars before write.\n * Most entries don't need templating (use import-rewrite transformer instead).\n */\n template: z.boolean().optional(),\n /**\n * Maturity / lifecycle status of this entry. Defaults to `stable`.\n * See {@link UiEntryStatusSchema} for semantics.\n */\n status: UiEntryStatusSchema.default('stable'),\n /**\n * Free-text rationale shown to consumers when `status` is `deprecated`.\n * Should explain why the entry is going away and what replaces it.\n */\n deprecatedReason: z.string().optional(),\n /**\n * If this entry is `deprecated`, the id of the entry that supersedes it.\n * Consumers (and AI) should migrate to `replacedBy` rather than this entry.\n */\n replacedBy: z.string().optional(),\n});\n\n/**\n * UI package manifest schema — top-level manifest of `@teamix-evo/ui`.\n * Like skills, UI is flat (no variants); brand differences are absorbed by\n * design tokens at the `var(--primary)` layer.\n */\nexport const UiPackageManifestSchema = z.object({\n $schema: z.string().optional(),\n schemaVersion: z.literal(1),\n /** Always \"ui\" for this package */\n package: z.literal('ui'),\n /** Semver version of the ui package */\n version: z.string().regex(/^\\d+\\.\\d+\\.\\d+/, 'Invalid semver version'),\n /** Engine compatibility */\n engines: z.object({\n 'teamix-evo': z.string().min(1),\n }),\n /** Flat list of entries shipped by this package */\n entries: z.array(UiEntrySchema),\n});\n","import { z } from 'zod';\nimport { SkillIdeSchema, SkillScopeSchema } from './manifest.js';\n\n/**\n * Tailwind CSS major version that the project consumes.\n * Used by integration tooling (skills) to choose the correct token entry file.\n */\nexport const TailwindVersionSchema = z.enum(['v3', 'v4']);\n\n/**\n * Aliases for ui entry write-back paths in the consumer project.\n * Keys mirror shadcn `components.json` aliases for familiarity.\n */\nexport const UiAliasesSchema = z.object({\n components: z.string().min(1),\n hooks: z.string().min(1),\n utils: z.string().min(1),\n lib: z.string().min(1),\n});\n\n/**\n * Package entry within a project config.\n *\n * Some fields only apply to specific packages:\n * - `tailwind` — design only\n * - `ides` / `scope` — skills only\n * - `aliases` / `iconLibrary` / `tsx` / `rsc` — ui only\n *\n * All package-specific fields are optional at the schema level so a single\n * `PackageEntrySchema` can describe every package family.\n */\nexport const PackageEntrySchema = z.object({\n /** Variant identifier (e.g. \"opentrek\"; use \"_flat\" for skills/ui) */\n variant: z.string().min(1),\n /** Semver version string */\n version: z.string().min(1),\n /** Tailwind CSS version this project uses (only meaningful for design package). */\n tailwind: TailwindVersionSchema.optional(),\n /** IDEs this package was installed for (only meaningful for skills package). */\n ides: z.array(SkillIdeSchema).optional(),\n /** Install scope (only meaningful for skills package). */\n scope: SkillScopeSchema.optional(),\n /** Path aliases for ui entry installation (only meaningful for ui package). */\n aliases: UiAliasesSchema.optional(),\n /**\n * Default icon library declared by the project (only meaningful for ui).\n * Declarative only — does NOT trigger code rewrites; ui entries hardcode imports.\n */\n iconLibrary: z.string().min(1).optional(),\n /** Whether the project uses TSX (true) or JSX (false). ui-specific. */\n tsx: z.boolean().optional(),\n /** Whether to emit React Server Components markers (`\"use client\"`). ui-specific. */\n rsc: z.boolean().optional(),\n});\n\n/**\n * Project configuration schema — teamix-evo config.json at project root.\n */\nexport const ProjectConfigSchema = z.object({\n $schema: z.string().optional(),\n schemaVersion: z.literal(1),\n /** IDE identifier */\n ide: z.string().min(1),\n /** Installed packages keyed by package name */\n packages: z.record(z.string(), PackageEntrySchema),\n});\n","import { z } from 'zod';\nimport { SkillIdeSchema, SkillScopeSchema } from './manifest.js';\n\n/**\n * An installed resource entry — tracks individual resource installation state.\n *\n * For type=\"skill\" resources, the same logical skill may produce multiple installed\n * entries (one per ide × scope combination); the optional `ide`/`scope` fields\n * disambiguate them.\n */\nexport const InstalledResourceSchema = z.object({\n /** Resource identifier matching the variant manifest */\n id: z.string().min(1),\n /** Target path where the resource was installed (absolute or project-relative) */\n target: z.string().min(1),\n /** Content hash for change detection (e.g. \"sha256:...\") */\n hash: z.string().min(1),\n /** Update strategy that was applied */\n strategy: z.enum(['frozen', 'regenerable', 'managed']),\n /** IDE this resource was installed for (skill resources only) */\n ide: SkillIdeSchema.optional(),\n /** Install scope (skill resources only) */\n scope: SkillScopeSchema.optional(),\n});\n\n/**\n * An installed package entry — tracks a single package installation.\n */\nexport const InstalledPackageSchema = z.object({\n /** Full package name (e.g. \"@teamix-evo/design\") */\n package: z.string().min(1),\n /** Variant identifier (use \"_flat\" for non-variant packages such as skills) */\n variant: z.string().min(1),\n /** Installed version */\n version: z.string().min(1),\n /** ISO 8601 timestamp of installation */\n installedAt: z.string().min(1),\n /** List of installed resources */\n resources: z.array(InstalledResourceSchema),\n});\n\n/**\n * Installed manifest schema — tracks all installed packages in a project.\n * Stored at `.teamix-evo/manifest.json`.\n */\nexport const InstalledManifestSchema = z.object({\n schemaVersion: z.literal(1),\n /** List of installed packages */\n installed: z.array(InstalledPackageSchema),\n});\n","import * as fs from 'node:fs/promises';\nimport * as path from 'node:path';\nimport {\n validateManifest,\n validateSkillsPackage,\n validateUiPackage,\n} from './validator.js';\nimport type {\n VariantManifest,\n SkillsPackageManifest,\n UiPackageManifest,\n} from './types.js';\n\n/**\n * Load and validate a variant manifest from a package directory.\n *\n * Reads `manifest.json` from the given directory, parses it as JSON,\n * and validates it against the VariantManifest schema.\n *\n * @param packageDir - Absolute or relative path to the variant package directory\n * @returns The validated VariantManifest\n * @throws Error if the file cannot be read or the manifest is invalid\n */\nexport async function loadVariantManifest(\n packageDir: string,\n): Promise<VariantManifest> {\n const manifestPath = path.join(packageDir, 'manifest.json');\n\n let raw: string;\n try {\n raw = await fs.readFile(manifestPath, 'utf-8');\n } catch (err) {\n const code = (err as NodeJS.ErrnoException).code;\n if (code === 'ENOENT') {\n throw new Error(`Manifest not found: ${manifestPath}`);\n }\n throw new Error(\n `Failed to read manifest at ${manifestPath}: ${(err as Error).message}`,\n );\n }\n\n let data: unknown;\n try {\n data = JSON.parse(raw);\n } catch {\n throw new Error(`Invalid JSON in manifest at ${manifestPath}`);\n }\n\n const result = validateManifest(data);\n if (!result.success) {\n throw new Error(`${result.error}\\n File: ${manifestPath}`);\n }\n\n return result.data;\n}\n\n/**\n * Load and validate the top-level manifest of a skills package.\n *\n * Reads `manifest.json` from the given directory and validates it against\n * the SkillsPackageManifest schema (flat list of skills, no variants).\n *\n * @param packageDir - Absolute or relative path to the skills package directory\n * @returns The validated SkillsPackageManifest\n * @throws Error if the file cannot be read or the manifest is invalid\n */\nexport async function loadSkillsPackageManifest(\n packageDir: string,\n): Promise<SkillsPackageManifest> {\n const manifestPath = path.join(packageDir, 'manifest.json');\n\n let raw: string;\n try {\n raw = await fs.readFile(manifestPath, 'utf-8');\n } catch (err) {\n const code = (err as NodeJS.ErrnoException).code;\n if (code === 'ENOENT') {\n throw new Error(`Skills manifest not found: ${manifestPath}`);\n }\n throw new Error(\n `Failed to read skills manifest at ${manifestPath}: ${\n (err as Error).message\n }`,\n );\n }\n\n let data: unknown;\n try {\n data = JSON.parse(raw);\n } catch {\n throw new Error(`Invalid JSON in skills manifest at ${manifestPath}`);\n }\n\n const result = validateSkillsPackage(data);\n if (!result.success) {\n throw new Error(`${result.error}\\n File: ${manifestPath}`);\n }\n\n return result.data;\n}\n\n/**\n * Load and validate the top-level manifest of a UI package.\n *\n * Reads `manifest.json` from the given directory and validates it against\n * the UiPackageManifest schema (flat list of entries, no variants).\n * Also performs registryDependencies graph validation (existence + no cycles).\n *\n * @param packageDir - Absolute or relative path to the ui package directory\n * @returns The validated UiPackageManifest\n * @throws Error if the file cannot be read, the manifest is invalid, or the dep graph is broken\n */\nexport async function loadUiPackageManifest(\n packageDir: string,\n): Promise<UiPackageManifest> {\n const manifestPath = path.join(packageDir, 'manifest.json');\n\n let raw: string;\n try {\n raw = await fs.readFile(manifestPath, 'utf-8');\n } catch (err) {\n const code = (err as NodeJS.ErrnoException).code;\n if (code === 'ENOENT') {\n throw new Error(`UI manifest not found: ${manifestPath}`);\n }\n throw new Error(\n `Failed to read ui manifest at ${manifestPath}: ${(err as Error).message}`,\n );\n }\n\n let data: unknown;\n try {\n data = JSON.parse(raw);\n } catch {\n throw new Error(`Invalid JSON in ui manifest at ${manifestPath}`);\n }\n\n const result = validateUiPackage(data);\n if (!result.success) {\n throw new Error(`${result.error}\\n File: ${manifestPath}`);\n }\n\n return result.data;\n}\n","import { ZodError } from 'zod';\nimport {\n VariantManifestSchema,\n SkillsPackageManifestSchema,\n UiPackageManifestSchema,\n} from './schema/manifest.js';\nimport { ProjectConfigSchema } from './schema/config.js';\nimport { InstalledManifestSchema } from './schema/installed.js';\nimport type {\n VariantManifest,\n SkillsPackageManifest,\n UiPackageManifest,\n UiEntry,\n ProjectConfig,\n InstalledManifest,\n Result,\n} from './types.js';\n\n/**\n * Format a ZodError into a human-readable error message.\n */\nfunction formatZodError(error: ZodError): string {\n return error.issues\n .map((issue) => {\n const path = issue.path.length > 0 ? issue.path.join('.') : '(root)';\n return ` - ${path}: ${issue.message}`;\n })\n .join('\\n');\n}\n\n/**\n * Validate unknown data against the VariantManifest schema.\n * Returns a discriminated Result with either the parsed data or a friendly error message.\n */\nexport function validateManifest(data: unknown): Result<VariantManifest> {\n const result = VariantManifestSchema.safeParse(data);\n if (result.success) {\n return { success: true, data: result.data };\n }\n return {\n success: false,\n error: `Invalid variant manifest:\\n${formatZodError(result.error)}`,\n };\n}\n\n/**\n * Validate unknown data against the ProjectConfig schema.\n */\nexport function validateConfig(data: unknown): Result<ProjectConfig> {\n const result = ProjectConfigSchema.safeParse(data);\n if (result.success) {\n return { success: true, data: result.data };\n }\n return {\n success: false,\n error: `Invalid project config:\\n${formatZodError(result.error)}`,\n };\n}\n\n/**\n * Validate unknown data against the InstalledManifest schema.\n */\nexport function validateInstalled(data: unknown): Result<InstalledManifest> {\n const result = InstalledManifestSchema.safeParse(data);\n if (result.success) {\n return { success: true, data: result.data };\n }\n return {\n success: false,\n error: `Invalid installed manifest:\\n${formatZodError(result.error)}`,\n };\n}\n\n/**\n * Validate unknown data against the SkillsPackageManifest schema.\n */\nexport function validateSkillsPackage(\n data: unknown,\n): Result<SkillsPackageManifest> {\n const result = SkillsPackageManifestSchema.safeParse(data);\n if (result.success) {\n return { success: true, data: result.data };\n }\n return {\n success: false,\n error: `Invalid skills package manifest:\\n${formatZodError(result.error)}`,\n };\n}\n\n/**\n * Validate unknown data against the UiPackageManifest schema, then verify the\n * registryDependencies graph: every reference resolves and there are no cycles.\n */\nexport function validateUiPackage(data: unknown): Result<UiPackageManifest> {\n const parsed = UiPackageManifestSchema.safeParse(data);\n if (!parsed.success) {\n return {\n success: false,\n error: `Invalid ui package manifest:\\n${formatZodError(parsed.error)}`,\n };\n }\n\n const graphIssues = validateUiDependencyGraph(parsed.data.entries);\n if (graphIssues.length > 0) {\n return {\n success: false,\n error: `Invalid ui package manifest dependency graph:\\n${graphIssues\n .map((i) => ` - ${i}`)\n .join('\\n')}`,\n };\n }\n\n return { success: true, data: parsed.data };\n}\n\n/**\n * Validate the registryDependencies graph among ui entries.\n * Returns a list of issue strings (empty when the graph is sound).\n *\n * Issues detected:\n * - Duplicate entry id\n * - Reference to an unknown entry id\n * - Cyclic dependency\n */\nexport function validateUiDependencyGraph(entries: UiEntry[]): string[] {\n const issues: string[] = [];\n const idToEntry = new Map<string, UiEntry>();\n\n for (const entry of entries) {\n if (idToEntry.has(entry.id)) {\n issues.push(`duplicate entry id: \"${entry.id}\"`);\n } else {\n idToEntry.set(entry.id, entry);\n }\n }\n\n for (const entry of entries) {\n const deps = entry.registryDependencies ?? [];\n for (const dep of deps) {\n if (!idToEntry.has(dep)) {\n issues.push(\n `entry \"${entry.id}\" depends on unknown entry \"${dep}\"`,\n );\n }\n }\n }\n\n // Cycle detection via DFS with three colors (white/gray/black).\n const WHITE = 0;\n const GRAY = 1;\n const BLACK = 2;\n const color = new Map<string, number>();\n for (const id of idToEntry.keys()) color.set(id, WHITE);\n\n const cycles: string[][] = [];\n\n function dfs(id: string, path: string[]): void {\n color.set(id, GRAY);\n path.push(id);\n const entry = idToEntry.get(id);\n const deps = entry?.registryDependencies ?? [];\n for (const dep of deps) {\n if (!idToEntry.has(dep)) continue; // already reported above\n const c = color.get(dep);\n if (c === GRAY) {\n const startIdx = path.indexOf(dep);\n cycles.push([...path.slice(startIdx), dep]);\n } else if (c === WHITE) {\n dfs(dep, path);\n }\n }\n path.pop();\n color.set(id, BLACK);\n }\n\n for (const id of idToEntry.keys()) {\n if (color.get(id) === WHITE) dfs(id, []);\n }\n\n for (const cycle of cycles) {\n issues.push(`cyclic registryDependencies: ${cycle.join(' → ')}`);\n }\n\n return issues;\n}\n\n/**\n * Topologically sort a subset of ui entries so that dependencies come before\n * dependents. Used by `ui add` to determine install order.\n *\n * @param entries full list of entries (the package manifest's `entries`)\n * @param requested ids the user explicitly asked to install\n * @returns ordered list of entry ids (includes transitive deps, dedup'd)\n * @throws Error if a requested id or transitive dep is missing or graph has cycles\n */\nexport function resolveUiEntryOrder(\n entries: UiEntry[],\n requested: string[],\n): string[] {\n const idToEntry = new Map(entries.map((e) => [e.id, e]));\n\n for (const id of requested) {\n if (!idToEntry.has(id)) {\n throw new Error(`Unknown ui entry: \"${id}\"`);\n }\n }\n\n // Pre-flight cycle check on the full graph.\n const graphIssues = validateUiDependencyGraph(entries);\n if (graphIssues.length > 0) {\n throw new Error(\n `UI dependency graph has issues:\\n${graphIssues\n .map((i) => ` - ${i}`)\n .join('\\n')}`,\n );\n }\n\n const visited = new Set<string>();\n const order: string[] = [];\n\n function visit(id: string): void {\n if (visited.has(id)) return;\n visited.add(id);\n const entry = idToEntry.get(id);\n const deps = entry?.registryDependencies ?? [];\n for (const dep of deps) visit(dep);\n order.push(id);\n }\n\n for (const id of requested) visit(id);\n\n return order;\n}\n","import type { ManagedRegion } from './types.js';\n\n/**\n * Regex pattern for matching managed region markers.\n * Captures the region id and the content between start/end markers.\n */\nconst REGION_PATTERN =\n /<!-- teamix-evo:managed:start id=\"([^\"]+)\" -->([\\s\\S]*?)<!-- teamix-evo:managed:end id=\"\\1\" -->/g;\n\n/**\n * Regex for a start marker without a matching end marker — used for error detection.\n */\nconst START_MARKER_PATTERN = /<!-- teamix-evo:managed:start id=\"([^\"]+)\" -->/g;\n\nconst END_MARKER_PATTERN = /<!-- teamix-evo:managed:end id=\"([^\"]+)\" -->/g;\n\n/**\n * Parse all managed regions from document content.\n *\n * @param content - The full document content\n * @returns Array of parsed ManagedRegion objects\n * @throws Error if there are unmatched start/end markers\n */\nexport function parseManagedRegions(content: string): ManagedRegion[] {\n // First, check for unmatched markers\n const startIds = new Set<string>();\n const endIds = new Set<string>();\n const startCounts = new Map<string, number>();\n\n let match: RegExpExecArray | null;\n\n const startRe = new RegExp(START_MARKER_PATTERN.source, 'g');\n while ((match = startRe.exec(content)) !== null) {\n const id = match[1];\n startIds.add(id);\n startCounts.set(id, (startCounts.get(id) ?? 0) + 1);\n }\n\n const endRe = new RegExp(END_MARKER_PATTERN.source, 'g');\n while ((match = endRe.exec(content)) !== null) {\n endIds.add(match[1]);\n }\n\n // Check for duplicate start markers\n for (const [id, count] of startCounts) {\n if (count > 1) {\n throw new Error(\n `Duplicate managed region: found ${count} start markers for \"${id}\". Each id must be unique within a file.`,\n );\n }\n }\n\n // Check for start markers without matching end markers\n for (const id of startIds) {\n if (!endIds.has(id)) {\n throw new Error(\n `Unmatched managed region: found start marker for \"${id}\" but no matching end marker`,\n );\n }\n }\n\n // Check for end markers without matching start markers\n for (const id of endIds) {\n if (!startIds.has(id)) {\n throw new Error(\n `Unmatched managed region: found end marker for \"${id}\" but no matching start marker`,\n );\n }\n }\n\n // Now parse matched regions\n const regions: ManagedRegion[] = [];\n const regionRe = new RegExp(REGION_PATTERN.source, 'g');\n\n while ((match = regionRe.exec(content)) !== null) {\n const id = match[1];\n const regionContent = match[2];\n regions.push({\n id,\n startMarker: `<!-- teamix-evo:managed:start id=\"${id}\" -->`,\n endMarker: `<!-- teamix-evo:managed:end id=\"${id}\" -->`,\n content: regionContent,\n });\n }\n\n return regions;\n}\n\n/**\n * Replace the content of a specific managed region by id.\n * Content outside managed regions is preserved.\n *\n * @param content - The full document content\n * @param id - The region id to replace\n * @param newContent - The new content for the region\n * @returns The updated document content\n * @throws Error if the region id is not found\n */\nexport function replaceManagedRegion(\n content: string,\n id: string,\n newContent: string,\n): string {\n const startMarker = `<!-- teamix-evo:managed:start id=\"${id}\" -->`;\n const endMarker = `<!-- teamix-evo:managed:end id=\"${id}\" -->`;\n\n const pattern = new RegExp(\n `<!-- teamix-evo:managed:start id=\"${escapeRegExp(\n id,\n )}\" -->[\\\\s\\\\S]*?<!-- teamix-evo:managed:end id=\"${escapeRegExp(id)}\" -->`,\n 'g',\n );\n\n // First check if the region actually exists\n if (!pattern.test(content)) {\n throw new Error(`Managed region \"${id}\" not found in content`);\n }\n\n // Reset lastIndex after test() with global flag\n pattern.lastIndex = 0;\n\n return content.replace(\n pattern,\n `${startMarker}\\n${newContent}\\n${endMarker}`,\n );\n}\n\n/**\n * Check whether a managed region with the given id exists in the content.\n *\n * @param content - The full document content\n * @param id - The region id to check\n * @returns true if the region exists\n */\nexport function hasManagedRegion(content: string, id: string): boolean {\n const pattern = new RegExp(\n `<!-- teamix-evo:managed:start id=\"${escapeRegExp(\n id,\n )}\" -->[\\\\s\\\\S]*?<!-- teamix-evo:managed:end id=\"${escapeRegExp(id)}\" -->`,\n );\n return pattern.test(content);\n}\n\n/**\n * Escape special regex characters in a string.\n */\nfunction escapeRegExp(str: string): string {\n return str.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n}\n","import type { UpdateStrategy } from \"./types.js\";\n\n/**\n * Determine whether a resource should be updated based on its strategy\n * and whether it already exists.\n *\n * @param strategy - The update strategy for the resource\n * @param resourceExists - Whether the resource file already exists\n * @returns true if the resource should be updated/created\n */\nexport function shouldUpdate(\n strategy: UpdateStrategy,\n resourceExists: boolean,\n): boolean {\n switch (strategy) {\n case \"frozen\":\n // Only install if it doesn't exist yet\n return !resourceExists;\n case \"regenerable\":\n // Always overwrite\n return true;\n case \"managed\":\n // Always update (managed regions only)\n return true;\n default:\n return false;\n }\n}\n\n/** Possible actions returned by getUpdateAction */\nexport type UpdateAction = \"skip\" | \"overwrite\" | \"managed-update\";\n\nexport interface UpdateActionOptions {\n /** Whether the resource file already exists */\n exists: boolean;\n /** Hash of the new content to be written */\n hash?: string;\n /** Hash of the currently installed content */\n currentHash?: string;\n}\n\n/**\n * Determine the specific update action to take for a resource.\n *\n * @param strategy - The update strategy for the resource\n * @param options - Context about the resource's current state\n * @returns The action to perform\n */\nexport function getUpdateAction(\n strategy: UpdateStrategy,\n options: UpdateActionOptions,\n): UpdateAction {\n switch (strategy) {\n case \"frozen\":\n if (!options.exists) {\n // First-time install\n return \"overwrite\";\n }\n // File exists, never modify\n return \"skip\";\n\n case \"regenerable\":\n if (\n options.exists &&\n options.hash &&\n options.currentHash &&\n options.hash === options.currentHash\n ) {\n // Content unchanged, skip\n return \"skip\";\n }\n return \"overwrite\";\n\n case \"managed\":\n if (!options.exists) {\n // First-time install — write the whole file\n return \"overwrite\";\n }\n return \"managed-update\";\n\n default:\n return \"skip\";\n }\n}\n"],"mappings":"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","names":["z","z","z","z","path"]}