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.
@@ -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 currentTokensVariant = await readTokensVariant(projectRoot);
742
- if (isIncremental) {
743
- const known = new Set(manifest.skills.map((s) => s.id));
744
- const unknown = requestedNames.filter((n) => !known.has(n));
745
- if (unknown.length > 0) {
746
- const available = [...known].join(", ");
747
- throw new Error(
748
- `Unknown skill id(s): ${unknown.join(", ")}. Available: ${available || "(none)"}.`
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 existingInstalled = await readInstalledManifest(projectRoot);
753
- const existingPkg = existingInstalled?.installed.find(
754
- (p) => p.package === packageName
820
+ const existing = await readExistingState(projectRoot, packageName);
821
+ const skippedSkillIds = requestedNames.filter(
822
+ (n) => existing.skillIds.has(n)
755
823
  );
756
- const existingLock = await readSkillsLock(projectRoot);
757
- const existingSkillIds = /* @__PURE__ */ new Set([
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 = existingInstalled ?? {
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
- existingPkg?.resources ?? [],
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 = existingLock ?? {
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/installer.ts
1720
+ // src/core/variant-ui-add.ts
1475
1721
  import * as path12 from "path";
1476
- import * as fs9 from "fs/promises";
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 = path12.join(projectRoot, resource.target);
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 fs9.readFile(sourcePath, "utf-8");
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 = path12.join(projectRoot, resource.target);
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 = path12.relative(sourcePath, entry);
1543
- let targetFile = path12.join(targetDir, relPath);
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 fs9.readFile(entry, "utf-8");
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 = path12.relative(projectRoot, targetFile);
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 path13 from "path";
1570
- import * as fs10 from "fs/promises";
1571
- import { createRequire as createRequire4 } from "module";
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 require5 = createRequire4(import.meta.url);
1574
- function resolvePackageRoot3(packageName) {
1575
- const pkgJsonPath = require5.resolve(`${packageName}/package.json`);
1576
- return path13.dirname(pkgJsonPath);
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 = resolvePackageRoot3(packageName);
1580
- const variantDir = path13.join(packageRoot, "library", variant);
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 = path13.join(variantDir, "_data.json");
2099
+ const dataPath = path15.join(variantDir, "_data.json");
1586
2100
  try {
1587
- const raw = await fs10.readFile(dataPath, "utf-8");
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,