teamix-evo 0.3.1 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,11 +1,10 @@
1
- // src/core/design-init.ts
1
+ // src/core/tokens-init.ts
2
2
  import * as path9 from "path";
3
3
  import * as fs6 from "fs/promises";
4
4
  import { createRequire as createRequire2 } from "module";
5
5
  import {
6
- loadDesignPack,
7
- loadDesignPackageManifest,
8
- mergeDefaultAndVariant
6
+ loadTokensPackageManifest,
7
+ getVariantEntry
9
8
  } from "@teamix-evo/registry";
10
9
 
11
10
  // src/utils/fs.ts
@@ -90,71 +89,22 @@ function computeHash(content) {
90
89
  return `sha256:${hash}`;
91
90
  }
92
91
 
93
- // src/core/design-pack-classify.ts
94
- import * as path2 from "path";
95
- var TEAMIX_DIR = ".teamix-evo/design";
96
- var TOKENS_DIR = ".teamix-evo/tokens";
97
- var TOKENS_PACK_PREFIX = "foundations/tokens/";
98
- var ROOT_MANAGED_FILES = {
99
- "DESIGN.md": { target: "DESIGN.md", managedRegions: ["core"] },
100
- "AGENTS.md": { target: "AGENTS.md", managedRegions: ["teamix-evo"] },
101
- "CLAUDE.md": { target: "CLAUDE.md", managedRegions: ["teamix-evo"] }
102
- };
103
- var FROZEN_FILES = /* @__PURE__ */ new Set([
104
- "foundations/tokens/tokens.overrides.css"
105
- ]);
106
- function classifyPackFile(relPath) {
107
- if (path2.basename(relPath) === "README.md") {
108
- return null;
109
- }
110
- const rootManaged = ROOT_MANAGED_FILES[relPath];
111
- if (rootManaged) {
112
- return {
113
- target: rootManaged.target,
114
- strategy: "managed",
115
- managedRegions: rootManaged.managedRegions,
116
- isFrozen: false
117
- };
118
- }
119
- if (relPath.startsWith(TOKENS_PACK_PREFIX)) {
120
- const rel2 = relPath.slice(TOKENS_PACK_PREFIX.length);
121
- const target = path2.posix.join(TOKENS_DIR, rel2);
122
- if (FROZEN_FILES.has(relPath)) {
123
- return { target, strategy: "frozen", isFrozen: true };
124
- }
125
- return { target, strategy: "regenerable", isFrozen: false };
126
- }
127
- if (FROZEN_FILES.has(relPath)) {
128
- return {
129
- target: path2.posix.join(TEAMIX_DIR, relPath),
130
- strategy: "frozen",
131
- isFrozen: true
132
- };
133
- }
134
- return {
135
- target: path2.posix.join(TEAMIX_DIR, relPath),
136
- strategy: "regenerable",
137
- isFrozen: false
138
- };
139
- }
140
-
141
92
  // src/core/state.ts
142
- import * as path3 from "path";
93
+ import * as path2 from "path";
143
94
  import {
144
95
  validateConfig,
145
96
  validateInstalled,
146
97
  validateSkillsLock,
147
- DesignPackLockSchema
98
+ TokensPackLockSchema
148
99
  } from "@teamix-evo/registry";
149
- var TEAMIX_DIR2 = ".teamix-evo";
100
+ var TEAMIX_DIR = ".teamix-evo";
150
101
  var CONFIG_FILE = "config.json";
151
102
  var MANIFEST_FILE = "manifest.json";
152
- var DESIGN_DIR = "design";
153
- var DESIGN_LOCK_FILE = "pack.lock.json";
103
+ var TOKENS_LOCK_FILE = "tokens-lock.json";
154
104
  var SKILLS_DIR = "skills";
155
105
  var SKILLS_LOCK_FILE = "manifest.lock.json";
156
106
  function getTeamixDir(projectRoot) {
157
- return path3.join(projectRoot, TEAMIX_DIR2);
107
+ return path2.join(projectRoot, TEAMIX_DIR);
158
108
  }
159
109
  async function ensureTeamixDir(projectRoot) {
160
110
  const dir = getTeamixDir(projectRoot);
@@ -162,84 +112,85 @@ async function ensureTeamixDir(projectRoot) {
162
112
  return dir;
163
113
  }
164
114
  async function readProjectConfig(projectRoot) {
165
- const configPath = path3.join(projectRoot, TEAMIX_DIR2, CONFIG_FILE);
115
+ const configPath = path2.join(projectRoot, TEAMIX_DIR, CONFIG_FILE);
166
116
  const raw = await readFileOrNull(configPath);
167
117
  if (raw === null) return null;
118
+ let data;
168
119
  try {
169
- const data = JSON.parse(raw);
170
- const result = validateConfig(data);
171
- if (!result.success) {
172
- logger.warn(`Invalid config.json: ${result.error}`);
173
- return null;
174
- }
175
- return result.data;
120
+ data = JSON.parse(raw);
176
121
  } catch (err) {
177
- logger.warn(`Failed to parse config.json: ${err.message}`);
178
- return null;
122
+ throw new Error(
123
+ `Corrupted config.json (${err.message}). Fix the JSON manually or remove the file to start fresh; refusing to clobber prior config.`
124
+ );
179
125
  }
126
+ const result = validateConfig(data);
127
+ if (!result.success) {
128
+ throw new Error(
129
+ `Invalid config.json schema: ${result.error}. Fix the file manually or remove it to start fresh.`
130
+ );
131
+ }
132
+ return result.data;
180
133
  }
181
134
  async function writeProjectConfig(projectRoot, config) {
182
- const configPath = path3.join(projectRoot, TEAMIX_DIR2, CONFIG_FILE);
135
+ const configPath = path2.join(projectRoot, TEAMIX_DIR, CONFIG_FILE);
183
136
  await writeFileSafe(configPath, JSON.stringify(config, null, 2) + "\n");
184
137
  logger.debug(`Wrote config \u2192 ${configPath}`);
185
138
  }
186
139
  async function readInstalledManifest(projectRoot) {
187
- const manifestPath = path3.join(projectRoot, TEAMIX_DIR2, MANIFEST_FILE);
140
+ const manifestPath = path2.join(projectRoot, TEAMIX_DIR, MANIFEST_FILE);
188
141
  const raw = await readFileOrNull(manifestPath);
189
142
  if (raw === null) return null;
143
+ let data;
190
144
  try {
191
- const data = JSON.parse(raw);
192
- const result = validateInstalled(data);
193
- if (!result.success) {
194
- logger.warn(`Invalid manifest.json: ${result.error}`);
195
- return null;
196
- }
197
- return result.data;
145
+ data = JSON.parse(raw);
198
146
  } catch (err) {
199
- logger.warn(`Failed to parse manifest.json: ${err.message}`);
200
- return null;
147
+ throw new Error(
148
+ `Corrupted manifest.json (${err.message}). Fix the JSON manually or remove the file to start fresh; refusing to clobber prior install records.`
149
+ );
201
150
  }
151
+ const result = validateInstalled(data);
152
+ if (!result.success) {
153
+ throw new Error(
154
+ `Invalid manifest.json schema: ${result.error}. Fix the file manually or remove it to start fresh.`
155
+ );
156
+ }
157
+ return result.data;
202
158
  }
203
159
  async function writeInstalledManifest(projectRoot, manifest) {
204
- const manifestPath = path3.join(projectRoot, TEAMIX_DIR2, MANIFEST_FILE);
160
+ const manifestPath = path2.join(projectRoot, TEAMIX_DIR, MANIFEST_FILE);
205
161
  await writeFileSafe(manifestPath, JSON.stringify(manifest, null, 2) + "\n");
206
162
  logger.debug(`Wrote manifest \u2192 ${manifestPath}`);
207
163
  }
208
- async function readDesignPackLock(projectRoot) {
209
- const lockPath = path3.join(
210
- projectRoot,
211
- TEAMIX_DIR2,
212
- DESIGN_DIR,
213
- DESIGN_LOCK_FILE
214
- );
164
+ async function readTokensLock(projectRoot) {
165
+ const lockPath = path2.join(projectRoot, TEAMIX_DIR, TOKENS_LOCK_FILE);
215
166
  const raw = await readFileOrNull(lockPath);
216
167
  if (raw === null) return null;
217
168
  try {
218
- const parsed = DesignPackLockSchema.safeParse(JSON.parse(raw));
169
+ const parsed = TokensPackLockSchema.safeParse(JSON.parse(raw));
219
170
  if (!parsed.success) {
220
- logger.warn(`Invalid design pack.lock.json: ${parsed.error.message}`);
171
+ logger.warn(`Invalid tokens-lock.json: ${parsed.error.message}`);
221
172
  return null;
222
173
  }
223
174
  return parsed.data;
224
175
  } catch (err) {
225
176
  logger.warn(
226
- `Failed to parse design pack.lock.json: ${err.message}`
177
+ `Failed to parse tokens-lock.json: ${err.message}`
227
178
  );
228
179
  return null;
229
180
  }
230
181
  }
231
- async function readDesignVariant(projectRoot) {
232
- const lock = await readDesignPackLock(projectRoot);
182
+ async function readTokensVariant(projectRoot) {
183
+ const lock = await readTokensLock(projectRoot);
233
184
  return lock?.variant.name ?? null;
234
185
  }
235
186
  function getSkillsSourceDir(projectRoot, skillName) {
236
- const base = path3.join(projectRoot, TEAMIX_DIR2, SKILLS_DIR);
237
- return skillName ? path3.join(base, skillName) : base;
187
+ const base = path2.join(projectRoot, TEAMIX_DIR, SKILLS_DIR);
188
+ return skillName ? path2.join(base, skillName) : base;
238
189
  }
239
190
  async function readSkillsLock(projectRoot) {
240
- const lockPath = path3.join(
191
+ const lockPath = path2.join(
241
192
  projectRoot,
242
- TEAMIX_DIR2,
193
+ TEAMIX_DIR,
243
194
  SKILLS_DIR,
244
195
  SKILLS_LOCK_FILE
245
196
  );
@@ -261,9 +212,9 @@ async function readSkillsLock(projectRoot) {
261
212
  }
262
213
  }
263
214
  async function writeSkillsLock(projectRoot, lock) {
264
- const lockPath = path3.join(
215
+ const lockPath = path2.join(
265
216
  projectRoot,
266
- TEAMIX_DIR2,
217
+ TEAMIX_DIR,
267
218
  SKILLS_DIR,
268
219
  SKILLS_LOCK_FILE
269
220
  );
@@ -272,21 +223,21 @@ async function writeSkillsLock(projectRoot, lock) {
272
223
  }
273
224
 
274
225
  // src/core/skills-client.ts
275
- import * as path4 from "path";
226
+ import * as path3 from "path";
276
227
  import * as fs2 from "fs/promises";
277
228
  import { createRequire } from "module";
278
229
  import { loadSkillsPackageManifest } from "@teamix-evo/registry";
279
230
  var require2 = createRequire(import.meta.url);
280
231
  function resolvePackageRoot(packageName) {
281
232
  const pkgJsonPath = require2.resolve(`${packageName}/package.json`);
282
- return path4.dirname(pkgJsonPath);
233
+ return path3.dirname(pkgJsonPath);
283
234
  }
284
235
  async function loadSkillsData(packageName) {
285
236
  const packageRoot = resolvePackageRoot(packageName);
286
237
  logger.debug(`Resolved skills package root: ${packageRoot}`);
287
238
  const manifest = await loadSkillsPackageManifest(packageRoot);
288
239
  let data = {};
289
- const dataPath = path4.join(packageRoot, "_data.json");
240
+ const dataPath = path3.join(packageRoot, "_data.json");
290
241
  try {
291
242
  const raw = await fs2.readFile(dataPath, "utf-8");
292
243
  data = JSON.parse(raw);
@@ -300,13 +251,16 @@ async function loadSkillsData(packageName) {
300
251
  }
301
252
 
302
253
  // src/core/skills-installer.ts
303
- import * as path8 from "path";
254
+ import * as path7 from "path";
304
255
  import * as fs5 from "fs/promises";
305
- import { replaceManagedRegion } from "@teamix-evo/registry";
256
+ import {
257
+ replaceManagedRegion,
258
+ hasManagedRegion
259
+ } from "@teamix-evo/registry";
306
260
 
307
261
  // src/ide/QoderAdapter.ts
308
262
  import * as os from "os";
309
- import * as path5 from "path";
263
+ import * as path4 from "path";
310
264
  var QoderAdapter = class {
311
265
  kind = "qoder";
312
266
  name = "qoder";
@@ -317,14 +271,14 @@ var QoderAdapter = class {
317
271
  return true;
318
272
  }
319
273
  getSkillTargetDir(skillName, scope, projectRoot) {
320
- const base = scope === "global" ? path5.join(os.homedir(), ".qoder") : path5.join(projectRoot ?? this.getProjectRoot(), ".qoder");
321
- return path5.join(base, "skills", skillName);
274
+ const base = scope === "global" ? path4.join(os.homedir(), ".qoder") : path4.join(projectRoot ?? this.getProjectRoot(), ".qoder");
275
+ return path4.join(base, "skills", skillName);
322
276
  }
323
277
  };
324
278
 
325
279
  // src/ide/ClaudeAdapter.ts
326
280
  import * as os2 from "os";
327
- import * as path6 from "path";
281
+ import * as path5 from "path";
328
282
  var ClaudeAdapter = class {
329
283
  kind = "claude";
330
284
  name = "claude";
@@ -335,8 +289,8 @@ var ClaudeAdapter = class {
335
289
  return Boolean(process.env.CLAUDECODE);
336
290
  }
337
291
  getSkillTargetDir(skillName, scope, projectRoot) {
338
- const base = scope === "global" ? path6.join(os2.homedir(), ".claude") : path6.join(projectRoot ?? this.getProjectRoot(), ".claude");
339
- return path6.join(base, "skills", skillName);
292
+ const base = scope === "global" ? path5.join(os2.homedir(), ".claude") : path5.join(projectRoot ?? this.getProjectRoot(), ".claude");
293
+ return path5.join(base, "skills", skillName);
340
294
  }
341
295
  };
342
296
 
@@ -383,19 +337,19 @@ async function loadTemplateFile(filePath) {
383
337
  }
384
338
 
385
339
  // src/utils/path.ts
386
- import * as path7 from "path";
340
+ import * as path6 from "path";
387
341
  import * as fs4 from "fs/promises";
388
342
  function resolveSourcePath(source, variantDir, packageRoot) {
389
343
  if (source.startsWith("_template/")) {
390
- return path7.join(packageRoot, source);
344
+ return path6.join(packageRoot, source);
391
345
  }
392
- return path7.join(variantDir, source);
346
+ return path6.join(variantDir, source);
393
347
  }
394
348
  async function walkDir(dir) {
395
349
  const files = [];
396
350
  const entries = await fs4.readdir(dir, { withFileTypes: true });
397
351
  for (const entry of entries) {
398
- const fullPath = path7.join(dir, entry.name);
352
+ const fullPath = path6.join(dir, entry.name);
399
353
  if (entry.isDirectory()) {
400
354
  files.push(...await walkDir(fullPath));
401
355
  } else if (entry.isFile()) {
@@ -438,12 +392,12 @@ async function installSkills(options) {
438
392
  }
439
393
  async function writeSkillSource(skill, options) {
440
394
  const { data, packageRoot, projectRoot } = options;
441
- const sourceAbs = path8.resolve(packageRoot, skill.source);
395
+ const sourceAbs = path7.resolve(packageRoot, skill.source);
442
396
  const targetDir = getSkillsSourceDir(projectRoot, skill.name);
443
397
  const stat2 = await fs5.stat(sourceAbs);
444
398
  const records = [];
445
399
  if (stat2.isFile()) {
446
- const targetFile = path8.join(targetDir, "SKILL.md");
400
+ const targetFile = path7.join(targetDir, "SKILL.md");
447
401
  const content = await renderSkillContent(sourceAbs, skill, data);
448
402
  await writeFileSafe(targetFile, content);
449
403
  records.push(makeSourceRecord(skill, targetFile, content));
@@ -453,14 +407,14 @@ async function writeSkillSource(skill, options) {
453
407
  await ensureDir(targetDir);
454
408
  const entries = await walkDir(sourceAbs);
455
409
  for (const entry of entries) {
456
- const rel2 = path8.relative(sourceAbs, entry);
457
- let targetFile = path8.join(targetDir, rel2);
410
+ const rel2 = path7.relative(sourceAbs, entry);
411
+ let targetFile = path7.join(targetDir, rel2);
458
412
  if (skill.template && targetFile.endsWith(".hbs")) {
459
413
  targetFile = targetFile.slice(0, -4);
460
414
  }
461
415
  const content = skill.template && entry.endsWith(".hbs") ? renderTemplate(await loadTemplateFile(entry), { ...data, skill }) : await fs5.readFile(entry, "utf-8");
462
416
  await writeFileSafe(targetFile, content);
463
- const relWritten = path8.relative(targetDir, targetFile);
417
+ const relWritten = path7.relative(targetDir, targetFile);
464
418
  records.push(makeSourceRecord(skill, targetFile, content, relWritten));
465
419
  logger.debug(` Wrote source: ${targetFile}`);
466
420
  }
@@ -474,15 +428,66 @@ async function mirrorSkillToIde(skill, ide, scope, projectRoot) {
474
428
  const sourceFiles = await walkDir(sourceDir);
475
429
  await ensureDir(targetDir);
476
430
  for (const src of sourceFiles) {
477
- const rel2 = path8.relative(sourceDir, src);
478
- const targetFile = path8.join(targetDir, rel2);
479
- const content = await fs5.readFile(src, "utf-8");
480
- await writeFileSafe(targetFile, content);
481
- records.push(makeMirrorRecord(skill, targetFile, content, ide, scope, rel2));
431
+ const rel2 = path7.relative(sourceDir, src);
432
+ const targetFile = path7.join(targetDir, rel2);
433
+ const sourceContent = await fs5.readFile(src, "utf-8");
434
+ const writtenContent = await writeMirrorContent(
435
+ targetFile,
436
+ sourceContent,
437
+ skill.managedRegions,
438
+ src
439
+ );
440
+ records.push(
441
+ makeMirrorRecord(skill, targetFile, writtenContent, ide, scope, rel2)
442
+ );
482
443
  logger.debug(` Mirrored ${ide}:${scope}: ${targetFile}`);
483
444
  }
484
445
  return records;
485
446
  }
447
+ async function writeMirrorContent(targetFile, sourceContent, managedRegions, sourceFile) {
448
+ const existing = await readFileOrNull(targetFile);
449
+ if (existing === null) {
450
+ await writeFileSafe(targetFile, sourceContent);
451
+ return sourceContent;
452
+ }
453
+ const regions = managedRegions ?? [];
454
+ const matchedRegions = regions.filter((id) => hasManagedRegion(existing, id));
455
+ if (matchedRegions.length === 0) {
456
+ if (existing !== sourceContent) {
457
+ logger.warn(
458
+ `Mirror drift detected at ${targetFile} \u2014 overwriting from source. Edit ${sourceFile} (not the mirror) and re-run \`teamix-evo skills sync\`.`
459
+ );
460
+ await writeFileSafe(targetFile, sourceContent);
461
+ return sourceContent;
462
+ }
463
+ return existing;
464
+ }
465
+ let merged = existing;
466
+ for (const id of matchedRegions) {
467
+ const newRegion = extractRegionBody(sourceContent, id);
468
+ if (newRegion === null) continue;
469
+ try {
470
+ merged = replaceManagedRegion(merged, id, newRegion);
471
+ } catch {
472
+ }
473
+ }
474
+ if (merged !== existing) {
475
+ await writeFileSafe(targetFile, merged);
476
+ }
477
+ return merged;
478
+ }
479
+ function extractRegionBody(content, id) {
480
+ const re = new RegExp(
481
+ `<!-- teamix-evo:managed:start id="${escapeRegExp(
482
+ id
483
+ )}" -->([\\s\\S]*?)<!-- teamix-evo:managed:end id="${escapeRegExp(
484
+ id
485
+ )}" -->`
486
+ );
487
+ const m = content.match(re);
488
+ if (!m) return null;
489
+ return m[1].replace(/^\n/, "").replace(/\n$/, "");
490
+ }
486
491
  async function renderSkillContent(sourceAbs, skill, data) {
487
492
  if (skill.template ?? sourceAbs.endsWith(".hbs")) {
488
493
  const tpl = await loadTemplateFile(sourceAbs);
@@ -537,7 +542,7 @@ async function updateSkills(options) {
537
542
  }
538
543
  async function rewriteSkillSource(skill, options, summary) {
539
544
  const { data, packageRoot, projectRoot } = options;
540
- const sourceAbs = path8.resolve(packageRoot, skill.source);
545
+ const sourceAbs = path7.resolve(packageRoot, skill.source);
541
546
  const targetDir = getSkillsSourceDir(projectRoot, skill.name);
542
547
  const stat2 = await fs5.stat(sourceAbs);
543
548
  if (!stat2.isFile()) {
@@ -545,8 +550,8 @@ async function rewriteSkillSource(skill, options, summary) {
545
550
  const entries = await walkDir(sourceAbs);
546
551
  const records = [];
547
552
  for (const entry of entries) {
548
- const rel2 = path8.relative(sourceAbs, entry);
549
- let targetFile2 = path8.join(targetDir, rel2);
553
+ const rel2 = path7.relative(sourceAbs, entry);
554
+ let targetFile2 = path7.join(targetDir, rel2);
550
555
  if (skill.template && targetFile2.endsWith(".hbs")) {
551
556
  targetFile2 = targetFile2.slice(0, -4);
552
557
  }
@@ -559,12 +564,12 @@ async function rewriteSkillSource(skill, options, summary) {
559
564
  summary.created++;
560
565
  }
561
566
  await writeFileSafe(targetFile2, content);
562
- const relWritten = path8.relative(targetDir, targetFile2);
567
+ const relWritten = path7.relative(targetDir, targetFile2);
563
568
  records.push(makeSourceRecord(skill, targetFile2, content, relWritten));
564
569
  }
565
570
  return records;
566
571
  }
567
- const targetFile = path8.join(targetDir, "SKILL.md");
572
+ const targetFile = path7.join(targetDir, "SKILL.md");
568
573
  const newContent = await renderSkillContent(sourceAbs, skill, data);
569
574
  const exists = await fileExists(targetFile);
570
575
  if (skill.updateStrategy === "frozen") {
@@ -639,14 +644,19 @@ async function syncSkillsToIdes(options) {
639
644
  await ensureDir(targetDir);
640
645
  const sourceFiles = await walkDir(sourceDir);
641
646
  for (const src of sourceFiles) {
642
- const rel2 = path8.relative(sourceDir, src);
643
- const targetFile = path8.join(targetDir, rel2);
644
- const content = await fs5.readFile(src, "utf-8");
645
- await writeFileSafe(targetFile, content);
647
+ const rel2 = path7.relative(sourceDir, src);
648
+ const targetFile = path7.join(targetDir, rel2);
649
+ const sourceContent = await fs5.readFile(src, "utf-8");
650
+ const writtenContent = await writeMirrorContent(
651
+ targetFile,
652
+ sourceContent,
653
+ skill.managedRegions,
654
+ src
655
+ );
646
656
  out.push({
647
657
  id: rel2 === "SKILL.md" ? skill.id : `${skill.id}:${rel2}`,
648
658
  target: targetFile,
649
- hash: computeHash(content),
659
+ hash: computeHash(writtenContent),
650
660
  strategy: skill.updateStrategy,
651
661
  ide,
652
662
  scope
@@ -668,17 +678,46 @@ async function removeSkillFiles(records) {
668
678
  }
669
679
  }
670
680
  }
671
- const parents = new Set(records.map((r) => path8.dirname(r.target)));
672
- for (const dir of parents) {
673
- try {
674
- const entries = await fs5.readdir(dir);
675
- if (entries.length === 0) await fs5.rmdir(dir);
676
- } catch {
681
+ const startDirs = new Set(records.map((r) => path7.dirname(r.target)));
682
+ for (const startDir of startDirs) {
683
+ let dir = startDir;
684
+ for (let depth = 0; depth < 8; depth++) {
685
+ try {
686
+ const entries = await fs5.readdir(dir);
687
+ if (entries.length !== 0) break;
688
+ await fs5.rmdir(dir);
689
+ } catch {
690
+ break;
691
+ }
692
+ dir = path7.dirname(dir);
677
693
  }
678
694
  }
679
695
  return removed;
680
696
  }
681
697
 
698
+ // src/utils/mcp.ts
699
+ import * as path8 from "path";
700
+ var MCP_JSON_CONTENT = {
701
+ mcpServers: {
702
+ "teamix-evo": {
703
+ command: "npx",
704
+ args: ["-y", "@teamix-evo/mcp"]
705
+ }
706
+ }
707
+ };
708
+ async function ensureMcpJson(projectRoot) {
709
+ const mcpPath = path8.join(projectRoot, ".mcp.json");
710
+ if (await fileExists(mcpPath)) return "exists";
711
+ try {
712
+ await writeFileSafe(mcpPath, JSON.stringify(MCP_JSON_CONTENT, null, 2) + "\n");
713
+ logger.debug(`Wrote .mcp.json \u2192 ${mcpPath}`);
714
+ return "created";
715
+ } catch (err) {
716
+ logger.warn(`Failed to write .mcp.json: ${err.message}`);
717
+ return "failed";
718
+ }
719
+ }
720
+
682
721
  // src/core/skills-add.ts
683
722
  var DEFAULT_SKILLS_PACKAGE = "@teamix-evo/skills";
684
723
  var FLAT_VARIANT = "_flat";
@@ -690,9 +729,6 @@ async function runSkillsAdd(options) {
690
729
  await ensureTeamixDir(projectRoot);
691
730
  const existingConfig = await readProjectConfig(projectRoot);
692
731
  const existingSkillsCfg = existingConfig?.packages?.skills;
693
- if (!isIncremental && existingSkillsCfg) {
694
- return { status: "already-added" };
695
- }
696
732
  const ides = options.ides && options.ides.length > 0 ? [...options.ides] : existingSkillsCfg?.ides ? [...existingSkillsCfg.ides] : [];
697
733
  const scope = options.scope ?? existingSkillsCfg?.scope;
698
734
  if (ides.length === 0) {
@@ -702,7 +738,7 @@ async function runSkillsAdd(options) {
702
738
  throw new Error("Scope must be specified (project | global).");
703
739
  }
704
740
  const { manifest, data, packageRoot } = await loadSkillsData(packageName);
705
- const currentDesignVariant = await readDesignVariant(projectRoot);
741
+ const currentTokensVariant = await readTokensVariant(projectRoot);
706
742
  if (isIncremental) {
707
743
  const known = new Set(manifest.skills.map((s) => s.id));
708
744
  const unknown = requestedNames.filter((n) => !known.has(n));
@@ -730,23 +766,27 @@ async function runSkillsAdd(options) {
730
766
  skippedSkillIds = requestedNames.filter((n) => existingSkillIds.has(n));
731
767
  onlyIds = requestedNames.filter((n) => !existingSkillIds.has(n));
732
768
  } else {
733
- skippedSkillIds = [];
734
- onlyIds = manifest.skills.filter((s) => {
769
+ const candidateIds = manifest.skills.filter((s) => {
735
770
  if (!s.variant) return true;
736
- if (!currentDesignVariant) {
771
+ if (!currentTokensVariant) {
737
772
  logger.debug(
738
- `Skipping variant-bound skill "${s.id}" (variant=${s.variant}): no design pack installed; will be picked up when "design init" runs.`
773
+ `Skipping variant-bound skill "${s.id}" (variant=${s.variant}): no tokens variant installed; will be picked up when "tokens init" runs.`
739
774
  );
740
775
  return false;
741
776
  }
742
- if (s.variant !== currentDesignVariant) {
777
+ if (s.variant !== currentTokensVariant) {
743
778
  logger.debug(
744
- `Skipping variant-bound skill "${s.id}" (variant=${s.variant}): current design variant is "${currentDesignVariant}".`
779
+ `Skipping variant-bound skill "${s.id}" (variant=${s.variant}): current tokens variant is "${currentTokensVariant}".`
745
780
  );
746
781
  return false;
747
782
  }
748
783
  return true;
749
784
  }).map((s) => s.id);
785
+ skippedSkillIds = candidateIds.filter((id) => existingSkillIds.has(id));
786
+ onlyIds = candidateIds.filter((id) => !existingSkillIds.has(id));
787
+ }
788
+ if (!isIncremental && existingSkillsCfg && onlyIds.length === 0) {
789
+ return { status: "already-added" };
750
790
  }
751
791
  if (isIncremental && onlyIds.length === 0) {
752
792
  return {
@@ -823,6 +863,7 @@ async function runSkillsAdd(options) {
823
863
  };
824
864
  }
825
865
  await writeSkillsLock(projectRoot, lock);
866
+ await ensureMcpJson(projectRoot);
826
867
  return {
827
868
  status: "installed",
828
869
  packageName,
@@ -844,85 +885,110 @@ function mergeInstalledResources(existing, next) {
844
885
  return [...map.values()];
845
886
  }
846
887
 
847
- // src/core/design-init.ts
848
- var BASELINE_DESIGN_RULES_SKILL = "teamix-evo-design-rules";
888
+ // src/core/tokens-init.ts
849
889
  var DEFAULT_SKILLS_PACKAGE2 = "@teamix-evo/skills";
850
890
  var DEFAULT_AUTO_SKILL_IDES = ["qoder", "claude"];
851
891
  var DEFAULT_AUTO_SKILL_SCOPE = "project";
852
- var DEFAULT_DESIGN_PACKAGE = "@teamix-evo/design";
892
+ var DEFAULT_TOKENS_PACKAGE = "@teamix-evo/tokens";
893
+ var CONSUMER_TOKENS_DIR = "tokens";
894
+ var CONSUMER_THEME_FILE = "tokens.theme.css";
895
+ var CONSUMER_OVERRIDES_FILE = "tokens.overrides.css";
896
+ var EMPTY_OVERRIDES_TEMPLATE = `/* User-owned token overrides \u2014 frozen on subsequent installs. */
897
+ /* See @teamix-evo/tokens variant theme.css for available CSS custom properties. */
898
+ `;
853
899
  var require3 = createRequire2(import.meta.url);
854
- async function runDesignInit(options) {
900
+ async function runTokensInit(options) {
855
901
  const { projectRoot, variant, ide } = options;
856
- const packageName = options.packageName ?? DEFAULT_DESIGN_PACKAGE;
902
+ const packageName = options.packageName ?? DEFAULT_TOKENS_PACKAGE;
857
903
  await ensureTeamixDir(projectRoot);
858
- const existingConfig = await readProjectConfig(projectRoot);
859
- if (existingConfig?.packages?.design) {
860
- return {
861
- status: "already-initialized",
862
- existingVariant: existingConfig.packages.design.variant
863
- };
864
- }
865
- const packageRoot = options.packageRoot ?? resolveDesignPackageRoot(packageName);
866
- const catalog = await loadDesignPackageManifest(packageRoot);
867
- const variantEntry = catalog.variants.find((v) => v.name === variant);
904
+ const packageRoot = options.packageRoot ?? resolveTokensPackageRoot(packageName);
905
+ const catalog = await loadTokensPackageManifest(packageRoot);
906
+ const variantEntry = getVariantEntry(catalog, variant);
868
907
  if (!variantEntry) {
869
908
  const known = catalog.variants.map((v) => v.name).join(", ");
870
909
  throw new Error(
871
- `Design variant not found: "${variant}". Known variants: ${known || "(none)"}. Hint: run "teamix-evo design list-variants" to see all.`
910
+ `Unknown variant "${variant}". Available variants: ${known || "(none)"}.
911
+ Run \`teamix-evo tokens list-variants\` to see all options.`
872
912
  );
873
913
  }
874
- const defaultDir = path9.join(packageRoot, "default");
875
- const variantDir = path9.join(packageRoot, "variants", variant);
876
- const defaultPack = await loadDesignPack(defaultDir);
877
- const variantPack = await loadDesignPack(variantDir);
878
- const merge = await mergeDefaultAndVariant(defaultDir, variantDir);
914
+ const existingConfig = await readProjectConfig(projectRoot);
915
+ if (existingConfig?.packages?.tokens) {
916
+ const existingVariant = existingConfig.packages.tokens.variant;
917
+ if (existingVariant === variant) {
918
+ return { status: "already-initialized", existingVariant };
919
+ }
920
+ return {
921
+ status: "variant-mismatch",
922
+ existingVariant,
923
+ requestedVariant: variant
924
+ };
925
+ }
879
926
  const installed = [];
880
- for (const file of merge.files) {
881
- const result = await installPackFile(file, projectRoot);
927
+ for (const fileRel of variantEntry.files) {
928
+ const result = await installVariantFile(fileRel, packageRoot, projectRoot);
882
929
  if (result) installed.push(result);
883
930
  }
931
+ const overridesAbs = path9.join(
932
+ projectRoot,
933
+ CONSUMER_TOKENS_DIR,
934
+ CONSUMER_OVERRIDES_FILE
935
+ );
936
+ if (!await fileExists(overridesAbs)) {
937
+ await writeFileSafe(overridesAbs, EMPTY_OVERRIDES_TEMPLATE);
938
+ }
939
+ const overridesContent = await fs6.readFile(overridesAbs, "utf-8");
940
+ installed.push({
941
+ id: `tokens:${CONSUMER_OVERRIDES_FILE}`,
942
+ target: path9.posix.join(CONSUMER_TOKENS_DIR, CONSUMER_OVERRIDES_FILE),
943
+ hash: computeHash(overridesContent),
944
+ strategy: "frozen"
945
+ });
884
946
  const lock = {
885
947
  schemaVersion: 1,
886
- default: { version: defaultPack.version, from: packageName },
887
948
  variant: {
888
- name: variantPack.name,
889
- displayName: variantPack.displayName,
890
- version: variantPack.version,
949
+ name: variantEntry.name,
950
+ displayName: variantEntry.displayName,
951
+ version: variantEntry.version,
891
952
  from: packageName
892
953
  },
893
- linked: variantPack.linked,
954
+ packageVersion: catalog.version,
955
+ linked: variantEntry.linked,
894
956
  installedAt: (/* @__PURE__ */ new Date()).toISOString()
895
957
  };
896
958
  await writeFileSafe(
897
- path9.join(projectRoot, ".teamix-evo", "design", "pack.lock.json"),
959
+ path9.join(projectRoot, ".teamix-evo", "tokens-lock.json"),
898
960
  JSON.stringify(lock, null, 2) + "\n"
899
961
  );
900
962
  const config = {
901
963
  $schema: "https://teamix-evo.dev/schema/config/v1.json",
902
964
  schemaVersion: 1,
903
- ide,
965
+ ide: existingConfig?.ide ?? ide,
904
966
  packages: {
905
- design: {
967
+ ...existingConfig?.packages ?? {},
968
+ tokens: {
906
969
  variant,
907
- version: variantPack.version,
970
+ version: variantEntry.version,
908
971
  tailwind: "v4"
909
972
  }
910
973
  }
911
974
  };
912
975
  await writeProjectConfig(projectRoot, config);
913
- const installedManifest = {
976
+ const prior = await readInstalledManifest(projectRoot) ?? {
914
977
  schemaVersion: 1,
915
- installed: [
916
- {
917
- package: packageName,
918
- variant,
919
- version: variantPack.version,
920
- installedAt: (/* @__PURE__ */ new Date()).toISOString(),
921
- resources: installed
922
- }
923
- ]
978
+ installed: []
924
979
  };
925
- await writeInstalledManifest(projectRoot, installedManifest);
980
+ const tokensIdx = prior.installed.findIndex((p) => p.package === packageName);
981
+ const tokensEntry = {
982
+ package: packageName,
983
+ variant,
984
+ version: variantEntry.version,
985
+ installedAt: (/* @__PURE__ */ new Date()).toISOString(),
986
+ resources: installed
987
+ };
988
+ if (tokensIdx >= 0) prior.installed[tokensIdx] = tokensEntry;
989
+ else prior.installed.push(tokensEntry);
990
+ await writeInstalledManifest(projectRoot, prior);
991
+ await ensureMcpJson(projectRoot);
926
992
  const skills = await tryAutoInstallVariantSkills({
927
993
  projectRoot,
928
994
  variant,
@@ -932,21 +998,16 @@ async function runDesignInit(options) {
932
998
  status: "installed",
933
999
  packageName,
934
1000
  variant,
935
- version: variantPack.version,
1001
+ version: variantEntry.version,
936
1002
  count: installed.length,
937
1003
  resources: installed,
938
- merge: {
939
- overrides: merge.overrides,
940
- variantAdds: merge.variantAdds,
941
- defaultPassThrough: merge.defaultPassThrough
942
- },
943
1004
  skills
944
1005
  };
945
1006
  }
946
1007
  async function tryAutoInstallVariantSkills(args) {
947
1008
  const { projectRoot, variant, ide } = args;
948
- const variantSkillId = `${BASELINE_DESIGN_RULES_SKILL}-${variant}`;
949
- const desired = [BASELINE_DESIGN_RULES_SKILL, variantSkillId];
1009
+ const variantSkillId = `teamix-evo-design-${variant}`;
1010
+ const desired = [variantSkillId];
950
1011
  let manifestSkillIds;
951
1012
  try {
952
1013
  const { manifest } = await loadSkillsData(DEFAULT_SKILLS_PACKAGE2);
@@ -966,7 +1027,9 @@ async function tryAutoInstallVariantSkills(args) {
966
1027
  const missing = desired.filter((id) => !manifestSkillIds.has(id));
967
1028
  if (missing.length > 0) {
968
1029
  logger.warn(
969
- `Skills auto-install: not found in manifest, skipping: ${missing.join(", ")}.`
1030
+ `Skills auto-install: not found in manifest, skipping: ${missing.join(
1031
+ ", "
1032
+ )}.`
970
1033
  );
971
1034
  }
972
1035
  if (present.length === 0) {
@@ -1011,32 +1074,69 @@ async function tryAutoInstallVariantSkills(args) {
1011
1074
  };
1012
1075
  }
1013
1076
  }
1014
- async function installPackFile(file, projectRoot) {
1015
- const cls = classifyPackFile(file.relPath);
1016
- if (cls === null) return null;
1017
- const targetAbs = path9.join(projectRoot, cls.target);
1018
- if (cls.isFrozen && await fileExists(targetAbs)) {
1019
- const existing = await fs6.readFile(targetAbs, "utf-8");
1077
+ async function installVariantFile(fileRelToPackage, packageRoot, projectRoot) {
1078
+ const sourceAbs = path9.join(packageRoot, fileRelToPackage);
1079
+ const base = path9.basename(fileRelToPackage);
1080
+ if (base === "theme.css") {
1081
+ const targetRel = path9.posix.join(
1082
+ CONSUMER_TOKENS_DIR,
1083
+ CONSUMER_THEME_FILE
1084
+ );
1085
+ const targetAbs = path9.join(projectRoot, targetRel);
1086
+ const content = await fs6.readFile(sourceAbs, "utf-8");
1087
+ await writeFileSafe(targetAbs, content);
1020
1088
  return {
1021
- id: `pack:${file.relPath}`,
1022
- target: cls.target,
1023
- hash: computeHash(existing),
1024
- strategy: cls.strategy
1089
+ id: `tokens:${CONSUMER_THEME_FILE}`,
1090
+ target: targetRel,
1091
+ hash: computeHash(content),
1092
+ strategy: "regenerable"
1025
1093
  };
1026
1094
  }
1027
- const content = await fs6.readFile(file.sourcePath, "utf-8");
1028
- await writeFileSafe(targetAbs, content);
1029
- return {
1030
- id: `pack:${file.relPath}`,
1031
- target: cls.target,
1032
- hash: computeHash(content),
1033
- strategy: cls.strategy
1034
- };
1095
+ if (base === "overrides.css" || base === "tokens.overrides.css") {
1096
+ const targetRel = path9.posix.join(
1097
+ CONSUMER_TOKENS_DIR,
1098
+ CONSUMER_OVERRIDES_FILE
1099
+ );
1100
+ const targetAbs = path9.join(projectRoot, targetRel);
1101
+ if (await fileExists(targetAbs)) {
1102
+ const existing = await fs6.readFile(targetAbs, "utf-8");
1103
+ return {
1104
+ id: `tokens:${CONSUMER_OVERRIDES_FILE}`,
1105
+ target: targetRel,
1106
+ hash: computeHash(existing),
1107
+ strategy: "frozen"
1108
+ };
1109
+ }
1110
+ const content = await fs6.readFile(sourceAbs, "utf-8");
1111
+ await writeFileSafe(targetAbs, content);
1112
+ return {
1113
+ id: `tokens:${CONSUMER_OVERRIDES_FILE}`,
1114
+ target: targetRel,
1115
+ hash: computeHash(content),
1116
+ strategy: "frozen"
1117
+ };
1118
+ }
1119
+ return null;
1035
1120
  }
1036
- function resolveDesignPackageRoot(packageName) {
1121
+ function resolveTokensPackageRoot(packageName) {
1037
1122
  const pkgJson = require3.resolve(`${packageName}/package.json`);
1038
1123
  return path9.dirname(pkgJson);
1039
1124
  }
1125
+ async function listTokenVariants(packageName = DEFAULT_TOKENS_PACKAGE, packageRoot) {
1126
+ const root = packageRoot ?? resolveTokensPackageRoot(packageName);
1127
+ const catalog = await loadTokensPackageManifest(root);
1128
+ return {
1129
+ packageName,
1130
+ packageVersion: catalog.version,
1131
+ variants: catalog.variants.map((v) => ({
1132
+ name: v.name,
1133
+ displayName: v.displayName,
1134
+ version: v.version,
1135
+ description: v.description,
1136
+ linked: v.linked
1137
+ }))
1138
+ };
1139
+ }
1040
1140
 
1041
1141
  // src/core/ui-init.ts
1042
1142
  var DEFAULT_UI_ALIASES = {
@@ -1082,6 +1182,7 @@ async function runUiInit(options) {
1082
1182
  rsc
1083
1183
  };
1084
1184
  await writeProjectConfig(projectRoot, config);
1185
+ await ensureMcpJson(projectRoot);
1085
1186
  return {
1086
1187
  status: "installed",
1087
1188
  aliases,
@@ -1161,12 +1262,12 @@ function aliasToImportPath(alias) {
1161
1262
  }
1162
1263
 
1163
1264
  // src/core/ui-installer.ts
1164
- var DESIGN_COMPONENTS_DIR = ".teamix-evo/design/components";
1165
1265
  async function installUiEntries(options) {
1166
1266
  const {
1167
1267
  projectRoot,
1168
1268
  manifest,
1169
1269
  packageRoot,
1270
+ entryPackageRoot,
1170
1271
  aliases,
1171
1272
  requested,
1172
1273
  skipExisting = true
@@ -1175,7 +1276,6 @@ async function installUiEntries(options) {
1175
1276
  const idToEntry = new Map(manifest.entries.map((e) => [e.id, e]));
1176
1277
  const resources = [];
1177
1278
  const npmDeps = {};
1178
- const metaFiles = [];
1179
1279
  let written = 0;
1180
1280
  let skipped = 0;
1181
1281
  for (const id of orderedIds) {
@@ -1194,7 +1294,8 @@ async function installUiEntries(options) {
1194
1294
  skipped++;
1195
1295
  continue;
1196
1296
  }
1197
- const sourceAbs = path11.resolve(packageRoot, file.source);
1297
+ const rootForEntry = entryPackageRoot?.get(entry.id) ?? packageRoot;
1298
+ const sourceAbs = path11.resolve(rootForEntry, file.source);
1198
1299
  const raw = await fs8.readFile(sourceAbs, "utf-8");
1199
1300
  const transformed = rewriteImports(raw, aliases);
1200
1301
  await writeFileSafe(targetAbs, transformed);
@@ -1207,32 +1308,13 @@ async function installUiEntries(options) {
1207
1308
  strategy: entry.updateStrategy ?? "frozen"
1208
1309
  });
1209
1310
  }
1210
- if (entry.meta) {
1211
- const metaSourceAbs = path11.resolve(packageRoot, entry.meta);
1212
- const metaContent = await fs8.readFile(metaSourceAbs, "utf-8");
1213
- const metaTargetAbs = path11.join(
1214
- projectRoot,
1215
- DESIGN_COMPONENTS_DIR,
1216
- `${entry.id}.meta.md`
1217
- );
1218
- await writeFileSafe(metaTargetAbs, metaContent);
1219
- metaFiles.push(metaTargetAbs);
1220
- resources.push({
1221
- id: `${entry.id}:meta`,
1222
- target: metaTargetAbs,
1223
- hash: computeHash(metaContent),
1224
- strategy: "regenerable"
1225
- });
1226
- logger.info(` meta: ${rel(projectRoot, metaTargetAbs)}`);
1227
- }
1228
1311
  }
1229
1312
  return {
1230
1313
  orderedIds,
1231
1314
  resources,
1232
1315
  npmDependencies: npmDeps,
1233
1316
  written,
1234
- skipped,
1235
- metaFiles
1317
+ skipped
1236
1318
  };
1237
1319
  }
1238
1320
  function resolveTargetPath(projectRoot, aliases, entry, file) {
@@ -1273,7 +1355,7 @@ async function removeUiFiles(records) {
1273
1355
  // src/core/ui-add.ts
1274
1356
  var DEFAULT_UI_PACKAGE = "@teamix-evo/ui";
1275
1357
  async function runUiAdd(options) {
1276
- const { projectRoot, ids, overwrite } = options;
1358
+ const { projectRoot, ids, overwrite, includeDeprecated } = options;
1277
1359
  const packageName = options.packageName ?? DEFAULT_UI_PACKAGE;
1278
1360
  if (ids.length === 0) {
1279
1361
  throw new Error("At least one entry id must be provided.");
@@ -1286,7 +1368,21 @@ async function runUiAdd(options) {
1286
1368
  );
1287
1369
  }
1288
1370
  const { manifest, packageRoot } = await loadUiData(packageName);
1289
- const knownIds = new Set(manifest.entries.map((e) => e.id));
1371
+ const archived = manifest.deprecatedEntries ?? [];
1372
+ const archivedIds = new Set(archived.map((e) => e.id));
1373
+ const activeIds = new Set(manifest.entries.map((e) => e.id));
1374
+ const requestedDeprecated = ids.filter((id) => archivedIds.has(id));
1375
+ if (requestedDeprecated.length > 0 && !includeDeprecated) {
1376
+ const list = requestedDeprecated.map((s) => `"${s}"`).join(", ");
1377
+ throw new Error(
1378
+ `Refusing to install deprecated entr${requestedDeprecated.length === 1 ? "y" : "ies"} ${list}. These entries are archived and not part of the active distribution (ADR 0028). Pass \`--include-deprecated\` to override (e.g. for migration tooling).`
1379
+ );
1380
+ }
1381
+ const effectiveManifest = includeDeprecated ? { ...manifest, entries: [...manifest.entries, ...archived] } : manifest;
1382
+ const knownIds = /* @__PURE__ */ new Set([
1383
+ ...activeIds,
1384
+ ...includeDeprecated ? archivedIds : []
1385
+ ]);
1290
1386
  const unknown = ids.filter((id) => !knownIds.has(id));
1291
1387
  if (unknown.length > 0) {
1292
1388
  throw new Error(
@@ -1295,7 +1391,7 @@ async function runUiAdd(options) {
1295
1391
  }
1296
1392
  const result = await installUiEntries({
1297
1393
  projectRoot,
1298
- manifest,
1394
+ manifest: effectiveManifest,
1299
1395
  packageRoot,
1300
1396
  aliases: uiCfg.aliases,
1301
1397
  requested: ids,
@@ -1329,7 +1425,6 @@ async function runUiAdd(options) {
1329
1425
  orderedIds: result.orderedIds,
1330
1426
  written: result.written,
1331
1427
  skipped: result.skipped,
1332
- metaFiles: result.metaFiles,
1333
1428
  npmDependencies: result.npmDependencies,
1334
1429
  resources: result.resources
1335
1430
  };
@@ -1344,7 +1439,7 @@ function mergeResources(prior, next) {
1344
1439
  // src/core/ui-list.ts
1345
1440
  var DEFAULT_UI_PACKAGE2 = "@teamix-evo/ui";
1346
1441
  async function runUiList(options) {
1347
- const { projectRoot, installedOnly } = options;
1442
+ const { projectRoot, installedOnly, includeDeprecated } = options;
1348
1443
  const packageName = options.packageName ?? DEFAULT_UI_PACKAGE2;
1349
1444
  const { manifest } = await loadUiData(packageName);
1350
1445
  const installedManifest = await readInstalledManifest(projectRoot);
@@ -1356,15 +1451,21 @@ async function runUiList(options) {
1356
1451
  const colon = r.id.indexOf(":");
1357
1452
  installedIds.add(colon >= 0 ? r.id.slice(0, colon) : r.id);
1358
1453
  }
1359
- const entries = manifest.entries.filter((e) => !installedOnly || installedIds.has(e.id)).map((e) => ({
1360
- id: e.id,
1361
- type: e.type,
1362
- description: e.description,
1363
- installed: installedIds.has(e.id)
1454
+ const archived = manifest.deprecatedEntries ?? [];
1455
+ const pool = includeDeprecated ? [
1456
+ ...manifest.entries.map((e) => ({ entry: e, deprecated: false })),
1457
+ ...archived.map((e) => ({ entry: e, deprecated: true }))
1458
+ ] : manifest.entries.map((e) => ({ entry: e, deprecated: false }));
1459
+ const entries = pool.filter(({ entry }) => !installedOnly || installedIds.has(entry.id)).map(({ entry, deprecated }) => ({
1460
+ id: entry.id,
1461
+ type: entry.type,
1462
+ description: entry.description,
1463
+ installed: installedIds.has(entry.id),
1464
+ deprecated
1364
1465
  }));
1365
1466
  return {
1366
1467
  packageName,
1367
- total: manifest.entries.length,
1468
+ total: manifest.entries.length + (includeDeprecated ? archived.length : 0),
1368
1469
  installedCount: installedIds.size,
1369
1470
  entries
1370
1471
  };
@@ -1501,6 +1602,7 @@ export {
1501
1602
  installResources,
1502
1603
  installSkills,
1503
1604
  installUiEntries,
1605
+ listTokenVariants,
1504
1606
  loadSkillsData,
1505
1607
  loadUiData,
1506
1608
  loadVariantData,
@@ -1508,8 +1610,8 @@ export {
1508
1610
  readProjectConfig,
1509
1611
  removeSkillFiles,
1510
1612
  removeUiFiles,
1511
- runDesignInit,
1512
1613
  runSkillsAdd,
1614
+ runTokensInit,
1513
1615
  runUiAdd,
1514
1616
  runUiInit,
1515
1617
  runUiList,