teamix-evo 0.17.0 → 0.18.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +36 -36
- package/dist/core/index.d.ts +3 -1
- package/dist/core/index.js +12 -1
- package/dist/core/index.js.map +1 -1
- package/dist/index.js +605 -197
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -2395,11 +2395,11 @@ var uninstallCommand = new Command5("uninstall").description(
|
|
|
2395
2395
|
`Will remove ${removable.length} file(s); keep ${kept} managed file(s).`
|
|
2396
2396
|
);
|
|
2397
2397
|
if (!opts.yes) {
|
|
2398
|
-
const
|
|
2398
|
+
const confirm8 = await prompts.confirm({
|
|
2399
2399
|
message: "\u786E\u8BA4\u5378\u8F7D tokens \u53D8\u4F53\uFF1F",
|
|
2400
2400
|
initialValue: false
|
|
2401
2401
|
});
|
|
2402
|
-
if (prompts.isCancel(
|
|
2402
|
+
if (prompts.isCancel(confirm8) || !confirm8) {
|
|
2403
2403
|
logger.info("Cancelled.");
|
|
2404
2404
|
return;
|
|
2405
2405
|
}
|
|
@@ -4583,11 +4583,11 @@ async function runFullUninstall(args) {
|
|
|
4583
4583
|
`Will remove ${resources.length} skill file(s) installed by ${SKILLS_PACKAGE3}.`
|
|
4584
4584
|
);
|
|
4585
4585
|
if (!opts.yes) {
|
|
4586
|
-
const
|
|
4586
|
+
const confirm8 = await prompts4.confirm({
|
|
4587
4587
|
message: "\u786E\u8BA4\u5378\u8F7D\uFF1F\u6B64\u64CD\u4F5C\u4F1A\u5220\u9664\u4E0A\u8FF0\u6587\u4EF6\u3002",
|
|
4588
4588
|
initialValue: false
|
|
4589
4589
|
});
|
|
4590
|
-
if (prompts4.isCancel(
|
|
4590
|
+
if (prompts4.isCancel(confirm8) || !confirm8) {
|
|
4591
4591
|
logger.info("Cancelled.");
|
|
4592
4592
|
return;
|
|
4593
4593
|
}
|
|
@@ -4640,11 +4640,11 @@ async function runPartialUninstall(args) {
|
|
|
4640
4640
|
`Will remove ${matched.length} skill(s): ${matched.join(", ")} (${toRemove.length} file(s)).`
|
|
4641
4641
|
);
|
|
4642
4642
|
if (!opts.yes) {
|
|
4643
|
-
const
|
|
4643
|
+
const confirm8 = await prompts4.confirm({
|
|
4644
4644
|
message: "\u786E\u8BA4\u5378\u8F7D\uFF1F\u6B64\u64CD\u4F5C\u4F1A\u5220\u9664\u4E0A\u8FF0\u6587\u4EF6\u3002",
|
|
4645
4645
|
initialValue: false
|
|
4646
4646
|
});
|
|
4647
|
-
if (prompts4.isCancel(
|
|
4647
|
+
if (prompts4.isCancel(confirm8) || !confirm8) {
|
|
4648
4648
|
logger.info("Cancelled.");
|
|
4649
4649
|
return;
|
|
4650
4650
|
}
|
|
@@ -8615,9 +8615,17 @@ var STATE_TO_COMMAND = {
|
|
|
8615
8615
|
"teamix-evo": "update",
|
|
8616
8616
|
other: "graft"
|
|
8617
8617
|
};
|
|
8618
|
-
|
|
8618
|
+
var FORCE_BYPASSABLE = {
|
|
8619
|
+
init: /* @__PURE__ */ new Set(["shadcn"]),
|
|
8620
|
+
migrate: /* @__PURE__ */ new Set([]),
|
|
8621
|
+
update: /* @__PURE__ */ new Set([]),
|
|
8622
|
+
graft: /* @__PURE__ */ new Set([])
|
|
8623
|
+
};
|
|
8624
|
+
function assertCommandPrecondition(command, state, options) {
|
|
8619
8625
|
const expected = VALID_STATES[command];
|
|
8620
8626
|
if (state === expected) return;
|
|
8627
|
+
const canForce = FORCE_BYPASSABLE[command].has(state);
|
|
8628
|
+
if (options?.force && canForce) return;
|
|
8621
8629
|
const stateLabel = STATE_LABELS[state];
|
|
8622
8630
|
const commandLabel = COMMAND_LABELS[command];
|
|
8623
8631
|
logger.error(
|
|
@@ -8628,6 +8636,9 @@ function assertCommandPrecondition(command, state) {
|
|
|
8628
8636
|
const suggestionLabel = COMMAND_LABELS[suggestion];
|
|
8629
8637
|
logger.info(`\u5EFA\u8BAE\u4F7F\u7528\uFF1Ateamix-evo ${suggestion}\uFF08${suggestionLabel}\uFF09`);
|
|
8630
8638
|
}
|
|
8639
|
+
if (!canForce) {
|
|
8640
|
+
logger.info("--force \u4E0D\u80FD\u7ED5\u8FC7\u6B64\u9650\u5236\u3002");
|
|
8641
|
+
}
|
|
8631
8642
|
process.exitCode = 1;
|
|
8632
8643
|
}
|
|
8633
8644
|
|
|
@@ -9342,10 +9353,8 @@ var initCommand5 = new Command36("init").description(
|
|
|
9342
9353
|
"\u5982\u9700\u5347\u7EA7\u5DF2\u5B89\u88C5\u8D44\u4EA7\u5230\u65B0\u7248\u672C\uFF0C\u8BF7\u4F7F\u7528 teamix-evo update\u3002"
|
|
9343
9354
|
);
|
|
9344
9355
|
} else if (state.state !== "empty") {
|
|
9345
|
-
|
|
9346
|
-
|
|
9347
|
-
return;
|
|
9348
|
-
}
|
|
9356
|
+
assertCommandPrecondition("init", state.state, { force: opts.force });
|
|
9357
|
+
if (process.exitCode) return;
|
|
9349
9358
|
}
|
|
9350
9359
|
const isInteractive = Boolean(process.stdin.isTTY);
|
|
9351
9360
|
const answers = await runInitWizard({
|
|
@@ -9687,155 +9696,18 @@ var migrateCommand = new Command38("migrate").description(
|
|
|
9687
9696
|
|
|
9688
9697
|
// src/commands/graft/index.ts
|
|
9689
9698
|
import { Command as Command39 } from "commander";
|
|
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
9699
|
import * as path45 from "path";
|
|
9700
|
+
import * as fs32 from "fs/promises";
|
|
9833
9701
|
import * as prompts7 from "@clack/prompts";
|
|
9834
9702
|
|
|
9703
|
+
// src/core/graft-init.ts
|
|
9704
|
+
import { hasManagedRegion as hasManagedRegion5, replaceManagedRegion as replaceManagedRegion4 } from "@teamix-evo/registry";
|
|
9705
|
+
init_state();
|
|
9706
|
+
|
|
9835
9707
|
// src/core/snapshot.ts
|
|
9836
9708
|
init_logger();
|
|
9837
|
-
import * as
|
|
9838
|
-
import * as
|
|
9709
|
+
import * as fs31 from "fs/promises";
|
|
9710
|
+
import * as path43 from "path";
|
|
9839
9711
|
var TEAMIX_DIR6 = ".teamix-evo";
|
|
9840
9712
|
var SNAPSHOTS_DIR = ".snapshots";
|
|
9841
9713
|
var META_FILE = "_meta.json";
|
|
@@ -9851,9 +9723,9 @@ function fsSafeToIso(safe) {
|
|
|
9851
9723
|
);
|
|
9852
9724
|
}
|
|
9853
9725
|
async function createSnapshot(projectRoot, opts = {}) {
|
|
9854
|
-
const teamixDir =
|
|
9726
|
+
const teamixDir = path43.join(projectRoot, TEAMIX_DIR6);
|
|
9855
9727
|
try {
|
|
9856
|
-
const stat6 = await
|
|
9728
|
+
const stat6 = await fs31.stat(teamixDir);
|
|
9857
9729
|
if (!stat6.isDirectory()) return null;
|
|
9858
9730
|
} catch (err) {
|
|
9859
9731
|
if (err.code === "ENOENT") return null;
|
|
@@ -9861,37 +9733,37 @@ async function createSnapshot(projectRoot, opts = {}) {
|
|
|
9861
9733
|
}
|
|
9862
9734
|
const isoTs = (/* @__PURE__ */ new Date()).toISOString();
|
|
9863
9735
|
const ts = isoToFsSafe3(isoTs);
|
|
9864
|
-
const snapshotRoot =
|
|
9865
|
-
const target =
|
|
9866
|
-
await
|
|
9867
|
-
const entries = await
|
|
9736
|
+
const snapshotRoot = path43.join(teamixDir, SNAPSHOTS_DIR);
|
|
9737
|
+
const target = path43.join(snapshotRoot, ts);
|
|
9738
|
+
await fs31.mkdir(target, { recursive: true });
|
|
9739
|
+
const entries = await fs31.readdir(teamixDir, { withFileTypes: true });
|
|
9868
9740
|
for (const entry of entries) {
|
|
9869
9741
|
if (entry.name === SNAPSHOTS_DIR) continue;
|
|
9870
|
-
const src =
|
|
9871
|
-
const dst =
|
|
9872
|
-
await
|
|
9742
|
+
const src = path43.join(teamixDir, entry.name);
|
|
9743
|
+
const dst = path43.join(target, entry.name);
|
|
9744
|
+
await fs31.cp(src, dst, { recursive: true });
|
|
9873
9745
|
}
|
|
9874
9746
|
const meta = {
|
|
9875
9747
|
ts: isoTs,
|
|
9876
9748
|
reason: opts.reason ?? "manual"
|
|
9877
9749
|
};
|
|
9878
|
-
await
|
|
9879
|
-
|
|
9750
|
+
await fs31.writeFile(
|
|
9751
|
+
path43.join(target, META_FILE),
|
|
9880
9752
|
JSON.stringify(meta, null, 2) + "\n",
|
|
9881
9753
|
"utf-8"
|
|
9882
9754
|
);
|
|
9883
9755
|
logger.debug(
|
|
9884
|
-
`Snapshot created \u2192 ${
|
|
9756
|
+
`Snapshot created \u2192 ${path43.relative(projectRoot, target)} (${meta.reason})`
|
|
9885
9757
|
);
|
|
9886
9758
|
const keep = opts.keep ?? DEFAULT_KEEP;
|
|
9887
9759
|
await pruneSnapshots(projectRoot, keep, { protectedTs: opts.protectedTs });
|
|
9888
9760
|
return { ts, path: target };
|
|
9889
9761
|
}
|
|
9890
9762
|
async function listSnapshots(projectRoot) {
|
|
9891
|
-
const snapshotRoot =
|
|
9763
|
+
const snapshotRoot = path43.join(projectRoot, TEAMIX_DIR6, SNAPSHOTS_DIR);
|
|
9892
9764
|
let entries;
|
|
9893
9765
|
try {
|
|
9894
|
-
entries = await
|
|
9766
|
+
entries = await fs31.readdir(snapshotRoot, { withFileTypes: true });
|
|
9895
9767
|
} catch (err) {
|
|
9896
9768
|
if (err.code === "ENOENT") return [];
|
|
9897
9769
|
throw err;
|
|
@@ -9899,11 +9771,11 @@ async function listSnapshots(projectRoot) {
|
|
|
9899
9771
|
const result = [];
|
|
9900
9772
|
for (const entry of entries) {
|
|
9901
9773
|
if (!entry.isDirectory()) continue;
|
|
9902
|
-
const dir =
|
|
9774
|
+
const dir = path43.join(snapshotRoot, entry.name);
|
|
9903
9775
|
let isoTs = null;
|
|
9904
9776
|
let reason = null;
|
|
9905
9777
|
try {
|
|
9906
|
-
const raw = await
|
|
9778
|
+
const raw = await fs31.readFile(path43.join(dir, META_FILE), "utf-8");
|
|
9907
9779
|
const parsed = JSON.parse(raw);
|
|
9908
9780
|
if (typeof parsed.ts === "string") isoTs = parsed.ts;
|
|
9909
9781
|
if (typeof parsed.reason === "string" && SNAPSHOT_REASONS.includes(
|
|
@@ -9928,17 +9800,17 @@ async function pruneSnapshots(projectRoot, keep = DEFAULT_KEEP, opts = {}) {
|
|
|
9928
9800
|
const toRemove = opts.protectedTs ? tail.filter((s) => s.ts !== opts.protectedTs) : tail;
|
|
9929
9801
|
const removed = [];
|
|
9930
9802
|
for (const snap of toRemove) {
|
|
9931
|
-
await
|
|
9803
|
+
await fs31.rm(snap.path, { recursive: true, force: true });
|
|
9932
9804
|
removed.push(snap.ts);
|
|
9933
9805
|
logger.debug(`Pruned snapshot ${snap.ts}`);
|
|
9934
9806
|
}
|
|
9935
9807
|
return removed.reverse();
|
|
9936
9808
|
}
|
|
9937
9809
|
async function restoreSnapshot(projectRoot, ts) {
|
|
9938
|
-
const snapshotRoot =
|
|
9939
|
-
const target =
|
|
9810
|
+
const snapshotRoot = path43.join(projectRoot, TEAMIX_DIR6, SNAPSHOTS_DIR);
|
|
9811
|
+
const target = path43.join(snapshotRoot, ts);
|
|
9940
9812
|
try {
|
|
9941
|
-
const stat6 = await
|
|
9813
|
+
const stat6 = await fs31.stat(target);
|
|
9942
9814
|
if (!stat6.isDirectory()) {
|
|
9943
9815
|
throw new Error(`Snapshot path is not a directory: ${target}`);
|
|
9944
9816
|
}
|
|
@@ -9951,33 +9823,569 @@ async function restoreSnapshot(projectRoot, ts) {
|
|
|
9951
9823
|
throw err;
|
|
9952
9824
|
}
|
|
9953
9825
|
await createSnapshot(projectRoot, { reason: "restore", protectedTs: ts });
|
|
9954
|
-
const teamixDir =
|
|
9955
|
-
const live = await
|
|
9826
|
+
const teamixDir = path43.join(projectRoot, TEAMIX_DIR6);
|
|
9827
|
+
const live = await fs31.readdir(teamixDir, { withFileTypes: true });
|
|
9956
9828
|
for (const entry of live) {
|
|
9957
9829
|
if (entry.name === SNAPSHOTS_DIR) continue;
|
|
9958
|
-
await
|
|
9830
|
+
await fs31.rm(path43.join(teamixDir, entry.name), {
|
|
9959
9831
|
recursive: true,
|
|
9960
9832
|
force: true
|
|
9961
9833
|
});
|
|
9962
9834
|
}
|
|
9963
|
-
const snapshotEntries = await
|
|
9835
|
+
const snapshotEntries = await fs31.readdir(target, { withFileTypes: true });
|
|
9964
9836
|
for (const entry of snapshotEntries) {
|
|
9965
9837
|
if (entry.name === META_FILE) continue;
|
|
9966
|
-
const src =
|
|
9967
|
-
const dst =
|
|
9968
|
-
await
|
|
9838
|
+
const src = path43.join(target, entry.name);
|
|
9839
|
+
const dst = path43.join(teamixDir, entry.name);
|
|
9840
|
+
await fs31.cp(src, dst, { recursive: true });
|
|
9969
9841
|
}
|
|
9970
9842
|
logger.debug(`Restored .teamix-evo/ from snapshot ${ts}`);
|
|
9971
9843
|
}
|
|
9972
9844
|
|
|
9845
|
+
// src/core/graft-init.ts
|
|
9846
|
+
init_error();
|
|
9847
|
+
init_logger();
|
|
9848
|
+
init_fs();
|
|
9849
|
+
import * as fsNode2 from "fs/promises";
|
|
9850
|
+
import * as path44 from "path";
|
|
9851
|
+
var CRITICAL_STEPS2 = /* @__PURE__ */ new Set([
|
|
9852
|
+
"ensure-teamix-dir",
|
|
9853
|
+
"tokens",
|
|
9854
|
+
"ui-init",
|
|
9855
|
+
"skills"
|
|
9856
|
+
]);
|
|
9857
|
+
var AGENTS_MD_GRAFT_MANAGED_ID = "teamix-evo-graft";
|
|
9858
|
+
var GITIGNORE_MARKER_START2 = "# >>> teamix-evo:managed >>>";
|
|
9859
|
+
var GITIGNORE_MARKER_END2 = "# <<< teamix-evo:managed <<<";
|
|
9860
|
+
var GITIGNORE_RULES2 = [
|
|
9861
|
+
"# Runtime artifacts (regenerable / archives)",
|
|
9862
|
+
".teamix-evo/.snapshots/",
|
|
9863
|
+
".teamix-evo/.backups/",
|
|
9864
|
+
".teamix-evo/.upgrade-staging/",
|
|
9865
|
+
".teamix-evo/.upgrade-hints/"
|
|
9866
|
+
];
|
|
9867
|
+
var LEGACY_LIB_META = {
|
|
9868
|
+
fusion: {
|
|
9869
|
+
displayName: "Fusion Design",
|
|
9870
|
+
imports: ["teamix/ui", "@alifd/next", "@ali/teamix-material"]
|
|
9871
|
+
},
|
|
9872
|
+
antd: {
|
|
9873
|
+
displayName: "Ant Design",
|
|
9874
|
+
imports: ["antd", "@ant-design/*"]
|
|
9875
|
+
},
|
|
9876
|
+
element: {
|
|
9877
|
+
displayName: "Element UI",
|
|
9878
|
+
imports: ["element-ui", "element-plus"]
|
|
9879
|
+
}
|
|
9880
|
+
};
|
|
9881
|
+
async function runGraftInit(options) {
|
|
9882
|
+
const {
|
|
9883
|
+
projectRoot,
|
|
9884
|
+
variant,
|
|
9885
|
+
legacyLib,
|
|
9886
|
+
onStep
|
|
9887
|
+
} = options;
|
|
9888
|
+
const ide = options.ide ?? "qoder";
|
|
9889
|
+
const ides = options.ides ?? ["qoder", "claude"];
|
|
9890
|
+
const scope = options.scope ?? "project";
|
|
9891
|
+
const steps = [];
|
|
9892
|
+
let aborted = false;
|
|
9893
|
+
function record(step) {
|
|
9894
|
+
steps.push(step);
|
|
9895
|
+
onStep?.(step);
|
|
9896
|
+
}
|
|
9897
|
+
function recordFailure(name, err) {
|
|
9898
|
+
const message = getErrorMessage(err);
|
|
9899
|
+
record({ name, status: "fail", detail: message });
|
|
9900
|
+
if (CRITICAL_STEPS2.has(name)) aborted = true;
|
|
9901
|
+
}
|
|
9902
|
+
try {
|
|
9903
|
+
await ensureTeamixDir(projectRoot);
|
|
9904
|
+
record({ name: "ensure-teamix-dir", status: "ok" });
|
|
9905
|
+
} catch (err) {
|
|
9906
|
+
recordFailure("ensure-teamix-dir", err);
|
|
9907
|
+
}
|
|
9908
|
+
if (!aborted) {
|
|
9909
|
+
try {
|
|
9910
|
+
const snap = await createSnapshot(projectRoot, { reason: "graft" });
|
|
9911
|
+
record({
|
|
9912
|
+
name: "snapshot",
|
|
9913
|
+
status: "ok",
|
|
9914
|
+
detail: snap ? `snapshot ${snap.ts}` : "empty .teamix-evo/ \u2014 nothing to snapshot"
|
|
9915
|
+
});
|
|
9916
|
+
} catch (err) {
|
|
9917
|
+
recordFailure("snapshot", err);
|
|
9918
|
+
}
|
|
9919
|
+
} else {
|
|
9920
|
+
record({ name: "snapshot", status: "skip", detail: "aborted: earlier critical step failed" });
|
|
9921
|
+
}
|
|
9922
|
+
if (!aborted) {
|
|
9923
|
+
try {
|
|
9924
|
+
const result = await runTokensInit({ projectRoot, variant, ide });
|
|
9925
|
+
const detail = result.status === "installed" ? `${result.packageName}@${result.version} (${result.count} files)` : result.status;
|
|
9926
|
+
record({ name: "tokens", status: "ok", detail });
|
|
9927
|
+
} catch (err) {
|
|
9928
|
+
recordFailure("tokens", err);
|
|
9929
|
+
}
|
|
9930
|
+
} else {
|
|
9931
|
+
record({ name: "tokens", status: "skip", detail: "aborted: earlier critical step failed" });
|
|
9932
|
+
}
|
|
9933
|
+
if (!aborted) {
|
|
9934
|
+
try {
|
|
9935
|
+
const initResult = await runUiInit({ projectRoot, ide });
|
|
9936
|
+
record({
|
|
9937
|
+
name: "ui-init",
|
|
9938
|
+
status: "ok",
|
|
9939
|
+
detail: initResult.status === "installed" ? "config.json packages.ui written" : initResult.status
|
|
9940
|
+
});
|
|
9941
|
+
} catch (err) {
|
|
9942
|
+
recordFailure("ui-init", err);
|
|
9943
|
+
}
|
|
9944
|
+
} else {
|
|
9945
|
+
record({ name: "ui-init", status: "skip", detail: "aborted: earlier critical step failed" });
|
|
9946
|
+
}
|
|
9947
|
+
const collectedNpmDeps = {};
|
|
9948
|
+
if (!aborted) {
|
|
9949
|
+
try {
|
|
9950
|
+
const { manifest } = await loadUiData("@teamix-evo/ui");
|
|
9951
|
+
const allIds = manifest.entries.map((e) => e.id);
|
|
9952
|
+
const addResult = await runUiAdd({
|
|
9953
|
+
projectRoot,
|
|
9954
|
+
ids: allIds,
|
|
9955
|
+
overwrite: true
|
|
9956
|
+
});
|
|
9957
|
+
record({
|
|
9958
|
+
name: "ui-add",
|
|
9959
|
+
status: "ok",
|
|
9960
|
+
detail: `${addResult.orderedIds.length} entries (${addResult.written} written, ${addResult.skipped} skipped)`
|
|
9961
|
+
});
|
|
9962
|
+
Object.assign(collectedNpmDeps, addResult.npmDependencies);
|
|
9963
|
+
} catch (err) {
|
|
9964
|
+
recordFailure("ui-add", err);
|
|
9965
|
+
}
|
|
9966
|
+
} else {
|
|
9967
|
+
record({ name: "ui-add", status: "skip", detail: "aborted: earlier critical step failed" });
|
|
9968
|
+
}
|
|
9969
|
+
if (!aborted) {
|
|
9970
|
+
try {
|
|
9971
|
+
const listing = await listBizUiEntries(variant);
|
|
9972
|
+
if (listing.entries.length === 0) {
|
|
9973
|
+
record({
|
|
9974
|
+
name: "biz-ui-add",
|
|
9975
|
+
status: "skip",
|
|
9976
|
+
detail: `no biz-ui entries for variant "${variant}"`
|
|
9977
|
+
});
|
|
9978
|
+
} else {
|
|
9979
|
+
const allIds = listing.entries.map((e) => e.id);
|
|
9980
|
+
const result = await runBizUiAdd({
|
|
9981
|
+
projectRoot,
|
|
9982
|
+
variant,
|
|
9983
|
+
ids: allIds,
|
|
9984
|
+
overwrite: true
|
|
9985
|
+
});
|
|
9986
|
+
record({
|
|
9987
|
+
name: "biz-ui-add",
|
|
9988
|
+
status: "ok",
|
|
9989
|
+
detail: `${result.orderedIds.length} entries (${result.written} written, ${result.skipped} skipped)`
|
|
9990
|
+
});
|
|
9991
|
+
if (result.npmDependencies) {
|
|
9992
|
+
Object.assign(collectedNpmDeps, result.npmDependencies);
|
|
9993
|
+
}
|
|
9994
|
+
}
|
|
9995
|
+
} catch (err) {
|
|
9996
|
+
recordFailure("biz-ui-add", err);
|
|
9997
|
+
}
|
|
9998
|
+
} else {
|
|
9999
|
+
record({ name: "biz-ui-add", status: "skip", detail: "aborted: earlier critical step failed" });
|
|
10000
|
+
}
|
|
10001
|
+
if (!aborted && Object.keys(collectedNpmDeps).length > 0) {
|
|
10002
|
+
try {
|
|
10003
|
+
await installProjectDeps({
|
|
10004
|
+
projectRoot,
|
|
10005
|
+
npmDependencies: collectedNpmDeps,
|
|
10006
|
+
skipInstall: options.skipInstall ?? false
|
|
10007
|
+
});
|
|
10008
|
+
} catch (err) {
|
|
10009
|
+
logger.warn(
|
|
10010
|
+
`\u5B89\u88C5 ui/biz-ui \u4F20\u9012\u4F9D\u8D56\u5931\u8D25\uFF1A${getErrorMessage(err)}\uFF08\u53EF\u624B\u52A8\u8FD0\u884C \`npm install\` \u91CD\u8BD5\uFF09`
|
|
10011
|
+
);
|
|
10012
|
+
}
|
|
10013
|
+
}
|
|
10014
|
+
if (!aborted) {
|
|
10015
|
+
try {
|
|
10016
|
+
const result = await runSkillsInit({ projectRoot, ides, scope, ide });
|
|
10017
|
+
if (result.status === "already-initialized") {
|
|
10018
|
+
record({ name: "skills", status: "ok", detail: "already-initialized" });
|
|
10019
|
+
} else {
|
|
10020
|
+
record({
|
|
10021
|
+
name: "skills",
|
|
10022
|
+
status: "ok",
|
|
10023
|
+
detail: `${result.skillCount} skills, ${result.fileCount} files`
|
|
10024
|
+
});
|
|
10025
|
+
}
|
|
10026
|
+
} catch (err) {
|
|
10027
|
+
recordFailure("skills", err);
|
|
10028
|
+
}
|
|
10029
|
+
} else {
|
|
10030
|
+
record({ name: "skills", status: "skip", detail: "aborted: earlier critical step failed" });
|
|
10031
|
+
}
|
|
10032
|
+
if (!aborted) {
|
|
10033
|
+
try {
|
|
10034
|
+
const result = await runGenerateAgentsMd({
|
|
10035
|
+
projectRoot,
|
|
10036
|
+
variant,
|
|
10037
|
+
skillIds: [
|
|
10038
|
+
`teamix-evo-design-${variant}`,
|
|
10039
|
+
`teamix-evo-code-${variant}`
|
|
10040
|
+
],
|
|
10041
|
+
globalSkillIds: ["teamix-evo-manage"],
|
|
10042
|
+
mode: "merge-managed"
|
|
10043
|
+
});
|
|
10044
|
+
record({
|
|
10045
|
+
name: "agents-md",
|
|
10046
|
+
status: "ok",
|
|
10047
|
+
detail: `${result.skillCount} skill index (${result.merge})`
|
|
10048
|
+
});
|
|
10049
|
+
} catch (err) {
|
|
10050
|
+
recordFailure("agents-md", err);
|
|
10051
|
+
}
|
|
10052
|
+
} else {
|
|
10053
|
+
record({ name: "agents-md", status: "skip", detail: "aborted" });
|
|
10054
|
+
}
|
|
10055
|
+
if (!aborted) {
|
|
10056
|
+
try {
|
|
10057
|
+
const agentsMdPath = path44.join(projectRoot, "AGENTS.md");
|
|
10058
|
+
const existing = await readFileOrNull(agentsMdPath) ?? "";
|
|
10059
|
+
const meta = LEGACY_LIB_META[legacyLib] ?? {
|
|
10060
|
+
displayName: legacyLib,
|
|
10061
|
+
imports: [legacyLib]
|
|
10062
|
+
};
|
|
10063
|
+
const importsStr = meta.imports.map((i) => `\`${i}\``).join("\u3001");
|
|
10064
|
+
const graftBody = renderGraftManagedBody(meta.displayName, importsStr);
|
|
10065
|
+
let output;
|
|
10066
|
+
if (hasManagedRegion5(existing, AGENTS_MD_GRAFT_MANAGED_ID)) {
|
|
10067
|
+
output = replaceManagedRegion4(
|
|
10068
|
+
existing,
|
|
10069
|
+
AGENTS_MD_GRAFT_MANAGED_ID,
|
|
10070
|
+
graftBody
|
|
10071
|
+
);
|
|
10072
|
+
} else {
|
|
10073
|
+
const wrapped = wrapGraftManagedBlock(graftBody);
|
|
10074
|
+
output = existing.trimEnd() + "\n\n" + wrapped + "\n";
|
|
10075
|
+
}
|
|
10076
|
+
await fsNode2.writeFile(agentsMdPath, output, "utf-8");
|
|
10077
|
+
record({ name: "agents-md-graft", status: "ok", detail: `dual-stack rules for ${legacyLib}` });
|
|
10078
|
+
} catch (err) {
|
|
10079
|
+
recordFailure("agents-md-graft", err);
|
|
10080
|
+
}
|
|
10081
|
+
} else {
|
|
10082
|
+
record({ name: "agents-md-graft", status: "skip", detail: "aborted" });
|
|
10083
|
+
}
|
|
10084
|
+
if (!aborted) {
|
|
10085
|
+
try {
|
|
10086
|
+
const uiResult = await landUiMeta(projectRoot);
|
|
10087
|
+
const bizResult = await landBizUiMeta(projectRoot, variant);
|
|
10088
|
+
record({
|
|
10089
|
+
name: "meta-landing",
|
|
10090
|
+
status: "ok",
|
|
10091
|
+
detail: `ui: ${uiResult.metaFilesWritten}/${uiResult.metaFilesTotal}, biz-ui: ${bizResult.metaFilesWritten}/${bizResult.metaFilesTotal}`
|
|
10092
|
+
});
|
|
10093
|
+
} catch (err) {
|
|
10094
|
+
recordFailure("meta-landing", err);
|
|
10095
|
+
}
|
|
10096
|
+
} else {
|
|
10097
|
+
record({ name: "meta-landing", status: "skip", detail: "aborted" });
|
|
10098
|
+
}
|
|
10099
|
+
if (!aborted) {
|
|
10100
|
+
try {
|
|
10101
|
+
const config = await readProjectConfig(projectRoot);
|
|
10102
|
+
if (config) {
|
|
10103
|
+
config.mode = "graft";
|
|
10104
|
+
config.legacyLib = legacyLib;
|
|
10105
|
+
await writeProjectConfig(projectRoot, config);
|
|
10106
|
+
record({ name: "config-mode", status: "ok", detail: `mode=graft, legacyLib=${legacyLib}` });
|
|
10107
|
+
} else {
|
|
10108
|
+
record({ name: "config-mode", status: "skip", detail: "no config.json found to patch" });
|
|
10109
|
+
}
|
|
10110
|
+
} catch (err) {
|
|
10111
|
+
recordFailure("config-mode", err);
|
|
10112
|
+
}
|
|
10113
|
+
} else {
|
|
10114
|
+
record({ name: "config-mode", status: "skip", detail: "aborted" });
|
|
10115
|
+
}
|
|
10116
|
+
if (!aborted) {
|
|
10117
|
+
try {
|
|
10118
|
+
const giPath = path44.join(projectRoot, ".gitignore");
|
|
10119
|
+
let giContent = "";
|
|
10120
|
+
try {
|
|
10121
|
+
giContent = await fsNode2.readFile(giPath, "utf-8");
|
|
10122
|
+
} catch {
|
|
10123
|
+
}
|
|
10124
|
+
if (giContent.includes(GITIGNORE_MARKER_START2)) {
|
|
10125
|
+
record({ name: "gitignore", status: "skip", detail: "teamix-evo markers already present" });
|
|
10126
|
+
} else {
|
|
10127
|
+
const block = [
|
|
10128
|
+
"",
|
|
10129
|
+
GITIGNORE_MARKER_START2,
|
|
10130
|
+
...GITIGNORE_RULES2,
|
|
10131
|
+
GITIGNORE_MARKER_END2,
|
|
10132
|
+
""
|
|
10133
|
+
].join("\n");
|
|
10134
|
+
const separator = giContent.length > 0 && !giContent.endsWith("\n") ? "\n" : "";
|
|
10135
|
+
await fsNode2.writeFile(giPath, giContent + separator + block, "utf-8");
|
|
10136
|
+
record({
|
|
10137
|
+
name: "gitignore",
|
|
10138
|
+
status: "ok",
|
|
10139
|
+
detail: `${GITIGNORE_RULES2.filter((r) => r && !r.startsWith("#")).length} rules appended`
|
|
10140
|
+
});
|
|
10141
|
+
}
|
|
10142
|
+
} catch (err) {
|
|
10143
|
+
recordFailure("gitignore", err);
|
|
10144
|
+
}
|
|
10145
|
+
} else {
|
|
10146
|
+
record({ name: "gitignore", status: "skip", detail: "aborted" });
|
|
10147
|
+
}
|
|
10148
|
+
const status = steps.some((s) => s.status === "fail") ? "partial" : "success";
|
|
10149
|
+
return { status, steps };
|
|
10150
|
+
}
|
|
10151
|
+
function renderGraftManagedBody(legacyLibName, legacyImports) {
|
|
10152
|
+
return `## \u53CC\u6808\u7814\u53D1\u89C4\u5219
|
|
10153
|
+
|
|
10154
|
+
\u672C\u9879\u76EE\u540C\u65F6\u5B58\u5728 ${legacyLibName}\uFF08\u65E7\u6808\uFF09\u548C teamix-evo\uFF08\u65B0\u6808\uFF09\u4E24\u5957\u6280\u672F\u6808\u3002
|
|
10155
|
+
|
|
10156
|
+
### \u5224\u65AD\u89C4\u5219\u2014\u2014\u901A\u8FC7 import \u8BED\u53E5\u8BC6\u522B
|
|
10157
|
+
- \u6587\u4EF6\u4E2D import \u4E86 ${legacyImports} \u2192 **\u65E7\u6808**\uFF0C\u6309 ${legacyLibName} \u89C4\u8303\u7814\u53D1\uFF0C**\u8DF3\u8FC7** teamix-evo \u7684 design / code skill
|
|
10158
|
+
- \u6587\u4EF6\u4E2D import \u4E86 \`@/components/ui\`\u3001\u4F7F\u7528 Tailwind class \u2192 **\u65B0\u6808**\uFF0C\u6B63\u5E38\u89E6\u53D1 teamix-evo design / code skill
|
|
10159
|
+
- \u65B0\u5EFA\u9875\u9762 \u2192 \u9ED8\u8BA4\u4F7F\u7528\u65B0\u6808\uFF08teamix-evo\uFF09
|
|
10160
|
+
|
|
10161
|
+
### \u7981\u6B62\u4E8B\u9879
|
|
10162
|
+
- \u7981\u6B62\u5728\u65E7\u6808\u6587\u4EF6\u4E2D\u5F15\u5165 \`@/components/ui\` \u6216 Tailwind class
|
|
10163
|
+
- \u7981\u6B62\u5728\u65B0\u6808\u6587\u4EF6\u4E2D\u5F15\u5165 ${legacyImports}
|
|
10164
|
+
- \u7981\u6B62\u5728\u540C\u4E00\u6587\u4EF6\u4E2D\u6DF7\u7528\u4E24\u5957\u7EC4\u4EF6\u5E93`;
|
|
10165
|
+
}
|
|
10166
|
+
function wrapGraftManagedBlock(body) {
|
|
10167
|
+
return `<!-- teamix-evo:managed:start id="${AGENTS_MD_GRAFT_MANAGED_ID}" -->
|
|
10168
|
+
${body}
|
|
10169
|
+
<!-- teamix-evo:managed:end id="${AGENTS_MD_GRAFT_MANAGED_ID}" -->`;
|
|
10170
|
+
}
|
|
10171
|
+
|
|
10172
|
+
// src/commands/graft/index.ts
|
|
10173
|
+
init_logger();
|
|
10174
|
+
init_error();
|
|
10175
|
+
init_fs();
|
|
10176
|
+
var APP_ENTRY_CANDIDATES = [
|
|
10177
|
+
"src/app.tsx",
|
|
10178
|
+
"src/app.ts",
|
|
10179
|
+
"src/app.jsx",
|
|
10180
|
+
"src/app.js",
|
|
10181
|
+
"src/index.tsx",
|
|
10182
|
+
"src/index.ts",
|
|
10183
|
+
"src/index.jsx",
|
|
10184
|
+
"src/index.js"
|
|
10185
|
+
];
|
|
10186
|
+
var POSTCSS_CONFIG_CANDIDATES = [
|
|
10187
|
+
"postcss.config.js",
|
|
10188
|
+
"postcss.config.cjs",
|
|
10189
|
+
"postcss.config.mjs",
|
|
10190
|
+
"postcss.config.ts",
|
|
10191
|
+
".postcssrc",
|
|
10192
|
+
".postcssrc.json",
|
|
10193
|
+
".postcssrc.yml",
|
|
10194
|
+
".postcssrc.yaml",
|
|
10195
|
+
".postcssrc.js"
|
|
10196
|
+
];
|
|
10197
|
+
var CONFLICT_PATHS = [
|
|
10198
|
+
{ path: ".teamix-evo", type: "directory" },
|
|
10199
|
+
{ path: "src/components/ui", type: "directory" },
|
|
10200
|
+
{ path: "src/components/business", type: "directory" },
|
|
10201
|
+
{ path: "tokens", type: "directory" }
|
|
10202
|
+
];
|
|
10203
|
+
async function findFirst(cwd, candidates) {
|
|
10204
|
+
for (const c of candidates) {
|
|
10205
|
+
if (await fileExists(path45.join(cwd, c))) return c;
|
|
10206
|
+
}
|
|
10207
|
+
return null;
|
|
10208
|
+
}
|
|
10209
|
+
async function getLegacyLibVersion(cwd, legacyLib) {
|
|
10210
|
+
const pkgRaw = await readFileOrNull(path45.join(cwd, "package.json"));
|
|
10211
|
+
if (!pkgRaw) return "unknown";
|
|
10212
|
+
try {
|
|
10213
|
+
const pkg = JSON.parse(pkgRaw);
|
|
10214
|
+
const allDeps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
10215
|
+
const libKeyMap = {
|
|
10216
|
+
fusion: ["@alifd/next", "@ali/teamix-material"],
|
|
10217
|
+
antd: ["antd"],
|
|
10218
|
+
element: ["element-ui", "element-plus"]
|
|
10219
|
+
};
|
|
10220
|
+
const keys = libKeyMap[legacyLib] ?? [];
|
|
10221
|
+
for (const key of keys) {
|
|
10222
|
+
if (allDeps[key]) return allDeps[key];
|
|
10223
|
+
}
|
|
10224
|
+
} catch {
|
|
10225
|
+
}
|
|
10226
|
+
return "unknown";
|
|
10227
|
+
}
|
|
10228
|
+
async function detectConflicts(cwd) {
|
|
10229
|
+
const conflicts = [];
|
|
10230
|
+
for (const entry of CONFLICT_PATHS) {
|
|
10231
|
+
const full = path45.join(cwd, entry.path);
|
|
10232
|
+
try {
|
|
10233
|
+
const stat6 = await fs32.stat(full);
|
|
10234
|
+
if (entry.type === "directory" && stat6.isDirectory() || entry.type === "file" && stat6.isFile()) {
|
|
10235
|
+
conflicts.push(entry);
|
|
10236
|
+
}
|
|
10237
|
+
} catch {
|
|
10238
|
+
}
|
|
10239
|
+
}
|
|
10240
|
+
return conflicts;
|
|
10241
|
+
}
|
|
10242
|
+
async function analyzeProject(cwd) {
|
|
10243
|
+
const state = await detectProjectState(cwd);
|
|
10244
|
+
if (state.state !== "other") {
|
|
10245
|
+
assertCommandPrecondition("graft", state.state);
|
|
10246
|
+
throw new Error("precondition-failed");
|
|
10247
|
+
}
|
|
10248
|
+
const legacyLib = state.legacyLib ?? "unknown";
|
|
10249
|
+
const buildTool = state.buildTool ?? "unknown";
|
|
10250
|
+
const legacyVersion = await getLegacyLibVersion(cwd, legacyLib);
|
|
10251
|
+
const BUILD_TOOL_CONFIG_CANDIDATES = {
|
|
10252
|
+
ice: ["build.json"],
|
|
10253
|
+
vite: [
|
|
10254
|
+
"vite.config.ts",
|
|
10255
|
+
"vite.config.js",
|
|
10256
|
+
"vite.config.mts",
|
|
10257
|
+
"vite.config.mjs"
|
|
10258
|
+
],
|
|
10259
|
+
webpack: ["webpack.config.js", "webpack.config.ts", "webpack.config.cjs"]
|
|
10260
|
+
};
|
|
10261
|
+
const buildToolConfig = await findFirst(
|
|
10262
|
+
cwd,
|
|
10263
|
+
BUILD_TOOL_CONFIG_CANDIDATES[buildTool] ?? []
|
|
10264
|
+
);
|
|
10265
|
+
const postcssPath = await findFirst(cwd, POSTCSS_CONFIG_CANDIDATES);
|
|
10266
|
+
const appEntry = await findFirst(cwd, APP_ENTRY_CANDIDATES);
|
|
10267
|
+
const conflicts = await detectConflicts(cwd);
|
|
10268
|
+
return {
|
|
10269
|
+
report: {
|
|
10270
|
+
projectRoot: cwd,
|
|
10271
|
+
legacyLib: { name: legacyLib, version: legacyVersion },
|
|
10272
|
+
buildTool: { type: buildTool, configFile: buildToolConfig },
|
|
10273
|
+
postcssConfig: { exists: postcssPath !== null, path: postcssPath },
|
|
10274
|
+
appEntry,
|
|
10275
|
+
conflicts
|
|
10276
|
+
},
|
|
10277
|
+
legacyLib
|
|
10278
|
+
};
|
|
10279
|
+
}
|
|
10280
|
+
function printReport(report) {
|
|
10281
|
+
logger.info("Teamix Evo Graft \u2014 \u53CC\u6808\u5171\u5B58\u524D\u7F6E\u68C0\u67E5");
|
|
10282
|
+
logger.info("");
|
|
10283
|
+
logger.info(` \u9879\u76EE\u76EE\u5F55\uFF1A${report.projectRoot}`);
|
|
10284
|
+
logger.info(
|
|
10285
|
+
` \u65E7\u7EC4\u4EF6\u5E93\uFF1A${report.legacyLib.name} (${report.legacyLib.version})`
|
|
10286
|
+
);
|
|
10287
|
+
logger.info(` \u6784\u5EFA\u5DE5\u5177\uFF1A${report.buildTool.type}`);
|
|
10288
|
+
logger.info(` PostCSS \u914D\u7F6E\uFF1A${report.postcssConfig.path ?? "\u672A\u68C0\u6D4B\u5230"}`);
|
|
10289
|
+
logger.info(` App \u5165\u53E3\uFF1A${report.appEntry ?? "\u672A\u68C0\u6D4B\u5230"}`);
|
|
10290
|
+
if (report.conflicts.length > 0) {
|
|
10291
|
+
logger.info("");
|
|
10292
|
+
logger.warn(" \u5DF2\u5B58\u5728\u7684\u8DEF\u5F84\uFF08\u53EF\u80FD\u51B2\u7A81\uFF09\uFF1A");
|
|
10293
|
+
for (const c of report.conflicts) {
|
|
10294
|
+
logger.warn(` ${c.path} (${c.type})`);
|
|
10295
|
+
}
|
|
10296
|
+
}
|
|
10297
|
+
}
|
|
10298
|
+
var graftCommand = new Command39("graft").description("\u53E0\u52A0 Teamix Evo AICoding \u80FD\u529B\u5230\u73B0\u6709\u9879\u76EE\uFF08\u53CC\u6808\u5171\u5B58\uFF0CADR 0047\uFF09").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").option("--apply", "\u6267\u884C graft pipeline\uFF08\u9ED8\u8BA4\u4EC5\u524D\u7F6E\u68C0\u67E5\uFF09").option("-y, --yes", "\u8DF3\u8FC7 --apply \u4E8C\u6B21\u786E\u8BA4").action(async (opts) => {
|
|
10299
|
+
const cwd = path45.resolve(opts.cwd ?? process.cwd());
|
|
10300
|
+
const apply = opts.apply ?? false;
|
|
10301
|
+
try {
|
|
10302
|
+
const { report, legacyLib } = await analyzeProject(cwd);
|
|
10303
|
+
if (opts.json) {
|
|
10304
|
+
console.log(JSON.stringify(report, null, 2));
|
|
10305
|
+
} else {
|
|
10306
|
+
printReport(report);
|
|
10307
|
+
}
|
|
10308
|
+
if (!apply) {
|
|
10309
|
+
if (!opts.json) {
|
|
10310
|
+
logger.info("");
|
|
10311
|
+
logger.info(
|
|
10312
|
+
"\u524D\u7F6E\u68C0\u67E5\u5B8C\u6210\u3002\u52A0 --apply --variant <v> \u6267\u884C graft pipeline\u3002"
|
|
10313
|
+
);
|
|
10314
|
+
}
|
|
10315
|
+
return;
|
|
10316
|
+
}
|
|
10317
|
+
if (!opts.variant) {
|
|
10318
|
+
logger.error("--apply \u9700\u8981\u6307\u5B9A --variant\uFF08\u5982 --variant opentrek\uFF09");
|
|
10319
|
+
process.exitCode = 1;
|
|
10320
|
+
return;
|
|
10321
|
+
}
|
|
10322
|
+
if (legacyLib === "unknown") {
|
|
10323
|
+
logger.error(
|
|
10324
|
+
"\u672A\u8BC6\u522B\u65E7\u7EC4\u4EF6\u5E93\u3002\u8BF7\u786E\u8BA4 package.json \u4E2D\u5305\u542B @alifd/next / antd / element-ui \u7B49\u4F9D\u8D56\u3002"
|
|
10325
|
+
);
|
|
10326
|
+
process.exitCode = 1;
|
|
10327
|
+
return;
|
|
10328
|
+
}
|
|
10329
|
+
const isInteractive = Boolean(process.stdin.isTTY);
|
|
10330
|
+
if (!opts.yes && isInteractive) {
|
|
10331
|
+
logger.info("");
|
|
10332
|
+
logger.info(
|
|
10333
|
+
`graft --apply \u5C06\u5B89\u88C5 teamix-evo \u5168\u6808\uFF08tokens + UI + biz-ui + skills + AGENTS.md\uFF09\uFF0Cvariant = "${opts.variant}"\u3002`
|
|
10334
|
+
);
|
|
10335
|
+
const confirmed = await prompts7.confirm({
|
|
10336
|
+
message: "\u7EE7\u7EED\u6267\u884C\uFF1F"
|
|
10337
|
+
});
|
|
10338
|
+
if (prompts7.isCancel(confirmed) || !confirmed) {
|
|
10339
|
+
logger.info("\u5DF2\u53D6\u6D88\u3002");
|
|
10340
|
+
return;
|
|
10341
|
+
}
|
|
10342
|
+
}
|
|
10343
|
+
logger.info("");
|
|
10344
|
+
logger.info("\u6267\u884C graft pipeline\u2026");
|
|
10345
|
+
logger.info("");
|
|
10346
|
+
const result = await runGraftInit({
|
|
10347
|
+
projectRoot: cwd,
|
|
10348
|
+
variant: opts.variant,
|
|
10349
|
+
legacyLib,
|
|
10350
|
+
onStep: (step) => {
|
|
10351
|
+
const icon = STEP_ICON[step.status];
|
|
10352
|
+
const detail = step.detail ? ` \u2014 ${step.detail}` : "";
|
|
10353
|
+
logger.info(` ${icon} ${step.name}${detail}`);
|
|
10354
|
+
}
|
|
10355
|
+
});
|
|
10356
|
+
logger.info("");
|
|
10357
|
+
if (result.status === "success") {
|
|
10358
|
+
logger.success(
|
|
10359
|
+
`graft \u5B8C\u6210\uFF08${result.steps.filter((s) => s.status === "ok").length}/${result.steps.length} \u6B65\u6210\u529F\uFF09`
|
|
10360
|
+
);
|
|
10361
|
+
} else {
|
|
10362
|
+
logger.warn("graft \u90E8\u5206\u5B8C\u6210\uFF08\u542B\u5931\u8D25\u6B65\u9AA4\uFF09\uFF0C\u8BE6\u89C1\u4E0A\u65B9\u660E\u7EC6\u3002");
|
|
10363
|
+
const failed = result.steps.filter((s) => s.status === "fail");
|
|
10364
|
+
for (const s of failed) {
|
|
10365
|
+
logger.error(` \u2716 ${s.name}: ${s.detail ?? "unknown error"}`);
|
|
10366
|
+
}
|
|
10367
|
+
process.exitCode = 1;
|
|
10368
|
+
}
|
|
10369
|
+
} catch (err) {
|
|
10370
|
+
if (getErrorMessage(err) !== "precondition-failed") {
|
|
10371
|
+
logger.error(`graft \u5931\u8D25\uFF1A${getErrorMessage(err)}`);
|
|
10372
|
+
logger.debug(err.stack ?? "");
|
|
10373
|
+
process.exitCode = 1;
|
|
10374
|
+
}
|
|
10375
|
+
}
|
|
10376
|
+
});
|
|
10377
|
+
|
|
9973
10378
|
// src/commands/restore/index.ts
|
|
10379
|
+
import { Command as Command40 } from "commander";
|
|
10380
|
+
import * as path46 from "path";
|
|
10381
|
+
import * as prompts8 from "@clack/prompts";
|
|
9974
10382
|
init_logger();
|
|
9975
10383
|
init_error();
|
|
9976
10384
|
function createRestoreCommand() {
|
|
9977
10385
|
return new Command40("restore").description(
|
|
9978
10386
|
"\u56DE\u6EDA .teamix-evo/ \u5230\u6307\u5B9A snapshot\uFF08init/update \u5931\u8D25\u65F6\u4F7F\u7528 \u2014 ADR 0019 \xA72\uFF09"
|
|
9979
10387
|
).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) => {
|
|
9980
|
-
const cwd =
|
|
10388
|
+
const cwd = path46.resolve(opts.cwd ?? process.cwd());
|
|
9981
10389
|
try {
|
|
9982
10390
|
const snapshots = await listSnapshots(cwd);
|
|
9983
10391
|
if (opts.list) {
|
|
@@ -10025,10 +10433,10 @@ function createRestoreCommand() {
|
|
|
10025
10433
|
logger.info(
|
|
10026
10434
|
'\u56DE\u6EDA\u524D\u4F1A\u81EA\u52A8\u518D\u505A\u4E00\u6B21 reason="restore" \u7684\u5B89\u5168 snapshot\uFF0C\u53EF\u4E8C\u6B21\u56DE\u6EDA\u3002'
|
|
10027
10435
|
);
|
|
10028
|
-
const confirmed = await
|
|
10436
|
+
const confirmed = await prompts8.confirm({
|
|
10029
10437
|
message: "\u7EE7\u7EED\u56DE\u6EDA\uFF1F"
|
|
10030
10438
|
});
|
|
10031
|
-
if (
|
|
10439
|
+
if (prompts8.isCancel(confirmed) || !confirmed) {
|
|
10032
10440
|
logger.info("\u5DF2\u53D6\u6D88\u3002");
|
|
10033
10441
|
return;
|
|
10034
10442
|
}
|
|
@@ -10074,12 +10482,12 @@ function printSnapshotTable(snapshots) {
|
|
|
10074
10482
|
|
|
10075
10483
|
// src/commands/switch/index.ts
|
|
10076
10484
|
import { Command as Command41 } from "commander";
|
|
10077
|
-
import * as
|
|
10078
|
-
import * as
|
|
10485
|
+
import * as path48 from "path";
|
|
10486
|
+
import * as prompts9 from "@clack/prompts";
|
|
10079
10487
|
|
|
10080
10488
|
// src/core/variant-switch.ts
|
|
10081
10489
|
init_fs();
|
|
10082
|
-
import * as
|
|
10490
|
+
import * as path47 from "path";
|
|
10083
10491
|
import * as fs33 from "fs/promises";
|
|
10084
10492
|
import {
|
|
10085
10493
|
loadTokensPackageManifest as loadTokensPackageManifest3,
|
|
@@ -10117,8 +10525,8 @@ async function runVariantSwitch(options) {
|
|
|
10117
10525
|
const upstreamByBasename = /* @__PURE__ */ new Map();
|
|
10118
10526
|
for (const fileRel of variantEntry.files) {
|
|
10119
10527
|
upstreamByBasename.set(
|
|
10120
|
-
|
|
10121
|
-
|
|
10528
|
+
path47.basename(fileRel),
|
|
10529
|
+
path47.join(packageRoot, fileRel)
|
|
10122
10530
|
);
|
|
10123
10531
|
}
|
|
10124
10532
|
const prior = await readInstalledManifest(projectRoot) ?? {
|
|
@@ -10132,7 +10540,7 @@ async function runVariantSwitch(options) {
|
|
|
10132
10540
|
const priorVersion = installedIdx >= 0 ? prior.installed[installedIdx].version : "0.0.0";
|
|
10133
10541
|
const changes = [];
|
|
10134
10542
|
for (const resource of priorResources) {
|
|
10135
|
-
const consumerBasename =
|
|
10543
|
+
const consumerBasename = path47.basename(resource.target);
|
|
10136
10544
|
const upstreamBasename = lookupUpstreamBasename2(consumerBasename);
|
|
10137
10545
|
const upstreamAbs = upstreamBasename ? upstreamByBasename.get(upstreamBasename) : void 0;
|
|
10138
10546
|
if (resource.strategy === "frozen") {
|
|
@@ -10206,8 +10614,8 @@ async function runVariantSwitch(options) {
|
|
|
10206
10614
|
}
|
|
10207
10615
|
const refreshedResources = [];
|
|
10208
10616
|
for (const resource of priorResources) {
|
|
10209
|
-
const consumerAbs =
|
|
10210
|
-
const consumerBasename =
|
|
10617
|
+
const consumerAbs = path47.isAbsolute(resource.target) ? resource.target : path47.join(projectRoot, resource.target);
|
|
10618
|
+
const consumerBasename = path47.basename(resource.target);
|
|
10211
10619
|
const upstreamBasename = lookupUpstreamBasename2(consumerBasename);
|
|
10212
10620
|
const upstreamAbs = upstreamBasename ? upstreamByBasename.get(upstreamBasename) : void 0;
|
|
10213
10621
|
if (resource.strategy === "regenerable" && upstreamAbs) {
|
|
@@ -10253,7 +10661,7 @@ async function runVariantSwitch(options) {
|
|
|
10253
10661
|
installedAt: now
|
|
10254
10662
|
};
|
|
10255
10663
|
await writeFileSafe(
|
|
10256
|
-
|
|
10664
|
+
path47.join(projectRoot, ".teamix-evo", "tokens-lock.json"),
|
|
10257
10665
|
JSON.stringify(lock, null, 2) + "\n"
|
|
10258
10666
|
);
|
|
10259
10667
|
logger.debug(
|
|
@@ -10373,7 +10781,7 @@ function createSwitchCommand() {
|
|
|
10373
10781
|
return new Command41("switch").description(
|
|
10374
10782
|
"variant \u5207\u6362\uFF1A\u5148\u5C55\u793A file-level diff\uFF0C--apply \u624D\u771F\u5199\uFF08ADR 0019 \xA7D3\uFF09"
|
|
10375
10783
|
).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) => {
|
|
10376
|
-
const cwd =
|
|
10784
|
+
const cwd = path48.resolve(opts.cwd ?? process.cwd());
|
|
10377
10785
|
const apply = opts.apply ?? false;
|
|
10378
10786
|
try {
|
|
10379
10787
|
const plan = await runVariantSwitch({
|
|
@@ -10419,10 +10827,10 @@ function createSwitchCommand() {
|
|
|
10419
10827
|
logger.info(
|
|
10420
10828
|
'\u6267\u884C\u524D\u4F1A\u81EA\u52A8\u6355\u83B7 reason="switch" snapshot\uFF0C\u53EF\u901A\u8FC7 `teamix-evo restore <ts>` \u56DE\u6EDA\u3002'
|
|
10421
10829
|
);
|
|
10422
|
-
const confirmed = await
|
|
10830
|
+
const confirmed = await prompts9.confirm({
|
|
10423
10831
|
message: `\u7EE7\u7EED\u5207\u6362\u81F3 "${newVariant}"\uFF1F`
|
|
10424
10832
|
});
|
|
10425
|
-
if (
|
|
10833
|
+
if (prompts9.isCancel(confirmed) || !confirmed) {
|
|
10426
10834
|
logger.info("\u5DF2\u53D6\u6D88\u3002");
|
|
10427
10835
|
return;
|
|
10428
10836
|
}
|