teamix-evo 0.4.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -167,27 +167,28 @@ TEAMIX_DEBUG=1 teamix-evo tokens init opentrek
167
167
 
168
168
  ## 命令参考
169
169
 
170
- | 命令 | 说明 |
171
- | --------------------------------------------------- | ------------------------------------------------- |
172
- | `teamix-evo tokens init <variant>` | 初始化 tokens |
173
- | `teamix-evo tokens list-variants` | 列出可用 variant |
174
- | `teamix-evo tokens list` | 查看已装机的 variant |
175
- | `teamix-evo tokens update` | 更新已装资源(stub,v0.7 见 ADR 0019) |
176
- | `teamix-evo tokens uninstall` | 卸载已装 tokens |
177
- | `teamix-evo skills add [name...]` | 装 skills(写源 + 镜像 IDE);不传 = 全装 |
178
- | `teamix-evo skills list` | 列出所有 skill 的安装状态 |
179
- | `teamix-evo skills update` | 升级 skills(保留 managed 改动) |
180
- | `teamix-evo skills sync [name...]` | 源 → IDE 镜像(漂移恢复用) |
181
- | `teamix-evo skills doctor` | 检测源/镜像漂移(ADR 0013) |
182
- | `teamix-evo skills uninstall` | 卸载 skills(源 + 镜像 + lock) |
183
- | `teamix-evo ui init` | 初始化 ui 配置(aliases / iconLibrary / tsx / rsc) |
184
- | `teamix-evo ui add <id...>` | 安装指定 ui 组件源码 |
185
- | `teamix-evo ui list [--installed]` | 列出可用/已安装 ui 组件 |
186
- | `teamix-evo biz-ui list-variants` | 列出 biz-ui 包内提供的业务变体 |
187
- | `teamix-evo biz-ui add <id...> --variant <name>` | 安装变体感知业务组件(`--variant` 必填) |
188
- | `teamix-evo templates list-variants` | 列出 templates 包内提供的页面模板变体 |
189
- | `teamix-evo templates add <id...> --variant <name>` | 安装变体感知页面模板(`--variant` 必填) |
190
- | `teamix-evo logs analyze [...]` | 分析 vibe-logger AI 调用链(`.log/ai/**/*.jsonl`) |
170
+ | 命令 | 说明 |
171
+ | --------------------------------------------------- | -------------------------------------------------------------- |
172
+ | `teamix-evo tokens init <variant>` | 初始化 tokens |
173
+ | `teamix-evo tokens list-variants` | 列出可用 variant |
174
+ | `teamix-evo tokens list` | 查看已装机的 variant |
175
+ | `teamix-evo tokens update` | 更新已装资源(stub,v0.7 见 ADR 0019) |
176
+ | `teamix-evo tokens uninstall` | 卸载已装 tokens |
177
+ | `teamix-evo skills add [name...]` | 装 skills(写源 + 镜像 IDE);不传 = 全装 |
178
+ | `teamix-evo skills list` | 列出所有 skill 的安装状态 |
179
+ | `teamix-evo skills update` | 升级 skills(保留 managed 改动) |
180
+ | `teamix-evo skills sync [name...]` | 源 → IDE 镜像(漂移恢复用) |
181
+ | `teamix-evo skills doctor` | 检测源/镜像漂移(ADR 0013) |
182
+ | `teamix-evo skills uninstall` | 卸载 skills(源 + 镜像 + lock) |
183
+ | `teamix-evo ui init` | 初始化 ui 配置(aliases / iconLibrary / tsx / rsc) |
184
+ | `teamix-evo ui add <id...>` | 安装指定 ui 组件源码 |
185
+ | `teamix-evo ui list [--installed]` | 列出可用/已安装 ui 组件 |
186
+ | `teamix-evo biz-ui list-variants` | 列出 biz-ui 包内提供的业务变体 |
187
+ | `teamix-evo biz-ui add <id...> --variant <name>` | 安装变体感知业务组件(`--variant` 必填) |
188
+ | `teamix-evo templates list-variants` | 列出 templates 包内提供的页面模板变体 |
189
+ | `teamix-evo templates add <id...> --variant <name>` | 安装变体感知页面模板(`--variant` 必填) |
190
+ | `teamix-evo logs analyze [...]` | 分析 vibe-logger AI 调用链(`.log/ai/**/*.jsonl`) |
191
+ | `teamix-evo logs trace [...]` | 按会话还原 AI 调用链(prompt → PreToolUse → PostToolUse → Stop) |
191
192
 
192
193
  > 占位组件 → 真组件的升级流程**不是** CLI 子命令,由
193
194
  > [`teamix-evo-manage`](../../packages/skills/src/teamix-evo-manage/SKILL.md)
@@ -159,7 +159,6 @@ type RunUiInitResult = {
159
159
  iconLibrary: string;
160
160
  tsx: boolean;
161
161
  rsc: boolean;
162
- preferencesCss: 'deployed' | 'skipped' | 'source-missing';
163
162
  } | {
164
163
  status: 'already-initialized';
165
164
  };
@@ -180,6 +179,12 @@ interface RunUiAddOptions {
180
179
  overwrite?: boolean;
181
180
  /** Override the ui package name (defaults to "@teamix-evo/ui"). */
182
181
  packageName?: string;
182
+ /**
183
+ * When true, allow installing entries that live in `manifest.deprecatedEntries`
184
+ * (ADR 0028). Default: false — deprecated ids are treated as unknown and the
185
+ * call errors with a hint pointing the user at the active replacement.
186
+ */
187
+ includeDeprecated?: boolean;
183
188
  }
184
189
  interface RunUiAddResult {
185
190
  packageName: string;
@@ -209,12 +214,19 @@ interface RunUiListOptions {
209
214
  installedOnly?: boolean;
210
215
  /** Override the ui package name (defaults to "@teamix-evo/ui"). */
211
216
  packageName?: string;
217
+ /**
218
+ * When true, also include archived entries from `manifest.deprecatedEntries`
219
+ * (ADR 0028). They are flagged with `deprecated: true` in the result.
220
+ */
221
+ includeDeprecated?: boolean;
212
222
  }
213
223
  interface UiEntryListItem {
214
224
  id: string;
215
225
  type: UiEntry['type'];
216
226
  description: string;
217
227
  installed: boolean;
228
+ /** True when the entry comes from `manifest.deprecatedEntries` (ADR 0028). */
229
+ deprecated: boolean;
218
230
  }
219
231
  interface RunUiListResult {
220
232
  packageName: string;
@@ -1,5 +1,5 @@
1
1
  // src/core/tokens-init.ts
2
- import * as path8 from "path";
2
+ import * as path9 from "path";
3
3
  import * as fs6 from "fs/promises";
4
4
  import { createRequire as createRequire2 } from "module";
5
5
  import {
@@ -253,7 +253,10 @@ async function loadSkillsData(packageName) {
253
253
  // src/core/skills-installer.ts
254
254
  import * as path7 from "path";
255
255
  import * as fs5 from "fs/promises";
256
- import { replaceManagedRegion } from "@teamix-evo/registry";
256
+ import {
257
+ replaceManagedRegion,
258
+ hasManagedRegion
259
+ } from "@teamix-evo/registry";
257
260
 
258
261
  // src/ide/QoderAdapter.ts
259
262
  import * as os from "os";
@@ -428,20 +431,63 @@ async function mirrorSkillToIde(skill, ide, scope, projectRoot) {
428
431
  const rel2 = path7.relative(sourceDir, src);
429
432
  const targetFile = path7.join(targetDir, rel2);
430
433
  const sourceContent = await fs5.readFile(src, "utf-8");
431
- const existing = await readFileOrNull(targetFile);
432
- if (existing !== null && existing !== sourceContent) {
433
- logger.warn(
434
- `Mirror drift detected at ${targetFile} \u2014 overwriting from source. Edit ${src} (not the mirror) and re-run \`teamix-evo skills sync\`.`
435
- );
436
- }
437
- await writeFileSafe(targetFile, sourceContent);
434
+ const writtenContent = await writeMirrorContent(
435
+ targetFile,
436
+ sourceContent,
437
+ skill.managedRegions,
438
+ src
439
+ );
438
440
  records.push(
439
- makeMirrorRecord(skill, targetFile, sourceContent, ide, scope, rel2)
441
+ makeMirrorRecord(skill, targetFile, writtenContent, ide, scope, rel2)
440
442
  );
441
443
  logger.debug(` Mirrored ${ide}:${scope}: ${targetFile}`);
442
444
  }
443
445
  return records;
444
446
  }
447
+ async function writeMirrorContent(targetFile, sourceContent, managedRegions, sourceFile) {
448
+ const existing = await readFileOrNull(targetFile);
449
+ if (existing === null) {
450
+ await writeFileSafe(targetFile, sourceContent);
451
+ return sourceContent;
452
+ }
453
+ const regions = managedRegions ?? [];
454
+ const matchedRegions = regions.filter((id) => hasManagedRegion(existing, id));
455
+ if (matchedRegions.length === 0) {
456
+ if (existing !== sourceContent) {
457
+ logger.warn(
458
+ `Mirror drift detected at ${targetFile} \u2014 overwriting from source. Edit ${sourceFile} (not the mirror) and re-run \`teamix-evo skills sync\`.`
459
+ );
460
+ await writeFileSafe(targetFile, sourceContent);
461
+ return sourceContent;
462
+ }
463
+ return existing;
464
+ }
465
+ let merged = existing;
466
+ for (const id of matchedRegions) {
467
+ const newRegion = extractRegionBody(sourceContent, id);
468
+ if (newRegion === null) continue;
469
+ try {
470
+ merged = replaceManagedRegion(merged, id, newRegion);
471
+ } catch {
472
+ }
473
+ }
474
+ if (merged !== existing) {
475
+ await writeFileSafe(targetFile, merged);
476
+ }
477
+ return merged;
478
+ }
479
+ function extractRegionBody(content, id) {
480
+ const re = new RegExp(
481
+ `<!-- teamix-evo:managed:start id="${escapeRegExp(
482
+ id
483
+ )}" -->([\\s\\S]*?)<!-- teamix-evo:managed:end id="${escapeRegExp(
484
+ id
485
+ )}" -->`
486
+ );
487
+ const m = content.match(re);
488
+ if (!m) return null;
489
+ return m[1].replace(/^\n/, "").replace(/\n$/, "");
490
+ }
445
491
  async function renderSkillContent(sourceAbs, skill, data) {
446
492
  if (skill.template ?? sourceAbs.endsWith(".hbs")) {
447
493
  const tpl = await loadTemplateFile(sourceAbs);
@@ -601,17 +647,16 @@ async function syncSkillsToIdes(options) {
601
647
  const rel2 = path7.relative(sourceDir, src);
602
648
  const targetFile = path7.join(targetDir, rel2);
603
649
  const sourceContent = await fs5.readFile(src, "utf-8");
604
- const existing = await readFileOrNull(targetFile);
605
- if (existing !== null && existing !== sourceContent) {
606
- logger.warn(
607
- `Mirror drift detected at ${targetFile} \u2014 overwriting from source. Edit ${src} (not the mirror) and re-run \`teamix-evo skills sync\`.`
608
- );
609
- }
610
- await writeFileSafe(targetFile, sourceContent);
650
+ const writtenContent = await writeMirrorContent(
651
+ targetFile,
652
+ sourceContent,
653
+ skill.managedRegions,
654
+ src
655
+ );
611
656
  out.push({
612
657
  id: rel2 === "SKILL.md" ? skill.id : `${skill.id}:${rel2}`,
613
658
  target: targetFile,
614
- hash: computeHash(sourceContent),
659
+ hash: computeHash(writtenContent),
615
660
  strategy: skill.updateStrategy,
616
661
  ide,
617
662
  scope
@@ -650,6 +695,29 @@ async function removeSkillFiles(records) {
650
695
  return removed;
651
696
  }
652
697
 
698
+ // src/utils/mcp.ts
699
+ import * as path8 from "path";
700
+ var MCP_JSON_CONTENT = {
701
+ mcpServers: {
702
+ "teamix-evo": {
703
+ command: "npx",
704
+ args: ["-y", "@teamix-evo/mcp"]
705
+ }
706
+ }
707
+ };
708
+ async function ensureMcpJson(projectRoot) {
709
+ const mcpPath = path8.join(projectRoot, ".mcp.json");
710
+ if (await fileExists(mcpPath)) return "exists";
711
+ try {
712
+ await writeFileSafe(mcpPath, JSON.stringify(MCP_JSON_CONTENT, null, 2) + "\n");
713
+ logger.debug(`Wrote .mcp.json \u2192 ${mcpPath}`);
714
+ return "created";
715
+ } catch (err) {
716
+ logger.warn(`Failed to write .mcp.json: ${err.message}`);
717
+ return "failed";
718
+ }
719
+ }
720
+
653
721
  // src/core/skills-add.ts
654
722
  var DEFAULT_SKILLS_PACKAGE = "@teamix-evo/skills";
655
723
  var FLAT_VARIANT = "_flat";
@@ -661,9 +729,6 @@ async function runSkillsAdd(options) {
661
729
  await ensureTeamixDir(projectRoot);
662
730
  const existingConfig = await readProjectConfig(projectRoot);
663
731
  const existingSkillsCfg = existingConfig?.packages?.skills;
664
- if (!isIncremental && existingSkillsCfg) {
665
- return { status: "already-added" };
666
- }
667
732
  const ides = options.ides && options.ides.length > 0 ? [...options.ides] : existingSkillsCfg?.ides ? [...existingSkillsCfg.ides] : [];
668
733
  const scope = options.scope ?? existingSkillsCfg?.scope;
669
734
  if (ides.length === 0) {
@@ -701,8 +766,7 @@ async function runSkillsAdd(options) {
701
766
  skippedSkillIds = requestedNames.filter((n) => existingSkillIds.has(n));
702
767
  onlyIds = requestedNames.filter((n) => !existingSkillIds.has(n));
703
768
  } else {
704
- skippedSkillIds = [];
705
- onlyIds = manifest.skills.filter((s) => {
769
+ const candidateIds = manifest.skills.filter((s) => {
706
770
  if (!s.variant) return true;
707
771
  if (!currentTokensVariant) {
708
772
  logger.debug(
@@ -718,6 +782,11 @@ async function runSkillsAdd(options) {
718
782
  }
719
783
  return true;
720
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" };
721
790
  }
722
791
  if (isIncremental && onlyIds.length === 0) {
723
792
  return {
@@ -794,6 +863,7 @@ async function runSkillsAdd(options) {
794
863
  };
795
864
  }
796
865
  await writeSkillsLock(projectRoot, lock);
866
+ await ensureMcpJson(projectRoot);
797
867
  return {
798
868
  status: "installed",
799
869
  packageName,
@@ -831,6 +901,16 @@ async function runTokensInit(options) {
831
901
  const { projectRoot, variant, ide } = options;
832
902
  const packageName = options.packageName ?? DEFAULT_TOKENS_PACKAGE;
833
903
  await ensureTeamixDir(projectRoot);
904
+ const packageRoot = options.packageRoot ?? resolveTokensPackageRoot(packageName);
905
+ const catalog = await loadTokensPackageManifest(packageRoot);
906
+ const variantEntry = getVariantEntry(catalog, variant);
907
+ if (!variantEntry) {
908
+ const known = catalog.variants.map((v) => v.name).join(", ");
909
+ throw new Error(
910
+ `Unknown variant "${variant}". Available variants: ${known || "(none)"}.
911
+ Run \`teamix-evo tokens list-variants\` to see all options.`
912
+ );
913
+ }
834
914
  const existingConfig = await readProjectConfig(projectRoot);
835
915
  if (existingConfig?.packages?.tokens) {
836
916
  const existingVariant = existingConfig.packages.tokens.variant;
@@ -843,21 +923,12 @@ async function runTokensInit(options) {
843
923
  requestedVariant: variant
844
924
  };
845
925
  }
846
- const packageRoot = options.packageRoot ?? resolveTokensPackageRoot(packageName);
847
- const catalog = await loadTokensPackageManifest(packageRoot);
848
- const variantEntry = getVariantEntry(catalog, variant);
849
- if (!variantEntry) {
850
- const known = catalog.variants.map((v) => v.name).join(", ");
851
- throw new Error(
852
- `Tokens variant not found: "${variant}". Known variants: ${known || "(none)"}. Hint: run "teamix-evo tokens list-variants" to see all.`
853
- );
854
- }
855
926
  const installed = [];
856
927
  for (const fileRel of variantEntry.files) {
857
928
  const result = await installVariantFile(fileRel, packageRoot, projectRoot);
858
929
  if (result) installed.push(result);
859
930
  }
860
- const overridesAbs = path8.join(
931
+ const overridesAbs = path9.join(
861
932
  projectRoot,
862
933
  CONSUMER_TOKENS_DIR,
863
934
  CONSUMER_OVERRIDES_FILE
@@ -868,7 +939,7 @@ async function runTokensInit(options) {
868
939
  const overridesContent = await fs6.readFile(overridesAbs, "utf-8");
869
940
  installed.push({
870
941
  id: `tokens:${CONSUMER_OVERRIDES_FILE}`,
871
- target: path8.posix.join(CONSUMER_TOKENS_DIR, CONSUMER_OVERRIDES_FILE),
942
+ target: path9.posix.join(CONSUMER_TOKENS_DIR, CONSUMER_OVERRIDES_FILE),
872
943
  hash: computeHash(overridesContent),
873
944
  strategy: "frozen"
874
945
  });
@@ -885,7 +956,7 @@ async function runTokensInit(options) {
885
956
  installedAt: (/* @__PURE__ */ new Date()).toISOString()
886
957
  };
887
958
  await writeFileSafe(
888
- path8.join(projectRoot, ".teamix-evo", "tokens-lock.json"),
959
+ path9.join(projectRoot, ".teamix-evo", "tokens-lock.json"),
889
960
  JSON.stringify(lock, null, 2) + "\n"
890
961
  );
891
962
  const config = {
@@ -917,6 +988,7 @@ async function runTokensInit(options) {
917
988
  if (tokensIdx >= 0) prior.installed[tokensIdx] = tokensEntry;
918
989
  else prior.installed.push(tokensEntry);
919
990
  await writeInstalledManifest(projectRoot, prior);
991
+ await ensureMcpJson(projectRoot);
920
992
  const skills = await tryAutoInstallVariantSkills({
921
993
  projectRoot,
922
994
  variant,
@@ -1003,14 +1075,14 @@ async function tryAutoInstallVariantSkills(args) {
1003
1075
  }
1004
1076
  }
1005
1077
  async function installVariantFile(fileRelToPackage, packageRoot, projectRoot) {
1006
- const sourceAbs = path8.join(packageRoot, fileRelToPackage);
1007
- const base = path8.basename(fileRelToPackage);
1078
+ const sourceAbs = path9.join(packageRoot, fileRelToPackage);
1079
+ const base = path9.basename(fileRelToPackage);
1008
1080
  if (base === "theme.css") {
1009
- const targetRel = path8.posix.join(
1081
+ const targetRel = path9.posix.join(
1010
1082
  CONSUMER_TOKENS_DIR,
1011
1083
  CONSUMER_THEME_FILE
1012
1084
  );
1013
- const targetAbs = path8.join(projectRoot, targetRel);
1085
+ const targetAbs = path9.join(projectRoot, targetRel);
1014
1086
  const content = await fs6.readFile(sourceAbs, "utf-8");
1015
1087
  await writeFileSafe(targetAbs, content);
1016
1088
  return {
@@ -1021,11 +1093,11 @@ async function installVariantFile(fileRelToPackage, packageRoot, projectRoot) {
1021
1093
  };
1022
1094
  }
1023
1095
  if (base === "overrides.css" || base === "tokens.overrides.css") {
1024
- const targetRel = path8.posix.join(
1096
+ const targetRel = path9.posix.join(
1025
1097
  CONSUMER_TOKENS_DIR,
1026
1098
  CONSUMER_OVERRIDES_FILE
1027
1099
  );
1028
- const targetAbs = path8.join(projectRoot, targetRel);
1100
+ const targetAbs = path9.join(projectRoot, targetRel);
1029
1101
  if (await fileExists(targetAbs)) {
1030
1102
  const existing = await fs6.readFile(targetAbs, "utf-8");
1031
1103
  return {
@@ -1048,7 +1120,7 @@ async function installVariantFile(fileRelToPackage, packageRoot, projectRoot) {
1048
1120
  }
1049
1121
  function resolveTokensPackageRoot(packageName) {
1050
1122
  const pkgJson = require3.resolve(`${packageName}/package.json`);
1051
- return path8.dirname(pkgJson);
1123
+ return path9.dirname(pkgJson);
1052
1124
  }
1053
1125
  async function listTokenVariants(packageName = DEFAULT_TOKENS_PACKAGE, packageRoot) {
1054
1126
  const root = packageRoot ?? resolveTokensPackageRoot(packageName);
@@ -1067,35 +1139,6 @@ async function listTokenVariants(packageName = DEFAULT_TOKENS_PACKAGE, packageRo
1067
1139
  }
1068
1140
 
1069
1141
  // src/core/ui-init.ts
1070
- import * as fs7 from "fs/promises";
1071
- import { createRequire as createRequire3 } from "module";
1072
- import * as path9 from "path";
1073
- var require4 = createRequire3(import.meta.url);
1074
- async function deployPreferencesCss(projectRoot) {
1075
- const targetDir = path9.join(projectRoot, "src");
1076
- const targetPath = path9.join(targetDir, "preferences.css");
1077
- try {
1078
- await fs7.access(targetPath);
1079
- logger.debug(`preferences.css already exists at ${targetPath}, skipping`);
1080
- return "skipped";
1081
- } catch {
1082
- }
1083
- let sourcePath;
1084
- try {
1085
- const uiPkgJson = require4.resolve("@teamix-evo/ui/package.json");
1086
- sourcePath = path9.join(path9.dirname(uiPkgJson), "src", "preferences.css");
1087
- await fs7.access(sourcePath);
1088
- } catch {
1089
- logger.debug(
1090
- "Could not resolve @teamix-evo/ui/src/preferences.css; skipping deploy"
1091
- );
1092
- return "source-missing";
1093
- }
1094
- await fs7.mkdir(targetDir, { recursive: true });
1095
- const content = await fs7.readFile(sourcePath, "utf-8");
1096
- await fs7.writeFile(targetPath, content, "utf-8");
1097
- return "deployed";
1098
- }
1099
1142
  var DEFAULT_UI_ALIASES = {
1100
1143
  components: "src/components/ui",
1101
1144
  hooks: "src/hooks",
@@ -1139,25 +1182,24 @@ async function runUiInit(options) {
1139
1182
  rsc
1140
1183
  };
1141
1184
  await writeProjectConfig(projectRoot, config);
1142
- const preferencesCss = await deployPreferencesCss(projectRoot);
1185
+ await ensureMcpJson(projectRoot);
1143
1186
  return {
1144
1187
  status: "installed",
1145
1188
  aliases,
1146
1189
  iconLibrary,
1147
1190
  tsx,
1148
- rsc,
1149
- preferencesCss
1191
+ rsc
1150
1192
  };
1151
1193
  }
1152
1194
 
1153
1195
  // src/core/ui-client.ts
1154
1196
  import * as path10 from "path";
1155
- import * as fs8 from "fs/promises";
1156
- import { createRequire as createRequire4 } from "module";
1197
+ import * as fs7 from "fs/promises";
1198
+ import { createRequire as createRequire3 } from "module";
1157
1199
  import { loadUiPackageManifest } from "@teamix-evo/registry";
1158
- var require5 = createRequire4(import.meta.url);
1200
+ var require4 = createRequire3(import.meta.url);
1159
1201
  function resolvePackageRoot2(packageName) {
1160
- const pkgJsonPath = require5.resolve(`${packageName}/package.json`);
1202
+ const pkgJsonPath = require4.resolve(`${packageName}/package.json`);
1161
1203
  return path10.dirname(pkgJsonPath);
1162
1204
  }
1163
1205
  async function loadUiData(packageName) {
@@ -1167,7 +1209,7 @@ async function loadUiData(packageName) {
1167
1209
  let data = {};
1168
1210
  const dataPath = path10.join(packageRoot, "_data.json");
1169
1211
  try {
1170
- const raw = await fs8.readFile(dataPath, "utf-8");
1212
+ const raw = await fs7.readFile(dataPath, "utf-8");
1171
1213
  data = JSON.parse(raw);
1172
1214
  } catch (err) {
1173
1215
  if (err.code !== "ENOENT") {
@@ -1180,7 +1222,7 @@ async function loadUiData(packageName) {
1180
1222
 
1181
1223
  // src/core/ui-installer.ts
1182
1224
  import * as path11 from "path";
1183
- import * as fs9 from "fs/promises";
1225
+ import * as fs8 from "fs/promises";
1184
1226
  import { resolveUiEntryOrder } from "@teamix-evo/registry";
1185
1227
 
1186
1228
  // src/utils/transform-imports.ts
@@ -1254,7 +1296,7 @@ async function installUiEntries(options) {
1254
1296
  }
1255
1297
  const rootForEntry = entryPackageRoot?.get(entry.id) ?? packageRoot;
1256
1298
  const sourceAbs = path11.resolve(rootForEntry, file.source);
1257
- const raw = await fs9.readFile(sourceAbs, "utf-8");
1299
+ const raw = await fs8.readFile(sourceAbs, "utf-8");
1258
1300
  const transformed = rewriteImports(raw, aliases);
1259
1301
  await writeFileSafe(targetAbs, transformed);
1260
1302
  written++;
@@ -1291,7 +1333,7 @@ async function removeUiFiles(records) {
1291
1333
  const removed = [];
1292
1334
  for (const r of records) {
1293
1335
  try {
1294
- await fs9.unlink(r.target);
1336
+ await fs8.unlink(r.target);
1295
1337
  removed.push(r.target);
1296
1338
  } catch (err) {
1297
1339
  if (err.code !== "ENOENT") {
@@ -1302,8 +1344,8 @@ async function removeUiFiles(records) {
1302
1344
  const parents = new Set(records.map((r) => path11.dirname(r.target)));
1303
1345
  for (const dir of parents) {
1304
1346
  try {
1305
- const entries = await fs9.readdir(dir);
1306
- if (entries.length === 0) await fs9.rmdir(dir);
1347
+ const entries = await fs8.readdir(dir);
1348
+ if (entries.length === 0) await fs8.rmdir(dir);
1307
1349
  } catch {
1308
1350
  }
1309
1351
  }
@@ -1313,7 +1355,7 @@ async function removeUiFiles(records) {
1313
1355
  // src/core/ui-add.ts
1314
1356
  var DEFAULT_UI_PACKAGE = "@teamix-evo/ui";
1315
1357
  async function runUiAdd(options) {
1316
- const { projectRoot, ids, overwrite } = options;
1358
+ const { projectRoot, ids, overwrite, includeDeprecated } = options;
1317
1359
  const packageName = options.packageName ?? DEFAULT_UI_PACKAGE;
1318
1360
  if (ids.length === 0) {
1319
1361
  throw new Error("At least one entry id must be provided.");
@@ -1326,7 +1368,21 @@ async function runUiAdd(options) {
1326
1368
  );
1327
1369
  }
1328
1370
  const { manifest, packageRoot } = await loadUiData(packageName);
1329
- const knownIds = new Set(manifest.entries.map((e) => e.id));
1371
+ const archived = manifest.deprecatedEntries ?? [];
1372
+ const archivedIds = new Set(archived.map((e) => e.id));
1373
+ const activeIds = new Set(manifest.entries.map((e) => e.id));
1374
+ const requestedDeprecated = ids.filter((id) => archivedIds.has(id));
1375
+ if (requestedDeprecated.length > 0 && !includeDeprecated) {
1376
+ const list = requestedDeprecated.map((s) => `"${s}"`).join(", ");
1377
+ throw new Error(
1378
+ `Refusing to install deprecated entr${requestedDeprecated.length === 1 ? "y" : "ies"} ${list}. These entries are archived and not part of the active distribution (ADR 0028). Pass \`--include-deprecated\` to override (e.g. for migration tooling).`
1379
+ );
1380
+ }
1381
+ const effectiveManifest = includeDeprecated ? { ...manifest, entries: [...manifest.entries, ...archived] } : manifest;
1382
+ const knownIds = /* @__PURE__ */ new Set([
1383
+ ...activeIds,
1384
+ ...includeDeprecated ? archivedIds : []
1385
+ ]);
1330
1386
  const unknown = ids.filter((id) => !knownIds.has(id));
1331
1387
  if (unknown.length > 0) {
1332
1388
  throw new Error(
@@ -1335,7 +1391,7 @@ async function runUiAdd(options) {
1335
1391
  }
1336
1392
  const result = await installUiEntries({
1337
1393
  projectRoot,
1338
- manifest,
1394
+ manifest: effectiveManifest,
1339
1395
  packageRoot,
1340
1396
  aliases: uiCfg.aliases,
1341
1397
  requested: ids,
@@ -1383,7 +1439,7 @@ function mergeResources(prior, next) {
1383
1439
  // src/core/ui-list.ts
1384
1440
  var DEFAULT_UI_PACKAGE2 = "@teamix-evo/ui";
1385
1441
  async function runUiList(options) {
1386
- const { projectRoot, installedOnly } = options;
1442
+ const { projectRoot, installedOnly, includeDeprecated } = options;
1387
1443
  const packageName = options.packageName ?? DEFAULT_UI_PACKAGE2;
1388
1444
  const { manifest } = await loadUiData(packageName);
1389
1445
  const installedManifest = await readInstalledManifest(projectRoot);
@@ -1395,15 +1451,21 @@ async function runUiList(options) {
1395
1451
  const colon = r.id.indexOf(":");
1396
1452
  installedIds.add(colon >= 0 ? r.id.slice(0, colon) : r.id);
1397
1453
  }
1398
- const entries = manifest.entries.filter((e) => !installedOnly || installedIds.has(e.id)).map((e) => ({
1399
- id: e.id,
1400
- type: e.type,
1401
- description: e.description,
1402
- installed: installedIds.has(e.id)
1454
+ const archived = manifest.deprecatedEntries ?? [];
1455
+ const pool = includeDeprecated ? [
1456
+ ...manifest.entries.map((e) => ({ entry: e, deprecated: false })),
1457
+ ...archived.map((e) => ({ entry: e, deprecated: true }))
1458
+ ] : manifest.entries.map((e) => ({ entry: e, deprecated: false }));
1459
+ const entries = pool.filter(({ entry }) => !installedOnly || installedIds.has(entry.id)).map(({ entry, deprecated }) => ({
1460
+ id: entry.id,
1461
+ type: entry.type,
1462
+ description: entry.description,
1463
+ installed: installedIds.has(entry.id),
1464
+ deprecated
1403
1465
  }));
1404
1466
  return {
1405
1467
  packageName,
1406
- total: manifest.entries.length,
1468
+ total: manifest.entries.length + (includeDeprecated ? archived.length : 0),
1407
1469
  installedCount: installedIds.size,
1408
1470
  entries
1409
1471
  };
@@ -1411,7 +1473,7 @@ async function runUiList(options) {
1411
1473
 
1412
1474
  // src/core/installer.ts
1413
1475
  import * as path12 from "path";
1414
- import * as fs10 from "fs/promises";
1476
+ import * as fs9 from "fs/promises";
1415
1477
  async function installResources(options) {
1416
1478
  const { projectRoot, manifest, data, variantDir, packageRoot } = options;
1417
1479
  const installedResources = [];
@@ -1454,7 +1516,7 @@ async function installSingleResource(resource, projectRoot, data, variantDir, pa
1454
1516
  const templateContent = await loadTemplateFile(sourcePath);
1455
1517
  content = renderTemplate(templateContent, data);
1456
1518
  } else {
1457
- content = await fs10.readFile(sourcePath, "utf-8");
1519
+ content = await fs9.readFile(sourcePath, "utf-8");
1458
1520
  }
1459
1521
  await writeFileSafe(targetPath, content);
1460
1522
  const hash = computeHash(content);
@@ -1487,7 +1549,7 @@ async function installRecursiveResource(resource, projectRoot, data, variantDir,
1487
1549
  const templateContent = await loadTemplateFile(entry);
1488
1550
  content = renderTemplate(templateContent, data);
1489
1551
  } else {
1490
- content = await fs10.readFile(entry, "utf-8");
1552
+ content = await fs9.readFile(entry, "utf-8");
1491
1553
  }
1492
1554
  await writeFileSafe(targetFile, content);
1493
1555
  const hash = computeHash(content);
@@ -1505,12 +1567,12 @@ async function installRecursiveResource(resource, projectRoot, data, variantDir,
1505
1567
 
1506
1568
  // src/core/registry-client.ts
1507
1569
  import * as path13 from "path";
1508
- import * as fs11 from "fs/promises";
1509
- import { createRequire as createRequire5 } from "module";
1570
+ import * as fs10 from "fs/promises";
1571
+ import { createRequire as createRequire4 } from "module";
1510
1572
  import { loadVariantManifest } from "@teamix-evo/registry";
1511
- var require6 = createRequire5(import.meta.url);
1573
+ var require5 = createRequire4(import.meta.url);
1512
1574
  function resolvePackageRoot3(packageName) {
1513
- const pkgJsonPath = require6.resolve(`${packageName}/package.json`);
1575
+ const pkgJsonPath = require5.resolve(`${packageName}/package.json`);
1514
1576
  return path13.dirname(pkgJsonPath);
1515
1577
  }
1516
1578
  async function loadVariantData(packageName, variant) {
@@ -1522,7 +1584,7 @@ async function loadVariantData(packageName, variant) {
1522
1584
  let data = {};
1523
1585
  const dataPath = path13.join(variantDir, "_data.json");
1524
1586
  try {
1525
- const raw = await fs11.readFile(dataPath, "utf-8");
1587
+ const raw = await fs10.readFile(dataPath, "utf-8");
1526
1588
  data = JSON.parse(raw);
1527
1589
  } catch (err) {
1528
1590
  if (err.code !== "ENOENT") {