teamix-evo 0.4.0 → 0.5.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/README.md +22 -21
- package/dist/core/index.d.ts +13 -1
- package/dist/core/index.js +164 -102
- package/dist/core/index.js.map +1 -1
- package/dist/index.js +623 -231
- package/dist/index.js.map +1 -1
- package/package.json +5 -5
package/dist/index.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// src/index.ts
|
|
4
|
-
import { Command as
|
|
5
|
-
import { createRequire as
|
|
4
|
+
import { Command as Command29 } from "commander";
|
|
5
|
+
import { createRequire as createRequire7 } from "module";
|
|
6
6
|
|
|
7
7
|
// src/commands/tokens/index.ts
|
|
8
8
|
import { Command as Command6 } from "commander";
|
|
@@ -67,7 +67,7 @@ function detectIde() {
|
|
|
67
67
|
}
|
|
68
68
|
|
|
69
69
|
// src/core/tokens-init.ts
|
|
70
|
-
import * as
|
|
70
|
+
import * as path9 from "path";
|
|
71
71
|
import * as fs6 from "fs/promises";
|
|
72
72
|
import { createRequire as createRequire2 } from "module";
|
|
73
73
|
import {
|
|
@@ -321,7 +321,10 @@ async function loadSkillsData(packageName) {
|
|
|
321
321
|
// src/core/skills-installer.ts
|
|
322
322
|
import * as path7 from "path";
|
|
323
323
|
import * as fs5 from "fs/promises";
|
|
324
|
-
import {
|
|
324
|
+
import {
|
|
325
|
+
replaceManagedRegion,
|
|
326
|
+
hasManagedRegion
|
|
327
|
+
} from "@teamix-evo/registry";
|
|
325
328
|
|
|
326
329
|
// src/utils/template.ts
|
|
327
330
|
import Handlebars from "handlebars";
|
|
@@ -440,20 +443,63 @@ async function mirrorSkillToIde(skill, ide, scope, projectRoot) {
|
|
|
440
443
|
const rel2 = path7.relative(sourceDir, src);
|
|
441
444
|
const targetFile = path7.join(targetDir, rel2);
|
|
442
445
|
const sourceContent = await fs5.readFile(src, "utf-8");
|
|
443
|
-
const
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
await writeFileSafe(targetFile, sourceContent);
|
|
446
|
+
const writtenContent = await writeMirrorContent(
|
|
447
|
+
targetFile,
|
|
448
|
+
sourceContent,
|
|
449
|
+
skill.managedRegions,
|
|
450
|
+
src
|
|
451
|
+
);
|
|
450
452
|
records.push(
|
|
451
|
-
makeMirrorRecord(skill, targetFile,
|
|
453
|
+
makeMirrorRecord(skill, targetFile, writtenContent, ide, scope, rel2)
|
|
452
454
|
);
|
|
453
455
|
logger.debug(` Mirrored ${ide}:${scope}: ${targetFile}`);
|
|
454
456
|
}
|
|
455
457
|
return records;
|
|
456
458
|
}
|
|
459
|
+
async function writeMirrorContent(targetFile, sourceContent, managedRegions, sourceFile) {
|
|
460
|
+
const existing = await readFileOrNull(targetFile);
|
|
461
|
+
if (existing === null) {
|
|
462
|
+
await writeFileSafe(targetFile, sourceContent);
|
|
463
|
+
return sourceContent;
|
|
464
|
+
}
|
|
465
|
+
const regions = managedRegions ?? [];
|
|
466
|
+
const matchedRegions = regions.filter((id) => hasManagedRegion(existing, id));
|
|
467
|
+
if (matchedRegions.length === 0) {
|
|
468
|
+
if (existing !== sourceContent) {
|
|
469
|
+
logger.warn(
|
|
470
|
+
`Mirror drift detected at ${targetFile} \u2014 overwriting from source. Edit ${sourceFile} (not the mirror) and re-run \`teamix-evo skills sync\`.`
|
|
471
|
+
);
|
|
472
|
+
await writeFileSafe(targetFile, sourceContent);
|
|
473
|
+
return sourceContent;
|
|
474
|
+
}
|
|
475
|
+
return existing;
|
|
476
|
+
}
|
|
477
|
+
let merged = existing;
|
|
478
|
+
for (const id of matchedRegions) {
|
|
479
|
+
const newRegion = extractRegionBody(sourceContent, id);
|
|
480
|
+
if (newRegion === null) continue;
|
|
481
|
+
try {
|
|
482
|
+
merged = replaceManagedRegion(merged, id, newRegion);
|
|
483
|
+
} catch {
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
if (merged !== existing) {
|
|
487
|
+
await writeFileSafe(targetFile, merged);
|
|
488
|
+
}
|
|
489
|
+
return merged;
|
|
490
|
+
}
|
|
491
|
+
function extractRegionBody(content, id) {
|
|
492
|
+
const re = new RegExp(
|
|
493
|
+
`<!-- teamix-evo:managed:start id="${escapeRegExp(
|
|
494
|
+
id
|
|
495
|
+
)}" -->([\\s\\S]*?)<!-- teamix-evo:managed:end id="${escapeRegExp(
|
|
496
|
+
id
|
|
497
|
+
)}" -->`
|
|
498
|
+
);
|
|
499
|
+
const m = content.match(re);
|
|
500
|
+
if (!m) return null;
|
|
501
|
+
return m[1].replace(/^\n/, "").replace(/\n$/, "");
|
|
502
|
+
}
|
|
457
503
|
async function renderSkillContent(sourceAbs, skill, data) {
|
|
458
504
|
if (skill.template ?? sourceAbs.endsWith(".hbs")) {
|
|
459
505
|
const tpl = await loadTemplateFile(sourceAbs);
|
|
@@ -613,17 +659,16 @@ async function syncSkillsToIdes(options) {
|
|
|
613
659
|
const rel2 = path7.relative(sourceDir, src);
|
|
614
660
|
const targetFile = path7.join(targetDir, rel2);
|
|
615
661
|
const sourceContent = await fs5.readFile(src, "utf-8");
|
|
616
|
-
const
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
await writeFileSafe(targetFile, sourceContent);
|
|
662
|
+
const writtenContent = await writeMirrorContent(
|
|
663
|
+
targetFile,
|
|
664
|
+
sourceContent,
|
|
665
|
+
skill.managedRegions,
|
|
666
|
+
src
|
|
667
|
+
);
|
|
623
668
|
out.push({
|
|
624
669
|
id: rel2 === "SKILL.md" ? skill.id : `${skill.id}:${rel2}`,
|
|
625
670
|
target: targetFile,
|
|
626
|
-
hash: computeHash(
|
|
671
|
+
hash: computeHash(writtenContent),
|
|
627
672
|
strategy: skill.updateStrategy,
|
|
628
673
|
ide,
|
|
629
674
|
scope
|
|
@@ -662,6 +707,29 @@ async function removeSkillFiles(records) {
|
|
|
662
707
|
return removed;
|
|
663
708
|
}
|
|
664
709
|
|
|
710
|
+
// src/utils/mcp.ts
|
|
711
|
+
import * as path8 from "path";
|
|
712
|
+
var MCP_JSON_CONTENT = {
|
|
713
|
+
mcpServers: {
|
|
714
|
+
"teamix-evo": {
|
|
715
|
+
command: "npx",
|
|
716
|
+
args: ["-y", "@teamix-evo/mcp"]
|
|
717
|
+
}
|
|
718
|
+
}
|
|
719
|
+
};
|
|
720
|
+
async function ensureMcpJson(projectRoot) {
|
|
721
|
+
const mcpPath = path8.join(projectRoot, ".mcp.json");
|
|
722
|
+
if (await fileExists(mcpPath)) return "exists";
|
|
723
|
+
try {
|
|
724
|
+
await writeFileSafe(mcpPath, JSON.stringify(MCP_JSON_CONTENT, null, 2) + "\n");
|
|
725
|
+
logger.debug(`Wrote .mcp.json \u2192 ${mcpPath}`);
|
|
726
|
+
return "created";
|
|
727
|
+
} catch (err) {
|
|
728
|
+
logger.warn(`Failed to write .mcp.json: ${err.message}`);
|
|
729
|
+
return "failed";
|
|
730
|
+
}
|
|
731
|
+
}
|
|
732
|
+
|
|
665
733
|
// src/core/skills-add.ts
|
|
666
734
|
var DEFAULT_SKILLS_PACKAGE = "@teamix-evo/skills";
|
|
667
735
|
var FLAT_VARIANT = "_flat";
|
|
@@ -673,9 +741,6 @@ async function runSkillsAdd(options) {
|
|
|
673
741
|
await ensureTeamixDir(projectRoot);
|
|
674
742
|
const existingConfig = await readProjectConfig(projectRoot);
|
|
675
743
|
const existingSkillsCfg = existingConfig?.packages?.skills;
|
|
676
|
-
if (!isIncremental && existingSkillsCfg) {
|
|
677
|
-
return { status: "already-added" };
|
|
678
|
-
}
|
|
679
744
|
const ides = options.ides && options.ides.length > 0 ? [...options.ides] : existingSkillsCfg?.ides ? [...existingSkillsCfg.ides] : [];
|
|
680
745
|
const scope = options.scope ?? existingSkillsCfg?.scope;
|
|
681
746
|
if (ides.length === 0) {
|
|
@@ -713,8 +778,7 @@ async function runSkillsAdd(options) {
|
|
|
713
778
|
skippedSkillIds = requestedNames.filter((n) => existingSkillIds.has(n));
|
|
714
779
|
onlyIds = requestedNames.filter((n) => !existingSkillIds.has(n));
|
|
715
780
|
} else {
|
|
716
|
-
|
|
717
|
-
onlyIds = manifest.skills.filter((s) => {
|
|
781
|
+
const candidateIds = manifest.skills.filter((s) => {
|
|
718
782
|
if (!s.variant) return true;
|
|
719
783
|
if (!currentTokensVariant) {
|
|
720
784
|
logger.debug(
|
|
@@ -730,6 +794,11 @@ async function runSkillsAdd(options) {
|
|
|
730
794
|
}
|
|
731
795
|
return true;
|
|
732
796
|
}).map((s) => s.id);
|
|
797
|
+
skippedSkillIds = candidateIds.filter((id) => existingSkillIds.has(id));
|
|
798
|
+
onlyIds = candidateIds.filter((id) => !existingSkillIds.has(id));
|
|
799
|
+
}
|
|
800
|
+
if (!isIncremental && existingSkillsCfg && onlyIds.length === 0) {
|
|
801
|
+
return { status: "already-added" };
|
|
733
802
|
}
|
|
734
803
|
if (isIncremental && onlyIds.length === 0) {
|
|
735
804
|
return {
|
|
@@ -806,6 +875,7 @@ async function runSkillsAdd(options) {
|
|
|
806
875
|
};
|
|
807
876
|
}
|
|
808
877
|
await writeSkillsLock(projectRoot, lock);
|
|
878
|
+
await ensureMcpJson(projectRoot);
|
|
809
879
|
return {
|
|
810
880
|
status: "installed",
|
|
811
881
|
packageName,
|
|
@@ -843,6 +913,16 @@ async function runTokensInit(options) {
|
|
|
843
913
|
const { projectRoot, variant, ide } = options;
|
|
844
914
|
const packageName = options.packageName ?? DEFAULT_TOKENS_PACKAGE;
|
|
845
915
|
await ensureTeamixDir(projectRoot);
|
|
916
|
+
const packageRoot = options.packageRoot ?? resolveTokensPackageRoot(packageName);
|
|
917
|
+
const catalog = await loadTokensPackageManifest(packageRoot);
|
|
918
|
+
const variantEntry = getVariantEntry(catalog, variant);
|
|
919
|
+
if (!variantEntry) {
|
|
920
|
+
const known = catalog.variants.map((v) => v.name).join(", ");
|
|
921
|
+
throw new Error(
|
|
922
|
+
`Unknown variant "${variant}". Available variants: ${known || "(none)"}.
|
|
923
|
+
Run \`teamix-evo tokens list-variants\` to see all options.`
|
|
924
|
+
);
|
|
925
|
+
}
|
|
846
926
|
const existingConfig = await readProjectConfig(projectRoot);
|
|
847
927
|
if (existingConfig?.packages?.tokens) {
|
|
848
928
|
const existingVariant = existingConfig.packages.tokens.variant;
|
|
@@ -855,21 +935,12 @@ async function runTokensInit(options) {
|
|
|
855
935
|
requestedVariant: variant
|
|
856
936
|
};
|
|
857
937
|
}
|
|
858
|
-
const packageRoot = options.packageRoot ?? resolveTokensPackageRoot(packageName);
|
|
859
|
-
const catalog = await loadTokensPackageManifest(packageRoot);
|
|
860
|
-
const variantEntry = getVariantEntry(catalog, variant);
|
|
861
|
-
if (!variantEntry) {
|
|
862
|
-
const known = catalog.variants.map((v) => v.name).join(", ");
|
|
863
|
-
throw new Error(
|
|
864
|
-
`Tokens variant not found: "${variant}". Known variants: ${known || "(none)"}. Hint: run "teamix-evo tokens list-variants" to see all.`
|
|
865
|
-
);
|
|
866
|
-
}
|
|
867
938
|
const installed = [];
|
|
868
939
|
for (const fileRel of variantEntry.files) {
|
|
869
940
|
const result = await installVariantFile(fileRel, packageRoot, projectRoot);
|
|
870
941
|
if (result) installed.push(result);
|
|
871
942
|
}
|
|
872
|
-
const overridesAbs =
|
|
943
|
+
const overridesAbs = path9.join(
|
|
873
944
|
projectRoot,
|
|
874
945
|
CONSUMER_TOKENS_DIR,
|
|
875
946
|
CONSUMER_OVERRIDES_FILE
|
|
@@ -880,7 +951,7 @@ async function runTokensInit(options) {
|
|
|
880
951
|
const overridesContent = await fs6.readFile(overridesAbs, "utf-8");
|
|
881
952
|
installed.push({
|
|
882
953
|
id: `tokens:${CONSUMER_OVERRIDES_FILE}`,
|
|
883
|
-
target:
|
|
954
|
+
target: path9.posix.join(CONSUMER_TOKENS_DIR, CONSUMER_OVERRIDES_FILE),
|
|
884
955
|
hash: computeHash(overridesContent),
|
|
885
956
|
strategy: "frozen"
|
|
886
957
|
});
|
|
@@ -897,7 +968,7 @@ async function runTokensInit(options) {
|
|
|
897
968
|
installedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
898
969
|
};
|
|
899
970
|
await writeFileSafe(
|
|
900
|
-
|
|
971
|
+
path9.join(projectRoot, ".teamix-evo", "tokens-lock.json"),
|
|
901
972
|
JSON.stringify(lock, null, 2) + "\n"
|
|
902
973
|
);
|
|
903
974
|
const config = {
|
|
@@ -929,6 +1000,7 @@ async function runTokensInit(options) {
|
|
|
929
1000
|
if (tokensIdx >= 0) prior.installed[tokensIdx] = tokensEntry;
|
|
930
1001
|
else prior.installed.push(tokensEntry);
|
|
931
1002
|
await writeInstalledManifest(projectRoot, prior);
|
|
1003
|
+
await ensureMcpJson(projectRoot);
|
|
932
1004
|
const skills = await tryAutoInstallVariantSkills({
|
|
933
1005
|
projectRoot,
|
|
934
1006
|
variant,
|
|
@@ -1015,14 +1087,14 @@ async function tryAutoInstallVariantSkills(args) {
|
|
|
1015
1087
|
}
|
|
1016
1088
|
}
|
|
1017
1089
|
async function installVariantFile(fileRelToPackage, packageRoot, projectRoot) {
|
|
1018
|
-
const sourceAbs =
|
|
1019
|
-
const base =
|
|
1090
|
+
const sourceAbs = path9.join(packageRoot, fileRelToPackage);
|
|
1091
|
+
const base = path9.basename(fileRelToPackage);
|
|
1020
1092
|
if (base === "theme.css") {
|
|
1021
|
-
const targetRel =
|
|
1093
|
+
const targetRel = path9.posix.join(
|
|
1022
1094
|
CONSUMER_TOKENS_DIR,
|
|
1023
1095
|
CONSUMER_THEME_FILE
|
|
1024
1096
|
);
|
|
1025
|
-
const targetAbs =
|
|
1097
|
+
const targetAbs = path9.join(projectRoot, targetRel);
|
|
1026
1098
|
const content = await fs6.readFile(sourceAbs, "utf-8");
|
|
1027
1099
|
await writeFileSafe(targetAbs, content);
|
|
1028
1100
|
return {
|
|
@@ -1033,11 +1105,11 @@ async function installVariantFile(fileRelToPackage, packageRoot, projectRoot) {
|
|
|
1033
1105
|
};
|
|
1034
1106
|
}
|
|
1035
1107
|
if (base === "overrides.css" || base === "tokens.overrides.css") {
|
|
1036
|
-
const targetRel =
|
|
1108
|
+
const targetRel = path9.posix.join(
|
|
1037
1109
|
CONSUMER_TOKENS_DIR,
|
|
1038
1110
|
CONSUMER_OVERRIDES_FILE
|
|
1039
1111
|
);
|
|
1040
|
-
const targetAbs =
|
|
1112
|
+
const targetAbs = path9.join(projectRoot, targetRel);
|
|
1041
1113
|
if (await fileExists(targetAbs)) {
|
|
1042
1114
|
const existing = await fs6.readFile(targetAbs, "utf-8");
|
|
1043
1115
|
return {
|
|
@@ -1060,7 +1132,7 @@ async function installVariantFile(fileRelToPackage, packageRoot, projectRoot) {
|
|
|
1060
1132
|
}
|
|
1061
1133
|
function resolveTokensPackageRoot(packageName) {
|
|
1062
1134
|
const pkgJson = require3.resolve(`${packageName}/package.json`);
|
|
1063
|
-
return
|
|
1135
|
+
return path9.dirname(pkgJson);
|
|
1064
1136
|
}
|
|
1065
1137
|
async function listTokenVariants(packageName = DEFAULT_TOKENS_PACKAGE, packageRoot) {
|
|
1066
1138
|
const root = packageRoot ?? resolveTokensPackageRoot(packageName);
|
|
@@ -1078,11 +1150,46 @@ async function listTokenVariants(packageName = DEFAULT_TOKENS_PACKAGE, packageRo
|
|
|
1078
1150
|
};
|
|
1079
1151
|
}
|
|
1080
1152
|
|
|
1153
|
+
// src/utils/global-root.ts
|
|
1154
|
+
import { existsSync } from "fs";
|
|
1155
|
+
import * as fs7 from "fs/promises";
|
|
1156
|
+
import * as os3 from "os";
|
|
1157
|
+
import * as path10 from "path";
|
|
1158
|
+
var GLOBAL_META_DIR = ".teamix-evo-global";
|
|
1159
|
+
var TEAMIX_DIR2 = ".teamix-evo";
|
|
1160
|
+
var CONFIG_FILE2 = "config.json";
|
|
1161
|
+
function getGlobalMetaRoot() {
|
|
1162
|
+
return path10.join(os3.homedir(), GLOBAL_META_DIR);
|
|
1163
|
+
}
|
|
1164
|
+
function isTeamixEvoProject(dir) {
|
|
1165
|
+
return existsSync(path10.join(dir, TEAMIX_DIR2, CONFIG_FILE2));
|
|
1166
|
+
}
|
|
1167
|
+
async function ensureGlobalMetaRoot() {
|
|
1168
|
+
const root = getGlobalMetaRoot();
|
|
1169
|
+
await fs7.mkdir(root, { recursive: true });
|
|
1170
|
+
return root;
|
|
1171
|
+
}
|
|
1172
|
+
function hasPackageJson(projectRoot) {
|
|
1173
|
+
return existsSync(path10.join(projectRoot, "package.json"));
|
|
1174
|
+
}
|
|
1175
|
+
function resolveSkillsMaintenanceRoot(cwd) {
|
|
1176
|
+
if (isTeamixEvoProject(cwd)) return cwd;
|
|
1177
|
+
const globalRoot = getGlobalMetaRoot();
|
|
1178
|
+
if (isTeamixEvoProject(globalRoot)) return globalRoot;
|
|
1179
|
+
return cwd;
|
|
1180
|
+
}
|
|
1181
|
+
|
|
1081
1182
|
// src/commands/tokens/init.ts
|
|
1082
1183
|
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) => {
|
|
1083
1184
|
try {
|
|
1084
1185
|
const ide = detectIde();
|
|
1085
1186
|
const projectRoot = ide.getProjectRoot();
|
|
1187
|
+
if (!hasPackageJson(projectRoot)) {
|
|
1188
|
+
logger.error(
|
|
1189
|
+
"No package.json found in current directory. Please run this command in a valid project root."
|
|
1190
|
+
);
|
|
1191
|
+
process.exit(1);
|
|
1192
|
+
}
|
|
1086
1193
|
logger.info(`Initializing design system: variant="${variant}"`);
|
|
1087
1194
|
logger.debug(`Project root: ${projectRoot}`);
|
|
1088
1195
|
logger.debug(`IDE: ${ide.name}`);
|
|
@@ -1152,8 +1259,8 @@ var initCommand = new Command("init").description("\u521D\u59CB\u5316\u8BBE\u8BA
|
|
|
1152
1259
|
import { Command as Command2 } from "commander";
|
|
1153
1260
|
|
|
1154
1261
|
// src/core/tokens-update.ts
|
|
1155
|
-
import * as
|
|
1156
|
-
import * as
|
|
1262
|
+
import * as path11 from "path";
|
|
1263
|
+
import * as fs8 from "fs/promises";
|
|
1157
1264
|
import { createRequire as createRequire3 } from "module";
|
|
1158
1265
|
import {
|
|
1159
1266
|
loadTokensPackageManifest as loadTokensPackageManifest2,
|
|
@@ -1195,7 +1302,7 @@ async function runTokensUpdate(options) {
|
|
|
1195
1302
|
projectRoot
|
|
1196
1303
|
);
|
|
1197
1304
|
const preserved = [];
|
|
1198
|
-
const overridesAbs =
|
|
1305
|
+
const overridesAbs = path11.join(
|
|
1199
1306
|
projectRoot,
|
|
1200
1307
|
CONSUMER_TOKENS_DIR2,
|
|
1201
1308
|
"tokens.overrides.css"
|
|
@@ -1214,7 +1321,7 @@ async function runTokensUpdate(options) {
|
|
|
1214
1321
|
installedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
1215
1322
|
};
|
|
1216
1323
|
await writeFileSafe(
|
|
1217
|
-
|
|
1324
|
+
path11.join(projectRoot, ".teamix-evo", "tokens-lock.json"),
|
|
1218
1325
|
JSON.stringify(lock, null, 2) + "\n"
|
|
1219
1326
|
);
|
|
1220
1327
|
config.packages.tokens.version = variantEntry.version;
|
|
@@ -1229,9 +1336,9 @@ async function runTokensUpdate(options) {
|
|
|
1229
1336
|
prior.installed[idx].installedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
1230
1337
|
for (const r of prior.installed[idx].resources) {
|
|
1231
1338
|
if (r.strategy === "regenerable") {
|
|
1232
|
-
const abs =
|
|
1339
|
+
const abs = path11.isAbsolute(r.target) ? r.target : path11.join(projectRoot, r.target);
|
|
1233
1340
|
if (await fileExists(abs)) {
|
|
1234
|
-
r.hash = computeHash(await
|
|
1341
|
+
r.hash = computeHash(await fs8.readFile(abs, "utf-8"));
|
|
1235
1342
|
}
|
|
1236
1343
|
}
|
|
1237
1344
|
}
|
|
@@ -1250,15 +1357,15 @@ async function runTokensUpdate(options) {
|
|
|
1250
1357
|
async function rewriteRegenerableFiles(files, packageRoot, projectRoot) {
|
|
1251
1358
|
const written = [];
|
|
1252
1359
|
for (const fileRel of files) {
|
|
1253
|
-
const base =
|
|
1360
|
+
const base = path11.basename(fileRel);
|
|
1254
1361
|
if (base !== "theme.css") continue;
|
|
1255
|
-
const sourceAbs =
|
|
1256
|
-
const targetAbs =
|
|
1362
|
+
const sourceAbs = path11.join(packageRoot, fileRel);
|
|
1363
|
+
const targetAbs = path11.join(
|
|
1257
1364
|
projectRoot,
|
|
1258
1365
|
CONSUMER_TOKENS_DIR2,
|
|
1259
1366
|
CONSUMER_THEME_FILE2
|
|
1260
1367
|
);
|
|
1261
|
-
const content = await
|
|
1368
|
+
const content = await fs8.readFile(sourceAbs, "utf-8");
|
|
1262
1369
|
await writeFileSafe(targetAbs, content);
|
|
1263
1370
|
written.push(CONSUMER_THEME_FILE2);
|
|
1264
1371
|
}
|
|
@@ -1266,7 +1373,7 @@ async function rewriteRegenerableFiles(files, packageRoot, projectRoot) {
|
|
|
1266
1373
|
}
|
|
1267
1374
|
function resolveTokensPackageRoot2(packageName) {
|
|
1268
1375
|
const pkgJson = require4.resolve(`${packageName}/package.json`);
|
|
1269
|
-
return
|
|
1376
|
+
return path11.dirname(pkgJson);
|
|
1270
1377
|
}
|
|
1271
1378
|
|
|
1272
1379
|
// src/commands/tokens/update.ts
|
|
@@ -1382,8 +1489,8 @@ var listVariantsCommand = new Command4("list-variants").description("\u5217\u51F
|
|
|
1382
1489
|
|
|
1383
1490
|
// src/commands/tokens/uninstall.ts
|
|
1384
1491
|
import { Command as Command5 } from "commander";
|
|
1385
|
-
import * as
|
|
1386
|
-
import * as
|
|
1492
|
+
import * as fs9 from "fs/promises";
|
|
1493
|
+
import * as path12 from "path";
|
|
1387
1494
|
import * as prompts from "@clack/prompts";
|
|
1388
1495
|
var TOKENS_PACKAGE = "@teamix-evo/tokens";
|
|
1389
1496
|
var uninstallCommand = new Command5("uninstall").description(
|
|
@@ -1425,9 +1532,9 @@ var uninstallCommand = new Command5("uninstall").description(
|
|
|
1425
1532
|
}
|
|
1426
1533
|
let removed = 0;
|
|
1427
1534
|
for (const r of removable) {
|
|
1428
|
-
const target =
|
|
1535
|
+
const target = path12.isAbsolute(r.target) ? r.target : path12.join(projectRoot, r.target);
|
|
1429
1536
|
try {
|
|
1430
|
-
await
|
|
1537
|
+
await fs9.unlink(target);
|
|
1431
1538
|
removed++;
|
|
1432
1539
|
} catch (err) {
|
|
1433
1540
|
if (err.code !== "ENOENT") {
|
|
@@ -1445,13 +1552,13 @@ var uninstallCommand = new Command5("uninstall").description(
|
|
|
1445
1552
|
}
|
|
1446
1553
|
delete config.packages.tokens;
|
|
1447
1554
|
await writeProjectConfig(projectRoot, config);
|
|
1448
|
-
const lockPath =
|
|
1555
|
+
const lockPath = path12.join(
|
|
1449
1556
|
projectRoot,
|
|
1450
1557
|
".teamix-evo",
|
|
1451
1558
|
"tokens-lock.json"
|
|
1452
1559
|
);
|
|
1453
1560
|
try {
|
|
1454
|
-
await
|
|
1561
|
+
await fs9.unlink(lockPath);
|
|
1455
1562
|
} catch (err) {
|
|
1456
1563
|
if (err.code !== "ENOENT") {
|
|
1457
1564
|
logger.warn(
|
|
@@ -1486,34 +1593,6 @@ import { Command as Command13 } from "commander";
|
|
|
1486
1593
|
// src/commands/skills/add.ts
|
|
1487
1594
|
import { Command as Command7 } from "commander";
|
|
1488
1595
|
import * as prompts2 from "@clack/prompts";
|
|
1489
|
-
|
|
1490
|
-
// src/utils/global-root.ts
|
|
1491
|
-
import { existsSync } from "fs";
|
|
1492
|
-
import * as fs9 from "fs/promises";
|
|
1493
|
-
import * as os3 from "os";
|
|
1494
|
-
import * as path11 from "path";
|
|
1495
|
-
var GLOBAL_META_DIR = ".teamix-evo-global";
|
|
1496
|
-
var TEAMIX_DIR2 = ".teamix-evo";
|
|
1497
|
-
var CONFIG_FILE2 = "config.json";
|
|
1498
|
-
function getGlobalMetaRoot() {
|
|
1499
|
-
return path11.join(os3.homedir(), GLOBAL_META_DIR);
|
|
1500
|
-
}
|
|
1501
|
-
function isTeamixEvoProject(dir) {
|
|
1502
|
-
return existsSync(path11.join(dir, TEAMIX_DIR2, CONFIG_FILE2));
|
|
1503
|
-
}
|
|
1504
|
-
async function ensureGlobalMetaRoot() {
|
|
1505
|
-
const root = getGlobalMetaRoot();
|
|
1506
|
-
await fs9.mkdir(root, { recursive: true });
|
|
1507
|
-
return root;
|
|
1508
|
-
}
|
|
1509
|
-
function resolveSkillsMaintenanceRoot(cwd) {
|
|
1510
|
-
if (isTeamixEvoProject(cwd)) return cwd;
|
|
1511
|
-
const globalRoot = getGlobalMetaRoot();
|
|
1512
|
-
if (isTeamixEvoProject(globalRoot)) return globalRoot;
|
|
1513
|
-
return cwd;
|
|
1514
|
-
}
|
|
1515
|
-
|
|
1516
|
-
// src/commands/skills/add.ts
|
|
1517
1596
|
var addCommand = new Command7("add").description(
|
|
1518
1597
|
"\u5411\u9879\u76EE\uFF08\u6216\u5168\u5C40 IDE \u914D\u7F6E\uFF09\u6DFB\u52A0 teamix-evo skills\uFF1B\u4E0D\u4F20 names \u5219\u6DFB\u52A0 manifest \u5185\u5168\u90E8 skill"
|
|
1519
1598
|
).argument(
|
|
@@ -1536,6 +1615,11 @@ var addCommand = new Command7("add").description(
|
|
|
1536
1615
|
if (scope === "global" && !isTeamixEvoProject(cwd)) {
|
|
1537
1616
|
projectRoot = await ensureGlobalMetaRoot();
|
|
1538
1617
|
logger.info(`Global skill install \u2014 meta root: ${projectRoot}`);
|
|
1618
|
+
} else if (scope !== "global" && !hasPackageJson(cwd)) {
|
|
1619
|
+
logger.error(
|
|
1620
|
+
"No package.json found in current directory. Please run this command in a valid project root."
|
|
1621
|
+
);
|
|
1622
|
+
process.exit(1);
|
|
1539
1623
|
}
|
|
1540
1624
|
logger.info(
|
|
1541
1625
|
isIncremental ? `Adding skills [${names.join(",")}]: ides=[${ides.join(
|
|
@@ -1843,7 +1927,7 @@ var updateCommand2 = new Command9("update").description("\u66F4\u65B0\u5DF2\u5B8
|
|
|
1843
1927
|
// src/commands/skills/uninstall.ts
|
|
1844
1928
|
import { Command as Command10 } from "commander";
|
|
1845
1929
|
import * as prompts3 from "@clack/prompts";
|
|
1846
|
-
import * as
|
|
1930
|
+
import * as path13 from "path";
|
|
1847
1931
|
import * as fs10 from "fs/promises";
|
|
1848
1932
|
var SKILLS_PACKAGE3 = "@teamix-evo/skills";
|
|
1849
1933
|
var uninstallCommand2 = new Command10("uninstall").description(
|
|
@@ -1912,6 +1996,7 @@ async function runFullUninstall(args) {
|
|
|
1912
1996
|
const removed = await removeSkillFiles(resources);
|
|
1913
1997
|
logger.debug(`Removed ${removed.length} files`);
|
|
1914
1998
|
const skillsRoot = getSkillsSourceDir(projectRoot);
|
|
1999
|
+
const sourceSkillNames = await listSkillSourceNames(skillsRoot);
|
|
1915
2000
|
try {
|
|
1916
2001
|
await fs10.rm(skillsRoot, { recursive: true, force: true });
|
|
1917
2002
|
logger.debug(`Removed source dir ${skillsRoot}`);
|
|
@@ -1920,6 +2005,17 @@ async function runFullUninstall(args) {
|
|
|
1920
2005
|
`Failed to remove ${skillsRoot}: ${err.message}`
|
|
1921
2006
|
);
|
|
1922
2007
|
}
|
|
2008
|
+
const skillNames = collectSkillNames({
|
|
2009
|
+
fromSources: sourceSkillNames,
|
|
2010
|
+
fromConfig: config,
|
|
2011
|
+
fromResources: resources
|
|
2012
|
+
});
|
|
2013
|
+
const cleanedMirrorDirs = await removeMirrorDirs(
|
|
2014
|
+
projectRoot,
|
|
2015
|
+
config?.packages?.skills?.scope,
|
|
2016
|
+
config?.packages?.skills?.ides,
|
|
2017
|
+
skillNames
|
|
2018
|
+
);
|
|
1923
2019
|
if (installedManifest && pkg) {
|
|
1924
2020
|
installedManifest.installed = installedManifest.installed.filter(
|
|
1925
2021
|
(p) => p.package !== SKILLS_PACKAGE3
|
|
@@ -1930,7 +2026,12 @@ async function runFullUninstall(args) {
|
|
|
1930
2026
|
await writeProjectConfig(projectRoot, config);
|
|
1931
2027
|
logger.success(`Uninstalled ${SKILLS_PACKAGE3}`);
|
|
1932
2028
|
logger.info(` Removed: ${removed.length} files`);
|
|
1933
|
-
logger.info(` Source: ${
|
|
2029
|
+
logger.info(` Source: ${path13.relative(projectRoot, skillsRoot)} (cleaned)`);
|
|
2030
|
+
if (cleanedMirrorDirs.length > 0) {
|
|
2031
|
+
logger.info(
|
|
2032
|
+
` Mirrors: ${cleanedMirrorDirs.map((d) => path13.relative(projectRoot, d)).join(", ")} (cleaned)`
|
|
2033
|
+
);
|
|
2034
|
+
}
|
|
1934
2035
|
}
|
|
1935
2036
|
async function runPartialUninstall(args) {
|
|
1936
2037
|
const { projectRoot, installedManifest, pkg, resources, ids, opts } = args;
|
|
@@ -1972,6 +2073,13 @@ async function runPartialUninstall(args) {
|
|
|
1972
2073
|
logger.warn(`Failed to remove ${dir}: ${err.message}`);
|
|
1973
2074
|
}
|
|
1974
2075
|
}
|
|
2076
|
+
const config = await readProjectConfig(projectRoot);
|
|
2077
|
+
const cleanedMirrorDirs = await removeMirrorDirs(
|
|
2078
|
+
projectRoot,
|
|
2079
|
+
config?.packages?.skills?.scope,
|
|
2080
|
+
config?.packages?.skills?.ides,
|
|
2081
|
+
matched
|
|
2082
|
+
);
|
|
1975
2083
|
const lock = await readSkillsLock(projectRoot);
|
|
1976
2084
|
if (lock) {
|
|
1977
2085
|
for (const id of matched) delete lock.skills[id];
|
|
@@ -1985,10 +2093,69 @@ async function runPartialUninstall(args) {
|
|
|
1985
2093
|
`Removed ${matched.length} skill(s): ${matched.join(", ")}`
|
|
1986
2094
|
);
|
|
1987
2095
|
logger.info(` Files: ${removed.length}`);
|
|
2096
|
+
if (cleanedMirrorDirs.length > 0) {
|
|
2097
|
+
logger.info(
|
|
2098
|
+
` Mirrors: ${cleanedMirrorDirs.map((d) => path13.relative(projectRoot, d)).join(", ")} (cleaned)`
|
|
2099
|
+
);
|
|
2100
|
+
}
|
|
1988
2101
|
if (missing.length > 0) {
|
|
1989
2102
|
logger.info(` Skipped: ${missing.join(", ")} (not installed)`);
|
|
1990
2103
|
}
|
|
1991
2104
|
}
|
|
2105
|
+
async function listSkillSourceNames(skillsRoot) {
|
|
2106
|
+
try {
|
|
2107
|
+
const entries = await fs10.readdir(skillsRoot, { withFileTypes: true });
|
|
2108
|
+
return entries.filter((e) => e.isDirectory()).map((e) => e.name);
|
|
2109
|
+
} catch {
|
|
2110
|
+
return [];
|
|
2111
|
+
}
|
|
2112
|
+
}
|
|
2113
|
+
function collectSkillNames(args) {
|
|
2114
|
+
const set = new Set(args.fromSources);
|
|
2115
|
+
for (const r of args.fromResources) {
|
|
2116
|
+
set.add(r.id.split(":")[0]);
|
|
2117
|
+
}
|
|
2118
|
+
return [...set];
|
|
2119
|
+
}
|
|
2120
|
+
async function removeMirrorDirs(projectRoot, scope, ides, skillNames) {
|
|
2121
|
+
if (skillNames.length === 0) return [];
|
|
2122
|
+
const targetIdes = ides && ides.length > 0 ? ides.filter((i) => i === "qoder" || i === "claude") : [...ALL_IDE_KINDS];
|
|
2123
|
+
const targetScope = scope === "global" ? "global" : "project";
|
|
2124
|
+
const removed = [];
|
|
2125
|
+
for (const ide of targetIdes) {
|
|
2126
|
+
const adapter = getAdapter(ide);
|
|
2127
|
+
for (const name of skillNames) {
|
|
2128
|
+
const dir = adapter.getSkillTargetDir(name, targetScope, projectRoot);
|
|
2129
|
+
let existed = true;
|
|
2130
|
+
try {
|
|
2131
|
+
await fs10.access(dir);
|
|
2132
|
+
} catch {
|
|
2133
|
+
existed = false;
|
|
2134
|
+
}
|
|
2135
|
+
if (!existed) continue;
|
|
2136
|
+
try {
|
|
2137
|
+
await fs10.rm(dir, { recursive: true, force: true });
|
|
2138
|
+
removed.push(dir);
|
|
2139
|
+
logger.debug(`Removed mirror dir ${dir}`);
|
|
2140
|
+
} catch (err) {
|
|
2141
|
+
logger.warn(`Failed to remove ${dir}: ${err.message}`);
|
|
2142
|
+
}
|
|
2143
|
+
}
|
|
2144
|
+
if (removed.length > 0) {
|
|
2145
|
+
const skillsParent = path13.dirname(
|
|
2146
|
+
adapter.getSkillTargetDir("placeholder", targetScope, projectRoot)
|
|
2147
|
+
);
|
|
2148
|
+
try {
|
|
2149
|
+
const remaining = await fs10.readdir(skillsParent);
|
|
2150
|
+
if (remaining.length === 0) {
|
|
2151
|
+
await fs10.rmdir(skillsParent);
|
|
2152
|
+
}
|
|
2153
|
+
} catch {
|
|
2154
|
+
}
|
|
2155
|
+
}
|
|
2156
|
+
}
|
|
2157
|
+
return removed;
|
|
2158
|
+
}
|
|
1992
2159
|
function skillIdOf(r) {
|
|
1993
2160
|
return r.id.split(":")[0];
|
|
1994
2161
|
}
|
|
@@ -2010,7 +2177,7 @@ function dedupe(values) {
|
|
|
2010
2177
|
import { Command as Command11 } from "commander";
|
|
2011
2178
|
|
|
2012
2179
|
// src/core/skills-sync.ts
|
|
2013
|
-
import * as
|
|
2180
|
+
import * as path14 from "path";
|
|
2014
2181
|
import * as fs11 from "fs/promises";
|
|
2015
2182
|
import { createRequire as createRequire4 } from "module";
|
|
2016
2183
|
import { loadSkillsPackageManifest as loadSkillsPackageManifest2 } from "@teamix-evo/registry";
|
|
@@ -2018,7 +2185,7 @@ var require5 = createRequire4(import.meta.url);
|
|
|
2018
2185
|
async function readSkillMetaFromUpstream(skillId) {
|
|
2019
2186
|
try {
|
|
2020
2187
|
const pkgJson = require5.resolve("@teamix-evo/skills/package.json");
|
|
2021
|
-
const packageRoot =
|
|
2188
|
+
const packageRoot = path14.dirname(pkgJson);
|
|
2022
2189
|
const manifest = await loadSkillsPackageManifest2(packageRoot);
|
|
2023
2190
|
const entry = manifest.skills.find((s) => s.id === skillId);
|
|
2024
2191
|
if (!entry) return null;
|
|
@@ -2192,7 +2359,7 @@ function parseScope2(input) {
|
|
|
2192
2359
|
import { Command as Command12 } from "commander";
|
|
2193
2360
|
|
|
2194
2361
|
// src/core/skills-doctor.ts
|
|
2195
|
-
import * as
|
|
2362
|
+
import * as path15 from "path";
|
|
2196
2363
|
import * as fs12 from "fs/promises";
|
|
2197
2364
|
async function runSkillsDoctor(options) {
|
|
2198
2365
|
const { projectRoot } = options;
|
|
@@ -2215,7 +2382,7 @@ async function runSkillsDoctor(options) {
|
|
|
2215
2382
|
const sourceFiles = await walkDir(sourceDir);
|
|
2216
2383
|
const sourceContents = /* @__PURE__ */ new Map();
|
|
2217
2384
|
for (const f of sourceFiles) {
|
|
2218
|
-
const rel2 =
|
|
2385
|
+
const rel2 = path15.relative(sourceDir, f);
|
|
2219
2386
|
sourceContents.set(rel2, await fs12.readFile(f, "utf-8"));
|
|
2220
2387
|
}
|
|
2221
2388
|
for (const ide of entry.mirroredTo) {
|
|
@@ -2237,7 +2404,7 @@ async function runSkillsDoctor(options) {
|
|
|
2237
2404
|
continue;
|
|
2238
2405
|
}
|
|
2239
2406
|
for (const [rel2, sourceContent] of sourceContents.entries()) {
|
|
2240
|
-
const mirrorFile =
|
|
2407
|
+
const mirrorFile = path15.join(mirrorDir, rel2);
|
|
2241
2408
|
if (!await fileExists(mirrorFile)) {
|
|
2242
2409
|
findings.push({
|
|
2243
2410
|
kind: "missing-mirror",
|
|
@@ -2335,35 +2502,6 @@ import { Command as Command14 } from "commander";
|
|
|
2335
2502
|
import * as prompts4 from "@clack/prompts";
|
|
2336
2503
|
|
|
2337
2504
|
// 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
|
-
}
|
|
2367
2505
|
var DEFAULT_UI_ALIASES = {
|
|
2368
2506
|
components: "src/components/ui",
|
|
2369
2507
|
hooks: "src/hooks",
|
|
@@ -2407,14 +2545,13 @@ async function runUiInit(options) {
|
|
|
2407
2545
|
rsc
|
|
2408
2546
|
};
|
|
2409
2547
|
await writeProjectConfig(projectRoot, config);
|
|
2410
|
-
|
|
2548
|
+
await ensureMcpJson(projectRoot);
|
|
2411
2549
|
return {
|
|
2412
2550
|
status: "installed",
|
|
2413
2551
|
aliases,
|
|
2414
2552
|
iconLibrary,
|
|
2415
2553
|
tsx,
|
|
2416
|
-
rsc
|
|
2417
|
-
preferencesCss
|
|
2554
|
+
rsc
|
|
2418
2555
|
};
|
|
2419
2556
|
}
|
|
2420
2557
|
|
|
@@ -2429,6 +2566,12 @@ var initCommand2 = new Command14("init").description(
|
|
|
2429
2566
|
try {
|
|
2430
2567
|
const ide = detectIde();
|
|
2431
2568
|
const projectRoot = ide.getProjectRoot();
|
|
2569
|
+
if (!hasPackageJson(projectRoot)) {
|
|
2570
|
+
logger.error(
|
|
2571
|
+
"No package.json found in current directory. Please run this command in a valid project root."
|
|
2572
|
+
);
|
|
2573
|
+
process.exit(1);
|
|
2574
|
+
}
|
|
2432
2575
|
const cfg = await resolveConfig(opts);
|
|
2433
2576
|
const result = await runUiInit({
|
|
2434
2577
|
projectRoot,
|
|
@@ -2451,14 +2594,6 @@ var initCommand2 = new Command14("init").description(
|
|
|
2451
2594
|
logger.info(` lib: ${result.aliases.lib}`);
|
|
2452
2595
|
logger.info(` iconLibrary: ${result.iconLibrary}`);
|
|
2453
2596
|
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
|
-
}
|
|
2462
2597
|
logger.info("");
|
|
2463
2598
|
logger.info("Next: `npx teamix-evo ui add button`");
|
|
2464
2599
|
} catch (err) {
|
|
@@ -2538,12 +2673,12 @@ import { Command as Command15 } from "commander";
|
|
|
2538
2673
|
|
|
2539
2674
|
// src/core/ui-client.ts
|
|
2540
2675
|
import * as path16 from "path";
|
|
2541
|
-
import * as
|
|
2542
|
-
import { createRequire as
|
|
2676
|
+
import * as fs13 from "fs/promises";
|
|
2677
|
+
import { createRequire as createRequire5 } from "module";
|
|
2543
2678
|
import { loadUiPackageManifest } from "@teamix-evo/registry";
|
|
2544
|
-
var
|
|
2679
|
+
var require6 = createRequire5(import.meta.url);
|
|
2545
2680
|
function resolvePackageRoot2(packageName) {
|
|
2546
|
-
const pkgJsonPath =
|
|
2681
|
+
const pkgJsonPath = require6.resolve(`${packageName}/package.json`);
|
|
2547
2682
|
return path16.dirname(pkgJsonPath);
|
|
2548
2683
|
}
|
|
2549
2684
|
async function loadUiData(packageName) {
|
|
@@ -2553,7 +2688,7 @@ async function loadUiData(packageName) {
|
|
|
2553
2688
|
let data = {};
|
|
2554
2689
|
const dataPath = path16.join(packageRoot, "_data.json");
|
|
2555
2690
|
try {
|
|
2556
|
-
const raw = await
|
|
2691
|
+
const raw = await fs13.readFile(dataPath, "utf-8");
|
|
2557
2692
|
data = JSON.parse(raw);
|
|
2558
2693
|
} catch (err) {
|
|
2559
2694
|
if (err.code !== "ENOENT") {
|
|
@@ -2566,7 +2701,7 @@ async function loadUiData(packageName) {
|
|
|
2566
2701
|
|
|
2567
2702
|
// src/core/ui-installer.ts
|
|
2568
2703
|
import * as path17 from "path";
|
|
2569
|
-
import * as
|
|
2704
|
+
import * as fs14 from "fs/promises";
|
|
2570
2705
|
import { resolveUiEntryOrder } from "@teamix-evo/registry";
|
|
2571
2706
|
|
|
2572
2707
|
// src/utils/transform-imports.ts
|
|
@@ -2579,13 +2714,13 @@ var SOURCE_ROOT_TO_ALIAS_KEY = {
|
|
|
2579
2714
|
function rewriteImports(source, aliases) {
|
|
2580
2715
|
return source.replace(
|
|
2581
2716
|
/(['"])@\/([a-z][a-z0-9-]*)(\/[^'"]*)?\1/g,
|
|
2582
|
-
(full,
|
|
2717
|
+
(full, quote2, root, rest) => {
|
|
2583
2718
|
const aliasKey = SOURCE_ROOT_TO_ALIAS_KEY[root];
|
|
2584
2719
|
if (!aliasKey) return full;
|
|
2585
2720
|
const alias = aliases[aliasKey];
|
|
2586
2721
|
const normalized = aliasToImportPath(alias);
|
|
2587
2722
|
const flatRest = flattenRestPath(rest);
|
|
2588
|
-
return `${
|
|
2723
|
+
return `${quote2}${normalized}${flatRest}${quote2}`;
|
|
2589
2724
|
}
|
|
2590
2725
|
);
|
|
2591
2726
|
}
|
|
@@ -2640,7 +2775,7 @@ async function installUiEntries(options) {
|
|
|
2640
2775
|
}
|
|
2641
2776
|
const rootForEntry = entryPackageRoot?.get(entry.id) ?? packageRoot;
|
|
2642
2777
|
const sourceAbs = path17.resolve(rootForEntry, file.source);
|
|
2643
|
-
const raw = await
|
|
2778
|
+
const raw = await fs14.readFile(sourceAbs, "utf-8");
|
|
2644
2779
|
const transformed = rewriteImports(raw, aliases);
|
|
2645
2780
|
await writeFileSafe(targetAbs, transformed);
|
|
2646
2781
|
written++;
|
|
@@ -2677,7 +2812,7 @@ function rel(projectRoot, abs) {
|
|
|
2677
2812
|
// src/core/ui-add.ts
|
|
2678
2813
|
var DEFAULT_UI_PACKAGE = "@teamix-evo/ui";
|
|
2679
2814
|
async function runUiAdd(options) {
|
|
2680
|
-
const { projectRoot, ids, overwrite } = options;
|
|
2815
|
+
const { projectRoot, ids, overwrite, includeDeprecated } = options;
|
|
2681
2816
|
const packageName = options.packageName ?? DEFAULT_UI_PACKAGE;
|
|
2682
2817
|
if (ids.length === 0) {
|
|
2683
2818
|
throw new Error("At least one entry id must be provided.");
|
|
@@ -2690,7 +2825,21 @@ async function runUiAdd(options) {
|
|
|
2690
2825
|
);
|
|
2691
2826
|
}
|
|
2692
2827
|
const { manifest, packageRoot } = await loadUiData(packageName);
|
|
2693
|
-
const
|
|
2828
|
+
const archived = manifest.deprecatedEntries ?? [];
|
|
2829
|
+
const archivedIds = new Set(archived.map((e) => e.id));
|
|
2830
|
+
const activeIds = new Set(manifest.entries.map((e) => e.id));
|
|
2831
|
+
const requestedDeprecated = ids.filter((id) => archivedIds.has(id));
|
|
2832
|
+
if (requestedDeprecated.length > 0 && !includeDeprecated) {
|
|
2833
|
+
const list = requestedDeprecated.map((s) => `"${s}"`).join(", ");
|
|
2834
|
+
throw new Error(
|
|
2835
|
+
`Refusing to install deprecated entr${requestedDeprecated.length === 1 ? "y" : "ies"} ${list}. These entries are archived and not part of the active distribution (ADR 0028). Pass \`--include-deprecated\` to override (e.g. for migration tooling).`
|
|
2836
|
+
);
|
|
2837
|
+
}
|
|
2838
|
+
const effectiveManifest = includeDeprecated ? { ...manifest, entries: [...manifest.entries, ...archived] } : manifest;
|
|
2839
|
+
const knownIds = /* @__PURE__ */ new Set([
|
|
2840
|
+
...activeIds,
|
|
2841
|
+
...includeDeprecated ? archivedIds : []
|
|
2842
|
+
]);
|
|
2694
2843
|
const unknown = ids.filter((id) => !knownIds.has(id));
|
|
2695
2844
|
if (unknown.length > 0) {
|
|
2696
2845
|
throw new Error(
|
|
@@ -2699,7 +2848,7 @@ async function runUiAdd(options) {
|
|
|
2699
2848
|
}
|
|
2700
2849
|
const result = await installUiEntries({
|
|
2701
2850
|
projectRoot,
|
|
2702
|
-
manifest,
|
|
2851
|
+
manifest: effectiveManifest,
|
|
2703
2852
|
packageRoot,
|
|
2704
2853
|
aliases: uiCfg.aliases,
|
|
2705
2854
|
requested: ids,
|
|
@@ -2747,40 +2896,48 @@ function mergeResources(prior, next) {
|
|
|
2747
2896
|
// src/commands/ui/add.ts
|
|
2748
2897
|
var addCommand2 = new Command15("add").description(
|
|
2749
2898
|
"\u5B89\u88C5\u4E00\u4E2A\u6216\u591A\u4E2A ui entry\uFF08\u6309 id\uFF0C\u81EA\u52A8\u5C55\u5F00 registryDependencies\uFF09"
|
|
2750
|
-
).argument("<ids...>", 'entry id \u5217\u8868\uFF0C\u5982 "button" "dialog"').option("--overwrite", "\u5373\u4F7F\u76EE\u6807\u6587\u4EF6\u5DF2\u5B58\u5728\u4E5F\u8986\u76D6\uFF08\u7ED5\u8FC7 frozen \u8DF3\u8FC7\uFF09").
|
|
2751
|
-
|
|
2752
|
-
|
|
2753
|
-
|
|
2754
|
-
|
|
2755
|
-
|
|
2756
|
-
|
|
2757
|
-
|
|
2758
|
-
|
|
2759
|
-
|
|
2760
|
-
|
|
2761
|
-
|
|
2762
|
-
|
|
2763
|
-
|
|
2764
|
-
|
|
2765
|
-
|
|
2766
|
-
|
|
2899
|
+
).argument("<ids...>", 'entry id \u5217\u8868\uFF0C\u5982 "button" "dialog"').option("--overwrite", "\u5373\u4F7F\u76EE\u6807\u6587\u4EF6\u5DF2\u5B58\u5728\u4E5F\u8986\u76D6\uFF08\u7ED5\u8FC7 frozen \u8DF3\u8FC7\uFF09").option(
|
|
2900
|
+
"--include-deprecated",
|
|
2901
|
+
"\u5141\u8BB8\u5B89\u88C5\u5DF2\u5F52\u6863\u7684 deprecated entry\uFF08\u4EC5\u8FC1\u79FB / \u5BA1\u8BA1\u573A\u666F\uFF0CADR 0028\uFF09"
|
|
2902
|
+
).action(
|
|
2903
|
+
async (ids, opts) => {
|
|
2904
|
+
try {
|
|
2905
|
+
const ide = detectIde();
|
|
2906
|
+
const projectRoot = ide.getProjectRoot();
|
|
2907
|
+
logger.info(`Installing entries: ${ids.join(", ")}`);
|
|
2908
|
+
const result = await runUiAdd({
|
|
2909
|
+
projectRoot,
|
|
2910
|
+
ids,
|
|
2911
|
+
overwrite: opts.overwrite,
|
|
2912
|
+
includeDeprecated: opts.includeDeprecated
|
|
2913
|
+
});
|
|
2914
|
+
logger.success(
|
|
2915
|
+
`UI add complete: ${result.written} written, ${result.skipped} skipped.`
|
|
2916
|
+
);
|
|
2767
2917
|
logger.info("");
|
|
2768
|
-
logger.info(
|
|
2769
|
-
const
|
|
2770
|
-
|
|
2771
|
-
|
|
2772
|
-
|
|
2773
|
-
|
|
2774
|
-
|
|
2775
|
-
|
|
2776
|
-
|
|
2777
|
-
}
|
|
2778
|
-
|
|
2918
|
+
logger.info(`Resolved order: ${result.orderedIds.join(" \u2192 ")}`);
|
|
2919
|
+
const npmDeps = Object.entries(result.npmDependencies);
|
|
2920
|
+
if (npmDeps.length > 0) {
|
|
2921
|
+
logger.info("");
|
|
2922
|
+
logger.info("Install npm dependencies in your project:");
|
|
2923
|
+
const installCmd = npmDeps.map(([name, range]) => `${name}@${range}`).join(" ");
|
|
2924
|
+
logger.info(` pnpm add ${installCmd}`);
|
|
2925
|
+
logger.info(` # or: npm install ${installCmd}`);
|
|
2926
|
+
}
|
|
2927
|
+
} catch (err) {
|
|
2928
|
+
const message = err.message;
|
|
2929
|
+
if (message.startsWith("UI not initialized")) {
|
|
2930
|
+
logger.error(
|
|
2931
|
+
"UI not initialized. Run `npx teamix-evo ui init` first."
|
|
2932
|
+
);
|
|
2933
|
+
} else {
|
|
2934
|
+
logger.error(`Failed to add ui entries: ${message}`);
|
|
2935
|
+
}
|
|
2936
|
+
logger.debug(err.stack ?? "");
|
|
2937
|
+
process.exitCode = 1;
|
|
2779
2938
|
}
|
|
2780
|
-
logger.debug(err.stack ?? "");
|
|
2781
|
-
process.exitCode = 1;
|
|
2782
2939
|
}
|
|
2783
|
-
|
|
2940
|
+
);
|
|
2784
2941
|
|
|
2785
2942
|
// src/commands/ui/list.ts
|
|
2786
2943
|
import { Command as Command16 } from "commander";
|
|
@@ -2788,7 +2945,7 @@ import { Command as Command16 } from "commander";
|
|
|
2788
2945
|
// src/core/ui-list.ts
|
|
2789
2946
|
var DEFAULT_UI_PACKAGE2 = "@teamix-evo/ui";
|
|
2790
2947
|
async function runUiList(options) {
|
|
2791
|
-
const { projectRoot, installedOnly } = options;
|
|
2948
|
+
const { projectRoot, installedOnly, includeDeprecated } = options;
|
|
2792
2949
|
const packageName = options.packageName ?? DEFAULT_UI_PACKAGE2;
|
|
2793
2950
|
const { manifest } = await loadUiData(packageName);
|
|
2794
2951
|
const installedManifest = await readInstalledManifest(projectRoot);
|
|
@@ -2800,65 +2957,77 @@ async function runUiList(options) {
|
|
|
2800
2957
|
const colon = r.id.indexOf(":");
|
|
2801
2958
|
installedIds.add(colon >= 0 ? r.id.slice(0, colon) : r.id);
|
|
2802
2959
|
}
|
|
2803
|
-
const
|
|
2804
|
-
|
|
2805
|
-
|
|
2806
|
-
|
|
2807
|
-
|
|
2960
|
+
const archived = manifest.deprecatedEntries ?? [];
|
|
2961
|
+
const pool = includeDeprecated ? [
|
|
2962
|
+
...manifest.entries.map((e) => ({ entry: e, deprecated: false })),
|
|
2963
|
+
...archived.map((e) => ({ entry: e, deprecated: true }))
|
|
2964
|
+
] : manifest.entries.map((e) => ({ entry: e, deprecated: false }));
|
|
2965
|
+
const entries = pool.filter(({ entry }) => !installedOnly || installedIds.has(entry.id)).map(({ entry, deprecated }) => ({
|
|
2966
|
+
id: entry.id,
|
|
2967
|
+
type: entry.type,
|
|
2968
|
+
description: entry.description,
|
|
2969
|
+
installed: installedIds.has(entry.id),
|
|
2970
|
+
deprecated
|
|
2808
2971
|
}));
|
|
2809
2972
|
return {
|
|
2810
2973
|
packageName,
|
|
2811
|
-
total: manifest.entries.length,
|
|
2974
|
+
total: manifest.entries.length + (includeDeprecated ? archived.length : 0),
|
|
2812
2975
|
installedCount: installedIds.size,
|
|
2813
2976
|
entries
|
|
2814
2977
|
};
|
|
2815
2978
|
}
|
|
2816
2979
|
|
|
2817
2980
|
// src/commands/ui/list.ts
|
|
2818
|
-
var listCommand3 = new Command16("list").description("\u5217\u51FA @teamix-evo/ui \u7684\u6240\u6709 entry \u53CA\u5DF2\u5B89\u88C5\u72B6\u6001").option("--installed", "\u4EC5\u5C55\u793A\u5DF2\u5B89\u88C5\u7684 entry").
|
|
2819
|
-
|
|
2820
|
-
|
|
2821
|
-
|
|
2822
|
-
|
|
2823
|
-
|
|
2824
|
-
|
|
2825
|
-
|
|
2826
|
-
|
|
2981
|
+
var listCommand3 = new Command16("list").description("\u5217\u51FA @teamix-evo/ui \u7684\u6240\u6709 entry \u53CA\u5DF2\u5B89\u88C5\u72B6\u6001").option("--installed", "\u4EC5\u5C55\u793A\u5DF2\u5B89\u88C5\u7684 entry").option(
|
|
2982
|
+
"--include-deprecated",
|
|
2983
|
+
"\u540C\u65F6\u5217\u51FA\u5DF2\u5F52\u6863\u7684 deprecated entry\uFF08\u9ED8\u8BA4\u9690\u85CF\uFF0CADR 0028\uFF09"
|
|
2984
|
+
).action(
|
|
2985
|
+
async (opts) => {
|
|
2986
|
+
try {
|
|
2987
|
+
const ide = detectIde();
|
|
2988
|
+
const projectRoot = ide.getProjectRoot();
|
|
2989
|
+
const { entries, total, installedCount } = await runUiList({
|
|
2990
|
+
projectRoot,
|
|
2991
|
+
installedOnly: opts.installed,
|
|
2992
|
+
includeDeprecated: opts.includeDeprecated
|
|
2993
|
+
});
|
|
2994
|
+
if (entries.length === 0) {
|
|
2995
|
+
logger.info(
|
|
2996
|
+
opts.installed ? "No ui entries installed." : "No ui entries available."
|
|
2997
|
+
);
|
|
2998
|
+
return;
|
|
2999
|
+
}
|
|
3000
|
+
const idWidth = Math.max(...entries.map((e) => e.id.length), 4);
|
|
3001
|
+
const typeWidth = Math.max(...entries.map((e) => e.type.length), 4);
|
|
2827
3002
|
logger.info(
|
|
2828
|
-
|
|
3003
|
+
`${"ID".padEnd(idWidth)} ${"TYPE".padEnd(
|
|
3004
|
+
typeWidth
|
|
3005
|
+
)} STATUS DESCRIPTION`
|
|
2829
3006
|
);
|
|
2830
|
-
return;
|
|
2831
|
-
}
|
|
2832
|
-
const idWidth = Math.max(...entries.map((e) => e.id.length), 4);
|
|
2833
|
-
const typeWidth = Math.max(...entries.map((e) => e.type.length), 4);
|
|
2834
|
-
logger.info(
|
|
2835
|
-
`${"ID".padEnd(idWidth)} ${"TYPE".padEnd(
|
|
2836
|
-
typeWidth
|
|
2837
|
-
)} STATUS DESCRIPTION`
|
|
2838
|
-
);
|
|
2839
|
-
logger.info(
|
|
2840
|
-
`${"\u2500".repeat(idWidth)} ${"\u2500".repeat(
|
|
2841
|
-
typeWidth
|
|
2842
|
-
)} \u2500\u2500\u2500\u2500\u2500\u2500\u2500 \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500`
|
|
2843
|
-
);
|
|
2844
|
-
for (const e of entries) {
|
|
2845
|
-
const status = e.installed ? "INSTALLED" : "\u2013";
|
|
2846
3007
|
logger.info(
|
|
2847
|
-
`${
|
|
3008
|
+
`${"\u2500".repeat(idWidth)} ${"\u2500".repeat(
|
|
2848
3009
|
typeWidth
|
|
2849
|
-
)}
|
|
3010
|
+
)} \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500`
|
|
2850
3011
|
);
|
|
3012
|
+
for (const e of entries) {
|
|
3013
|
+
const status = e.deprecated ? e.installed ? "INST/DEPR" : "DEPRECATED" : e.installed ? "INSTALLED" : "\u2013";
|
|
3014
|
+
logger.info(
|
|
3015
|
+
`${e.id.padEnd(idWidth)} ${e.type.padEnd(
|
|
3016
|
+
typeWidth
|
|
3017
|
+
)} ${status.padEnd(10)} ${e.description}`
|
|
3018
|
+
);
|
|
3019
|
+
}
|
|
3020
|
+
logger.info("");
|
|
3021
|
+
logger.info(
|
|
3022
|
+
`Total: ${total} entr${total === 1 ? "y" : "ies"}, ${installedCount} installed.`
|
|
3023
|
+
);
|
|
3024
|
+
} catch (err) {
|
|
3025
|
+
logger.error(`Failed to list ui entries: ${err.message}`);
|
|
3026
|
+
logger.debug(err.stack ?? "");
|
|
3027
|
+
process.exitCode = 1;
|
|
2851
3028
|
}
|
|
2852
|
-
logger.info("");
|
|
2853
|
-
logger.info(
|
|
2854
|
-
`Total: ${total} entr${total === 1 ? "y" : "ies"}, ${installedCount} installed.`
|
|
2855
|
-
);
|
|
2856
|
-
} catch (err) {
|
|
2857
|
-
logger.error(`Failed to list ui entries: ${err.message}`);
|
|
2858
|
-
logger.debug(err.stack ?? "");
|
|
2859
|
-
process.exitCode = 1;
|
|
2860
3029
|
}
|
|
2861
|
-
|
|
3030
|
+
);
|
|
2862
3031
|
|
|
2863
3032
|
// src/commands/ui/index.ts
|
|
2864
3033
|
var uiCommand = new Command17("ui").description(
|
|
@@ -2876,15 +3045,15 @@ import { Command as Command18 } from "commander";
|
|
|
2876
3045
|
|
|
2877
3046
|
// src/core/variant-ui-add.ts
|
|
2878
3047
|
import * as path18 from "path";
|
|
2879
|
-
import { createRequire as
|
|
3048
|
+
import { createRequire as createRequire6 } from "module";
|
|
2880
3049
|
import {
|
|
2881
3050
|
loadUiPackageManifest as loadUiPackageManifest2,
|
|
2882
3051
|
loadVariantUiPackageCatalog,
|
|
2883
3052
|
loadVariantUiPackageManifest
|
|
2884
3053
|
} from "@teamix-evo/registry";
|
|
2885
|
-
var
|
|
3054
|
+
var require7 = createRequire6(import.meta.url);
|
|
2886
3055
|
function resolvePackageRoot3(packageName) {
|
|
2887
|
-
const pkgJsonPath =
|
|
3056
|
+
const pkgJsonPath = require7.resolve(`${packageName}/package.json`);
|
|
2888
3057
|
return path18.dirname(pkgJsonPath);
|
|
2889
3058
|
}
|
|
2890
3059
|
async function runVariantUiAdd(packageName, options) {
|
|
@@ -3055,6 +3224,12 @@ var addCommand3 = new Command18("add").description(
|
|
|
3055
3224
|
}
|
|
3056
3225
|
const ide = detectIde();
|
|
3057
3226
|
const projectRoot = ide.getProjectRoot();
|
|
3227
|
+
const projectVariant = await readTokensVariant(projectRoot);
|
|
3228
|
+
if (projectVariant && projectVariant !== opts.variant) {
|
|
3229
|
+
throw new Error(
|
|
3230
|
+
`Variant mismatch \u2014 project is locked to "${projectVariant}" but you requested "${opts.variant}". Fix: run \`teamix-evo tokens uninstall -y\` then \`teamix-evo tokens init ${opts.variant}\` to switch, or re-run with \`--variant ${projectVariant}\` to install for the current variant.`
|
|
3231
|
+
);
|
|
3232
|
+
}
|
|
3058
3233
|
logger.info(
|
|
3059
3234
|
`Installing biz-ui entries from variant "${opts.variant}": ${ids.join(", ")}`
|
|
3060
3235
|
);
|
|
@@ -3159,6 +3334,12 @@ var addCommand4 = new Command22("add").description(
|
|
|
3159
3334
|
}
|
|
3160
3335
|
const ide = detectIde();
|
|
3161
3336
|
const projectRoot = ide.getProjectRoot();
|
|
3337
|
+
const projectVariant = await readTokensVariant(projectRoot);
|
|
3338
|
+
if (projectVariant && projectVariant !== opts.variant) {
|
|
3339
|
+
throw new Error(
|
|
3340
|
+
`Variant mismatch \u2014 project is locked to "${projectVariant}" but you requested "${opts.variant}". Fix: run \`teamix-evo tokens uninstall -y\` then \`teamix-evo tokens init ${opts.variant}\` to switch, or re-run with \`--variant ${projectVariant}\` to install for the current variant.`
|
|
3341
|
+
);
|
|
3342
|
+
}
|
|
3162
3343
|
logger.info(
|
|
3163
3344
|
`Installing templates from variant "${opts.variant}": ${ids.join(", ")}`
|
|
3164
3345
|
);
|
|
@@ -3247,7 +3428,7 @@ templatesCommand.addCommand(listCommand5);
|
|
|
3247
3428
|
templatesCommand.addCommand(listVariantsCommand3);
|
|
3248
3429
|
|
|
3249
3430
|
// src/commands/logs/index.ts
|
|
3250
|
-
import { Command as
|
|
3431
|
+
import { Command as Command28 } from "commander";
|
|
3251
3432
|
|
|
3252
3433
|
// src/commands/logs/analyze.ts
|
|
3253
3434
|
import { Command as Command26 } from "commander";
|
|
@@ -3433,16 +3614,227 @@ function parseIntOrUndef(v) {
|
|
|
3433
3614
|
return Number.isFinite(n) && n > 0 ? n : void 0;
|
|
3434
3615
|
}
|
|
3435
3616
|
|
|
3617
|
+
// src/commands/logs/trace.ts
|
|
3618
|
+
import { Command as Command27 } from "commander";
|
|
3619
|
+
import { readFileSync as readFileSync2, readdirSync as readdirSync2, existsSync as existsSync3, statSync as statSync2 } from "fs";
|
|
3620
|
+
import { resolve as resolve4, join as join18 } from "path";
|
|
3621
|
+
var DATE_DIR_RE2 = /^\d{4}-\d{2}-\d{2}$/;
|
|
3622
|
+
var logsTraceCommand = new Command27("trace").description(
|
|
3623
|
+
"\u6309\u4F1A\u8BDD\u8FD8\u539F AI \u8C03\u7528\u94FE\u8DEF:\u4ECE\u7528\u6237 prompt \u8D77\u59CB,\u4E32\u8054\u540E\u7EED PreToolUse/PostToolUse \u76F4\u5230\u4E0B\u4E00\u4E2A prompt \u6216 Stop"
|
|
3624
|
+
).option("--prompt <keyword>", "\u6309\u7528\u6237\u8F93\u5165\u5173\u952E\u5B57\u8FC7\u6EE4 (\u5B50\u4E32\u5339\u914D,\u4E0D\u533A\u5206\u5927\u5C0F\u5199)").option("--session <id>", "\u6307\u5B9A\u4F1A\u8BDD ID (\u524D\u7F00\u5339\u914D)").option("--days <n>", "\u53EA\u770B\u6700\u8FD1 N \u5929\u7684\u76EE\u5F55 (\u9ED8\u8BA4 7)", "7").option("--dir <path>", "log \u76EE\u5F55 (\u9ED8\u8BA4 <project>/.log/ai)").option("--json", "\u4EE5 JSON \u8F93\u51FA (CI/\u5DE5\u5177\u53CB\u597D)").action((opts) => {
|
|
3625
|
+
const baseDir = resolve4(opts.dir ?? join18(process.cwd(), ".log", "ai"));
|
|
3626
|
+
if (!existsSync3(baseDir)) {
|
|
3627
|
+
logger.warn(`No log directory at ${baseDir}.`);
|
|
3628
|
+
logger.info(
|
|
3629
|
+
"\u8FD0\u884C vibe-logger hook \u89E6\u53D1\u540E\u4F1A\u5728\u6B64\u76EE\u5F55\u751F\u6210 JSONL \u2014 \u89C1 .claude/scripts/vibe-logger.mjs"
|
|
3630
|
+
);
|
|
3631
|
+
return;
|
|
3632
|
+
}
|
|
3633
|
+
const dayLimit = parseIntOrUndef2(opts.days) ?? 7;
|
|
3634
|
+
const records = readRecords(baseDir, dayLimit);
|
|
3635
|
+
const report = buildTrace(records, {
|
|
3636
|
+
prompt: opts.prompt,
|
|
3637
|
+
session: opts.session
|
|
3638
|
+
});
|
|
3639
|
+
if (opts.json) {
|
|
3640
|
+
process.stdout.write(JSON.stringify(report, null, 2) + "\n");
|
|
3641
|
+
return;
|
|
3642
|
+
}
|
|
3643
|
+
printTrace(baseDir, report);
|
|
3644
|
+
});
|
|
3645
|
+
function readRecords(baseDir, dayLimit) {
|
|
3646
|
+
const dayDirs = readdirSync2(baseDir, { withFileTypes: true }).filter((e) => e.isDirectory() && DATE_DIR_RE2.test(e.name)).map((e) => e.name).sort().reverse();
|
|
3647
|
+
const selected = dayDirs.slice(0, dayLimit);
|
|
3648
|
+
const records = [];
|
|
3649
|
+
for (const day of selected) {
|
|
3650
|
+
const dayPath = join18(baseDir, day);
|
|
3651
|
+
let entries;
|
|
3652
|
+
try {
|
|
3653
|
+
entries = readdirSync2(dayPath);
|
|
3654
|
+
} catch {
|
|
3655
|
+
continue;
|
|
3656
|
+
}
|
|
3657
|
+
for (const entry of entries) {
|
|
3658
|
+
if (!entry.endsWith(".jsonl")) continue;
|
|
3659
|
+
const fp = join18(dayPath, entry);
|
|
3660
|
+
try {
|
|
3661
|
+
if (!statSync2(fp).isFile()) continue;
|
|
3662
|
+
} catch {
|
|
3663
|
+
continue;
|
|
3664
|
+
}
|
|
3665
|
+
const text2 = readFileSync2(fp, "utf8");
|
|
3666
|
+
for (const line of text2.split("\n")) {
|
|
3667
|
+
if (!line.trim()) continue;
|
|
3668
|
+
try {
|
|
3669
|
+
records.push(JSON.parse(line));
|
|
3670
|
+
} catch {
|
|
3671
|
+
}
|
|
3672
|
+
}
|
|
3673
|
+
}
|
|
3674
|
+
}
|
|
3675
|
+
return records;
|
|
3676
|
+
}
|
|
3677
|
+
function buildTrace(records, filter = {}) {
|
|
3678
|
+
const groups = /* @__PURE__ */ new Map();
|
|
3679
|
+
for (const r of records) {
|
|
3680
|
+
if (!r.session) continue;
|
|
3681
|
+
const arr = groups.get(r.session) ?? [];
|
|
3682
|
+
arr.push(r);
|
|
3683
|
+
groups.set(r.session, arr);
|
|
3684
|
+
}
|
|
3685
|
+
const promptNeedle = filter.prompt?.toLowerCase();
|
|
3686
|
+
const sessionPrefix = filter.session;
|
|
3687
|
+
const sessions = [];
|
|
3688
|
+
for (const [sessionId, items] of groups.entries()) {
|
|
3689
|
+
if (sessionPrefix && !sessionId.startsWith(sessionPrefix)) continue;
|
|
3690
|
+
items.sort((a, b) => a.ts < b.ts ? -1 : a.ts > b.ts ? 1 : 0);
|
|
3691
|
+
const chains = [];
|
|
3692
|
+
let current = null;
|
|
3693
|
+
let pending = /* @__PURE__ */ new Map();
|
|
3694
|
+
const closeCurrent = () => {
|
|
3695
|
+
if (current) chains.push(current);
|
|
3696
|
+
current = null;
|
|
3697
|
+
pending = /* @__PURE__ */ new Map();
|
|
3698
|
+
};
|
|
3699
|
+
for (const r of items) {
|
|
3700
|
+
if (r.event === "UserPromptSubmit") {
|
|
3701
|
+
if (current) closeCurrent();
|
|
3702
|
+
current = { prompt: r.prompt ?? "", promptTs: r.ts, steps: [] };
|
|
3703
|
+
pending = /* @__PURE__ */ new Map();
|
|
3704
|
+
continue;
|
|
3705
|
+
}
|
|
3706
|
+
if (r.event === "Stop") {
|
|
3707
|
+
if (current) closeCurrent();
|
|
3708
|
+
continue;
|
|
3709
|
+
}
|
|
3710
|
+
if (!current) continue;
|
|
3711
|
+
if (r.event === "PreToolUse") {
|
|
3712
|
+
const idx = current.steps.length;
|
|
3713
|
+
current.steps.push({
|
|
3714
|
+
ts: r.ts,
|
|
3715
|
+
event: "PreToolUse",
|
|
3716
|
+
tool: r.tool,
|
|
3717
|
+
file: r.file,
|
|
3718
|
+
tags: r.tags,
|
|
3719
|
+
duration_ms: r.duration_ms,
|
|
3720
|
+
error: r.error ?? false
|
|
3721
|
+
});
|
|
3722
|
+
if (r.tool) {
|
|
3723
|
+
const list = pending.get(r.tool) ?? [];
|
|
3724
|
+
list.push(idx);
|
|
3725
|
+
pending.set(r.tool, list);
|
|
3726
|
+
}
|
|
3727
|
+
} else if (r.event === "PostToolUse") {
|
|
3728
|
+
const list = r.tool ? pending.get(r.tool) : void 0;
|
|
3729
|
+
if (list && list.length > 0) {
|
|
3730
|
+
const idx = list.shift();
|
|
3731
|
+
if (list.length === 0 && r.tool) pending.delete(r.tool);
|
|
3732
|
+
const step = current.steps[idx];
|
|
3733
|
+
if (r.duration_ms !== void 0) step.duration_ms = r.duration_ms;
|
|
3734
|
+
if (r.error !== void 0) step.error = r.error;
|
|
3735
|
+
if (!step.file && r.file) step.file = r.file;
|
|
3736
|
+
if ((!step.tags || step.tags.length === 0) && r.tags)
|
|
3737
|
+
step.tags = r.tags;
|
|
3738
|
+
} else {
|
|
3739
|
+
current.steps.push({
|
|
3740
|
+
ts: r.ts,
|
|
3741
|
+
event: "PostToolUse",
|
|
3742
|
+
tool: r.tool,
|
|
3743
|
+
file: r.file,
|
|
3744
|
+
tags: r.tags,
|
|
3745
|
+
duration_ms: r.duration_ms,
|
|
3746
|
+
error: r.error ?? false
|
|
3747
|
+
});
|
|
3748
|
+
}
|
|
3749
|
+
}
|
|
3750
|
+
}
|
|
3751
|
+
if (current) closeCurrent();
|
|
3752
|
+
const filteredChains = promptNeedle ? chains.filter((c) => c.prompt.toLowerCase().includes(promptNeedle)) : chains;
|
|
3753
|
+
if (filteredChains.length === 0) continue;
|
|
3754
|
+
sessions.push({
|
|
3755
|
+
id: sessionId,
|
|
3756
|
+
agent: items[0]?.agent ?? "unknown",
|
|
3757
|
+
chains: filteredChains
|
|
3758
|
+
});
|
|
3759
|
+
}
|
|
3760
|
+
sessions.sort((a, b) => {
|
|
3761
|
+
const ta = a.chains[0]?.promptTs ?? "";
|
|
3762
|
+
const tb = b.chains[0]?.promptTs ?? "";
|
|
3763
|
+
return tb.localeCompare(ta);
|
|
3764
|
+
});
|
|
3765
|
+
return { sessions };
|
|
3766
|
+
}
|
|
3767
|
+
function printTrace(baseDir, r) {
|
|
3768
|
+
logger.info(`vibe-logger \u94FE\u8DEF\u8FFD\u8E2A`);
|
|
3769
|
+
logger.info(` \u76EE\u5F55: ${baseDir}`);
|
|
3770
|
+
logger.info(` \u4F1A\u8BDD: ${r.sessions.length}`);
|
|
3771
|
+
logger.info("");
|
|
3772
|
+
if (r.sessions.length === 0) {
|
|
3773
|
+
logger.info("\u672A\u627E\u5230\u5339\u914D\u7684\u4F1A\u8BDD/\u63D0\u793A\u3002");
|
|
3774
|
+
return;
|
|
3775
|
+
}
|
|
3776
|
+
for (const s of r.sessions) {
|
|
3777
|
+
logger.info(`\u2501\u2501\u2501 Session: ${s.id} (${s.agent}) \u2501\u2501\u2501`);
|
|
3778
|
+
logger.info("");
|
|
3779
|
+
for (const c of s.chains) {
|
|
3780
|
+
logger.info(
|
|
3781
|
+
`[${formatTime(c.promptTs)}] \u{1F4AC} Prompt: ${quote(truncate(c.prompt, 200))}`
|
|
3782
|
+
);
|
|
3783
|
+
for (const step of c.steps) {
|
|
3784
|
+
logger.info(` ${formatStep(step)}`);
|
|
3785
|
+
}
|
|
3786
|
+
logger.info("");
|
|
3787
|
+
}
|
|
3788
|
+
}
|
|
3789
|
+
}
|
|
3790
|
+
function formatStep(s) {
|
|
3791
|
+
const ts = `[${formatTime(s.ts)}]`;
|
|
3792
|
+
const isEdit = s.tool === "Edit" || s.tool === "Write" || s.tool === "MultiEdit" || s.tool === "create_file" || s.tool === "search_replace";
|
|
3793
|
+
const icon = isEdit ? "\u{1F4DD}" : "\u{1F527}";
|
|
3794
|
+
const head = isEdit && s.file ? `${s.tool ?? "?"} \u2192 ${s.file}` : s.tool ?? s.event ?? "?";
|
|
3795
|
+
const dur = s.duration_ms !== void 0 ? `${s.duration_ms}ms` : "";
|
|
3796
|
+
const tags = s.tags && s.tags.length ? `[${s.tags.join(",")}]` : "";
|
|
3797
|
+
const err = s.error ? "\u274C" : "";
|
|
3798
|
+
return [ts, icon, padRight(head, 40), padLeft(dur, 6), tags, err].filter((x) => x !== "").join(" ");
|
|
3799
|
+
}
|
|
3800
|
+
function formatTime(ts) {
|
|
3801
|
+
const d = new Date(ts);
|
|
3802
|
+
if (Number.isNaN(d.getTime())) return ts;
|
|
3803
|
+
const hh = String(d.getUTCHours()).padStart(2, "0");
|
|
3804
|
+
const mm = String(d.getUTCMinutes()).padStart(2, "0");
|
|
3805
|
+
const ss = String(d.getUTCSeconds()).padStart(2, "0");
|
|
3806
|
+
return `${hh}:${mm}:${ss}`;
|
|
3807
|
+
}
|
|
3808
|
+
function quote(s) {
|
|
3809
|
+
return `"${s.replace(/"/g, '\\"')}"`;
|
|
3810
|
+
}
|
|
3811
|
+
function truncate(s, n) {
|
|
3812
|
+
if (s.length <= n) return s;
|
|
3813
|
+
return s.slice(0, n) + "\u2026";
|
|
3814
|
+
}
|
|
3815
|
+
function padRight(s, n) {
|
|
3816
|
+
return s.length >= n ? s : s + " ".repeat(n - s.length);
|
|
3817
|
+
}
|
|
3818
|
+
function padLeft(s, n) {
|
|
3819
|
+
return s.length >= n ? s : " ".repeat(n - s.length) + s;
|
|
3820
|
+
}
|
|
3821
|
+
function parseIntOrUndef2(v) {
|
|
3822
|
+
if (v === void 0) return void 0;
|
|
3823
|
+
const n = Number.parseInt(v, 10);
|
|
3824
|
+
return Number.isFinite(n) && n > 0 ? n : void 0;
|
|
3825
|
+
}
|
|
3826
|
+
|
|
3436
3827
|
// src/commands/logs/index.ts
|
|
3437
|
-
var logsCommand = new
|
|
3828
|
+
var logsCommand = new Command28("logs").description(
|
|
3438
3829
|
"\u67E5\u8BE2 vibe-logger \u8F93\u51FA (.log/ai/**/*.jsonl) \u2014 AI \u8C03\u7528\u94FE\u5206\u6790"
|
|
3439
3830
|
);
|
|
3440
3831
|
logsCommand.addCommand(logsAnalyzeCommand);
|
|
3832
|
+
logsCommand.addCommand(logsTraceCommand);
|
|
3441
3833
|
|
|
3442
3834
|
// src/index.ts
|
|
3443
|
-
var
|
|
3444
|
-
var { version } =
|
|
3445
|
-
var program = new
|
|
3835
|
+
var require8 = createRequire7(import.meta.url);
|
|
3836
|
+
var { version } = require8("../package.json");
|
|
3837
|
+
var program = new Command29();
|
|
3446
3838
|
program.name("teamix-evo").description("Where ideas evolve. \u2014 AI Coding \u5957\u4EF6").version(version);
|
|
3447
3839
|
program.addCommand(tokensCommand);
|
|
3448
3840
|
program.addCommand(skillsCommand);
|