teamix-evo 0.14.1 → 0.14.3

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.
@@ -509,9 +509,14 @@ declare function runLintInit(options: RunLintInitOptions): Promise<RunLintInitRe
509
509
  * skill activation conditions even when the user prompt does not directly
510
510
  * hit the description-based trigger.
511
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
+ *
512
518
  * Out of scope (per ADR 0038):
513
519
  * - Does NOT copy skill body / rules / patterns — those stay in the skill.
514
- * - Does NOT include `teamix-evo-manage` (entry skill, global scope, ADR 0033).
515
520
  *
516
521
  * Lifted from `create-teamix-evo` (v0.5) into `teamix-evo/core` so both
517
522
  * `npm create teamix-evo` (scaffold path) and `teamix-evo init` (existing-
@@ -524,11 +529,14 @@ interface RunGenerateAgentsMdOptions {
524
529
  projectRoot: string;
525
530
  /** Tokens / skills variant (e.g. "opentrek"). Used for header context. */
526
531
  variant: string;
532
+ /** Project-scope skill ids to index. */
533
+ skillIds: string[];
527
534
  /**
528
- * Skill ids to index. Caller is responsible for filtering out global-only
529
- * skills (e.g. `teamix-evo-manage`).
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.
530
538
  */
531
- skillIds: string[];
539
+ globalSkillIds?: string[];
532
540
  /**
533
541
  * Reconciliation mode (Phase 2.B):
534
542
  * - `'overwrite'` (default): always rewrite the full file. Pre-existing
@@ -1463,18 +1463,24 @@ import { hasManagedRegion as hasManagedRegion2, replaceManagedRegion as replaceM
1463
1463
  var AGENTS_MD_MANAGED_ID = "teamix-evo-skills";
1464
1464
  async function runGenerateAgentsMd(options) {
1465
1465
  const { projectRoot, variant, skillIds } = options;
1466
+ const globalSkillIds = options.globalSkillIds ?? [];
1466
1467
  const mode = options.mode ?? "overwrite";
1467
1468
  const config = await readProjectConfig(projectRoot);
1468
1469
  const lock = await readSkillsLock(projectRoot);
1469
1470
  const ides = config?.packages?.skills?.ides ?? ["qoder", "claude"];
1470
1471
  const scope = config?.packages?.skills?.scope ?? lock?.skills[skillIds[0] ?? ""]?.scope ?? "project";
1471
- const ordered = [...skillIds].sort(
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(
1472
1477
  (a, b) => bucketRank(a) - bucketRank(b) || a.localeCompare(b)
1473
1478
  );
1474
1479
  const sections = [];
1475
1480
  const missingSkillIds = [];
1476
1481
  for (const id of ordered) {
1477
- const { section, missing } = await renderSkillSection(projectRoot, id, ides, scope);
1482
+ const skillScope = skillScopeMap.get(id) ?? scope;
1483
+ const { section, missing } = await renderSkillSection(projectRoot, id, ides, skillScope);
1478
1484
  sections.push(section);
1479
1485
  if (missing) missingSkillIds.push(id);
1480
1486
  }
@@ -1558,6 +1564,12 @@ async function renderSkillSection(projectRoot, skillId, ides, scope) {
1558
1564
  if (parts?.coordinates) {
1559
1565
  lines.push(`- **Coordinates with**: ${parts.coordinates}`);
1560
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
+ }
1561
1573
  return { section: lines.join("\n"), missing };
1562
1574
  }
1563
1575
  function renderAgentsMd(args) {
@@ -1873,10 +1885,12 @@ async function runSkillsUpdate(options) {
1873
1885
  const variant = await readTokensVariant(projectRoot);
1874
1886
  if (variant) {
1875
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);
1876
1889
  await runGenerateAgentsMd({
1877
1890
  projectRoot,
1878
1891
  variant,
1879
1892
  skillIds: projectSkillIds,
1893
+ globalSkillIds,
1880
1894
  mode: "merge-managed"
1881
1895
  });
1882
1896
  }
@@ -1966,6 +1980,10 @@ async function loadUiData(packageName) {
1966
1980
  const packageRoot = resolvePackageRoot2(packageName);
1967
1981
  logger.debug(`Resolved ui package root: ${packageRoot}`);
1968
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;
1969
1987
  let data = {};
1970
1988
  const dataPath = path10.join(packageRoot, "_data.json");
1971
1989
  try {
@@ -2285,6 +2303,7 @@ async function runUiList(options) {
2285
2303
 
2286
2304
  // src/core/variant-ui-add.ts
2287
2305
  import * as path12 from "path";
2306
+ import * as fs11 from "fs/promises";
2288
2307
  import { createRequire as createRequire4 } from "module";
2289
2308
  import {
2290
2309
  loadUiPackageManifest as loadUiPackageManifest2,
@@ -2319,6 +2338,10 @@ async function runVariantUiAdd(packageName, options) {
2319
2338
  }
2320
2339
  const variantDir = path12.join(packageRoot, "variants", variant);
2321
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;
2322
2345
  const knownIds = new Set(variantManifest.entries.map((e) => e.id));
2323
2346
  const unknown = ids.filter((id) => !knownIds.has(id));
2324
2347
  if (unknown.length > 0) {
@@ -2342,7 +2365,7 @@ async function runVariantUiAdd(packageName, options) {
2342
2365
  const adaptedManifest = {
2343
2366
  schemaVersion: 1,
2344
2367
  package: "ui",
2345
- version: variantManifest.version,
2368
+ version: packageVersion,
2346
2369
  engines: variantManifest.engines,
2347
2370
  entries: mergedEntries
2348
2371
  };
@@ -2370,13 +2393,19 @@ async function runVariantUiAdd(packageName, options) {
2370
2393
  const entry = {
2371
2394
  package: fullPackageName,
2372
2395
  variant,
2373
- version: variantManifest.version,
2396
+ version: packageVersion,
2374
2397
  installedAt: (/* @__PURE__ */ new Date()).toISOString(),
2375
2398
  resources: mergedResources
2376
2399
  };
2377
2400
  if (idx >= 0) installed.installed[idx] = entry;
2378
2401
  else installed.installed.push(entry);
2379
2402
  await writeInstalledManifest(projectRoot, installed);
2403
+ config.packages[packageName] = {
2404
+ ...config.packages[packageName] ?? {},
2405
+ variant,
2406
+ version: packageVersion
2407
+ };
2408
+ await writeProjectConfig(projectRoot, config);
2380
2409
  return {
2381
2410
  packageName: fullPackageName,
2382
2411
  variant,
@@ -2446,7 +2475,7 @@ async function listBizUiEntries(variant, packageRoot) {
2446
2475
 
2447
2476
  // src/core/lint-init.ts
2448
2477
  import * as path13 from "path";
2449
- import * as fs11 from "fs";
2478
+ import * as fs12 from "fs";
2450
2479
  import { execa } from "execa";
2451
2480
  var ESLINT_CONFIG_CONTENT = `/**
2452
2481
  * teamix-evo consumer ESLint preset \u2014 9 token-discipline rules.
@@ -2538,7 +2567,7 @@ async function runLintInit(options) {
2538
2567
  let stylelintIgnoreFilesWarning = false;
2539
2568
  if (!stylelintNeedsWrite && stylelintTemplateExists) {
2540
2569
  try {
2541
- const existingContent = fs11.readFileSync(stylelintConfigPath, "utf-8");
2570
+ const existingContent = fs12.readFileSync(stylelintConfigPath, "utf-8");
2542
2571
  const usesTeamixPreset = existingContent.includes("@teamix-evo/stylelint-config/presets/") || existingContent.includes("@teamix-evo/stylelint-config/preset/");
2543
2572
  const hasTokenIgnore = existingContent.includes("tokens.theme.css") && existingContent.includes("tokens.overrides.css");
2544
2573
  if (!usesTeamixPreset && !hasTokenIgnore) {
@@ -2575,8 +2604,8 @@ async function runLintInit(options) {
2575
2604
  };
2576
2605
  }
2577
2606
  function detectPm(projectRoot) {
2578
- if (fs11.existsSync(path13.join(projectRoot, "pnpm-lock.yaml"))) return "pnpm";
2579
- if (fs11.existsSync(path13.join(projectRoot, "yarn.lock"))) return "yarn";
2607
+ if (fs12.existsSync(path13.join(projectRoot, "pnpm-lock.yaml"))) return "pnpm";
2608
+ if (fs12.existsSync(path13.join(projectRoot, "yarn.lock"))) return "yarn";
2580
2609
  return "npm";
2581
2610
  }
2582
2611
  async function patchPackageJsonScripts(projectRoot) {
@@ -2609,7 +2638,7 @@ async function patchPackageJsonScripts(projectRoot) {
2609
2638
  }
2610
2639
 
2611
2640
  // src/core/init-detect.ts
2612
- import * as fs12 from "fs/promises";
2641
+ import * as fs13 from "fs/promises";
2613
2642
  import * as path14 from "path";
2614
2643
  var IGNORED_TOP_LEVEL = /* @__PURE__ */ new Set([
2615
2644
  ".git",
@@ -2644,7 +2673,7 @@ async function detectProjectState(cwd) {
2644
2673
  }
2645
2674
  let entries;
2646
2675
  try {
2647
- entries = await fs12.readdir(absCwd);
2676
+ entries = await fs13.readdir(absCwd);
2648
2677
  } catch (err) {
2649
2678
  if (err.code === "ENOENT") {
2650
2679
  return {
@@ -2678,7 +2707,7 @@ async function detectProjectState(cwd) {
2678
2707
  }
2679
2708
 
2680
2709
  // src/core/project-state.ts
2681
- import * as fs13 from "fs/promises";
2710
+ import * as fs14 from "fs/promises";
2682
2711
  import * as path15 from "path";
2683
2712
  var IGNORED_TOP_LEVEL2 = /* @__PURE__ */ new Set([
2684
2713
  ".git",
@@ -2738,7 +2767,7 @@ async function detectProjectState2(cwd) {
2738
2767
  }
2739
2768
  let entries;
2740
2769
  try {
2741
- entries = await fs13.readdir(absCwd);
2770
+ entries = await fs14.readdir(absCwd);
2742
2771
  } catch (err) {
2743
2772
  if (err.code === "ENOENT") {
2744
2773
  return {
@@ -2821,7 +2850,7 @@ function assertCommandPrecondition(command, state) {
2821
2850
 
2822
2851
  // src/core/init-conflicts.ts
2823
2852
  import * as crypto from "crypto";
2824
- import * as fs14 from "fs/promises";
2853
+ import * as fs15 from "fs/promises";
2825
2854
  import * as path16 from "path";
2826
2855
  var TAILWIND_CONFIG_CANDIDATES = [
2827
2856
  "tailwind.config.ts",
@@ -2866,7 +2895,7 @@ var STYLELINT_CONFIG_CANDIDATES = [
2866
2895
  ];
2867
2896
  async function isDir(target) {
2868
2897
  try {
2869
- const stat3 = await fs14.stat(target);
2898
+ const stat3 = await fs15.stat(target);
2870
2899
  return stat3.isDirectory();
2871
2900
  } catch {
2872
2901
  return false;
@@ -2874,7 +2903,7 @@ async function isDir(target) {
2874
2903
  }
2875
2904
  async function dirHasContent(target) {
2876
2905
  try {
2877
- const entries = await fs14.readdir(target);
2906
+ const entries = await fs15.readdir(target);
2878
2907
  return entries.length > 0;
2879
2908
  } catch {
2880
2909
  return false;
@@ -3015,7 +3044,7 @@ async function detectShadcnSource(cwd) {
3015
3044
  try {
3016
3045
  const uiDir = path16.join(cwd, "src/components/ui");
3017
3046
  if (await isDir(uiDir)) {
3018
- const entries = await fs14.readdir(uiDir);
3047
+ const entries = await fs15.readdir(uiDir);
3019
3048
  componentCount = entries.filter(
3020
3049
  (e) => e.endsWith(".tsx") || e.endsWith(".ts")
3021
3050
  ).length;
@@ -3093,7 +3122,7 @@ async function detectStylelintConfig(cwd) {
3093
3122
 
3094
3123
  // src/core/meta-installer.ts
3095
3124
  import * as path17 from "path";
3096
- import * as fs15 from "fs/promises";
3125
+ import * as fs16 from "fs/promises";
3097
3126
  import { createRequire as createRequire5 } from "module";
3098
3127
  import {
3099
3128
  loadUiPackageManifest as loadUiPackageManifest3,
@@ -3137,7 +3166,7 @@ async function landManifestMeta(opts) {
3137
3166
  await ensureDir(metaDir);
3138
3167
  const manifestDest = path17.join(metaDir, "manifest.json");
3139
3168
  const manifestSrc = path17.join(packageRoot, "manifest.json");
3140
- await fs15.copyFile(manifestSrc, manifestDest);
3169
+ await fs16.copyFile(manifestSrc, manifestDest);
3141
3170
  logger.debug(`meta: copied manifest.json \u2192 ${manifestDest}`);
3142
3171
  let written = 0;
3143
3172
  let total = 0;
@@ -3147,7 +3176,7 @@ async function landManifestMeta(opts) {
3147
3176
  const srcPath = path17.join(packageRoot, entry.meta);
3148
3177
  const destPath = path17.join(metaDir, `${entry.id}.md`);
3149
3178
  try {
3150
- await fs15.copyFile(srcPath, destPath);
3179
+ await fs16.copyFile(srcPath, destPath);
3151
3180
  written++;
3152
3181
  logger.debug(`meta: ${entry.id} \u2192 ${destPath}`);
3153
3182
  } catch (err) {
@@ -3170,7 +3199,7 @@ async function landManifestMeta(opts) {
3170
3199
  }
3171
3200
 
3172
3201
  // src/core/deps-install.ts
3173
- import * as fs16 from "fs/promises";
3202
+ import * as fs17 from "fs/promises";
3174
3203
  import * as path18 from "path";
3175
3204
  import { exec } from "child_process";
3176
3205
  import { promisify } from "util";
@@ -3227,7 +3256,7 @@ async function installProjectDeps(options) {
3227
3256
  pkg.dependencies = Object.fromEntries(
3228
3257
  Object.entries(pkg.dependencies).sort(([a], [b]) => a.localeCompare(b))
3229
3258
  );
3230
- await fs16.writeFile(pkgPath, JSON.stringify(pkg, null, 2) + "\n", "utf-8");
3259
+ await fs17.writeFile(pkgPath, JSON.stringify(pkg, null, 2) + "\n", "utf-8");
3231
3260
  logger.info(
3232
3261
  ` patched package.json: +${Object.keys(added).length} dependencies`
3233
3262
  );
@@ -3289,7 +3318,7 @@ ${stepLines}
3289
3318
  }
3290
3319
 
3291
3320
  // src/core/file-changes.ts
3292
- import * as fs17 from "fs/promises";
3321
+ import * as fs18 from "fs/promises";
3293
3322
  import * as path19 from "path";
3294
3323
  function toRelativePosix(p, projectRoot) {
3295
3324
  let rel2 = p;
@@ -3418,6 +3447,7 @@ async function runProjectInit(options) {
3418
3447
  `teamix-evo-design-${variant}`,
3419
3448
  `teamix-evo-code-${variant}`
3420
3449
  ],
3450
+ globalSkillIds: ["teamix-evo-manage"],
3421
3451
  mode: "merge-managed"
3422
3452
  });
3423
3453
  record({
@@ -3748,7 +3778,7 @@ function deriveLintChanges(result) {
3748
3778
 
3749
3779
  // src/core/installer.ts
3750
3780
  import * as path21 from "path";
3751
- import * as fs18 from "fs/promises";
3781
+ import * as fs19 from "fs/promises";
3752
3782
  async function installResources(options) {
3753
3783
  const { projectRoot, manifest, data, variantDir, packageRoot } = options;
3754
3784
  const installedResources = [];
@@ -3791,7 +3821,7 @@ async function installSingleResource(resource, projectRoot, data, variantDir, pa
3791
3821
  const templateContent = await loadTemplateFile(sourcePath);
3792
3822
  content = renderTemplate(templateContent, data);
3793
3823
  } else {
3794
- content = await fs18.readFile(sourcePath, "utf-8");
3824
+ content = await fs19.readFile(sourcePath, "utf-8");
3795
3825
  }
3796
3826
  await writeFileSafe(targetPath, content);
3797
3827
  const hash = computeHash(content);
@@ -3824,7 +3854,7 @@ async function installRecursiveResource(resource, projectRoot, data, variantDir,
3824
3854
  const templateContent = await loadTemplateFile(entry);
3825
3855
  content = renderTemplate(templateContent, data);
3826
3856
  } else {
3827
- content = await fs18.readFile(entry, "utf-8");
3857
+ content = await fs19.readFile(entry, "utf-8");
3828
3858
  }
3829
3859
  await writeFileSafe(targetFile, content);
3830
3860
  const hash = computeHash(content);
@@ -3842,7 +3872,7 @@ async function installRecursiveResource(resource, projectRoot, data, variantDir,
3842
3872
 
3843
3873
  // src/core/registry-client.ts
3844
3874
  import * as path22 from "path";
3845
- import * as fs19 from "fs/promises";
3875
+ import * as fs20 from "fs/promises";
3846
3876
  import { createRequire as createRequire6 } from "module";
3847
3877
  import { loadVariantManifest } from "@teamix-evo/registry";
3848
3878
  var require7 = createRequire6(import.meta.url);
@@ -3859,7 +3889,7 @@ async function loadVariantData(packageName, variant) {
3859
3889
  let data = {};
3860
3890
  const dataPath = path22.join(variantDir, "_data.json");
3861
3891
  try {
3862
- const raw = await fs19.readFile(dataPath, "utf-8");
3892
+ const raw = await fs20.readFile(dataPath, "utf-8");
3863
3893
  data = JSON.parse(raw);
3864
3894
  } catch (err) {
3865
3895
  if (err.code !== "ENOENT") {