teamix-evo 0.14.0 → 0.14.2
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/dist/core/index.d.ts +31 -6
- package/dist/core/index.js +169 -57
- package/dist/core/index.js.map +1 -1
- package/dist/index.js +269 -81
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
package/dist/core/index.d.ts
CHANGED
|
@@ -314,8 +314,14 @@ interface RunUiAddResult {
|
|
|
314
314
|
packageName: string;
|
|
315
315
|
/** Registered ids in install order (deps + requested). */
|
|
316
316
|
orderedIds: string[];
|
|
317
|
-
/** Number of files written. */
|
|
317
|
+
/** Number of files written (= created + overwritten). */
|
|
318
318
|
written: number;
|
|
319
|
+
/** Number of files newly created. */
|
|
320
|
+
created: number;
|
|
321
|
+
/** Number of existing files overwritten. */
|
|
322
|
+
overwritten: number;
|
|
323
|
+
/** Number of overwritten files that had local modifications. */
|
|
324
|
+
userModified: number;
|
|
319
325
|
/** Number of files skipped due to frozen + exists. */
|
|
320
326
|
skipped: number;
|
|
321
327
|
/** Aggregate npm dependencies of the installed entries. */
|
|
@@ -390,6 +396,9 @@ interface RunVariantUiAddResult {
|
|
|
390
396
|
variant: string;
|
|
391
397
|
orderedIds: string[];
|
|
392
398
|
written: number;
|
|
399
|
+
created: number;
|
|
400
|
+
overwritten: number;
|
|
401
|
+
userModified: number;
|
|
393
402
|
skipped: number;
|
|
394
403
|
npmDependencies: Record<string, string>;
|
|
395
404
|
resources: InstalledResource[];
|
|
@@ -500,9 +509,14 @@ declare function runLintInit(options: RunLintInitOptions): Promise<RunLintInitRe
|
|
|
500
509
|
* skill activation conditions even when the user prompt does not directly
|
|
501
510
|
* hit the description-based trigger.
|
|
502
511
|
*
|
|
512
|
+
* Includes both project-scope content skills AND global-scope lifecycle skills
|
|
513
|
+
* (e.g. `teamix-evo-manage`): manage triggers are rendered into the project
|
|
514
|
+
* AGENTS.md so team members who clone the repo see the lifecycle entry points
|
|
515
|
+
* even before installing the global skill themselves. A "全局技能" note guides
|
|
516
|
+
* the AI to check availability and prompt installation when needed (ADR 0033).
|
|
517
|
+
*
|
|
503
518
|
* Out of scope (per ADR 0038):
|
|
504
519
|
* - Does NOT copy skill body / rules / patterns — those stay in the skill.
|
|
505
|
-
* - Does NOT include `teamix-evo-manage` (entry skill, global scope, ADR 0033).
|
|
506
520
|
*
|
|
507
521
|
* Lifted from `create-teamix-evo` (v0.5) into `teamix-evo/core` so both
|
|
508
522
|
* `npm create teamix-evo` (scaffold path) and `teamix-evo init` (existing-
|
|
@@ -515,11 +529,14 @@ interface RunGenerateAgentsMdOptions {
|
|
|
515
529
|
projectRoot: string;
|
|
516
530
|
/** Tokens / skills variant (e.g. "opentrek"). Used for header context. */
|
|
517
531
|
variant: string;
|
|
532
|
+
/** Project-scope skill ids to index. */
|
|
533
|
+
skillIds: string[];
|
|
518
534
|
/**
|
|
519
|
-
*
|
|
520
|
-
*
|
|
535
|
+
* Global-scope skill ids to include alongside project skills. Rendered with
|
|
536
|
+
* a "全局技能" installation note. TRIGGER / SKIP text is read from the
|
|
537
|
+
* global IDE mirror path at generation time.
|
|
521
538
|
*/
|
|
522
|
-
|
|
539
|
+
globalSkillIds?: string[];
|
|
523
540
|
/**
|
|
524
541
|
* Reconciliation mode (Phase 2.B):
|
|
525
542
|
* - `'overwrite'` (default): always rewrite the full file. Pre-existing
|
|
@@ -883,6 +900,8 @@ interface UiInstallOptions {
|
|
|
883
900
|
skipExisting?: boolean;
|
|
884
901
|
/** When false, preserve directory structure in import paths (skip flattenRestPath). Defaults to true. */
|
|
885
902
|
flatten?: boolean;
|
|
903
|
+
/** Prior manifest resources for the same package — used to detect user-modified files before overwrite. */
|
|
904
|
+
priorResources?: InstalledResource[];
|
|
886
905
|
}
|
|
887
906
|
interface UiInstallResult {
|
|
888
907
|
/** Ordered list of entry ids that were processed (deps + requested) */
|
|
@@ -891,8 +910,14 @@ interface UiInstallResult {
|
|
|
891
910
|
resources: InstalledResource[];
|
|
892
911
|
/** Aggregate npm dependencies across the installed entries */
|
|
893
912
|
npmDependencies: Record<string, string>;
|
|
894
|
-
/** Number of files written */
|
|
913
|
+
/** Number of files written (= created + overwritten, kept for backwards compat) */
|
|
895
914
|
written: number;
|
|
915
|
+
/** Number of files newly created (target did not exist) */
|
|
916
|
+
created: number;
|
|
917
|
+
/** Number of existing files overwritten */
|
|
918
|
+
overwritten: number;
|
|
919
|
+
/** Number of overwritten files that had local modifications vs manifest hash */
|
|
920
|
+
userModified: number;
|
|
896
921
|
/** Number of files skipped because they already exist (frozen) */
|
|
897
922
|
skipped: number;
|
|
898
923
|
}
|
package/dist/core/index.js
CHANGED
|
@@ -165,12 +165,40 @@ async function readInstalledManifest(projectRoot) {
|
|
|
165
165
|
);
|
|
166
166
|
}
|
|
167
167
|
const result = validateInstalled(data);
|
|
168
|
-
if (
|
|
169
|
-
|
|
170
|
-
|
|
168
|
+
if (result.success) {
|
|
169
|
+
return result.data;
|
|
170
|
+
}
|
|
171
|
+
const migrated = migrateManifest(data);
|
|
172
|
+
const retryResult = validateInstalled(migrated);
|
|
173
|
+
if (retryResult.success) {
|
|
174
|
+
logger.warn(
|
|
175
|
+
"Migrated legacy manifest.json \u2014 will be overwritten on next install."
|
|
171
176
|
);
|
|
177
|
+
return retryResult.data;
|
|
172
178
|
}
|
|
173
|
-
|
|
179
|
+
throw new Error(
|
|
180
|
+
`Invalid manifest.json schema: ${result.error}. Fix the file manually or remove it to start fresh.`
|
|
181
|
+
);
|
|
182
|
+
}
|
|
183
|
+
function migrateManifest(data) {
|
|
184
|
+
if (typeof data !== "object" || data === null) return data;
|
|
185
|
+
const obj = data;
|
|
186
|
+
if (!("schemaVersion" in obj)) obj.schemaVersion = 1;
|
|
187
|
+
if (!Array.isArray(obj.installed)) obj.installed = [];
|
|
188
|
+
for (const pkg of obj.installed) {
|
|
189
|
+
if (typeof pkg !== "object" || pkg === null) continue;
|
|
190
|
+
if (!pkg.variant) pkg.variant = "_flat";
|
|
191
|
+
if (!pkg.installedAt) pkg.installedAt = "";
|
|
192
|
+
if (!pkg.version) pkg.version = "0.0.0";
|
|
193
|
+
if (Array.isArray(pkg.resources)) {
|
|
194
|
+
for (const res of pkg.resources) {
|
|
195
|
+
if (typeof res !== "object" || res === null) continue;
|
|
196
|
+
if (!res.hash) res.hash = "sha256:legacy-unknown";
|
|
197
|
+
if (!res.strategy) res.strategy = "frozen";
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
return obj;
|
|
174
202
|
}
|
|
175
203
|
async function writeInstalledManifest(projectRoot, manifest) {
|
|
176
204
|
const manifestPath = path2.join(projectRoot, TEAMIX_DIR, MANIFEST_FILE);
|
|
@@ -948,9 +976,15 @@ function partitionByVersion(ids, manifest, existing) {
|
|
|
948
976
|
onlyIds.push(name);
|
|
949
977
|
continue;
|
|
950
978
|
}
|
|
951
|
-
const installedVer = existing.lock?.skills?.[name]?.version;
|
|
979
|
+
const installedVer = existing.lock?.skills?.[name]?.version ?? existing.pkg?.version;
|
|
952
980
|
const latestVer = manifestById.get(name)?.version;
|
|
953
|
-
if (installedVer
|
|
981
|
+
if (!installedVer || !latestVer) {
|
|
982
|
+
if (latestVer) {
|
|
983
|
+
outdatedSkills.push({ id: name, installed: "0.0.0", latest: latestVer });
|
|
984
|
+
} else {
|
|
985
|
+
skippedSkillIds.push(name);
|
|
986
|
+
}
|
|
987
|
+
} else if (compareSemver(installedVer, latestVer) < 0) {
|
|
954
988
|
outdatedSkills.push({
|
|
955
989
|
id: name,
|
|
956
990
|
installed: installedVer,
|
|
@@ -1429,18 +1463,24 @@ import { hasManagedRegion as hasManagedRegion2, replaceManagedRegion as replaceM
|
|
|
1429
1463
|
var AGENTS_MD_MANAGED_ID = "teamix-evo-skills";
|
|
1430
1464
|
async function runGenerateAgentsMd(options) {
|
|
1431
1465
|
const { projectRoot, variant, skillIds } = options;
|
|
1466
|
+
const globalSkillIds = options.globalSkillIds ?? [];
|
|
1432
1467
|
const mode = options.mode ?? "overwrite";
|
|
1433
1468
|
const config = await readProjectConfig(projectRoot);
|
|
1434
1469
|
const lock = await readSkillsLock(projectRoot);
|
|
1435
1470
|
const ides = config?.packages?.skills?.ides ?? ["qoder", "claude"];
|
|
1436
1471
|
const scope = config?.packages?.skills?.scope ?? lock?.skills[skillIds[0] ?? ""]?.scope ?? "project";
|
|
1437
|
-
const
|
|
1472
|
+
const skillScopeMap = /* @__PURE__ */ new Map();
|
|
1473
|
+
for (const id of skillIds) skillScopeMap.set(id, scope);
|
|
1474
|
+
for (const id of globalSkillIds) skillScopeMap.set(id, "global");
|
|
1475
|
+
const allSkillIds = [...skillIds, ...globalSkillIds];
|
|
1476
|
+
const ordered = allSkillIds.sort(
|
|
1438
1477
|
(a, b) => bucketRank(a) - bucketRank(b) || a.localeCompare(b)
|
|
1439
1478
|
);
|
|
1440
1479
|
const sections = [];
|
|
1441
1480
|
const missingSkillIds = [];
|
|
1442
1481
|
for (const id of ordered) {
|
|
1443
|
-
const
|
|
1482
|
+
const skillScope = skillScopeMap.get(id) ?? scope;
|
|
1483
|
+
const { section, missing } = await renderSkillSection(projectRoot, id, ides, skillScope);
|
|
1444
1484
|
sections.push(section);
|
|
1445
1485
|
if (missing) missingSkillIds.push(id);
|
|
1446
1486
|
}
|
|
@@ -1524,6 +1564,12 @@ async function renderSkillSection(projectRoot, skillId, ides, scope) {
|
|
|
1524
1564
|
if (parts?.coordinates) {
|
|
1525
1565
|
lines.push(`- **Coordinates with**: ${parts.coordinates}`);
|
|
1526
1566
|
}
|
|
1567
|
+
if (scope === "global") {
|
|
1568
|
+
lines.push("");
|
|
1569
|
+
lines.push(
|
|
1570
|
+
"> **\u5168\u5C40\u6280\u80FD** \u2014 \u5B89\u88C5\u5728\u5168\u5C40\u800C\u975E\u9879\u76EE\u5185\uFF0C\u4E0D\u968F\u4EE3\u7801\u4ED3\u5E93\u5206\u53D1\u3002AI \u89E6\u53D1\u65F6\u5E94\u5148\u786E\u8BA4\u672C\u6280\u80FD\u53EF\u7528\uFF1B\u82E5\u4E0D\u53EF\u7528\uFF0C\u5F15\u5BFC\u7528\u6237\u6267\u884C\u5168\u5C40\u5B89\u88C5\u3002"
|
|
1571
|
+
);
|
|
1572
|
+
}
|
|
1527
1573
|
return { section: lines.join("\n"), missing };
|
|
1528
1574
|
}
|
|
1529
1575
|
function renderAgentsMd(args) {
|
|
@@ -1669,13 +1715,34 @@ async function runSkillsUpdate(options) {
|
|
|
1669
1715
|
}
|
|
1670
1716
|
const ides = skillsCfg.ides ?? ["qoder", "claude"];
|
|
1671
1717
|
const scope = skillsCfg.scope ?? "project";
|
|
1672
|
-
|
|
1718
|
+
let existingLock = await readSkillsLock(projectRoot);
|
|
1673
1719
|
if (!existingLock || Object.keys(existingLock.skills).length === 0) {
|
|
1674
|
-
|
|
1720
|
+
const installedManifest2 = await readInstalledManifest(projectRoot);
|
|
1721
|
+
const pkg = installedManifest2?.installed.find(
|
|
1722
|
+
(p) => p.package === packageName
|
|
1723
|
+
);
|
|
1724
|
+
if (!pkg || pkg.resources.length === 0) {
|
|
1725
|
+
return { status: "no-skills" };
|
|
1726
|
+
}
|
|
1727
|
+
const derivedSkills = {};
|
|
1728
|
+
for (const r of pkg.resources) {
|
|
1729
|
+
const skillId = r.id.split(":")[0] ?? r.id;
|
|
1730
|
+
if (!derivedSkills[skillId]) {
|
|
1731
|
+
derivedSkills[skillId] = {
|
|
1732
|
+
version: pkg.version,
|
|
1733
|
+
from: packageName,
|
|
1734
|
+
installedAt: "",
|
|
1735
|
+
scope,
|
|
1736
|
+
mirroredTo: []
|
|
1737
|
+
};
|
|
1738
|
+
}
|
|
1739
|
+
}
|
|
1740
|
+
existingLock = { schemaVersion: 1, skills: derivedSkills };
|
|
1675
1741
|
}
|
|
1742
|
+
const activeLock = existingLock;
|
|
1676
1743
|
const { manifest, data, packageRoot } = await loadSkillsData(packageName);
|
|
1677
1744
|
const manifestById = new Map(manifest.skills.map((s) => [s.id, s]));
|
|
1678
|
-
const lockIds = Object.keys(
|
|
1745
|
+
const lockIds = Object.keys(activeLock.skills);
|
|
1679
1746
|
const requestedSet = requestedNames ? new Set(requestedNames) : null;
|
|
1680
1747
|
if (requestedSet) {
|
|
1681
1748
|
const unknown = requestedNames.filter(
|
|
@@ -1712,7 +1779,7 @@ async function runSkillsUpdate(options) {
|
|
|
1712
1779
|
targetIds.push(id);
|
|
1713
1780
|
}
|
|
1714
1781
|
const allSame = targetIds.every((id) => {
|
|
1715
|
-
const lockVer =
|
|
1782
|
+
const lockVer = activeLock.skills[id].version;
|
|
1716
1783
|
const manVer = manifestById.get(id).version;
|
|
1717
1784
|
return lockVer === manVer;
|
|
1718
1785
|
});
|
|
@@ -1726,7 +1793,7 @@ async function runSkillsUpdate(options) {
|
|
|
1726
1793
|
}
|
|
1727
1794
|
if (dryRun) {
|
|
1728
1795
|
const plan = targetIds.map((id) => {
|
|
1729
|
-
const lockVer =
|
|
1796
|
+
const lockVer = activeLock.skills[id].version;
|
|
1730
1797
|
const entry2 = manifestById.get(id);
|
|
1731
1798
|
const sameVersion = lockVer === entry2.version;
|
|
1732
1799
|
return {
|
|
@@ -1798,7 +1865,7 @@ async function runSkillsUpdate(options) {
|
|
|
1798
1865
|
await writeInstalledManifest(projectRoot, installedManifest);
|
|
1799
1866
|
const lock = {
|
|
1800
1867
|
schemaVersion: 1,
|
|
1801
|
-
skills: { ...
|
|
1868
|
+
skills: { ...activeLock.skills }
|
|
1802
1869
|
};
|
|
1803
1870
|
for (const id of targetIds) {
|
|
1804
1871
|
const skillDef = manifestById.get(id);
|
|
@@ -1818,10 +1885,12 @@ async function runSkillsUpdate(options) {
|
|
|
1818
1885
|
const variant = await readTokensVariant(projectRoot);
|
|
1819
1886
|
if (variant) {
|
|
1820
1887
|
const projectSkillIds = Object.entries(lock.skills).filter(([, v]) => v.scope === "project").map(([id]) => id);
|
|
1888
|
+
const globalSkillIds = Object.entries(lock.skills).filter(([, v]) => v.scope === "global").map(([id]) => id);
|
|
1821
1889
|
await runGenerateAgentsMd({
|
|
1822
1890
|
projectRoot,
|
|
1823
1891
|
variant,
|
|
1824
1892
|
skillIds: projectSkillIds,
|
|
1893
|
+
globalSkillIds,
|
|
1825
1894
|
mode: "merge-managed"
|
|
1826
1895
|
});
|
|
1827
1896
|
}
|
|
@@ -1911,6 +1980,10 @@ async function loadUiData(packageName) {
|
|
|
1911
1980
|
const packageRoot = resolvePackageRoot2(packageName);
|
|
1912
1981
|
logger.debug(`Resolved ui package root: ${packageRoot}`);
|
|
1913
1982
|
const manifest = await loadUiPackageManifest(packageRoot);
|
|
1983
|
+
const pkgJson = JSON.parse(
|
|
1984
|
+
await fs9.readFile(path10.join(packageRoot, "package.json"), "utf-8")
|
|
1985
|
+
);
|
|
1986
|
+
manifest.version = pkgJson.version;
|
|
1914
1987
|
let data = {};
|
|
1915
1988
|
const dataPath = path10.join(packageRoot, "_data.json");
|
|
1916
1989
|
try {
|
|
@@ -1984,8 +2057,14 @@ async function installUiEntries(options) {
|
|
|
1984
2057
|
const idToEntry = new Map(manifest.entries.map((e) => [e.id, e]));
|
|
1985
2058
|
const resources = [];
|
|
1986
2059
|
const npmDeps = {};
|
|
1987
|
-
let
|
|
2060
|
+
let created = 0;
|
|
2061
|
+
let overwritten = 0;
|
|
2062
|
+
let userModified = 0;
|
|
1988
2063
|
let skipped = 0;
|
|
2064
|
+
const { priorResources } = options;
|
|
2065
|
+
const priorByTarget = new Map(
|
|
2066
|
+
(priorResources ?? []).map((r) => [r.target, r])
|
|
2067
|
+
);
|
|
1989
2068
|
for (const id of orderedIds) {
|
|
1990
2069
|
const entry = idToEntry.get(id);
|
|
1991
2070
|
if (!entry) continue;
|
|
@@ -2019,11 +2098,25 @@ async function installUiEntries(options) {
|
|
|
2019
2098
|
});
|
|
2020
2099
|
continue;
|
|
2021
2100
|
}
|
|
2101
|
+
const relPath = path11.relative(projectRoot, targetAbs);
|
|
2102
|
+
const prior = priorByTarget.get(relPath);
|
|
2103
|
+
if (prior && prior.hash !== "sha256:legacy-unknown") {
|
|
2104
|
+
const onDiskHash = computeHash(current);
|
|
2105
|
+
if (onDiskHash !== prior.hash) {
|
|
2106
|
+
logger.warn(
|
|
2107
|
+
` \u26A0 ${relPath} has local modifications (backed up)`
|
|
2108
|
+
);
|
|
2109
|
+
userModified++;
|
|
2110
|
+
}
|
|
2111
|
+
}
|
|
2022
2112
|
await backupFile(targetAbs, projectRoot);
|
|
2113
|
+
overwritten++;
|
|
2114
|
+
logger.info(` overwrite: ${rel(projectRoot, targetAbs)}`);
|
|
2115
|
+
} else {
|
|
2116
|
+
created++;
|
|
2117
|
+
logger.info(` create: ${rel(projectRoot, targetAbs)}`);
|
|
2023
2118
|
}
|
|
2024
2119
|
await writeFileSafe(targetAbs, transformed);
|
|
2025
|
-
written++;
|
|
2026
|
-
logger.info(` write: ${rel(projectRoot, targetAbs)}`);
|
|
2027
2120
|
resources.push({
|
|
2028
2121
|
id: `${entry.id}:${file.targetName}`,
|
|
2029
2122
|
target: path11.relative(projectRoot, targetAbs),
|
|
@@ -2036,7 +2129,10 @@ async function installUiEntries(options) {
|
|
|
2036
2129
|
orderedIds,
|
|
2037
2130
|
resources,
|
|
2038
2131
|
npmDependencies: npmDeps,
|
|
2039
|
-
written,
|
|
2132
|
+
written: created + overwritten,
|
|
2133
|
+
created,
|
|
2134
|
+
overwritten,
|
|
2135
|
+
userModified,
|
|
2040
2136
|
skipped
|
|
2041
2137
|
};
|
|
2042
2138
|
}
|
|
@@ -2115,17 +2211,22 @@ async function runUiAdd(options) {
|
|
|
2115
2211
|
`Unknown entry id(s): ${unknown.map((s) => `"${s}"`).join(", ")}. Run \`teamix-evo ui list\` to see options.`
|
|
2116
2212
|
);
|
|
2117
2213
|
}
|
|
2214
|
+
const existingManifest = await readInstalledManifest(
|
|
2215
|
+
projectRoot
|
|
2216
|
+
) ?? { schemaVersion: 1, installed: [] };
|
|
2217
|
+
const priorPkg = existingManifest.installed.find(
|
|
2218
|
+
(p) => p.package === packageName
|
|
2219
|
+
);
|
|
2118
2220
|
const result = await installUiEntries({
|
|
2119
2221
|
projectRoot,
|
|
2120
2222
|
manifest: effectiveManifest,
|
|
2121
2223
|
packageRoot,
|
|
2122
2224
|
aliases: uiCfg.aliases,
|
|
2123
2225
|
requested: ids,
|
|
2124
|
-
skipExisting: !overwrite
|
|
2226
|
+
skipExisting: !overwrite,
|
|
2227
|
+
priorResources: priorPkg?.resources
|
|
2125
2228
|
});
|
|
2126
|
-
const installed =
|
|
2127
|
-
projectRoot
|
|
2128
|
-
) ?? { schemaVersion: 1, installed: [] };
|
|
2229
|
+
const installed = existingManifest;
|
|
2129
2230
|
const idx = installed.installed.findIndex((p) => p.package === packageName);
|
|
2130
2231
|
const prior = idx >= 0 ? installed.installed[idx] : null;
|
|
2131
2232
|
const mergedResources = mergeResources(
|
|
@@ -2150,6 +2251,9 @@ async function runUiAdd(options) {
|
|
|
2150
2251
|
packageName,
|
|
2151
2252
|
orderedIds: result.orderedIds,
|
|
2152
2253
|
written: result.written,
|
|
2254
|
+
created: result.created,
|
|
2255
|
+
overwritten: result.overwritten,
|
|
2256
|
+
userModified: result.userModified,
|
|
2153
2257
|
skipped: result.skipped,
|
|
2154
2258
|
npmDependencies: result.npmDependencies,
|
|
2155
2259
|
resources: result.resources
|
|
@@ -2199,6 +2303,7 @@ async function runUiList(options) {
|
|
|
2199
2303
|
|
|
2200
2304
|
// src/core/variant-ui-add.ts
|
|
2201
2305
|
import * as path12 from "path";
|
|
2306
|
+
import * as fs11 from "fs/promises";
|
|
2202
2307
|
import { createRequire as createRequire4 } from "module";
|
|
2203
2308
|
import {
|
|
2204
2309
|
loadUiPackageManifest as loadUiPackageManifest2,
|
|
@@ -2233,6 +2338,10 @@ async function runVariantUiAdd(packageName, options) {
|
|
|
2233
2338
|
}
|
|
2234
2339
|
const variantDir = path12.join(packageRoot, "variants", variant);
|
|
2235
2340
|
const variantManifest = await loadVariantUiPackageManifest(variantDir);
|
|
2341
|
+
const pkgJson = JSON.parse(
|
|
2342
|
+
await fs11.readFile(path12.join(packageRoot, "package.json"), "utf-8")
|
|
2343
|
+
);
|
|
2344
|
+
const packageVersion = pkgJson.version;
|
|
2236
2345
|
const knownIds = new Set(variantManifest.entries.map((e) => e.id));
|
|
2237
2346
|
const unknown = ids.filter((id) => !knownIds.has(id));
|
|
2238
2347
|
if (unknown.length > 0) {
|
|
@@ -2256,28 +2365,27 @@ async function runVariantUiAdd(packageName, options) {
|
|
|
2256
2365
|
const adaptedManifest = {
|
|
2257
2366
|
schemaVersion: 1,
|
|
2258
2367
|
package: "ui",
|
|
2259
|
-
version:
|
|
2368
|
+
version: packageVersion,
|
|
2260
2369
|
engines: variantManifest.engines,
|
|
2261
2370
|
entries: mergedEntries
|
|
2262
2371
|
};
|
|
2372
|
+
const installed = await readInstalledManifest(
|
|
2373
|
+
projectRoot
|
|
2374
|
+
) ?? { schemaVersion: 1, installed: [] };
|
|
2375
|
+
const idx = installed.installed.findIndex(
|
|
2376
|
+
(p) => p.package === fullPackageName && p.variant === variant
|
|
2377
|
+
);
|
|
2378
|
+
const prior = idx >= 0 ? installed.installed[idx] : null;
|
|
2263
2379
|
const result = await installUiEntries({
|
|
2264
2380
|
projectRoot,
|
|
2265
2381
|
manifest: adaptedManifest,
|
|
2266
2382
|
packageRoot: variantDir,
|
|
2267
|
-
// default for variant entries
|
|
2268
2383
|
entryPackageRoot,
|
|
2269
|
-
// ui entries resolve from uiPackageRoot
|
|
2270
2384
|
aliases: uiCfg.aliases,
|
|
2271
2385
|
requested: ids,
|
|
2272
|
-
skipExisting: !overwrite
|
|
2386
|
+
skipExisting: !overwrite,
|
|
2387
|
+
priorResources: prior?.resources
|
|
2273
2388
|
});
|
|
2274
|
-
const installed = await readInstalledManifest(
|
|
2275
|
-
projectRoot
|
|
2276
|
-
) ?? { schemaVersion: 1, installed: [] };
|
|
2277
|
-
const idx = installed.installed.findIndex(
|
|
2278
|
-
(p) => p.package === fullPackageName && p.variant === variant
|
|
2279
|
-
);
|
|
2280
|
-
const prior = idx >= 0 ? installed.installed[idx] : null;
|
|
2281
2389
|
const mergedResources = mergeResources2(
|
|
2282
2390
|
prior?.resources ?? [],
|
|
2283
2391
|
result.resources
|
|
@@ -2285,7 +2393,7 @@ async function runVariantUiAdd(packageName, options) {
|
|
|
2285
2393
|
const entry = {
|
|
2286
2394
|
package: fullPackageName,
|
|
2287
2395
|
variant,
|
|
2288
|
-
version:
|
|
2396
|
+
version: packageVersion,
|
|
2289
2397
|
installedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2290
2398
|
resources: mergedResources
|
|
2291
2399
|
};
|
|
@@ -2297,6 +2405,9 @@ async function runVariantUiAdd(packageName, options) {
|
|
|
2297
2405
|
variant,
|
|
2298
2406
|
orderedIds: result.orderedIds,
|
|
2299
2407
|
written: result.written,
|
|
2408
|
+
created: result.created,
|
|
2409
|
+
overwritten: result.overwritten,
|
|
2410
|
+
userModified: result.userModified,
|
|
2300
2411
|
skipped: result.skipped,
|
|
2301
2412
|
npmDependencies: result.npmDependencies,
|
|
2302
2413
|
resources: result.resources
|
|
@@ -2358,7 +2469,7 @@ async function listBizUiEntries(variant, packageRoot) {
|
|
|
2358
2469
|
|
|
2359
2470
|
// src/core/lint-init.ts
|
|
2360
2471
|
import * as path13 from "path";
|
|
2361
|
-
import * as
|
|
2472
|
+
import * as fs12 from "fs";
|
|
2362
2473
|
import { execa } from "execa";
|
|
2363
2474
|
var ESLINT_CONFIG_CONTENT = `/**
|
|
2364
2475
|
* teamix-evo consumer ESLint preset \u2014 9 token-discipline rules.
|
|
@@ -2450,7 +2561,7 @@ async function runLintInit(options) {
|
|
|
2450
2561
|
let stylelintIgnoreFilesWarning = false;
|
|
2451
2562
|
if (!stylelintNeedsWrite && stylelintTemplateExists) {
|
|
2452
2563
|
try {
|
|
2453
|
-
const existingContent =
|
|
2564
|
+
const existingContent = fs12.readFileSync(stylelintConfigPath, "utf-8");
|
|
2454
2565
|
const usesTeamixPreset = existingContent.includes("@teamix-evo/stylelint-config/presets/") || existingContent.includes("@teamix-evo/stylelint-config/preset/");
|
|
2455
2566
|
const hasTokenIgnore = existingContent.includes("tokens.theme.css") && existingContent.includes("tokens.overrides.css");
|
|
2456
2567
|
if (!usesTeamixPreset && !hasTokenIgnore) {
|
|
@@ -2487,8 +2598,8 @@ async function runLintInit(options) {
|
|
|
2487
2598
|
};
|
|
2488
2599
|
}
|
|
2489
2600
|
function detectPm(projectRoot) {
|
|
2490
|
-
if (
|
|
2491
|
-
if (
|
|
2601
|
+
if (fs12.existsSync(path13.join(projectRoot, "pnpm-lock.yaml"))) return "pnpm";
|
|
2602
|
+
if (fs12.existsSync(path13.join(projectRoot, "yarn.lock"))) return "yarn";
|
|
2492
2603
|
return "npm";
|
|
2493
2604
|
}
|
|
2494
2605
|
async function patchPackageJsonScripts(projectRoot) {
|
|
@@ -2521,7 +2632,7 @@ async function patchPackageJsonScripts(projectRoot) {
|
|
|
2521
2632
|
}
|
|
2522
2633
|
|
|
2523
2634
|
// src/core/init-detect.ts
|
|
2524
|
-
import * as
|
|
2635
|
+
import * as fs13 from "fs/promises";
|
|
2525
2636
|
import * as path14 from "path";
|
|
2526
2637
|
var IGNORED_TOP_LEVEL = /* @__PURE__ */ new Set([
|
|
2527
2638
|
".git",
|
|
@@ -2556,7 +2667,7 @@ async function detectProjectState(cwd) {
|
|
|
2556
2667
|
}
|
|
2557
2668
|
let entries;
|
|
2558
2669
|
try {
|
|
2559
|
-
entries = await
|
|
2670
|
+
entries = await fs13.readdir(absCwd);
|
|
2560
2671
|
} catch (err) {
|
|
2561
2672
|
if (err.code === "ENOENT") {
|
|
2562
2673
|
return {
|
|
@@ -2590,7 +2701,7 @@ async function detectProjectState(cwd) {
|
|
|
2590
2701
|
}
|
|
2591
2702
|
|
|
2592
2703
|
// src/core/project-state.ts
|
|
2593
|
-
import * as
|
|
2704
|
+
import * as fs14 from "fs/promises";
|
|
2594
2705
|
import * as path15 from "path";
|
|
2595
2706
|
var IGNORED_TOP_LEVEL2 = /* @__PURE__ */ new Set([
|
|
2596
2707
|
".git",
|
|
@@ -2650,7 +2761,7 @@ async function detectProjectState2(cwd) {
|
|
|
2650
2761
|
}
|
|
2651
2762
|
let entries;
|
|
2652
2763
|
try {
|
|
2653
|
-
entries = await
|
|
2764
|
+
entries = await fs14.readdir(absCwd);
|
|
2654
2765
|
} catch (err) {
|
|
2655
2766
|
if (err.code === "ENOENT") {
|
|
2656
2767
|
return {
|
|
@@ -2733,7 +2844,7 @@ function assertCommandPrecondition(command, state) {
|
|
|
2733
2844
|
|
|
2734
2845
|
// src/core/init-conflicts.ts
|
|
2735
2846
|
import * as crypto from "crypto";
|
|
2736
|
-
import * as
|
|
2847
|
+
import * as fs15 from "fs/promises";
|
|
2737
2848
|
import * as path16 from "path";
|
|
2738
2849
|
var TAILWIND_CONFIG_CANDIDATES = [
|
|
2739
2850
|
"tailwind.config.ts",
|
|
@@ -2778,7 +2889,7 @@ var STYLELINT_CONFIG_CANDIDATES = [
|
|
|
2778
2889
|
];
|
|
2779
2890
|
async function isDir(target) {
|
|
2780
2891
|
try {
|
|
2781
|
-
const stat3 = await
|
|
2892
|
+
const stat3 = await fs15.stat(target);
|
|
2782
2893
|
return stat3.isDirectory();
|
|
2783
2894
|
} catch {
|
|
2784
2895
|
return false;
|
|
@@ -2786,7 +2897,7 @@ async function isDir(target) {
|
|
|
2786
2897
|
}
|
|
2787
2898
|
async function dirHasContent(target) {
|
|
2788
2899
|
try {
|
|
2789
|
-
const entries = await
|
|
2900
|
+
const entries = await fs15.readdir(target);
|
|
2790
2901
|
return entries.length > 0;
|
|
2791
2902
|
} catch {
|
|
2792
2903
|
return false;
|
|
@@ -2927,7 +3038,7 @@ async function detectShadcnSource(cwd) {
|
|
|
2927
3038
|
try {
|
|
2928
3039
|
const uiDir = path16.join(cwd, "src/components/ui");
|
|
2929
3040
|
if (await isDir(uiDir)) {
|
|
2930
|
-
const entries = await
|
|
3041
|
+
const entries = await fs15.readdir(uiDir);
|
|
2931
3042
|
componentCount = entries.filter(
|
|
2932
3043
|
(e) => e.endsWith(".tsx") || e.endsWith(".ts")
|
|
2933
3044
|
).length;
|
|
@@ -3005,7 +3116,7 @@ async function detectStylelintConfig(cwd) {
|
|
|
3005
3116
|
|
|
3006
3117
|
// src/core/meta-installer.ts
|
|
3007
3118
|
import * as path17 from "path";
|
|
3008
|
-
import * as
|
|
3119
|
+
import * as fs16 from "fs/promises";
|
|
3009
3120
|
import { createRequire as createRequire5 } from "module";
|
|
3010
3121
|
import {
|
|
3011
3122
|
loadUiPackageManifest as loadUiPackageManifest3,
|
|
@@ -3049,7 +3160,7 @@ async function landManifestMeta(opts) {
|
|
|
3049
3160
|
await ensureDir(metaDir);
|
|
3050
3161
|
const manifestDest = path17.join(metaDir, "manifest.json");
|
|
3051
3162
|
const manifestSrc = path17.join(packageRoot, "manifest.json");
|
|
3052
|
-
await
|
|
3163
|
+
await fs16.copyFile(manifestSrc, manifestDest);
|
|
3053
3164
|
logger.debug(`meta: copied manifest.json \u2192 ${manifestDest}`);
|
|
3054
3165
|
let written = 0;
|
|
3055
3166
|
let total = 0;
|
|
@@ -3059,7 +3170,7 @@ async function landManifestMeta(opts) {
|
|
|
3059
3170
|
const srcPath = path17.join(packageRoot, entry.meta);
|
|
3060
3171
|
const destPath = path17.join(metaDir, `${entry.id}.md`);
|
|
3061
3172
|
try {
|
|
3062
|
-
await
|
|
3173
|
+
await fs16.copyFile(srcPath, destPath);
|
|
3063
3174
|
written++;
|
|
3064
3175
|
logger.debug(`meta: ${entry.id} \u2192 ${destPath}`);
|
|
3065
3176
|
} catch (err) {
|
|
@@ -3082,7 +3193,7 @@ async function landManifestMeta(opts) {
|
|
|
3082
3193
|
}
|
|
3083
3194
|
|
|
3084
3195
|
// src/core/deps-install.ts
|
|
3085
|
-
import * as
|
|
3196
|
+
import * as fs17 from "fs/promises";
|
|
3086
3197
|
import * as path18 from "path";
|
|
3087
3198
|
import { exec } from "child_process";
|
|
3088
3199
|
import { promisify } from "util";
|
|
@@ -3139,7 +3250,7 @@ async function installProjectDeps(options) {
|
|
|
3139
3250
|
pkg.dependencies = Object.fromEntries(
|
|
3140
3251
|
Object.entries(pkg.dependencies).sort(([a], [b]) => a.localeCompare(b))
|
|
3141
3252
|
);
|
|
3142
|
-
await
|
|
3253
|
+
await fs17.writeFile(pkgPath, JSON.stringify(pkg, null, 2) + "\n", "utf-8");
|
|
3143
3254
|
logger.info(
|
|
3144
3255
|
` patched package.json: +${Object.keys(added).length} dependencies`
|
|
3145
3256
|
);
|
|
@@ -3201,7 +3312,7 @@ ${stepLines}
|
|
|
3201
3312
|
}
|
|
3202
3313
|
|
|
3203
3314
|
// src/core/file-changes.ts
|
|
3204
|
-
import * as
|
|
3315
|
+
import * as fs18 from "fs/promises";
|
|
3205
3316
|
import * as path19 from "path";
|
|
3206
3317
|
function toRelativePosix(p, projectRoot) {
|
|
3207
3318
|
let rel2 = p;
|
|
@@ -3330,6 +3441,7 @@ async function runProjectInit(options) {
|
|
|
3330
3441
|
`teamix-evo-design-${variant}`,
|
|
3331
3442
|
`teamix-evo-code-${variant}`
|
|
3332
3443
|
],
|
|
3444
|
+
globalSkillIds: ["teamix-evo-manage"],
|
|
3333
3445
|
mode: "merge-managed"
|
|
3334
3446
|
});
|
|
3335
3447
|
record({
|
|
@@ -3660,7 +3772,7 @@ function deriveLintChanges(result) {
|
|
|
3660
3772
|
|
|
3661
3773
|
// src/core/installer.ts
|
|
3662
3774
|
import * as path21 from "path";
|
|
3663
|
-
import * as
|
|
3775
|
+
import * as fs19 from "fs/promises";
|
|
3664
3776
|
async function installResources(options) {
|
|
3665
3777
|
const { projectRoot, manifest, data, variantDir, packageRoot } = options;
|
|
3666
3778
|
const installedResources = [];
|
|
@@ -3703,7 +3815,7 @@ async function installSingleResource(resource, projectRoot, data, variantDir, pa
|
|
|
3703
3815
|
const templateContent = await loadTemplateFile(sourcePath);
|
|
3704
3816
|
content = renderTemplate(templateContent, data);
|
|
3705
3817
|
} else {
|
|
3706
|
-
content = await
|
|
3818
|
+
content = await fs19.readFile(sourcePath, "utf-8");
|
|
3707
3819
|
}
|
|
3708
3820
|
await writeFileSafe(targetPath, content);
|
|
3709
3821
|
const hash = computeHash(content);
|
|
@@ -3736,7 +3848,7 @@ async function installRecursiveResource(resource, projectRoot, data, variantDir,
|
|
|
3736
3848
|
const templateContent = await loadTemplateFile(entry);
|
|
3737
3849
|
content = renderTemplate(templateContent, data);
|
|
3738
3850
|
} else {
|
|
3739
|
-
content = await
|
|
3851
|
+
content = await fs19.readFile(entry, "utf-8");
|
|
3740
3852
|
}
|
|
3741
3853
|
await writeFileSafe(targetFile, content);
|
|
3742
3854
|
const hash = computeHash(content);
|
|
@@ -3754,7 +3866,7 @@ async function installRecursiveResource(resource, projectRoot, data, variantDir,
|
|
|
3754
3866
|
|
|
3755
3867
|
// src/core/registry-client.ts
|
|
3756
3868
|
import * as path22 from "path";
|
|
3757
|
-
import * as
|
|
3869
|
+
import * as fs20 from "fs/promises";
|
|
3758
3870
|
import { createRequire as createRequire6 } from "module";
|
|
3759
3871
|
import { loadVariantManifest } from "@teamix-evo/registry";
|
|
3760
3872
|
var require7 = createRequire6(import.meta.url);
|
|
@@ -3771,7 +3883,7 @@ async function loadVariantData(packageName, variant) {
|
|
|
3771
3883
|
let data = {};
|
|
3772
3884
|
const dataPath = path22.join(variantDir, "_data.json");
|
|
3773
3885
|
try {
|
|
3774
|
-
const raw = await
|
|
3886
|
+
const raw = await fs20.readFile(dataPath, "utf-8");
|
|
3775
3887
|
data = JSON.parse(raw);
|
|
3776
3888
|
} catch (err) {
|
|
3777
3889
|
if (err.code !== "ENOENT") {
|