teamix-evo 0.14.1 → 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.
@@ -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,7 +2393,7 @@ 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
  };
@@ -2446,7 +2469,7 @@ async function listBizUiEntries(variant, packageRoot) {
2446
2469
 
2447
2470
  // src/core/lint-init.ts
2448
2471
  import * as path13 from "path";
2449
- import * as fs11 from "fs";
2472
+ import * as fs12 from "fs";
2450
2473
  import { execa } from "execa";
2451
2474
  var ESLINT_CONFIG_CONTENT = `/**
2452
2475
  * teamix-evo consumer ESLint preset \u2014 9 token-discipline rules.
@@ -2538,7 +2561,7 @@ async function runLintInit(options) {
2538
2561
  let stylelintIgnoreFilesWarning = false;
2539
2562
  if (!stylelintNeedsWrite && stylelintTemplateExists) {
2540
2563
  try {
2541
- const existingContent = fs11.readFileSync(stylelintConfigPath, "utf-8");
2564
+ const existingContent = fs12.readFileSync(stylelintConfigPath, "utf-8");
2542
2565
  const usesTeamixPreset = existingContent.includes("@teamix-evo/stylelint-config/presets/") || existingContent.includes("@teamix-evo/stylelint-config/preset/");
2543
2566
  const hasTokenIgnore = existingContent.includes("tokens.theme.css") && existingContent.includes("tokens.overrides.css");
2544
2567
  if (!usesTeamixPreset && !hasTokenIgnore) {
@@ -2575,8 +2598,8 @@ async function runLintInit(options) {
2575
2598
  };
2576
2599
  }
2577
2600
  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";
2601
+ if (fs12.existsSync(path13.join(projectRoot, "pnpm-lock.yaml"))) return "pnpm";
2602
+ if (fs12.existsSync(path13.join(projectRoot, "yarn.lock"))) return "yarn";
2580
2603
  return "npm";
2581
2604
  }
2582
2605
  async function patchPackageJsonScripts(projectRoot) {
@@ -2609,7 +2632,7 @@ async function patchPackageJsonScripts(projectRoot) {
2609
2632
  }
2610
2633
 
2611
2634
  // src/core/init-detect.ts
2612
- import * as fs12 from "fs/promises";
2635
+ import * as fs13 from "fs/promises";
2613
2636
  import * as path14 from "path";
2614
2637
  var IGNORED_TOP_LEVEL = /* @__PURE__ */ new Set([
2615
2638
  ".git",
@@ -2644,7 +2667,7 @@ async function detectProjectState(cwd) {
2644
2667
  }
2645
2668
  let entries;
2646
2669
  try {
2647
- entries = await fs12.readdir(absCwd);
2670
+ entries = await fs13.readdir(absCwd);
2648
2671
  } catch (err) {
2649
2672
  if (err.code === "ENOENT") {
2650
2673
  return {
@@ -2678,7 +2701,7 @@ async function detectProjectState(cwd) {
2678
2701
  }
2679
2702
 
2680
2703
  // src/core/project-state.ts
2681
- import * as fs13 from "fs/promises";
2704
+ import * as fs14 from "fs/promises";
2682
2705
  import * as path15 from "path";
2683
2706
  var IGNORED_TOP_LEVEL2 = /* @__PURE__ */ new Set([
2684
2707
  ".git",
@@ -2738,7 +2761,7 @@ async function detectProjectState2(cwd) {
2738
2761
  }
2739
2762
  let entries;
2740
2763
  try {
2741
- entries = await fs13.readdir(absCwd);
2764
+ entries = await fs14.readdir(absCwd);
2742
2765
  } catch (err) {
2743
2766
  if (err.code === "ENOENT") {
2744
2767
  return {
@@ -2821,7 +2844,7 @@ function assertCommandPrecondition(command, state) {
2821
2844
 
2822
2845
  // src/core/init-conflicts.ts
2823
2846
  import * as crypto from "crypto";
2824
- import * as fs14 from "fs/promises";
2847
+ import * as fs15 from "fs/promises";
2825
2848
  import * as path16 from "path";
2826
2849
  var TAILWIND_CONFIG_CANDIDATES = [
2827
2850
  "tailwind.config.ts",
@@ -2866,7 +2889,7 @@ var STYLELINT_CONFIG_CANDIDATES = [
2866
2889
  ];
2867
2890
  async function isDir(target) {
2868
2891
  try {
2869
- const stat3 = await fs14.stat(target);
2892
+ const stat3 = await fs15.stat(target);
2870
2893
  return stat3.isDirectory();
2871
2894
  } catch {
2872
2895
  return false;
@@ -2874,7 +2897,7 @@ async function isDir(target) {
2874
2897
  }
2875
2898
  async function dirHasContent(target) {
2876
2899
  try {
2877
- const entries = await fs14.readdir(target);
2900
+ const entries = await fs15.readdir(target);
2878
2901
  return entries.length > 0;
2879
2902
  } catch {
2880
2903
  return false;
@@ -3015,7 +3038,7 @@ async function detectShadcnSource(cwd) {
3015
3038
  try {
3016
3039
  const uiDir = path16.join(cwd, "src/components/ui");
3017
3040
  if (await isDir(uiDir)) {
3018
- const entries = await fs14.readdir(uiDir);
3041
+ const entries = await fs15.readdir(uiDir);
3019
3042
  componentCount = entries.filter(
3020
3043
  (e) => e.endsWith(".tsx") || e.endsWith(".ts")
3021
3044
  ).length;
@@ -3093,7 +3116,7 @@ async function detectStylelintConfig(cwd) {
3093
3116
 
3094
3117
  // src/core/meta-installer.ts
3095
3118
  import * as path17 from "path";
3096
- import * as fs15 from "fs/promises";
3119
+ import * as fs16 from "fs/promises";
3097
3120
  import { createRequire as createRequire5 } from "module";
3098
3121
  import {
3099
3122
  loadUiPackageManifest as loadUiPackageManifest3,
@@ -3137,7 +3160,7 @@ async function landManifestMeta(opts) {
3137
3160
  await ensureDir(metaDir);
3138
3161
  const manifestDest = path17.join(metaDir, "manifest.json");
3139
3162
  const manifestSrc = path17.join(packageRoot, "manifest.json");
3140
- await fs15.copyFile(manifestSrc, manifestDest);
3163
+ await fs16.copyFile(manifestSrc, manifestDest);
3141
3164
  logger.debug(`meta: copied manifest.json \u2192 ${manifestDest}`);
3142
3165
  let written = 0;
3143
3166
  let total = 0;
@@ -3147,7 +3170,7 @@ async function landManifestMeta(opts) {
3147
3170
  const srcPath = path17.join(packageRoot, entry.meta);
3148
3171
  const destPath = path17.join(metaDir, `${entry.id}.md`);
3149
3172
  try {
3150
- await fs15.copyFile(srcPath, destPath);
3173
+ await fs16.copyFile(srcPath, destPath);
3151
3174
  written++;
3152
3175
  logger.debug(`meta: ${entry.id} \u2192 ${destPath}`);
3153
3176
  } catch (err) {
@@ -3170,7 +3193,7 @@ async function landManifestMeta(opts) {
3170
3193
  }
3171
3194
 
3172
3195
  // src/core/deps-install.ts
3173
- import * as fs16 from "fs/promises";
3196
+ import * as fs17 from "fs/promises";
3174
3197
  import * as path18 from "path";
3175
3198
  import { exec } from "child_process";
3176
3199
  import { promisify } from "util";
@@ -3227,7 +3250,7 @@ async function installProjectDeps(options) {
3227
3250
  pkg.dependencies = Object.fromEntries(
3228
3251
  Object.entries(pkg.dependencies).sort(([a], [b]) => a.localeCompare(b))
3229
3252
  );
3230
- await fs16.writeFile(pkgPath, JSON.stringify(pkg, null, 2) + "\n", "utf-8");
3253
+ await fs17.writeFile(pkgPath, JSON.stringify(pkg, null, 2) + "\n", "utf-8");
3231
3254
  logger.info(
3232
3255
  ` patched package.json: +${Object.keys(added).length} dependencies`
3233
3256
  );
@@ -3289,7 +3312,7 @@ ${stepLines}
3289
3312
  }
3290
3313
 
3291
3314
  // src/core/file-changes.ts
3292
- import * as fs17 from "fs/promises";
3315
+ import * as fs18 from "fs/promises";
3293
3316
  import * as path19 from "path";
3294
3317
  function toRelativePosix(p, projectRoot) {
3295
3318
  let rel2 = p;
@@ -3418,6 +3441,7 @@ async function runProjectInit(options) {
3418
3441
  `teamix-evo-design-${variant}`,
3419
3442
  `teamix-evo-code-${variant}`
3420
3443
  ],
3444
+ globalSkillIds: ["teamix-evo-manage"],
3421
3445
  mode: "merge-managed"
3422
3446
  });
3423
3447
  record({
@@ -3748,7 +3772,7 @@ function deriveLintChanges(result) {
3748
3772
 
3749
3773
  // src/core/installer.ts
3750
3774
  import * as path21 from "path";
3751
- import * as fs18 from "fs/promises";
3775
+ import * as fs19 from "fs/promises";
3752
3776
  async function installResources(options) {
3753
3777
  const { projectRoot, manifest, data, variantDir, packageRoot } = options;
3754
3778
  const installedResources = [];
@@ -3791,7 +3815,7 @@ async function installSingleResource(resource, projectRoot, data, variantDir, pa
3791
3815
  const templateContent = await loadTemplateFile(sourcePath);
3792
3816
  content = renderTemplate(templateContent, data);
3793
3817
  } else {
3794
- content = await fs18.readFile(sourcePath, "utf-8");
3818
+ content = await fs19.readFile(sourcePath, "utf-8");
3795
3819
  }
3796
3820
  await writeFileSafe(targetPath, content);
3797
3821
  const hash = computeHash(content);
@@ -3824,7 +3848,7 @@ async function installRecursiveResource(resource, projectRoot, data, variantDir,
3824
3848
  const templateContent = await loadTemplateFile(entry);
3825
3849
  content = renderTemplate(templateContent, data);
3826
3850
  } else {
3827
- content = await fs18.readFile(entry, "utf-8");
3851
+ content = await fs19.readFile(entry, "utf-8");
3828
3852
  }
3829
3853
  await writeFileSafe(targetFile, content);
3830
3854
  const hash = computeHash(content);
@@ -3842,7 +3866,7 @@ async function installRecursiveResource(resource, projectRoot, data, variantDir,
3842
3866
 
3843
3867
  // src/core/registry-client.ts
3844
3868
  import * as path22 from "path";
3845
- import * as fs19 from "fs/promises";
3869
+ import * as fs20 from "fs/promises";
3846
3870
  import { createRequire as createRequire6 } from "module";
3847
3871
  import { loadVariantManifest } from "@teamix-evo/registry";
3848
3872
  var require7 = createRequire6(import.meta.url);
@@ -3859,7 +3883,7 @@ async function loadVariantData(packageName, variant) {
3859
3883
  let data = {};
3860
3884
  const dataPath = path22.join(variantDir, "_data.json");
3861
3885
  try {
3862
- const raw = await fs19.readFile(dataPath, "utf-8");
3886
+ const raw = await fs20.readFile(dataPath, "utf-8");
3863
3887
  data = JSON.parse(raw);
3864
3888
  } catch (err) {
3865
3889
  if (err.code !== "ENOENT") {