create-teamix-evo 0.2.0 → 0.3.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.
package/README.md CHANGED
@@ -20,7 +20,7 @@ yarn create teamix-evo my-app
20
20
  `create-teamix-evo` 默认产出 **完整中后台工程**(无需 `--preset` 选择):
21
21
 
22
22
  - Vite + React + TS + Tailwind v4
23
- - `@teamix-evo/design` tokens(`opentrek` variant)+ AI skills(Qoder + Claude)
23
+ - `@teamix-evo/tokens`(`opentrek` variant)+ AI skills(Qoder + Claude)
24
24
  - react-router-dom + ConsoleLayout + Dashboard / List / Detail / Form 页面
25
25
  - 真装 Button + Card / Table / Form / Input 占位(后续用 `ui add` 一键替换)
26
26
 
@@ -46,23 +46,28 @@ After the command finishes:
46
46
 
47
47
  ```
48
48
  my-app/
49
- ├── .teamix-evo/ # 装机元数据 + 资源(frozen / regenerable / managed)
49
+ ├── .teamix-evo/ # 装机元数据(frozen / regenerable)
50
50
  │ ├── config.json # 工程级 config (frozen)
51
- │ ├── manifest.json # 装机产物清单
52
- │ ├── tokens/ # design tokens(W1.4 提层)
53
- ├── design/ # philosophy / foundations / patterns / ...
54
- │ └── skills/ # skills 源(source-mirror 模型,ADR 0013)
55
- ├── .qoder/skills/ # AI skills mirror for Qoder
56
- ├── .claude/skills/ # AI skills mirror for Claude Code
57
- ├── AGENTS.md / CLAUDE.md # 工程级 AI 上下文(managed regions)
51
+ │ ├── manifest.json # 装机产物清单(regenerable)
52
+ │ ├── tokens-lock.json # tokens 装机记录(variant + version, regenerable)
53
+ └── skills/ # skills 源(source-mirror 模型,ADR 0013)
54
+ ├── tokens/ # 设计 token 真值(W3C JSON + Tailwind v4 @theme,ADR 0020)
55
+ ├── tokens.theme.css # regenerable
56
+ ├── base.tokens.json # regenerable
57
+ │ └── tokens.overrides.css # frozen 业务自定义覆盖
58
+ ├── .qoder/skills/ # AI skills mirror for Qoder(含 variant 设计 skill)
59
+ ├── .claude/skills/ # AI skills mirror for Claude Code(含 variant 设计 skill)
58
60
  ├── src/
59
- │ ├── components/ui/ # ui add 落地的真实组件(如 button.tsx)
60
- │ ├── components/_placeholder/ # console preset 占位组件(待 ui 包补齐)
61
+ │ ├── preferences.css # shadcn 全局偏好(frozen,由 ui init 部署)
62
+ │ ├── components/ui/ # ui add 落地的真实组件(如 button.tsx,frozen)
63
+ │ ├── components/_placeholder/ # console preset 占位组件(待 ui 包补齐)
61
64
  │ ├── pages/, layouts/, routes.tsx
62
65
  │ ├── App.tsx, main.tsx, index.css
63
66
  ├── package.json, vite.config.ts, ...
64
67
  ```
65
68
 
69
+ > ADR 0020 之后,设计纲领 / AI 入口指路不再落 `AGENTS.md` / `DESIGN.md` / `CLAUDE.md` 到工程根 —— variant 设计 skill 自包含完整规则,由 IDE 经 `.qoder/skills/` / `.claude/skills/` 加载。
70
+
66
71
  ## Next steps
67
72
 
68
73
  ```bash
@@ -76,4 +81,4 @@ Want to add more UI components later? Inside the project:
76
81
  npx teamix-evo ui add card table form input
77
82
  ```
78
83
 
79
- Read the project-level `AGENTS.md` for the full lifecycle guide (`design update`, `skills update`, `ui add`, etc.).
84
+ Full lifecycle guide (`tokens update`, `skills update`, `ui add`, etc.) lives in the `teamix-evo-manage` skill — your IDE loads it from `.qoder/skills/` or `.claude/skills/` automatically.
package/dist/index.js CHANGED
@@ -11,10 +11,11 @@ import path2 from "path";
11
11
  import { fileURLToPath } from "url";
12
12
  import { execa as execa2 } from "execa";
13
13
  import {
14
- runDesignInit,
14
+ runTokensInit,
15
15
  runSkillsAdd,
16
16
  runUiInit,
17
- runUiAdd
17
+ runUiAdd,
18
+ listTokenVariants
18
19
  } from "teamix-evo/core";
19
20
 
20
21
  // src/copy.ts
@@ -190,12 +191,15 @@ var consolePreset = {
190
191
  displayName: "Console",
191
192
  description: "\u4E2D\u540E\u53F0\u6807\u914D\uFF1AVite + React + TS + Tailwind v4 + design tokens + AI skills + react-router-dom + ConsoleLayout + Dashboard / List / Detail / Form \u56DB\u9875\u9762 + \u771F\u88C5 Button\u3002",
192
193
  baseTemplate: "react-ts",
193
- design: {
194
+ tokens: {
194
195
  variant: "opentrek",
195
196
  tailwind: "v4"
196
197
  },
197
198
  skills: {
198
- entries: ["teamix-evo-manage"],
199
+ // Bundle all 3 ship-day skills: manage (lifecycle), design-<variant>,
200
+ // code-<variant>. orchestrator expands `design-<variant>` /
201
+ // `code-<variant>` from the resolved variant id.
202
+ entries: ["teamix-evo-manage", "teamix-evo-design-${variant}", "teamix-evo-code-${variant}"],
199
203
  ides: ["qoder", "claude"]
200
204
  },
201
205
  ui: {
@@ -254,12 +258,13 @@ async function orchestrate(options) {
254
258
  }
255
259
  const dir = path2.resolve(options.dir);
256
260
  await prepareTargetDir(dir, options.force ?? false);
261
+ const variant = await resolveVariant(options.variant, preset);
257
262
  const pmInfo = detectPackageManager(options.pm);
258
263
  const projectName = path2.basename(dir);
259
264
  const pkgRoot = getPackageRoot();
260
265
  logger.step("\u62F7\u8D1D base \u6A21\u677F");
261
266
  const baseTemplateDir = path2.join(pkgRoot, "templates", preset.baseTemplate);
262
- const hbsCtx = buildHbsContext({ preset, projectName, pmInfo });
267
+ const hbsCtx = buildHbsContext({ preset, variant, projectName, pmInfo });
263
268
  await copyDir(baseTemplateDir, dir, { hbs: hbsCtx });
264
269
  logger.detail(`base: ${preset.baseTemplate}`);
265
270
  if (preset.overlay) {
@@ -267,26 +272,32 @@ async function orchestrate(options) {
267
272
  const overlayDir = path2.join(pkgRoot, "overlays", preset.overlay);
268
273
  await copyDir(overlayDir, dir, { hbs: hbsCtx });
269
274
  }
270
- logger.step("\u88C5\u8F7D design tokens");
271
- const designResult = await runDesignInit({
275
+ logger.step(`\u88C5\u8F7D design tokens (variant=${variant})`);
276
+ const tokensResult = await runTokensInit({
272
277
  projectRoot: dir,
273
- variant: preset.design.variant,
278
+ variant,
274
279
  ide: "qoder"
275
280
  });
276
- if (designResult.status === "installed") {
281
+ if (tokensResult.status === "installed") {
277
282
  logger.detail(
278
- `${designResult.packageName}@${designResult.version} (${designResult.count} files)`
283
+ `${tokensResult.packageName}@${tokensResult.version} (${tokensResult.count} files)`
279
284
  );
280
285
  }
286
+ const expandedSkillNames = preset.skills.entries.map(
287
+ (id) => id.replace(/\$\{variant\}/g, variant)
288
+ );
281
289
  logger.step("\u88C5\u8F7D AI skills");
282
290
  const skillsResult = await runSkillsAdd({
283
291
  projectRoot: dir,
292
+ names: expandedSkillNames,
284
293
  ides: preset.skills.ides,
285
294
  scope: "project"
286
295
  });
287
296
  if (skillsResult.status === "installed") {
288
297
  logger.detail(
289
- `${skillsResult.skillCount} skill(s) \u2192 ${skillsResult.ides.join(" + ")}`
298
+ `${skillsResult.skillCount + skillsResult.skippedSkillIds.length} skill(s) \u2192 ${skillsResult.ides.join(
299
+ " + "
300
+ )} (added: ${skillsResult.addedSkillIds.join(", ") || "none"}; existing: ${skillsResult.skippedSkillIds.join(", ") || "none"})`
290
301
  );
291
302
  }
292
303
  logger.step("\u914D\u7F6E UI");
@@ -319,6 +330,8 @@ async function orchestrate(options) {
319
330
  await writePendingUi(dir, preset.id);
320
331
  logger.detail(".teamix-evo/create/pending-ui.json \u5DF2\u5199\u5165");
321
332
  }
333
+ await writeMcpJson(dir);
334
+ logger.detail(".mcp.json \u5DF2\u5199\u5165");
322
335
  if (options.install) {
323
336
  logger.step(`\u5B89\u88C5\u4F9D\u8D56\uFF08${pmInfo.installCommand}\uFF09`);
324
337
  try {
@@ -354,9 +367,15 @@ async function prepareTargetDir(dir, force) {
354
367
  const entries = await fs3.readdir(dir);
355
368
  if (entries.length === 0) return;
356
369
  if (entries.includes(".teamix-evo")) {
357
- throw new Error(
358
- `Target directory already contains a .teamix-evo/ \u2014 please run \`teamix-evo design init\` inside it instead of using create-teamix-evo.`
359
- );
370
+ if (!force) {
371
+ throw new Error(
372
+ `Target directory already contains a .teamix-evo/ \u2014 please run \`teamix-evo tokens init\` inside it instead of using create-teamix-evo. Or pass --force to wipe the directory and rebuild from scratch.`
373
+ );
374
+ }
375
+ logger.warn(`--force\uFF1A\u5220\u9664\u5DF2\u6709 teamix-evo \u5DE5\u7A0B\u540E\u91CD\u5EFA ${dir}`);
376
+ await fs3.rm(dir, { recursive: true, force: true });
377
+ await fs3.mkdir(dir, { recursive: true });
378
+ return;
360
379
  }
361
380
  if (!force) {
362
381
  throw new Error(
@@ -364,17 +383,36 @@ async function prepareTargetDir(dir, force) {
364
383
  );
365
384
  }
366
385
  logger.warn(`--force\uFF1A\u8986\u76D6\u5DF2\u6709\u76EE\u5F55 ${dir}`);
386
+ await fs3.rm(dir, { recursive: true, force: true });
387
+ await fs3.mkdir(dir, { recursive: true });
367
388
  }
368
389
  function buildHbsContext(args) {
369
- const { preset, projectName, pmInfo } = args;
390
+ const { preset, variant, projectName, pmInfo } = args;
370
391
  return {
371
392
  projectName,
372
- designVariant: preset.design.variant,
393
+ tokensVariant: variant,
373
394
  pmInstall: pmInfo.installCommand,
374
395
  pmRun: pmInfo.runPrefix,
375
396
  uiInstalled: preset.ui.components.length > 0 ? preset.ui.components.join(", ") : "\uFF08\u65E0\uFF09"
376
397
  };
377
398
  }
399
+ async function resolveVariant(override, preset) {
400
+ const candidate = override ?? preset.tokens.variant;
401
+ let known = [];
402
+ try {
403
+ const catalog = await listTokenVariants();
404
+ known = catalog.variants.map((v) => v.name);
405
+ } catch {
406
+ return candidate;
407
+ }
408
+ if (!known.includes(candidate)) {
409
+ throw new Error(
410
+ `Unknown tokens variant "${candidate}". Available: ${known.join(", ")}.
411
+ Hint: run \`npx teamix-evo tokens list-variants\` to see all variants.`
412
+ );
413
+ }
414
+ return candidate;
415
+ }
378
416
  async function mergeProjectPackageJson(args) {
379
417
  const pkgPath = path2.join(args.dir, "package.json");
380
418
  const base = await readJson(pkgPath);
@@ -412,14 +450,25 @@ async function writePendingUi(dir, presetId) {
412
450
  schemaVersion: 1,
413
451
  preset: presetId,
414
452
  pendingComponents: [
415
- { id: "card", placeholder: "src/components/_placeholder/Card.tsx" },
416
- { id: "input", placeholder: "src/components/_placeholder/Input.tsx" },
417
- { id: "form", placeholder: "src/components/_placeholder/Form.tsx" },
418
- { id: "table", placeholder: "src/components/_placeholder/Table.tsx" }
453
+ { id: "card", placeholder: "src/components/_placeholder/card.tsx" },
454
+ { id: "input", placeholder: "src/components/_placeholder/input.tsx" },
455
+ { id: "form", placeholder: "src/components/_placeholder/form.tsx" },
456
+ { id: "table", placeholder: "src/components/_placeholder/table.tsx" }
419
457
  ]
420
458
  };
421
459
  await writeJson(pendingPath, payload);
422
460
  }
461
+ async function writeMcpJson(dir) {
462
+ const mcpJson = {
463
+ mcpServers: {
464
+ "teamix-evo": {
465
+ command: "npx",
466
+ args: ["-y", "@teamix-evo/mcp"]
467
+ }
468
+ }
469
+ };
470
+ await writeJson(path2.join(dir, ".mcp.json"), mcpJson);
471
+ }
423
472
  function printNextSteps(args) {
424
473
  const { dir, pmInfo, preset } = args;
425
474
  const rel = path2.relative(process.cwd(), dir) || ".";
@@ -441,10 +490,38 @@ function printNextSteps(args) {
441
490
 
442
491
  // src/prompts.ts
443
492
  import * as p from "@clack/prompts";
493
+ import { listTokenVariants as listTokenVariants2 } from "teamix-evo/core";
444
494
  async function promptMissing(seed) {
445
495
  p.intro("create-teamix-evo");
446
496
  p.note(`\u{1F4E6} Target directory: ${seed.dir}`);
447
497
  const presetId = seed.presetId ?? "console";
498
+ let variant = seed.variant;
499
+ if (!variant) {
500
+ let variantOptions = [];
501
+ try {
502
+ const catalog = await listTokenVariants2();
503
+ variantOptions = catalog.variants.map((v) => ({
504
+ value: v.name,
505
+ label: `${v.displayName} (${v.name})`,
506
+ hint: v.description
507
+ }));
508
+ } catch {
509
+ variantOptions = [
510
+ { value: "opentrek", label: "OpenTrek (opentrek)" },
511
+ { value: "uni-manager", label: "Uni-Manager (uni-manager)" }
512
+ ];
513
+ }
514
+ const choice = await p.select({
515
+ message: "Tokens variant",
516
+ options: variantOptions,
517
+ initialValue: variantOptions[0]?.value ?? "opentrek"
518
+ });
519
+ if (p.isCancel(choice)) {
520
+ p.cancel("\u5DF2\u53D6\u6D88");
521
+ process.exit(0);
522
+ }
523
+ variant = choice;
524
+ }
448
525
  let pm = seed.pm && isValidPackageManager(seed.pm) ? seed.pm : void 0;
449
526
  if (!pm) {
450
527
  const pmChoice = await p.select({
@@ -475,7 +552,7 @@ async function promptMissing(seed) {
475
552
  }
476
553
  git = confirmed;
477
554
  }
478
- return { presetId, pm, git };
555
+ return { presetId, pm, git, variant };
479
556
  }
480
557
 
481
558
  // src/index.ts
@@ -486,7 +563,10 @@ async function main() {
486
563
  ).argument(
487
564
  "[dir]",
488
565
  "target directory (will be created if it does not exist)"
489
- ).option("--preset <id>", `preset id (${listPresetIds().join(" | ")})`).option("--pm <name>", "package manager: pnpm | npm | yarn").option("--no-git", "skip git init").option("--no-install", "skip dependency installation").option("--force", "overwrite non-empty target directory").helpOption("-h, --help", "display help");
566
+ ).option("--preset <id>", `preset id (${listPresetIds().join(" | ")})`).option(
567
+ "--variant <name>",
568
+ "tokens variant (e.g. opentrek | uni-manager); \u4E0D\u4F20\u5219\u4EA4\u4E92\u8BE2\u95EE"
569
+ ).option("--pm <name>", "package manager: pnpm | npm | yarn").option("--no-git", "skip git init").option("--no-install", "skip dependency installation").option("--force", "overwrite non-empty target directory").helpOption("-h, --help", "display help");
490
570
  program.parse(process.argv);
491
571
  const opts = program.opts();
492
572
  const dirArg = program.args[0];
@@ -507,16 +587,19 @@ async function main() {
507
587
  let presetId = opts.preset ?? "console";
508
588
  let pm = opts.pm;
509
589
  let git = opts.git;
510
- if (process.stdin.isTTY && git === void 0) {
590
+ let variant = opts.variant;
591
+ if (process.stdin.isTTY && (git === void 0 || variant === void 0)) {
511
592
  const answers = await promptMissing({
512
593
  dir,
513
594
  presetId,
514
595
  pm,
515
- git
596
+ git,
597
+ variant
516
598
  });
517
599
  presetId = answers.presetId;
518
600
  git = answers.git;
519
601
  if (answers.pm) pm = answers.pm;
602
+ variant = answers.variant;
520
603
  } else {
521
604
  git = git ?? true;
522
605
  }
@@ -524,6 +607,7 @@ async function main() {
524
607
  await orchestrate({
525
608
  dir,
526
609
  presetId,
610
+ variant,
527
611
  pm: pm && isValidPackageManager(pm) ? pm : void 0,
528
612
  install: opts.install ?? true,
529
613
  git: git ?? true,
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/orchestrator.ts","../src/copy.ts","../src/git.ts","../src/merge-package-json.ts","../src/pm.ts","../src/presets/console.ts","../src/presets/index.ts","../src/utils/logger.ts","../src/prompts.ts"],"sourcesContent":["import path from 'node:path';\nimport { Command } from 'commander';\nimport { red } from 'kolorist';\nimport { orchestrate } from './orchestrator.js';\nimport { listPresetIds } from './presets/index.js';\nimport { isValidPackageManager } from './pm.js';\nimport { promptMissing } from './prompts.js';\nimport { logger } from './utils/logger.js';\n\ninterface CliOptions {\n preset?: string;\n pm?: string;\n /** commander treats `--no-git` as `git: false`. */\n git?: boolean;\n /** commander treats `--no-install` as `install: false`. */\n install?: boolean;\n force?: boolean;\n}\n\nasync function main(): Promise<void> {\n const program = new Command();\n\n program\n .name('create-teamix-evo')\n .description(\n 'Scaffold a Vite + React + TypeScript project pre-wired with Teamix Evo design tokens, AI skills, and UI components.',\n )\n .argument(\n '[dir]',\n 'target directory (will be created if it does not exist)',\n )\n .option('--preset <id>', `preset id (${listPresetIds().join(' | ')})`)\n .option('--pm <name>', 'package manager: pnpm | npm | yarn')\n .option('--no-git', 'skip git init')\n .option('--no-install', 'skip dependency installation')\n .option('--force', 'overwrite non-empty target directory')\n .helpOption('-h, --help', 'display help');\n\n program.parse(process.argv);\n const opts = program.opts<CliOptions>();\n const dirArg = program.args[0];\n\n // Resolve target directory (interactive only if no dirArg).\n const dir = dirArg\n ? path.resolve(dirArg)\n : path.resolve(process.cwd(), 'my-app');\n if (!dirArg) {\n logger.warn(`未指定目录,使用默认路径:${dir}`);\n }\n\n // Validate --preset / --pm if provided\n if (opts.preset && !listPresetIds().includes(opts.preset)) {\n logger.error(\n `未知 preset \"${opts.preset}\"。可选:${listPresetIds().join(', ')}`,\n );\n process.exit(1);\n }\n if (opts.pm && !isValidPackageManager(opts.pm)) {\n logger.error(`未知包管理器 \"${opts.pm}\"。可选:pnpm | npm | yarn`);\n process.exit(1);\n }\n\n // Interactive prompts for missing fields (when running in a TTY).\n let presetId = opts.preset ?? 'console';\n let pm = opts.pm;\n let git = opts.git;\n if (process.stdin.isTTY && git === undefined) {\n const answers = await promptMissing({\n dir,\n presetId,\n pm,\n git,\n });\n presetId = answers.presetId;\n git = answers.git;\n if (answers.pm) pm = answers.pm;\n } else {\n git = git ?? true;\n }\n\n try {\n await orchestrate({\n dir,\n presetId: presetId!,\n pm: pm && isValidPackageManager(pm) ? pm : undefined,\n install: opts.install ?? true,\n git: git ?? true,\n force: opts.force ?? false,\n });\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n console.error(`\\n${red('✗')} ${message}`);\n process.exit(1);\n }\n}\n\nmain().catch((err) => {\n console.error(`\\n${red('✗')} 未捕获的错误`);\n console.error(err);\n process.exit(1);\n});\n","import fs from 'node:fs/promises';\nimport path from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport { execa } from 'execa';\nimport {\n runDesignInit,\n runSkillsAdd,\n runUiInit,\n runUiAdd,\n} from 'teamix-evo/core';\nimport { copyDir } from './copy.js';\nimport { gitInit } from './git.js';\nimport {\n mergePackageJson,\n readJson,\n writeJson,\n VersionConflictError,\n} from './merge-package-json.js';\nimport {\n detectPackageManager,\n type PackageManager,\n type PackageManagerInfo,\n} from './pm.js';\nimport { findPreset, type Preset } from './presets/index.js';\nimport { logger } from './utils/logger.js';\n\nexport interface OrchestrateOptions {\n /** Absolute target directory. */\n dir: string;\n /** Preset id. */\n presetId: string;\n /** Preferred package manager (else auto-detect). */\n pm?: PackageManager;\n /** Run package manager install at the end. */\n install: boolean;\n /** Run git init at the end. */\n git: boolean;\n /** Overwrite non-empty target directory. */\n force?: boolean;\n}\n\n/**\n * Locate the create-teamix-evo package root (regardless of whether running\n * from source via tsx, or from `dist/index.js` after bundling).\n */\nfunction getPackageRoot(): string {\n // Resolves to <pkg>/dist/index.js.map's directory in dev/build.\n const here = path.dirname(fileURLToPath(import.meta.url));\n // From dist/ go up to package root.\n return path.resolve(here, '..');\n}\n\n/**\n * Main scaffolding pipeline.\n *\n * Order:\n * 1. validate target dir\n * 2. copy base template (renders all `.hbs`)\n * 3. copy overlay if any\n * 4. teamix-evo design init\n * 5. teamix-evo skills add\n * 6. teamix-evo ui init + ui add\n * 7. rewrite package.json (base + overlay fragment + ui npm deps)\n * 8. write pending-ui.json (if overlay declares placeholders)\n * 9. install deps\n * 10. git init\n */\nexport async function orchestrate(options: OrchestrateOptions): Promise<void> {\n const preset = findPreset(options.presetId);\n if (!preset) {\n throw new Error(\n `Unknown preset \"${options.presetId}\". Available: console.`,\n );\n }\n\n const dir = path.resolve(options.dir);\n await prepareTargetDir(dir, options.force ?? false);\n\n const pmInfo = detectPackageManager(options.pm);\n const projectName = path.basename(dir);\n const pkgRoot = getPackageRoot();\n\n // ─── 1. base template ───────────────────────────────────────────────────\n logger.step('拷贝 base 模板');\n const baseTemplateDir = path.join(pkgRoot, 'templates', preset.baseTemplate);\n const hbsCtx = buildHbsContext({ preset, projectName, pmInfo });\n await copyDir(baseTemplateDir, dir, { hbs: hbsCtx });\n logger.detail(`base: ${preset.baseTemplate}`);\n\n // ─── 2. overlay ─────────────────────────────────────────────────────────\n if (preset.overlay) {\n logger.step(`应用 overlay: ${preset.overlay}`);\n const overlayDir = path.join(pkgRoot, 'overlays', preset.overlay);\n await copyDir(overlayDir, dir, { hbs: hbsCtx });\n }\n\n // ─── 3. design tokens ───────────────────────────────────────────────────\n logger.step('装载 design tokens');\n const designResult = await runDesignInit({\n projectRoot: dir,\n variant: preset.design.variant,\n ide: 'qoder',\n });\n if (designResult.status === 'installed') {\n logger.detail(\n `${designResult.packageName}@${designResult.version} (${designResult.count} files)`,\n );\n }\n\n // ─── 4. AI skills ───────────────────────────────────────────────────────\n logger.step('装载 AI skills');\n const skillsResult = await runSkillsAdd({\n projectRoot: dir,\n ides: preset.skills.ides,\n scope: 'project',\n });\n if (skillsResult.status === 'installed') {\n logger.detail(\n `${skillsResult.skillCount} skill(s) → ${skillsResult.ides.join(' + ')}`,\n );\n }\n\n // ─── 5. ui init + ui add ────────────────────────────────────────────────\n logger.step('配置 UI');\n await runUiInit({ projectRoot: dir });\n let uiAddDeps: Record<string, string> = {};\n if (preset.ui.components.length > 0) {\n const uiAddResult = await runUiAdd({\n projectRoot: dir,\n ids: preset.ui.components,\n });\n uiAddDeps = uiAddResult.npmDependencies;\n logger.detail(\n `installed: ${uiAddResult.orderedIds.join(', ')} (${\n uiAddResult.written\n } files)`,\n );\n } else {\n logger.detail('ui init only — 无组件落地');\n }\n\n // ─── 6. merge package.json ──────────────────────────────────────────────\n logger.step('合并 package.json');\n await mergeProjectPackageJson({\n dir,\n overlayFragmentPath: preset.overlay\n ? path.join(\n pkgRoot,\n 'overlays',\n preset.overlay,\n 'package.json.fragment.json',\n )\n : null,\n extraDependencies: uiAddDeps,\n });\n\n // ─── 7. pending-ui.json ─────────────────────────────────────────────────\n if (preset.overlay === 'console') {\n await writePendingUi(dir, preset.id);\n logger.detail('.teamix-evo/create/pending-ui.json 已写入');\n }\n\n // ─── 8. install deps ────────────────────────────────────────────────────\n if (options.install) {\n logger.step(`安装依赖(${pmInfo.installCommand})`);\n try {\n await execa(pmInfo.name, pmInfo.install, { cwd: dir, stdio: 'inherit' });\n } catch (err) {\n logger.warn(\n `依赖安装失败 — 可手动执行:cd ${\n path.relative(process.cwd(), dir) || '.'\n } && ${pmInfo.installCommand}`,\n );\n if (err instanceof Error) logger.detail(err.message);\n }\n } else {\n logger.detail(`跳过依赖安装(手动执行:${pmInfo.installCommand})`);\n }\n\n // ─── 9. git init ────────────────────────────────────────────────────────\n if (options.git) {\n logger.step('初始化 git');\n const result = await gitInit(dir);\n if (result.ok) logger.detail('git 仓库已就绪(含首个 commit)');\n else logger.warn(`git init 失败:${result.reason}`);\n }\n\n // ─── done ───────────────────────────────────────────────────────────────\n printNextSteps({ dir, pmInfo, preset });\n}\n\nasync function prepareTargetDir(dir: string, force: boolean): Promise<void> {\n let exists = false;\n try {\n await fs.access(dir);\n exists = true;\n } catch {\n /* not exists */\n }\n\n if (!exists) {\n await fs.mkdir(dir, { recursive: true });\n return;\n }\n\n const entries = await fs.readdir(dir);\n if (entries.length === 0) return;\n\n // Reject existing teamix-evo project regardless of --force\n if (entries.includes('.teamix-evo')) {\n throw new Error(\n `Target directory already contains a .teamix-evo/ — please run \\`teamix-evo design init\\` inside it instead of using create-teamix-evo.`,\n );\n }\n\n if (!force) {\n throw new Error(\n `Target directory \"${dir}\" is not empty. Use --force to overwrite.`,\n );\n }\n logger.warn(`--force:覆盖已有目录 ${dir}`);\n}\n\nfunction buildHbsContext(args: {\n preset: Preset;\n projectName: string;\n pmInfo: PackageManagerInfo;\n}): Record<string, unknown> {\n const { preset, projectName, pmInfo } = args;\n return {\n projectName,\n designVariant: preset.design.variant,\n pmInstall: pmInfo.installCommand,\n pmRun: pmInfo.runPrefix,\n uiInstalled:\n preset.ui.components.length > 0\n ? preset.ui.components.join(', ')\n : '(无)',\n };\n}\n\nasync function mergeProjectPackageJson(args: {\n dir: string;\n overlayFragmentPath: string | null;\n extraDependencies: Record<string, string>;\n}): Promise<void> {\n const pkgPath = path.join(args.dir, 'package.json');\n const base = await readJson<Record<string, unknown>>(pkgPath);\n let overlay: Record<string, unknown> | null = null;\n if (args.overlayFragmentPath) {\n try {\n overlay = await readJson<Record<string, unknown>>(\n args.overlayFragmentPath,\n );\n } catch {\n overlay = null;\n }\n }\n try {\n const merged = mergePackageJson(base, overlay, {\n extraDependencies: args.extraDependencies,\n });\n await writeJson(pkgPath, merged);\n } catch (err) {\n if (err instanceof VersionConflictError) {\n throw new Error(\n `package.json 合并失败:${err.message}\\n` +\n `请检查 base 模板与 overlay/ui 组件依赖的版本声明,确保一致。`,\n );\n }\n throw err;\n }\n}\n\nasync function writePendingUi(dir: string, presetId: string): Promise<void> {\n const pendingDir = path.join(dir, '.teamix-evo', 'create');\n await fs.mkdir(pendingDir, { recursive: true });\n const pendingPath = path.join(pendingDir, 'pending-ui.json');\n const payload = {\n $schema: 'https://teamix-evo.dev/schema/pending-ui/v1.json',\n schemaVersion: 1,\n preset: presetId,\n pendingComponents: [\n { id: 'card', placeholder: 'src/components/_placeholder/Card.tsx' },\n { id: 'input', placeholder: 'src/components/_placeholder/Input.tsx' },\n { id: 'form', placeholder: 'src/components/_placeholder/Form.tsx' },\n { id: 'table', placeholder: 'src/components/_placeholder/Table.tsx' },\n ],\n };\n await writeJson(pendingPath, payload);\n}\n\nfunction printNextSteps(args: {\n dir: string;\n pmInfo: PackageManagerInfo;\n preset: Preset;\n}): void {\n const { dir, pmInfo, preset } = args;\n const rel = path.relative(process.cwd(), dir) || '.';\n logger.blank();\n logger.success(`${preset.displayName} preset 已就绪:${dir}`);\n logger.blank();\n console.log('Next steps:');\n console.log(` cd ${rel}`);\n console.log(\n ` ${pmInfo.runPrefix}${pmInfo.runPrefix === 'yarn' ? ' ' : ' '}dev`,\n );\n if (preset.id === 'console') {\n logger.blank();\n console.log(\n '💡 console preset 内含占位组件,可用 `npx teamix-evo ui add card` 等替换为真组件。',\n );\n }\n}\n","import fs from 'node:fs/promises';\nimport path from 'node:path';\nimport Handlebars from 'handlebars';\n\nexport interface CopyContext {\n /** Handlebars render context for `.hbs` templates. */\n hbs: Record<string, unknown>;\n}\n\n/**\n * Recursively copy `srcDir` into `destDir`, applying:\n * - `.hbs` files: rendered with `ctx.hbs`, written without `.hbs` extension\n * - `_gitignore` / `_editorconfig` etc. → `.gitignore` / `.editorconfig`\n * - Skips `package.json.fragment.json` (handled separately by the merger)\n *\n * Existing files are overwritten — call site is responsible for `--force`\n * / clean-target semantics.\n */\nexport async function copyDir(\n srcDir: string,\n destDir: string,\n ctx: CopyContext,\n): Promise<void> {\n await fs.mkdir(destDir, { recursive: true });\n\n const entries = await fs.readdir(srcDir, { withFileTypes: true });\n for (const entry of entries) {\n const srcPath = path.join(srcDir, entry.name);\n const destName = mapDestName(entry.name);\n if (destName === null) continue; // explicitly skipped\n const destPath = path.join(destDir, destName);\n\n if (entry.isDirectory()) {\n await copyDir(srcPath, destPath, ctx);\n continue;\n }\n\n if (entry.name.endsWith('.hbs')) {\n const tpl = await fs.readFile(srcPath, 'utf8');\n const rendered = Handlebars.compile(tpl, { noEscape: true })(ctx.hbs);\n await fs.writeFile(destPath, rendered, 'utf8');\n continue;\n }\n\n await fs.copyFile(srcPath, destPath);\n }\n}\n\n/**\n * Translate a source filename to its destination filename, or `null` to skip.\n */\nfunction mapDestName(name: string): string | null {\n // Skip the package.json fragment — orchestrator merges it into base.\n if (name === 'package.json.fragment.json') return null;\n\n // _gitignore → .gitignore (npm strips real `.gitignore` from packed tarballs)\n if (name === '_gitignore') return '.gitignore';\n if (name === '_editorconfig') return '.editorconfig';\n if (name === '_npmrc') return '.npmrc';\n\n // Strip .hbs extension\n if (name.endsWith('.hbs')) {\n return name.slice(0, -'.hbs'.length);\n }\n\n return name;\n}\n","import { execa } from 'execa';\n\n/**\n * Initialize a fresh git repo with a single commit. Best-effort:\n * any failure is reported as `{ ok: false }` instead of throwing —\n * scaffolding should not fail just because git is missing.\n */\nexport async function gitInit(\n cwd: string,\n): Promise<{ ok: true } | { ok: false; reason: string }> {\n try {\n await execa('git', ['init', '--quiet'], { cwd });\n await execa('git', ['add', '-A'], { cwd });\n await execa(\n 'git',\n [\n '-c',\n 'user.email=create-teamix-evo@local',\n '-c',\n 'user.name=create-teamix-evo',\n 'commit',\n '--quiet',\n '--no-gpg-sign',\n '-m',\n 'chore: scaffolded by create-teamix-evo',\n ],\n { cwd },\n );\n return { ok: true };\n } catch (err) {\n const reason = err instanceof Error ? err.message : String(err);\n return { ok: false, reason };\n }\n}\n","import fs from 'node:fs/promises';\n\ninterface PackageJsonLike {\n [key: string]: unknown;\n dependencies?: Record<string, string>;\n devDependencies?: Record<string, string>;\n scripts?: Record<string, string>;\n}\n\nexport interface MergeOptions {\n /** Extra dependencies (e.g. from `runUiAdd`) merged with conflict checks. */\n extraDependencies?: Record<string, string>;\n /** Extra dev dependencies merged with conflict checks. */\n extraDevDependencies?: Record<string, string>;\n}\n\nexport class VersionConflictError extends Error {\n constructor(\n readonly key: 'dependencies' | 'devDependencies' | 'scripts',\n override readonly name: string,\n readonly base: string,\n readonly incoming: string,\n ) {\n super(\n `Version conflict in ${key}: ${name} declared as \"${base}\" in base but \"${incoming}\" in overlay/extras.`,\n );\n this.name = 'VersionConflictError';\n }\n}\n\n/**\n * Merge a base package.json with an overlay fragment + extras.\n *\n * - Merges `dependencies`, `devDependencies`, and `scripts` (shallow).\n * - Throws {@link VersionConflictError} on any version mismatch within the same key.\n * - Other top-level keys (`name`, `version`, etc.) come from `base` only.\n */\nexport function mergePackageJson(\n base: PackageJsonLike,\n overlay: PackageJsonLike | null,\n options: MergeOptions = {},\n): PackageJsonLike {\n const merged: PackageJsonLike = { ...base };\n\n for (const key of ['dependencies', 'devDependencies', 'scripts'] as const) {\n const baseMap = (base[key] ?? {}) as Record<string, string>;\n const overlayMap = (overlay?.[key] ?? {}) as Record<string, string>;\n const extrasMap =\n key === 'dependencies'\n ? options.extraDependencies ?? {}\n : key === 'devDependencies'\n ? options.extraDevDependencies ?? {}\n : {};\n\n const result: Record<string, string> = { ...baseMap };\n for (const [name, version] of Object.entries(overlayMap)) {\n if (result[name] !== undefined && result[name] !== version) {\n throw new VersionConflictError(key, name, result[name], version);\n }\n result[name] = version;\n }\n for (const [name, version] of Object.entries(extrasMap)) {\n if (result[name] !== undefined && result[name] !== version) {\n throw new VersionConflictError(key, name, result[name], version);\n }\n result[name] = version;\n }\n if (Object.keys(result).length > 0) {\n merged[key] = sortObjectByKey(result);\n }\n }\n\n return merged;\n}\n\nfunction sortObjectByKey<T extends Record<string, unknown>>(obj: T): T {\n const sorted: Record<string, unknown> = {};\n for (const k of Object.keys(obj).sort()) sorted[k] = obj[k];\n return sorted as T;\n}\n\nexport async function readJson<T = unknown>(filePath: string): Promise<T> {\n const raw = await fs.readFile(filePath, 'utf8');\n return JSON.parse(raw) as T;\n}\n\nexport async function writeJson(\n filePath: string,\n value: unknown,\n): Promise<void> {\n await fs.writeFile(filePath, JSON.stringify(value, null, 2) + '\\n', 'utf8');\n}\n","/**\n * Detect the user's package manager from `npm_config_user_agent`,\n * with fallback heuristics, and produce install / run commands.\n */\n\nexport type PackageManager = 'pnpm' | 'npm' | 'yarn';\n\nexport interface PackageManagerInfo {\n name: PackageManager;\n /** Command + args to install dependencies in cwd. */\n install: string[];\n /** Command + args prefix to run a package script. */\n run: string[];\n /** Human-readable command (`pnpm install`, etc.). */\n installCommand: string;\n /** Human-readable run prefix (`pnpm`, `npm run`, `yarn`). */\n runPrefix: string;\n}\n\n/**\n * Detect the package manager invoking `create-teamix-evo`.\n *\n * Priority:\n * 1. explicit `prefer` argument\n * 2. `npm_config_user_agent` env (set by `pnpm create` / `npm create` / `yarn create`)\n * 3. fallback to `npm`\n */\nexport function detectPackageManager(\n prefer?: PackageManager,\n): PackageManagerInfo {\n const detected = prefer ?? detectFromUserAgent() ?? 'npm';\n return buildInfo(detected);\n}\n\nexport function isValidPackageManager(value: string): value is PackageManager {\n return value === 'pnpm' || value === 'npm' || value === 'yarn';\n}\n\nfunction detectFromUserAgent(): PackageManager | null {\n const ua = process.env.npm_config_user_agent;\n if (!ua) return null;\n const head = ua.split(' ')[0] ?? '';\n if (head.startsWith('pnpm')) return 'pnpm';\n if (head.startsWith('yarn')) return 'yarn';\n if (head.startsWith('npm')) return 'npm';\n return null;\n}\n\nfunction buildInfo(name: PackageManager): PackageManagerInfo {\n switch (name) {\n case 'pnpm':\n return {\n name,\n install: ['install'],\n run: ['run'],\n installCommand: 'pnpm install',\n runPrefix: 'pnpm',\n };\n case 'yarn':\n return {\n name,\n install: ['install'],\n run: [],\n installCommand: 'yarn install',\n runPrefix: 'yarn',\n };\n case 'npm':\n default:\n return {\n name,\n install: ['install'],\n run: ['run'],\n installCommand: 'npm install',\n runPrefix: 'npm run',\n };\n }\n}\n","import type { Preset } from './types.js';\n\nexport const consolePreset: Preset = {\n id: 'console',\n displayName: 'Console',\n description:\n '中后台标配:Vite + React + TS + Tailwind v4 + design tokens + AI skills + react-router-dom + ConsoleLayout + Dashboard / List / Detail / Form 四页面 + 真装 Button。',\n baseTemplate: 'react-ts',\n design: {\n variant: 'opentrek',\n tailwind: 'v4',\n },\n skills: {\n entries: ['teamix-evo-manage'],\n ides: ['qoder', 'claude'],\n },\n ui: {\n components: ['button'],\n },\n overlay: 'console',\n};\n","import type { Preset } from './types.js';\nimport { consolePreset } from './console.js';\n\nexport type { Preset } from './types.js';\n\nexport const presets: Preset[] = [consolePreset];\n\nexport function findPreset(id: string): Preset | undefined {\n return presets.find((p) => p.id === id);\n}\n\nexport function listPresetIds(): string[] {\n return presets.map((p) => p.id);\n}\n","import { bold, cyan, dim, green, red, yellow } from 'kolorist';\n\nexport const logger = {\n info(message: string): void {\n console.log(`${cyan('ℹ')} ${message}`);\n },\n success(message: string): void {\n console.log(`${green('✓')} ${message}`);\n },\n warn(message: string): void {\n console.warn(`${yellow('⚠')} ${message}`);\n },\n error(message: string): void {\n console.error(`${red('✗')} ${message}`);\n },\n step(message: string): void {\n console.log(`\\n${bold(cyan('▸'))} ${bold(message)}`);\n },\n detail(message: string): void {\n console.log(` ${dim(message)}`);\n },\n blank(): void {\n console.log('');\n },\n};\n","import * as p from '@clack/prompts';\nimport { isValidPackageManager, type PackageManager } from './pm.js';\n\nexport interface InteractiveAnswers {\n presetId: string;\n pm: PackageManager | undefined;\n git: boolean;\n}\n\n/**\n * Run interactive prompts for missing options. The `seed` represents whatever\n * the user already passed via flags; only unanswered fields are prompted for.\n */\nexport async function promptMissing(seed: {\n dir: string;\n presetId?: string;\n pm?: string;\n git?: boolean;\n}): Promise<InteractiveAnswers> {\n p.intro('create-teamix-evo');\n p.note(`📦 Target directory: ${seed.dir}`);\n\n const presetId = seed.presetId ?? 'console';\n\n let pm: PackageManager | undefined =\n seed.pm && isValidPackageManager(seed.pm) ? seed.pm : undefined;\n if (!pm) {\n const pmChoice = await p.select<string>({\n message: '包管理器',\n options: [\n { value: 'auto', label: '自动检测(推荐)' },\n { value: 'pnpm', label: 'pnpm' },\n { value: 'npm', label: 'npm' },\n { value: 'yarn', label: 'yarn' },\n ],\n initialValue: 'auto',\n });\n if (p.isCancel(pmChoice)) {\n p.cancel('已取消');\n process.exit(0);\n }\n pm =\n pmChoice === 'auto'\n ? undefined\n : isValidPackageManager(pmChoice as string)\n ? (pmChoice as PackageManager)\n : undefined;\n }\n\n let git = seed.git;\n if (git === undefined) {\n const confirmed = await p.confirm({\n message: '初始化 git 仓库?',\n initialValue: true,\n });\n if (p.isCancel(confirmed)) {\n p.cancel('已取消');\n process.exit(0);\n }\n git = confirmed as boolean;\n }\n\n return { presetId, pm, git };\n}\n"],"mappings":";;;AAAA,OAAOA,WAAU;AACjB,SAAS,eAAe;AACxB,SAAS,OAAAC,YAAW;;;ACFpB,OAAOC,SAAQ;AACf,OAAOC,WAAU;AACjB,SAAS,qBAAqB;AAC9B,SAAS,SAAAC,cAAa;AACtB;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;;;ACTP,OAAO,QAAQ;AACf,OAAO,UAAU;AACjB,OAAO,gBAAgB;AAgBvB,eAAsB,QACpB,QACA,SACA,KACe;AACf,QAAM,GAAG,MAAM,SAAS,EAAE,WAAW,KAAK,CAAC;AAE3C,QAAM,UAAU,MAAM,GAAG,QAAQ,QAAQ,EAAE,eAAe,KAAK,CAAC;AAChE,aAAW,SAAS,SAAS;AAC3B,UAAM,UAAU,KAAK,KAAK,QAAQ,MAAM,IAAI;AAC5C,UAAM,WAAW,YAAY,MAAM,IAAI;AACvC,QAAI,aAAa,KAAM;AACvB,UAAM,WAAW,KAAK,KAAK,SAAS,QAAQ;AAE5C,QAAI,MAAM,YAAY,GAAG;AACvB,YAAM,QAAQ,SAAS,UAAU,GAAG;AACpC;AAAA,IACF;AAEA,QAAI,MAAM,KAAK,SAAS,MAAM,GAAG;AAC/B,YAAM,MAAM,MAAM,GAAG,SAAS,SAAS,MAAM;AAC7C,YAAM,WAAW,WAAW,QAAQ,KAAK,EAAE,UAAU,KAAK,CAAC,EAAE,IAAI,GAAG;AACpE,YAAM,GAAG,UAAU,UAAU,UAAU,MAAM;AAC7C;AAAA,IACF;AAEA,UAAM,GAAG,SAAS,SAAS,QAAQ;AAAA,EACrC;AACF;AAKA,SAAS,YAAY,MAA6B;AAEhD,MAAI,SAAS,6BAA8B,QAAO;AAGlD,MAAI,SAAS,aAAc,QAAO;AAClC,MAAI,SAAS,gBAAiB,QAAO;AACrC,MAAI,SAAS,SAAU,QAAO;AAG9B,MAAI,KAAK,SAAS,MAAM,GAAG;AACzB,WAAO,KAAK,MAAM,GAAG,CAAC,OAAO,MAAM;AAAA,EACrC;AAEA,SAAO;AACT;;;AClEA,SAAS,aAAa;AAOtB,eAAsB,QACpB,KACuD;AACvD,MAAI;AACF,UAAM,MAAM,OAAO,CAAC,QAAQ,SAAS,GAAG,EAAE,IAAI,CAAC;AAC/C,UAAM,MAAM,OAAO,CAAC,OAAO,IAAI,GAAG,EAAE,IAAI,CAAC;AACzC,UAAM;AAAA,MACJ;AAAA,MACA;AAAA,QACE;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,MACA,EAAE,IAAI;AAAA,IACR;AACA,WAAO,EAAE,IAAI,KAAK;AAAA,EACpB,SAAS,KAAK;AACZ,UAAM,SAAS,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAC9D,WAAO,EAAE,IAAI,OAAO,OAAO;AAAA,EAC7B;AACF;;;ACjCA,OAAOC,SAAQ;AAgBR,IAAM,uBAAN,cAAmC,MAAM;AAAA,EAC9C,YACW,KACS,MACT,MACA,UACT;AACA;AAAA,MACE,uBAAuB,GAAG,KAAK,IAAI,iBAAiB,IAAI,kBAAkB,QAAQ;AAAA,IACpF;AAPS;AACS;AACT;AACA;AAKT,SAAK,OAAO;AAAA,EACd;AAAA,EATW;AAAA,EACS;AAAA,EACT;AAAA,EACA;AAOb;AASO,SAAS,iBACd,MACA,SACA,UAAwB,CAAC,GACR;AACjB,QAAM,SAA0B,EAAE,GAAG,KAAK;AAE1C,aAAW,OAAO,CAAC,gBAAgB,mBAAmB,SAAS,GAAY;AACzE,UAAM,UAAW,KAAK,GAAG,KAAK,CAAC;AAC/B,UAAM,aAAc,UAAU,GAAG,KAAK,CAAC;AACvC,UAAM,YACJ,QAAQ,iBACJ,QAAQ,qBAAqB,CAAC,IAC9B,QAAQ,oBACR,QAAQ,wBAAwB,CAAC,IACjC,CAAC;AAEP,UAAM,SAAiC,EAAE,GAAG,QAAQ;AACpD,eAAW,CAAC,MAAM,OAAO,KAAK,OAAO,QAAQ,UAAU,GAAG;AACxD,UAAI,OAAO,IAAI,MAAM,UAAa,OAAO,IAAI,MAAM,SAAS;AAC1D,cAAM,IAAI,qBAAqB,KAAK,MAAM,OAAO,IAAI,GAAG,OAAO;AAAA,MACjE;AACA,aAAO,IAAI,IAAI;AAAA,IACjB;AACA,eAAW,CAAC,MAAM,OAAO,KAAK,OAAO,QAAQ,SAAS,GAAG;AACvD,UAAI,OAAO,IAAI,MAAM,UAAa,OAAO,IAAI,MAAM,SAAS;AAC1D,cAAM,IAAI,qBAAqB,KAAK,MAAM,OAAO,IAAI,GAAG,OAAO;AAAA,MACjE;AACA,aAAO,IAAI,IAAI;AAAA,IACjB;AACA,QAAI,OAAO,KAAK,MAAM,EAAE,SAAS,GAAG;AAClC,aAAO,GAAG,IAAI,gBAAgB,MAAM;AAAA,IACtC;AAAA,EACF;AAEA,SAAO;AACT;AAEA,SAAS,gBAAmD,KAAW;AACrE,QAAM,SAAkC,CAAC;AACzC,aAAW,KAAK,OAAO,KAAK,GAAG,EAAE,KAAK,EAAG,QAAO,CAAC,IAAI,IAAI,CAAC;AAC1D,SAAO;AACT;AAEA,eAAsB,SAAsB,UAA8B;AACxE,QAAM,MAAM,MAAMA,IAAG,SAAS,UAAU,MAAM;AAC9C,SAAO,KAAK,MAAM,GAAG;AACvB;AAEA,eAAsB,UACpB,UACA,OACe;AACf,QAAMA,IAAG,UAAU,UAAU,KAAK,UAAU,OAAO,MAAM,CAAC,IAAI,MAAM,MAAM;AAC5E;;;AChEO,SAAS,qBACd,QACoB;AACpB,QAAM,WAAW,UAAU,oBAAoB,KAAK;AACpD,SAAO,UAAU,QAAQ;AAC3B;AAEO,SAAS,sBAAsB,OAAwC;AAC5E,SAAO,UAAU,UAAU,UAAU,SAAS,UAAU;AAC1D;AAEA,SAAS,sBAA6C;AACpD,QAAM,KAAK,QAAQ,IAAI;AACvB,MAAI,CAAC,GAAI,QAAO;AAChB,QAAM,OAAO,GAAG,MAAM,GAAG,EAAE,CAAC,KAAK;AACjC,MAAI,KAAK,WAAW,MAAM,EAAG,QAAO;AACpC,MAAI,KAAK,WAAW,MAAM,EAAG,QAAO;AACpC,MAAI,KAAK,WAAW,KAAK,EAAG,QAAO;AACnC,SAAO;AACT;AAEA,SAAS,UAAU,MAA0C;AAC3D,UAAQ,MAAM;AAAA,IACZ,KAAK;AACH,aAAO;AAAA,QACL;AAAA,QACA,SAAS,CAAC,SAAS;AAAA,QACnB,KAAK,CAAC,KAAK;AAAA,QACX,gBAAgB;AAAA,QAChB,WAAW;AAAA,MACb;AAAA,IACF,KAAK;AACH,aAAO;AAAA,QACL;AAAA,QACA,SAAS,CAAC,SAAS;AAAA,QACnB,KAAK,CAAC;AAAA,QACN,gBAAgB;AAAA,QAChB,WAAW;AAAA,MACb;AAAA,IACF,KAAK;AAAA,IACL;AACE,aAAO;AAAA,QACL;AAAA,QACA,SAAS,CAAC,SAAS;AAAA,QACnB,KAAK,CAAC,KAAK;AAAA,QACX,gBAAgB;AAAA,QAChB,WAAW;AAAA,MACb;AAAA,EACJ;AACF;;;AC1EO,IAAM,gBAAwB;AAAA,EACnC,IAAI;AAAA,EACJ,aAAa;AAAA,EACb,aACE;AAAA,EACF,cAAc;AAAA,EACd,QAAQ;AAAA,IACN,SAAS;AAAA,IACT,UAAU;AAAA,EACZ;AAAA,EACA,QAAQ;AAAA,IACN,SAAS,CAAC,mBAAmB;AAAA,IAC7B,MAAM,CAAC,SAAS,QAAQ;AAAA,EAC1B;AAAA,EACA,IAAI;AAAA,IACF,YAAY,CAAC,QAAQ;AAAA,EACvB;AAAA,EACA,SAAS;AACX;;;ACfO,IAAM,UAAoB,CAAC,aAAa;AAExC,SAAS,WAAW,IAAgC;AACzD,SAAO,QAAQ,KAAK,CAACC,OAAMA,GAAE,OAAO,EAAE;AACxC;AAEO,SAAS,gBAA0B;AACxC,SAAO,QAAQ,IAAI,CAACA,OAAMA,GAAE,EAAE;AAChC;;;ACbA,SAAS,MAAM,MAAM,KAAK,OAAO,KAAK,cAAc;AAE7C,IAAM,SAAS;AAAA,EACpB,KAAK,SAAuB;AAC1B,YAAQ,IAAI,GAAG,KAAK,QAAG,CAAC,IAAI,OAAO,EAAE;AAAA,EACvC;AAAA,EACA,QAAQ,SAAuB;AAC7B,YAAQ,IAAI,GAAG,MAAM,QAAG,CAAC,IAAI,OAAO,EAAE;AAAA,EACxC;AAAA,EACA,KAAK,SAAuB;AAC1B,YAAQ,KAAK,GAAG,OAAO,QAAG,CAAC,IAAI,OAAO,EAAE;AAAA,EAC1C;AAAA,EACA,MAAM,SAAuB;AAC3B,YAAQ,MAAM,GAAG,IAAI,QAAG,CAAC,IAAI,OAAO,EAAE;AAAA,EACxC;AAAA,EACA,KAAK,SAAuB;AAC1B,YAAQ,IAAI;AAAA,EAAK,KAAK,KAAK,QAAG,CAAC,CAAC,IAAI,KAAK,OAAO,CAAC,EAAE;AAAA,EACrD;AAAA,EACA,OAAO,SAAuB;AAC5B,YAAQ,IAAI,KAAK,IAAI,OAAO,CAAC,EAAE;AAAA,EACjC;AAAA,EACA,QAAc;AACZ,YAAQ,IAAI,EAAE;AAAA,EAChB;AACF;;;APqBA,SAAS,iBAAyB;AAEhC,QAAM,OAAOC,MAAK,QAAQ,cAAc,YAAY,GAAG,CAAC;AAExD,SAAOA,MAAK,QAAQ,MAAM,IAAI;AAChC;AAiBA,eAAsB,YAAY,SAA4C;AAC5E,QAAM,SAAS,WAAW,QAAQ,QAAQ;AAC1C,MAAI,CAAC,QAAQ;AACX,UAAM,IAAI;AAAA,MACR,mBAAmB,QAAQ,QAAQ;AAAA,IACrC;AAAA,EACF;AAEA,QAAM,MAAMA,MAAK,QAAQ,QAAQ,GAAG;AACpC,QAAM,iBAAiB,KAAK,QAAQ,SAAS,KAAK;AAElD,QAAM,SAAS,qBAAqB,QAAQ,EAAE;AAC9C,QAAM,cAAcA,MAAK,SAAS,GAAG;AACrC,QAAM,UAAU,eAAe;AAG/B,SAAO,KAAK,gCAAY;AACxB,QAAM,kBAAkBA,MAAK,KAAK,SAAS,aAAa,OAAO,YAAY;AAC3E,QAAM,SAAS,gBAAgB,EAAE,QAAQ,aAAa,OAAO,CAAC;AAC9D,QAAM,QAAQ,iBAAiB,KAAK,EAAE,KAAK,OAAO,CAAC;AACnD,SAAO,OAAO,SAAS,OAAO,YAAY,EAAE;AAG5C,MAAI,OAAO,SAAS;AAClB,WAAO,KAAK,yBAAe,OAAO,OAAO,EAAE;AAC3C,UAAM,aAAaA,MAAK,KAAK,SAAS,YAAY,OAAO,OAAO;AAChE,UAAM,QAAQ,YAAY,KAAK,EAAE,KAAK,OAAO,CAAC;AAAA,EAChD;AAGA,SAAO,KAAK,4BAAkB;AAC9B,QAAM,eAAe,MAAM,cAAc;AAAA,IACvC,aAAa;AAAA,IACb,SAAS,OAAO,OAAO;AAAA,IACvB,KAAK;AAAA,EACP,CAAC;AACD,MAAI,aAAa,WAAW,aAAa;AACvC,WAAO;AAAA,MACL,GAAG,aAAa,WAAW,IAAI,aAAa,OAAO,KAAK,aAAa,KAAK;AAAA,IAC5E;AAAA,EACF;AAGA,SAAO,KAAK,wBAAc;AAC1B,QAAM,eAAe,MAAM,aAAa;AAAA,IACtC,aAAa;AAAA,IACb,MAAM,OAAO,OAAO;AAAA,IACpB,OAAO;AAAA,EACT,CAAC;AACD,MAAI,aAAa,WAAW,aAAa;AACvC,WAAO;AAAA,MACL,GAAG,aAAa,UAAU,oBAAe,aAAa,KAAK,KAAK,KAAK,CAAC;AAAA,IACxE;AAAA,EACF;AAGA,SAAO,KAAK,iBAAO;AACnB,QAAM,UAAU,EAAE,aAAa,IAAI,CAAC;AACpC,MAAI,YAAoC,CAAC;AACzC,MAAI,OAAO,GAAG,WAAW,SAAS,GAAG;AACnC,UAAM,cAAc,MAAM,SAAS;AAAA,MACjC,aAAa;AAAA,MACb,KAAK,OAAO,GAAG;AAAA,IACjB,CAAC;AACD,gBAAY,YAAY;AACxB,WAAO;AAAA,MACL,cAAc,YAAY,WAAW,KAAK,IAAI,CAAC,KAC7C,YAAY,OACd;AAAA,IACF;AAAA,EACF,OAAO;AACL,WAAO,OAAO,oDAAsB;AAAA,EACtC;AAGA,SAAO,KAAK,2BAAiB;AAC7B,QAAM,wBAAwB;AAAA,IAC5B;AAAA,IACA,qBAAqB,OAAO,UACxBA,MAAK;AAAA,MACH;AAAA,MACA;AAAA,MACA,OAAO;AAAA,MACP;AAAA,IACF,IACA;AAAA,IACJ,mBAAmB;AAAA,EACrB,CAAC;AAGD,MAAI,OAAO,YAAY,WAAW;AAChC,UAAM,eAAe,KAAK,OAAO,EAAE;AACnC,WAAO,OAAO,uDAAwC;AAAA,EACxD;AAGA,MAAI,QAAQ,SAAS;AACnB,WAAO,KAAK,iCAAQ,OAAO,cAAc,QAAG;AAC5C,QAAI;AACF,YAAMC,OAAM,OAAO,MAAM,OAAO,SAAS,EAAE,KAAK,KAAK,OAAO,UAAU,CAAC;AAAA,IACzE,SAAS,KAAK;AACZ,aAAO;AAAA,QACL,sFACED,MAAK,SAAS,QAAQ,IAAI,GAAG,GAAG,KAAK,GACvC,OAAO,OAAO,cAAc;AAAA,MAC9B;AACA,UAAI,eAAe,MAAO,QAAO,OAAO,IAAI,OAAO;AAAA,IACrD;AAAA,EACF,OAAO;AACL,WAAO,OAAO,2EAAe,OAAO,cAAc,QAAG;AAAA,EACvD;AAGA,MAAI,QAAQ,KAAK;AACf,WAAO,KAAK,wBAAS;AACrB,UAAM,SAAS,MAAM,QAAQ,GAAG;AAChC,QAAI,OAAO,GAAI,QAAO,OAAO,yEAAuB;AAAA,QAC/C,QAAO,KAAK,8BAAe,OAAO,MAAM,EAAE;AAAA,EACjD;AAGA,iBAAe,EAAE,KAAK,QAAQ,OAAO,CAAC;AACxC;AAEA,eAAe,iBAAiB,KAAa,OAA+B;AAC1E,MAAI,SAAS;AACb,MAAI;AACF,UAAME,IAAG,OAAO,GAAG;AACnB,aAAS;AAAA,EACX,QAAQ;AAAA,EAER;AAEA,MAAI,CAAC,QAAQ;AACX,UAAMA,IAAG,MAAM,KAAK,EAAE,WAAW,KAAK,CAAC;AACvC;AAAA,EACF;AAEA,QAAM,UAAU,MAAMA,IAAG,QAAQ,GAAG;AACpC,MAAI,QAAQ,WAAW,EAAG;AAG1B,MAAI,QAAQ,SAAS,aAAa,GAAG;AACnC,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AAEA,MAAI,CAAC,OAAO;AACV,UAAM,IAAI;AAAA,MACR,qBAAqB,GAAG;AAAA,IAC1B;AAAA,EACF;AACA,SAAO,KAAK,qDAAkB,GAAG,EAAE;AACrC;AAEA,SAAS,gBAAgB,MAIG;AAC1B,QAAM,EAAE,QAAQ,aAAa,OAAO,IAAI;AACxC,SAAO;AAAA,IACL;AAAA,IACA,eAAe,OAAO,OAAO;AAAA,IAC7B,WAAW,OAAO;AAAA,IAClB,OAAO,OAAO;AAAA,IACd,aACE,OAAO,GAAG,WAAW,SAAS,IAC1B,OAAO,GAAG,WAAW,KAAK,IAAI,IAC9B;AAAA,EACR;AACF;AAEA,eAAe,wBAAwB,MAIrB;AAChB,QAAM,UAAUF,MAAK,KAAK,KAAK,KAAK,cAAc;AAClD,QAAM,OAAO,MAAM,SAAkC,OAAO;AAC5D,MAAI,UAA0C;AAC9C,MAAI,KAAK,qBAAqB;AAC5B,QAAI;AACF,gBAAU,MAAM;AAAA,QACd,KAAK;AAAA,MACP;AAAA,IACF,QAAQ;AACN,gBAAU;AAAA,IACZ;AAAA,EACF;AACA,MAAI;AACF,UAAM,SAAS,iBAAiB,MAAM,SAAS;AAAA,MAC7C,mBAAmB,KAAK;AAAA,IAC1B,CAAC;AACD,UAAM,UAAU,SAAS,MAAM;AAAA,EACjC,SAAS,KAAK;AACZ,QAAI,eAAe,sBAAsB;AACvC,YAAM,IAAI;AAAA,QACR,8CAAqB,IAAI,OAAO;AAAA;AAAA,MAElC;AAAA,IACF;AACA,UAAM;AAAA,EACR;AACF;AAEA,eAAe,eAAe,KAAa,UAAiC;AAC1E,QAAM,aAAaA,MAAK,KAAK,KAAK,eAAe,QAAQ;AACzD,QAAME,IAAG,MAAM,YAAY,EAAE,WAAW,KAAK,CAAC;AAC9C,QAAM,cAAcF,MAAK,KAAK,YAAY,iBAAiB;AAC3D,QAAM,UAAU;AAAA,IACd,SAAS;AAAA,IACT,eAAe;AAAA,IACf,QAAQ;AAAA,IACR,mBAAmB;AAAA,MACjB,EAAE,IAAI,QAAQ,aAAa,uCAAuC;AAAA,MAClE,EAAE,IAAI,SAAS,aAAa,wCAAwC;AAAA,MACpE,EAAE,IAAI,QAAQ,aAAa,uCAAuC;AAAA,MAClE,EAAE,IAAI,SAAS,aAAa,wCAAwC;AAAA,IACtE;AAAA,EACF;AACA,QAAM,UAAU,aAAa,OAAO;AACtC;AAEA,SAAS,eAAe,MAIf;AACP,QAAM,EAAE,KAAK,QAAQ,OAAO,IAAI;AAChC,QAAM,MAAMA,MAAK,SAAS,QAAQ,IAAI,GAAG,GAAG,KAAK;AACjD,SAAO,MAAM;AACb,SAAO,QAAQ,GAAG,OAAO,WAAW,mCAAe,GAAG,EAAE;AACxD,SAAO,MAAM;AACb,UAAQ,IAAI,aAAa;AACzB,UAAQ,IAAI,QAAQ,GAAG,EAAE;AACzB,UAAQ;AAAA,IACN,KAAK,OAAO,SAAS,GAAG,OAAO,cAAc,SAAS,MAAM,GAAG;AAAA,EACjE;AACA,MAAI,OAAO,OAAO,WAAW;AAC3B,WAAO,MAAM;AACb,YAAQ;AAAA,MACN;AAAA,IACF;AAAA,EACF;AACF;;;AQzTA,YAAY,OAAO;AAanB,eAAsB,cAAc,MAKJ;AAC9B,EAAE,QAAM,mBAAmB;AAC3B,EAAE,OAAK,gCAAyB,KAAK,GAAG,EAAE;AAE1C,QAAM,WAAW,KAAK,YAAY;AAElC,MAAI,KACF,KAAK,MAAM,sBAAsB,KAAK,EAAE,IAAI,KAAK,KAAK;AACxD,MAAI,CAAC,IAAI;AACP,UAAM,WAAW,MAAQ,SAAe;AAAA,MACtC,SAAS;AAAA,MACT,SAAS;AAAA,QACP,EAAE,OAAO,QAAQ,OAAO,mDAAW;AAAA,QACnC,EAAE,OAAO,QAAQ,OAAO,OAAO;AAAA,QAC/B,EAAE,OAAO,OAAO,OAAO,MAAM;AAAA,QAC7B,EAAE,OAAO,QAAQ,OAAO,OAAO;AAAA,MACjC;AAAA,MACA,cAAc;AAAA,IAChB,CAAC;AACD,QAAM,WAAS,QAAQ,GAAG;AACxB,MAAE,SAAO,oBAAK;AACd,cAAQ,KAAK,CAAC;AAAA,IAChB;AACA,SACE,aAAa,SACT,SACA,sBAAsB,QAAkB,IACvC,WACD;AAAA,EACR;AAEA,MAAI,MAAM,KAAK;AACf,MAAI,QAAQ,QAAW;AACrB,UAAM,YAAY,MAAQ,UAAQ;AAAA,MAChC,SAAS;AAAA,MACT,cAAc;AAAA,IAChB,CAAC;AACD,QAAM,WAAS,SAAS,GAAG;AACzB,MAAE,SAAO,oBAAK;AACd,cAAQ,KAAK,CAAC;AAAA,IAChB;AACA,UAAM;AAAA,EACR;AAEA,SAAO,EAAE,UAAU,IAAI,IAAI;AAC7B;;;AT5CA,eAAe,OAAsB;AACnC,QAAM,UAAU,IAAI,QAAQ;AAE5B,UACG,KAAK,mBAAmB,EACxB;AAAA,IACC;AAAA,EACF,EACC;AAAA,IACC;AAAA,IACA;AAAA,EACF,EACC,OAAO,iBAAiB,cAAc,cAAc,EAAE,KAAK,KAAK,CAAC,GAAG,EACpE,OAAO,eAAe,oCAAoC,EAC1D,OAAO,YAAY,eAAe,EAClC,OAAO,gBAAgB,8BAA8B,EACrD,OAAO,WAAW,sCAAsC,EACxD,WAAW,cAAc,cAAc;AAE1C,UAAQ,MAAM,QAAQ,IAAI;AAC1B,QAAM,OAAO,QAAQ,KAAiB;AACtC,QAAM,SAAS,QAAQ,KAAK,CAAC;AAG7B,QAAM,MAAM,SACRG,MAAK,QAAQ,MAAM,IACnBA,MAAK,QAAQ,QAAQ,IAAI,GAAG,QAAQ;AACxC,MAAI,CAAC,QAAQ;AACX,WAAO,KAAK,iFAAgB,GAAG,EAAE;AAAA,EACnC;AAGA,MAAI,KAAK,UAAU,CAAC,cAAc,EAAE,SAAS,KAAK,MAAM,GAAG;AACzD,WAAO;AAAA,MACL,wBAAc,KAAK,MAAM,4BAAQ,cAAc,EAAE,KAAK,IAAI,CAAC;AAAA,IAC7D;AACA,YAAQ,KAAK,CAAC;AAAA,EAChB;AACA,MAAI,KAAK,MAAM,CAAC,sBAAsB,KAAK,EAAE,GAAG;AAC9C,WAAO,MAAM,yCAAW,KAAK,EAAE,4CAAwB;AACvD,YAAQ,KAAK,CAAC;AAAA,EAChB;AAGA,MAAI,WAAW,KAAK,UAAU;AAC9B,MAAI,KAAK,KAAK;AACd,MAAI,MAAM,KAAK;AACf,MAAI,QAAQ,MAAM,SAAS,QAAQ,QAAW;AAC5C,UAAM,UAAU,MAAM,cAAc;AAAA,MAClC;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF,CAAC;AACD,eAAW,QAAQ;AACnB,UAAM,QAAQ;AACd,QAAI,QAAQ,GAAI,MAAK,QAAQ;AAAA,EAC/B,OAAO;AACL,UAAM,OAAO;AAAA,EACf;AAEA,MAAI;AACF,UAAM,YAAY;AAAA,MAChB;AAAA,MACA;AAAA,MACA,IAAI,MAAM,sBAAsB,EAAE,IAAI,KAAK;AAAA,MAC3C,SAAS,KAAK,WAAW;AAAA,MACzB,KAAK,OAAO;AAAA,MACZ,OAAO,KAAK,SAAS;AAAA,IACvB,CAAC;AAAA,EACH,SAAS,KAAK;AACZ,UAAM,UAAU,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAC/D,YAAQ,MAAM;AAAA,EAAKC,KAAI,QAAG,CAAC,IAAI,OAAO,EAAE;AACxC,YAAQ,KAAK,CAAC;AAAA,EAChB;AACF;AAEA,KAAK,EAAE,MAAM,CAAC,QAAQ;AACpB,UAAQ,MAAM;AAAA,EAAKA,KAAI,QAAG,CAAC,uCAAS;AACpC,UAAQ,MAAM,GAAG;AACjB,UAAQ,KAAK,CAAC;AAChB,CAAC;","names":["path","red","fs","path","execa","fs","p","path","execa","fs","path","red"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/orchestrator.ts","../src/copy.ts","../src/git.ts","../src/merge-package-json.ts","../src/pm.ts","../src/presets/console.ts","../src/presets/index.ts","../src/utils/logger.ts","../src/prompts.ts"],"sourcesContent":["import path from 'node:path';\nimport { Command } from 'commander';\nimport { red } from 'kolorist';\nimport { orchestrate } from './orchestrator.js';\nimport { listPresetIds } from './presets/index.js';\nimport { isValidPackageManager } from './pm.js';\nimport { promptMissing } from './prompts.js';\nimport { logger } from './utils/logger.js';\n\ninterface CliOptions {\n preset?: string;\n variant?: string;\n pm?: string;\n /** commander treats `--no-git` as `git: false`. */\n git?: boolean;\n /** commander treats `--no-install` as `install: false`. */\n install?: boolean;\n force?: boolean;\n}\n\nasync function main(): Promise<void> {\n const program = new Command();\n\n program\n .name('create-teamix-evo')\n .description(\n 'Scaffold a Vite + React + TypeScript project pre-wired with Teamix Evo design tokens, AI skills, and UI components.',\n )\n .argument(\n '[dir]',\n 'target directory (will be created if it does not exist)',\n )\n .option('--preset <id>', `preset id (${listPresetIds().join(' | ')})`)\n .option(\n '--variant <name>',\n 'tokens variant (e.g. opentrek | uni-manager); 不传则交互询问',\n )\n .option('--pm <name>', 'package manager: pnpm | npm | yarn')\n .option('--no-git', 'skip git init')\n .option('--no-install', 'skip dependency installation')\n .option('--force', 'overwrite non-empty target directory')\n .helpOption('-h, --help', 'display help');\n\n program.parse(process.argv);\n const opts = program.opts<CliOptions>();\n const dirArg = program.args[0];\n\n // Resolve target directory (interactive only if no dirArg).\n const dir = dirArg\n ? path.resolve(dirArg)\n : path.resolve(process.cwd(), 'my-app');\n if (!dirArg) {\n logger.warn(`未指定目录,使用默认路径:${dir}`);\n }\n\n // Validate --preset / --pm if provided\n if (opts.preset && !listPresetIds().includes(opts.preset)) {\n logger.error(\n `未知 preset \"${opts.preset}\"。可选:${listPresetIds().join(', ')}`,\n );\n process.exit(1);\n }\n if (opts.pm && !isValidPackageManager(opts.pm)) {\n logger.error(`未知包管理器 \"${opts.pm}\"。可选:pnpm | npm | yarn`);\n process.exit(1);\n }\n\n // Interactive prompts for missing fields (when running in a TTY).\n let presetId = opts.preset ?? 'console';\n let pm = opts.pm;\n let git = opts.git;\n let variant = opts.variant;\n if (process.stdin.isTTY && (git === undefined || variant === undefined)) {\n const answers = await promptMissing({\n dir,\n presetId,\n pm,\n git,\n variant,\n });\n presetId = answers.presetId;\n git = answers.git;\n if (answers.pm) pm = answers.pm;\n variant = answers.variant;\n } else {\n git = git ?? true;\n }\n\n try {\n await orchestrate({\n dir,\n presetId: presetId!,\n variant,\n pm: pm && isValidPackageManager(pm) ? pm : undefined,\n install: opts.install ?? true,\n git: git ?? true,\n force: opts.force ?? false,\n });\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n console.error(`\\n${red('✗')} ${message}`);\n process.exit(1);\n }\n}\n\nmain().catch((err) => {\n console.error(`\\n${red('✗')} 未捕获的错误`);\n console.error(err);\n process.exit(1);\n});\n","import fs from 'node:fs/promises';\nimport path from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport { execa } from 'execa';\nimport {\n runTokensInit,\n runSkillsAdd,\n runUiInit,\n runUiAdd,\n listTokenVariants,\n} from 'teamix-evo/core';\nimport { copyDir } from './copy.js';\nimport { gitInit } from './git.js';\nimport {\n mergePackageJson,\n readJson,\n writeJson,\n VersionConflictError,\n} from './merge-package-json.js';\nimport {\n detectPackageManager,\n type PackageManager,\n type PackageManagerInfo,\n} from './pm.js';\nimport { findPreset, type Preset } from './presets/index.js';\nimport { logger } from './utils/logger.js';\n\nexport interface OrchestrateOptions {\n /** Absolute target directory. */\n dir: string;\n /** Preset id. */\n presetId: string;\n /**\n * Tokens variant override. Falls back to `preset.tokens.variant` when\n * unspecified. Validated against `@teamix-evo/tokens` manifest.\n */\n variant?: string;\n /** Preferred package manager (else auto-detect). */\n pm?: PackageManager;\n /** Run package manager install at the end. */\n install: boolean;\n /** Run git init at the end. */\n git: boolean;\n /** Overwrite non-empty target directory. */\n force?: boolean;\n}\n\n/**\n * Locate the create-teamix-evo package root (regardless of whether running\n * from source via tsx, or from `dist/index.js` after bundling).\n */\nfunction getPackageRoot(): string {\n // Resolves to <pkg>/dist/index.js.map's directory in dev/build.\n const here = path.dirname(fileURLToPath(import.meta.url));\n // From dist/ go up to package root.\n return path.resolve(here, '..');\n}\n\n/**\n * Main scaffolding pipeline.\n *\n * Order:\n * 1. validate target dir\n * 2. copy base template (renders all `.hbs`)\n * 3. copy overlay if any\n * 4. teamix-evo tokens init\n * 5. teamix-evo skills add\n * 6. teamix-evo ui init + ui add\n * 7. rewrite package.json (base + overlay fragment + ui npm deps)\n * 8. write pending-ui.json (if overlay declares placeholders)\n * 9. install deps\n * 10. git init\n */\nexport async function orchestrate(options: OrchestrateOptions): Promise<void> {\n const preset = findPreset(options.presetId);\n if (!preset) {\n throw new Error(\n `Unknown preset \"${options.presetId}\". Available: console.`,\n );\n }\n\n const dir = path.resolve(options.dir);\n await prepareTargetDir(dir, options.force ?? false);\n\n const variant = await resolveVariant(options.variant, preset);\n\n const pmInfo = detectPackageManager(options.pm);\n const projectName = path.basename(dir);\n const pkgRoot = getPackageRoot();\n\n // ─── 1. base template ───────────────────────────────────────────────────\n logger.step('拷贝 base 模板');\n const baseTemplateDir = path.join(pkgRoot, 'templates', preset.baseTemplate);\n const hbsCtx = buildHbsContext({ preset, variant, projectName, pmInfo });\n await copyDir(baseTemplateDir, dir, { hbs: hbsCtx });\n logger.detail(`base: ${preset.baseTemplate}`);\n\n // ─── 2. overlay ─────────────────────────────────────────────────────────\n if (preset.overlay) {\n logger.step(`应用 overlay: ${preset.overlay}`);\n const overlayDir = path.join(pkgRoot, 'overlays', preset.overlay);\n await copyDir(overlayDir, dir, { hbs: hbsCtx });\n }\n\n // ─── 3. design tokens ───────────────────────────────────────────────────\n logger.step(`装载 design tokens (variant=${variant})`);\n const tokensResult = await runTokensInit({\n projectRoot: dir,\n variant,\n ide: 'qoder',\n });\n if (tokensResult.status === 'installed') {\n logger.detail(\n `${tokensResult.packageName}@${tokensResult.version} (${tokensResult.count} files)`,\n );\n }\n\n // ─── 4. AI skills ───────────────────────────────────────────────────────\n // Expand `${variant}` placeholder in preset.skills.entries.\n // tokens init may have already installed teamix-evo-design-<variant>; pass\n // `names` (incremental mode) so skills-add skips installed ones and adds\n // the rest (manage / code-<variant>) instead of short-circuiting on\n // 'already-added' (#3).\n const expandedSkillNames = preset.skills.entries.map((id) =>\n id.replace(/\\$\\{variant\\}/g, variant),\n );\n logger.step('装载 AI skills');\n const skillsResult = await runSkillsAdd({\n projectRoot: dir,\n names: expandedSkillNames,\n ides: preset.skills.ides,\n scope: 'project',\n });\n if (skillsResult.status === 'installed') {\n logger.detail(\n `${skillsResult.skillCount + skillsResult.skippedSkillIds.length} skill(s) → ${skillsResult.ides.join(\n ' + ',\n )} (added: ${skillsResult.addedSkillIds.join(', ') || 'none'}; existing: ${\n skillsResult.skippedSkillIds.join(', ') || 'none'\n })`,\n );\n }\n\n // ─── 5. ui init + ui add ────────────────────────────────────────────────\n logger.step('配置 UI');\n await runUiInit({ projectRoot: dir });\n let uiAddDeps: Record<string, string> = {};\n if (preset.ui.components.length > 0) {\n const uiAddResult = await runUiAdd({\n projectRoot: dir,\n ids: preset.ui.components,\n });\n uiAddDeps = uiAddResult.npmDependencies;\n logger.detail(\n `installed: ${uiAddResult.orderedIds.join(', ')} (${\n uiAddResult.written\n } files)`,\n );\n } else {\n logger.detail('ui init only — 无组件落地');\n }\n\n // ─── 6. merge package.json ──────────────────────────────────────────────\n logger.step('合并 package.json');\n await mergeProjectPackageJson({\n dir,\n overlayFragmentPath: preset.overlay\n ? path.join(\n pkgRoot,\n 'overlays',\n preset.overlay,\n 'package.json.fragment.json',\n )\n : null,\n extraDependencies: uiAddDeps,\n });\n\n // ─── 7. pending-ui.json ─────────────────────────────────────────────────\n if (preset.overlay === 'console') {\n await writePendingUi(dir, preset.id);\n logger.detail('.teamix-evo/create/pending-ui.json 已写入');\n }\n\n // ─── 7b. .mcp.json ──────────────────────────────────────────────────────\n // Bootstraps the MCP server entry so AI IDEs (Cursor / Claude Code / Cline)\n // can discover it without manual config (#1). The server reads ui registry\n // from node_modules/@teamix-evo/ui, ADR snapshot from bundled mcp dist,\n // and skills from node_modules/@teamix-evo/skills — all installed below.\n await writeMcpJson(dir);\n logger.detail('.mcp.json 已写入');\n\n // ─── 8. install deps ────────────────────────────────────────────────────\n if (options.install) {\n logger.step(`安装依赖(${pmInfo.installCommand})`);\n try {\n await execa(pmInfo.name, pmInfo.install, { cwd: dir, stdio: 'inherit' });\n } catch (err) {\n logger.warn(\n `依赖安装失败 — 可手动执行:cd ${\n path.relative(process.cwd(), dir) || '.'\n } && ${pmInfo.installCommand}`,\n );\n if (err instanceof Error) logger.detail(err.message);\n }\n } else {\n logger.detail(`跳过依赖安装(手动执行:${pmInfo.installCommand})`);\n }\n\n // ─── 9. git init ────────────────────────────────────────────────────────\n if (options.git) {\n logger.step('初始化 git');\n const result = await gitInit(dir);\n if (result.ok) logger.detail('git 仓库已就绪(含首个 commit)');\n else logger.warn(`git init 失败:${result.reason}`);\n }\n\n // ─── done ───────────────────────────────────────────────────────────────\n printNextSteps({ dir, pmInfo, preset });\n}\n\nasync function prepareTargetDir(dir: string, force: boolean): Promise<void> {\n let exists = false;\n try {\n await fs.access(dir);\n exists = true;\n } catch {\n /* not exists */\n }\n\n if (!exists) {\n await fs.mkdir(dir, { recursive: true });\n return;\n }\n\n const entries = await fs.readdir(dir);\n if (entries.length === 0) return;\n\n if (entries.includes('.teamix-evo')) {\n if (!force) {\n // Default: keep prior teamix-evo install intact, point user at the\n // right command (#10).\n throw new Error(\n `Target directory already contains a .teamix-evo/ — please run \\`teamix-evo tokens init\\` inside it instead of using create-teamix-evo. ` +\n `Or pass --force to wipe the directory and rebuild from scratch.`,\n );\n }\n // --force on existing teamix-evo project: wipe everything (#10 #37).\n logger.warn(`--force:删除已有 teamix-evo 工程后重建 ${dir}`);\n await fs.rm(dir, { recursive: true, force: true });\n await fs.mkdir(dir, { recursive: true });\n return;\n }\n\n if (!force) {\n throw new Error(\n `Target directory \"${dir}\" is not empty. Use --force to overwrite.`,\n );\n }\n // --force on non-empty non-teamix-evo dir: wipe and rebuild.\n logger.warn(`--force:覆盖已有目录 ${dir}`);\n await fs.rm(dir, { recursive: true, force: true });\n await fs.mkdir(dir, { recursive: true });\n}\n\nfunction buildHbsContext(args: {\n preset: Preset;\n variant: string;\n projectName: string;\n pmInfo: PackageManagerInfo;\n}): Record<string, unknown> {\n const { preset, variant, projectName, pmInfo } = args;\n return {\n projectName,\n tokensVariant: variant,\n pmInstall: pmInfo.installCommand,\n pmRun: pmInfo.runPrefix,\n uiInstalled:\n preset.ui.components.length > 0\n ? preset.ui.components.join(', ')\n : '(无)',\n };\n}\n\n/**\n * Resolve the final tokens variant. Validates against the live\n * `@teamix-evo/tokens` manifest so typos like `unimanager` (no dash) fail at\n * the create-teamix-evo CLI surface, before runTokensInit which would emit a\n * deeper stack-trace.\n */\nasync function resolveVariant(\n override: string | undefined,\n preset: Preset,\n): Promise<string> {\n const candidate = override ?? preset.tokens.variant;\n let known: string[] = [];\n try {\n const catalog = await listTokenVariants();\n known = catalog.variants.map((v) => v.name);\n } catch {\n // Manifest unreachable (offline / monorepo dev): trust the candidate.\n return candidate;\n }\n if (!known.includes(candidate)) {\n throw new Error(\n `Unknown tokens variant \"${candidate}\". Available: ${known.join(', ')}.\\n` +\n ` Hint: run \\`npx teamix-evo tokens list-variants\\` to see all variants.`,\n );\n }\n return candidate;\n}\n\nasync function mergeProjectPackageJson(args: {\n dir: string;\n overlayFragmentPath: string | null;\n extraDependencies: Record<string, string>;\n}): Promise<void> {\n const pkgPath = path.join(args.dir, 'package.json');\n const base = await readJson<Record<string, unknown>>(pkgPath);\n let overlay: Record<string, unknown> | null = null;\n if (args.overlayFragmentPath) {\n try {\n overlay = await readJson<Record<string, unknown>>(\n args.overlayFragmentPath,\n );\n } catch {\n overlay = null;\n }\n }\n try {\n const merged = mergePackageJson(base, overlay, {\n extraDependencies: args.extraDependencies,\n });\n await writeJson(pkgPath, merged);\n } catch (err) {\n if (err instanceof VersionConflictError) {\n throw new Error(\n `package.json 合并失败:${err.message}\\n` +\n `请检查 base 模板与 overlay/ui 组件依赖的版本声明,确保一致。`,\n );\n }\n throw err;\n }\n}\n\nasync function writePendingUi(dir: string, presetId: string): Promise<void> {\n const pendingDir = path.join(dir, '.teamix-evo', 'create');\n await fs.mkdir(pendingDir, { recursive: true });\n const pendingPath = path.join(pendingDir, 'pending-ui.json');\n // Lowercase placeholder filenames to match ui registry id casing (#7).\n // Avoids macOS case-insensitive FS pitfalls during placeholder→real swap.\n const payload = {\n $schema: 'https://teamix-evo.dev/schema/pending-ui/v1.json',\n schemaVersion: 1,\n preset: presetId,\n pendingComponents: [\n { id: 'card', placeholder: 'src/components/_placeholder/card.tsx' },\n { id: 'input', placeholder: 'src/components/_placeholder/input.tsx' },\n { id: 'form', placeholder: 'src/components/_placeholder/form.tsx' },\n { id: 'table', placeholder: 'src/components/_placeholder/table.tsx' },\n ],\n };\n await writeJson(pendingPath, payload);\n}\n\n/**\n * Write a project-root `.mcp.json` (#1). Supported by Cursor / Claude Code /\n * Cline — they pick it up automatically without further config.\n *\n * The server itself is `@teamix-evo/mcp`, installed as a devDependency by\n * mergeProjectPackageJson below. `npx -y @teamix-evo/mcp` resolves the local\n * install (no global state, no version drift).\n */\nasync function writeMcpJson(dir: string): Promise<void> {\n const mcpJson = {\n mcpServers: {\n 'teamix-evo': {\n command: 'npx',\n args: ['-y', '@teamix-evo/mcp'],\n },\n },\n };\n await writeJson(path.join(dir, '.mcp.json'), mcpJson);\n}\n\nfunction printNextSteps(args: {\n dir: string;\n pmInfo: PackageManagerInfo;\n preset: Preset;\n}): void {\n const { dir, pmInfo, preset } = args;\n const rel = path.relative(process.cwd(), dir) || '.';\n logger.blank();\n logger.success(`${preset.displayName} preset 已就绪:${dir}`);\n logger.blank();\n console.log('Next steps:');\n console.log(` cd ${rel}`);\n console.log(\n ` ${pmInfo.runPrefix}${pmInfo.runPrefix === 'yarn' ? ' ' : ' '}dev`,\n );\n if (preset.id === 'console') {\n logger.blank();\n console.log(\n '💡 console preset 内含占位组件,可用 `npx teamix-evo ui add card` 等替换为真组件。',\n );\n }\n}\n","import fs from 'node:fs/promises';\nimport path from 'node:path';\nimport Handlebars from 'handlebars';\n\nexport interface CopyContext {\n /** Handlebars render context for `.hbs` templates. */\n hbs: Record<string, unknown>;\n}\n\n/**\n * Recursively copy `srcDir` into `destDir`, applying:\n * - `.hbs` files: rendered with `ctx.hbs`, written without `.hbs` extension\n * - `_gitignore` / `_editorconfig` etc. → `.gitignore` / `.editorconfig`\n * - Skips `package.json.fragment.json` (handled separately by the merger)\n *\n * Existing files are overwritten — call site is responsible for `--force`\n * / clean-target semantics.\n */\nexport async function copyDir(\n srcDir: string,\n destDir: string,\n ctx: CopyContext,\n): Promise<void> {\n await fs.mkdir(destDir, { recursive: true });\n\n const entries = await fs.readdir(srcDir, { withFileTypes: true });\n for (const entry of entries) {\n const srcPath = path.join(srcDir, entry.name);\n const destName = mapDestName(entry.name);\n if (destName === null) continue; // explicitly skipped\n const destPath = path.join(destDir, destName);\n\n if (entry.isDirectory()) {\n await copyDir(srcPath, destPath, ctx);\n continue;\n }\n\n if (entry.name.endsWith('.hbs')) {\n const tpl = await fs.readFile(srcPath, 'utf8');\n const rendered = Handlebars.compile(tpl, { noEscape: true })(ctx.hbs);\n await fs.writeFile(destPath, rendered, 'utf8');\n continue;\n }\n\n await fs.copyFile(srcPath, destPath);\n }\n}\n\n/**\n * Translate a source filename to its destination filename, or `null` to skip.\n */\nfunction mapDestName(name: string): string | null {\n // Skip the package.json fragment — orchestrator merges it into base.\n if (name === 'package.json.fragment.json') return null;\n\n // _gitignore → .gitignore (npm strips real `.gitignore` from packed tarballs)\n if (name === '_gitignore') return '.gitignore';\n if (name === '_editorconfig') return '.editorconfig';\n if (name === '_npmrc') return '.npmrc';\n\n // Strip .hbs extension\n if (name.endsWith('.hbs')) {\n return name.slice(0, -'.hbs'.length);\n }\n\n return name;\n}\n","import { execa } from 'execa';\n\n/**\n * Initialize a fresh git repo with a single commit. Best-effort:\n * any failure is reported as `{ ok: false }` instead of throwing —\n * scaffolding should not fail just because git is missing.\n */\nexport async function gitInit(\n cwd: string,\n): Promise<{ ok: true } | { ok: false; reason: string }> {\n try {\n await execa('git', ['init', '--quiet'], { cwd });\n await execa('git', ['add', '-A'], { cwd });\n await execa(\n 'git',\n [\n '-c',\n 'user.email=create-teamix-evo@local',\n '-c',\n 'user.name=create-teamix-evo',\n 'commit',\n '--quiet',\n '--no-gpg-sign',\n '-m',\n 'chore: scaffolded by create-teamix-evo',\n ],\n { cwd },\n );\n return { ok: true };\n } catch (err) {\n const reason = err instanceof Error ? err.message : String(err);\n return { ok: false, reason };\n }\n}\n","import fs from 'node:fs/promises';\n\ninterface PackageJsonLike {\n [key: string]: unknown;\n dependencies?: Record<string, string>;\n devDependencies?: Record<string, string>;\n scripts?: Record<string, string>;\n}\n\nexport interface MergeOptions {\n /** Extra dependencies (e.g. from `runUiAdd`) merged with conflict checks. */\n extraDependencies?: Record<string, string>;\n /** Extra dev dependencies merged with conflict checks. */\n extraDevDependencies?: Record<string, string>;\n}\n\nexport class VersionConflictError extends Error {\n constructor(\n readonly key: 'dependencies' | 'devDependencies' | 'scripts',\n override readonly name: string,\n readonly base: string,\n readonly incoming: string,\n ) {\n super(\n `Version conflict in ${key}: ${name} declared as \"${base}\" in base but \"${incoming}\" in overlay/extras.`,\n );\n this.name = 'VersionConflictError';\n }\n}\n\n/**\n * Merge a base package.json with an overlay fragment + extras.\n *\n * - Merges `dependencies`, `devDependencies`, and `scripts` (shallow).\n * - Throws {@link VersionConflictError} on any version mismatch within the same key.\n * - Other top-level keys (`name`, `version`, etc.) come from `base` only.\n */\nexport function mergePackageJson(\n base: PackageJsonLike,\n overlay: PackageJsonLike | null,\n options: MergeOptions = {},\n): PackageJsonLike {\n const merged: PackageJsonLike = { ...base };\n\n for (const key of ['dependencies', 'devDependencies', 'scripts'] as const) {\n const baseMap = (base[key] ?? {}) as Record<string, string>;\n const overlayMap = (overlay?.[key] ?? {}) as Record<string, string>;\n const extrasMap =\n key === 'dependencies'\n ? options.extraDependencies ?? {}\n : key === 'devDependencies'\n ? options.extraDevDependencies ?? {}\n : {};\n\n const result: Record<string, string> = { ...baseMap };\n for (const [name, version] of Object.entries(overlayMap)) {\n if (result[name] !== undefined && result[name] !== version) {\n throw new VersionConflictError(key, name, result[name], version);\n }\n result[name] = version;\n }\n for (const [name, version] of Object.entries(extrasMap)) {\n if (result[name] !== undefined && result[name] !== version) {\n throw new VersionConflictError(key, name, result[name], version);\n }\n result[name] = version;\n }\n if (Object.keys(result).length > 0) {\n merged[key] = sortObjectByKey(result);\n }\n }\n\n return merged;\n}\n\nfunction sortObjectByKey<T extends Record<string, unknown>>(obj: T): T {\n const sorted: Record<string, unknown> = {};\n for (const k of Object.keys(obj).sort()) sorted[k] = obj[k];\n return sorted as T;\n}\n\nexport async function readJson<T = unknown>(filePath: string): Promise<T> {\n const raw = await fs.readFile(filePath, 'utf8');\n return JSON.parse(raw) as T;\n}\n\nexport async function writeJson(\n filePath: string,\n value: unknown,\n): Promise<void> {\n await fs.writeFile(filePath, JSON.stringify(value, null, 2) + '\\n', 'utf8');\n}\n","/**\n * Detect the user's package manager from `npm_config_user_agent`,\n * with fallback heuristics, and produce install / run commands.\n */\n\nexport type PackageManager = 'pnpm' | 'npm' | 'yarn';\n\nexport interface PackageManagerInfo {\n name: PackageManager;\n /** Command + args to install dependencies in cwd. */\n install: string[];\n /** Command + args prefix to run a package script. */\n run: string[];\n /** Human-readable command (`pnpm install`, etc.). */\n installCommand: string;\n /** Human-readable run prefix (`pnpm`, `npm run`, `yarn`). */\n runPrefix: string;\n}\n\n/**\n * Detect the package manager invoking `create-teamix-evo`.\n *\n * Priority:\n * 1. explicit `prefer` argument\n * 2. `npm_config_user_agent` env (set by `pnpm create` / `npm create` / `yarn create`)\n * 3. fallback to `npm`\n */\nexport function detectPackageManager(\n prefer?: PackageManager,\n): PackageManagerInfo {\n const detected = prefer ?? detectFromUserAgent() ?? 'npm';\n return buildInfo(detected);\n}\n\nexport function isValidPackageManager(value: string): value is PackageManager {\n return value === 'pnpm' || value === 'npm' || value === 'yarn';\n}\n\nfunction detectFromUserAgent(): PackageManager | null {\n const ua = process.env.npm_config_user_agent;\n if (!ua) return null;\n const head = ua.split(' ')[0] ?? '';\n if (head.startsWith('pnpm')) return 'pnpm';\n if (head.startsWith('yarn')) return 'yarn';\n if (head.startsWith('npm')) return 'npm';\n return null;\n}\n\nfunction buildInfo(name: PackageManager): PackageManagerInfo {\n switch (name) {\n case 'pnpm':\n return {\n name,\n install: ['install'],\n run: ['run'],\n installCommand: 'pnpm install',\n runPrefix: 'pnpm',\n };\n case 'yarn':\n return {\n name,\n install: ['install'],\n run: [],\n installCommand: 'yarn install',\n runPrefix: 'yarn',\n };\n case 'npm':\n default:\n return {\n name,\n install: ['install'],\n run: ['run'],\n installCommand: 'npm install',\n runPrefix: 'npm run',\n };\n }\n}\n","import type { Preset } from './types.js';\n\nexport const consolePreset: Preset = {\n id: 'console',\n displayName: 'Console',\n description:\n '中后台标配:Vite + React + TS + Tailwind v4 + design tokens + AI skills + react-router-dom + ConsoleLayout + Dashboard / List / Detail / Form 四页面 + 真装 Button。',\n baseTemplate: 'react-ts',\n tokens: {\n variant: 'opentrek',\n tailwind: 'v4',\n },\n skills: {\n // Bundle all 3 ship-day skills: manage (lifecycle), design-<variant>,\n // code-<variant>. orchestrator expands `design-<variant>` /\n // `code-<variant>` from the resolved variant id.\n entries: ['teamix-evo-manage', 'teamix-evo-design-${variant}', 'teamix-evo-code-${variant}'],\n ides: ['qoder', 'claude'],\n },\n ui: {\n components: ['button'],\n },\n overlay: 'console',\n};\n","import type { Preset } from './types.js';\nimport { consolePreset } from './console.js';\n\nexport type { Preset } from './types.js';\n\nexport const presets: Preset[] = [consolePreset];\n\nexport function findPreset(id: string): Preset | undefined {\n return presets.find((p) => p.id === id);\n}\n\nexport function listPresetIds(): string[] {\n return presets.map((p) => p.id);\n}\n","import { bold, cyan, dim, green, red, yellow } from 'kolorist';\n\nexport const logger = {\n info(message: string): void {\n console.log(`${cyan('ℹ')} ${message}`);\n },\n success(message: string): void {\n console.log(`${green('✓')} ${message}`);\n },\n warn(message: string): void {\n console.warn(`${yellow('⚠')} ${message}`);\n },\n error(message: string): void {\n console.error(`${red('✗')} ${message}`);\n },\n step(message: string): void {\n console.log(`\\n${bold(cyan('▸'))} ${bold(message)}`);\n },\n detail(message: string): void {\n console.log(` ${dim(message)}`);\n },\n blank(): void {\n console.log('');\n },\n};\n","import * as p from '@clack/prompts';\nimport { listTokenVariants } from 'teamix-evo/core';\nimport { isValidPackageManager, type PackageManager } from './pm.js';\n\nexport interface InteractiveAnswers {\n presetId: string;\n pm: PackageManager | undefined;\n git: boolean;\n variant: string | undefined;\n}\n\n/**\n * Run interactive prompts for missing options. The `seed` represents whatever\n * the user already passed via flags; only unanswered fields are prompted for.\n */\nexport async function promptMissing(seed: {\n dir: string;\n presetId?: string;\n pm?: string;\n git?: boolean;\n variant?: string;\n}): Promise<InteractiveAnswers> {\n p.intro('create-teamix-evo');\n p.note(`📦 Target directory: ${seed.dir}`);\n\n const presetId = seed.presetId ?? 'console';\n\n let variant = seed.variant;\n if (!variant) {\n let variantOptions: Array<{\n value: string;\n label: string;\n hint?: string;\n }> = [];\n try {\n const catalog = await listTokenVariants();\n variantOptions = catalog.variants.map((v) => ({\n value: v.name,\n label: `${v.displayName} (${v.name})`,\n hint: v.description,\n }));\n } catch {\n // Fallback to known variants if manifest cannot be loaded\n variantOptions = [\n { value: 'opentrek', label: 'OpenTrek (opentrek)' },\n { value: 'uni-manager', label: 'Uni-Manager (uni-manager)' },\n ];\n }\n const choice = await p.select<string>({\n message: 'Tokens variant',\n options: variantOptions,\n initialValue: variantOptions[0]?.value ?? 'opentrek',\n });\n if (p.isCancel(choice)) {\n p.cancel('已取消');\n process.exit(0);\n }\n variant = choice as string;\n }\n\n let pm: PackageManager | undefined =\n seed.pm && isValidPackageManager(seed.pm) ? seed.pm : undefined;\n if (!pm) {\n const pmChoice = await p.select<string>({\n message: '包管理器',\n options: [\n { value: 'auto', label: '自动检测(推荐)' },\n { value: 'pnpm', label: 'pnpm' },\n { value: 'npm', label: 'npm' },\n { value: 'yarn', label: 'yarn' },\n ],\n initialValue: 'auto',\n });\n if (p.isCancel(pmChoice)) {\n p.cancel('已取消');\n process.exit(0);\n }\n pm =\n pmChoice === 'auto'\n ? undefined\n : isValidPackageManager(pmChoice as string)\n ? (pmChoice as PackageManager)\n : undefined;\n }\n\n let git = seed.git;\n if (git === undefined) {\n const confirmed = await p.confirm({\n message: '初始化 git 仓库?',\n initialValue: true,\n });\n if (p.isCancel(confirmed)) {\n p.cancel('已取消');\n process.exit(0);\n }\n git = confirmed as boolean;\n }\n\n return { presetId, pm, git, variant };\n}\n"],"mappings":"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","names":["path","red","fs","path","execa","fs","p","path","execa","fs","listTokenVariants","listTokenVariants","path","red"]}
@@ -6,10 +6,10 @@
6
6
 
7
7
  | 文件 | 用途 | 真组件 id |
8
8
  | ----------- | ---------------------------- | ----------------- |
9
- | `Card.tsx` | 容器卡片(Dashboard / 详情) | `card`(待发布) |
10
- | `Input.tsx` | 表单输入框 | `input`(待发布) |
11
- | `Form.tsx` | 表单容器 + `Form.Item` | `form`(待发布) |
12
- | `Table.tsx` | 数据表(含简易列定义) | `table`(待发布) |
9
+ | `card.tsx` | 容器卡片(Dashboard / 详情) | `card`(待发布) |
10
+ | `input.tsx` | 表单输入框 | `input`(待发布) |
11
+ | `form.tsx` | 表单容器 + `Form.Item` | `form`(待发布) |
12
+ | `table.tsx` | 数据表(含简易列定义) | `table`(待发布) |
13
13
 
14
14
  每个文件顶部都有 `@teamix-evo:placeholder` 标识符 — `grep` / AI 都可凭此快速发现待迁移项。
15
15
 
@@ -19,7 +19,7 @@
19
19
  # 1. 装真组件(以 card 为例)
20
20
  npx teamix-evo ui add card
21
21
 
22
- # 2. 全项目替换 import:@/components/_placeholder/Card → @/components/ui/card
22
+ # 2. 全项目替换 import:@/components/_placeholder/card → @/components/ui/card
23
23
  # (API 可能有差异,按需调整 props)
24
24
 
25
25
  # 3. 删除本文件中对应的 .tsx
@@ -5,7 +5,7 @@
5
5
  *
6
6
  * 升级路径(ui 包补齐 Card 组件后):
7
7
  * 1. `npx teamix-evo ui add card`
8
- * 2. 全项目替换 `@/components/_placeholder/Card` → `@/components/ui/card`,对齐新 props
8
+ * 2. 全项目替换 `@/components/_placeholder/card` → `@/components/ui/card`,对齐新 props
9
9
  * 3. 删除本文件,并从 `_placeholder/` 同步移除 `pending-ui.json` 中的条目
10
10
  *
11
11
  * 你也可以直接询问 AI:"帮我升级 Card 组件" — `teamix-evo-manage` skill 会读
@@ -5,7 +5,7 @@
5
5
  *
6
6
  * 升级路径:
7
7
  * 1. `npx teamix-evo ui add form`
8
- * 2. 替换 `@/components/_placeholder/Form` → `@/components/ui/form`,按真组件 API 适配
8
+ * 2. 替换 `@/components/_placeholder/form` → `@/components/ui/form`,按真组件 API 适配
9
9
  * 3. 删除本文件
10
10
  *
11
11
  * `teamix-evo-manage` skill 会引导自动迁移。
@@ -20,7 +20,7 @@ export function Form({ children, className, ...rest }: FormProps) {
20
20
  return (
21
21
  <form
22
22
  {...rest}
23
- className={['space-y-4', className].filter(Boolean).join(' ')}
23
+ className={['flex flex-col gap-4', className].filter(Boolean).join(' ')}
24
24
  >
25
25
  {children}
26
26
  </form>
@@ -36,7 +36,7 @@ export interface FormItemProps {
36
36
 
37
37
  function FormItem({ label, required, hint, children }: FormItemProps) {
38
38
  return (
39
- <div className="space-y-1.5">
39
+ <div className="flex flex-col gap-1.5">
40
40
  {label ? (
41
41
  <label className="text-sm font-medium text-foreground">
42
42
  {label}
@@ -5,7 +5,7 @@
5
5
  *
6
6
  * 升级路径:
7
7
  * 1. `npx teamix-evo ui add input`
8
- * 2. 替换 `@/components/_placeholder/Input` → `@/components/ui/input`
8
+ * 2. 替换 `@/components/_placeholder/input` → `@/components/ui/input`
9
9
  * 3. 删除本文件
10
10
  *
11
11
  * `teamix-evo-manage` skill 会引导自动迁移。
@@ -5,7 +5,7 @@
5
5
  *
6
6
  * 升级路径:
7
7
  * 1. `npx teamix-evo ui add table`
8
- * 2. 替换 `@/components/_placeholder/Table` → `@/components/ui/table`,按真组件 API 适配
8
+ * 2. 替换 `@/components/_placeholder/table` → `@/components/ui/table`,按真组件 API 适配
9
9
  * 3. 删除本文件
10
10
  *
11
11
  * `teamix-evo-manage` skill 会引导自动迁移。
@@ -1,4 +1,4 @@
1
- import { Card } from '@/components/_placeholder/Card';
1
+ import { Card } from '@/components/_placeholder/card';
2
2
 
3
3
  const stats = [
4
4
  { label: '用户总数', value: '1,284', delta: '+12% 本周' },
@@ -9,7 +9,7 @@ const stats = [
9
9
 
10
10
  export function DashboardPage() {
11
11
  return (
12
- <div className="space-y-6">
12
+ <div className="flex flex-col gap-6">
13
13
  <div>
14
14
  <h2 className="text-2xl font-semibold tracking-tight">Dashboard</h2>
15
15
  <p className="text-sm text-muted-foreground mt-1">
@@ -1,5 +1,5 @@
1
1
  import { Link, useParams } from 'react-router-dom';
2
- import { Card } from '@/components/_placeholder/Card';
2
+ import { Card } from '@/components/_placeholder/card';
3
3
  import { Button } from '@/components/ui/button';
4
4
  import { mockUsers } from '@/lib/mock-data';
5
5
 
@@ -19,7 +19,7 @@ export function UserDetailPage() {
19
19
  }
20
20
 
21
21
  return (
22
- <div className="space-y-6">
22
+ <div className="flex flex-col gap-6">
23
23
  <div className="flex items-center justify-between">
24
24
  <h2 className="text-2xl font-semibold tracking-tight">用户详情</h2>
25
25
  <div className="flex gap-2">
@@ -1,8 +1,8 @@
1
1
  import { useState } from 'react';
2
2
  import { Link, useNavigate, useParams } from 'react-router-dom';
3
- import { Card } from '@/components/_placeholder/Card';
4
- import { Form } from '@/components/_placeholder/Form';
5
- import { Input } from '@/components/_placeholder/Input';
3
+ import { Card } from '@/components/_placeholder/card';
4
+ import { Form } from '@/components/_placeholder/form';
5
+ import { Input } from '@/components/_placeholder/input';
6
6
  import { Button } from '@/components/ui/button';
7
7
  import { mockUsers } from '@/lib/mock-data';
8
8
 
@@ -19,13 +19,12 @@ export function UserFormPage() {
19
19
  const handleSubmit = (e: React.FormEvent) => {
20
20
  e.preventDefault();
21
21
  // 真实业务请替换为 API 调用
22
- // eslint-disable-next-line no-console
23
22
  console.info('[demo] submit', { name, email, role });
24
23
  navigate('/users');
25
24
  };
26
25
 
27
26
  return (
28
- <div className="space-y-6 max-w-2xl">
27
+ <div className="flex flex-col gap-6 max-w-2xl">
29
28
  <h2 className="text-2xl font-semibold tracking-tight">
30
29
  {isEdit ? '编辑用户' : '新建用户'}
31
30
  </h2>
@@ -1,8 +1,8 @@
1
1
  import { useState } from 'react';
2
2
  import { Link } from 'react-router-dom';
3
- import { Card } from '@/components/_placeholder/Card';
4
- import { Input } from '@/components/_placeholder/Input';
5
- import { Table } from '@/components/_placeholder/Table';
3
+ import { Card } from '@/components/_placeholder/card';
4
+ import { Input } from '@/components/_placeholder/input';
5
+ import { Table } from '@/components/_placeholder/table';
6
6
  import { Button } from '@/components/ui/button';
7
7
  import { mockUsers } from '@/lib/mock-data';
8
8
 
@@ -13,7 +13,7 @@ export function UserListPage() {
13
13
  );
14
14
 
15
15
  return (
16
- <div className="space-y-6">
16
+ <div className="flex flex-col gap-6">
17
17
  <div className="flex items-center justify-between">
18
18
  <div>
19
19
  <h2 className="text-2xl font-semibold tracking-tight">用户管理</h2>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-teamix-evo",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "Scaffold a Vite + React + TypeScript project pre-wired with Teamix Evo design tokens, AI skills, and UI components.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -18,7 +18,7 @@
18
18
  "execa": "^9.0.0",
19
19
  "handlebars": "^4.7.0",
20
20
  "kolorist": "^1.8.0",
21
- "teamix-evo": "0.3.0"
21
+ "teamix-evo": "0.4.0"
22
22
  },
23
23
  "devDependencies": {
24
24
  "@types/cross-spawn": "^6.0.6",
@@ -12,15 +12,16 @@
12
12
 
13
13
  ## 已安装资产
14
14
 
15
- - **设计 tokens**:`.teamix-evo/tokens/`(variant: `{{designVariant}}`)
16
- - **AI 入口**:`AGENTS.md`(项目级)/ `.qoder/agents/` / `.claude/agents/`
17
- - **UI 组件**:`src/components/ui/`(已落地:`{{uiInstalled}}`)
15
+ - **设计 tokens**:`tokens/`(variant: `{{tokensVariant}}`)
16
+ - **AI skills**:`.qoder/skills/` / `.claude/skills/`(含 `teamix-evo-design-{{tokensVariant}}` 自包含设计规则)
17
+ - **UI 组件**:`src/components/ui/`(已落地:`{{uiInstalled}}`)
18
+ - **shadcn 全局偏好**:`src/preferences.css`(frozen)
18
19
 
19
20
  ## 更新设计资产
20
21
 
21
22
  ```bash
22
23
  # 重新拉取最新 design tokens(覆盖 regenerable,保留 frozen)
23
- npx teamix-evo design update {{designVariant}}
24
+ npx teamix-evo tokens update {{tokensVariant}}
24
25
 
25
26
  # 同步 AI skills 文件
26
27
  npx teamix-evo skills update
@@ -32,8 +33,8 @@ npx teamix-evo ui list
32
33
 
33
34
  ## 自定义 token
34
35
 
35
- `.teamix-evo/tokens/tokens.overrides.css` 是 **frozen** 资源 — 在这里覆盖任何 `--color-primary` 等 CSS 变量后,刷新即可生效,CLI 升级不会覆盖你的改动。
36
+ `tokens/tokens.overrides.css` 是 **frozen** 资源 — 在这里覆盖任何 `--color-primary` 等 CSS 变量后,刷新即可生效,CLI 升级不会覆盖你的改动。
36
37
 
37
38
  ## AI 协作
38
39
 
39
- 打开本项目时,AI 助手会自动读取 `AGENTS.md` / `CLAUDE.md` `.teamix-evo/design/` 下的设计上下文 直接告诉它"帮我加一个用户列表页"即可。
40
+ 打开本项目时,IDE 会按 [ADR 0015](https://github.com/teamix-evo/teamix-evo/blob/master/docs/adr/0015-skill-description-trigger-contract.md) 的 description-trigger 契约自动识别 `.qoder/skills/` / `.claude/skills/` 下的 skill:`teamix-evo-design-{{tokensVariant}}` 提供设计规则,`teamix-evo-manage` 处理生命周期。token 真值在根 `tokens/`,经 MCP `tokens_*` 工具查询。直接告诉 AI "帮我加一个用户列表页" 即可。
@@ -0,0 +1,12 @@
1
+ /**
2
+ * teamix-evo consumer ESLint preset — 9 token-discipline rules.
3
+ * - Repo-wide: no-color-literal / no-arbitrary-tw-value / no-raw-color-scale /
4
+ * no-large-radius / prefer-gap-over-space / no-manual-dark-classnames /
5
+ * dialog-must-have-title (all error)
6
+ * - src/components/ui/** only: no-relative-ui-import / icon-from-lucide (error)
7
+ *
8
+ * See ADR 0008 / docs/principles.md §P4.
9
+ */
10
+ import consumerPreset from '@teamix-evo/eslint-config/presets/consumer';
11
+
12
+ export default [...consumerPreset];
@@ -7,7 +7,8 @@
7
7
  "dev": "vite",
8
8
  "build": "tsc -b && vite build",
9
9
  "preview": "vite preview",
10
- "typecheck": "tsc --noEmit"
10
+ "typecheck": "tsc --noEmit",
11
+ "lint": "eslint src/"
11
12
  },
12
13
  "dependencies": {
13
14
  "react": "^18.3.1",
@@ -15,10 +16,16 @@
15
16
  },
16
17
  "devDependencies": {
17
18
  "@tailwindcss/vite": "^4.0.0",
19
+ "@teamix-evo/eslint-config": "^0.2.0",
20
+ "@teamix-evo/mcp": "^0.3.0",
21
+ "@teamix-evo/skills": "^0.3.0",
22
+ "@teamix-evo/ui": "^0.2.0",
18
23
  "@types/node": "^20.0.0",
19
24
  "@types/react": "^18.3.0",
20
25
  "@types/react-dom": "^18.3.0",
26
+ "@typescript-eslint/parser": "^8.0.0",
21
27
  "@vitejs/plugin-react": "^4.3.0",
28
+ "eslint": "^9.0.0",
22
29
  "tailwindcss": "^4.0.0",
23
30
  "typescript": "^5.5.0",
24
31
  "vite": "^5.4.0"
@@ -5,7 +5,7 @@ export default function App() {
5
5
  <p className="text-muted-foreground max-w-md text-center">
6
6
  设计 tokens 已就位 — 修改{' '}
7
7
  <code className="px-1 py-0.5 rounded bg-muted">
8
- .teamix-evo/tokens/tokens.overrides.css
8
+ tokens/tokens.overrides.css
9
9
  </code>{' '}
10
10
  试试热更新。
11
11
  </p>
@@ -1,6 +1,8 @@
1
1
  @import 'tailwindcss';
2
2
 
3
- /* Teamix Evo design tokens — 由 `teamix-evo design init` 装载到 .teamix-evo/tokens/
4
- * (tokens 被 lift 出 design/ 目录以缩短嵌套,见 design-pack-classify.ts) */
5
- @import '../.teamix-evo/tokens/tokens.theme.css';
6
- @import '../.teamix-evo/tokens/tokens.overrides.css';
3
+ /* Teamix Evo design tokens — 由 `teamix-evo tokens init` 装载到根 tokens/ 目录 */
4
+ @import '../tokens/tokens.theme.css';
5
+ @import '../tokens/tokens.overrides.css';
6
+
7
+ /* shadcn 全局偏好(pointer cursor 等) — 由 `teamix-evo ui init` 部署 */
8
+ @import './preferences.css';