teamix-evo 0.4.0 → 0.4.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 +22 -21
- package/dist/core/index.d.ts +13 -1
- package/dist/core/index.js +164 -102
- package/dist/core/index.js.map +1 -1
- package/dist/index.js +623 -231
- package/dist/index.js.map +1 -1
- package/package.json +6 -6
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)
|
package/dist/core/index.d.ts
CHANGED
|
@@ -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;
|
package/dist/core/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// src/core/tokens-init.ts
|
|
2
|
-
import * as
|
|
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 {
|
|
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
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
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,
|
|
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
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
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(
|
|
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
|
-
|
|
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 =
|
|
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:
|
|
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
|
-
|
|
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 =
|
|
1007
|
-
const base =
|
|
1078
|
+
const sourceAbs = path9.join(packageRoot, fileRelToPackage);
|
|
1079
|
+
const base = path9.basename(fileRelToPackage);
|
|
1008
1080
|
if (base === "theme.css") {
|
|
1009
|
-
const targetRel =
|
|
1081
|
+
const targetRel = path9.posix.join(
|
|
1010
1082
|
CONSUMER_TOKENS_DIR,
|
|
1011
1083
|
CONSUMER_THEME_FILE
|
|
1012
1084
|
);
|
|
1013
|
-
const targetAbs =
|
|
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 =
|
|
1096
|
+
const targetRel = path9.posix.join(
|
|
1025
1097
|
CONSUMER_TOKENS_DIR,
|
|
1026
1098
|
CONSUMER_OVERRIDES_FILE
|
|
1027
1099
|
);
|
|
1028
|
-
const targetAbs =
|
|
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
|
|
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
|
-
|
|
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
|
|
1156
|
-
import { createRequire as
|
|
1197
|
+
import * as fs7 from "fs/promises";
|
|
1198
|
+
import { createRequire as createRequire3 } from "module";
|
|
1157
1199
|
import { loadUiPackageManifest } from "@teamix-evo/registry";
|
|
1158
|
-
var
|
|
1200
|
+
var require4 = createRequire3(import.meta.url);
|
|
1159
1201
|
function resolvePackageRoot2(packageName) {
|
|
1160
|
-
const pkgJsonPath =
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
1306
|
-
if (entries.length === 0) await
|
|
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
|
|
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
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
1509
|
-
import { createRequire as
|
|
1570
|
+
import * as fs10 from "fs/promises";
|
|
1571
|
+
import { createRequire as createRequire4 } from "module";
|
|
1510
1572
|
import { loadVariantManifest } from "@teamix-evo/registry";
|
|
1511
|
-
var
|
|
1573
|
+
var require5 = createRequire4(import.meta.url);
|
|
1512
1574
|
function resolvePackageRoot3(packageName) {
|
|
1513
|
-
const pkgJsonPath =
|
|
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
|
|
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") {
|