teamix-evo 0.16.0 → 0.17.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
@@ -582,7 +582,7 @@ var init_registry = __esm({
582
582
  });
583
583
 
584
584
  // src/index.ts
585
- import { Command as Command41 } from "commander";
585
+ import { Command as Command42 } from "commander";
586
586
  import { createRequire as createRequire9 } from "module";
587
587
 
588
588
  // src/commands/tokens/index.ts
@@ -807,9 +807,9 @@ async function installSkills(options) {
807
807
  async function renderSkillFiles(skill, options) {
808
808
  const { data, packageRoot } = options;
809
809
  const sourceAbs = path7.resolve(packageRoot, skill.source);
810
- const stat5 = await fs6.stat(sourceAbs);
810
+ const stat6 = await fs6.stat(sourceAbs);
811
811
  const rendered = /* @__PURE__ */ new Map();
812
- if (stat5.isFile()) {
812
+ if (stat6.isFile()) {
813
813
  const content = await renderSkillContent(sourceAbs, skill, data);
814
814
  rendered.set("SKILL.md", content);
815
815
  return rendered;
@@ -1072,13 +1072,13 @@ async function pruneEmptyIdeSkillDirs(args) {
1072
1072
  }
1073
1073
  for (const name of entries) {
1074
1074
  const dir = path7.join(skillsRoot, name);
1075
- let stat5;
1075
+ let stat6;
1076
1076
  try {
1077
- stat5 = await fs6.stat(dir);
1077
+ stat6 = await fs6.stat(dir);
1078
1078
  } catch {
1079
1079
  continue;
1080
1080
  }
1081
- if (!stat5.isDirectory()) continue;
1081
+ if (!stat6.isDirectory()) continue;
1082
1082
  let children;
1083
1083
  try {
1084
1084
  children = await fs6.readdir(dir);
@@ -5016,8 +5016,8 @@ async function runSkillsDoctor(options) {
5016
5016
  }
5017
5017
  async function dirExists(p2) {
5018
5018
  try {
5019
- const stat5 = await fs17.stat(p2);
5020
- return stat5.isDirectory();
5019
+ const stat6 = await fs17.stat(p2);
5020
+ return stat6.isDirectory();
5021
5021
  } catch {
5022
5022
  return false;
5023
5023
  }
@@ -6125,8 +6125,8 @@ function extractIds(pkg) {
6125
6125
  }
6126
6126
  async function directoryExists(p2) {
6127
6127
  try {
6128
- const stat5 = await fs22.stat(p2);
6129
- return stat5.isDirectory();
6128
+ const stat6 = await fs22.stat(p2);
6129
+ return stat6.isDirectory();
6130
6130
  } catch {
6131
6131
  return false;
6132
6132
  }
@@ -8548,13 +8548,44 @@ async function detectProjectState(cwd) {
8548
8548
  significantEntries: []
8549
8549
  };
8550
8550
  }
8551
+ let legacyLib = "unknown";
8552
+ let buildTool = "unknown";
8553
+ let allDeps = {};
8554
+ if (hasPackageJson2) {
8555
+ const pkgRaw = await readFileOrNull(path36.join(absCwd, "package.json"));
8556
+ if (pkgRaw) {
8557
+ try {
8558
+ const pkg = JSON.parse(pkgRaw);
8559
+ allDeps = { ...pkg.dependencies, ...pkg.devDependencies };
8560
+ } catch {
8561
+ }
8562
+ }
8563
+ }
8564
+ if ("@alifd/next" in allDeps || "@ali/teamix-material" in allDeps) {
8565
+ legacyLib = "fusion";
8566
+ } else if ("antd" in allDeps) {
8567
+ legacyLib = "antd";
8568
+ } else if ("element-ui" in allDeps || "element-plus" in allDeps) {
8569
+ legacyLib = "element";
8570
+ }
8571
+ if (await fileExists(path36.join(absCwd, "build.json"))) {
8572
+ buildTool = "ice";
8573
+ } else if (await fileExists(path36.join(absCwd, "vite.config.ts")) || await fileExists(path36.join(absCwd, "vite.config.js")) || await fileExists(path36.join(absCwd, "vite.config.mts"))) {
8574
+ buildTool = "vite";
8575
+ } else if (await fileExists(path36.join(absCwd, "webpack.config.js")) || await fileExists(path36.join(absCwd, "webpack.config.ts"))) {
8576
+ buildTool = "webpack";
8577
+ } else if ("umi" in allDeps || "@umijs/max" in allDeps) {
8578
+ buildTool = "umi";
8579
+ }
8551
8580
  return {
8552
8581
  state: "other",
8553
8582
  cwd: absCwd,
8554
8583
  hasTeamixDir: false,
8555
8584
  hasPackageJson: hasPackageJson2,
8556
8585
  hasComponentsJson,
8557
- significantEntries: significant.slice(0, 20).sort()
8586
+ significantEntries: significant.slice(0, 20).sort(),
8587
+ legacyLib,
8588
+ buildTool
8558
8589
  };
8559
8590
  }
8560
8591
 
@@ -8563,7 +8594,8 @@ init_logger();
8563
8594
  var COMMAND_LABELS = {
8564
8595
  init: "\u521D\u59CB\u5316 Teamix Evo \u5957\u4EF6",
8565
8596
  migrate: "shadcn \u9879\u76EE\u8FC1\u79FB\u4E3A Teamix Evo \u5957\u4EF6",
8566
- update: "Teamix Evo \u5957\u4EF6\u66F4\u65B0"
8597
+ update: "Teamix Evo \u5957\u4EF6\u66F4\u65B0",
8598
+ graft: "\u53E0\u52A0 Teamix Evo \u80FD\u529B"
8567
8599
  };
8568
8600
  var STATE_LABELS = {
8569
8601
  empty: "\u7A7A\u76EE\u5F55",
@@ -8574,13 +8606,14 @@ var STATE_LABELS = {
8574
8606
  var VALID_STATES = {
8575
8607
  init: "empty",
8576
8608
  migrate: "shadcn",
8577
- update: "teamix-evo"
8609
+ update: "teamix-evo",
8610
+ graft: "other"
8578
8611
  };
8579
8612
  var STATE_TO_COMMAND = {
8580
8613
  empty: "init",
8581
8614
  shadcn: "migrate",
8582
8615
  "teamix-evo": "update",
8583
- other: null
8616
+ other: "graft"
8584
8617
  };
8585
8618
  function assertCommandPrecondition(command, state) {
8586
8619
  const expected = VALID_STATES[command];
@@ -8594,13 +8627,6 @@ function assertCommandPrecondition(command, state) {
8594
8627
  if (suggestion) {
8595
8628
  const suggestionLabel = COMMAND_LABELS[suggestion];
8596
8629
  logger.info(`\u5EFA\u8BAE\u4F7F\u7528\uFF1Ateamix-evo ${suggestion}\uFF08${suggestionLabel}\uFF09`);
8597
- } else {
8598
- logger.info(
8599
- "\u5F53\u524D\u9879\u76EE\u7C7B\u578B\u6682\u4E0D\u652F\u6301\u76F4\u63A5\u63A5\u5165\u3002"
8600
- );
8601
- logger.info(
8602
- "\u5EFA\u8BAE\uFF1A\u5148\u7528 teamix-evo init \u521D\u59CB\u5316 Teamix Evo \u5957\u4EF6\uFF08\u7A7A\u76EE\u5F55\uFF09\uFF0C\u7136\u540E\u5BF9\u65E7\u9879\u76EE\u8FDB\u884C\u91CD\u6784\u3002"
8603
- );
8604
8630
  }
8605
8631
  process.exitCode = 1;
8606
8632
  }
@@ -9482,7 +9508,7 @@ async function detectLintVersions(projectRoot) {
9482
9508
  const pkgJson = pkgJsonRaw ? JSON.parse(pkgJsonRaw) : null;
9483
9509
  const devDeps = pkgJson?.devDependencies ?? {};
9484
9510
  const deps = pkgJson?.dependencies ?? {};
9485
- const resolve12 = async (pkg) => {
9511
+ const resolve13 = async (pkg) => {
9486
9512
  const declared = devDeps[pkg] ?? deps[pkg] ?? null;
9487
9513
  if (!declared) return null;
9488
9514
  const installedPkgJson = await readFileOrNull(
@@ -9492,8 +9518,8 @@ async function detectLintVersions(projectRoot) {
9492
9518
  return { declared, installed };
9493
9519
  };
9494
9520
  const [eslintConfig, stylelintConfig] = await Promise.all([
9495
- resolve12(LINT_PACKAGES[0]),
9496
- resolve12(LINT_PACKAGES[1])
9521
+ resolve13(LINT_PACKAGES[0]),
9522
+ resolve13(LINT_PACKAGES[1])
9497
9523
  ]);
9498
9524
  return { eslintConfig, stylelintConfig };
9499
9525
  }
@@ -9659,19 +9685,162 @@ var migrateCommand = new Command38("migrate").description(
9659
9685
  }
9660
9686
  });
9661
9687
 
9662
- // src/commands/restore/index.ts
9688
+ // src/commands/graft/index.ts
9663
9689
  import { Command as Command39 } from "commander";
9664
- import * as path44 from "path";
9690
+ import * as path43 from "path";
9691
+ import * as fs31 from "fs/promises";
9692
+ init_logger();
9693
+ init_error();
9694
+ init_fs();
9695
+ var APP_ENTRY_CANDIDATES = [
9696
+ "src/app.tsx",
9697
+ "src/app.ts",
9698
+ "src/app.jsx",
9699
+ "src/app.js",
9700
+ "src/index.tsx",
9701
+ "src/index.ts",
9702
+ "src/index.jsx",
9703
+ "src/index.js"
9704
+ ];
9705
+ var POSTCSS_CONFIG_CANDIDATES = [
9706
+ "postcss.config.js",
9707
+ "postcss.config.cjs",
9708
+ "postcss.config.mjs",
9709
+ "postcss.config.ts",
9710
+ ".postcssrc",
9711
+ ".postcssrc.json",
9712
+ ".postcssrc.yml",
9713
+ ".postcssrc.yaml",
9714
+ ".postcssrc.js"
9715
+ ];
9716
+ var CONFLICT_PATHS = [
9717
+ { path: ".teamix-evo", type: "directory" },
9718
+ { path: "src/components/ui", type: "directory" },
9719
+ { path: "src/components/business", type: "directory" },
9720
+ { path: "tokens", type: "directory" }
9721
+ ];
9722
+ async function findFirst(cwd, candidates) {
9723
+ for (const c of candidates) {
9724
+ if (await fileExists(path43.join(cwd, c))) return c;
9725
+ }
9726
+ return null;
9727
+ }
9728
+ async function getLegacyLibVersion(cwd, legacyLib) {
9729
+ const pkgRaw = await readFileOrNull(path43.join(cwd, "package.json"));
9730
+ if (!pkgRaw) return "unknown";
9731
+ try {
9732
+ const pkg = JSON.parse(pkgRaw);
9733
+ const allDeps = { ...pkg.dependencies, ...pkg.devDependencies };
9734
+ const libKeyMap = {
9735
+ fusion: ["@alifd/next", "@ali/teamix-material"],
9736
+ antd: ["antd"],
9737
+ element: ["element-ui", "element-plus"]
9738
+ };
9739
+ const keys = libKeyMap[legacyLib] ?? [];
9740
+ for (const key of keys) {
9741
+ if (allDeps[key]) return allDeps[key];
9742
+ }
9743
+ } catch {
9744
+ }
9745
+ return "unknown";
9746
+ }
9747
+ async function detectConflicts(cwd) {
9748
+ const conflicts = [];
9749
+ for (const entry of CONFLICT_PATHS) {
9750
+ const full = path43.join(cwd, entry.path);
9751
+ try {
9752
+ const stat6 = await fs31.stat(full);
9753
+ if (entry.type === "directory" && stat6.isDirectory() || entry.type === "file" && stat6.isFile()) {
9754
+ conflicts.push(entry);
9755
+ }
9756
+ } catch {
9757
+ }
9758
+ }
9759
+ return conflicts;
9760
+ }
9761
+ var graftCommand = new Command39("graft").description(
9762
+ "\u53E0\u52A0 Teamix Evo AICoding \u80FD\u529B\u5230\u73B0\u6709\u9879\u76EE\uFF08\u53CC\u6808\u5171\u5B58\uFF0CADR 0047\uFF09"
9763
+ ).option("--variant <name>", "\u6307\u5B9A tokens variant\uFF08\u5982 opentrek\uFF09").option("--cwd <dir>", "\u6307\u5B9A\u5DE5\u7A0B\u6839\u76EE\u5F55\uFF08\u9ED8\u8BA4\uFF1A\u5F53\u524D\u76EE\u5F55\uFF09").option("--json", "\u8F93\u51FA JSON \u683C\u5F0F\u7684\u5206\u6790\u62A5\u544A\uFF08\u4F9B AI skill \u6D88\u8D39\uFF09").action(async (opts) => {
9764
+ const cwd = path43.resolve(opts.cwd ?? process.cwd());
9765
+ try {
9766
+ const state = await detectProjectState(cwd);
9767
+ if (state.state !== "other") {
9768
+ assertCommandPrecondition("graft", state.state);
9769
+ return;
9770
+ }
9771
+ const legacyLib = state.legacyLib ?? "unknown";
9772
+ const buildTool = state.buildTool ?? "unknown";
9773
+ const legacyVersion = await getLegacyLibVersion(cwd, legacyLib);
9774
+ const BUILD_TOOL_CONFIG_CANDIDATES = {
9775
+ ice: ["build.json"],
9776
+ vite: ["vite.config.ts", "vite.config.js", "vite.config.mts", "vite.config.mjs"],
9777
+ webpack: ["webpack.config.js", "webpack.config.ts", "webpack.config.cjs"]
9778
+ };
9779
+ const buildToolConfig = await findFirst(
9780
+ cwd,
9781
+ BUILD_TOOL_CONFIG_CANDIDATES[buildTool] ?? []
9782
+ );
9783
+ const postcssPath = await findFirst(cwd, POSTCSS_CONFIG_CANDIDATES);
9784
+ const appEntry = await findFirst(cwd, APP_ENTRY_CANDIDATES);
9785
+ const conflicts = await detectConflicts(cwd);
9786
+ const report = {
9787
+ projectRoot: cwd,
9788
+ legacyLib: { name: legacyLib, version: legacyVersion },
9789
+ buildTool: { type: buildTool, configFile: buildToolConfig },
9790
+ postcssConfig: { exists: postcssPath !== null, path: postcssPath },
9791
+ appEntry,
9792
+ conflicts
9793
+ };
9794
+ if (opts.json) {
9795
+ console.log(JSON.stringify(report, null, 2));
9796
+ } else {
9797
+ logger.info("Teamix Evo Graft \u2014 \u53CC\u6808\u5171\u5B58\u524D\u7F6E\u68C0\u67E5");
9798
+ logger.info("");
9799
+ logger.info(` \u9879\u76EE\u76EE\u5F55\uFF1A${cwd}`);
9800
+ logger.info(
9801
+ ` \u65E7\u7EC4\u4EF6\u5E93\uFF1A${legacyLib} (${legacyVersion})`
9802
+ );
9803
+ logger.info(` \u6784\u5EFA\u5DE5\u5177\uFF1A${buildTool}`);
9804
+ logger.info(
9805
+ ` PostCSS \u914D\u7F6E\uFF1A${postcssPath ?? "\u672A\u68C0\u6D4B\u5230"}`
9806
+ );
9807
+ logger.info(` App \u5165\u53E3\uFF1A${appEntry ?? "\u672A\u68C0\u6D4B\u5230"}`);
9808
+ if (conflicts.length > 0) {
9809
+ logger.info("");
9810
+ logger.warn(" \u5DF2\u5B58\u5728\u7684\u8DEF\u5F84\uFF08\u53EF\u80FD\u51B2\u7A81\uFF09\uFF1A");
9811
+ for (const c of conflicts) {
9812
+ logger.warn(` ${c.path} (${c.type})`);
9813
+ }
9814
+ }
9815
+ logger.info("");
9816
+ logger.info(
9817
+ "\u524D\u7F6E\u68C0\u67E5\u901A\u8FC7\u3002\u8BF7\u5728 AI IDE \u4E2D\u89E6\u53D1 teamix-evo-manage skill \u4EE5\u5F15\u5BFC graft \u6D41\u7A0B\u3002"
9818
+ );
9819
+ logger.info(
9820
+ "CLI \u4EC5\u505A\u524D\u7F6E\u68C0\u67E5\uFF0C\u5B9E\u9645 graft \u7531 AI skill \u9A71\u52A8\u3002"
9821
+ );
9822
+ }
9823
+ } catch (err) {
9824
+ logger.error(`graft \u524D\u7F6E\u68C0\u67E5\u5931\u8D25\uFF1A${getErrorMessage(err)}`);
9825
+ logger.debug(err.stack ?? "");
9826
+ process.exitCode = 1;
9827
+ }
9828
+ });
9829
+
9830
+ // src/commands/restore/index.ts
9831
+ import { Command as Command40 } from "commander";
9832
+ import * as path45 from "path";
9665
9833
  import * as prompts7 from "@clack/prompts";
9666
9834
 
9667
9835
  // src/core/snapshot.ts
9668
9836
  init_logger();
9669
- import * as fs31 from "fs/promises";
9670
- import * as path43 from "path";
9837
+ import * as fs32 from "fs/promises";
9838
+ import * as path44 from "path";
9671
9839
  var TEAMIX_DIR6 = ".teamix-evo";
9672
9840
  var SNAPSHOTS_DIR = ".snapshots";
9673
9841
  var META_FILE = "_meta.json";
9674
9842
  var DEFAULT_KEEP = 5;
9843
+ var SNAPSHOT_REASONS = ["init", "update", "switch", "restore", "graft", "manual"];
9675
9844
  function isoToFsSafe3(iso) {
9676
9845
  return iso.replace(/[:.]/g, "-");
9677
9846
  }
@@ -9682,47 +9851,47 @@ function fsSafeToIso(safe) {
9682
9851
  );
9683
9852
  }
9684
9853
  async function createSnapshot(projectRoot, opts = {}) {
9685
- const teamixDir = path43.join(projectRoot, TEAMIX_DIR6);
9854
+ const teamixDir = path44.join(projectRoot, TEAMIX_DIR6);
9686
9855
  try {
9687
- const stat5 = await fs31.stat(teamixDir);
9688
- if (!stat5.isDirectory()) return null;
9856
+ const stat6 = await fs32.stat(teamixDir);
9857
+ if (!stat6.isDirectory()) return null;
9689
9858
  } catch (err) {
9690
9859
  if (err.code === "ENOENT") return null;
9691
9860
  throw err;
9692
9861
  }
9693
9862
  const isoTs = (/* @__PURE__ */ new Date()).toISOString();
9694
9863
  const ts = isoToFsSafe3(isoTs);
9695
- const snapshotRoot = path43.join(teamixDir, SNAPSHOTS_DIR);
9696
- const target = path43.join(snapshotRoot, ts);
9697
- await fs31.mkdir(target, { recursive: true });
9698
- const entries = await fs31.readdir(teamixDir, { withFileTypes: true });
9864
+ const snapshotRoot = path44.join(teamixDir, SNAPSHOTS_DIR);
9865
+ const target = path44.join(snapshotRoot, ts);
9866
+ await fs32.mkdir(target, { recursive: true });
9867
+ const entries = await fs32.readdir(teamixDir, { withFileTypes: true });
9699
9868
  for (const entry of entries) {
9700
9869
  if (entry.name === SNAPSHOTS_DIR) continue;
9701
- const src = path43.join(teamixDir, entry.name);
9702
- const dst = path43.join(target, entry.name);
9703
- await fs31.cp(src, dst, { recursive: true });
9870
+ const src = path44.join(teamixDir, entry.name);
9871
+ const dst = path44.join(target, entry.name);
9872
+ await fs32.cp(src, dst, { recursive: true });
9704
9873
  }
9705
9874
  const meta = {
9706
9875
  ts: isoTs,
9707
9876
  reason: opts.reason ?? "manual"
9708
9877
  };
9709
- await fs31.writeFile(
9710
- path43.join(target, META_FILE),
9878
+ await fs32.writeFile(
9879
+ path44.join(target, META_FILE),
9711
9880
  JSON.stringify(meta, null, 2) + "\n",
9712
9881
  "utf-8"
9713
9882
  );
9714
9883
  logger.debug(
9715
- `Snapshot created \u2192 ${path43.relative(projectRoot, target)} (${meta.reason})`
9884
+ `Snapshot created \u2192 ${path44.relative(projectRoot, target)} (${meta.reason})`
9716
9885
  );
9717
9886
  const keep = opts.keep ?? DEFAULT_KEEP;
9718
9887
  await pruneSnapshots(projectRoot, keep, { protectedTs: opts.protectedTs });
9719
9888
  return { ts, path: target };
9720
9889
  }
9721
9890
  async function listSnapshots(projectRoot) {
9722
- const snapshotRoot = path43.join(projectRoot, TEAMIX_DIR6, SNAPSHOTS_DIR);
9891
+ const snapshotRoot = path44.join(projectRoot, TEAMIX_DIR6, SNAPSHOTS_DIR);
9723
9892
  let entries;
9724
9893
  try {
9725
- entries = await fs31.readdir(snapshotRoot, { withFileTypes: true });
9894
+ entries = await fs32.readdir(snapshotRoot, { withFileTypes: true });
9726
9895
  } catch (err) {
9727
9896
  if (err.code === "ENOENT") return [];
9728
9897
  throw err;
@@ -9730,14 +9899,14 @@ async function listSnapshots(projectRoot) {
9730
9899
  const result = [];
9731
9900
  for (const entry of entries) {
9732
9901
  if (!entry.isDirectory()) continue;
9733
- const dir = path43.join(snapshotRoot, entry.name);
9902
+ const dir = path44.join(snapshotRoot, entry.name);
9734
9903
  let isoTs = null;
9735
9904
  let reason = null;
9736
9905
  try {
9737
- const raw = await fs31.readFile(path43.join(dir, META_FILE), "utf-8");
9906
+ const raw = await fs32.readFile(path44.join(dir, META_FILE), "utf-8");
9738
9907
  const parsed = JSON.parse(raw);
9739
9908
  if (typeof parsed.ts === "string") isoTs = parsed.ts;
9740
- if (typeof parsed.reason === "string" && ["init", "update", "switch", "restore", "manual"].includes(
9909
+ if (typeof parsed.reason === "string" && SNAPSHOT_REASONS.includes(
9741
9910
  parsed.reason
9742
9911
  )) {
9743
9912
  reason = parsed.reason;
@@ -9759,18 +9928,18 @@ async function pruneSnapshots(projectRoot, keep = DEFAULT_KEEP, opts = {}) {
9759
9928
  const toRemove = opts.protectedTs ? tail.filter((s) => s.ts !== opts.protectedTs) : tail;
9760
9929
  const removed = [];
9761
9930
  for (const snap of toRemove) {
9762
- await fs31.rm(snap.path, { recursive: true, force: true });
9931
+ await fs32.rm(snap.path, { recursive: true, force: true });
9763
9932
  removed.push(snap.ts);
9764
9933
  logger.debug(`Pruned snapshot ${snap.ts}`);
9765
9934
  }
9766
9935
  return removed.reverse();
9767
9936
  }
9768
9937
  async function restoreSnapshot(projectRoot, ts) {
9769
- const snapshotRoot = path43.join(projectRoot, TEAMIX_DIR6, SNAPSHOTS_DIR);
9770
- const target = path43.join(snapshotRoot, ts);
9938
+ const snapshotRoot = path44.join(projectRoot, TEAMIX_DIR6, SNAPSHOTS_DIR);
9939
+ const target = path44.join(snapshotRoot, ts);
9771
9940
  try {
9772
- const stat5 = await fs31.stat(target);
9773
- if (!stat5.isDirectory()) {
9941
+ const stat6 = await fs32.stat(target);
9942
+ if (!stat6.isDirectory()) {
9774
9943
  throw new Error(`Snapshot path is not a directory: ${target}`);
9775
9944
  }
9776
9945
  } catch (err) {
@@ -9782,21 +9951,21 @@ async function restoreSnapshot(projectRoot, ts) {
9782
9951
  throw err;
9783
9952
  }
9784
9953
  await createSnapshot(projectRoot, { reason: "restore", protectedTs: ts });
9785
- const teamixDir = path43.join(projectRoot, TEAMIX_DIR6);
9786
- const live = await fs31.readdir(teamixDir, { withFileTypes: true });
9954
+ const teamixDir = path44.join(projectRoot, TEAMIX_DIR6);
9955
+ const live = await fs32.readdir(teamixDir, { withFileTypes: true });
9787
9956
  for (const entry of live) {
9788
9957
  if (entry.name === SNAPSHOTS_DIR) continue;
9789
- await fs31.rm(path43.join(teamixDir, entry.name), {
9958
+ await fs32.rm(path44.join(teamixDir, entry.name), {
9790
9959
  recursive: true,
9791
9960
  force: true
9792
9961
  });
9793
9962
  }
9794
- const snapshotEntries = await fs31.readdir(target, { withFileTypes: true });
9963
+ const snapshotEntries = await fs32.readdir(target, { withFileTypes: true });
9795
9964
  for (const entry of snapshotEntries) {
9796
9965
  if (entry.name === META_FILE) continue;
9797
- const src = path43.join(target, entry.name);
9798
- const dst = path43.join(teamixDir, entry.name);
9799
- await fs31.cp(src, dst, { recursive: true });
9966
+ const src = path44.join(target, entry.name);
9967
+ const dst = path44.join(teamixDir, entry.name);
9968
+ await fs32.cp(src, dst, { recursive: true });
9800
9969
  }
9801
9970
  logger.debug(`Restored .teamix-evo/ from snapshot ${ts}`);
9802
9971
  }
@@ -9805,10 +9974,10 @@ async function restoreSnapshot(projectRoot, ts) {
9805
9974
  init_logger();
9806
9975
  init_error();
9807
9976
  function createRestoreCommand() {
9808
- return new Command39("restore").description(
9977
+ return new Command40("restore").description(
9809
9978
  "\u56DE\u6EDA .teamix-evo/ \u5230\u6307\u5B9A snapshot\uFF08init/update \u5931\u8D25\u65F6\u4F7F\u7528 \u2014 ADR 0019 \xA72\uFF09"
9810
9979
  ).argument("[ts]", "\u76EE\u6807 snapshot \u65F6\u95F4\u6233\uFF08\u5982 2026-06-11T20-59-03-000Z\uFF09").option("--list", "\u5217\u51FA\u53EF\u7528 snapshot\uFF08\u4E0D\u505A\u5B9E\u9645\u56DE\u6EDA\uFF09").option("--cwd <dir>", "\u6307\u5B9A\u5DE5\u7A0B\u6839\u76EE\u5F55\uFF08\u9ED8\u8BA4\uFF1A\u5F53\u524D\u76EE\u5F55\uFF09").option("-y, --yes", "\u8DF3\u8FC7\u4E8C\u6B21\u786E\u8BA4\uFF08destructive\uFF0C\u8BF7\u786E\u8BA4\u65E0\u8BEF\uFF09").action(async (ts, opts) => {
9811
- const cwd = path44.resolve(opts.cwd ?? process.cwd());
9980
+ const cwd = path45.resolve(opts.cwd ?? process.cwd());
9812
9981
  try {
9813
9982
  const snapshots = await listSnapshots(cwd);
9814
9983
  if (opts.list) {
@@ -9904,14 +10073,14 @@ function printSnapshotTable(snapshots) {
9904
10073
  }
9905
10074
 
9906
10075
  // src/commands/switch/index.ts
9907
- import { Command as Command40 } from "commander";
9908
- import * as path46 from "path";
10076
+ import { Command as Command41 } from "commander";
10077
+ import * as path47 from "path";
9909
10078
  import * as prompts8 from "@clack/prompts";
9910
10079
 
9911
10080
  // src/core/variant-switch.ts
9912
10081
  init_fs();
9913
- import * as path45 from "path";
9914
- import * as fs32 from "fs/promises";
10082
+ import * as path46 from "path";
10083
+ import * as fs33 from "fs/promises";
9915
10084
  import {
9916
10085
  loadTokensPackageManifest as loadTokensPackageManifest3,
9917
10086
  getVariantEntry as getVariantEntry3
@@ -9948,8 +10117,8 @@ async function runVariantSwitch(options) {
9948
10117
  const upstreamByBasename = /* @__PURE__ */ new Map();
9949
10118
  for (const fileRel of variantEntry.files) {
9950
10119
  upstreamByBasename.set(
9951
- path45.basename(fileRel),
9952
- path45.join(packageRoot, fileRel)
10120
+ path46.basename(fileRel),
10121
+ path46.join(packageRoot, fileRel)
9953
10122
  );
9954
10123
  }
9955
10124
  const prior = await readInstalledManifest(projectRoot) ?? {
@@ -9963,7 +10132,7 @@ async function runVariantSwitch(options) {
9963
10132
  const priorVersion = installedIdx >= 0 ? prior.installed[installedIdx].version : "0.0.0";
9964
10133
  const changes = [];
9965
10134
  for (const resource of priorResources) {
9966
- const consumerBasename = path45.basename(resource.target);
10135
+ const consumerBasename = path46.basename(resource.target);
9967
10136
  const upstreamBasename = lookupUpstreamBasename2(consumerBasename);
9968
10137
  const upstreamAbs = upstreamBasename ? upstreamByBasename.get(upstreamBasename) : void 0;
9969
10138
  if (resource.strategy === "frozen") {
@@ -9984,7 +10153,7 @@ async function runVariantSwitch(options) {
9984
10153
  });
9985
10154
  continue;
9986
10155
  }
9987
- const upstreamContent = await fs32.readFile(upstreamAbs, "utf-8");
10156
+ const upstreamContent = await fs33.readFile(upstreamAbs, "utf-8");
9988
10157
  if (resource.strategy === "regenerable") {
9989
10158
  const newHash = computeHash(upstreamContent);
9990
10159
  if (newHash === resource.hash) {
@@ -10037,12 +10206,12 @@ async function runVariantSwitch(options) {
10037
10206
  }
10038
10207
  const refreshedResources = [];
10039
10208
  for (const resource of priorResources) {
10040
- const consumerAbs = path45.isAbsolute(resource.target) ? resource.target : path45.join(projectRoot, resource.target);
10041
- const consumerBasename = path45.basename(resource.target);
10209
+ const consumerAbs = path46.isAbsolute(resource.target) ? resource.target : path46.join(projectRoot, resource.target);
10210
+ const consumerBasename = path46.basename(resource.target);
10042
10211
  const upstreamBasename = lookupUpstreamBasename2(consumerBasename);
10043
10212
  const upstreamAbs = upstreamBasename ? upstreamByBasename.get(upstreamBasename) : void 0;
10044
10213
  if (resource.strategy === "regenerable" && upstreamAbs) {
10045
- const upstreamContent = await fs32.readFile(upstreamAbs, "utf-8");
10214
+ const upstreamContent = await fs33.readFile(upstreamAbs, "utf-8");
10046
10215
  await writeFileSafe(consumerAbs, upstreamContent);
10047
10216
  logger.debug(`[variant-switch] rewrite regenerable: ${resource.target}`);
10048
10217
  refreshedResources.push({
@@ -10052,8 +10221,8 @@ async function runVariantSwitch(options) {
10052
10221
  continue;
10053
10222
  }
10054
10223
  if (resource.strategy === "managed" && upstreamAbs && await fileExists(consumerAbs)) {
10055
- const upstreamContent = await fs32.readFile(upstreamAbs, "utf-8");
10056
- const consumerContent = await fs32.readFile(consumerAbs, "utf-8");
10224
+ const upstreamContent = await fs33.readFile(upstreamAbs, "utf-8");
10225
+ const consumerContent = await fs33.readFile(consumerAbs, "utf-8");
10057
10226
  const merged = mergeManagedRegions(upstreamContent, consumerContent);
10058
10227
  if (merged !== consumerContent) {
10059
10228
  await writeFileSafe(consumerAbs, merged);
@@ -10084,7 +10253,7 @@ async function runVariantSwitch(options) {
10084
10253
  installedAt: now
10085
10254
  };
10086
10255
  await writeFileSafe(
10087
- path45.join(projectRoot, ".teamix-evo", "tokens-lock.json"),
10256
+ path46.join(projectRoot, ".teamix-evo", "tokens-lock.json"),
10088
10257
  JSON.stringify(lock, null, 2) + "\n"
10089
10258
  );
10090
10259
  logger.debug(
@@ -10201,10 +10370,10 @@ var KIND_LABEL = {
10201
10370
  unchanged: "unchanged"
10202
10371
  };
10203
10372
  function createSwitchCommand() {
10204
- return new Command40("switch").description(
10373
+ return new Command41("switch").description(
10205
10374
  "variant \u5207\u6362\uFF1A\u5148\u5C55\u793A file-level diff\uFF0C--apply \u624D\u771F\u5199\uFF08ADR 0019 \xA7D3\uFF09"
10206
10375
  ).argument("<new-variant>", "\u76EE\u6807 variant id\uFF08\u5982 opentrek / uni-manager\uFF09").option("--cwd <dir>", "\u6307\u5B9A\u5DE5\u7A0B\u6839\u76EE\u5F55\uFF08\u9ED8\u8BA4\uFF1A\u5F53\u524D\u76EE\u5F55\uFF09").option("--apply", "\u771F\u6B63\u6267\u884C\u5207\u6362\uFF08\u9ED8\u8BA4 dry-run\uFF0C\u4EC5\u5C55\u793A\u8BA1\u5212\uFF09").option("-y, --yes", "\u8DF3\u8FC7 --apply \u4E8C\u6B21\u786E\u8BA4\uFF08destructive\uFF0C\u8BF7\u786E\u8BA4\u65E0\u8BEF\uFF09").action(async (newVariant, opts) => {
10207
- const cwd = path46.resolve(opts.cwd ?? process.cwd());
10376
+ const cwd = path47.resolve(opts.cwd ?? process.cwd());
10208
10377
  const apply = opts.apply ?? false;
10209
10378
  try {
10210
10379
  const plan = await runVariantSwitch({
@@ -10320,7 +10489,7 @@ function printChangePlan(from, to, toVersion, changes) {
10320
10489
  // src/index.ts
10321
10490
  var require9 = createRequire9(import.meta.url);
10322
10491
  var { version } = require9("../package.json");
10323
- var program = new Command41();
10492
+ var program = new Command42();
10324
10493
  program.name("teamix-evo").description("Where ideas evolve. \u2014 AI Coding \u5957\u4EF6").version(version);
10325
10494
  program.addCommand(tokensCommand);
10326
10495
  program.addCommand(skillsCommand);
@@ -10331,6 +10500,7 @@ program.addCommand(lintCommand);
10331
10500
  program.addCommand(initCommand5);
10332
10501
  program.addCommand(updateCommand5);
10333
10502
  program.addCommand(migrateCommand);
10503
+ program.addCommand(graftCommand);
10334
10504
  program.addCommand(restoreCommand);
10335
10505
  program.addCommand(switchCommand);
10336
10506
  function enableHelpAfterError(cmd) {