teamix-evo 0.5.0 → 0.6.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 +5 -3
- package/dist/core/index.d.ts +205 -24
- package/dist/core/index.js +595 -72
- package/dist/core/index.js.map +1 -1
- package/dist/index.js +784 -254
- package/dist/index.js.map +1 -1
- package/package.json +8 -7
package/dist/core/index.js
CHANGED
|
@@ -517,9 +517,11 @@ function makeMirrorRecord(skill, targetAbs, content, ide, scope, rel2) {
|
|
|
517
517
|
}
|
|
518
518
|
async function updateSkills(options) {
|
|
519
519
|
const { manifest, ides, scope, projectRoot } = options;
|
|
520
|
+
const idFilter = options.onlyIds ? new Set(options.onlyIds) : null;
|
|
520
521
|
const summary = { overwritten: 0, managed: 0, skipped: 0, created: 0 };
|
|
521
522
|
const updated = [];
|
|
522
523
|
for (const skill of manifest.skills) {
|
|
524
|
+
if (idFilter && !idFilter.has(skill.id)) continue;
|
|
523
525
|
const skillIdes = skill.ides.filter((i) => ides.includes(i));
|
|
524
526
|
if (skillIdes.length === 0) continue;
|
|
525
527
|
const sourceRecords = await rewriteSkillSource(
|
|
@@ -721,11 +723,73 @@ async function ensureMcpJson(projectRoot) {
|
|
|
721
723
|
// src/core/skills-add.ts
|
|
722
724
|
var DEFAULT_SKILLS_PACKAGE = "@teamix-evo/skills";
|
|
723
725
|
var FLAT_VARIANT = "_flat";
|
|
726
|
+
async function runSkillsInit(options) {
|
|
727
|
+
const { projectRoot } = options;
|
|
728
|
+
const packageName = options.packageName ?? DEFAULT_SKILLS_PACKAGE;
|
|
729
|
+
const ides = [...options.ides];
|
|
730
|
+
const scope = options.scope;
|
|
731
|
+
if (ides.length === 0) {
|
|
732
|
+
throw new Error("At least one IDE must be selected.");
|
|
733
|
+
}
|
|
734
|
+
await ensureTeamixDir(projectRoot);
|
|
735
|
+
const existingConfig = await readProjectConfig(projectRoot);
|
|
736
|
+
const existingSkillsCfg = existingConfig?.packages?.skills;
|
|
737
|
+
const { manifest, data, packageRoot } = await loadSkillsData(packageName);
|
|
738
|
+
const currentTokensVariant = await readTokensVariant(projectRoot);
|
|
739
|
+
const existing = await readExistingState(projectRoot, packageName);
|
|
740
|
+
const candidateIds = manifest.skills.filter((s) => {
|
|
741
|
+
const effectiveScope = s.scope ?? "project";
|
|
742
|
+
if (effectiveScope !== scope) {
|
|
743
|
+
logger.debug(
|
|
744
|
+
`Skipping skill "${s.id}" (scope=${effectiveScope}): current install scope is "${scope}". Use \`skills add ${s.id} --scope ${effectiveScope}\` to install.`
|
|
745
|
+
);
|
|
746
|
+
return false;
|
|
747
|
+
}
|
|
748
|
+
if (!s.variant) return true;
|
|
749
|
+
if (!currentTokensVariant) {
|
|
750
|
+
logger.debug(
|
|
751
|
+
`Skipping variant-bound skill "${s.id}" (variant=${s.variant}): no tokens variant installed; will be picked up when "tokens init" runs.`
|
|
752
|
+
);
|
|
753
|
+
return false;
|
|
754
|
+
}
|
|
755
|
+
if (s.variant !== currentTokensVariant) {
|
|
756
|
+
logger.debug(
|
|
757
|
+
`Skipping variant-bound skill "${s.id}" (variant=${s.variant}): current tokens variant is "${currentTokensVariant}".`
|
|
758
|
+
);
|
|
759
|
+
return false;
|
|
760
|
+
}
|
|
761
|
+
return true;
|
|
762
|
+
}).map((s) => s.id);
|
|
763
|
+
const skippedSkillIds = candidateIds.filter(
|
|
764
|
+
(id) => existing.skillIds.has(id)
|
|
765
|
+
);
|
|
766
|
+
const onlyIds = candidateIds.filter((id) => !existing.skillIds.has(id));
|
|
767
|
+
if (existingSkillsCfg && onlyIds.length === 0) {
|
|
768
|
+
return { status: "already-initialized" };
|
|
769
|
+
}
|
|
770
|
+
return finalizeSkillsInstall({
|
|
771
|
+
projectRoot,
|
|
772
|
+
packageName,
|
|
773
|
+
ideIdent: options.ide ?? "qoder",
|
|
774
|
+
manifest,
|
|
775
|
+
data,
|
|
776
|
+
packageRoot,
|
|
777
|
+
ides,
|
|
778
|
+
scope,
|
|
779
|
+
onlyIds,
|
|
780
|
+
skippedSkillIds,
|
|
781
|
+
existing,
|
|
782
|
+
existingConfig
|
|
783
|
+
});
|
|
784
|
+
}
|
|
724
785
|
async function runSkillsAdd(options) {
|
|
786
|
+
if (!options.names || options.names.length === 0) {
|
|
787
|
+
throw new Error(
|
|
788
|
+
"runSkillsAdd requires at least one skill id. Use runSkillsInit() for bulk install."
|
|
789
|
+
);
|
|
790
|
+
}
|
|
725
791
|
const { projectRoot, names: requestedNames } = options;
|
|
726
792
|
const packageName = options.packageName ?? DEFAULT_SKILLS_PACKAGE;
|
|
727
|
-
const ideIdent = options.ide ?? "qoder";
|
|
728
|
-
const isIncremental = !!requestedNames && requestedNames.length > 0;
|
|
729
793
|
await ensureTeamixDir(projectRoot);
|
|
730
794
|
const existingConfig = await readProjectConfig(projectRoot);
|
|
731
795
|
const existingSkillsCfg = existingConfig?.packages?.skills;
|
|
@@ -738,57 +802,27 @@ async function runSkillsAdd(options) {
|
|
|
738
802
|
throw new Error("Scope must be specified (project | global).");
|
|
739
803
|
}
|
|
740
804
|
const { manifest, data, packageRoot } = await loadSkillsData(packageName);
|
|
741
|
-
const
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
const
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
805
|
+
const known = new Set(manifest.skills.map((s) => s.id));
|
|
806
|
+
const unknown = requestedNames.filter((n) => !known.has(n));
|
|
807
|
+
if (unknown.length > 0) {
|
|
808
|
+
const available = [...known].join(", ");
|
|
809
|
+
throw new Error(
|
|
810
|
+
`Unknown skill id(s): ${unknown.join(", ")}. Available: ${available || "(none)"}.`
|
|
811
|
+
);
|
|
812
|
+
}
|
|
813
|
+
for (const s of manifest.skills) {
|
|
814
|
+
if (requestedNames.includes(s.id) && s.scope && s.scope !== scope) {
|
|
815
|
+
logger.warn(
|
|
816
|
+
`"${s.id}" \u63A8\u8350 ${s.scope} scope \u5B89\u88C5\u3002\u5F53\u524D\u4EE5 ${scope} scope \u5F3A\u5236\u5B89\u88C5,\u53EF\u80FD\u4E0E\u53E6\u4E00 scope \u7684\u526F\u672C\u51B2\u7A81\u3002\u5EFA\u8BAE\u6539\u7528 \`skills add ${s.id} --scope ${s.scope}\`\u3002`
|
|
749
817
|
);
|
|
750
818
|
}
|
|
751
819
|
}
|
|
752
|
-
const
|
|
753
|
-
const
|
|
754
|
-
(
|
|
820
|
+
const existing = await readExistingState(projectRoot, packageName);
|
|
821
|
+
const skippedSkillIds = requestedNames.filter(
|
|
822
|
+
(n) => existing.skillIds.has(n)
|
|
755
823
|
);
|
|
756
|
-
const
|
|
757
|
-
|
|
758
|
-
...Object.keys(existingLock?.skills ?? {}),
|
|
759
|
-
// Legacy fallback: pre-ADR-0013 installs only had manifest.json. Derive
|
|
760
|
-
// skill ids by stripping the trailing :source / :sub-file suffix.
|
|
761
|
-
...(existingPkg?.resources ?? []).map((r) => r.id.split(":")[0])
|
|
762
|
-
]);
|
|
763
|
-
let onlyIds;
|
|
764
|
-
let skippedSkillIds;
|
|
765
|
-
if (isIncremental) {
|
|
766
|
-
skippedSkillIds = requestedNames.filter((n) => existingSkillIds.has(n));
|
|
767
|
-
onlyIds = requestedNames.filter((n) => !existingSkillIds.has(n));
|
|
768
|
-
} else {
|
|
769
|
-
const candidateIds = manifest.skills.filter((s) => {
|
|
770
|
-
if (!s.variant) return true;
|
|
771
|
-
if (!currentTokensVariant) {
|
|
772
|
-
logger.debug(
|
|
773
|
-
`Skipping variant-bound skill "${s.id}" (variant=${s.variant}): no tokens variant installed; will be picked up when "tokens init" runs.`
|
|
774
|
-
);
|
|
775
|
-
return false;
|
|
776
|
-
}
|
|
777
|
-
if (s.variant !== currentTokensVariant) {
|
|
778
|
-
logger.debug(
|
|
779
|
-
`Skipping variant-bound skill "${s.id}" (variant=${s.variant}): current tokens variant is "${currentTokensVariant}".`
|
|
780
|
-
);
|
|
781
|
-
return false;
|
|
782
|
-
}
|
|
783
|
-
return true;
|
|
784
|
-
}).map((s) => s.id);
|
|
785
|
-
skippedSkillIds = candidateIds.filter((id) => existingSkillIds.has(id));
|
|
786
|
-
onlyIds = candidateIds.filter((id) => !existingSkillIds.has(id));
|
|
787
|
-
}
|
|
788
|
-
if (!isIncremental && existingSkillsCfg && onlyIds.length === 0) {
|
|
789
|
-
return { status: "already-added" };
|
|
790
|
-
}
|
|
791
|
-
if (isIncremental && onlyIds.length === 0) {
|
|
824
|
+
const onlyIds = requestedNames.filter((n) => !existing.skillIds.has(n));
|
|
825
|
+
if (onlyIds.length === 0) {
|
|
792
826
|
return {
|
|
793
827
|
status: "installed",
|
|
794
828
|
packageName,
|
|
@@ -802,6 +836,48 @@ async function runSkillsAdd(options) {
|
|
|
802
836
|
skippedSkillIds
|
|
803
837
|
};
|
|
804
838
|
}
|
|
839
|
+
return finalizeSkillsInstall({
|
|
840
|
+
projectRoot,
|
|
841
|
+
packageName,
|
|
842
|
+
ideIdent: options.ide ?? "qoder",
|
|
843
|
+
manifest,
|
|
844
|
+
data,
|
|
845
|
+
packageRoot,
|
|
846
|
+
ides,
|
|
847
|
+
scope,
|
|
848
|
+
onlyIds,
|
|
849
|
+
skippedSkillIds,
|
|
850
|
+
existing,
|
|
851
|
+
existingConfig
|
|
852
|
+
});
|
|
853
|
+
}
|
|
854
|
+
async function readExistingState(projectRoot, packageName) {
|
|
855
|
+
const installed = await readInstalledManifest(projectRoot);
|
|
856
|
+
const pkg = installed?.installed.find((p) => p.package === packageName);
|
|
857
|
+
const lock = await readSkillsLock(projectRoot);
|
|
858
|
+
const skillIds = /* @__PURE__ */ new Set([
|
|
859
|
+
...Object.keys(lock?.skills ?? {}),
|
|
860
|
+
// Legacy fallback: pre-ADR-0013 installs only had manifest.json. Derive
|
|
861
|
+
// skill ids by stripping the trailing :source / :sub-file suffix.
|
|
862
|
+
...(pkg?.resources ?? []).map((r) => r.id.split(":")[0] ?? r.id)
|
|
863
|
+
]);
|
|
864
|
+
return { installed, pkg, lock, skillIds };
|
|
865
|
+
}
|
|
866
|
+
async function finalizeSkillsInstall(args) {
|
|
867
|
+
const {
|
|
868
|
+
projectRoot,
|
|
869
|
+
packageName,
|
|
870
|
+
ideIdent,
|
|
871
|
+
manifest,
|
|
872
|
+
data,
|
|
873
|
+
packageRoot,
|
|
874
|
+
ides,
|
|
875
|
+
scope,
|
|
876
|
+
onlyIds,
|
|
877
|
+
skippedSkillIds,
|
|
878
|
+
existing,
|
|
879
|
+
existingConfig
|
|
880
|
+
} = args;
|
|
805
881
|
const result = await installSkills({
|
|
806
882
|
projectRoot,
|
|
807
883
|
manifest,
|
|
@@ -825,7 +901,7 @@ async function runSkillsAdd(options) {
|
|
|
825
901
|
};
|
|
826
902
|
await writeProjectConfig(projectRoot, config);
|
|
827
903
|
const installedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
828
|
-
const installedManifest =
|
|
904
|
+
const installedManifest = existing.installed ?? {
|
|
829
905
|
schemaVersion: 1,
|
|
830
906
|
installed: []
|
|
831
907
|
};
|
|
@@ -833,7 +909,7 @@ async function runSkillsAdd(options) {
|
|
|
833
909
|
(p) => p.package === packageName
|
|
834
910
|
);
|
|
835
911
|
const mergedResources = mergeInstalledResources(
|
|
836
|
-
|
|
912
|
+
existing.pkg?.resources ?? [],
|
|
837
913
|
result.resources
|
|
838
914
|
);
|
|
839
915
|
const entry = {
|
|
@@ -846,7 +922,7 @@ async function runSkillsAdd(options) {
|
|
|
846
922
|
if (idx >= 0) installedManifest.installed[idx] = entry;
|
|
847
923
|
else installedManifest.installed.push(entry);
|
|
848
924
|
await writeInstalledManifest(projectRoot, installedManifest);
|
|
849
|
-
const lock =
|
|
925
|
+
const lock = existing.lock ?? {
|
|
850
926
|
schemaVersion: 1,
|
|
851
927
|
skills: {}
|
|
852
928
|
};
|
|
@@ -1138,6 +1214,176 @@ async function listTokenVariants(packageName = DEFAULT_TOKENS_PACKAGE, packageRo
|
|
|
1138
1214
|
};
|
|
1139
1215
|
}
|
|
1140
1216
|
|
|
1217
|
+
// src/core/skills-update.ts
|
|
1218
|
+
var DEFAULT_SKILLS_PACKAGE3 = "@teamix-evo/skills";
|
|
1219
|
+
var FLAT_VARIANT2 = "_flat";
|
|
1220
|
+
async function runSkillsUpdate(options) {
|
|
1221
|
+
const { projectRoot, names: requestedNames, dryRun } = options;
|
|
1222
|
+
const packageName = options.packageName ?? DEFAULT_SKILLS_PACKAGE3;
|
|
1223
|
+
const config = await readProjectConfig(projectRoot);
|
|
1224
|
+
const skillsCfg = config?.packages?.skills;
|
|
1225
|
+
if (!skillsCfg) {
|
|
1226
|
+
return { status: "no-skills" };
|
|
1227
|
+
}
|
|
1228
|
+
const ides = skillsCfg.ides ?? ["qoder", "claude"];
|
|
1229
|
+
const scope = skillsCfg.scope ?? "project";
|
|
1230
|
+
const existingLock = await readSkillsLock(projectRoot);
|
|
1231
|
+
if (!existingLock || Object.keys(existingLock.skills).length === 0) {
|
|
1232
|
+
return { status: "no-skills" };
|
|
1233
|
+
}
|
|
1234
|
+
const { manifest, data, packageRoot } = await loadSkillsData(packageName);
|
|
1235
|
+
const manifestById = new Map(manifest.skills.map((s) => [s.id, s]));
|
|
1236
|
+
const lockIds = Object.keys(existingLock.skills);
|
|
1237
|
+
const requestedSet = requestedNames ? new Set(requestedNames) : null;
|
|
1238
|
+
if (requestedSet) {
|
|
1239
|
+
const unknown = requestedNames.filter(
|
|
1240
|
+
(n) => !lockIds.includes(n) && !manifestById.has(n)
|
|
1241
|
+
);
|
|
1242
|
+
if (unknown.length > 0) {
|
|
1243
|
+
throw new Error(
|
|
1244
|
+
`Unknown skill id(s): ${unknown.join(
|
|
1245
|
+
", "
|
|
1246
|
+
)}. Available (installed): ${lockIds.join(", ") || "(none)"}.`
|
|
1247
|
+
);
|
|
1248
|
+
}
|
|
1249
|
+
}
|
|
1250
|
+
const targetIds = [];
|
|
1251
|
+
const skippedSkillIds = [];
|
|
1252
|
+
for (const id of lockIds) {
|
|
1253
|
+
if (requestedSet && !requestedSet.has(id)) continue;
|
|
1254
|
+
const entry2 = manifestById.get(id);
|
|
1255
|
+
if (!entry2) {
|
|
1256
|
+
logger.debug(
|
|
1257
|
+
`Skipping "${id}": no longer in upstream manifest. Use \`skills uninstall ${id}\` to remove.`
|
|
1258
|
+
);
|
|
1259
|
+
skippedSkillIds.push(id);
|
|
1260
|
+
continue;
|
|
1261
|
+
}
|
|
1262
|
+
const effectiveScope = entry2.scope ?? "project";
|
|
1263
|
+
if (effectiveScope !== scope) {
|
|
1264
|
+
logger.debug(
|
|
1265
|
+
`Skipping "${id}" (scope=${effectiveScope}): current install scope is "${scope}".`
|
|
1266
|
+
);
|
|
1267
|
+
skippedSkillIds.push(id);
|
|
1268
|
+
continue;
|
|
1269
|
+
}
|
|
1270
|
+
targetIds.push(id);
|
|
1271
|
+
}
|
|
1272
|
+
const allSame = targetIds.every((id) => {
|
|
1273
|
+
const lockVer = existingLock.skills[id].version;
|
|
1274
|
+
const manVer = manifestById.get(id).version;
|
|
1275
|
+
return lockVer === manVer;
|
|
1276
|
+
});
|
|
1277
|
+
if (targetIds.length > 0 && allSame && !dryRun) {
|
|
1278
|
+
return {
|
|
1279
|
+
status: "no-changes",
|
|
1280
|
+
packageName,
|
|
1281
|
+
version: manifest.version,
|
|
1282
|
+
checkedSkillIds: targetIds
|
|
1283
|
+
};
|
|
1284
|
+
}
|
|
1285
|
+
if (dryRun) {
|
|
1286
|
+
const plan = targetIds.map((id) => {
|
|
1287
|
+
const lockVer = existingLock.skills[id].version;
|
|
1288
|
+
const entry2 = manifestById.get(id);
|
|
1289
|
+
const sameVersion = lockVer === entry2.version;
|
|
1290
|
+
return {
|
|
1291
|
+
id,
|
|
1292
|
+
current: lockVer,
|
|
1293
|
+
next: entry2.version,
|
|
1294
|
+
strategy: entry2.updateStrategy ?? "managed",
|
|
1295
|
+
action: sameVersion ? "up-to-date" : "version-bump"
|
|
1296
|
+
};
|
|
1297
|
+
});
|
|
1298
|
+
return {
|
|
1299
|
+
status: "dry-run",
|
|
1300
|
+
packageName,
|
|
1301
|
+
currentVersion: skillsCfg.version,
|
|
1302
|
+
availableVersion: manifest.version,
|
|
1303
|
+
plan
|
|
1304
|
+
};
|
|
1305
|
+
}
|
|
1306
|
+
if (targetIds.length === 0) {
|
|
1307
|
+
return {
|
|
1308
|
+
status: "updated",
|
|
1309
|
+
packageName,
|
|
1310
|
+
version: manifest.version,
|
|
1311
|
+
ides,
|
|
1312
|
+
scope,
|
|
1313
|
+
updatedSkillIds: [],
|
|
1314
|
+
skippedSkillIds,
|
|
1315
|
+
summary: { overwritten: 0, managed: 0, skipped: 0, created: 0 },
|
|
1316
|
+
resources: []
|
|
1317
|
+
};
|
|
1318
|
+
}
|
|
1319
|
+
const result = await updateSkills({
|
|
1320
|
+
projectRoot,
|
|
1321
|
+
manifest,
|
|
1322
|
+
data,
|
|
1323
|
+
packageRoot,
|
|
1324
|
+
ides,
|
|
1325
|
+
scope,
|
|
1326
|
+
onlyIds: targetIds
|
|
1327
|
+
});
|
|
1328
|
+
config.packages.skills = {
|
|
1329
|
+
...skillsCfg,
|
|
1330
|
+
version: manifest.version
|
|
1331
|
+
};
|
|
1332
|
+
await writeProjectConfig(projectRoot, config);
|
|
1333
|
+
const installedManifest = await readInstalledManifest(projectRoot) ?? {
|
|
1334
|
+
schemaVersion: 1,
|
|
1335
|
+
installed: []
|
|
1336
|
+
};
|
|
1337
|
+
const idx = installedManifest.installed.findIndex(
|
|
1338
|
+
(p) => p.package === packageName
|
|
1339
|
+
);
|
|
1340
|
+
const installedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
1341
|
+
const prior = idx >= 0 ? installedManifest.installed[idx].resources : [];
|
|
1342
|
+
const targetSet = new Set(targetIds);
|
|
1343
|
+
const preserved = prior.filter((r) => {
|
|
1344
|
+
const skillId = r.id.split(":")[0];
|
|
1345
|
+
return skillId ? !targetSet.has(skillId) : true;
|
|
1346
|
+
});
|
|
1347
|
+
const entry = {
|
|
1348
|
+
package: packageName,
|
|
1349
|
+
variant: FLAT_VARIANT2,
|
|
1350
|
+
version: manifest.version,
|
|
1351
|
+
installedAt,
|
|
1352
|
+
resources: [...preserved, ...result.resources]
|
|
1353
|
+
};
|
|
1354
|
+
if (idx >= 0) installedManifest.installed[idx] = entry;
|
|
1355
|
+
else installedManifest.installed.push(entry);
|
|
1356
|
+
await writeInstalledManifest(projectRoot, installedManifest);
|
|
1357
|
+
const lock = {
|
|
1358
|
+
schemaVersion: 1,
|
|
1359
|
+
skills: { ...existingLock.skills }
|
|
1360
|
+
};
|
|
1361
|
+
for (const id of targetIds) {
|
|
1362
|
+
const skillDef = manifestById.get(id);
|
|
1363
|
+
if (!skillDef) continue;
|
|
1364
|
+
const mirroredTo = skillDef.ides.filter((i) => ides.includes(i));
|
|
1365
|
+
lock.skills[id] = {
|
|
1366
|
+
version: skillDef.version,
|
|
1367
|
+
from: packageName,
|
|
1368
|
+
installedAt,
|
|
1369
|
+
scope,
|
|
1370
|
+
mirroredTo
|
|
1371
|
+
};
|
|
1372
|
+
}
|
|
1373
|
+
await writeSkillsLock(projectRoot, lock);
|
|
1374
|
+
return {
|
|
1375
|
+
status: "updated",
|
|
1376
|
+
packageName,
|
|
1377
|
+
version: manifest.version,
|
|
1378
|
+
ides,
|
|
1379
|
+
scope,
|
|
1380
|
+
updatedSkillIds: targetIds,
|
|
1381
|
+
skippedSkillIds,
|
|
1382
|
+
summary: result.summary,
|
|
1383
|
+
resources: result.resources
|
|
1384
|
+
};
|
|
1385
|
+
}
|
|
1386
|
+
|
|
1141
1387
|
// src/core/ui-init.ts
|
|
1142
1388
|
var DEFAULT_UI_ALIASES = {
|
|
1143
1389
|
components: "src/components/ui",
|
|
@@ -1471,9 +1717,277 @@ async function runUiList(options) {
|
|
|
1471
1717
|
};
|
|
1472
1718
|
}
|
|
1473
1719
|
|
|
1474
|
-
// src/core/
|
|
1720
|
+
// src/core/variant-ui-add.ts
|
|
1475
1721
|
import * as path12 from "path";
|
|
1476
|
-
import
|
|
1722
|
+
import { createRequire as createRequire4 } from "module";
|
|
1723
|
+
import {
|
|
1724
|
+
loadUiPackageManifest as loadUiPackageManifest2,
|
|
1725
|
+
loadVariantUiPackageCatalog,
|
|
1726
|
+
loadVariantUiPackageManifest
|
|
1727
|
+
} from "@teamix-evo/registry";
|
|
1728
|
+
var require5 = createRequire4(import.meta.url);
|
|
1729
|
+
function resolvePackageRoot3(packageName) {
|
|
1730
|
+
const pkgJsonPath = require5.resolve(`${packageName}/package.json`);
|
|
1731
|
+
return path12.dirname(pkgJsonPath);
|
|
1732
|
+
}
|
|
1733
|
+
async function runVariantUiAdd(packageName, options) {
|
|
1734
|
+
const { projectRoot, variant, ids, overwrite } = options;
|
|
1735
|
+
const fullPackageName = options.packageName ?? `@teamix-evo/${packageName}`;
|
|
1736
|
+
if (ids.length === 0) {
|
|
1737
|
+
throw new Error("At least one entry id must be provided.");
|
|
1738
|
+
}
|
|
1739
|
+
const config = await readProjectConfig(projectRoot);
|
|
1740
|
+
const uiCfg = config?.packages?.ui;
|
|
1741
|
+
if (!config || !uiCfg?.aliases) {
|
|
1742
|
+
throw new Error(
|
|
1743
|
+
`UI not initialized. Run \`teamix-evo ui init\` first \u2014 \`${packageName} add\` writes into the same alias map (business / templates).`
|
|
1744
|
+
);
|
|
1745
|
+
}
|
|
1746
|
+
const packageRoot = options.packageRoot ?? resolvePackageRoot3(fullPackageName);
|
|
1747
|
+
const catalog = await loadVariantUiPackageCatalog(packageRoot);
|
|
1748
|
+
if (!catalog.variants.some((v) => v.name === variant)) {
|
|
1749
|
+
const known = catalog.variants.map((v) => v.name).join(", ");
|
|
1750
|
+
throw new Error(
|
|
1751
|
+
`Variant "${variant}" not found in ${fullPackageName}. Known variants: ${known}. Hint: \`teamix-evo ${packageName} list-variants\` shows all.`
|
|
1752
|
+
);
|
|
1753
|
+
}
|
|
1754
|
+
const variantDir = path12.join(packageRoot, "variants", variant);
|
|
1755
|
+
const variantManifest = await loadVariantUiPackageManifest(variantDir);
|
|
1756
|
+
const knownIds = new Set(variantManifest.entries.map((e) => e.id));
|
|
1757
|
+
const unknown = ids.filter((id) => !knownIds.has(id));
|
|
1758
|
+
if (unknown.length > 0) {
|
|
1759
|
+
throw new Error(
|
|
1760
|
+
`Unknown entry id(s) in ${packageName}#${variant}: ${unknown.map((s) => `"${s}"`).join(", ")}. Run \`teamix-evo ${packageName} list-variants\` to see this package's variants, or \`teamix-evo ${packageName} list --variant ${variant}\` for its entries.`
|
|
1761
|
+
);
|
|
1762
|
+
}
|
|
1763
|
+
const uiPackageRoot = resolvePackageRoot3("@teamix-evo/ui");
|
|
1764
|
+
const uiManifest = await loadUiPackageManifest2(uiPackageRoot);
|
|
1765
|
+
const entryPackageRoot = /* @__PURE__ */ new Map();
|
|
1766
|
+
const mergedEntries = [];
|
|
1767
|
+
for (const e of variantManifest.entries) {
|
|
1768
|
+
entryPackageRoot.set(e.id, variantDir);
|
|
1769
|
+
mergedEntries.push(e);
|
|
1770
|
+
}
|
|
1771
|
+
for (const e of uiManifest.entries) {
|
|
1772
|
+
if (entryPackageRoot.has(e.id)) continue;
|
|
1773
|
+
entryPackageRoot.set(e.id, uiPackageRoot);
|
|
1774
|
+
mergedEntries.push(e);
|
|
1775
|
+
}
|
|
1776
|
+
const adaptedManifest = {
|
|
1777
|
+
schemaVersion: 1,
|
|
1778
|
+
package: "ui",
|
|
1779
|
+
version: variantManifest.version,
|
|
1780
|
+
engines: variantManifest.engines,
|
|
1781
|
+
entries: mergedEntries
|
|
1782
|
+
};
|
|
1783
|
+
const result = await installUiEntries({
|
|
1784
|
+
projectRoot,
|
|
1785
|
+
manifest: adaptedManifest,
|
|
1786
|
+
packageRoot: variantDir,
|
|
1787
|
+
// default for variant entries
|
|
1788
|
+
entryPackageRoot,
|
|
1789
|
+
// ui entries resolve from uiPackageRoot
|
|
1790
|
+
aliases: uiCfg.aliases,
|
|
1791
|
+
requested: ids,
|
|
1792
|
+
skipExisting: !overwrite
|
|
1793
|
+
});
|
|
1794
|
+
const installed = await readInstalledManifest(
|
|
1795
|
+
projectRoot
|
|
1796
|
+
) ?? { schemaVersion: 1, installed: [] };
|
|
1797
|
+
const idx = installed.installed.findIndex(
|
|
1798
|
+
(p) => p.package === fullPackageName && p.variant === variant
|
|
1799
|
+
);
|
|
1800
|
+
const prior = idx >= 0 ? installed.installed[idx] : null;
|
|
1801
|
+
const mergedResources = mergeResources2(
|
|
1802
|
+
prior?.resources ?? [],
|
|
1803
|
+
result.resources
|
|
1804
|
+
);
|
|
1805
|
+
const entry = {
|
|
1806
|
+
package: fullPackageName,
|
|
1807
|
+
variant,
|
|
1808
|
+
version: variantManifest.version,
|
|
1809
|
+
installedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1810
|
+
resources: mergedResources
|
|
1811
|
+
};
|
|
1812
|
+
if (idx >= 0) installed.installed[idx] = entry;
|
|
1813
|
+
else installed.installed.push(entry);
|
|
1814
|
+
await writeInstalledManifest(projectRoot, installed);
|
|
1815
|
+
return {
|
|
1816
|
+
packageName: fullPackageName,
|
|
1817
|
+
variant,
|
|
1818
|
+
orderedIds: result.orderedIds,
|
|
1819
|
+
written: result.written,
|
|
1820
|
+
skipped: result.skipped,
|
|
1821
|
+
npmDependencies: result.npmDependencies,
|
|
1822
|
+
resources: result.resources
|
|
1823
|
+
};
|
|
1824
|
+
}
|
|
1825
|
+
function mergeResources2(prior, next) {
|
|
1826
|
+
const merged = /* @__PURE__ */ new Map();
|
|
1827
|
+
for (const r of prior) merged.set(r.id, r);
|
|
1828
|
+
for (const r of next) merged.set(r.id, r);
|
|
1829
|
+
return Array.from(merged.values());
|
|
1830
|
+
}
|
|
1831
|
+
async function runBizUiAdd(options) {
|
|
1832
|
+
return runVariantUiAdd("biz-ui", options);
|
|
1833
|
+
}
|
|
1834
|
+
async function runTemplatesAdd(options) {
|
|
1835
|
+
return runVariantUiAdd("templates", options);
|
|
1836
|
+
}
|
|
1837
|
+
async function listVariantUi(packageName, packageRoot) {
|
|
1838
|
+
const fullPackageName = `@teamix-evo/${packageName}`;
|
|
1839
|
+
const root = packageRoot ?? resolvePackageRoot3(fullPackageName);
|
|
1840
|
+
const catalog = await loadVariantUiPackageCatalog(root);
|
|
1841
|
+
return {
|
|
1842
|
+
packageName: fullPackageName,
|
|
1843
|
+
variants: catalog.variants.map((v) => ({
|
|
1844
|
+
name: v.name,
|
|
1845
|
+
displayName: v.displayName,
|
|
1846
|
+
version: v.version,
|
|
1847
|
+
description: v.description
|
|
1848
|
+
}))
|
|
1849
|
+
};
|
|
1850
|
+
}
|
|
1851
|
+
async function listBizUiVariants(packageRoot) {
|
|
1852
|
+
return listVariantUi("biz-ui", packageRoot);
|
|
1853
|
+
}
|
|
1854
|
+
async function listTemplatesVariants(packageRoot) {
|
|
1855
|
+
return listVariantUi("templates", packageRoot);
|
|
1856
|
+
}
|
|
1857
|
+
async function listVariantUiEntries(packageName, variant, packageRoot) {
|
|
1858
|
+
const fullPackageName = `@teamix-evo/${packageName}`;
|
|
1859
|
+
const root = packageRoot ?? resolvePackageRoot3(fullPackageName);
|
|
1860
|
+
const catalog = await loadVariantUiPackageCatalog(root);
|
|
1861
|
+
if (!catalog.variants.some((v) => v.name === variant)) {
|
|
1862
|
+
const known = catalog.variants.map((v) => v.name).join(", ");
|
|
1863
|
+
throw new Error(
|
|
1864
|
+
`Variant "${variant}" not found in ${fullPackageName}. Known: ${known}.`
|
|
1865
|
+
);
|
|
1866
|
+
}
|
|
1867
|
+
const variantDir = path12.join(root, "variants", variant);
|
|
1868
|
+
const variantManifest = await loadVariantUiPackageManifest(variantDir);
|
|
1869
|
+
return {
|
|
1870
|
+
packageName: fullPackageName,
|
|
1871
|
+
variant,
|
|
1872
|
+
entries: variantManifest.entries.map((e) => ({
|
|
1873
|
+
id: e.id,
|
|
1874
|
+
name: e.name,
|
|
1875
|
+
type: e.type,
|
|
1876
|
+
description: e.description,
|
|
1877
|
+
registryDependencies: e.registryDependencies ?? []
|
|
1878
|
+
}))
|
|
1879
|
+
};
|
|
1880
|
+
}
|
|
1881
|
+
async function listBizUiEntries(variant, packageRoot) {
|
|
1882
|
+
return listVariantUiEntries("biz-ui", variant, packageRoot);
|
|
1883
|
+
}
|
|
1884
|
+
async function listTemplatesEntries(variant, packageRoot) {
|
|
1885
|
+
return listVariantUiEntries("templates", variant, packageRoot);
|
|
1886
|
+
}
|
|
1887
|
+
|
|
1888
|
+
// src/core/lint-init.ts
|
|
1889
|
+
import * as path13 from "path";
|
|
1890
|
+
import * as fs9 from "fs";
|
|
1891
|
+
import { execa } from "execa";
|
|
1892
|
+
var ESLINT_CONFIG_CONTENT = `/**
|
|
1893
|
+
* teamix-evo consumer ESLint preset \u2014 9 token-discipline rules.
|
|
1894
|
+
* - Repo-wide: no-color-literal / no-arbitrary-tw-value / no-raw-color-scale /
|
|
1895
|
+
* no-large-radius / prefer-gap-over-space / no-manual-dark-classnames /
|
|
1896
|
+
* dialog-must-have-title (all error)
|
|
1897
|
+
* - src/components/ui/** only: no-relative-ui-import / icon-from-lucide (error)
|
|
1898
|
+
*
|
|
1899
|
+
* See ADR 0008 / docs/principles.md \xA7P4.
|
|
1900
|
+
*/
|
|
1901
|
+
import consumerPreset from '@teamix-evo/eslint-config/presets/consumer';
|
|
1902
|
+
|
|
1903
|
+
export default [...consumerPreset];
|
|
1904
|
+
`;
|
|
1905
|
+
var STYLELINT_CONFIG_CONTENT = `/** @type {import('stylelint').Config} */
|
|
1906
|
+
module.exports = {
|
|
1907
|
+
extends: ['@teamix-evo/stylelint-config/presets/consumer'],
|
|
1908
|
+
};
|
|
1909
|
+
`;
|
|
1910
|
+
var ESLINT_DEPS = [
|
|
1911
|
+
"@teamix-evo/eslint-config",
|
|
1912
|
+
"eslint",
|
|
1913
|
+
"@typescript-eslint/parser"
|
|
1914
|
+
];
|
|
1915
|
+
var STYLELINT_DEPS = ["@teamix-evo/stylelint-config", "stylelint"];
|
|
1916
|
+
async function runLintInit(options) {
|
|
1917
|
+
const { projectRoot, skipInstall } = options;
|
|
1918
|
+
const eslintConfigPath = path13.join(projectRoot, "eslint.config.js");
|
|
1919
|
+
const stylelintConfigPath = path13.join(projectRoot, "stylelint.config.cjs");
|
|
1920
|
+
const eslintExists = await fileExists(eslintConfigPath);
|
|
1921
|
+
const stylelintExists = await fileExists(stylelintConfigPath);
|
|
1922
|
+
if (eslintExists && stylelintExists) {
|
|
1923
|
+
return { status: "already-initialized" };
|
|
1924
|
+
}
|
|
1925
|
+
if (!skipInstall) {
|
|
1926
|
+
const depsToInstall = [
|
|
1927
|
+
...eslintExists ? [] : ESLINT_DEPS,
|
|
1928
|
+
...stylelintExists ? [] : STYLELINT_DEPS
|
|
1929
|
+
];
|
|
1930
|
+
if (depsToInstall.length > 0) {
|
|
1931
|
+
const pm = detectPm(projectRoot);
|
|
1932
|
+
const args = pm === "yarn" ? ["add", "--dev", ...depsToInstall] : pm === "pnpm" ? ["add", "-D", ...depsToInstall] : ["install", "--save-dev", ...depsToInstall];
|
|
1933
|
+
logger.info(`Installing lint deps via ${pm}...`);
|
|
1934
|
+
await execa(pm, args, { cwd: projectRoot, stdio: "inherit" });
|
|
1935
|
+
}
|
|
1936
|
+
}
|
|
1937
|
+
let wroteEslint = false;
|
|
1938
|
+
let wroteStylelint = false;
|
|
1939
|
+
if (!eslintExists) {
|
|
1940
|
+
await writeFileSafe(eslintConfigPath, ESLINT_CONFIG_CONTENT);
|
|
1941
|
+
logger.debug(`Wrote eslint.config.js \u2192 ${eslintConfigPath}`);
|
|
1942
|
+
wroteEslint = true;
|
|
1943
|
+
}
|
|
1944
|
+
if (!stylelintExists) {
|
|
1945
|
+
await writeFileSafe(stylelintConfigPath, STYLELINT_CONFIG_CONTENT);
|
|
1946
|
+
logger.debug(`Wrote stylelint.config.cjs \u2192 ${stylelintConfigPath}`);
|
|
1947
|
+
wroteStylelint = true;
|
|
1948
|
+
}
|
|
1949
|
+
await patchPackageJsonScripts(projectRoot);
|
|
1950
|
+
return {
|
|
1951
|
+
status: "installed",
|
|
1952
|
+
eslint: wroteEslint,
|
|
1953
|
+
stylelint: wroteStylelint
|
|
1954
|
+
};
|
|
1955
|
+
}
|
|
1956
|
+
function detectPm(projectRoot) {
|
|
1957
|
+
if (fs9.existsSync(path13.join(projectRoot, "pnpm-lock.yaml"))) return "pnpm";
|
|
1958
|
+
if (fs9.existsSync(path13.join(projectRoot, "yarn.lock"))) return "yarn";
|
|
1959
|
+
return "npm";
|
|
1960
|
+
}
|
|
1961
|
+
async function patchPackageJsonScripts(projectRoot) {
|
|
1962
|
+
const pkgPath = path13.join(projectRoot, "package.json");
|
|
1963
|
+
const raw = await readFileOrNull(pkgPath);
|
|
1964
|
+
if (!raw) return;
|
|
1965
|
+
let pkg;
|
|
1966
|
+
try {
|
|
1967
|
+
pkg = JSON.parse(raw);
|
|
1968
|
+
} catch {
|
|
1969
|
+
return;
|
|
1970
|
+
}
|
|
1971
|
+
const scripts = pkg.scripts ?? {};
|
|
1972
|
+
let changed = false;
|
|
1973
|
+
if (!scripts.lint) {
|
|
1974
|
+
scripts.lint = "eslint src/";
|
|
1975
|
+
changed = true;
|
|
1976
|
+
}
|
|
1977
|
+
if (!scripts["lint:css"]) {
|
|
1978
|
+
scripts["lint:css"] = "stylelint 'src/**/*.css'";
|
|
1979
|
+
changed = true;
|
|
1980
|
+
}
|
|
1981
|
+
if (changed) {
|
|
1982
|
+
pkg.scripts = scripts;
|
|
1983
|
+
await writeFileSafe(pkgPath, JSON.stringify(pkg, null, 2) + "\n");
|
|
1984
|
+
logger.debug("Patched package.json scripts with lint / lint:css");
|
|
1985
|
+
}
|
|
1986
|
+
}
|
|
1987
|
+
|
|
1988
|
+
// src/core/installer.ts
|
|
1989
|
+
import * as path14 from "path";
|
|
1990
|
+
import * as fs10 from "fs/promises";
|
|
1477
1991
|
async function installResources(options) {
|
|
1478
1992
|
const { projectRoot, manifest, data, variantDir, packageRoot } = options;
|
|
1479
1993
|
const installedResources = [];
|
|
@@ -1510,13 +2024,13 @@ async function installSingleResource(resource, projectRoot, data, variantDir, pa
|
|
|
1510
2024
|
variantDir,
|
|
1511
2025
|
packageRoot
|
|
1512
2026
|
);
|
|
1513
|
-
const targetPath =
|
|
2027
|
+
const targetPath = path14.join(projectRoot, resource.target);
|
|
1514
2028
|
let content;
|
|
1515
2029
|
if (resource.template) {
|
|
1516
2030
|
const templateContent = await loadTemplateFile(sourcePath);
|
|
1517
2031
|
content = renderTemplate(templateContent, data);
|
|
1518
2032
|
} else {
|
|
1519
|
-
content = await
|
|
2033
|
+
content = await fs10.readFile(sourcePath, "utf-8");
|
|
1520
2034
|
}
|
|
1521
2035
|
await writeFileSafe(targetPath, content);
|
|
1522
2036
|
const hash = computeHash(content);
|
|
@@ -1534,13 +2048,13 @@ async function installRecursiveResource(resource, projectRoot, data, variantDir,
|
|
|
1534
2048
|
variantDir,
|
|
1535
2049
|
packageRoot
|
|
1536
2050
|
);
|
|
1537
|
-
const targetDir =
|
|
2051
|
+
const targetDir = path14.join(projectRoot, resource.target);
|
|
1538
2052
|
const results = [];
|
|
1539
2053
|
await ensureDir(targetDir);
|
|
1540
2054
|
const entries = await walkDir(sourcePath);
|
|
1541
2055
|
for (const entry of entries) {
|
|
1542
|
-
const relPath =
|
|
1543
|
-
let targetFile =
|
|
2056
|
+
const relPath = path14.relative(sourcePath, entry);
|
|
2057
|
+
let targetFile = path14.join(targetDir, relPath);
|
|
1544
2058
|
if (resource.template && targetFile.endsWith(".hbs")) {
|
|
1545
2059
|
targetFile = targetFile.slice(0, -4);
|
|
1546
2060
|
}
|
|
@@ -1549,11 +2063,11 @@ async function installRecursiveResource(resource, projectRoot, data, variantDir,
|
|
|
1549
2063
|
const templateContent = await loadTemplateFile(entry);
|
|
1550
2064
|
content = renderTemplate(templateContent, data);
|
|
1551
2065
|
} else {
|
|
1552
|
-
content = await
|
|
2066
|
+
content = await fs10.readFile(entry, "utf-8");
|
|
1553
2067
|
}
|
|
1554
2068
|
await writeFileSafe(targetFile, content);
|
|
1555
2069
|
const hash = computeHash(content);
|
|
1556
|
-
const targetRel =
|
|
2070
|
+
const targetRel = path14.relative(projectRoot, targetFile);
|
|
1557
2071
|
results.push({
|
|
1558
2072
|
id: `${resource.id}:${relPath}`,
|
|
1559
2073
|
target: targetRel,
|
|
@@ -1566,25 +2080,25 @@ async function installRecursiveResource(resource, projectRoot, data, variantDir,
|
|
|
1566
2080
|
}
|
|
1567
2081
|
|
|
1568
2082
|
// src/core/registry-client.ts
|
|
1569
|
-
import * as
|
|
1570
|
-
import * as
|
|
1571
|
-
import { createRequire as
|
|
2083
|
+
import * as path15 from "path";
|
|
2084
|
+
import * as fs11 from "fs/promises";
|
|
2085
|
+
import { createRequire as createRequire5 } from "module";
|
|
1572
2086
|
import { loadVariantManifest } from "@teamix-evo/registry";
|
|
1573
|
-
var
|
|
1574
|
-
function
|
|
1575
|
-
const pkgJsonPath =
|
|
1576
|
-
return
|
|
2087
|
+
var require6 = createRequire5(import.meta.url);
|
|
2088
|
+
function resolvePackageRoot4(packageName) {
|
|
2089
|
+
const pkgJsonPath = require6.resolve(`${packageName}/package.json`);
|
|
2090
|
+
return path15.dirname(pkgJsonPath);
|
|
1577
2091
|
}
|
|
1578
2092
|
async function loadVariantData(packageName, variant) {
|
|
1579
|
-
const packageRoot =
|
|
1580
|
-
const variantDir =
|
|
2093
|
+
const packageRoot = resolvePackageRoot4(packageName);
|
|
2094
|
+
const variantDir = path15.join(packageRoot, "library", variant);
|
|
1581
2095
|
logger.debug(`Resolved variant dir: ${variantDir}`);
|
|
1582
2096
|
logger.debug(`Package root: ${packageRoot}`);
|
|
1583
2097
|
const manifest = await loadVariantManifest(variantDir);
|
|
1584
2098
|
let data = {};
|
|
1585
|
-
const dataPath =
|
|
2099
|
+
const dataPath = path15.join(variantDir, "_data.json");
|
|
1586
2100
|
try {
|
|
1587
|
-
const raw = await
|
|
2101
|
+
const raw = await fs11.readFile(dataPath, "utf-8");
|
|
1588
2102
|
data = JSON.parse(raw);
|
|
1589
2103
|
} catch (err) {
|
|
1590
2104
|
if (err.code !== "ENOENT") {
|
|
@@ -1602,6 +2116,10 @@ export {
|
|
|
1602
2116
|
installResources,
|
|
1603
2117
|
installSkills,
|
|
1604
2118
|
installUiEntries,
|
|
2119
|
+
listBizUiEntries,
|
|
2120
|
+
listBizUiVariants,
|
|
2121
|
+
listTemplatesEntries,
|
|
2122
|
+
listTemplatesVariants,
|
|
1605
2123
|
listTokenVariants,
|
|
1606
2124
|
loadSkillsData,
|
|
1607
2125
|
loadUiData,
|
|
@@ -1610,7 +2128,12 @@ export {
|
|
|
1610
2128
|
readProjectConfig,
|
|
1611
2129
|
removeSkillFiles,
|
|
1612
2130
|
removeUiFiles,
|
|
2131
|
+
runBizUiAdd,
|
|
2132
|
+
runLintInit,
|
|
1613
2133
|
runSkillsAdd,
|
|
2134
|
+
runSkillsInit,
|
|
2135
|
+
runSkillsUpdate,
|
|
2136
|
+
runTemplatesAdd,
|
|
1614
2137
|
runTokensInit,
|
|
1615
2138
|
runUiAdd,
|
|
1616
2139
|
runUiInit,
|