teamix-evo 0.3.1 → 0.4.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
@@ -1,13 +1,13 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  // src/index.ts
4
- import { Command as Command24 } from "commander";
5
- import { createRequire as createRequire5 } from "module";
4
+ import { Command as Command28 } from "commander";
5
+ import { createRequire as createRequire8 } from "module";
6
6
 
7
- // src/commands/design/index.ts
7
+ // src/commands/tokens/index.ts
8
8
  import { Command as Command6 } from "commander";
9
9
 
10
- // src/commands/design/init.ts
10
+ // src/commands/tokens/init.ts
11
11
  import { Command } from "commander";
12
12
 
13
13
  // src/ide/QoderAdapter.ts
@@ -66,14 +66,13 @@ function detectIde() {
66
66
  return new QoderAdapter();
67
67
  }
68
68
 
69
- // src/core/design-init.ts
70
- import * as path9 from "path";
69
+ // src/core/tokens-init.ts
70
+ import * as path8 from "path";
71
71
  import * as fs6 from "fs/promises";
72
72
  import { createRequire as createRequire2 } from "module";
73
73
  import {
74
- loadDesignPack,
75
- loadDesignPackageManifest,
76
- mergeDefaultAndVariant
74
+ loadTokensPackageManifest,
75
+ getVariantEntry
77
76
  } from "@teamix-evo/registry";
78
77
 
79
78
  // src/utils/fs.ts
@@ -158,71 +157,22 @@ function computeHash(content) {
158
157
  return `sha256:${hash}`;
159
158
  }
160
159
 
161
- // src/core/design-pack-classify.ts
162
- import * as path4 from "path";
163
- var TEAMIX_DIR = ".teamix-evo/design";
164
- var TOKENS_DIR = ".teamix-evo/tokens";
165
- var TOKENS_PACK_PREFIX = "foundations/tokens/";
166
- var ROOT_MANAGED_FILES = {
167
- "DESIGN.md": { target: "DESIGN.md", managedRegions: ["core"] },
168
- "AGENTS.md": { target: "AGENTS.md", managedRegions: ["teamix-evo"] },
169
- "CLAUDE.md": { target: "CLAUDE.md", managedRegions: ["teamix-evo"] }
170
- };
171
- var FROZEN_FILES = /* @__PURE__ */ new Set([
172
- "foundations/tokens/tokens.overrides.css"
173
- ]);
174
- function classifyPackFile(relPath) {
175
- if (path4.basename(relPath) === "README.md") {
176
- return null;
177
- }
178
- const rootManaged = ROOT_MANAGED_FILES[relPath];
179
- if (rootManaged) {
180
- return {
181
- target: rootManaged.target,
182
- strategy: "managed",
183
- managedRegions: rootManaged.managedRegions,
184
- isFrozen: false
185
- };
186
- }
187
- if (relPath.startsWith(TOKENS_PACK_PREFIX)) {
188
- const rel2 = relPath.slice(TOKENS_PACK_PREFIX.length);
189
- const target = path4.posix.join(TOKENS_DIR, rel2);
190
- if (FROZEN_FILES.has(relPath)) {
191
- return { target, strategy: "frozen", isFrozen: true };
192
- }
193
- return { target, strategy: "regenerable", isFrozen: false };
194
- }
195
- if (FROZEN_FILES.has(relPath)) {
196
- return {
197
- target: path4.posix.join(TEAMIX_DIR, relPath),
198
- strategy: "frozen",
199
- isFrozen: true
200
- };
201
- }
202
- return {
203
- target: path4.posix.join(TEAMIX_DIR, relPath),
204
- strategy: "regenerable",
205
- isFrozen: false
206
- };
207
- }
208
-
209
160
  // src/core/state.ts
210
- import * as path5 from "path";
161
+ import * as path4 from "path";
211
162
  import {
212
163
  validateConfig,
213
164
  validateInstalled,
214
165
  validateSkillsLock,
215
- DesignPackLockSchema
166
+ TokensPackLockSchema
216
167
  } from "@teamix-evo/registry";
217
- var TEAMIX_DIR2 = ".teamix-evo";
168
+ var TEAMIX_DIR = ".teamix-evo";
218
169
  var CONFIG_FILE = "config.json";
219
170
  var MANIFEST_FILE = "manifest.json";
220
- var DESIGN_DIR = "design";
221
- var DESIGN_LOCK_FILE = "pack.lock.json";
171
+ var TOKENS_LOCK_FILE = "tokens-lock.json";
222
172
  var SKILLS_DIR = "skills";
223
173
  var SKILLS_LOCK_FILE = "manifest.lock.json";
224
174
  function getTeamixDir(projectRoot) {
225
- return path5.join(projectRoot, TEAMIX_DIR2);
175
+ return path4.join(projectRoot, TEAMIX_DIR);
226
176
  }
227
177
  async function ensureTeamixDir(projectRoot) {
228
178
  const dir = getTeamixDir(projectRoot);
@@ -230,84 +180,85 @@ async function ensureTeamixDir(projectRoot) {
230
180
  return dir;
231
181
  }
232
182
  async function readProjectConfig(projectRoot) {
233
- const configPath = path5.join(projectRoot, TEAMIX_DIR2, CONFIG_FILE);
183
+ const configPath = path4.join(projectRoot, TEAMIX_DIR, CONFIG_FILE);
234
184
  const raw = await readFileOrNull(configPath);
235
185
  if (raw === null) return null;
186
+ let data;
236
187
  try {
237
- const data = JSON.parse(raw);
238
- const result = validateConfig(data);
239
- if (!result.success) {
240
- logger.warn(`Invalid config.json: ${result.error}`);
241
- return null;
242
- }
243
- return result.data;
188
+ data = JSON.parse(raw);
244
189
  } catch (err) {
245
- logger.warn(`Failed to parse config.json: ${err.message}`);
246
- return null;
190
+ throw new Error(
191
+ `Corrupted config.json (${err.message}). Fix the JSON manually or remove the file to start fresh; refusing to clobber prior config.`
192
+ );
193
+ }
194
+ const result = validateConfig(data);
195
+ if (!result.success) {
196
+ throw new Error(
197
+ `Invalid config.json schema: ${result.error}. Fix the file manually or remove it to start fresh.`
198
+ );
247
199
  }
200
+ return result.data;
248
201
  }
249
202
  async function writeProjectConfig(projectRoot, config) {
250
- const configPath = path5.join(projectRoot, TEAMIX_DIR2, CONFIG_FILE);
203
+ const configPath = path4.join(projectRoot, TEAMIX_DIR, CONFIG_FILE);
251
204
  await writeFileSafe(configPath, JSON.stringify(config, null, 2) + "\n");
252
205
  logger.debug(`Wrote config \u2192 ${configPath}`);
253
206
  }
254
207
  async function readInstalledManifest(projectRoot) {
255
- const manifestPath = path5.join(projectRoot, TEAMIX_DIR2, MANIFEST_FILE);
208
+ const manifestPath = path4.join(projectRoot, TEAMIX_DIR, MANIFEST_FILE);
256
209
  const raw = await readFileOrNull(manifestPath);
257
210
  if (raw === null) return null;
211
+ let data;
258
212
  try {
259
- const data = JSON.parse(raw);
260
- const result = validateInstalled(data);
261
- if (!result.success) {
262
- logger.warn(`Invalid manifest.json: ${result.error}`);
263
- return null;
264
- }
265
- return result.data;
213
+ data = JSON.parse(raw);
266
214
  } catch (err) {
267
- logger.warn(`Failed to parse manifest.json: ${err.message}`);
268
- return null;
215
+ throw new Error(
216
+ `Corrupted manifest.json (${err.message}). Fix the JSON manually or remove the file to start fresh; refusing to clobber prior install records.`
217
+ );
218
+ }
219
+ const result = validateInstalled(data);
220
+ if (!result.success) {
221
+ throw new Error(
222
+ `Invalid manifest.json schema: ${result.error}. Fix the file manually or remove it to start fresh.`
223
+ );
269
224
  }
225
+ return result.data;
270
226
  }
271
227
  async function writeInstalledManifest(projectRoot, manifest) {
272
- const manifestPath = path5.join(projectRoot, TEAMIX_DIR2, MANIFEST_FILE);
228
+ const manifestPath = path4.join(projectRoot, TEAMIX_DIR, MANIFEST_FILE);
273
229
  await writeFileSafe(manifestPath, JSON.stringify(manifest, null, 2) + "\n");
274
230
  logger.debug(`Wrote manifest \u2192 ${manifestPath}`);
275
231
  }
276
- async function readDesignPackLock(projectRoot) {
277
- const lockPath = path5.join(
278
- projectRoot,
279
- TEAMIX_DIR2,
280
- DESIGN_DIR,
281
- DESIGN_LOCK_FILE
282
- );
232
+ async function readTokensLock(projectRoot) {
233
+ const lockPath = path4.join(projectRoot, TEAMIX_DIR, TOKENS_LOCK_FILE);
283
234
  const raw = await readFileOrNull(lockPath);
284
235
  if (raw === null) return null;
285
236
  try {
286
- const parsed = DesignPackLockSchema.safeParse(JSON.parse(raw));
237
+ const parsed = TokensPackLockSchema.safeParse(JSON.parse(raw));
287
238
  if (!parsed.success) {
288
- logger.warn(`Invalid design pack.lock.json: ${parsed.error.message}`);
239
+ logger.warn(`Invalid tokens-lock.json: ${parsed.error.message}`);
289
240
  return null;
290
241
  }
291
242
  return parsed.data;
292
243
  } catch (err) {
293
244
  logger.warn(
294
- `Failed to parse design pack.lock.json: ${err.message}`
245
+ `Failed to parse tokens-lock.json: ${err.message}`
295
246
  );
296
247
  return null;
297
248
  }
298
249
  }
299
- async function readDesignVariant(projectRoot) {
300
- const lock = await readDesignPackLock(projectRoot);
250
+ async function readTokensVariant(projectRoot) {
251
+ const lock = await readTokensLock(projectRoot);
301
252
  return lock?.variant.name ?? null;
302
253
  }
303
254
  function getSkillsSourceDir(projectRoot, skillName) {
304
- const base = path5.join(projectRoot, TEAMIX_DIR2, SKILLS_DIR);
305
- return skillName ? path5.join(base, skillName) : base;
255
+ const base = path4.join(projectRoot, TEAMIX_DIR, SKILLS_DIR);
256
+ return skillName ? path4.join(base, skillName) : base;
306
257
  }
307
258
  async function readSkillsLock(projectRoot) {
308
- const lockPath = path5.join(
259
+ const lockPath = path4.join(
309
260
  projectRoot,
310
- TEAMIX_DIR2,
261
+ TEAMIX_DIR,
311
262
  SKILLS_DIR,
312
263
  SKILLS_LOCK_FILE
313
264
  );
@@ -329,9 +280,9 @@ async function readSkillsLock(projectRoot) {
329
280
  }
330
281
  }
331
282
  async function writeSkillsLock(projectRoot, lock) {
332
- const lockPath = path5.join(
283
+ const lockPath = path4.join(
333
284
  projectRoot,
334
- TEAMIX_DIR2,
285
+ TEAMIX_DIR,
335
286
  SKILLS_DIR,
336
287
  SKILLS_LOCK_FILE
337
288
  );
@@ -340,21 +291,21 @@ async function writeSkillsLock(projectRoot, lock) {
340
291
  }
341
292
 
342
293
  // src/core/skills-client.ts
343
- import * as path6 from "path";
294
+ import * as path5 from "path";
344
295
  import * as fs2 from "fs/promises";
345
296
  import { createRequire } from "module";
346
297
  import { loadSkillsPackageManifest } from "@teamix-evo/registry";
347
298
  var require2 = createRequire(import.meta.url);
348
299
  function resolvePackageRoot(packageName) {
349
300
  const pkgJsonPath = require2.resolve(`${packageName}/package.json`);
350
- return path6.dirname(pkgJsonPath);
301
+ return path5.dirname(pkgJsonPath);
351
302
  }
352
303
  async function loadSkillsData(packageName) {
353
304
  const packageRoot = resolvePackageRoot(packageName);
354
305
  logger.debug(`Resolved skills package root: ${packageRoot}`);
355
306
  const manifest = await loadSkillsPackageManifest(packageRoot);
356
307
  let data = {};
357
- const dataPath = path6.join(packageRoot, "_data.json");
308
+ const dataPath = path5.join(packageRoot, "_data.json");
358
309
  try {
359
310
  const raw = await fs2.readFile(dataPath, "utf-8");
360
311
  data = JSON.parse(raw);
@@ -368,7 +319,7 @@ async function loadSkillsData(packageName) {
368
319
  }
369
320
 
370
321
  // src/core/skills-installer.ts
371
- import * as path8 from "path";
322
+ import * as path7 from "path";
372
323
  import * as fs5 from "fs/promises";
373
324
  import { replaceManagedRegion } from "@teamix-evo/registry";
374
325
 
@@ -401,13 +352,13 @@ async function loadTemplateFile(filePath) {
401
352
  }
402
353
 
403
354
  // src/utils/path.ts
404
- import * as path7 from "path";
355
+ import * as path6 from "path";
405
356
  import * as fs4 from "fs/promises";
406
357
  async function walkDir(dir) {
407
358
  const files = [];
408
359
  const entries = await fs4.readdir(dir, { withFileTypes: true });
409
360
  for (const entry of entries) {
410
- const fullPath = path7.join(dir, entry.name);
361
+ const fullPath = path6.join(dir, entry.name);
411
362
  if (entry.isDirectory()) {
412
363
  files.push(...await walkDir(fullPath));
413
364
  } else if (entry.isFile()) {
@@ -450,12 +401,12 @@ async function installSkills(options) {
450
401
  }
451
402
  async function writeSkillSource(skill, options) {
452
403
  const { data, packageRoot, projectRoot } = options;
453
- const sourceAbs = path8.resolve(packageRoot, skill.source);
404
+ const sourceAbs = path7.resolve(packageRoot, skill.source);
454
405
  const targetDir = getSkillsSourceDir(projectRoot, skill.name);
455
406
  const stat4 = await fs5.stat(sourceAbs);
456
407
  const records = [];
457
408
  if (stat4.isFile()) {
458
- const targetFile = path8.join(targetDir, "SKILL.md");
409
+ const targetFile = path7.join(targetDir, "SKILL.md");
459
410
  const content = await renderSkillContent(sourceAbs, skill, data);
460
411
  await writeFileSafe(targetFile, content);
461
412
  records.push(makeSourceRecord(skill, targetFile, content));
@@ -465,14 +416,14 @@ async function writeSkillSource(skill, options) {
465
416
  await ensureDir(targetDir);
466
417
  const entries = await walkDir(sourceAbs);
467
418
  for (const entry of entries) {
468
- const rel2 = path8.relative(sourceAbs, entry);
469
- let targetFile = path8.join(targetDir, rel2);
419
+ const rel2 = path7.relative(sourceAbs, entry);
420
+ let targetFile = path7.join(targetDir, rel2);
470
421
  if (skill.template && targetFile.endsWith(".hbs")) {
471
422
  targetFile = targetFile.slice(0, -4);
472
423
  }
473
424
  const content = skill.template && entry.endsWith(".hbs") ? renderTemplate(await loadTemplateFile(entry), { ...data, skill }) : await fs5.readFile(entry, "utf-8");
474
425
  await writeFileSafe(targetFile, content);
475
- const relWritten = path8.relative(targetDir, targetFile);
426
+ const relWritten = path7.relative(targetDir, targetFile);
476
427
  records.push(makeSourceRecord(skill, targetFile, content, relWritten));
477
428
  logger.debug(` Wrote source: ${targetFile}`);
478
429
  }
@@ -486,11 +437,19 @@ async function mirrorSkillToIde(skill, ide, scope, projectRoot) {
486
437
  const sourceFiles = await walkDir(sourceDir);
487
438
  await ensureDir(targetDir);
488
439
  for (const src of sourceFiles) {
489
- const rel2 = path8.relative(sourceDir, src);
490
- const targetFile = path8.join(targetDir, rel2);
491
- const content = await fs5.readFile(src, "utf-8");
492
- await writeFileSafe(targetFile, content);
493
- records.push(makeMirrorRecord(skill, targetFile, content, ide, scope, rel2));
440
+ const rel2 = path7.relative(sourceDir, src);
441
+ const targetFile = path7.join(targetDir, rel2);
442
+ const sourceContent = await fs5.readFile(src, "utf-8");
443
+ const existing = await readFileOrNull(targetFile);
444
+ if (existing !== null && existing !== sourceContent) {
445
+ logger.warn(
446
+ `Mirror drift detected at ${targetFile} \u2014 overwriting from source. Edit ${src} (not the mirror) and re-run \`teamix-evo skills sync\`.`
447
+ );
448
+ }
449
+ await writeFileSafe(targetFile, sourceContent);
450
+ records.push(
451
+ makeMirrorRecord(skill, targetFile, sourceContent, ide, scope, rel2)
452
+ );
494
453
  logger.debug(` Mirrored ${ide}:${scope}: ${targetFile}`);
495
454
  }
496
455
  return records;
@@ -549,7 +508,7 @@ async function updateSkills(options) {
549
508
  }
550
509
  async function rewriteSkillSource(skill, options, summary) {
551
510
  const { data, packageRoot, projectRoot } = options;
552
- const sourceAbs = path8.resolve(packageRoot, skill.source);
511
+ const sourceAbs = path7.resolve(packageRoot, skill.source);
553
512
  const targetDir = getSkillsSourceDir(projectRoot, skill.name);
554
513
  const stat4 = await fs5.stat(sourceAbs);
555
514
  if (!stat4.isFile()) {
@@ -557,8 +516,8 @@ async function rewriteSkillSource(skill, options, summary) {
557
516
  const entries = await walkDir(sourceAbs);
558
517
  const records = [];
559
518
  for (const entry of entries) {
560
- const rel2 = path8.relative(sourceAbs, entry);
561
- let targetFile2 = path8.join(targetDir, rel2);
519
+ const rel2 = path7.relative(sourceAbs, entry);
520
+ let targetFile2 = path7.join(targetDir, rel2);
562
521
  if (skill.template && targetFile2.endsWith(".hbs")) {
563
522
  targetFile2 = targetFile2.slice(0, -4);
564
523
  }
@@ -571,12 +530,12 @@ async function rewriteSkillSource(skill, options, summary) {
571
530
  summary.created++;
572
531
  }
573
532
  await writeFileSafe(targetFile2, content);
574
- const relWritten = path8.relative(targetDir, targetFile2);
533
+ const relWritten = path7.relative(targetDir, targetFile2);
575
534
  records.push(makeSourceRecord(skill, targetFile2, content, relWritten));
576
535
  }
577
536
  return records;
578
537
  }
579
- const targetFile = path8.join(targetDir, "SKILL.md");
538
+ const targetFile = path7.join(targetDir, "SKILL.md");
580
539
  const newContent = await renderSkillContent(sourceAbs, skill, data);
581
540
  const exists = await fileExists(targetFile);
582
541
  if (skill.updateStrategy === "frozen") {
@@ -651,14 +610,20 @@ async function syncSkillsToIdes(options) {
651
610
  await ensureDir(targetDir);
652
611
  const sourceFiles = await walkDir(sourceDir);
653
612
  for (const src of sourceFiles) {
654
- const rel2 = path8.relative(sourceDir, src);
655
- const targetFile = path8.join(targetDir, rel2);
656
- const content = await fs5.readFile(src, "utf-8");
657
- await writeFileSafe(targetFile, content);
613
+ const rel2 = path7.relative(sourceDir, src);
614
+ const targetFile = path7.join(targetDir, rel2);
615
+ const sourceContent = await fs5.readFile(src, "utf-8");
616
+ const existing = await readFileOrNull(targetFile);
617
+ if (existing !== null && existing !== sourceContent) {
618
+ logger.warn(
619
+ `Mirror drift detected at ${targetFile} \u2014 overwriting from source. Edit ${src} (not the mirror) and re-run \`teamix-evo skills sync\`.`
620
+ );
621
+ }
622
+ await writeFileSafe(targetFile, sourceContent);
658
623
  out.push({
659
624
  id: rel2 === "SKILL.md" ? skill.id : `${skill.id}:${rel2}`,
660
625
  target: targetFile,
661
- hash: computeHash(content),
626
+ hash: computeHash(sourceContent),
662
627
  strategy: skill.updateStrategy,
663
628
  ide,
664
629
  scope
@@ -680,12 +645,18 @@ async function removeSkillFiles(records) {
680
645
  }
681
646
  }
682
647
  }
683
- const parents = new Set(records.map((r) => path8.dirname(r.target)));
684
- for (const dir of parents) {
685
- try {
686
- const entries = await fs5.readdir(dir);
687
- if (entries.length === 0) await fs5.rmdir(dir);
688
- } catch {
648
+ const startDirs = new Set(records.map((r) => path7.dirname(r.target)));
649
+ for (const startDir of startDirs) {
650
+ let dir = startDir;
651
+ for (let depth = 0; depth < 8; depth++) {
652
+ try {
653
+ const entries = await fs5.readdir(dir);
654
+ if (entries.length !== 0) break;
655
+ await fs5.rmdir(dir);
656
+ } catch {
657
+ break;
658
+ }
659
+ dir = path7.dirname(dir);
689
660
  }
690
661
  }
691
662
  return removed;
@@ -714,7 +685,7 @@ async function runSkillsAdd(options) {
714
685
  throw new Error("Scope must be specified (project | global).");
715
686
  }
716
687
  const { manifest, data, packageRoot } = await loadSkillsData(packageName);
717
- const currentDesignVariant = await readDesignVariant(projectRoot);
688
+ const currentTokensVariant = await readTokensVariant(projectRoot);
718
689
  if (isIncremental) {
719
690
  const known = new Set(manifest.skills.map((s) => s.id));
720
691
  const unknown = requestedNames.filter((n) => !known.has(n));
@@ -745,15 +716,15 @@ async function runSkillsAdd(options) {
745
716
  skippedSkillIds = [];
746
717
  onlyIds = manifest.skills.filter((s) => {
747
718
  if (!s.variant) return true;
748
- if (!currentDesignVariant) {
719
+ if (!currentTokensVariant) {
749
720
  logger.debug(
750
- `Skipping variant-bound skill "${s.id}" (variant=${s.variant}): no design pack installed; will be picked up when "design init" runs.`
721
+ `Skipping variant-bound skill "${s.id}" (variant=${s.variant}): no tokens variant installed; will be picked up when "tokens init" runs.`
751
722
  );
752
723
  return false;
753
724
  }
754
- if (s.variant !== currentDesignVariant) {
725
+ if (s.variant !== currentTokensVariant) {
755
726
  logger.debug(
756
- `Skipping variant-bound skill "${s.id}" (variant=${s.variant}): current design variant is "${currentDesignVariant}".`
727
+ `Skipping variant-bound skill "${s.id}" (variant=${s.variant}): current tokens variant is "${currentTokensVariant}".`
757
728
  );
758
729
  return false;
759
730
  }
@@ -856,85 +827,108 @@ function mergeInstalledResources(existing, next) {
856
827
  return [...map.values()];
857
828
  }
858
829
 
859
- // src/core/design-init.ts
860
- var BASELINE_DESIGN_RULES_SKILL = "teamix-evo-design-rules";
830
+ // src/core/tokens-init.ts
861
831
  var DEFAULT_SKILLS_PACKAGE2 = "@teamix-evo/skills";
862
832
  var DEFAULT_AUTO_SKILL_IDES = ["qoder", "claude"];
863
833
  var DEFAULT_AUTO_SKILL_SCOPE = "project";
864
- var DEFAULT_DESIGN_PACKAGE = "@teamix-evo/design";
834
+ var DEFAULT_TOKENS_PACKAGE = "@teamix-evo/tokens";
835
+ var CONSUMER_TOKENS_DIR = "tokens";
836
+ var CONSUMER_THEME_FILE = "tokens.theme.css";
837
+ var CONSUMER_OVERRIDES_FILE = "tokens.overrides.css";
838
+ var EMPTY_OVERRIDES_TEMPLATE = `/* User-owned token overrides \u2014 frozen on subsequent installs. */
839
+ /* See @teamix-evo/tokens variant theme.css for available CSS custom properties. */
840
+ `;
865
841
  var require3 = createRequire2(import.meta.url);
866
- async function runDesignInit(options) {
842
+ async function runTokensInit(options) {
867
843
  const { projectRoot, variant, ide } = options;
868
- const packageName = options.packageName ?? DEFAULT_DESIGN_PACKAGE;
844
+ const packageName = options.packageName ?? DEFAULT_TOKENS_PACKAGE;
869
845
  await ensureTeamixDir(projectRoot);
870
846
  const existingConfig = await readProjectConfig(projectRoot);
871
- if (existingConfig?.packages?.design) {
847
+ if (existingConfig?.packages?.tokens) {
848
+ const existingVariant = existingConfig.packages.tokens.variant;
849
+ if (existingVariant === variant) {
850
+ return { status: "already-initialized", existingVariant };
851
+ }
872
852
  return {
873
- status: "already-initialized",
874
- existingVariant: existingConfig.packages.design.variant
853
+ status: "variant-mismatch",
854
+ existingVariant,
855
+ requestedVariant: variant
875
856
  };
876
857
  }
877
- const packageRoot = options.packageRoot ?? resolveDesignPackageRoot(packageName);
878
- const catalog = await loadDesignPackageManifest(packageRoot);
879
- const variantEntry = catalog.variants.find((v) => v.name === variant);
858
+ const packageRoot = options.packageRoot ?? resolveTokensPackageRoot(packageName);
859
+ const catalog = await loadTokensPackageManifest(packageRoot);
860
+ const variantEntry = getVariantEntry(catalog, variant);
880
861
  if (!variantEntry) {
881
862
  const known = catalog.variants.map((v) => v.name).join(", ");
882
863
  throw new Error(
883
- `Design variant not found: "${variant}". Known variants: ${known || "(none)"}. Hint: run "teamix-evo design list-variants" to see all.`
864
+ `Tokens variant not found: "${variant}". Known variants: ${known || "(none)"}. Hint: run "teamix-evo tokens list-variants" to see all.`
884
865
  );
885
866
  }
886
- const defaultDir = path9.join(packageRoot, "default");
887
- const variantDir = path9.join(packageRoot, "variants", variant);
888
- const defaultPack = await loadDesignPack(defaultDir);
889
- const variantPack = await loadDesignPack(variantDir);
890
- const merge = await mergeDefaultAndVariant(defaultDir, variantDir);
891
867
  const installed = [];
892
- for (const file of merge.files) {
893
- const result = await installPackFile(file, projectRoot);
868
+ for (const fileRel of variantEntry.files) {
869
+ const result = await installVariantFile(fileRel, packageRoot, projectRoot);
894
870
  if (result) installed.push(result);
895
871
  }
872
+ const overridesAbs = path8.join(
873
+ projectRoot,
874
+ CONSUMER_TOKENS_DIR,
875
+ CONSUMER_OVERRIDES_FILE
876
+ );
877
+ if (!await fileExists(overridesAbs)) {
878
+ await writeFileSafe(overridesAbs, EMPTY_OVERRIDES_TEMPLATE);
879
+ }
880
+ const overridesContent = await fs6.readFile(overridesAbs, "utf-8");
881
+ installed.push({
882
+ id: `tokens:${CONSUMER_OVERRIDES_FILE}`,
883
+ target: path8.posix.join(CONSUMER_TOKENS_DIR, CONSUMER_OVERRIDES_FILE),
884
+ hash: computeHash(overridesContent),
885
+ strategy: "frozen"
886
+ });
896
887
  const lock = {
897
888
  schemaVersion: 1,
898
- default: { version: defaultPack.version, from: packageName },
899
889
  variant: {
900
- name: variantPack.name,
901
- displayName: variantPack.displayName,
902
- version: variantPack.version,
890
+ name: variantEntry.name,
891
+ displayName: variantEntry.displayName,
892
+ version: variantEntry.version,
903
893
  from: packageName
904
894
  },
905
- linked: variantPack.linked,
895
+ packageVersion: catalog.version,
896
+ linked: variantEntry.linked,
906
897
  installedAt: (/* @__PURE__ */ new Date()).toISOString()
907
898
  };
908
899
  await writeFileSafe(
909
- path9.join(projectRoot, ".teamix-evo", "design", "pack.lock.json"),
900
+ path8.join(projectRoot, ".teamix-evo", "tokens-lock.json"),
910
901
  JSON.stringify(lock, null, 2) + "\n"
911
902
  );
912
903
  const config = {
913
904
  $schema: "https://teamix-evo.dev/schema/config/v1.json",
914
905
  schemaVersion: 1,
915
- ide,
906
+ ide: existingConfig?.ide ?? ide,
916
907
  packages: {
917
- design: {
908
+ ...existingConfig?.packages ?? {},
909
+ tokens: {
918
910
  variant,
919
- version: variantPack.version,
911
+ version: variantEntry.version,
920
912
  tailwind: "v4"
921
913
  }
922
914
  }
923
915
  };
924
916
  await writeProjectConfig(projectRoot, config);
925
- const installedManifest = {
917
+ const prior = await readInstalledManifest(projectRoot) ?? {
926
918
  schemaVersion: 1,
927
- installed: [
928
- {
929
- package: packageName,
930
- variant,
931
- version: variantPack.version,
932
- installedAt: (/* @__PURE__ */ new Date()).toISOString(),
933
- resources: installed
934
- }
935
- ]
919
+ installed: []
936
920
  };
937
- await writeInstalledManifest(projectRoot, installedManifest);
921
+ const tokensIdx = prior.installed.findIndex((p) => p.package === packageName);
922
+ const tokensEntry = {
923
+ package: packageName,
924
+ variant,
925
+ version: variantEntry.version,
926
+ installedAt: (/* @__PURE__ */ new Date()).toISOString(),
927
+ resources: installed
928
+ };
929
+ if (tokensIdx >= 0) prior.installed[tokensIdx] = tokensEntry;
930
+ else prior.installed.push(tokensEntry);
931
+ await writeInstalledManifest(projectRoot, prior);
938
932
  const skills = await tryAutoInstallVariantSkills({
939
933
  projectRoot,
940
934
  variant,
@@ -944,21 +938,16 @@ async function runDesignInit(options) {
944
938
  status: "installed",
945
939
  packageName,
946
940
  variant,
947
- version: variantPack.version,
941
+ version: variantEntry.version,
948
942
  count: installed.length,
949
943
  resources: installed,
950
- merge: {
951
- overrides: merge.overrides,
952
- variantAdds: merge.variantAdds,
953
- defaultPassThrough: merge.defaultPassThrough
954
- },
955
944
  skills
956
945
  };
957
946
  }
958
947
  async function tryAutoInstallVariantSkills(args) {
959
948
  const { projectRoot, variant, ide } = args;
960
- const variantSkillId = `${BASELINE_DESIGN_RULES_SKILL}-${variant}`;
961
- const desired = [BASELINE_DESIGN_RULES_SKILL, variantSkillId];
949
+ const variantSkillId = `teamix-evo-design-${variant}`;
950
+ const desired = [variantSkillId];
962
951
  let manifestSkillIds;
963
952
  try {
964
953
  const { manifest } = await loadSkillsData(DEFAULT_SKILLS_PACKAGE2);
@@ -978,7 +967,9 @@ async function tryAutoInstallVariantSkills(args) {
978
967
  const missing = desired.filter((id) => !manifestSkillIds.has(id));
979
968
  if (missing.length > 0) {
980
969
  logger.warn(
981
- `Skills auto-install: not found in manifest, skipping: ${missing.join(", ")}.`
970
+ `Skills auto-install: not found in manifest, skipping: ${missing.join(
971
+ ", "
972
+ )}.`
982
973
  );
983
974
  }
984
975
  if (present.length === 0) {
@@ -1023,38 +1014,60 @@ async function tryAutoInstallVariantSkills(args) {
1023
1014
  };
1024
1015
  }
1025
1016
  }
1026
- async function installPackFile(file, projectRoot) {
1027
- const cls = classifyPackFile(file.relPath);
1028
- if (cls === null) return null;
1029
- const targetAbs = path9.join(projectRoot, cls.target);
1030
- if (cls.isFrozen && await fileExists(targetAbs)) {
1031
- const existing = await fs6.readFile(targetAbs, "utf-8");
1017
+ async function installVariantFile(fileRelToPackage, packageRoot, projectRoot) {
1018
+ const sourceAbs = path8.join(packageRoot, fileRelToPackage);
1019
+ const base = path8.basename(fileRelToPackage);
1020
+ if (base === "theme.css") {
1021
+ const targetRel = path8.posix.join(
1022
+ CONSUMER_TOKENS_DIR,
1023
+ CONSUMER_THEME_FILE
1024
+ );
1025
+ const targetAbs = path8.join(projectRoot, targetRel);
1026
+ const content = await fs6.readFile(sourceAbs, "utf-8");
1027
+ await writeFileSafe(targetAbs, content);
1032
1028
  return {
1033
- id: `pack:${file.relPath}`,
1034
- target: cls.target,
1035
- hash: computeHash(existing),
1036
- strategy: cls.strategy
1029
+ id: `tokens:${CONSUMER_THEME_FILE}`,
1030
+ target: targetRel,
1031
+ hash: computeHash(content),
1032
+ strategy: "regenerable"
1037
1033
  };
1038
1034
  }
1039
- const content = await fs6.readFile(file.sourcePath, "utf-8");
1040
- await writeFileSafe(targetAbs, content);
1041
- return {
1042
- id: `pack:${file.relPath}`,
1043
- target: cls.target,
1044
- hash: computeHash(content),
1045
- strategy: cls.strategy
1046
- };
1035
+ if (base === "overrides.css" || base === "tokens.overrides.css") {
1036
+ const targetRel = path8.posix.join(
1037
+ CONSUMER_TOKENS_DIR,
1038
+ CONSUMER_OVERRIDES_FILE
1039
+ );
1040
+ const targetAbs = path8.join(projectRoot, targetRel);
1041
+ if (await fileExists(targetAbs)) {
1042
+ const existing = await fs6.readFile(targetAbs, "utf-8");
1043
+ return {
1044
+ id: `tokens:${CONSUMER_OVERRIDES_FILE}`,
1045
+ target: targetRel,
1046
+ hash: computeHash(existing),
1047
+ strategy: "frozen"
1048
+ };
1049
+ }
1050
+ const content = await fs6.readFile(sourceAbs, "utf-8");
1051
+ await writeFileSafe(targetAbs, content);
1052
+ return {
1053
+ id: `tokens:${CONSUMER_OVERRIDES_FILE}`,
1054
+ target: targetRel,
1055
+ hash: computeHash(content),
1056
+ strategy: "frozen"
1057
+ };
1058
+ }
1059
+ return null;
1047
1060
  }
1048
- function resolveDesignPackageRoot(packageName) {
1061
+ function resolveTokensPackageRoot(packageName) {
1049
1062
  const pkgJson = require3.resolve(`${packageName}/package.json`);
1050
- return path9.dirname(pkgJson);
1063
+ return path8.dirname(pkgJson);
1051
1064
  }
1052
- async function listDesignVariants(packageName = DEFAULT_DESIGN_PACKAGE, packageRoot) {
1053
- const root = packageRoot ?? resolveDesignPackageRoot(packageName);
1054
- const catalog = await loadDesignPackageManifest(root);
1065
+ async function listTokenVariants(packageName = DEFAULT_TOKENS_PACKAGE, packageRoot) {
1066
+ const root = packageRoot ?? resolveTokensPackageRoot(packageName);
1067
+ const catalog = await loadTokensPackageManifest(root);
1055
1068
  return {
1056
1069
  packageName,
1057
- defaultDescription: catalog.default.description,
1070
+ packageVersion: catalog.version,
1058
1071
  variants: catalog.variants.map((v) => ({
1059
1072
  name: v.name,
1060
1073
  displayName: v.displayName,
@@ -1065,7 +1078,7 @@ async function listDesignVariants(packageName = DEFAULT_DESIGN_PACKAGE, packageR
1065
1078
  };
1066
1079
  }
1067
1080
 
1068
- // src/commands/design/init.ts
1081
+ // src/commands/tokens/init.ts
1069
1082
  var initCommand = new Command("init").description("\u521D\u59CB\u5316\u8BBE\u8BA1\u4F53\u7CFB\u8D44\u6E90\uFF08\u5FC5\u987B\u663E\u5F0F\u6307\u5B9A\u4E1A\u52A1\u53D8\u4F53\uFF09").argument("<variant>", '\u4E1A\u52A1\u53D8\u4F53\u540D\u79F0\uFF08\u5982 "opentrek"\u3001"uni-manager"\uFF09').action(async (variant) => {
1070
1083
  try {
1071
1084
  const ide = detectIde();
@@ -1075,15 +1088,28 @@ var initCommand = new Command("init").description("\u521D\u59CB\u5316\u8BBE\u8BA
1075
1088
  logger.debug(`IDE: ${ide.name}`);
1076
1089
  logger.info(`Loading variant "${variant}"...`);
1077
1090
  logger.info("Installing resources...");
1078
- const result = await runDesignInit({
1091
+ const result = await runTokensInit({
1079
1092
  projectRoot,
1080
1093
  variant,
1081
1094
  ide: ide.name
1082
1095
  });
1083
1096
  if (result.status === "already-initialized") {
1084
- logger.warn(
1085
- `Design system already initialized (variant: ${result.existingVariant}). Use "teamix-evo design update" to update.`
1097
+ logger.info(
1098
+ `Design system already initialized (variant: ${result.existingVariant}). Use "teamix-evo tokens update" to refresh resources.`
1099
+ );
1100
+ return;
1101
+ }
1102
+ if (result.status === "variant-mismatch") {
1103
+ logger.error(
1104
+ `Cannot switch tokens variant in place. Currently installed: "${result.existingVariant}"; requested: "${result.requestedVariant}".`
1105
+ );
1106
+ logger.info("To switch variants:");
1107
+ logger.info(" 1. teamix-evo tokens uninstall --yes");
1108
+ logger.info(` 2. teamix-evo tokens init ${result.requestedVariant}`);
1109
+ logger.info(
1110
+ "Note: tokens.overrides.css (frozen) is preserved across uninstall/init by default."
1086
1111
  );
1112
+ process.exitCode = 1;
1087
1113
  return;
1088
1114
  }
1089
1115
  logger.success(
@@ -1092,9 +1118,6 @@ var initCommand = new Command("init").description("\u521D\u59CB\u5316\u8BBE\u8BA
1092
1118
  logger.info(` Variant: ${result.variant}`);
1093
1119
  logger.info(` Tailwind: v4`);
1094
1120
  logger.info(` Resources: ${result.count} files installed`);
1095
- logger.info(
1096
- ` Merge: ${result.merge.overrides.length} overrides / ${result.merge.variantAdds.length} variant-only / ${result.merge.defaultPassThrough.length} default-passthrough`
1097
- );
1098
1121
  if (result.skills) {
1099
1122
  const { addedSkillIds, skippedSkillIds, missing } = result.skills;
1100
1123
  if (addedSkillIds.length > 0) {
@@ -1114,9 +1137,9 @@ var initCommand = new Command("init").description("\u521D\u59CB\u5316\u8BBE\u8BA
1114
1137
  }
1115
1138
  }
1116
1139
  logger.info("");
1117
- logger.info('Run "teamix-evo design update" to update resources later.');
1140
+ logger.info('Run "teamix-evo tokens update" to update resources later.');
1118
1141
  logger.info(
1119
- 'Run "teamix-evo design list-variants" to see all available variants.'
1142
+ 'Run "teamix-evo tokens list-variants" to see all available variants.'
1120
1143
  );
1121
1144
  } catch (err) {
1122
1145
  logger.error(`Failed to initialize: ${err.message}`);
@@ -1125,43 +1148,191 @@ var initCommand = new Command("init").description("\u521D\u59CB\u5316\u8BBE\u8BA
1125
1148
  }
1126
1149
  });
1127
1150
 
1128
- // src/commands/design/update.ts
1151
+ // src/commands/tokens/update.ts
1129
1152
  import { Command as Command2 } from "commander";
1130
- var updateCommand = new Command2("update").description("(v0.7) \u66F4\u65B0\u8BBE\u8BA1\u4F53\u7CFB\u8D44\u6E90 \u2014 \u5F53\u524D\u672A\u5B9E\u73B0,\u89C1 ADR 0010 / PLAN \xA712.6").action(() => {
1131
- logger.warn(
1132
- "design update is not yet implemented for the design pack model (default + variants/, ADR 0010)."
1153
+
1154
+ // src/core/tokens-update.ts
1155
+ import * as path9 from "path";
1156
+ import * as fs7 from "fs/promises";
1157
+ import { createRequire as createRequire3 } from "module";
1158
+ import {
1159
+ loadTokensPackageManifest as loadTokensPackageManifest2,
1160
+ getVariantEntry as getVariantEntry2
1161
+ } from "@teamix-evo/registry";
1162
+ var DEFAULT_TOKENS_PACKAGE2 = "@teamix-evo/tokens";
1163
+ var CONSUMER_TOKENS_DIR2 = "tokens";
1164
+ var CONSUMER_THEME_FILE2 = "tokens.theme.css";
1165
+ var require4 = createRequire3(import.meta.url);
1166
+ async function runTokensUpdate(options) {
1167
+ const { projectRoot } = options;
1168
+ const packageName = options.packageName ?? DEFAULT_TOKENS_PACKAGE2;
1169
+ const config = await readProjectConfig(projectRoot);
1170
+ if (!config?.packages?.tokens) {
1171
+ return { status: "not-initialized" };
1172
+ }
1173
+ const currentVariant = config.packages.tokens.variant;
1174
+ const currentVersion = config.packages.tokens.version;
1175
+ const packageRoot = options.packageRoot ?? resolveTokensPackageRoot2(packageName);
1176
+ const catalog = await loadTokensPackageManifest2(packageRoot);
1177
+ const variantEntry = getVariantEntry2(catalog, currentVariant);
1178
+ if (!variantEntry) {
1179
+ throw new Error(
1180
+ `Currently installed variant "${currentVariant}" no longer exists in ${packageName}@${catalog.version}. Available: ${catalog.variants.map((v) => v.name).join(", ")}. Run \`teamix-evo tokens uninstall\` then \`teamix-evo tokens init <variant>\` to switch.`
1181
+ );
1182
+ }
1183
+ if (variantEntry.version === currentVersion) {
1184
+ await rewriteRegenerableFiles(variantEntry.files, packageRoot, projectRoot);
1185
+ return {
1186
+ status: "up-to-date",
1187
+ packageName,
1188
+ variant: currentVariant,
1189
+ version: currentVersion
1190
+ };
1191
+ }
1192
+ const rewritten = await rewriteRegenerableFiles(
1193
+ variantEntry.files,
1194
+ packageRoot,
1195
+ projectRoot
1133
1196
  );
1134
- logger.info(
1135
- "Workaround: clean `.teamix-evo/design/` and re-run `teamix-evo design init <variant>`."
1197
+ const preserved = [];
1198
+ const overridesAbs = path9.join(
1199
+ projectRoot,
1200
+ CONSUMER_TOKENS_DIR2,
1201
+ "tokens.overrides.css"
1136
1202
  );
1137
- logger.info(
1138
- "Tracking: PLAN \xA712.6 v0.7 \u2014 semantic upgrade flow + tokens.overrides.css preservation."
1203
+ if (await fileExists(overridesAbs)) preserved.push("tokens.overrides.css");
1204
+ const lock = {
1205
+ schemaVersion: 1,
1206
+ variant: {
1207
+ name: variantEntry.name,
1208
+ displayName: variantEntry.displayName,
1209
+ version: variantEntry.version,
1210
+ from: packageName
1211
+ },
1212
+ packageVersion: catalog.version,
1213
+ linked: variantEntry.linked,
1214
+ installedAt: (/* @__PURE__ */ new Date()).toISOString()
1215
+ };
1216
+ await writeFileSafe(
1217
+ path9.join(projectRoot, ".teamix-evo", "tokens-lock.json"),
1218
+ JSON.stringify(lock, null, 2) + "\n"
1139
1219
  );
1140
- process.exitCode = 0;
1220
+ config.packages.tokens.version = variantEntry.version;
1221
+ await writeProjectConfig(projectRoot, config);
1222
+ const prior = await readInstalledManifest(projectRoot) ?? {
1223
+ schemaVersion: 1,
1224
+ installed: []
1225
+ };
1226
+ const idx = prior.installed.findIndex((p) => p.package === packageName);
1227
+ if (idx >= 0) {
1228
+ prior.installed[idx].version = variantEntry.version;
1229
+ prior.installed[idx].installedAt = (/* @__PURE__ */ new Date()).toISOString();
1230
+ for (const r of prior.installed[idx].resources) {
1231
+ if (r.strategy === "regenerable") {
1232
+ const abs = path9.isAbsolute(r.target) ? r.target : path9.join(projectRoot, r.target);
1233
+ if (await fileExists(abs)) {
1234
+ r.hash = computeHash(await fs7.readFile(abs, "utf-8"));
1235
+ }
1236
+ }
1237
+ }
1238
+ await writeInstalledManifest(projectRoot, prior);
1239
+ }
1240
+ return {
1241
+ status: "updated",
1242
+ packageName,
1243
+ variant: currentVariant,
1244
+ from: currentVersion,
1245
+ to: variantEntry.version,
1246
+ rewritten,
1247
+ preserved
1248
+ };
1249
+ }
1250
+ async function rewriteRegenerableFiles(files, packageRoot, projectRoot) {
1251
+ const written = [];
1252
+ for (const fileRel of files) {
1253
+ const base = path9.basename(fileRel);
1254
+ if (base !== "theme.css") continue;
1255
+ const sourceAbs = path9.join(packageRoot, fileRel);
1256
+ const targetAbs = path9.join(
1257
+ projectRoot,
1258
+ CONSUMER_TOKENS_DIR2,
1259
+ CONSUMER_THEME_FILE2
1260
+ );
1261
+ const content = await fs7.readFile(sourceAbs, "utf-8");
1262
+ await writeFileSafe(targetAbs, content);
1263
+ written.push(CONSUMER_THEME_FILE2);
1264
+ }
1265
+ return written;
1266
+ }
1267
+ function resolveTokensPackageRoot2(packageName) {
1268
+ const pkgJson = require4.resolve(`${packageName}/package.json`);
1269
+ return path9.dirname(pkgJson);
1270
+ }
1271
+
1272
+ // src/commands/tokens/update.ts
1273
+ var updateCommand = new Command2("update").description(
1274
+ "\u5237\u65B0 design tokens\uFF08regenerable \u8986\u76D6\u3001frozen \u4FDD\u7559 \u2014 ADR 0003 \u4E09\u6001\uFF09"
1275
+ ).action(async () => {
1276
+ try {
1277
+ const ide = detectIde();
1278
+ const projectRoot = ide.getProjectRoot();
1279
+ const result = await runTokensUpdate({ projectRoot });
1280
+ if (result.status === "not-initialized") {
1281
+ logger.error(
1282
+ "No tokens variant installed. Run `teamix-evo tokens init <variant>` first."
1283
+ );
1284
+ process.exitCode = 1;
1285
+ return;
1286
+ }
1287
+ if (result.status === "up-to-date") {
1288
+ logger.success(
1289
+ `Already at latest: ${result.packageName} (${result.variant} v${result.version})`
1290
+ );
1291
+ logger.info(
1292
+ " Regenerable files refreshed in case of manual edits."
1293
+ );
1294
+ return;
1295
+ }
1296
+ logger.success(
1297
+ `Updated ${result.packageName} (${result.variant}): v${result.from} \u2192 v${result.to}`
1298
+ );
1299
+ if (result.rewritten.length > 0) {
1300
+ logger.info(` Rewrote: ${result.rewritten.join(", ")}`);
1301
+ }
1302
+ if (result.preserved.length > 0) {
1303
+ logger.info(
1304
+ ` Preserved: ${result.preserved.join(", ")} (frozen \u2014 your customizations kept)`
1305
+ );
1306
+ }
1307
+ } catch (err) {
1308
+ logger.error(`Failed to update tokens: ${err.message}`);
1309
+ logger.debug(err.stack ?? "");
1310
+ process.exitCode = 1;
1311
+ }
1141
1312
  });
1142
1313
 
1143
- // src/commands/design/list.ts
1314
+ // src/commands/tokens/list.ts
1144
1315
  import { Command as Command3 } from "commander";
1145
1316
  var listCommand = new Command3("list").description("\u5217\u51FA\u5DF2\u5B89\u88C5\u7684\u8BBE\u8BA1\u53D8\u4F53").action(async () => {
1146
1317
  try {
1147
1318
  const ide = detectIde();
1148
1319
  const projectRoot = ide.getProjectRoot();
1149
1320
  const config = await readProjectConfig(projectRoot);
1150
- if (!config?.packages?.design) {
1151
- logger.info("No design system installed.");
1152
- logger.info('Run "teamix-evo design init [variant]" to get started.');
1321
+ if (!config?.packages?.tokens) {
1322
+ logger.info("No tokens variant installed.");
1323
+ logger.info('Run "teamix-evo tokens init [variant]" to get started.');
1153
1324
  return;
1154
1325
  }
1155
- const { variant, version: version2 } = config.packages.design;
1156
- logger.info("Installed design system:");
1157
- logger.info(` Package: @teamix-evo/design`);
1326
+ const { variant, version: version2 } = config.packages.tokens;
1327
+ logger.info("Installed tokens variant:");
1328
+ logger.info(` Package: @teamix-evo/tokens`);
1158
1329
  logger.info(` Variant: ${variant}`);
1159
1330
  logger.info(` Version: ${version2}`);
1160
1331
  logger.info(` IDE: ${config.ide}`);
1161
1332
  const manifest = await readInstalledManifest(projectRoot);
1162
1333
  if (manifest) {
1163
1334
  const pkg = manifest.installed.find(
1164
- (p) => p.package === "@teamix-evo/design" && p.variant === variant
1335
+ (p) => p.package === "@teamix-evo/tokens" && p.variant === variant
1165
1336
  );
1166
1337
  if (pkg) {
1167
1338
  logger.info(` Resources: ${pkg.resources.length} files`);
@@ -1176,20 +1347,17 @@ var listCommand = new Command3("list").description("\u5217\u51FA\u5DF2\u5B89\u88
1176
1347
  }
1177
1348
  });
1178
1349
 
1179
- // src/commands/design/list-variants.ts
1350
+ // src/commands/tokens/list-variants.ts
1180
1351
  import { Command as Command4 } from "commander";
1181
- var listVariantsCommand = new Command4("list-variants").description("\u5217\u51FA @teamix-evo/design \u5305\u5185\u63D0\u4F9B\u7684\u6240\u6709\u53D8\u4F53").action(async () => {
1352
+ var listVariantsCommand = new Command4("list-variants").description("\u5217\u51FA @teamix-evo/tokens \u5305\u5185\u63D0\u4F9B\u7684\u6240\u6709\u53D8\u4F53").action(async () => {
1182
1353
  try {
1183
- const result = await listDesignVariants();
1184
- logger.info(`Available design variants in ${result.packageName}:`);
1185
- logger.info("");
1186
- logger.info(" default \u2014 B \u7AEF\u901A\u7528\u57FA\u7EBF(\u59CB\u7EC8\u5185\u7F6E,\u65E0\u9700\u9009\u62E9)");
1187
- if (result.defaultDescription) {
1188
- logger.info(` ${result.defaultDescription}`);
1189
- }
1354
+ const result = await listTokenVariants();
1355
+ logger.info(
1356
+ `Available variants in ${result.packageName} v${result.packageVersion}:`
1357
+ );
1190
1358
  logger.info("");
1191
1359
  if (result.variants.length === 0) {
1192
- logger.info(" (no variants beyond default)");
1360
+ logger.info(" (no variants advertised in manifest.json)");
1193
1361
  return;
1194
1362
  }
1195
1363
  for (const v of result.variants) {
@@ -1198,12 +1366,13 @@ var listVariantsCommand = new Command4("list-variants").description("\u5217\u51F
1198
1366
  if (v.linked) {
1199
1367
  const links = [];
1200
1368
  if (v.linked["biz-ui"]) links.push(`biz-ui: ${v.linked["biz-ui"]}`);
1201
- if (v.linked.templates) links.push(`templates: ${v.linked.templates}`);
1369
+ if (v.linked.templates)
1370
+ links.push(`templates: ${v.linked.templates}`);
1202
1371
  if (links.length) logger.info(` linked: ${links.join(" / ")}`);
1203
1372
  }
1204
1373
  logger.info("");
1205
1374
  }
1206
- logger.info("Install a variant: teamix-evo design init <name>");
1375
+ logger.info("Install a variant: teamix-evo tokens init <name>");
1207
1376
  } catch (err) {
1208
1377
  logger.error(`Failed to list variants: ${err.message}`);
1209
1378
  logger.debug(err.stack ?? "");
@@ -1211,37 +1380,42 @@ var listVariantsCommand = new Command4("list-variants").description("\u5217\u51F
1211
1380
  }
1212
1381
  });
1213
1382
 
1214
- // src/commands/design/uninstall.ts
1383
+ // src/commands/tokens/uninstall.ts
1215
1384
  import { Command as Command5 } from "commander";
1216
- import * as fs7 from "fs/promises";
1385
+ import * as fs8 from "fs/promises";
1217
1386
  import * as path10 from "path";
1218
1387
  import * as prompts from "@clack/prompts";
1219
- var DESIGN_PACKAGE = "@teamix-evo/design";
1220
- var uninstallCommand = new Command5("uninstall").description("\u5378\u8F7D\u8BBE\u8BA1\u4F53\u7CFB\u8D44\u6E90\uFF08\u9ED8\u8BA4\u4F1A\u5220\u9664 frozen / regenerable \u8D44\u6E90\u6587\u4EF6\uFF09").option("-y, --yes", "\u8DF3\u8FC7\u786E\u8BA4").option(
1388
+ var TOKENS_PACKAGE = "@teamix-evo/tokens";
1389
+ var uninstallCommand = new Command5("uninstall").description(
1390
+ "\u5378\u8F7D\u5DF2\u88C5\u7684 tokens \u53D8\u4F53\uFF08\u9ED8\u8BA4\u4FDD\u7559 frozen \u6587\u4EF6\u5982 tokens.overrides.css\uFF1B--purge \u624D\u4E00\u5E76\u5220\uFF09"
1391
+ ).option("-y, --yes", "\u8DF3\u8FC7\u786E\u8BA4").option(
1221
1392
  "--keep-files",
1222
- "\u4EC5\u6E05\u7406 .teamix-evo \u4E2D\u7684\u8BB0\u8D26\u4FE1\u606F\uFF0C\u4E0D\u5220\u9664\u5DF2\u843D\u5730\u8D44\u6E90\u6587\u4EF6"
1393
+ "\u4EC5\u6E05\u7406 .teamix-evo \u4E2D\u7684\u8BB0\u8D26\u4FE1\u606F\uFF0C\u4E0D\u5220\u9664\u4EFB\u4F55\u843D\u5730\u8D44\u6E90\u6587\u4EF6"
1394
+ ).option(
1395
+ "--purge",
1396
+ "\u540C\u65F6\u5220\u9664 frozen \u6587\u4EF6\uFF08\u9ED8\u8BA4 frozen / managed \u90FD\u4FDD\u7559 \u2014 ADR 0003\uFF09"
1223
1397
  ).action(async (opts) => {
1224
1398
  try {
1225
1399
  const ide = detectIde();
1226
1400
  const projectRoot = ide.getProjectRoot();
1227
1401
  const config = await readProjectConfig(projectRoot);
1228
- if (!config?.packages?.design) {
1229
- logger.info("Design system is not installed. Nothing to do.");
1402
+ if (!config?.packages?.tokens) {
1403
+ logger.info("No tokens variant installed. Nothing to do.");
1230
1404
  return;
1231
1405
  }
1232
1406
  const installedManifest = await readInstalledManifest(projectRoot);
1233
1407
  const pkg = installedManifest?.installed.find(
1234
- (p) => p.package === DESIGN_PACKAGE
1408
+ (p) => p.package === TOKENS_PACKAGE
1235
1409
  );
1236
1410
  const resources = pkg?.resources ?? [];
1237
- const removable = opts.keepFiles ? [] : resources.filter((r) => r.strategy !== "managed");
1411
+ const removable = opts.keepFiles ? [] : opts.purge ? resources.filter((r) => r.strategy !== "managed") : resources.filter((r) => r.strategy === "regenerable");
1238
1412
  const kept = resources.length - removable.length;
1239
1413
  logger.info(
1240
1414
  `Will remove ${removable.length} file(s); keep ${kept} managed file(s).`
1241
1415
  );
1242
1416
  if (!opts.yes) {
1243
1417
  const confirm4 = await prompts.confirm({
1244
- message: "\u786E\u8BA4\u5378\u8F7D\u8BBE\u8BA1\u4F53\u7CFB\uFF1F",
1418
+ message: "\u786E\u8BA4\u5378\u8F7D tokens \u53D8\u4F53\uFF1F",
1245
1419
  initialValue: false
1246
1420
  });
1247
1421
  if (prompts.isCancel(confirm4) || !confirm4) {
@@ -1253,7 +1427,7 @@ var uninstallCommand = new Command5("uninstall").description("\u5378\u8F7D\u8BBE
1253
1427
  for (const r of removable) {
1254
1428
  const target = path10.isAbsolute(r.target) ? r.target : path10.join(projectRoot, r.target);
1255
1429
  try {
1256
- await fs7.unlink(target);
1430
+ await fs8.unlink(target);
1257
1431
  removed++;
1258
1432
  } catch (err) {
1259
1433
  if (err.code !== "ENOENT") {
@@ -1265,18 +1439,31 @@ var uninstallCommand = new Command5("uninstall").description("\u5378\u8F7D\u8BBE
1265
1439
  }
1266
1440
  if (installedManifest) {
1267
1441
  installedManifest.installed = installedManifest.installed.filter(
1268
- (p) => p.package !== DESIGN_PACKAGE
1442
+ (p) => p.package !== TOKENS_PACKAGE
1269
1443
  );
1270
1444
  await writeInstalledManifest(projectRoot, installedManifest);
1271
1445
  }
1272
- delete config.packages.design;
1446
+ delete config.packages.tokens;
1273
1447
  await writeProjectConfig(projectRoot, config);
1274
- logger.success(`Uninstalled ${DESIGN_PACKAGE}`);
1448
+ const lockPath = path10.join(
1449
+ projectRoot,
1450
+ ".teamix-evo",
1451
+ "tokens-lock.json"
1452
+ );
1453
+ try {
1454
+ await fs8.unlink(lockPath);
1455
+ } catch (err) {
1456
+ if (err.code !== "ENOENT") {
1457
+ logger.warn(
1458
+ `Failed to remove tokens-lock.json: ${err.message}`
1459
+ );
1460
+ }
1461
+ }
1462
+ logger.success(`Uninstalled ${TOKENS_PACKAGE}`);
1275
1463
  logger.info(` Removed: ${removed} files`);
1276
1464
  if (kept > 0) {
1277
- logger.info(
1278
- ` Kept: ${kept} managed files (you may delete manually)`
1279
- );
1465
+ const note = opts.purge ? "managed (you may delete manually)" : "frozen / managed (preserved \u2014 ADR 0003; --purge to force)";
1466
+ logger.info(` Kept: ${kept} files \u2014 ${note}`);
1280
1467
  }
1281
1468
  } catch (err) {
1282
1469
  logger.error(`Failed to uninstall: ${err.message}`);
@@ -1285,15 +1472,13 @@ var uninstallCommand = new Command5("uninstall").description("\u5378\u8F7D\u8BBE
1285
1472
  }
1286
1473
  });
1287
1474
 
1288
- // src/commands/design/index.ts
1289
- var designCommand = new Command6("design").description(
1290
- "\u7BA1\u7406\u8BBE\u8BA1\u4F53\u7CFB\u8D44\u6E90"
1291
- );
1292
- designCommand.addCommand(initCommand);
1293
- designCommand.addCommand(updateCommand);
1294
- designCommand.addCommand(listCommand);
1295
- designCommand.addCommand(listVariantsCommand);
1296
- designCommand.addCommand(uninstallCommand);
1475
+ // src/commands/tokens/index.ts
1476
+ var tokensCommand = new Command6("tokens").description("\u7BA1\u7406 design tokens(\u53D8\u4F53\u7EA7 theme.css \u7B49)");
1477
+ tokensCommand.addCommand(initCommand);
1478
+ tokensCommand.addCommand(updateCommand);
1479
+ tokensCommand.addCommand(listCommand);
1480
+ tokensCommand.addCommand(listVariantsCommand);
1481
+ tokensCommand.addCommand(uninstallCommand);
1297
1482
 
1298
1483
  // src/commands/skills/index.ts
1299
1484
  import { Command as Command13 } from "commander";
@@ -1304,21 +1489,21 @@ import * as prompts2 from "@clack/prompts";
1304
1489
 
1305
1490
  // src/utils/global-root.ts
1306
1491
  import { existsSync } from "fs";
1307
- import * as fs8 from "fs/promises";
1492
+ import * as fs9 from "fs/promises";
1308
1493
  import * as os3 from "os";
1309
1494
  import * as path11 from "path";
1310
1495
  var GLOBAL_META_DIR = ".teamix-evo-global";
1311
- var TEAMIX_DIR3 = ".teamix-evo";
1496
+ var TEAMIX_DIR2 = ".teamix-evo";
1312
1497
  var CONFIG_FILE2 = "config.json";
1313
1498
  function getGlobalMetaRoot() {
1314
1499
  return path11.join(os3.homedir(), GLOBAL_META_DIR);
1315
1500
  }
1316
1501
  function isTeamixEvoProject(dir) {
1317
- return existsSync(path11.join(dir, TEAMIX_DIR3, CONFIG_FILE2));
1502
+ return existsSync(path11.join(dir, TEAMIX_DIR2, CONFIG_FILE2));
1318
1503
  }
1319
1504
  async function ensureGlobalMetaRoot() {
1320
1505
  const root = getGlobalMetaRoot();
1321
- await fs8.mkdir(root, { recursive: true });
1506
+ await fs9.mkdir(root, { recursive: true });
1322
1507
  return root;
1323
1508
  }
1324
1509
  function resolveSkillsMaintenanceRoot(cwd) {
@@ -1483,11 +1668,17 @@ var listCommand2 = new Command8("list").alias("ls").description(
1483
1668
  const pkg = installedManifest?.installed.find(
1484
1669
  (p) => p.package === SKILLS_PACKAGE
1485
1670
  );
1671
+ const skillsLock = await readSkillsLock(projectRoot);
1486
1672
  const installedBySkill = /* @__PURE__ */ new Map();
1487
1673
  for (const r of pkg?.resources ?? []) {
1488
1674
  const skillId = r.id.split(":")[0];
1489
1675
  installedBySkill.set(skillId, (installedBySkill.get(skillId) ?? 0) + 1);
1490
1676
  }
1677
+ for (const skillId of Object.keys(skillsLock?.skills ?? {})) {
1678
+ if (!installedBySkill.has(skillId)) {
1679
+ installedBySkill.set(skillId, 1);
1680
+ }
1681
+ }
1491
1682
  if (opts.installed) {
1492
1683
  if (!config?.packages?.skills || !pkg) {
1493
1684
  logger.info("No skills installed.");
@@ -1510,9 +1701,13 @@ var listCommand2 = new Command8("list").alias("ls").description(
1510
1701
  const skills = [...manifest.skills].sort(
1511
1702
  (a, b) => a.id.localeCompare(b.id)
1512
1703
  );
1513
- const isInstalled = !!config?.packages?.skills && !!pkg;
1514
- if (isInstalled) {
1704
+ const isInstalled = installedBySkill.size > 0;
1705
+ if (isInstalled && config?.packages?.skills && pkg) {
1515
1706
  printInstalledHeader(config.packages.skills, pkg.installedAt);
1707
+ } else if (isInstalled) {
1708
+ logger.info(
1709
+ `Installed (${installedBySkill.size} skill(s)) \u2014 config or manifest record missing; run "teamix-evo skills doctor" to repair.`
1710
+ );
1516
1711
  } else {
1517
1712
  logger.info("Skills package not yet added.");
1518
1713
  logger.info(
@@ -1649,7 +1844,7 @@ var updateCommand2 = new Command9("update").description("\u66F4\u65B0\u5DF2\u5B8
1649
1844
  import { Command as Command10 } from "commander";
1650
1845
  import * as prompts3 from "@clack/prompts";
1651
1846
  import * as path12 from "path";
1652
- import * as fs9 from "fs/promises";
1847
+ import * as fs10 from "fs/promises";
1653
1848
  var SKILLS_PACKAGE3 = "@teamix-evo/skills";
1654
1849
  var uninstallCommand2 = new Command10("uninstall").description(
1655
1850
  "\u5378\u8F7D\u5DF2\u5B89\u88C5\u7684 teamix-evo skills\uFF1B\u4E0D\u4F20 ids \u5219\u5378\u8F7D\u6574\u5305\uFF0C\u4F20 ids \u5219\u6309 skill \u5220\u9664"
@@ -1718,7 +1913,7 @@ async function runFullUninstall(args) {
1718
1913
  logger.debug(`Removed ${removed.length} files`);
1719
1914
  const skillsRoot = getSkillsSourceDir(projectRoot);
1720
1915
  try {
1721
- await fs9.rm(skillsRoot, { recursive: true, force: true });
1916
+ await fs10.rm(skillsRoot, { recursive: true, force: true });
1722
1917
  logger.debug(`Removed source dir ${skillsRoot}`);
1723
1918
  } catch (err) {
1724
1919
  logger.warn(
@@ -1771,7 +1966,7 @@ async function runPartialUninstall(args) {
1771
1966
  for (const id of matched) {
1772
1967
  const dir = getSkillsSourceDir(projectRoot, id);
1773
1968
  try {
1774
- await fs9.rm(dir, { recursive: true, force: true });
1969
+ await fs10.rm(dir, { recursive: true, force: true });
1775
1970
  logger.debug(`Removed source dir ${dir}`);
1776
1971
  } catch (err) {
1777
1972
  logger.warn(`Failed to remove ${dir}: ${err.message}`);
@@ -1815,7 +2010,26 @@ function dedupe(values) {
1815
2010
  import { Command as Command11 } from "commander";
1816
2011
 
1817
2012
  // src/core/skills-sync.ts
1818
- import * as fs10 from "fs/promises";
2013
+ import * as path13 from "path";
2014
+ import * as fs11 from "fs/promises";
2015
+ import { createRequire as createRequire4 } from "module";
2016
+ import { loadSkillsPackageManifest as loadSkillsPackageManifest2 } from "@teamix-evo/registry";
2017
+ var require5 = createRequire4(import.meta.url);
2018
+ async function readSkillMetaFromUpstream(skillId) {
2019
+ try {
2020
+ const pkgJson = require5.resolve("@teamix-evo/skills/package.json");
2021
+ const packageRoot = path13.dirname(pkgJson);
2022
+ const manifest = await loadSkillsPackageManifest2(packageRoot);
2023
+ const entry = manifest.skills.find((s) => s.id === skillId);
2024
+ if (!entry) return null;
2025
+ return {
2026
+ updateStrategy: entry.updateStrategy,
2027
+ managedRegions: entry.managedRegions
2028
+ };
2029
+ } catch {
2030
+ return null;
2031
+ }
2032
+ }
1819
2033
  var SKILLS_PACKAGE_DEFAULT = "@teamix-evo/skills";
1820
2034
  async function runSkillsSync(options) {
1821
2035
  const { projectRoot, names } = options;
@@ -1849,13 +2063,15 @@ async function runSkillsSync(options) {
1849
2063
  logger.warn(`Skill "${skillId}" has no IDE mirror targets; skipped.`);
1850
2064
  continue;
1851
2065
  }
2066
+ const upstreamMeta = await readSkillMetaFromUpstream(skillId);
1852
2067
  const result = await syncSkillsToIdes({
1853
2068
  projectRoot,
1854
2069
  skills: [
1855
2070
  {
1856
2071
  id: skillId,
1857
2072
  name: skillId,
1858
- updateStrategy: "regenerable"
2073
+ updateStrategy: upstreamMeta?.updateStrategy ?? "regenerable",
2074
+ managedRegions: upstreamMeta?.managedRegions
1859
2075
  }
1860
2076
  ],
1861
2077
  ides,
@@ -1882,7 +2098,7 @@ async function runSkillsSync(options) {
1882
2098
  }
1883
2099
  async function dirExists(p) {
1884
2100
  try {
1885
- const stat4 = await fs10.stat(p);
2101
+ const stat4 = await fs11.stat(p);
1886
2102
  return stat4.isDirectory();
1887
2103
  } catch {
1888
2104
  return false;
@@ -1976,8 +2192,8 @@ function parseScope2(input) {
1976
2192
  import { Command as Command12 } from "commander";
1977
2193
 
1978
2194
  // src/core/skills-doctor.ts
1979
- import * as path13 from "path";
1980
- import * as fs11 from "fs/promises";
2195
+ import * as path14 from "path";
2196
+ import * as fs12 from "fs/promises";
1981
2197
  async function runSkillsDoctor(options) {
1982
2198
  const { projectRoot } = options;
1983
2199
  const lock = await readSkillsLock(projectRoot);
@@ -1999,8 +2215,8 @@ async function runSkillsDoctor(options) {
1999
2215
  const sourceFiles = await walkDir(sourceDir);
2000
2216
  const sourceContents = /* @__PURE__ */ new Map();
2001
2217
  for (const f of sourceFiles) {
2002
- const rel2 = path13.relative(sourceDir, f);
2003
- sourceContents.set(rel2, await fs11.readFile(f, "utf-8"));
2218
+ const rel2 = path14.relative(sourceDir, f);
2219
+ sourceContents.set(rel2, await fs12.readFile(f, "utf-8"));
2004
2220
  }
2005
2221
  for (const ide of entry.mirroredTo) {
2006
2222
  const adapter = getAdapter(ide);
@@ -2021,7 +2237,7 @@ async function runSkillsDoctor(options) {
2021
2237
  continue;
2022
2238
  }
2023
2239
  for (const [rel2, sourceContent] of sourceContents.entries()) {
2024
- const mirrorFile = path13.join(mirrorDir, rel2);
2240
+ const mirrorFile = path14.join(mirrorDir, rel2);
2025
2241
  if (!await fileExists(mirrorFile)) {
2026
2242
  findings.push({
2027
2243
  kind: "missing-mirror",
@@ -2033,7 +2249,7 @@ async function runSkillsDoctor(options) {
2033
2249
  });
2034
2250
  continue;
2035
2251
  }
2036
- const mirrorContent = await fs11.readFile(mirrorFile, "utf-8");
2252
+ const mirrorContent = await fs12.readFile(mirrorFile, "utf-8");
2037
2253
  if (computeHash(mirrorContent) !== computeHash(sourceContent)) {
2038
2254
  findings.push({
2039
2255
  kind: "mirror-drift",
@@ -2054,7 +2270,7 @@ async function runSkillsDoctor(options) {
2054
2270
  }
2055
2271
  async function dirExists2(p) {
2056
2272
  try {
2057
- const stat4 = await fs11.stat(p);
2273
+ const stat4 = await fs12.stat(p);
2058
2274
  return stat4.isDirectory();
2059
2275
  } catch {
2060
2276
  return false;
@@ -2119,6 +2335,35 @@ import { Command as Command14 } from "commander";
2119
2335
  import * as prompts4 from "@clack/prompts";
2120
2336
 
2121
2337
  // src/core/ui-init.ts
2338
+ import * as fs13 from "fs/promises";
2339
+ import { createRequire as createRequire5 } from "module";
2340
+ import * as path15 from "path";
2341
+ var require6 = createRequire5(import.meta.url);
2342
+ async function deployPreferencesCss(projectRoot) {
2343
+ const targetDir = path15.join(projectRoot, "src");
2344
+ const targetPath = path15.join(targetDir, "preferences.css");
2345
+ try {
2346
+ await fs13.access(targetPath);
2347
+ logger.debug(`preferences.css already exists at ${targetPath}, skipping`);
2348
+ return "skipped";
2349
+ } catch {
2350
+ }
2351
+ let sourcePath;
2352
+ try {
2353
+ const uiPkgJson = require6.resolve("@teamix-evo/ui/package.json");
2354
+ sourcePath = path15.join(path15.dirname(uiPkgJson), "src", "preferences.css");
2355
+ await fs13.access(sourcePath);
2356
+ } catch {
2357
+ logger.debug(
2358
+ "Could not resolve @teamix-evo/ui/src/preferences.css; skipping deploy"
2359
+ );
2360
+ return "source-missing";
2361
+ }
2362
+ await fs13.mkdir(targetDir, { recursive: true });
2363
+ const content = await fs13.readFile(sourcePath, "utf-8");
2364
+ await fs13.writeFile(targetPath, content, "utf-8");
2365
+ return "deployed";
2366
+ }
2122
2367
  var DEFAULT_UI_ALIASES = {
2123
2368
  components: "src/components/ui",
2124
2369
  hooks: "src/hooks",
@@ -2162,12 +2407,14 @@ async function runUiInit(options) {
2162
2407
  rsc
2163
2408
  };
2164
2409
  await writeProjectConfig(projectRoot, config);
2410
+ const preferencesCss = await deployPreferencesCss(projectRoot);
2165
2411
  return {
2166
2412
  status: "installed",
2167
2413
  aliases,
2168
2414
  iconLibrary,
2169
2415
  tsx,
2170
- rsc
2416
+ rsc,
2417
+ preferencesCss
2171
2418
  };
2172
2419
  }
2173
2420
 
@@ -2204,6 +2451,14 @@ var initCommand2 = new Command14("init").description(
2204
2451
  logger.info(` lib: ${result.aliases.lib}`);
2205
2452
  logger.info(` iconLibrary: ${result.iconLibrary}`);
2206
2453
  logger.info(` tsx: ${result.tsx}, rsc: ${result.rsc}`);
2454
+ if (result.preferencesCss === "deployed") {
2455
+ logger.info(" preferences.css: deployed \u2192 src/preferences.css");
2456
+ logger.info(
2457
+ " \u5728 src/index.css \u9876\u90E8\u52A0 `@import './preferences.css';` \u542F\u7528 shadcn \u5168\u5C40\u504F\u597D"
2458
+ );
2459
+ } else if (result.preferencesCss === "skipped") {
2460
+ logger.info(" preferences.css: \u5DF2\u5B58\u5728,\u4FDD\u7559\u7528\u6237\u7248\u672C");
2461
+ }
2207
2462
  logger.info("");
2208
2463
  logger.info("Next: `npx teamix-evo ui add button`");
2209
2464
  } catch (err) {
@@ -2282,23 +2537,23 @@ async function resolveConfig(opts) {
2282
2537
  import { Command as Command15 } from "commander";
2283
2538
 
2284
2539
  // src/core/ui-client.ts
2285
- import * as path14 from "path";
2286
- import * as fs12 from "fs/promises";
2287
- import { createRequire as createRequire3 } from "module";
2540
+ import * as path16 from "path";
2541
+ import * as fs14 from "fs/promises";
2542
+ import { createRequire as createRequire6 } from "module";
2288
2543
  import { loadUiPackageManifest } from "@teamix-evo/registry";
2289
- var require4 = createRequire3(import.meta.url);
2544
+ var require7 = createRequire6(import.meta.url);
2290
2545
  function resolvePackageRoot2(packageName) {
2291
- const pkgJsonPath = require4.resolve(`${packageName}/package.json`);
2292
- return path14.dirname(pkgJsonPath);
2546
+ const pkgJsonPath = require7.resolve(`${packageName}/package.json`);
2547
+ return path16.dirname(pkgJsonPath);
2293
2548
  }
2294
2549
  async function loadUiData(packageName) {
2295
2550
  const packageRoot = resolvePackageRoot2(packageName);
2296
2551
  logger.debug(`Resolved ui package root: ${packageRoot}`);
2297
2552
  const manifest = await loadUiPackageManifest(packageRoot);
2298
2553
  let data = {};
2299
- const dataPath = path14.join(packageRoot, "_data.json");
2554
+ const dataPath = path16.join(packageRoot, "_data.json");
2300
2555
  try {
2301
- const raw = await fs12.readFile(dataPath, "utf-8");
2556
+ const raw = await fs14.readFile(dataPath, "utf-8");
2302
2557
  data = JSON.parse(raw);
2303
2558
  } catch (err) {
2304
2559
  if (err.code !== "ENOENT") {
@@ -2310,8 +2565,8 @@ async function loadUiData(packageName) {
2310
2565
  }
2311
2566
 
2312
2567
  // src/core/ui-installer.ts
2313
- import * as path15 from "path";
2314
- import * as fs13 from "fs/promises";
2568
+ import * as path17 from "path";
2569
+ import * as fs15 from "fs/promises";
2315
2570
  import { resolveUiEntryOrder } from "@teamix-evo/registry";
2316
2571
 
2317
2572
  // src/utils/transform-imports.ts
@@ -2351,12 +2606,12 @@ function aliasToImportPath(alias) {
2351
2606
  }
2352
2607
 
2353
2608
  // src/core/ui-installer.ts
2354
- var DESIGN_COMPONENTS_DIR = ".teamix-evo/design/components";
2355
2609
  async function installUiEntries(options) {
2356
2610
  const {
2357
2611
  projectRoot,
2358
2612
  manifest,
2359
2613
  packageRoot,
2614
+ entryPackageRoot,
2360
2615
  aliases,
2361
2616
  requested,
2362
2617
  skipExisting = true
@@ -2365,7 +2620,6 @@ async function installUiEntries(options) {
2365
2620
  const idToEntry = new Map(manifest.entries.map((e) => [e.id, e]));
2366
2621
  const resources = [];
2367
2622
  const npmDeps = {};
2368
- const metaFiles = [];
2369
2623
  let written = 0;
2370
2624
  let skipped = 0;
2371
2625
  for (const id of orderedIds) {
@@ -2384,8 +2638,9 @@ async function installUiEntries(options) {
2384
2638
  skipped++;
2385
2639
  continue;
2386
2640
  }
2387
- const sourceAbs = path15.resolve(packageRoot, file.source);
2388
- const raw = await fs13.readFile(sourceAbs, "utf-8");
2641
+ const rootForEntry = entryPackageRoot?.get(entry.id) ?? packageRoot;
2642
+ const sourceAbs = path17.resolve(rootForEntry, file.source);
2643
+ const raw = await fs15.readFile(sourceAbs, "utf-8");
2389
2644
  const transformed = rewriteImports(raw, aliases);
2390
2645
  await writeFileSafe(targetAbs, transformed);
2391
2646
  written++;
@@ -2397,32 +2652,13 @@ async function installUiEntries(options) {
2397
2652
  strategy: entry.updateStrategy ?? "frozen"
2398
2653
  });
2399
2654
  }
2400
- if (entry.meta) {
2401
- const metaSourceAbs = path15.resolve(packageRoot, entry.meta);
2402
- const metaContent = await fs13.readFile(metaSourceAbs, "utf-8");
2403
- const metaTargetAbs = path15.join(
2404
- projectRoot,
2405
- DESIGN_COMPONENTS_DIR,
2406
- `${entry.id}.meta.md`
2407
- );
2408
- await writeFileSafe(metaTargetAbs, metaContent);
2409
- metaFiles.push(metaTargetAbs);
2410
- resources.push({
2411
- id: `${entry.id}:meta`,
2412
- target: metaTargetAbs,
2413
- hash: computeHash(metaContent),
2414
- strategy: "regenerable"
2415
- });
2416
- logger.info(` meta: ${rel(projectRoot, metaTargetAbs)}`);
2417
- }
2418
2655
  }
2419
2656
  return {
2420
2657
  orderedIds,
2421
2658
  resources,
2422
2659
  npmDependencies: npmDeps,
2423
2660
  written,
2424
- skipped,
2425
- metaFiles
2661
+ skipped
2426
2662
  };
2427
2663
  }
2428
2664
  function resolveTargetPath(projectRoot, aliases, entry, file) {
@@ -2432,10 +2668,10 @@ function resolveTargetPath(projectRoot, aliases, entry, file) {
2432
2668
  `Entry "${entry.id}" requires alias "${file.targetAlias}" but it is not configured.`
2433
2669
  );
2434
2670
  }
2435
- return path15.join(projectRoot, aliasDir, file.targetName);
2671
+ return path17.join(projectRoot, aliasDir, file.targetName);
2436
2672
  }
2437
2673
  function rel(projectRoot, abs) {
2438
- return path15.relative(projectRoot, abs);
2674
+ return path17.relative(projectRoot, abs);
2439
2675
  }
2440
2676
 
2441
2677
  // src/core/ui-add.ts
@@ -2497,7 +2733,6 @@ async function runUiAdd(options) {
2497
2733
  orderedIds: result.orderedIds,
2498
2734
  written: result.written,
2499
2735
  skipped: result.skipped,
2500
- metaFiles: result.metaFiles,
2501
2736
  npmDependencies: result.npmDependencies,
2502
2737
  resources: result.resources
2503
2738
  };
@@ -2523,7 +2758,7 @@ var addCommand2 = new Command15("add").description(
2523
2758
  overwrite: opts.overwrite
2524
2759
  });
2525
2760
  logger.success(
2526
- `UI add complete: ${result.written} written, ${result.skipped} skipped, ${result.metaFiles.length} meta.`
2761
+ `UI add complete: ${result.written} written, ${result.skipped} skipped.`
2527
2762
  );
2528
2763
  logger.info("");
2529
2764
  logger.info(`Resolved order: ${result.orderedIds.join(" \u2192 ")}`);
@@ -2535,12 +2770,6 @@ var addCommand2 = new Command15("add").description(
2535
2770
  logger.info(` pnpm add ${installCmd}`);
2536
2771
  logger.info(` # or: npm install ${installCmd}`);
2537
2772
  }
2538
- if (result.metaFiles.length > 0) {
2539
- logger.info("");
2540
- logger.info(
2541
- "Component meta dropped under .teamix-evo/design/components/ (AI-readable)."
2542
- );
2543
- }
2544
2773
  } catch (err) {
2545
2774
  const message = err.message;
2546
2775
  if (message.startsWith("UI not initialized")) {
@@ -2640,22 +2869,23 @@ uiCommand.addCommand(addCommand2);
2640
2869
  uiCommand.addCommand(listCommand3);
2641
2870
 
2642
2871
  // src/commands/biz-ui/index.ts
2643
- import { Command as Command20 } from "commander";
2872
+ import { Command as Command21 } from "commander";
2644
2873
 
2645
2874
  // src/commands/biz-ui/add.ts
2646
2875
  import { Command as Command18 } from "commander";
2647
2876
 
2648
2877
  // src/core/variant-ui-add.ts
2649
- import * as path16 from "path";
2650
- import { createRequire as createRequire4 } from "module";
2878
+ import * as path18 from "path";
2879
+ import { createRequire as createRequire7 } from "module";
2651
2880
  import {
2881
+ loadUiPackageManifest as loadUiPackageManifest2,
2652
2882
  loadVariantUiPackageCatalog,
2653
2883
  loadVariantUiPackageManifest
2654
2884
  } from "@teamix-evo/registry";
2655
- var require5 = createRequire4(import.meta.url);
2885
+ var require8 = createRequire7(import.meta.url);
2656
2886
  function resolvePackageRoot3(packageName) {
2657
- const pkgJsonPath = require5.resolve(`${packageName}/package.json`);
2658
- return path16.dirname(pkgJsonPath);
2887
+ const pkgJsonPath = require8.resolve(`${packageName}/package.json`);
2888
+ return path18.dirname(pkgJsonPath);
2659
2889
  }
2660
2890
  async function runVariantUiAdd(packageName, options) {
2661
2891
  const { projectRoot, variant, ids, overwrite } = options;
@@ -2678,27 +2908,42 @@ async function runVariantUiAdd(packageName, options) {
2678
2908
  `Variant "${variant}" not found in ${fullPackageName}. Known variants: ${known}. Hint: \`teamix-evo ${packageName} list-variants\` shows all.`
2679
2909
  );
2680
2910
  }
2681
- const variantDir = path16.join(packageRoot, "variants", variant);
2911
+ const variantDir = path18.join(packageRoot, "variants", variant);
2682
2912
  const variantManifest = await loadVariantUiPackageManifest(variantDir);
2683
2913
  const knownIds = new Set(variantManifest.entries.map((e) => e.id));
2684
2914
  const unknown = ids.filter((id) => !knownIds.has(id));
2685
2915
  if (unknown.length > 0) {
2686
2916
  throw new Error(
2687
- `Unknown entry id(s) in ${packageName}#${variant}: ${unknown.map((s) => `"${s}"`).join(", ")}. Run \`teamix-evo ${packageName} list --variant ${variant}\` to see options.`
2917
+ `Unknown entry id(s) in ${packageName}#${variant}: ${unknown.map((s) => `"${s}"`).join(", ")}. Run \`teamix-evo ${packageName} list-variants\` to see this package's variants, or \`teamix-evo ${packageName} list --variant ${variant}\` for its entries.`
2688
2918
  );
2689
2919
  }
2920
+ const uiPackageRoot = resolvePackageRoot3("@teamix-evo/ui");
2921
+ const uiManifest = await loadUiPackageManifest2(uiPackageRoot);
2922
+ const entryPackageRoot = /* @__PURE__ */ new Map();
2923
+ const mergedEntries = [];
2924
+ for (const e of variantManifest.entries) {
2925
+ entryPackageRoot.set(e.id, variantDir);
2926
+ mergedEntries.push(e);
2927
+ }
2928
+ for (const e of uiManifest.entries) {
2929
+ if (entryPackageRoot.has(e.id)) continue;
2930
+ entryPackageRoot.set(e.id, uiPackageRoot);
2931
+ mergedEntries.push(e);
2932
+ }
2690
2933
  const adaptedManifest = {
2691
2934
  schemaVersion: 1,
2692
2935
  package: "ui",
2693
2936
  version: variantManifest.version,
2694
2937
  engines: variantManifest.engines,
2695
- entries: variantManifest.entries
2938
+ entries: mergedEntries
2696
2939
  };
2697
2940
  const result = await installUiEntries({
2698
2941
  projectRoot,
2699
2942
  manifest: adaptedManifest,
2700
2943
  packageRoot: variantDir,
2701
- // sources resolved relative to variant dir
2944
+ // default for variant entries
2945
+ entryPackageRoot,
2946
+ // ui entries resolve from uiPackageRoot
2702
2947
  aliases: uiCfg.aliases,
2703
2948
  requested: ids,
2704
2949
  skipExisting: !overwrite
@@ -2730,7 +2975,6 @@ async function runVariantUiAdd(packageName, options) {
2730
2975
  orderedIds: result.orderedIds,
2731
2976
  written: result.written,
2732
2977
  skipped: result.skipped,
2733
- metaFiles: result.metaFiles,
2734
2978
  npmDependencies: result.npmDependencies,
2735
2979
  resources: result.resources
2736
2980
  };
@@ -2767,6 +3011,36 @@ async function listBizUiVariants(packageRoot) {
2767
3011
  async function listTemplatesVariants(packageRoot) {
2768
3012
  return listVariantUi("templates", packageRoot);
2769
3013
  }
3014
+ async function listVariantUiEntries(packageName, variant, packageRoot) {
3015
+ const fullPackageName = `@teamix-evo/${packageName}`;
3016
+ const root = packageRoot ?? resolvePackageRoot3(fullPackageName);
3017
+ const catalog = await loadVariantUiPackageCatalog(root);
3018
+ if (!catalog.variants.some((v) => v.name === variant)) {
3019
+ const known = catalog.variants.map((v) => v.name).join(", ");
3020
+ throw new Error(
3021
+ `Variant "${variant}" not found in ${fullPackageName}. Known: ${known}.`
3022
+ );
3023
+ }
3024
+ const variantDir = path18.join(root, "variants", variant);
3025
+ const variantManifest = await loadVariantUiPackageManifest(variantDir);
3026
+ return {
3027
+ packageName: fullPackageName,
3028
+ variant,
3029
+ entries: variantManifest.entries.map((e) => ({
3030
+ id: e.id,
3031
+ name: e.name,
3032
+ type: e.type,
3033
+ description: e.description,
3034
+ registryDependencies: e.registryDependencies ?? []
3035
+ }))
3036
+ };
3037
+ }
3038
+ async function listBizUiEntries(variant, packageRoot) {
3039
+ return listVariantUiEntries("biz-ui", variant, packageRoot);
3040
+ }
3041
+ async function listTemplatesEntries(variant, packageRoot) {
3042
+ return listVariantUiEntries("templates", variant, packageRoot);
3043
+ }
2770
3044
 
2771
3045
  // src/commands/biz-ui/add.ts
2772
3046
  var addCommand3 = new Command18("add").description(
@@ -2791,7 +3065,7 @@ var addCommand3 = new Command18("add").description(
2791
3065
  overwrite: opts.overwrite
2792
3066
  });
2793
3067
  logger.success(
2794
- `biz-ui add complete: ${result.written} written, ${result.skipped} skipped, ${result.metaFiles.length} meta.`
3068
+ `biz-ui add complete: ${result.written} written, ${result.skipped} skipped.`
2795
3069
  );
2796
3070
  logger.info("");
2797
3071
  logger.info(`Variant: ${result.variant}`);
@@ -2811,9 +3085,35 @@ var addCommand3 = new Command18("add").description(
2811
3085
  }
2812
3086
  );
2813
3087
 
2814
- // src/commands/biz-ui/list-variants.ts
3088
+ // src/commands/biz-ui/list.ts
2815
3089
  import { Command as Command19 } from "commander";
2816
- var listVariantsCommand2 = new Command19("list-variants").description("\u5217\u51FA @teamix-evo/biz-ui \u5305\u5185\u63D0\u4F9B\u7684\u6240\u6709\u4E1A\u52A1\u53D8\u4F53").action(async () => {
3090
+ var listCommand4 = new Command19("list").description("\u5217\u51FA\u6307\u5B9A\u53D8\u4F53\u4E0B\u7684 biz-ui entries").requiredOption("--variant <name>", "\u53D8\u4F53\u540D\uFF08\u5982 opentrek / uni-manager\uFF09").action(async (opts) => {
3091
+ try {
3092
+ const result = await listBizUiEntries(opts.variant);
3093
+ logger.info(`${result.packageName}#${result.variant} entries:`);
3094
+ logger.info("");
3095
+ if (result.entries.length === 0) {
3096
+ logger.info(" (no entries \u2014 variant skeleton, awaiting components)");
3097
+ return;
3098
+ }
3099
+ for (const e of result.entries) {
3100
+ const deps = e.registryDependencies.length ? ` [deps: ${e.registryDependencies.join(", ")}]` : "";
3101
+ logger.info(` ${e.id} (${e.type})${deps}`);
3102
+ if (e.description) logger.info(` ${e.description}`);
3103
+ logger.info("");
3104
+ }
3105
+ logger.info(
3106
+ `Install: teamix-evo biz-ui add <id> --variant ${result.variant}`
3107
+ );
3108
+ } catch (err) {
3109
+ logger.error(`Failed: ${err.message}`);
3110
+ process.exitCode = 1;
3111
+ }
3112
+ });
3113
+
3114
+ // src/commands/biz-ui/list-variants.ts
3115
+ import { Command as Command20 } from "commander";
3116
+ var listVariantsCommand2 = new Command20("list-variants").description("\u5217\u51FA @teamix-evo/biz-ui \u5305\u5185\u63D0\u4F9B\u7684\u6240\u6709\u4E1A\u52A1\u53D8\u4F53").action(async () => {
2817
3117
  try {
2818
3118
  const result = await listBizUiVariants();
2819
3119
  logger.info(`Available biz-ui variants in ${result.packageName}:`);
@@ -2835,18 +3135,19 @@ var listVariantsCommand2 = new Command19("list-variants").description("\u5217\u5
2835
3135
  });
2836
3136
 
2837
3137
  // src/commands/biz-ui/index.ts
2838
- var bizUiCommand = new Command20("biz-ui").description(
3138
+ var bizUiCommand = new Command21("biz-ui").description(
2839
3139
  "\u7BA1\u7406\u4E1A\u52A1 UI \u7EC4\u4EF6(\u53D8\u4F53\u611F\u77E5 \u2014 \u4E0E design / templates \u540C\u53D8\u4F53\u540D\u7A7A\u95F4)"
2840
3140
  );
2841
3141
  bizUiCommand.addCommand(addCommand3);
3142
+ bizUiCommand.addCommand(listCommand4);
2842
3143
  bizUiCommand.addCommand(listVariantsCommand2);
2843
3144
 
2844
3145
  // src/commands/templates/index.ts
2845
- import { Command as Command23 } from "commander";
3146
+ import { Command as Command25 } from "commander";
2846
3147
 
2847
3148
  // src/commands/templates/add.ts
2848
- import { Command as Command21 } from "commander";
2849
- var addCommand4 = new Command21("add").description(
3149
+ import { Command as Command22 } from "commander";
3150
+ var addCommand4 = new Command22("add").description(
2850
3151
  "\u5B89\u88C5\u4E00\u4E2A\u6216\u591A\u4E2A\u9875\u9762\u6A21\u677F(\u6309 id,\u81EA\u52A8\u5C55\u5F00 ui \u5305\u7684 registryDependencies)"
2851
3152
  ).argument("<ids...>", '\u6A21\u677F id \u5217\u8868,\u5982 "list-detail-page"').option("--variant <name>", '\u53D8\u4F53 id(\u5FC5\u586B,\u5982 "opentrek"\u3001"uni-manager")').option("--overwrite", "\u5373\u4F7F\u76EE\u6807\u6587\u4EF6\u5DF2\u5B58\u5728\u4E5F\u8986\u76D6").action(
2852
3153
  async (ids, opts) => {
@@ -2868,7 +3169,7 @@ var addCommand4 = new Command21("add").description(
2868
3169
  overwrite: opts.overwrite
2869
3170
  });
2870
3171
  logger.success(
2871
- `templates add complete: ${result.written} written, ${result.skipped} skipped, ${result.metaFiles.length} meta.`
3172
+ `templates add complete: ${result.written} written, ${result.skipped} skipped.`
2872
3173
  );
2873
3174
  logger.info("");
2874
3175
  logger.info(`Variant: ${result.variant}`);
@@ -2888,9 +3189,35 @@ var addCommand4 = new Command21("add").description(
2888
3189
  }
2889
3190
  );
2890
3191
 
3192
+ // src/commands/templates/list.ts
3193
+ import { Command as Command23 } from "commander";
3194
+ var listCommand5 = new Command23("list").description("\u5217\u51FA\u6307\u5B9A\u53D8\u4F53\u4E0B\u7684 templates entries").requiredOption("--variant <name>", "\u53D8\u4F53\u540D\uFF08\u5982 opentrek / uni-manager\uFF09").action(async (opts) => {
3195
+ try {
3196
+ const result = await listTemplatesEntries(opts.variant);
3197
+ logger.info(`${result.packageName}#${result.variant} entries:`);
3198
+ logger.info("");
3199
+ if (result.entries.length === 0) {
3200
+ logger.info(" (no entries \u2014 variant skeleton, awaiting templates)");
3201
+ return;
3202
+ }
3203
+ for (const e of result.entries) {
3204
+ const deps = e.registryDependencies.length ? ` [deps: ${e.registryDependencies.join(", ")}]` : "";
3205
+ logger.info(` ${e.id} (${e.type})${deps}`);
3206
+ if (e.description) logger.info(` ${e.description}`);
3207
+ logger.info("");
3208
+ }
3209
+ logger.info(
3210
+ `Install: teamix-evo templates add <id> --variant ${result.variant}`
3211
+ );
3212
+ } catch (err) {
3213
+ logger.error(`Failed: ${err.message}`);
3214
+ process.exitCode = 1;
3215
+ }
3216
+ });
3217
+
2891
3218
  // src/commands/templates/list-variants.ts
2892
- import { Command as Command22 } from "commander";
2893
- var listVariantsCommand3 = new Command22("list-variants").description("\u5217\u51FA @teamix-evo/templates \u5305\u5185\u63D0\u4F9B\u7684\u6240\u6709\u9875\u9762\u6A21\u677F\u53D8\u4F53").action(async () => {
3219
+ import { Command as Command24 } from "commander";
3220
+ var listVariantsCommand3 = new Command24("list-variants").description("\u5217\u51FA @teamix-evo/templates \u5305\u5185\u63D0\u4F9B\u7684\u6240\u6709\u9875\u9762\u6A21\u677F\u53D8\u4F53").action(async () => {
2894
3221
  try {
2895
3222
  const result = await listTemplatesVariants();
2896
3223
  logger.info(`Available templates variants in ${result.packageName}:`);
@@ -2912,21 +3239,216 @@ var listVariantsCommand3 = new Command22("list-variants").description("\u5217\u5
2912
3239
  });
2913
3240
 
2914
3241
  // src/commands/templates/index.ts
2915
- var templatesCommand = new Command23("templates").description(
3242
+ var templatesCommand = new Command25("templates").description(
2916
3243
  "\u7BA1\u7406\u9875\u9762\u6A21\u677F(\u53D8\u4F53\u611F\u77E5 \u2014 \u4E0E design / biz-ui \u540C\u53D8\u4F53\u540D\u7A7A\u95F4)"
2917
3244
  );
2918
3245
  templatesCommand.addCommand(addCommand4);
3246
+ templatesCommand.addCommand(listCommand5);
2919
3247
  templatesCommand.addCommand(listVariantsCommand3);
2920
3248
 
3249
+ // src/commands/logs/index.ts
3250
+ import { Command as Command27 } from "commander";
3251
+
3252
+ // src/commands/logs/analyze.ts
3253
+ import { Command as Command26 } from "commander";
3254
+ import { readFileSync, readdirSync, existsSync as existsSync2, statSync } from "fs";
3255
+ import { resolve as resolve3, join as join17 } from "path";
3256
+ var DATE_DIR_RE = /^\d{4}-\d{2}-\d{2}$/;
3257
+ var logsAnalyzeCommand = new Command26("analyze").description(
3258
+ "\u6C47\u603B vibe-logger \u8F93\u51FA (.log/ai/**/*.jsonl) \u2014 \u5DE5\u5177 / \u5305\u6807\u7B7E / MCP \u8C03\u7528\u9891\u7387,\u8F85\u52A9\u751F\u6001\u4F18\u5316"
3259
+ ).option("--dir <path>", "log \u76EE\u5F55 (\u9ED8\u8BA4 <project>/.log/ai)").option(
3260
+ "--days <n>",
3261
+ "\u53EA\u770B\u6700\u8FD1 N \u5929\u7684\u76EE\u5F55 (\u9ED8\u8BA4\u5168\u90E8;\u6309\u76EE\u5F55\u540D YYYY-MM-DD \u6BD4\u5BF9,\u4E0D\u89E3\u6790\u8BB0\u5F55 ts)"
3262
+ ).option("--top <n>", "\u6BCF\u4E2A\u6392\u884C\u5C55\u793A\u524D N \u9879 (\u9ED8\u8BA4 10)", "10").option("--json", "\u4EE5 JSON \u8F93\u51FA (CI/\u5DE5\u5177\u53CB\u597D)").action((opts) => {
3263
+ const baseDir = resolve3(opts.dir ?? join17(process.cwd(), ".log", "ai"));
3264
+ if (!existsSync2(baseDir)) {
3265
+ logger.warn(`No log directory at ${baseDir}.`);
3266
+ logger.info(
3267
+ "\u8FD0\u884C vibe-logger hook \u89E6\u53D1\u540E\u4F1A\u5728\u6B64\u76EE\u5F55\u751F\u6210 JSONL \u2014 \u89C1 .claude/scripts/vibe-logger.mjs"
3268
+ );
3269
+ return;
3270
+ }
3271
+ const dayLimit = parseIntOrUndef(opts.days);
3272
+ const top = parseIntOrUndef(opts.top) ?? 10;
3273
+ const dayDirs = readdirSync(baseDir, { withFileTypes: true }).filter((e) => e.isDirectory() && DATE_DIR_RE.test(e.name)).map((e) => e.name).sort().reverse();
3274
+ const selected = dayLimit !== void 0 ? dayDirs.slice(0, dayLimit) : dayDirs;
3275
+ const records = [];
3276
+ for (const day of selected) {
3277
+ const dayPath = join17(baseDir, day);
3278
+ let entries;
3279
+ try {
3280
+ entries = readdirSync(dayPath);
3281
+ } catch {
3282
+ continue;
3283
+ }
3284
+ for (const entry of entries) {
3285
+ if (!entry.endsWith(".jsonl")) continue;
3286
+ const fp = join17(dayPath, entry);
3287
+ try {
3288
+ if (!statSync(fp).isFile()) continue;
3289
+ } catch {
3290
+ continue;
3291
+ }
3292
+ const text2 = readFileSync(fp, "utf8");
3293
+ for (const line of text2.split("\n")) {
3294
+ if (!line.trim()) continue;
3295
+ try {
3296
+ records.push(JSON.parse(line));
3297
+ } catch {
3298
+ }
3299
+ }
3300
+ }
3301
+ }
3302
+ const report = buildReport(records, top);
3303
+ if (opts.json) {
3304
+ process.stdout.write(JSON.stringify(report, null, 2) + "\n");
3305
+ return;
3306
+ }
3307
+ printReport(baseDir, selected.length, report);
3308
+ });
3309
+ function buildReport(records, top) {
3310
+ const byAgent = {};
3311
+ const byEvent = {};
3312
+ const tools = /* @__PURE__ */ new Map();
3313
+ const tags = /* @__PURE__ */ new Map();
3314
+ const mcp = /* @__PURE__ */ new Map();
3315
+ const sessions = /* @__PURE__ */ new Set();
3316
+ const filesTouched = /* @__PURE__ */ new Set();
3317
+ const errors = [];
3318
+ let from = null;
3319
+ let to = null;
3320
+ for (const r of records) {
3321
+ if (!from || r.ts < from) from = r.ts;
3322
+ if (!to || r.ts > to) to = r.ts;
3323
+ byAgent[r.agent] = (byAgent[r.agent] ?? 0) + 1;
3324
+ byEvent[r.event] = (byEvent[r.event] ?? 0) + 1;
3325
+ sessions.add(`${r.agent}::${r.session}`);
3326
+ if (r.file) filesTouched.add(r.file);
3327
+ if (r.tool) {
3328
+ tools.set(r.tool, (tools.get(r.tool) ?? 0) + 1);
3329
+ if (r.tool.startsWith("mcp__")) {
3330
+ const name = r.tool.replace(/^mcp__[^_]+__/, "");
3331
+ const slot = mcp.get(name) ?? { count: 0, keys: /* @__PURE__ */ new Set() };
3332
+ slot.count += 1;
3333
+ for (const k of r.mcpArgs ?? []) slot.keys.add(k);
3334
+ mcp.set(name, slot);
3335
+ }
3336
+ }
3337
+ for (const tag of r.tags ?? []) {
3338
+ tags.set(tag, (tags.get(tag) ?? 0) + 1);
3339
+ }
3340
+ if (r.error) {
3341
+ errors.push({
3342
+ ts: r.ts,
3343
+ tool: r.tool,
3344
+ file: r.file,
3345
+ session: r.session
3346
+ });
3347
+ }
3348
+ }
3349
+ const topTools = sortAndSlice(tools, top).map(([tool, count]) => ({
3350
+ tool,
3351
+ count
3352
+ }));
3353
+ const topTags = sortAndSlice(tags, top).map(([tag, count]) => ({
3354
+ tag,
3355
+ count
3356
+ }));
3357
+ const topMcp = [...mcp.entries()].sort((a, b) => b[1].count - a[1].count).slice(0, top).map(([name, v]) => ({
3358
+ name,
3359
+ count: v.count,
3360
+ argKeys: [...v.keys].sort()
3361
+ }));
3362
+ const recentErrors = errors.slice(-10);
3363
+ return {
3364
+ range: { from, to },
3365
+ totals: {
3366
+ records: records.length,
3367
+ sessions: sessions.size,
3368
+ errors: errors.length,
3369
+ files: filesTouched.size
3370
+ },
3371
+ byAgent,
3372
+ byEvent,
3373
+ topTools,
3374
+ topTags,
3375
+ topMcp,
3376
+ recentErrors
3377
+ };
3378
+ }
3379
+ function sortAndSlice(m, top) {
3380
+ return [...m.entries()].sort((a, b) => b[1] - a[1]).slice(0, top);
3381
+ }
3382
+ function printReport(baseDir, dayCount, r) {
3383
+ logger.info(`vibe-logger \u5206\u6790\u62A5\u544A`);
3384
+ logger.info(` \u76EE\u5F55: ${baseDir}`);
3385
+ logger.info(` \u5929\u6570: ${dayCount}`);
3386
+ logger.info(` \u65F6\u95F4: ${r.range.from ?? "-"} \u2192 ${r.range.to ?? "-"}`);
3387
+ logger.info("");
3388
+ logger.info(
3389
+ `Totals records=${r.totals.records} sessions=${r.totals.sessions} errors=${r.totals.errors} files=${r.totals.files}`
3390
+ );
3391
+ logger.info(`By agent ${formatKv(r.byAgent)}`);
3392
+ logger.info(`By event ${formatKv(r.byEvent)}`);
3393
+ logger.info("");
3394
+ logger.info("Top tools:");
3395
+ for (const { tool, count } of r.topTools) {
3396
+ logger.info(` ${pad(count, 5)} ${tool}`);
3397
+ }
3398
+ if (r.topTags.length) {
3399
+ logger.info("");
3400
+ logger.info("Top package tags (which package the AI touched):");
3401
+ for (const { tag, count } of r.topTags) {
3402
+ logger.info(` ${pad(count, 5)} ${tag}`);
3403
+ }
3404
+ }
3405
+ if (r.topMcp.length) {
3406
+ logger.info("");
3407
+ logger.info("Top MCP tools:");
3408
+ for (const { name, count, argKeys } of r.topMcp) {
3409
+ const keys = argKeys.length ? ` args: ${argKeys.join(", ")}` : "";
3410
+ logger.info(` ${pad(count, 5)} ${name}${keys}`);
3411
+ }
3412
+ }
3413
+ if (r.recentErrors.length) {
3414
+ logger.info("");
3415
+ logger.info(`Recent errors (last ${r.recentErrors.length}):`);
3416
+ for (const e of r.recentErrors) {
3417
+ logger.info(
3418
+ ` ${e.ts} session=${e.session} tool=${e.tool ?? "-"} file=${e.file ?? "-"}`
3419
+ );
3420
+ }
3421
+ }
3422
+ }
3423
+ function formatKv(o) {
3424
+ return Object.entries(o).sort((a, b) => b[1] - a[1]).map(([k, v]) => `${k}=${v}`).join(" ");
3425
+ }
3426
+ function pad(n, width) {
3427
+ const s = String(n);
3428
+ return s.length >= width ? s : " ".repeat(width - s.length) + s;
3429
+ }
3430
+ function parseIntOrUndef(v) {
3431
+ if (v === void 0) return void 0;
3432
+ const n = Number.parseInt(v, 10);
3433
+ return Number.isFinite(n) && n > 0 ? n : void 0;
3434
+ }
3435
+
3436
+ // src/commands/logs/index.ts
3437
+ var logsCommand = new Command27("logs").description(
3438
+ "\u67E5\u8BE2 vibe-logger \u8F93\u51FA (.log/ai/**/*.jsonl) \u2014 AI \u8C03\u7528\u94FE\u5206\u6790"
3439
+ );
3440
+ logsCommand.addCommand(logsAnalyzeCommand);
3441
+
2921
3442
  // src/index.ts
2922
- var require6 = createRequire5(import.meta.url);
2923
- var { version } = require6("../package.json");
2924
- var program = new Command24();
3443
+ var require9 = createRequire8(import.meta.url);
3444
+ var { version } = require9("../package.json");
3445
+ var program = new Command28();
2925
3446
  program.name("teamix-evo").description("Where ideas evolve. \u2014 AI Coding \u5957\u4EF6").version(version);
2926
- program.addCommand(designCommand);
3447
+ program.addCommand(tokensCommand);
2927
3448
  program.addCommand(skillsCommand);
2928
3449
  program.addCommand(uiCommand);
2929
3450
  program.addCommand(bizUiCommand);
2930
3451
  program.addCommand(templatesCommand);
3452
+ program.addCommand(logsCommand);
2931
3453
  program.parse();
2932
3454
  //# sourceMappingURL=index.js.map