teamix-evo 0.5.0 → 0.6.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.
@@ -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,109 @@ async function runUiList(options) {
1471
1717
  };
1472
1718
  }
1473
1719
 
1474
- // src/core/installer.ts
1720
+ // src/core/lint-init.ts
1475
1721
  import * as path12 from "path";
1476
- import * as fs9 from "fs/promises";
1722
+ import * as fs9 from "fs";
1723
+ import { execa } from "execa";
1724
+ var ESLINT_CONFIG_CONTENT = `/**
1725
+ * teamix-evo consumer ESLint preset \u2014 9 token-discipline rules.
1726
+ * - Repo-wide: no-color-literal / no-arbitrary-tw-value / no-raw-color-scale /
1727
+ * no-large-radius / prefer-gap-over-space / no-manual-dark-classnames /
1728
+ * dialog-must-have-title (all error)
1729
+ * - src/components/ui/** only: no-relative-ui-import / icon-from-lucide (error)
1730
+ *
1731
+ * See ADR 0008 / docs/principles.md \xA7P4.
1732
+ */
1733
+ import consumerPreset from '@teamix-evo/eslint-config/presets/consumer';
1734
+
1735
+ export default [...consumerPreset];
1736
+ `;
1737
+ var STYLELINT_CONFIG_CONTENT = `/** @type {import('stylelint').Config} */
1738
+ module.exports = {
1739
+ extends: ['@teamix-evo/stylelint-config/presets/consumer'],
1740
+ };
1741
+ `;
1742
+ var ESLINT_DEPS = [
1743
+ "@teamix-evo/eslint-config",
1744
+ "eslint",
1745
+ "@typescript-eslint/parser"
1746
+ ];
1747
+ var STYLELINT_DEPS = ["@teamix-evo/stylelint-config", "stylelint"];
1748
+ async function runLintInit(options) {
1749
+ const { projectRoot, skipInstall } = options;
1750
+ const eslintConfigPath = path12.join(projectRoot, "eslint.config.js");
1751
+ const stylelintConfigPath = path12.join(projectRoot, "stylelint.config.cjs");
1752
+ const eslintExists = await fileExists(eslintConfigPath);
1753
+ const stylelintExists = await fileExists(stylelintConfigPath);
1754
+ if (eslintExists && stylelintExists) {
1755
+ return { status: "already-initialized" };
1756
+ }
1757
+ if (!skipInstall) {
1758
+ const depsToInstall = [
1759
+ ...eslintExists ? [] : ESLINT_DEPS,
1760
+ ...stylelintExists ? [] : STYLELINT_DEPS
1761
+ ];
1762
+ if (depsToInstall.length > 0) {
1763
+ const pm = detectPm(projectRoot);
1764
+ const args = pm === "yarn" ? ["add", "--dev", ...depsToInstall] : pm === "pnpm" ? ["add", "-D", ...depsToInstall] : ["install", "--save-dev", ...depsToInstall];
1765
+ logger.info(`Installing lint deps via ${pm}...`);
1766
+ await execa(pm, args, { cwd: projectRoot, stdio: "inherit" });
1767
+ }
1768
+ }
1769
+ let wroteEslint = false;
1770
+ let wroteStylelint = false;
1771
+ if (!eslintExists) {
1772
+ await writeFileSafe(eslintConfigPath, ESLINT_CONFIG_CONTENT);
1773
+ logger.debug(`Wrote eslint.config.js \u2192 ${eslintConfigPath}`);
1774
+ wroteEslint = true;
1775
+ }
1776
+ if (!stylelintExists) {
1777
+ await writeFileSafe(stylelintConfigPath, STYLELINT_CONFIG_CONTENT);
1778
+ logger.debug(`Wrote stylelint.config.cjs \u2192 ${stylelintConfigPath}`);
1779
+ wroteStylelint = true;
1780
+ }
1781
+ await patchPackageJsonScripts(projectRoot);
1782
+ return {
1783
+ status: "installed",
1784
+ eslint: wroteEslint,
1785
+ stylelint: wroteStylelint
1786
+ };
1787
+ }
1788
+ function detectPm(projectRoot) {
1789
+ if (fs9.existsSync(path12.join(projectRoot, "pnpm-lock.yaml"))) return "pnpm";
1790
+ if (fs9.existsSync(path12.join(projectRoot, "yarn.lock"))) return "yarn";
1791
+ return "npm";
1792
+ }
1793
+ async function patchPackageJsonScripts(projectRoot) {
1794
+ const pkgPath = path12.join(projectRoot, "package.json");
1795
+ const raw = await readFileOrNull(pkgPath);
1796
+ if (!raw) return;
1797
+ let pkg;
1798
+ try {
1799
+ pkg = JSON.parse(raw);
1800
+ } catch {
1801
+ return;
1802
+ }
1803
+ const scripts = pkg.scripts ?? {};
1804
+ let changed = false;
1805
+ if (!scripts.lint) {
1806
+ scripts.lint = "eslint src/";
1807
+ changed = true;
1808
+ }
1809
+ if (!scripts["lint:css"]) {
1810
+ scripts["lint:css"] = "stylelint 'src/**/*.css'";
1811
+ changed = true;
1812
+ }
1813
+ if (changed) {
1814
+ pkg.scripts = scripts;
1815
+ await writeFileSafe(pkgPath, JSON.stringify(pkg, null, 2) + "\n");
1816
+ logger.debug("Patched package.json scripts with lint / lint:css");
1817
+ }
1818
+ }
1819
+
1820
+ // src/core/installer.ts
1821
+ import * as path13 from "path";
1822
+ import * as fs10 from "fs/promises";
1477
1823
  async function installResources(options) {
1478
1824
  const { projectRoot, manifest, data, variantDir, packageRoot } = options;
1479
1825
  const installedResources = [];
@@ -1510,13 +1856,13 @@ async function installSingleResource(resource, projectRoot, data, variantDir, pa
1510
1856
  variantDir,
1511
1857
  packageRoot
1512
1858
  );
1513
- const targetPath = path12.join(projectRoot, resource.target);
1859
+ const targetPath = path13.join(projectRoot, resource.target);
1514
1860
  let content;
1515
1861
  if (resource.template) {
1516
1862
  const templateContent = await loadTemplateFile(sourcePath);
1517
1863
  content = renderTemplate(templateContent, data);
1518
1864
  } else {
1519
- content = await fs9.readFile(sourcePath, "utf-8");
1865
+ content = await fs10.readFile(sourcePath, "utf-8");
1520
1866
  }
1521
1867
  await writeFileSafe(targetPath, content);
1522
1868
  const hash = computeHash(content);
@@ -1534,13 +1880,13 @@ async function installRecursiveResource(resource, projectRoot, data, variantDir,
1534
1880
  variantDir,
1535
1881
  packageRoot
1536
1882
  );
1537
- const targetDir = path12.join(projectRoot, resource.target);
1883
+ const targetDir = path13.join(projectRoot, resource.target);
1538
1884
  const results = [];
1539
1885
  await ensureDir(targetDir);
1540
1886
  const entries = await walkDir(sourcePath);
1541
1887
  for (const entry of entries) {
1542
- const relPath = path12.relative(sourcePath, entry);
1543
- let targetFile = path12.join(targetDir, relPath);
1888
+ const relPath = path13.relative(sourcePath, entry);
1889
+ let targetFile = path13.join(targetDir, relPath);
1544
1890
  if (resource.template && targetFile.endsWith(".hbs")) {
1545
1891
  targetFile = targetFile.slice(0, -4);
1546
1892
  }
@@ -1549,11 +1895,11 @@ async function installRecursiveResource(resource, projectRoot, data, variantDir,
1549
1895
  const templateContent = await loadTemplateFile(entry);
1550
1896
  content = renderTemplate(templateContent, data);
1551
1897
  } else {
1552
- content = await fs9.readFile(entry, "utf-8");
1898
+ content = await fs10.readFile(entry, "utf-8");
1553
1899
  }
1554
1900
  await writeFileSafe(targetFile, content);
1555
1901
  const hash = computeHash(content);
1556
- const targetRel = path12.relative(projectRoot, targetFile);
1902
+ const targetRel = path13.relative(projectRoot, targetFile);
1557
1903
  results.push({
1558
1904
  id: `${resource.id}:${relPath}`,
1559
1905
  target: targetRel,
@@ -1566,25 +1912,25 @@ async function installRecursiveResource(resource, projectRoot, data, variantDir,
1566
1912
  }
1567
1913
 
1568
1914
  // src/core/registry-client.ts
1569
- import * as path13 from "path";
1570
- import * as fs10 from "fs/promises";
1915
+ import * as path14 from "path";
1916
+ import * as fs11 from "fs/promises";
1571
1917
  import { createRequire as createRequire4 } from "module";
1572
1918
  import { loadVariantManifest } from "@teamix-evo/registry";
1573
1919
  var require5 = createRequire4(import.meta.url);
1574
1920
  function resolvePackageRoot3(packageName) {
1575
1921
  const pkgJsonPath = require5.resolve(`${packageName}/package.json`);
1576
- return path13.dirname(pkgJsonPath);
1922
+ return path14.dirname(pkgJsonPath);
1577
1923
  }
1578
1924
  async function loadVariantData(packageName, variant) {
1579
1925
  const packageRoot = resolvePackageRoot3(packageName);
1580
- const variantDir = path13.join(packageRoot, "library", variant);
1926
+ const variantDir = path14.join(packageRoot, "library", variant);
1581
1927
  logger.debug(`Resolved variant dir: ${variantDir}`);
1582
1928
  logger.debug(`Package root: ${packageRoot}`);
1583
1929
  const manifest = await loadVariantManifest(variantDir);
1584
1930
  let data = {};
1585
- const dataPath = path13.join(variantDir, "_data.json");
1931
+ const dataPath = path14.join(variantDir, "_data.json");
1586
1932
  try {
1587
- const raw = await fs10.readFile(dataPath, "utf-8");
1933
+ const raw = await fs11.readFile(dataPath, "utf-8");
1588
1934
  data = JSON.parse(raw);
1589
1935
  } catch (err) {
1590
1936
  if (err.code !== "ENOENT") {
@@ -1610,7 +1956,10 @@ export {
1610
1956
  readProjectConfig,
1611
1957
  removeSkillFiles,
1612
1958
  removeUiFiles,
1959
+ runLintInit,
1613
1960
  runSkillsAdd,
1961
+ runSkillsInit,
1962
+ runSkillsUpdate,
1614
1963
  runTokensInit,
1615
1964
  runUiAdd,
1616
1965
  runUiInit,