teamix-evo 0.15.5 → 0.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -729,7 +729,7 @@ interface FileChange {
729
729
  * true, it skips conflict detection entirely.
730
730
  */
731
731
 
732
- type ProjectInitStepName = 'tokens' | 'skills' | 'agents-md' | 'ui-init' | 'ui-add' | 'biz-ui-add' | 'meta-landing' | 'lint' | 'gitignore';
732
+ type ProjectInitStepName = 'tokens' | 'html-theme' | 'skills' | 'agents-md' | 'ui-init' | 'ui-add' | 'biz-ui-add' | 'meta-landing' | 'lint' | 'gitignore';
733
733
  type ProjectInitStepStatus = 'ok' | 'skip' | 'fail' | 'planned';
734
734
  interface ProjectInitStep {
735
735
  name: ProjectInitStepName;
@@ -3117,8 +3117,30 @@ async function detectStylelintConfig(cwd) {
3117
3117
  };
3118
3118
  }
3119
3119
 
3120
- // src/core/meta-installer.ts
3120
+ // src/core/html-theme-patch.ts
3121
3121
  import * as path17 from "path";
3122
+ async function patchHtmlDataTheme(projectRoot, variant) {
3123
+ const htmlPath = path17.join(projectRoot, "index.html");
3124
+ const content = await readFileOrNull(htmlPath);
3125
+ if (content === null) {
3126
+ return { status: "not-found", htmlPath };
3127
+ }
3128
+ if (/data-theme\s*=/.test(content)) {
3129
+ return { status: "already-set", htmlPath };
3130
+ }
3131
+ const patched = content.replace(
3132
+ /<html([^>]*)>/,
3133
+ `<html$1 data-theme="${variant}">`
3134
+ );
3135
+ if (patched === content) {
3136
+ return { status: "not-found", htmlPath };
3137
+ }
3138
+ await writeFileSafe(htmlPath, patched);
3139
+ return { status: "patched", htmlPath };
3140
+ }
3141
+
3142
+ // src/core/meta-installer.ts
3143
+ import * as path18 from "path";
3122
3144
  import * as fs16 from "fs/promises";
3123
3145
  import { createRequire as createRequire5 } from "module";
3124
3146
  import {
@@ -3129,11 +3151,11 @@ var require6 = createRequire5(import.meta.url);
3129
3151
  var META_DIR = "meta";
3130
3152
  function resolvePackageRoot4(packageName) {
3131
3153
  const pkgJsonPath = require6.resolve(`${packageName}/package.json`);
3132
- return path17.dirname(pkgJsonPath);
3154
+ return path18.dirname(pkgJsonPath);
3133
3155
  }
3134
3156
  function getMetaDir(projectRoot, category) {
3135
- const base = path17.join(getTeamixDir(projectRoot), META_DIR);
3136
- return category ? path17.join(base, category) : base;
3157
+ const base = path18.join(getTeamixDir(projectRoot), META_DIR);
3158
+ return category ? path18.join(base, category) : base;
3137
3159
  }
3138
3160
  async function landUiMeta(projectRoot) {
3139
3161
  const packageRoot = resolvePackageRoot4("@teamix-evo/ui");
@@ -3147,7 +3169,7 @@ async function landUiMeta(projectRoot) {
3147
3169
  }
3148
3170
  async function landBizUiMeta(projectRoot, variant) {
3149
3171
  const packageRoot = resolvePackageRoot4("@teamix-evo/biz-ui");
3150
- const variantRoot = path17.join(packageRoot, "variants", variant);
3172
+ const variantRoot = path18.join(packageRoot, "variants", variant);
3151
3173
  const manifest = await loadVariantUiPackageManifest2(variantRoot);
3152
3174
  return landManifestMeta({
3153
3175
  projectRoot,
@@ -3161,8 +3183,8 @@ async function landManifestMeta(opts) {
3161
3183
  await ensureTeamixDir(projectRoot);
3162
3184
  const metaDir = getMetaDir(projectRoot, category);
3163
3185
  await ensureDir(metaDir);
3164
- const manifestDest = path17.join(metaDir, "manifest.json");
3165
- const manifestSrc = path17.join(packageRoot, "manifest.json");
3186
+ const manifestDest = path18.join(metaDir, "manifest.json");
3187
+ const manifestSrc = path18.join(packageRoot, "manifest.json");
3166
3188
  await fs16.copyFile(manifestSrc, manifestDest);
3167
3189
  logger.debug(`meta: copied manifest.json \u2192 ${manifestDest}`);
3168
3190
  let written = 0;
@@ -3170,8 +3192,8 @@ async function landManifestMeta(opts) {
3170
3192
  for (const entry of manifest.entries) {
3171
3193
  if (!entry.meta) continue;
3172
3194
  total++;
3173
- const srcPath = path17.join(packageRoot, entry.meta);
3174
- const destPath = path17.join(metaDir, `${entry.id}.md`);
3195
+ const srcPath = path18.join(packageRoot, entry.meta);
3196
+ const destPath = path18.join(metaDir, `${entry.id}.md`);
3175
3197
  try {
3176
3198
  await fs16.copyFile(srcPath, destPath);
3177
3199
  written++;
@@ -3197,17 +3219,17 @@ async function landManifestMeta(opts) {
3197
3219
 
3198
3220
  // src/core/deps-install.ts
3199
3221
  import * as fs17 from "fs/promises";
3200
- import * as path18 from "path";
3222
+ import * as path19 from "path";
3201
3223
  import { exec } from "child_process";
3202
3224
  import { promisify } from "util";
3203
3225
  var execAsync = promisify(exec);
3204
3226
  async function detectPackageManager(projectRoot) {
3205
- if (await fileExists(path18.join(projectRoot, "pnpm-lock.yaml"))) return "pnpm";
3206
- if (await fileExists(path18.join(projectRoot, "pnpm-workspace.yaml")))
3227
+ if (await fileExists(path19.join(projectRoot, "pnpm-lock.yaml"))) return "pnpm";
3228
+ if (await fileExists(path19.join(projectRoot, "pnpm-workspace.yaml")))
3207
3229
  return "pnpm";
3208
- if (await fileExists(path18.join(projectRoot, "bun.lockb"))) return "bun";
3209
- if (await fileExists(path18.join(projectRoot, "bun.lock"))) return "bun";
3210
- if (await fileExists(path18.join(projectRoot, "yarn.lock"))) return "yarn";
3230
+ if (await fileExists(path19.join(projectRoot, "bun.lockb"))) return "bun";
3231
+ if (await fileExists(path19.join(projectRoot, "bun.lock"))) return "bun";
3232
+ if (await fileExists(path19.join(projectRoot, "yarn.lock"))) return "yarn";
3211
3233
  return "npm";
3212
3234
  }
3213
3235
  function getInstallCommand(pm) {
@@ -3224,7 +3246,7 @@ function getInstallCommand(pm) {
3224
3246
  }
3225
3247
  async function installProjectDeps(options) {
3226
3248
  const { projectRoot, npmDependencies, skipInstall = false } = options;
3227
- const pkgPath = path18.join(projectRoot, "package.json");
3249
+ const pkgPath = path19.join(projectRoot, "package.json");
3228
3250
  const raw = await readFileOrNull(pkgPath);
3229
3251
  if (!raw) {
3230
3252
  throw new Error(
@@ -3316,18 +3338,18 @@ ${stepLines}
3316
3338
 
3317
3339
  // src/core/file-changes.ts
3318
3340
  import * as fs18 from "fs/promises";
3319
- import * as path19 from "path";
3341
+ import * as path20 from "path";
3320
3342
  function toRelativePosix(p, projectRoot) {
3321
3343
  let rel2 = p;
3322
- if (path19.isAbsolute(p)) {
3323
- rel2 = path19.relative(projectRoot, p);
3344
+ if (path20.isAbsolute(p)) {
3345
+ rel2 = path20.relative(projectRoot, p);
3324
3346
  }
3325
- return rel2.split(path19.sep).join("/");
3347
+ return rel2.split(path20.sep).join("/");
3326
3348
  }
3327
3349
 
3328
3350
  // src/core/project-init.ts
3329
3351
  import * as fsNode from "fs/promises";
3330
- import * as path20 from "path";
3352
+ import * as path21 from "path";
3331
3353
  var CRITICAL_STEPS = /* @__PURE__ */ new Set([
3332
3354
  "tokens",
3333
3355
  "skills",
@@ -3395,6 +3417,38 @@ async function runProjectInit(options) {
3395
3417
  recordFailure("tokens", err);
3396
3418
  }
3397
3419
  }
3420
+ if (dryRun) {
3421
+ record({
3422
+ name: "html-theme",
3423
+ status: "planned",
3424
+ detail: `patchHtmlDataTheme(variant=${variant})`
3425
+ });
3426
+ } else if (aborted) {
3427
+ record({
3428
+ name: "html-theme",
3429
+ status: "skip",
3430
+ detail: "aborted: earlier critical step failed"
3431
+ });
3432
+ } else {
3433
+ try {
3434
+ const htmlResult = await patchHtmlDataTheme(projectRoot, variant);
3435
+ record({
3436
+ name: "html-theme",
3437
+ status: "ok",
3438
+ detail: htmlResult.status,
3439
+ changes: htmlResult.status === "patched" ? [
3440
+ {
3441
+ kind: "modified",
3442
+ path: "index.html",
3443
+ step: "html-theme",
3444
+ detail: `data-theme="${variant}"`
3445
+ }
3446
+ ] : []
3447
+ });
3448
+ } catch (err) {
3449
+ recordFailure("html-theme", err);
3450
+ }
3451
+ }
3398
3452
  if (dryRun) {
3399
3453
  record({
3400
3454
  name: "skills",
@@ -3669,7 +3723,7 @@ async function runProjectInit(options) {
3669
3723
  detail: "projectRoot does not exist"
3670
3724
  });
3671
3725
  } else {
3672
- const giPath = path20.join(projectRoot, ".gitignore");
3726
+ const giPath = path21.join(projectRoot, ".gitignore");
3673
3727
  let giContent = "";
3674
3728
  try {
3675
3729
  giContent = await fsNode.readFile(giPath, "utf-8");
@@ -3729,12 +3783,12 @@ async function runProjectInit(options) {
3729
3783
  if (!dryRun && hasFailures) {
3730
3784
  try {
3731
3785
  const checklistContent = renderInitChecklist({ variant, status, steps });
3732
- const checklistPath = path20.join(
3786
+ const checklistPath = path21.join(
3733
3787
  projectRoot,
3734
3788
  ".teamix-evo",
3735
3789
  "init-checklist.md"
3736
3790
  );
3737
- await fsNode.mkdir(path20.dirname(checklistPath), { recursive: true });
3791
+ await fsNode.mkdir(path21.dirname(checklistPath), { recursive: true });
3738
3792
  await fsNode.writeFile(checklistPath, checklistContent, "utf-8");
3739
3793
  logger.info(" wrote .teamix-evo/init-checklist.md");
3740
3794
  } catch {
@@ -3774,7 +3828,7 @@ function deriveLintChanges(result) {
3774
3828
  }
3775
3829
 
3776
3830
  // src/core/installer.ts
3777
- import * as path21 from "path";
3831
+ import * as path22 from "path";
3778
3832
  import * as fs19 from "fs/promises";
3779
3833
  async function installResources(options) {
3780
3834
  const { projectRoot, manifest, data, variantDir, packageRoot } = options;
@@ -3812,7 +3866,7 @@ async function installSingleResource(resource, projectRoot, data, variantDir, pa
3812
3866
  variantDir,
3813
3867
  packageRoot
3814
3868
  );
3815
- const targetPath = path21.join(projectRoot, resource.target);
3869
+ const targetPath = path22.join(projectRoot, resource.target);
3816
3870
  let content;
3817
3871
  if (resource.template) {
3818
3872
  const templateContent = await loadTemplateFile(sourcePath);
@@ -3836,13 +3890,13 @@ async function installRecursiveResource(resource, projectRoot, data, variantDir,
3836
3890
  variantDir,
3837
3891
  packageRoot
3838
3892
  );
3839
- const targetDir = path21.join(projectRoot, resource.target);
3893
+ const targetDir = path22.join(projectRoot, resource.target);
3840
3894
  const results = [];
3841
3895
  await ensureDir(targetDir);
3842
3896
  const entries = await walkDir(sourcePath);
3843
3897
  for (const entry of entries) {
3844
- const relPath = path21.relative(sourcePath, entry);
3845
- let targetFile = path21.join(targetDir, relPath);
3898
+ const relPath = path22.relative(sourcePath, entry);
3899
+ let targetFile = path22.join(targetDir, relPath);
3846
3900
  if (resource.template && targetFile.endsWith(".hbs")) {
3847
3901
  targetFile = targetFile.slice(0, -4);
3848
3902
  }
@@ -3855,7 +3909,7 @@ async function installRecursiveResource(resource, projectRoot, data, variantDir,
3855
3909
  }
3856
3910
  await writeFileSafe(targetFile, content);
3857
3911
  const hash = computeHash(content);
3858
- const targetRel = path21.relative(projectRoot, targetFile);
3912
+ const targetRel = path22.relative(projectRoot, targetFile);
3859
3913
  results.push({
3860
3914
  id: `${resource.id}:${relPath}`,
3861
3915
  target: targetRel,
@@ -3868,23 +3922,23 @@ async function installRecursiveResource(resource, projectRoot, data, variantDir,
3868
3922
  }
3869
3923
 
3870
3924
  // src/core/registry-client.ts
3871
- import * as path22 from "path";
3925
+ import * as path23 from "path";
3872
3926
  import * as fs20 from "fs/promises";
3873
3927
  import { createRequire as createRequire6 } from "module";
3874
3928
  import { loadVariantManifest } from "@teamix-evo/registry";
3875
3929
  var require7 = createRequire6(import.meta.url);
3876
3930
  function resolvePackageRoot5(packageName) {
3877
3931
  const pkgJsonPath = require7.resolve(`${packageName}/package.json`);
3878
- return path22.dirname(pkgJsonPath);
3932
+ return path23.dirname(pkgJsonPath);
3879
3933
  }
3880
3934
  async function loadVariantData(packageName, variant) {
3881
3935
  const packageRoot = resolvePackageRoot5(packageName);
3882
- const variantDir = path22.join(packageRoot, "library", variant);
3936
+ const variantDir = path23.join(packageRoot, "library", variant);
3883
3937
  logger.debug(`Resolved variant dir: ${variantDir}`);
3884
3938
  logger.debug(`Package root: ${packageRoot}`);
3885
3939
  const manifest = await loadVariantManifest(variantDir);
3886
3940
  let data = {};
3887
- const dataPath = path22.join(variantDir, "_data.json");
3941
+ const dataPath = path23.join(variantDir, "_data.json");
3888
3942
  try {
3889
3943
  const raw = await fs20.readFile(dataPath, "utf-8");
3890
3944
  data = JSON.parse(raw);