create-windy 0.1.1 → 0.2.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/dist/cli.js CHANGED
@@ -1,4 +1,197 @@
1
1
  #!/usr/bin/env node
2
+ import { createRequire } from "node:module";
3
+ var __create = Object.create;
4
+ var __getProtoOf = Object.getPrototypeOf;
5
+ var __defProp = Object.defineProperty;
6
+ var __getOwnPropNames = Object.getOwnPropertyNames;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ function __accessProp(key) {
9
+ return this[key];
10
+ }
11
+ var __toESMCache_node;
12
+ var __toESMCache_esm;
13
+ var __toESM = (mod, isNodeMode, target) => {
14
+ var canCache = mod != null && typeof mod === "object";
15
+ if (canCache) {
16
+ var cache = isNodeMode ? __toESMCache_node ??= new WeakMap : __toESMCache_esm ??= new WeakMap;
17
+ var cached = cache.get(mod);
18
+ if (cached)
19
+ return cached;
20
+ }
21
+ target = mod != null ? __create(__getProtoOf(mod)) : {};
22
+ const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
23
+ for (let key of __getOwnPropNames(mod))
24
+ if (!__hasOwnProp.call(to, key))
25
+ __defProp(to, key, {
26
+ get: __accessProp.bind(mod, key),
27
+ enumerable: true
28
+ });
29
+ if (canCache)
30
+ cache.set(mod, to);
31
+ return to;
32
+ };
33
+ var __commonJS = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports);
34
+ var __require = /* @__PURE__ */ createRequire(import.meta.url);
35
+
36
+ // ../../node_modules/.bun/cli-width@4.1.0/node_modules/cli-width/index.js
37
+ var require_cli_width = __commonJS((exports, module3) => {
38
+ module3.exports = cliWidth;
39
+ function normalizeOpts(options) {
40
+ const defaultOpts = {
41
+ defaultWidth: 0,
42
+ output: process.stdout,
43
+ tty: __require("tty")
44
+ };
45
+ if (!options) {
46
+ return defaultOpts;
47
+ }
48
+ Object.keys(defaultOpts).forEach(function(key) {
49
+ if (!options[key]) {
50
+ options[key] = defaultOpts[key];
51
+ }
52
+ });
53
+ return options;
54
+ }
55
+ function cliWidth(options) {
56
+ const opts = normalizeOpts(options);
57
+ if (opts.output.getWindowSize) {
58
+ return opts.output.getWindowSize()[0] || opts.defaultWidth;
59
+ }
60
+ if (opts.tty.getWindowSize) {
61
+ return opts.tty.getWindowSize()[1] || opts.defaultWidth;
62
+ }
63
+ if (opts.output.columns) {
64
+ return opts.output.columns;
65
+ }
66
+ if (process.env.CLI_WIDTH) {
67
+ const width = parseInt(process.env.CLI_WIDTH, 10);
68
+ if (!isNaN(width) && width !== 0) {
69
+ return width;
70
+ }
71
+ }
72
+ return opts.defaultWidth;
73
+ }
74
+ });
75
+
76
+ // ../../node_modules/.bun/mute-stream@3.0.0/node_modules/mute-stream/lib/index.js
77
+ var require_lib = __commonJS((exports, module3) => {
78
+ var Stream = __require("stream");
79
+
80
+ class MuteStream extends Stream {
81
+ #isTTY = null;
82
+ constructor(opts = {}) {
83
+ super(opts);
84
+ this.writable = this.readable = true;
85
+ this.muted = false;
86
+ this.on("pipe", this._onpipe);
87
+ this.replace = opts.replace;
88
+ this._prompt = opts.prompt || null;
89
+ this._hadControl = false;
90
+ }
91
+ #destSrc(key, def) {
92
+ if (this._dest) {
93
+ return this._dest[key];
94
+ }
95
+ if (this._src) {
96
+ return this._src[key];
97
+ }
98
+ return def;
99
+ }
100
+ #proxy(method, ...args) {
101
+ if (typeof this._dest?.[method] === "function") {
102
+ this._dest[method](...args);
103
+ }
104
+ if (typeof this._src?.[method] === "function") {
105
+ this._src[method](...args);
106
+ }
107
+ }
108
+ get isTTY() {
109
+ if (this.#isTTY !== null) {
110
+ return this.#isTTY;
111
+ }
112
+ return this.#destSrc("isTTY", false);
113
+ }
114
+ set isTTY(val) {
115
+ this.#isTTY = val;
116
+ }
117
+ get rows() {
118
+ return this.#destSrc("rows");
119
+ }
120
+ get columns() {
121
+ return this.#destSrc("columns");
122
+ }
123
+ mute() {
124
+ this.muted = true;
125
+ }
126
+ unmute() {
127
+ this.muted = false;
128
+ }
129
+ _onpipe(src) {
130
+ this._src = src;
131
+ }
132
+ pipe(dest, options) {
133
+ this._dest = dest;
134
+ return super.pipe(dest, options);
135
+ }
136
+ pause() {
137
+ if (this._src) {
138
+ return this._src.pause();
139
+ }
140
+ }
141
+ resume() {
142
+ if (this._src) {
143
+ return this._src.resume();
144
+ }
145
+ }
146
+ write(c) {
147
+ if (this.muted) {
148
+ if (!this.replace) {
149
+ return true;
150
+ }
151
+ if (c.match(/^\u001b/)) {
152
+ if (c.indexOf(this._prompt) === 0) {
153
+ c = c.slice(this._prompt.length);
154
+ c = c.replace(/./g, this.replace);
155
+ c = this._prompt + c;
156
+ }
157
+ this._hadControl = true;
158
+ return this.emit("data", c);
159
+ } else {
160
+ if (this._prompt && this._hadControl && c.indexOf(this._prompt) === 0) {
161
+ this._hadControl = false;
162
+ this.emit("data", this._prompt);
163
+ c = c.slice(this._prompt.length);
164
+ }
165
+ c = c.toString().replace(/./g, this.replace);
166
+ }
167
+ }
168
+ this.emit("data", c);
169
+ }
170
+ end(c) {
171
+ if (this.muted) {
172
+ if (c && this.replace) {
173
+ c = c.toString().replace(/./g, this.replace);
174
+ } else {
175
+ c = null;
176
+ }
177
+ }
178
+ if (c) {
179
+ this.emit("data", c);
180
+ }
181
+ this.emit("end");
182
+ }
183
+ destroy(...args) {
184
+ return this.#proxy("destroy", ...args);
185
+ }
186
+ destroySoon(...args) {
187
+ return this.#proxy("destroySoon", ...args);
188
+ }
189
+ close(...args) {
190
+ return this.#proxy("close", ...args);
191
+ }
192
+ }
193
+ module3.exports = MuteStream;
194
+ });
2
195
 
3
196
  // src/arguments.ts
4
197
  import { resolve } from "node:path";
@@ -495,6 +688,12 @@ function readProjectLicense(args) {
495
688
  }
496
689
  var helpText = `create-windy <项目名> [选项]
497
690
 
691
+ 生命周期命令:
692
+ create-windy doctor [--cwd <目录>] [--repair]
693
+ create-windy update --check [--cwd <目录>]
694
+ create-windy update --dry-run [--to <版本>] [--cwd <目录>]
695
+ create-windy update [--to <版本>] [--cwd <目录>]
696
+
498
697
  选项:
499
698
  --profile private-enterprise 单组织、单租户、私有部署 profile
500
699
  --skip-install 只生成文件,不执行 bun install
@@ -606,7 +805,7 @@ function isMissingCommand(error) {
606
805
  }
607
806
 
608
807
  // src/git.ts
609
- async function initializeGitRepository(targetDirectory, execute = runCommand) {
808
+ async function initializeGitRepository(targetDirectory, execute = runCommand, activateHooks = false) {
610
809
  try {
611
810
  await execute("git", ["init", "-b", "main"], targetDirectory);
612
811
  } catch (error) {
@@ -615,6 +814,16 @@ async function initializeGitRepository(targetDirectory, execute = runCommand) {
615
814
  warning: `未能初始化 Git 仓库,项目文件已保留。${recoveryHint(error)}`
616
815
  };
617
816
  }
817
+ if (activateHooks) {
818
+ try {
819
+ await execute("bun", ["run", "prepare"], targetDirectory);
820
+ } catch (error) {
821
+ return {
822
+ status: "skipped",
823
+ warning: "Git 仓库已初始化,但提交钩子未能启用。请安装依赖后运行 bun run prepare。" + compactReason(error)
824
+ };
825
+ }
826
+ }
618
827
  try {
619
828
  await execute("git", ["add", "--all"], targetDirectory);
620
829
  } catch (error) {
@@ -681,8 +890,9 @@ function rewriteCustomerDockerfile(source) {
681
890
  import { readFile as readFile2, writeFile as writeFile2 } from "node:fs/promises";
682
891
  import { join as join2 } from "node:path";
683
892
  var oxcStarterPolicy = [
684
- "- 代码检查与格式化统一使用 Oxc:OxlintOxfmt,不使用 ESLint 或 Prettier。",
685
- "- Oxc Starter 默认提供的代码质量方案;项目生成后由项目所有者决定是否保留、替换或并行使用其它工具。"
893
+ "- 生成时默认预装 OxlintOxfmt、lint-staged Husky。",
894
+ "- 提交前自动格式化暂存文件;lint、typecheck test 保留为显式命令。",
895
+ "- 这是 Starter 的初始配置;项目所有者可按团队需要保留、替换或扩展。"
686
896
  ].join(`
687
897
  `);
688
898
  var noCodeQualityPolicy = "- 本项目生成时未引入 lint 或 format 工具;项目所有者可按团队需要自行选择。";
@@ -702,7 +912,13 @@ import { mkdir, readFile as readFile3, rm, writeFile as writeFile3 } from "node:
702
912
  import { dirname, join as join3, resolve as resolve2 } from "node:path";
703
913
  import { fileURLToPath } from "node:url";
704
914
  var packageRoot = resolve2(dirname(fileURLToPath(import.meta.url)), "..");
705
- var apacheLicensePath = resolve2(packageRoot, "assets/LICENSE-Apache-2.0.txt");
915
+ var apacheLicensePath = resolve2(packageRoot, "LICENSE");
916
+ var windyLicensePath = ".windy/licenses/WINDY-APACHE-2.0.txt";
917
+ async function applyWindyBaseLicense(targetDirectory) {
918
+ const target = join3(targetDirectory, windyLicensePath);
919
+ await mkdir(dirname(target), { recursive: true });
920
+ await writeFile3(target, await readFile3(apacheLicensePath));
921
+ }
706
922
  async function applyProjectLicense(targetDirectory, license, holder, year = new Date().getFullYear()) {
707
923
  const target = join3(targetDirectory, "LICENSE");
708
924
  if (license === "UNLICENSED") {
@@ -751,7 +967,11 @@ import { lstat, readdir, readFile as readFile4, writeFile as writeFile4 } from "
751
967
  import { join as join4, relative, sep } from "node:path";
752
968
  var managedFilesManifestPath = ".windy/files.json";
753
969
  var ignoredDirectoryNames = new Set([".git", "node_modules", "dist"]);
754
- var ignoredFiles = new Set(["bun.lock", managedFilesManifestPath]);
970
+ var ignoredFiles = new Set([
971
+ "bun.lock",
972
+ managedFilesManifestPath,
973
+ ".windy/update-state.json"
974
+ ]);
755
975
  var projectOwnedRoots = [
756
976
  "apps/web/src/app",
757
977
  "apps/server/src/work-order",
@@ -784,6 +1004,16 @@ async function writeManagedFilesManifest(targetDirectory, generatorVersion) {
784
1004
  await writeFile4(join4(targetDirectory, managedFilesManifestPath), `${JSON.stringify(manifest, null, 2)}
785
1005
  `);
786
1006
  }
1007
+ async function readManagedFilesManifest(targetDirectory) {
1008
+ const parsed = JSON.parse(await readFile4(join4(targetDirectory, managedFilesManifestPath), "utf8"));
1009
+ if (!isManagedFilesManifest(parsed)) {
1010
+ throw new Error("受管文件清单无效,无法安全更新");
1011
+ }
1012
+ return parsed;
1013
+ }
1014
+ function hashContent(content) {
1015
+ return createHash("sha256").update(content).digest("hex");
1016
+ }
787
1017
  function classifyOwnership(path) {
788
1018
  if (matchesRoot(path, projectOwnedRoots))
789
1019
  return "project-owned";
@@ -804,6 +1034,10 @@ async function collectFiles(root) {
804
1034
  if (metadata.isSymbolicLink())
805
1035
  continue;
806
1036
  if (metadata.isDirectory()) {
1037
+ const relativeDirectory = relative(root, path).split(sep).join("/");
1038
+ if (relativeDirectory === ".windy/backups" || relativeDirectory === ".windy/reports") {
1039
+ continue;
1040
+ }
807
1041
  await visit(path, output);
808
1042
  continue;
809
1043
  }
@@ -816,6 +1050,17 @@ async function collectFiles(root) {
816
1050
  function matchesRoot(path, roots) {
817
1051
  return roots.some((root) => path === root || path.startsWith(`${root}/`));
818
1052
  }
1053
+ function isManagedFilesManifest(value) {
1054
+ if (!value || typeof value !== "object")
1055
+ return false;
1056
+ const manifest = value;
1057
+ return manifest.schemaVersion === 1 && manifest.algorithm === "sha256" && typeof manifest.generatorVersion === "string" && Array.isArray(manifest.files) && manifest.files.every((entry) => {
1058
+ if (!entry || typeof entry !== "object")
1059
+ return false;
1060
+ const file = entry;
1061
+ return typeof file.path === "string" && (file.ownership === "windy-managed" || file.ownership === "shared-scaffold" || file.ownership === "project-owned") && typeof file.hash === "string";
1062
+ });
1063
+ }
819
1064
 
820
1065
  // src/module-materializer.ts
821
1066
  import { lstat as lstat2, readFile as readFile5, readdir as readdir2, rm as rm2, writeFile as writeFile5 } from "node:fs/promises";
@@ -1101,8 +1346,10 @@ ${projectName} 是由 create-windy 生成的单组织、单租户企业应用项
1101
1346
  \`/\`,平台管理控制面位于 \`/admin/**\`;业务功能可以按自己的产品习惯开发,不需要
1102
1347
  复用 Admin 页面结构。
1103
1348
 
1104
- 本项目固定使用 Bun 1.3.14 或更高版本,当前法律许可为 \`${projectLicense}\`。项目不包含
1105
- 软件供应方的 License Authority、内部签名服务、发布密钥或私有源仓库信息。
1349
+ 本项目固定使用 Bun 1.3.14 或更高版本,客户业务代码的当前法律许可为
1350
+ \`${projectLicense}\`。Windy Starter 基座使用 Apache-2.0,正文保留在
1351
+ \`.windy/licenses/WINDY-APACHE-2.0.txt\`。项目不包含软件供应方的 License Authority、
1352
+ 内部签名服务、发布密钥或私有源仓库信息。
1106
1353
  ${includeExample ? "创建时包含了 `work-order` 示例模块,用于演示 Module Manifest 接入;它不是生产工单产品,可以在正式开发前替换。" : "创建时未选择 `work-order` 示例模块,当前项目只包含平台模块。"}
1107
1354
 
1108
1355
  ## 环境要求
@@ -1169,8 +1416,9 @@ bun run dev:web
1169
1416
  | ---------- | -------- | ------------ | ---- |
1170
1417
  ${moduleRows}
1171
1418
 
1172
- 精确生成来源和选择记录在 \`.windy/generation.json\`。当前版本尚未提供通用
1173
- \`module add/remove\` \`windy update\`,不要把 Feature Flag 关闭当成模块已经卸载。
1419
+ 精确生成来源和选择记录在 \`.windy/generation.json\`。当前版本已提供可回滚的
1420
+ \`windy update\`;通用 \`module add/remove\` 尚未交付,不要把 Feature Flag 关闭当成
1421
+ 模块已经卸载。
1174
1422
 
1175
1423
  ## 常用命令
1176
1424
 
@@ -1180,10 +1428,19 @@ bun run dev:server
1180
1428
  bun run typecheck
1181
1429
  bun run test
1182
1430
  bun run build
1431
+ bun run windy doctor
1432
+ bun run windy update --check
1433
+ bun run windy update --dry-run
1183
1434
  ${includeOxc ? `bun run lint
1184
1435
  bun run format` : "# 本项目未预装 lint/format 工具,可按团队需要自行选择。"}
1185
1436
  \`\`\`
1186
1437
 
1438
+ ${includeOxc ? "提交时 Husky 会通过 lint-staged 与 Oxfmt 格式化暂存文件,不会把未暂存内容带入提交。lint、typecheck 和 test 保留为需要时显式运行的命令。" : "当前项目没有生成 Husky 代码质量钩子;如后续自行引入工具,请同步配置提交工作流。"}
1439
+
1440
+ 更新前必须保持 Git 工作区干净。\`--dry-run\` 只生成计划,不写项目;正式更新先备份,
1441
+ 再做 package 字段级合并、共享脚手架三方合并与完整验证。任何冲突都会在写入前中止,
1442
+ 验证失败会自动回滚;中断恢复使用 \`bun run windy doctor --repair\`。
1443
+
1187
1444
  ## 开发约束
1188
1445
 
1189
1446
  - 新增路由默认需要登录;只有显式 public 的页面允许匿名访问。
@@ -1206,27 +1463,40 @@ create-windy 默认建立 \`main\` 分支并创建 \`chore: initialize project\`
1206
1463
 
1207
1464
  ## License
1208
1465
 
1209
- 本项目当前法律许可证为 \`${projectLicense}\`。${projectLicense === "UNLICENSED" ? "项目没有附带开源许可证。" : "完整许可证正文位于根目录 `LICENSE`。"}法律许可证与 \`system.license\` 离线运行时授权模块是两个不同概念;更换其中一个
1210
- 不会自动更换另一个。
1466
+ 客户业务代码当前法律许可证为 \`${projectLicense}\`。${projectLicense === "UNLICENSED" ? "项目没有附带开源许可证。" : "完整许可证正文位于根目录 `LICENSE`。"}Windy Starter 基座继续适用
1467
+ \`.windy/licenses/WINDY-APACHE-2.0.txt\` 中的 Apache-2.0。项目法律许可证与
1468
+ \`system.license\` 离线运行时授权模块是两个不同概念;更换其中一个不会自动更换
1469
+ 另一个。
1211
1470
  `;
1212
1471
  }
1213
1472
 
1214
1473
  // src/project-package.ts
1215
- function createStarterPackage(source, projectName, includeOxc = true, projectLicense = "UNLICENSED", selectedModules = []) {
1474
+ var defaultLintStaged = {
1475
+ "*.{cjs,css,cts,html,js,json,jsonc,jsx,less,md,mdx,mjs,mts,scss,ts,tsx,vue,yaml,yml}": "oxfmt --write"
1476
+ };
1477
+ function createStarterPackage(source, projectName, includeOxc = true, projectLicense = "UNLICENSED", selectedModules = [], generatorVersion) {
1478
+ const { "lint-staged": sourceLintStaged, ...sourceWithoutLintStaged } = source;
1216
1479
  const devDependencies = { ...source.devDependencies };
1217
1480
  if (!includeOxc) {
1481
+ delete devDependencies.husky;
1482
+ delete devDependencies["lint-staged"];
1218
1483
  delete devDependencies.oxfmt;
1219
1484
  delete devDependencies.oxlint;
1220
1485
  }
1221
1486
  return {
1222
- ...source,
1487
+ ...sourceWithoutLintStaged,
1223
1488
  name: projectName,
1224
1489
  private: true,
1225
1490
  license: projectLicense,
1226
1491
  packageManager: "bun@1.3.14",
1227
1492
  engines: { ...source.engines, bun: ">=1.3.14" },
1493
+ ...includeOxc ? { "lint-staged": sourceLintStaged ?? defaultLintStaged } : {},
1228
1494
  scripts: {
1495
+ ...includeOxc ? {
1496
+ prepare: "git rev-parse --git-dir >/dev/null 2>&1 || exit 0; husky"
1497
+ } : {},
1229
1498
  dev: "bun run --cwd apps/web dev",
1499
+ ...generatorVersion ? { windy: "create-windy" } : {},
1230
1500
  "dev:web": "bun run --cwd apps/web dev",
1231
1501
  "dev:server": "bun run --cwd apps/server dev",
1232
1502
  build: "bun run --cwd apps/web build",
@@ -1241,10 +1511,17 @@ function createStarterPackage(source, projectName, includeOxc = true, projectLic
1241
1511
  "bun run --cwd packages/database typecheck",
1242
1512
  "bun run --cwd packages/crud-generator typecheck"
1243
1513
  ].join(" && "),
1244
- ...includeOxc ? { lint: "oxlint .", format: "oxfmt" } : {},
1514
+ ...includeOxc ? {
1515
+ lint: "oxlint .",
1516
+ format: "oxfmt",
1517
+ "format:staged": "lint-staged"
1518
+ } : {},
1245
1519
  test: "bun test && bun run --cwd apps/web test"
1246
1520
  },
1247
- devDependencies
1521
+ devDependencies: {
1522
+ ...devDependencies,
1523
+ ...generatorVersion ? { "create-windy": generatorVersion } : {}
1524
+ }
1248
1525
  };
1249
1526
  }
1250
1527
 
@@ -1252,6 +1529,7 @@ function createStarterPackage(source, projectName, includeOxc = true, projectLic
1252
1529
  var templateRootFiles = [
1253
1530
  ".dockerignore",
1254
1531
  ".gitignore",
1532
+ ".husky/pre-commit",
1255
1533
  ".oxfmtrc.json",
1256
1534
  ".oxlintrc.json",
1257
1535
  "AGENTS.md",
@@ -1312,8 +1590,13 @@ var npmTemplateAliases = {
1312
1590
  "bunfig.toml": "_bunfig.toml"
1313
1591
  };
1314
1592
  function generationTemplatePaths(includeExample, includeOxc = true) {
1315
- return templatePaths.filter((path) => (includeExample || path !== "packages/example-work-order") && (includeOxc || path !== ".oxfmtrc.json" && path !== ".oxlintrc.json"));
1593
+ return templatePaths.filter((path) => (includeExample || path !== "packages/example-work-order") && (includeOxc || !oxcTemplatePaths.has(path)));
1316
1594
  }
1595
+ var oxcTemplatePaths = new Set([
1596
+ ".husky/pre-commit",
1597
+ ".oxfmtrc.json",
1598
+ ".oxlintrc.json"
1599
+ ]);
1317
1600
  var excludedNames = new Set([
1318
1601
  ".DS_Store",
1319
1602
  ".env",
@@ -1341,6 +1624,14 @@ async function readTemplateMetadata(sourceRoot) {
1341
1624
  }
1342
1625
  return parsed;
1343
1626
  }
1627
+ async function readGenerationProvenance(targetDirectory) {
1628
+ const path = join6(targetDirectory, generationMetadataFile);
1629
+ const parsed = JSON.parse(await readFile6(path, "utf8"));
1630
+ if (!isGenerationProvenance(parsed)) {
1631
+ throw new Error("当前目录不是受支持的 Windy 项目:Project Lock 无效");
1632
+ }
1633
+ return parsed;
1634
+ }
1344
1635
  async function writeGenerationProvenance(targetDirectory, metadata, profile, selectedModules, includeOxc, legalLicense) {
1345
1636
  const requested = selectedModuleManifests(selectedModules);
1346
1637
  const versions = new Map(metadata.modules.map((item) => [item.name, item]));
@@ -1378,6 +1669,14 @@ function isTemplateMetadata(value) {
1378
1669
  const metadata = value;
1379
1670
  return metadata.schemaVersion === 1 && typeof metadata.templateCommit === "string" && /^[0-9a-f]{40}$/.test(metadata.templateCommit) && typeof metadata.generatorVersion === "string" && metadata.generatorVersion.length > 0 && Array.isArray(metadata.modules) && metadata.modules.every(isModuleVersion);
1380
1671
  }
1672
+ function isGenerationProvenance(value) {
1673
+ if (!isTemplateMetadata(value))
1674
+ return false;
1675
+ const metadata = value;
1676
+ const toolchain = metadata.toolchain;
1677
+ const choices = metadata.choices;
1678
+ return typeof metadata.windyVersion === "string" && metadata.profile === "private-enterprise" && toolchain?.runtime === "bun" && (toolchain?.codeQuality === "oxc" || toolchain?.codeQuality === "none") && (metadata.legalLicense === "UNLICENSED" || metadata.legalLicense === "MIT" || metadata.legalLicense === "Apache-2.0") && Array.isArray(metadata.appliedRecipes) && metadata.appliedRecipes.every((item) => typeof item === "string") && metadata.managedFilesManifest === ".windy/files.json" && typeof choices?.includeExample === "boolean" && typeof choices.includeOxc === "boolean";
1679
+ }
1381
1680
  function isModuleVersion(value) {
1382
1681
  if (!value || typeof value !== "object")
1383
1682
  return false;
@@ -1401,13 +1700,14 @@ async function generateProject(input) {
1401
1700
  await materializeSelectedModules(input.targetDirectory, selectedModules);
1402
1701
  const packagePath = join7(input.targetDirectory, "package.json");
1403
1702
  const packageJson = JSON.parse(await readFile7(packagePath, "utf8"));
1404
- await writeFile7(packagePath, `${JSON.stringify(createStarterPackage(packageJson, input.projectName, includeOxc, projectLicense, selectedModules), null, 2)}
1703
+ await writeFile7(packagePath, `${JSON.stringify(createStarterPackage(packageJson, input.projectName, includeOxc, projectLicense, selectedModules, templateMetadata.generatorVersion), null, 2)}
1405
1704
  `);
1406
1705
  await writeFile7(join7(input.targetDirectory, "docker-compose.yml"), starterCompose);
1407
1706
  await writeFile7(join7(input.targetDirectory, ".env.example"), environmentExample(includeExample));
1408
1707
  await writeFile7(join7(input.targetDirectory, "README.md"), starterReadme(input.projectName, includeExample, includeOxc, projectLicense, selectedModules));
1409
1708
  await writeFile7(join7(input.targetDirectory, "docs/README.md"), starterDocsReadme(selectedModules.includes("system.license")));
1410
1709
  await reflectCodeQualityChoice(input.targetDirectory, includeOxc);
1710
+ await applyWindyBaseLicense(input.targetDirectory);
1411
1711
  await applyProjectLicense(input.targetDirectory, projectLicense, input.licenseHolder);
1412
1712
  await prepareCustomerDockerfiles(input.targetDirectory);
1413
1713
  await writeGenerationProvenance(input.targetDirectory, templateMetadata, input.profile ?? starterProfile.key, selectedModules, includeOxc, projectLicense);
@@ -1536,7 +1836,7 @@ async function createProject(options, dependencies = {}) {
1536
1836
  const log = dependencies.log ?? console.log;
1537
1837
  let gitInitialized = false;
1538
1838
  if (options.initializeGit) {
1539
- const result = await (dependencies.initializeGit ?? initializeGitRepository)(options.targetDirectory, dependencies.commandExecutor);
1839
+ const result = await (dependencies.initializeGit ?? initializeGitRepository)(options.targetDirectory, dependencies.commandExecutor, options.includeOxc && (options.install || options.verify));
1540
1840
  gitInitialized = result.status === "committed";
1541
1841
  if (result.status === "skipped")
1542
1842
  log(`
@@ -1579,95 +1879,2489 @@ function isMissing3(error) {
1579
1879
  }
1580
1880
 
1581
1881
  // src/interactive-selection.ts
1582
- import { createInterface } from "node:readline/promises";
1882
+ import { createInterface as createInterface2 } from "node:readline/promises";
1583
1883
  import { stdin, stdout } from "node:process";
1584
- async function applyInteractiveSelection(options, prompter = terminalPrompter()) {
1585
- if (!options.interactive)
1586
- return options;
1587
- const optional = moduleDistributionCatalog.filter(({ name }) => !requiredModuleNames.includes(name));
1588
- const requested = await prompter.selectModules({
1589
- choices: optional.map(({ name, label, selection }) => ({
1590
- value: name,
1591
- label: `${label} (${name})`,
1592
- hint: selection === "recommended" ? "推荐,默认选中" : "可选"
1593
- })),
1594
- defaults: [...recommendedModuleNames]
1884
+
1885
+ // ../../node_modules/.bun/@inquirer+core@11.2.1+e154a6929a67600d/node_modules/@inquirer/core/dist/lib/key.js
1886
+ var keybindings = ["emacs", "vim"];
1887
+ var keybindingLookup = new Set(keybindings);
1888
+ function isKeybinding(value) {
1889
+ return keybindingLookup.has(value);
1890
+ }
1891
+ function getDefaultKeybindings() {
1892
+ const env = process.env["INQUIRER_KEYBINDINGS"];
1893
+ if (!env)
1894
+ return [];
1895
+ return Array.from(new Set(env.toLowerCase().split(/[\s,]+/).filter(isKeybinding)));
1896
+ }
1897
+ var isUpKey = (key, keybindings2 = []) => key.name === "up" || keybindings2.includes("vim") && key.name === "k" || keybindings2.includes("emacs") && key.ctrl && key.name === "p";
1898
+ var isDownKey = (key, keybindings2 = []) => key.name === "down" || keybindings2.includes("vim") && key.name === "j" || keybindings2.includes("emacs") && key.ctrl && key.name === "n";
1899
+ var isSpaceKey = (key) => key.name === "space";
1900
+ var isNumberKey = (key) => "1234567890".includes(key.name);
1901
+ var isEnterKey = (key) => key.name === "enter" || key.name === "return";
1902
+ // ../../node_modules/.bun/@inquirer+core@11.2.1+e154a6929a67600d/node_modules/@inquirer/core/dist/lib/errors.js
1903
+ class AbortPromptError extends Error {
1904
+ name = "AbortPromptError";
1905
+ message = "Prompt was aborted";
1906
+ constructor(options) {
1907
+ super();
1908
+ this.cause = options?.cause;
1909
+ }
1910
+ }
1911
+
1912
+ class CancelPromptError extends Error {
1913
+ name = "CancelPromptError";
1914
+ message = "Prompt was canceled";
1915
+ }
1916
+
1917
+ class ExitPromptError extends Error {
1918
+ name = "ExitPromptError";
1919
+ }
1920
+
1921
+ class HookError extends Error {
1922
+ name = "HookError";
1923
+ }
1924
+
1925
+ class ValidationError extends Error {
1926
+ name = "ValidationError";
1927
+ }
1928
+ // ../../node_modules/.bun/@inquirer+core@11.2.1+e154a6929a67600d/node_modules/@inquirer/core/dist/lib/use-state.js
1929
+ import { AsyncResource as AsyncResource2 } from "node:async_hooks";
1930
+
1931
+ // ../../node_modules/.bun/@inquirer+core@11.2.1+e154a6929a67600d/node_modules/@inquirer/core/dist/lib/hook-engine.js
1932
+ import { AsyncLocalStorage, AsyncResource } from "node:async_hooks";
1933
+ var hookStorage = new AsyncLocalStorage;
1934
+ function createStore(rl) {
1935
+ const store = {
1936
+ rl,
1937
+ hooks: [],
1938
+ hooksCleanup: [],
1939
+ hooksEffect: [],
1940
+ index: 0,
1941
+ handleChange() {}
1942
+ };
1943
+ return store;
1944
+ }
1945
+ function withHooks(rl, cb) {
1946
+ const store = createStore(rl);
1947
+ return hookStorage.run(store, () => {
1948
+ function cycle(render) {
1949
+ store.handleChange = () => {
1950
+ store.index = 0;
1951
+ render();
1952
+ };
1953
+ store.handleChange();
1954
+ }
1955
+ return cb(cycle);
1595
1956
  });
1596
- const includeOxc = await prompter.confirm("是否引入 Oxlint + Oxfmt?", true);
1597
- const projectLicense = await prompter.selectLicense();
1598
- const licenseHolder = projectLicense === "MIT" ? (await prompter.text("MIT 许可证权利人名称:")).trim() : undefined;
1599
- if (projectLicense === "MIT" && !licenseHolder) {
1600
- throw new Error("选择 MIT 时必须填写许可证权利人名称");
1957
+ }
1958
+ function getStore() {
1959
+ const store = hookStorage.getStore();
1960
+ if (!store) {
1961
+ throw new HookError("[Inquirer] Hook functions can only be called from within a prompt");
1601
1962
  }
1602
- const selectedModules = resolveModuleSelection({
1603
- includeRecommended: false,
1604
- requested
1963
+ return store;
1964
+ }
1965
+ function readline() {
1966
+ return getStore().rl;
1967
+ }
1968
+ function withUpdates(fn) {
1969
+ const wrapped = (...args) => {
1970
+ const store = getStore();
1971
+ let shouldUpdate = false;
1972
+ const oldHandleChange = store.handleChange;
1973
+ store.handleChange = () => {
1974
+ shouldUpdate = true;
1975
+ };
1976
+ const returnValue = fn(...args);
1977
+ if (shouldUpdate) {
1978
+ oldHandleChange();
1979
+ }
1980
+ store.handleChange = oldHandleChange;
1981
+ return returnValue;
1982
+ };
1983
+ return AsyncResource.bind(wrapped);
1984
+ }
1985
+ function withPointer(cb) {
1986
+ const store = getStore();
1987
+ const { index } = store;
1988
+ const pointer = {
1989
+ get() {
1990
+ return store.hooks[index];
1991
+ },
1992
+ set(value) {
1993
+ store.hooks[index] = value;
1994
+ },
1995
+ initialized: index in store.hooks
1996
+ };
1997
+ const returnValue = cb(pointer);
1998
+ store.index++;
1999
+ return returnValue;
2000
+ }
2001
+ function handleChange() {
2002
+ getStore().handleChange();
2003
+ }
2004
+ var effectScheduler = {
2005
+ queue(cb) {
2006
+ const store = getStore();
2007
+ const { index } = store;
2008
+ store.hooksEffect.push(() => {
2009
+ store.hooksCleanup[index]?.();
2010
+ const cleanFn = cb(readline());
2011
+ if (cleanFn != null && typeof cleanFn !== "function") {
2012
+ throw new ValidationError("useEffect return value must be a cleanup function or nothing.");
2013
+ }
2014
+ store.hooksCleanup[index] = cleanFn;
2015
+ });
2016
+ },
2017
+ run() {
2018
+ const store = getStore();
2019
+ withUpdates(() => {
2020
+ store.hooksEffect.forEach((effect) => {
2021
+ effect();
2022
+ });
2023
+ store.hooksEffect.length = 0;
2024
+ })();
2025
+ },
2026
+ clearAll() {
2027
+ const store = getStore();
2028
+ store.hooksCleanup.forEach((cleanFn) => {
2029
+ cleanFn?.();
2030
+ });
2031
+ store.hooksEffect.length = 0;
2032
+ store.hooksCleanup.length = 0;
2033
+ }
2034
+ };
2035
+
2036
+ // ../../node_modules/.bun/@inquirer+core@11.2.1+e154a6929a67600d/node_modules/@inquirer/core/dist/lib/use-state.js
2037
+ function isFactory(value) {
2038
+ return typeof value === "function";
2039
+ }
2040
+ function useState(defaultValue) {
2041
+ return withPointer((pointer) => {
2042
+ const setState = AsyncResource2.bind(function setState2(newValue) {
2043
+ if (pointer.get() !== newValue) {
2044
+ pointer.set(newValue);
2045
+ handleChange();
2046
+ }
2047
+ });
2048
+ if (pointer.initialized) {
2049
+ return [pointer.get(), setState];
2050
+ }
2051
+ const value = isFactory(defaultValue) ? defaultValue() : defaultValue;
2052
+ pointer.set(value);
2053
+ return [value, setState];
2054
+ });
2055
+ }
2056
+
2057
+ // ../../node_modules/.bun/@inquirer+core@11.2.1+e154a6929a67600d/node_modules/@inquirer/core/dist/lib/use-effect.js
2058
+ function useEffect(cb, depArray) {
2059
+ withPointer((pointer) => {
2060
+ const oldDeps = pointer.get();
2061
+ const hasChanged = !Array.isArray(oldDeps) || depArray.some((dep, i) => !Object.is(dep, oldDeps[i]));
2062
+ if (hasChanged) {
2063
+ effectScheduler.queue(cb);
2064
+ }
2065
+ pointer.set(depArray);
1605
2066
  });
2067
+ }
2068
+
2069
+ // ../../node_modules/.bun/@inquirer+core@11.2.1+e154a6929a67600d/node_modules/@inquirer/core/dist/lib/theme.js
2070
+ import { styleText } from "node:util";
2071
+
2072
+ // ../../node_modules/.bun/@inquirer+figures@2.0.7/node_modules/@inquirer/figures/dist/index.js
2073
+ import process2 from "node:process";
2074
+ function isUnicodeSupported() {
2075
+ if (!process2.platform.startsWith("win")) {
2076
+ return process2.env["TERM"] !== "linux";
2077
+ }
2078
+ return Boolean(process2.env["CI"]) || Boolean(process2.env["WT_SESSION"]) || Boolean(process2.env["TERMINUS_SUBLIME"]) || process2.env["ConEmuTask"] === "{cmd::Cmder}" || process2.env["TERM_PROGRAM"] === "Terminus-Sublime" || process2.env["TERM_PROGRAM"] === "vscode" || process2.env["TERM"] === "xterm-256color" || process2.env["TERM"] === "alacritty" || process2.env["TERMINAL_EMULATOR"] === "JetBrains-JediTerm";
2079
+ }
2080
+ var common = {
2081
+ circleQuestionMark: "(?)",
2082
+ questionMarkPrefix: "(?)",
2083
+ square: "█",
2084
+ squareDarkShade: "▓",
2085
+ squareMediumShade: "▒",
2086
+ squareLightShade: "░",
2087
+ squareTop: "▀",
2088
+ squareBottom: "▄",
2089
+ squareLeft: "▌",
2090
+ squareRight: "▐",
2091
+ squareCenter: "■",
2092
+ bullet: "●",
2093
+ dot: "․",
2094
+ ellipsis: "…",
2095
+ pointerSmall: "›",
2096
+ triangleUp: "▲",
2097
+ triangleUpSmall: "▴",
2098
+ triangleDown: "▼",
2099
+ triangleDownSmall: "▾",
2100
+ triangleLeftSmall: "◂",
2101
+ triangleRightSmall: "▸",
2102
+ home: "⌂",
2103
+ heart: "♥",
2104
+ musicNote: "♪",
2105
+ musicNoteBeamed: "♫",
2106
+ arrowUp: "↑",
2107
+ arrowDown: "↓",
2108
+ arrowLeft: "←",
2109
+ arrowRight: "→",
2110
+ arrowLeftRight: "↔",
2111
+ arrowUpDown: "↕",
2112
+ almostEqual: "≈",
2113
+ notEqual: "≠",
2114
+ lessOrEqual: "≤",
2115
+ greaterOrEqual: "≥",
2116
+ identical: "≡",
2117
+ infinity: "∞",
2118
+ subscriptZero: "₀",
2119
+ subscriptOne: "₁",
2120
+ subscriptTwo: "₂",
2121
+ subscriptThree: "₃",
2122
+ subscriptFour: "₄",
2123
+ subscriptFive: "₅",
2124
+ subscriptSix: "₆",
2125
+ subscriptSeven: "₇",
2126
+ subscriptEight: "₈",
2127
+ subscriptNine: "₉",
2128
+ oneHalf: "½",
2129
+ oneThird: "⅓",
2130
+ oneQuarter: "¼",
2131
+ oneFifth: "⅕",
2132
+ oneSixth: "⅙",
2133
+ oneEighth: "⅛",
2134
+ twoThirds: "⅔",
2135
+ twoFifths: "⅖",
2136
+ threeQuarters: "¾",
2137
+ threeFifths: "⅗",
2138
+ threeEighths: "⅜",
2139
+ fourFifths: "⅘",
2140
+ fiveSixths: "⅚",
2141
+ fiveEighths: "⅝",
2142
+ sevenEighths: "⅞",
2143
+ line: "─",
2144
+ lineBold: "━",
2145
+ lineDouble: "═",
2146
+ lineDashed0: "┄",
2147
+ lineDashed1: "┅",
2148
+ lineDashed2: "┈",
2149
+ lineDashed3: "┉",
2150
+ lineDashed4: "╌",
2151
+ lineDashed5: "╍",
2152
+ lineDashed6: "╴",
2153
+ lineDashed7: "╶",
2154
+ lineDashed8: "╸",
2155
+ lineDashed9: "╺",
2156
+ lineDashed10: "╼",
2157
+ lineDashed11: "╾",
2158
+ lineDashed12: "−",
2159
+ lineDashed13: "–",
2160
+ lineDashed14: "‐",
2161
+ lineDashed15: "⁃",
2162
+ lineVertical: "│",
2163
+ lineVerticalBold: "┃",
2164
+ lineVerticalDouble: "║",
2165
+ lineVerticalDashed0: "┆",
2166
+ lineVerticalDashed1: "┇",
2167
+ lineVerticalDashed2: "┊",
2168
+ lineVerticalDashed3: "┋",
2169
+ lineVerticalDashed4: "╎",
2170
+ lineVerticalDashed5: "╏",
2171
+ lineVerticalDashed6: "╵",
2172
+ lineVerticalDashed7: "╷",
2173
+ lineVerticalDashed8: "╹",
2174
+ lineVerticalDashed9: "╻",
2175
+ lineVerticalDashed10: "╽",
2176
+ lineVerticalDashed11: "╿",
2177
+ lineDownLeft: "┐",
2178
+ lineDownLeftArc: "╮",
2179
+ lineDownBoldLeftBold: "┓",
2180
+ lineDownBoldLeft: "┒",
2181
+ lineDownLeftBold: "┑",
2182
+ lineDownDoubleLeftDouble: "╗",
2183
+ lineDownDoubleLeft: "╖",
2184
+ lineDownLeftDouble: "╕",
2185
+ lineDownRight: "┌",
2186
+ lineDownRightArc: "╭",
2187
+ lineDownBoldRightBold: "┏",
2188
+ lineDownBoldRight: "┎",
2189
+ lineDownRightBold: "┍",
2190
+ lineDownDoubleRightDouble: "╔",
2191
+ lineDownDoubleRight: "╓",
2192
+ lineDownRightDouble: "╒",
2193
+ lineUpLeft: "┘",
2194
+ lineUpLeftArc: "╯",
2195
+ lineUpBoldLeftBold: "┛",
2196
+ lineUpBoldLeft: "┚",
2197
+ lineUpLeftBold: "┙",
2198
+ lineUpDoubleLeftDouble: "╝",
2199
+ lineUpDoubleLeft: "╜",
2200
+ lineUpLeftDouble: "╛",
2201
+ lineUpRight: "└",
2202
+ lineUpRightArc: "╰",
2203
+ lineUpBoldRightBold: "┗",
2204
+ lineUpBoldRight: "┖",
2205
+ lineUpRightBold: "┕",
2206
+ lineUpDoubleRightDouble: "╚",
2207
+ lineUpDoubleRight: "╙",
2208
+ lineUpRightDouble: "╘",
2209
+ lineUpDownLeft: "┤",
2210
+ lineUpBoldDownBoldLeftBold: "┫",
2211
+ lineUpBoldDownBoldLeft: "┨",
2212
+ lineUpDownLeftBold: "┥",
2213
+ lineUpBoldDownLeftBold: "┩",
2214
+ lineUpDownBoldLeftBold: "┪",
2215
+ lineUpDownBoldLeft: "┧",
2216
+ lineUpBoldDownLeft: "┦",
2217
+ lineUpDoubleDownDoubleLeftDouble: "╣",
2218
+ lineUpDoubleDownDoubleLeft: "╢",
2219
+ lineUpDownLeftDouble: "╡",
2220
+ lineUpDownRight: "├",
2221
+ lineUpBoldDownBoldRightBold: "┣",
2222
+ lineUpBoldDownBoldRight: "┠",
2223
+ lineUpDownRightBold: "┝",
2224
+ lineUpBoldDownRightBold: "┡",
2225
+ lineUpDownBoldRightBold: "┢",
2226
+ lineUpDownBoldRight: "┟",
2227
+ lineUpBoldDownRight: "┞",
2228
+ lineUpDoubleDownDoubleRightDouble: "╠",
2229
+ lineUpDoubleDownDoubleRight: "╟",
2230
+ lineUpDownRightDouble: "╞",
2231
+ lineDownLeftRight: "┬",
2232
+ lineDownBoldLeftBoldRightBold: "┳",
2233
+ lineDownLeftBoldRightBold: "┯",
2234
+ lineDownBoldLeftRight: "┰",
2235
+ lineDownBoldLeftBoldRight: "┱",
2236
+ lineDownBoldLeftRightBold: "┲",
2237
+ lineDownLeftRightBold: "┮",
2238
+ lineDownLeftBoldRight: "┭",
2239
+ lineDownDoubleLeftDoubleRightDouble: "╦",
2240
+ lineDownDoubleLeftRight: "╥",
2241
+ lineDownLeftDoubleRightDouble: "╤",
2242
+ lineUpLeftRight: "┴",
2243
+ lineUpBoldLeftBoldRightBold: "┻",
2244
+ lineUpLeftBoldRightBold: "┷",
2245
+ lineUpBoldLeftRight: "┸",
2246
+ lineUpBoldLeftBoldRight: "┹",
2247
+ lineUpBoldLeftRightBold: "┺",
2248
+ lineUpLeftRightBold: "┶",
2249
+ lineUpLeftBoldRight: "┵",
2250
+ lineUpDoubleLeftDoubleRightDouble: "╩",
2251
+ lineUpDoubleLeftRight: "╨",
2252
+ lineUpLeftDoubleRightDouble: "╧",
2253
+ lineUpDownLeftRight: "┼",
2254
+ lineUpBoldDownBoldLeftBoldRightBold: "╋",
2255
+ lineUpDownBoldLeftBoldRightBold: "╈",
2256
+ lineUpBoldDownLeftBoldRightBold: "╇",
2257
+ lineUpBoldDownBoldLeftRightBold: "╊",
2258
+ lineUpBoldDownBoldLeftBoldRight: "╉",
2259
+ lineUpBoldDownLeftRight: "╀",
2260
+ lineUpDownBoldLeftRight: "╁",
2261
+ lineUpDownLeftBoldRight: "┽",
2262
+ lineUpDownLeftRightBold: "┾",
2263
+ lineUpBoldDownBoldLeftRight: "╂",
2264
+ lineUpDownLeftBoldRightBold: "┿",
2265
+ lineUpBoldDownLeftBoldRight: "╃",
2266
+ lineUpBoldDownLeftRightBold: "╄",
2267
+ lineUpDownBoldLeftBoldRight: "╅",
2268
+ lineUpDownBoldLeftRightBold: "╆",
2269
+ lineUpDoubleDownDoubleLeftDoubleRightDouble: "╬",
2270
+ lineUpDoubleDownDoubleLeftRight: "╫",
2271
+ lineUpDownLeftDoubleRightDouble: "╪",
2272
+ lineCross: "╳",
2273
+ lineBackslash: "╲",
2274
+ lineSlash: "╱"
2275
+ };
2276
+ var specialMainSymbols = {
2277
+ tick: "✔",
2278
+ info: "ℹ",
2279
+ warning: "⚠",
2280
+ cross: "✘",
2281
+ squareSmall: "◻",
2282
+ squareSmallFilled: "◼",
2283
+ circle: "◯",
2284
+ circleFilled: "◉",
2285
+ circleDotted: "◌",
2286
+ circleDouble: "◎",
2287
+ circleCircle: "ⓞ",
2288
+ circleCross: "ⓧ",
2289
+ circlePipe: "Ⓘ",
2290
+ radioOn: "◉",
2291
+ radioOff: "◯",
2292
+ checkboxOn: "☒",
2293
+ checkboxOff: "☐",
2294
+ checkboxCircleOn: "ⓧ",
2295
+ checkboxCircleOff: "Ⓘ",
2296
+ pointer: "❯",
2297
+ triangleUpOutline: "△",
2298
+ triangleLeft: "◀",
2299
+ triangleRight: "▶",
2300
+ lozenge: "◆",
2301
+ lozengeOutline: "◇",
2302
+ hamburger: "☰",
2303
+ smiley: "㋡",
2304
+ mustache: "෴",
2305
+ star: "★",
2306
+ play: "▶",
2307
+ nodejs: "⬢",
2308
+ oneSeventh: "⅐",
2309
+ oneNinth: "⅑",
2310
+ oneTenth: "⅒"
2311
+ };
2312
+ var specialFallbackSymbols = {
2313
+ tick: "√",
2314
+ info: "i",
2315
+ warning: "‼",
2316
+ cross: "×",
2317
+ squareSmall: "□",
2318
+ squareSmallFilled: "■",
2319
+ circle: "( )",
2320
+ circleFilled: "(*)",
2321
+ circleDotted: "( )",
2322
+ circleDouble: "( )",
2323
+ circleCircle: "(○)",
2324
+ circleCross: "(×)",
2325
+ circlePipe: "(│)",
2326
+ radioOn: "(*)",
2327
+ radioOff: "( )",
2328
+ checkboxOn: "[×]",
2329
+ checkboxOff: "[ ]",
2330
+ checkboxCircleOn: "(×)",
2331
+ checkboxCircleOff: "( )",
2332
+ pointer: ">",
2333
+ triangleUpOutline: "∆",
2334
+ triangleLeft: "◄",
2335
+ triangleRight: "►",
2336
+ lozenge: "♦",
2337
+ lozengeOutline: "◊",
2338
+ hamburger: "≡",
2339
+ smiley: "☺",
2340
+ mustache: "┌─┐",
2341
+ star: "✶",
2342
+ play: "►",
2343
+ nodejs: "♦",
2344
+ oneSeventh: "1/7",
2345
+ oneNinth: "1/9",
2346
+ oneTenth: "1/10"
2347
+ };
2348
+ var mainSymbols = {
2349
+ ...common,
2350
+ ...specialMainSymbols
2351
+ };
2352
+ var fallbackSymbols = {
2353
+ ...common,
2354
+ ...specialFallbackSymbols
2355
+ };
2356
+ var shouldUseMain = isUnicodeSupported();
2357
+ var figures = shouldUseMain ? mainSymbols : fallbackSymbols;
2358
+ var dist_default = figures;
2359
+ var replacements = Object.entries(specialMainSymbols);
2360
+
2361
+ // ../../node_modules/.bun/@inquirer+core@11.2.1+e154a6929a67600d/node_modules/@inquirer/core/dist/lib/theme.js
2362
+ var defaultTheme = {
2363
+ prefix: {
2364
+ idle: styleText("blue", "?"),
2365
+ done: styleText("green", dist_default.tick)
2366
+ },
2367
+ spinner: {
2368
+ interval: 80,
2369
+ frames: ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"].map((frame) => styleText("yellow", frame))
2370
+ },
2371
+ keybindings: [],
2372
+ style: {
2373
+ answer: (text) => styleText("cyan", text),
2374
+ message: (text) => styleText("bold", text),
2375
+ error: (text) => styleText("red", `> ${text}`),
2376
+ defaultAnswer: (text) => styleText("dim", `(${text})`),
2377
+ help: (text) => styleText("dim", text),
2378
+ highlight: (text) => styleText("cyan", text),
2379
+ key: (text) => styleText("cyan", styleText("bold", `<${text}>`))
2380
+ }
2381
+ };
2382
+ function getDefaultTheme() {
1606
2383
  return {
1607
- ...options,
1608
- selectedModules,
1609
- includeExample: selectedModules.includes("work-order"),
1610
- includeOxc,
1611
- projectLicense,
1612
- licenseHolder,
1613
- interactive: false
2384
+ ...defaultTheme,
2385
+ keybindings: getDefaultKeybindings()
1614
2386
  };
1615
2387
  }
1616
- function terminalPrompter() {
1617
- const question = async (message) => {
1618
- const readline = createInterface({ input: stdin, output: stdout });
1619
- try {
1620
- return await readline.question(message);
1621
- } finally {
1622
- readline.close();
2388
+
2389
+ // ../../node_modules/.bun/@inquirer+core@11.2.1+e154a6929a67600d/node_modules/@inquirer/core/dist/lib/make-theme.js
2390
+ function isPlainObject(value) {
2391
+ if (typeof value !== "object" || value === null)
2392
+ return false;
2393
+ let proto = value;
2394
+ while (Object.getPrototypeOf(proto) !== null) {
2395
+ proto = Object.getPrototypeOf(proto);
2396
+ }
2397
+ return Object.getPrototypeOf(value) === proto;
2398
+ }
2399
+ function deepMerge(...objects) {
2400
+ const output = {};
2401
+ for (const obj of objects) {
2402
+ for (const [key, value] of Object.entries(obj)) {
2403
+ const prevValue = output[key];
2404
+ output[key] = isPlainObject(prevValue) && isPlainObject(value) ? deepMerge(prevValue, value) : value;
2405
+ }
2406
+ }
2407
+ return output;
2408
+ }
2409
+ function makeTheme(...themes) {
2410
+ const themesToMerge = [
2411
+ getDefaultTheme(),
2412
+ ...themes.filter((theme) => theme != null)
2413
+ ];
2414
+ return deepMerge(...themesToMerge);
2415
+ }
2416
+
2417
+ // ../../node_modules/.bun/@inquirer+core@11.2.1+e154a6929a67600d/node_modules/@inquirer/core/dist/lib/use-prefix.js
2418
+ function usePrefix({ status = "idle", theme }) {
2419
+ const [showLoader, setShowLoader] = useState(false);
2420
+ const [tick, setTick] = useState(0);
2421
+ const { prefix, spinner } = makeTheme(theme);
2422
+ useEffect(() => {
2423
+ if (status === "loading") {
2424
+ let tickInterval;
2425
+ let inc = -1;
2426
+ const delayTimeout = setTimeout(() => {
2427
+ setShowLoader(true);
2428
+ tickInterval = setInterval(() => {
2429
+ inc = inc + 1;
2430
+ setTick(inc % spinner.frames.length);
2431
+ }, spinner.interval);
2432
+ }, 300);
2433
+ return () => {
2434
+ clearTimeout(delayTimeout);
2435
+ clearInterval(tickInterval);
2436
+ };
2437
+ } else {
2438
+ setShowLoader(false);
1623
2439
  }
2440
+ }, [status]);
2441
+ if (showLoader) {
2442
+ return spinner.frames[tick];
2443
+ }
2444
+ const iconName = status === "loading" ? "idle" : status;
2445
+ return typeof prefix === "string" ? prefix : prefix[iconName] ?? prefix["idle"];
2446
+ }
2447
+ // ../../node_modules/.bun/@inquirer+core@11.2.1+e154a6929a67600d/node_modules/@inquirer/core/dist/lib/use-memo.js
2448
+ function useMemo(fn, dependencies) {
2449
+ return withPointer((pointer) => {
2450
+ const prev = pointer.get();
2451
+ if (!prev || prev.dependencies.length !== dependencies.length || prev.dependencies.some((dep, i) => dep !== dependencies[i])) {
2452
+ const value = fn();
2453
+ pointer.set({ value, dependencies });
2454
+ return value;
2455
+ }
2456
+ return prev.value;
2457
+ });
2458
+ }
2459
+ // ../../node_modules/.bun/@inquirer+core@11.2.1+e154a6929a67600d/node_modules/@inquirer/core/dist/lib/use-ref.js
2460
+ function useRef(val) {
2461
+ return useState({ current: val })[0];
2462
+ }
2463
+
2464
+ // ../../node_modules/.bun/@inquirer+core@11.2.1+e154a6929a67600d/node_modules/@inquirer/core/dist/lib/use-keypress.js
2465
+ function useKeypress(userHandler) {
2466
+ const signal = useRef(userHandler);
2467
+ signal.current = userHandler;
2468
+ useEffect((rl) => {
2469
+ let ignore = false;
2470
+ const handler = withUpdates((_input, event) => {
2471
+ if (ignore)
2472
+ return;
2473
+ signal.current(event, rl);
2474
+ });
2475
+ rl.input.on("keypress", handler);
2476
+ return () => {
2477
+ ignore = true;
2478
+ rl.input.removeListener("keypress", handler);
2479
+ };
2480
+ }, []);
2481
+ }
2482
+ // ../../node_modules/.bun/@inquirer+core@11.2.1+e154a6929a67600d/node_modules/@inquirer/core/dist/lib/utils.js
2483
+ var import_cli_width = __toESM(require_cli_width(), 1);
2484
+
2485
+ // ../../node_modules/.bun/fast-string-truncated-width@3.0.3/node_modules/fast-string-truncated-width/dist/utils.js
2486
+ var getCodePointsLength = (() => {
2487
+ const SURROGATE_PAIR_RE = /[\uD800-\uDBFF][\uDC00-\uDFFF]/g;
2488
+ return (input) => {
2489
+ let surrogatePairsNr = 0;
2490
+ SURROGATE_PAIR_RE.lastIndex = 0;
2491
+ while (SURROGATE_PAIR_RE.test(input)) {
2492
+ surrogatePairsNr += 1;
2493
+ }
2494
+ return input.length - surrogatePairsNr;
1624
2495
  };
1625
- return {
1626
- async selectModules({ choices, defaults }) {
1627
- stdout.write(`
1628
- 请选择要生成的平台模块(逗号分隔编号,直接回车采用推荐项):
1629
- `);
1630
- choices.forEach((choice, index) => {
1631
- const checked = defaults.includes(choice.value) ? "x" : " ";
1632
- stdout.write(` ${index + 1}. [${checked}] ${choice.label} — ${choice.hint}
1633
- `);
1634
- });
1635
- const answer = (await question("> ")).trim();
1636
- if (!answer)
1637
- return defaults;
1638
- const indexes = answer.split(",").map((part) => Number(part.trim()) - 1);
1639
- if (indexes.some((index) => !Number.isSafeInteger(index) || !choices[index])) {
1640
- throw new Error("模块选择包含无效编号");
2496
+ })();
2497
+ var isFullWidth = (x) => {
2498
+ return x === 12288 || x >= 65281 && x <= 65376 || x >= 65504 && x <= 65510;
2499
+ };
2500
+ var isWideNotCJKTNotEmoji = (x) => {
2501
+ return x === 8987 || x === 9001 || x >= 12272 && x <= 12287 || x >= 12289 && x <= 12350 || x >= 12441 && x <= 12543 || x >= 12549 && x <= 12591 || x >= 12593 && x <= 12686 || x >= 12688 && x <= 12771 || x >= 12783 && x <= 12830 || x >= 12832 && x <= 12871 || x >= 12880 && x <= 19903 || x >= 65040 && x <= 65049 || x >= 65072 && x <= 65106 || x >= 65108 && x <= 65126 || x >= 65128 && x <= 65131 || x >= 127488 && x <= 127490 || x >= 127504 && x <= 127547 || x >= 127552 && x <= 127560 || x >= 131072 && x <= 196605 || x >= 196608 && x <= 262141;
2502
+ };
2503
+
2504
+ // ../../node_modules/.bun/fast-string-truncated-width@3.0.3/node_modules/fast-string-truncated-width/dist/index.js
2505
+ var ANSI_RE = /[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]|\u001b\]8;[^;]*;.*?(?:\u0007|\u001b\u005c)/y;
2506
+ var CONTROL_RE = /[\x00-\x08\x0A-\x1F\x7F-\x9F]{1,1000}/y;
2507
+ var CJKT_WIDE_RE = /(?:(?![\uFF61-\uFF9F\uFF00-\uFFEF])[\p{Script=Han}\p{Script=Hiragana}\p{Script=Katakana}\p{Script=Hangul}\p{Script=Tangut}]){1,1000}/yu;
2508
+ var TAB_RE = /\t{1,1000}/y;
2509
+ var EMOJI_RE = /[\u{1F1E6}-\u{1F1FF}]{2}|\u{1F3F4}[\u{E0061}-\u{E007A}]{2}[\u{E0030}-\u{E0039}\u{E0061}-\u{E007A}]{1,3}\u{E007F}|(?:\p{Emoji}\uFE0F\u20E3?|\p{Emoji_Modifier_Base}\p{Emoji_Modifier}?|\p{Emoji_Presentation})(?:\u200D(?:\p{Emoji_Modifier_Base}\p{Emoji_Modifier}?|\p{Emoji_Presentation}|\p{Emoji}\uFE0F\u20E3?))*/yu;
2510
+ var LATIN_RE = /(?:[\x20-\x7E\xA0-\xFF](?!\uFE0F)){1,1000}/y;
2511
+ var MODIFIER_RE = /\p{M}+/gu;
2512
+ var NO_TRUNCATION = { limit: Infinity, ellipsis: "" };
2513
+ var getStringTruncatedWidth = (input, truncationOptions = {}, widthOptions = {}) => {
2514
+ const LIMIT = truncationOptions.limit ?? Infinity;
2515
+ const ELLIPSIS = truncationOptions.ellipsis ?? "";
2516
+ const ELLIPSIS_WIDTH = truncationOptions?.ellipsisWidth ?? (ELLIPSIS ? getStringTruncatedWidth(ELLIPSIS, NO_TRUNCATION, widthOptions).width : 0);
2517
+ const ANSI_WIDTH = 0;
2518
+ const CONTROL_WIDTH = widthOptions.controlWidth ?? 0;
2519
+ const TAB_WIDTH = widthOptions.tabWidth ?? 8;
2520
+ const EMOJI_WIDTH = widthOptions.emojiWidth ?? 2;
2521
+ const FULL_WIDTH_WIDTH = 2;
2522
+ const REGULAR_WIDTH = widthOptions.regularWidth ?? 1;
2523
+ const WIDE_WIDTH = widthOptions.wideWidth ?? FULL_WIDTH_WIDTH;
2524
+ const PARSE_BLOCKS = [
2525
+ [LATIN_RE, REGULAR_WIDTH],
2526
+ [ANSI_RE, ANSI_WIDTH],
2527
+ [CONTROL_RE, CONTROL_WIDTH],
2528
+ [TAB_RE, TAB_WIDTH],
2529
+ [EMOJI_RE, EMOJI_WIDTH],
2530
+ [CJKT_WIDE_RE, WIDE_WIDTH]
2531
+ ];
2532
+ let indexPrev = 0;
2533
+ let index = 0;
2534
+ let length = input.length;
2535
+ let lengthExtra = 0;
2536
+ let truncationEnabled = false;
2537
+ let truncationIndex = length;
2538
+ let truncationLimit = Math.max(0, LIMIT - ELLIPSIS_WIDTH);
2539
+ let unmatchedStart = 0;
2540
+ let unmatchedEnd = 0;
2541
+ let width = 0;
2542
+ let widthExtra = 0;
2543
+ outer:
2544
+ while (true) {
2545
+ if (unmatchedEnd > unmatchedStart || index >= length && index > indexPrev) {
2546
+ const unmatched = input.slice(unmatchedStart, unmatchedEnd) || input.slice(indexPrev, index);
2547
+ lengthExtra = 0;
2548
+ for (const char of unmatched.replaceAll(MODIFIER_RE, "")) {
2549
+ const codePoint = char.codePointAt(0) || 0;
2550
+ if (isFullWidth(codePoint)) {
2551
+ widthExtra = FULL_WIDTH_WIDTH;
2552
+ } else if (isWideNotCJKTNotEmoji(codePoint)) {
2553
+ widthExtra = WIDE_WIDTH;
2554
+ } else {
2555
+ widthExtra = REGULAR_WIDTH;
2556
+ }
2557
+ if (width + widthExtra > truncationLimit) {
2558
+ truncationIndex = Math.min(truncationIndex, Math.max(unmatchedStart, indexPrev) + lengthExtra);
2559
+ }
2560
+ if (width + widthExtra > LIMIT) {
2561
+ truncationEnabled = true;
2562
+ break outer;
2563
+ }
2564
+ lengthExtra += char.length;
2565
+ width += widthExtra;
2566
+ }
2567
+ unmatchedStart = unmatchedEnd = 0;
1641
2568
  }
1642
- return [...new Set(indexes.map((index) => choices[index].value))];
1643
- },
1644
- async confirm(message, defaultValue) {
1645
- const hint = defaultValue ? "Y/n" : "y/N";
1646
- const answer = (await question(`${message} (${hint}) `)).trim().toLowerCase();
1647
- if (!answer)
1648
- return defaultValue;
1649
- return answer === "y" || answer === "yes";
1650
- },
1651
- async selectLicense() {
1652
- const answer = (await question(`项目法律许可证:1. UNLICENSED(默认) 2. MIT 3. Apache-2.0
1653
- > `)).trim();
1654
- if (!answer || answer === "1")
1655
- return "UNLICENSED";
1656
- if (answer === "2")
1657
- return "MIT";
1658
- if (answer === "3")
1659
- return "Apache-2.0";
1660
- throw new Error("许可证选择包含无效编号");
1661
- },
1662
- text(message) {
1663
- return question(message);
2569
+ if (index >= length) {
2570
+ break outer;
2571
+ }
2572
+ for (let i = 0, l = PARSE_BLOCKS.length;i < l; i++) {
2573
+ const [BLOCK_RE, BLOCK_WIDTH] = PARSE_BLOCKS[i];
2574
+ BLOCK_RE.lastIndex = index;
2575
+ if (BLOCK_RE.test(input)) {
2576
+ lengthExtra = BLOCK_RE === CJKT_WIDE_RE ? getCodePointsLength(input.slice(index, BLOCK_RE.lastIndex)) : BLOCK_RE === EMOJI_RE ? 1 : BLOCK_RE.lastIndex - index;
2577
+ widthExtra = lengthExtra * BLOCK_WIDTH;
2578
+ if (width + widthExtra > truncationLimit) {
2579
+ truncationIndex = Math.min(truncationIndex, index + Math.floor((truncationLimit - width) / BLOCK_WIDTH));
2580
+ }
2581
+ if (width + widthExtra > LIMIT) {
2582
+ truncationEnabled = true;
2583
+ break outer;
2584
+ }
2585
+ width += widthExtra;
2586
+ unmatchedStart = indexPrev;
2587
+ unmatchedEnd = index;
2588
+ index = indexPrev = BLOCK_RE.lastIndex;
2589
+ continue outer;
2590
+ }
2591
+ }
2592
+ index += 1;
1664
2593
  }
2594
+ return {
2595
+ width: truncationEnabled ? truncationLimit : width,
2596
+ index: truncationEnabled ? truncationIndex : length,
2597
+ truncated: truncationEnabled,
2598
+ ellipsed: truncationEnabled && LIMIT >= ELLIPSIS_WIDTH
1665
2599
  };
1666
- }
2600
+ };
2601
+ var dist_default2 = getStringTruncatedWidth;
1667
2602
 
1668
- // src/cli.ts
1669
- async function main() {
1670
- const options = parseArguments(process.argv.slice(2));
2603
+ // ../../node_modules/.bun/fast-string-width@3.0.2/node_modules/fast-string-width/dist/index.js
2604
+ var NO_TRUNCATION2 = {
2605
+ limit: Infinity,
2606
+ ellipsis: "",
2607
+ ellipsisWidth: 0
2608
+ };
2609
+ var fastStringWidth = (input, options = {}) => {
2610
+ return dist_default2(input, NO_TRUNCATION2, options).width;
2611
+ };
2612
+ var dist_default3 = fastStringWidth;
2613
+
2614
+ // ../../node_modules/.bun/fast-wrap-ansi@0.2.2/node_modules/fast-wrap-ansi/lib/main.js
2615
+ var ESC = "\x1B";
2616
+ var CSI = "›";
2617
+ var END_CODE = 39;
2618
+ var ANSI_ESCAPE_BELL = "\x07";
2619
+ var ANSI_CSI = "[";
2620
+ var ANSI_OSC = "]";
2621
+ var ANSI_SGR_TERMINATOR = "m";
2622
+ var ANSI_ESCAPE_LINK = `${ANSI_OSC}8;;`;
2623
+ var GROUP_REGEX = new RegExp(`(?:\\${ANSI_CSI}(?<code>\\d+)m|\\${ANSI_ESCAPE_LINK}(?<uri>.*)${ANSI_ESCAPE_BELL})`, "y");
2624
+ var getClosingCode = (openingCode) => {
2625
+ if (openingCode >= 30 && openingCode <= 37)
2626
+ return 39;
2627
+ if (openingCode >= 90 && openingCode <= 97)
2628
+ return 39;
2629
+ if (openingCode >= 40 && openingCode <= 47)
2630
+ return 49;
2631
+ if (openingCode >= 100 && openingCode <= 107)
2632
+ return 49;
2633
+ if (openingCode === 1 || openingCode === 2)
2634
+ return 22;
2635
+ if (openingCode === 3)
2636
+ return 23;
2637
+ if (openingCode === 4)
2638
+ return 24;
2639
+ if (openingCode === 7)
2640
+ return 27;
2641
+ if (openingCode === 8)
2642
+ return 28;
2643
+ if (openingCode === 9)
2644
+ return 29;
2645
+ if (openingCode === 0)
2646
+ return 0;
2647
+ return;
2648
+ };
2649
+ var wrapAnsiCode = (code) => `${ESC}${ANSI_CSI}${code}${ANSI_SGR_TERMINATOR}`;
2650
+ var wrapAnsiHyperlink = (url) => `${ESC}${ANSI_ESCAPE_LINK}${url}${ANSI_ESCAPE_BELL}`;
2651
+ var wrapWord = (rows, word, columns) => {
2652
+ const characters = word[Symbol.iterator]();
2653
+ let isInsideEscape = false;
2654
+ let isInsideLinkEscape = false;
2655
+ let lastRow = rows.at(-1);
2656
+ let visible = lastRow === undefined ? 0 : dist_default3(lastRow);
2657
+ let currentCharacter = characters.next();
2658
+ let nextCharacter = characters.next();
2659
+ let rawCharacterIndex = 0;
2660
+ while (!currentCharacter.done) {
2661
+ const character = currentCharacter.value;
2662
+ const characterLength = dist_default3(character);
2663
+ if (visible + characterLength <= columns) {
2664
+ rows[rows.length - 1] += character;
2665
+ } else {
2666
+ rows.push(character);
2667
+ visible = 0;
2668
+ }
2669
+ if (character === ESC || character === CSI) {
2670
+ isInsideEscape = true;
2671
+ isInsideLinkEscape = word.startsWith(ANSI_ESCAPE_LINK, rawCharacterIndex + 1);
2672
+ }
2673
+ if (isInsideEscape) {
2674
+ if (isInsideLinkEscape) {
2675
+ if (character === ANSI_ESCAPE_BELL) {
2676
+ isInsideEscape = false;
2677
+ isInsideLinkEscape = false;
2678
+ }
2679
+ } else if (character === ANSI_SGR_TERMINATOR) {
2680
+ isInsideEscape = false;
2681
+ }
2682
+ } else {
2683
+ visible += characterLength;
2684
+ if (visible === columns && !nextCharacter.done) {
2685
+ rows.push("");
2686
+ visible = 0;
2687
+ }
2688
+ }
2689
+ currentCharacter = nextCharacter;
2690
+ nextCharacter = characters.next();
2691
+ rawCharacterIndex += character.length;
2692
+ }
2693
+ lastRow = rows.at(-1);
2694
+ if (!visible && lastRow !== undefined && lastRow.length && rows.length > 1) {
2695
+ rows[rows.length - 2] += rows.pop();
2696
+ }
2697
+ };
2698
+ var stringVisibleTrimSpacesRight = (string) => {
2699
+ const words = string.split(" ");
2700
+ let last = words.length;
2701
+ while (last) {
2702
+ if (dist_default3(words[last - 1])) {
2703
+ break;
2704
+ }
2705
+ last--;
2706
+ }
2707
+ if (last === words.length) {
2708
+ return string;
2709
+ }
2710
+ return words.slice(0, last).join(" ") + words.slice(last).join("");
2711
+ };
2712
+ var exec = (string, columns, options = {}) => {
2713
+ if (options.trim !== false && string.trim() === "") {
2714
+ return "";
2715
+ }
2716
+ let returnValue = "";
2717
+ let escapeCode;
2718
+ let escapeUrl;
2719
+ const words = string.split(" ");
2720
+ let rows = [""];
2721
+ let rowLength = 0;
2722
+ for (let index = 0;index < words.length; index++) {
2723
+ const word = words[index];
2724
+ if (options.trim !== false) {
2725
+ const row = rows.at(-1) ?? "";
2726
+ const trimmed = row.trimStart();
2727
+ if (row.length !== trimmed.length) {
2728
+ rows[rows.length - 1] = trimmed;
2729
+ rowLength = dist_default3(trimmed);
2730
+ }
2731
+ }
2732
+ if (index !== 0) {
2733
+ if (rowLength >= columns && (options.wordWrap === false || options.trim === false)) {
2734
+ rows.push("");
2735
+ rowLength = 0;
2736
+ }
2737
+ if (rowLength || options.trim === false) {
2738
+ rows[rows.length - 1] += " ";
2739
+ rowLength++;
2740
+ }
2741
+ }
2742
+ const wordLength = dist_default3(word);
2743
+ if (options.hard && wordLength > columns) {
2744
+ const remainingColumns = columns - rowLength;
2745
+ const breaksStartingThisLine = 1 + Math.floor((wordLength - remainingColumns - 1) / columns);
2746
+ const breaksStartingNextLine = Math.floor((wordLength - 1) / columns);
2747
+ if (breaksStartingNextLine < breaksStartingThisLine) {
2748
+ rows.push("");
2749
+ }
2750
+ wrapWord(rows, word, columns);
2751
+ rowLength = dist_default3(rows.at(-1) ?? "");
2752
+ continue;
2753
+ }
2754
+ if (rowLength + wordLength > columns && rowLength && wordLength) {
2755
+ if (options.wordWrap === false && rowLength < columns) {
2756
+ wrapWord(rows, word, columns);
2757
+ rowLength = dist_default3(rows.at(-1) ?? "");
2758
+ continue;
2759
+ }
2760
+ rows.push("");
2761
+ rowLength = 0;
2762
+ }
2763
+ if (rowLength + wordLength > columns && options.wordWrap === false) {
2764
+ wrapWord(rows, word, columns);
2765
+ rowLength = dist_default3(rows.at(-1) ?? "");
2766
+ continue;
2767
+ }
2768
+ rows[rows.length - 1] += word;
2769
+ rowLength += wordLength;
2770
+ }
2771
+ if (options.trim !== false) {
2772
+ rows = rows.map((row) => stringVisibleTrimSpacesRight(row));
2773
+ }
2774
+ const preString = rows.join(`
2775
+ `);
2776
+ let inSurrogate = false;
2777
+ for (let i = 0;i < preString.length; i++) {
2778
+ const character = preString[i];
2779
+ returnValue += character;
2780
+ if (!inSurrogate) {
2781
+ inSurrogate = character >= "\uD800" && character <= "\uDBFF";
2782
+ if (inSurrogate) {
2783
+ continue;
2784
+ }
2785
+ } else {
2786
+ inSurrogate = false;
2787
+ }
2788
+ if (character === ESC || character === CSI) {
2789
+ GROUP_REGEX.lastIndex = i + 1;
2790
+ const groupsResult = GROUP_REGEX.exec(preString);
2791
+ const groups = groupsResult?.groups;
2792
+ if (groups?.code !== undefined) {
2793
+ const code = Number.parseFloat(groups.code);
2794
+ escapeCode = code === END_CODE ? undefined : code;
2795
+ } else if (groups?.uri !== undefined) {
2796
+ escapeUrl = groups.uri.length === 0 ? undefined : groups.uri;
2797
+ }
2798
+ }
2799
+ if (preString[i + 1] === `
2800
+ `) {
2801
+ if (escapeUrl) {
2802
+ returnValue += wrapAnsiHyperlink("");
2803
+ }
2804
+ const closingCode = escapeCode ? getClosingCode(escapeCode) : undefined;
2805
+ if (escapeCode && closingCode) {
2806
+ returnValue += wrapAnsiCode(closingCode);
2807
+ }
2808
+ } else if (character === `
2809
+ `) {
2810
+ if (escapeCode && getClosingCode(escapeCode)) {
2811
+ returnValue += wrapAnsiCode(escapeCode);
2812
+ }
2813
+ if (escapeUrl) {
2814
+ returnValue += wrapAnsiHyperlink(escapeUrl);
2815
+ }
2816
+ }
2817
+ }
2818
+ return returnValue;
2819
+ };
2820
+ var CRLF_OR_LF = /\r?\n/;
2821
+ function wrapAnsi(string, columns, options) {
2822
+ return String(string).normalize().split(CRLF_OR_LF).map((line) => exec(line, columns, options)).join(`
2823
+ `);
2824
+ }
2825
+
2826
+ // ../../node_modules/.bun/@inquirer+core@11.2.1+e154a6929a67600d/node_modules/@inquirer/core/dist/lib/utils.js
2827
+ function breakLines(content, width) {
2828
+ return content.split(`
2829
+ `).flatMap((line) => wrapAnsi(line, width, { trim: false, wordWrap: false }).split(`
2830
+ `).map((str) => str.trimEnd())).join(`
2831
+ `);
2832
+ }
2833
+ function readlineWidth() {
2834
+ return import_cli_width.default({ defaultWidth: 80, output: readline().output });
2835
+ }
2836
+
2837
+ // ../../node_modules/.bun/@inquirer+core@11.2.1+e154a6929a67600d/node_modules/@inquirer/core/dist/lib/pagination/use-pagination.js
2838
+ function usePointerPosition({ active, renderedItems, pageSize, loop }) {
2839
+ const state = useRef({
2840
+ lastPointer: active,
2841
+ lastActive: undefined
2842
+ });
2843
+ const { lastPointer, lastActive } = state.current;
2844
+ const middle = Math.floor(pageSize / 2);
2845
+ const renderedLength = renderedItems.reduce((acc, item) => acc + item.length, 0);
2846
+ const defaultPointerPosition = renderedItems.slice(0, active).reduce((acc, item) => acc + item.length, 0);
2847
+ let pointer = defaultPointerPosition;
2848
+ if (renderedLength > pageSize) {
2849
+ if (loop) {
2850
+ pointer = lastPointer;
2851
+ if (lastActive != null && lastActive < active && active - lastActive < pageSize) {
2852
+ pointer = Math.min(middle, Math.abs(active - lastActive) === 1 ? Math.min(lastPointer + (renderedItems[lastActive]?.length ?? 0), Math.max(defaultPointerPosition, lastPointer)) : lastPointer + active - lastActive);
2853
+ }
2854
+ } else {
2855
+ const spaceUnderActive = renderedItems.slice(active).reduce((acc, item) => acc + item.length, 0);
2856
+ pointer = spaceUnderActive < pageSize - middle ? pageSize - spaceUnderActive : Math.min(defaultPointerPosition, middle);
2857
+ }
2858
+ }
2859
+ state.current.lastPointer = pointer;
2860
+ state.current.lastActive = active;
2861
+ return pointer;
2862
+ }
2863
+ function usePagination({ items, active, renderItem, pageSize, loop = true }) {
2864
+ const width = readlineWidth();
2865
+ const bound = (num) => (num % items.length + items.length) % items.length;
2866
+ const renderedItems = items.map((item, index) => {
2867
+ if (item == null)
2868
+ return [];
2869
+ return breakLines(renderItem({ item, index, isActive: index === active }), width).split(`
2870
+ `);
2871
+ });
2872
+ const renderedLength = renderedItems.reduce((acc, item) => acc + item.length, 0);
2873
+ const renderItemAtIndex = (index) => renderedItems[index] ?? [];
2874
+ const pointer = usePointerPosition({ active, renderedItems, pageSize, loop });
2875
+ const activeItem = renderItemAtIndex(active).slice(0, pageSize);
2876
+ const activeItemPosition = pointer + activeItem.length <= pageSize ? pointer : pageSize - activeItem.length;
2877
+ const pageBuffer = Array.from({ length: pageSize });
2878
+ pageBuffer.splice(activeItemPosition, activeItem.length, ...activeItem);
2879
+ const itemVisited = new Set([active]);
2880
+ let bufferPointer = activeItemPosition + activeItem.length;
2881
+ let itemPointer = bound(active + 1);
2882
+ while (bufferPointer < pageSize && !itemVisited.has(itemPointer) && (loop && renderedLength > pageSize ? itemPointer !== active : itemPointer > active)) {
2883
+ const lines = renderItemAtIndex(itemPointer);
2884
+ const linesToAdd = lines.slice(0, pageSize - bufferPointer);
2885
+ pageBuffer.splice(bufferPointer, linesToAdd.length, ...linesToAdd);
2886
+ itemVisited.add(itemPointer);
2887
+ bufferPointer += linesToAdd.length;
2888
+ itemPointer = bound(itemPointer + 1);
2889
+ }
2890
+ bufferPointer = activeItemPosition - 1;
2891
+ itemPointer = bound(active - 1);
2892
+ while (bufferPointer >= 0 && !itemVisited.has(itemPointer) && (loop && renderedLength > pageSize ? itemPointer !== active : itemPointer < active)) {
2893
+ const lines = renderItemAtIndex(itemPointer);
2894
+ const linesToAdd = lines.slice(Math.max(0, lines.length - bufferPointer - 1));
2895
+ pageBuffer.splice(bufferPointer - linesToAdd.length + 1, linesToAdd.length, ...linesToAdd);
2896
+ itemVisited.add(itemPointer);
2897
+ bufferPointer -= linesToAdd.length;
2898
+ itemPointer = bound(itemPointer - 1);
2899
+ }
2900
+ return pageBuffer.filter((line) => typeof line === "string").join(`
2901
+ `);
2902
+ }
2903
+ // ../../node_modules/.bun/@inquirer+core@11.2.1+e154a6929a67600d/node_modules/@inquirer/core/dist/lib/create-prompt.js
2904
+ var import_mute_stream = __toESM(require_lib(), 1);
2905
+ import * as readline2 from "node:readline";
2906
+ import { AsyncResource as AsyncResource3 } from "node:async_hooks";
2907
+
2908
+ // ../../node_modules/.bun/signal-exit@4.1.0/node_modules/signal-exit/dist/mjs/signals.js
2909
+ var signals = [];
2910
+ signals.push("SIGHUP", "SIGINT", "SIGTERM");
2911
+ if (process.platform !== "win32") {
2912
+ signals.push("SIGALRM", "SIGABRT", "SIGVTALRM", "SIGXCPU", "SIGXFSZ", "SIGUSR2", "SIGTRAP", "SIGSYS", "SIGQUIT", "SIGIOT");
2913
+ }
2914
+ if (process.platform === "linux") {
2915
+ signals.push("SIGIO", "SIGPOLL", "SIGPWR", "SIGSTKFLT");
2916
+ }
2917
+
2918
+ // ../../node_modules/.bun/signal-exit@4.1.0/node_modules/signal-exit/dist/mjs/index.js
2919
+ var processOk = (process3) => !!process3 && typeof process3 === "object" && typeof process3.removeListener === "function" && typeof process3.emit === "function" && typeof process3.reallyExit === "function" && typeof process3.listeners === "function" && typeof process3.kill === "function" && typeof process3.pid === "number" && typeof process3.on === "function";
2920
+ var kExitEmitter = Symbol.for("signal-exit emitter");
2921
+ var global = globalThis;
2922
+ var ObjectDefineProperty = Object.defineProperty.bind(Object);
2923
+
2924
+ class Emitter {
2925
+ emitted = {
2926
+ afterExit: false,
2927
+ exit: false
2928
+ };
2929
+ listeners = {
2930
+ afterExit: [],
2931
+ exit: []
2932
+ };
2933
+ count = 0;
2934
+ id = Math.random();
2935
+ constructor() {
2936
+ if (global[kExitEmitter]) {
2937
+ return global[kExitEmitter];
2938
+ }
2939
+ ObjectDefineProperty(global, kExitEmitter, {
2940
+ value: this,
2941
+ writable: false,
2942
+ enumerable: false,
2943
+ configurable: false
2944
+ });
2945
+ }
2946
+ on(ev, fn) {
2947
+ this.listeners[ev].push(fn);
2948
+ }
2949
+ removeListener(ev, fn) {
2950
+ const list = this.listeners[ev];
2951
+ const i = list.indexOf(fn);
2952
+ if (i === -1) {
2953
+ return;
2954
+ }
2955
+ if (i === 0 && list.length === 1) {
2956
+ list.length = 0;
2957
+ } else {
2958
+ list.splice(i, 1);
2959
+ }
2960
+ }
2961
+ emit(ev, code, signal) {
2962
+ if (this.emitted[ev]) {
2963
+ return false;
2964
+ }
2965
+ this.emitted[ev] = true;
2966
+ let ret = false;
2967
+ for (const fn of this.listeners[ev]) {
2968
+ ret = fn(code, signal) === true || ret;
2969
+ }
2970
+ if (ev === "exit") {
2971
+ ret = this.emit("afterExit", code, signal) || ret;
2972
+ }
2973
+ return ret;
2974
+ }
2975
+ }
2976
+
2977
+ class SignalExitBase {
2978
+ }
2979
+ var signalExitWrap = (handler) => {
2980
+ return {
2981
+ onExit(cb, opts) {
2982
+ return handler.onExit(cb, opts);
2983
+ },
2984
+ load() {
2985
+ return handler.load();
2986
+ },
2987
+ unload() {
2988
+ return handler.unload();
2989
+ }
2990
+ };
2991
+ };
2992
+
2993
+ class SignalExitFallback extends SignalExitBase {
2994
+ onExit() {
2995
+ return () => {};
2996
+ }
2997
+ load() {}
2998
+ unload() {}
2999
+ }
3000
+
3001
+ class SignalExit extends SignalExitBase {
3002
+ #hupSig = process3.platform === "win32" ? "SIGINT" : "SIGHUP";
3003
+ #emitter = new Emitter;
3004
+ #process;
3005
+ #originalProcessEmit;
3006
+ #originalProcessReallyExit;
3007
+ #sigListeners = {};
3008
+ #loaded = false;
3009
+ constructor(process3) {
3010
+ super();
3011
+ this.#process = process3;
3012
+ this.#sigListeners = {};
3013
+ for (const sig of signals) {
3014
+ this.#sigListeners[sig] = () => {
3015
+ const listeners = this.#process.listeners(sig);
3016
+ let { count } = this.#emitter;
3017
+ const p = process3;
3018
+ if (typeof p.__signal_exit_emitter__ === "object" && typeof p.__signal_exit_emitter__.count === "number") {
3019
+ count += p.__signal_exit_emitter__.count;
3020
+ }
3021
+ if (listeners.length === count) {
3022
+ this.unload();
3023
+ const ret = this.#emitter.emit("exit", null, sig);
3024
+ const s = sig === "SIGHUP" ? this.#hupSig : sig;
3025
+ if (!ret)
3026
+ process3.kill(process3.pid, s);
3027
+ }
3028
+ };
3029
+ }
3030
+ this.#originalProcessReallyExit = process3.reallyExit;
3031
+ this.#originalProcessEmit = process3.emit;
3032
+ }
3033
+ onExit(cb, opts) {
3034
+ if (!processOk(this.#process)) {
3035
+ return () => {};
3036
+ }
3037
+ if (this.#loaded === false) {
3038
+ this.load();
3039
+ }
3040
+ const ev = opts?.alwaysLast ? "afterExit" : "exit";
3041
+ this.#emitter.on(ev, cb);
3042
+ return () => {
3043
+ this.#emitter.removeListener(ev, cb);
3044
+ if (this.#emitter.listeners["exit"].length === 0 && this.#emitter.listeners["afterExit"].length === 0) {
3045
+ this.unload();
3046
+ }
3047
+ };
3048
+ }
3049
+ load() {
3050
+ if (this.#loaded) {
3051
+ return;
3052
+ }
3053
+ this.#loaded = true;
3054
+ this.#emitter.count += 1;
3055
+ for (const sig of signals) {
3056
+ try {
3057
+ const fn = this.#sigListeners[sig];
3058
+ if (fn)
3059
+ this.#process.on(sig, fn);
3060
+ } catch (_) {}
3061
+ }
3062
+ this.#process.emit = (ev, ...a) => {
3063
+ return this.#processEmit(ev, ...a);
3064
+ };
3065
+ this.#process.reallyExit = (code) => {
3066
+ return this.#processReallyExit(code);
3067
+ };
3068
+ }
3069
+ unload() {
3070
+ if (!this.#loaded) {
3071
+ return;
3072
+ }
3073
+ this.#loaded = false;
3074
+ signals.forEach((sig) => {
3075
+ const listener = this.#sigListeners[sig];
3076
+ if (!listener) {
3077
+ throw new Error("Listener not defined for signal: " + sig);
3078
+ }
3079
+ try {
3080
+ this.#process.removeListener(sig, listener);
3081
+ } catch (_) {}
3082
+ });
3083
+ this.#process.emit = this.#originalProcessEmit;
3084
+ this.#process.reallyExit = this.#originalProcessReallyExit;
3085
+ this.#emitter.count -= 1;
3086
+ }
3087
+ #processReallyExit(code) {
3088
+ if (!processOk(this.#process)) {
3089
+ return 0;
3090
+ }
3091
+ this.#process.exitCode = code || 0;
3092
+ this.#emitter.emit("exit", this.#process.exitCode, null);
3093
+ return this.#originalProcessReallyExit.call(this.#process, this.#process.exitCode);
3094
+ }
3095
+ #processEmit(ev, ...args) {
3096
+ const og = this.#originalProcessEmit;
3097
+ if (ev === "exit" && processOk(this.#process)) {
3098
+ if (typeof args[0] === "number") {
3099
+ this.#process.exitCode = args[0];
3100
+ }
3101
+ const ret = og.call(this.#process, ev, ...args);
3102
+ this.#emitter.emit("exit", this.#process.exitCode, null);
3103
+ return ret;
3104
+ } else {
3105
+ return og.call(this.#process, ev, ...args);
3106
+ }
3107
+ }
3108
+ }
3109
+ var process3 = globalThis.process;
3110
+ var {
3111
+ onExit,
3112
+ load,
3113
+ unload
3114
+ } = signalExitWrap(processOk(process3) ? new SignalExit(process3) : new SignalExitFallback);
3115
+
3116
+ // ../../node_modules/.bun/@inquirer+core@11.2.1+e154a6929a67600d/node_modules/@inquirer/core/dist/lib/screen-manager.js
3117
+ import { stripVTControlCharacters } from "node:util";
3118
+
3119
+ // ../../node_modules/.bun/@inquirer+ansi@2.0.7/node_modules/@inquirer/ansi/dist/index.js
3120
+ var ESC2 = "\x1B[";
3121
+ var cursorLeft = ESC2 + "G";
3122
+ var cursorHide = ESC2 + "?25l";
3123
+ var cursorShow = ESC2 + "?25h";
3124
+ var cursorUp = (rows = 1) => rows > 0 ? `${ESC2}${rows}A` : "";
3125
+ var cursorDown = (rows = 1) => rows > 0 ? `${ESC2}${rows}B` : "";
3126
+ var cursorTo = (x, y) => {
3127
+ if (typeof y === "number" && !Number.isNaN(y)) {
3128
+ return `${ESC2}${y + 1};${x + 1}H`;
3129
+ }
3130
+ return `${ESC2}${x + 1}G`;
3131
+ };
3132
+ var eraseLine = ESC2 + "2K";
3133
+ var eraseLines = (lines) => lines > 0 ? (eraseLine + cursorUp(1)).repeat(lines - 1) + eraseLine + cursorLeft : "";
3134
+
3135
+ // ../../node_modules/.bun/@inquirer+core@11.2.1+e154a6929a67600d/node_modules/@inquirer/core/dist/lib/screen-manager.js
3136
+ var height = (content) => content.split(`
3137
+ `).length;
3138
+ var lastLine = (content) => content.split(`
3139
+ `).pop() ?? "";
3140
+
3141
+ class ScreenManager {
3142
+ height = 0;
3143
+ extraLinesUnderPrompt = 0;
3144
+ cursorPos;
3145
+ rl;
3146
+ constructor(rl) {
3147
+ this.rl = rl;
3148
+ this.cursorPos = rl.getCursorPos();
3149
+ }
3150
+ write(content) {
3151
+ this.rl.output.unmute();
3152
+ this.rl.output.write(content);
3153
+ this.rl.output.mute();
3154
+ }
3155
+ render(content, bottomContent = "") {
3156
+ const promptLine = lastLine(content);
3157
+ const rawPromptLine = stripVTControlCharacters(promptLine);
3158
+ let prompt = rawPromptLine;
3159
+ if (this.rl.line.length > 0) {
3160
+ prompt = prompt.slice(0, -this.rl.line.length);
3161
+ }
3162
+ this.rl.setPrompt(prompt);
3163
+ this.cursorPos = this.rl.getCursorPos();
3164
+ const width = readlineWidth();
3165
+ content = breakLines(content, width);
3166
+ bottomContent = breakLines(bottomContent, width);
3167
+ if (rawPromptLine.length % width === 0) {
3168
+ content += `
3169
+ `;
3170
+ }
3171
+ let output = content + (bottomContent ? `
3172
+ ` + bottomContent : "");
3173
+ const promptLineUpDiff = Math.floor(rawPromptLine.length / width) - this.cursorPos.rows;
3174
+ const bottomContentHeight = promptLineUpDiff + (bottomContent ? height(bottomContent) : 0);
3175
+ if (bottomContentHeight > 0)
3176
+ output += cursorUp(bottomContentHeight);
3177
+ output += cursorTo(this.cursorPos.cols);
3178
+ this.write(cursorDown(this.extraLinesUnderPrompt) + eraseLines(this.height) + output);
3179
+ this.extraLinesUnderPrompt = bottomContentHeight;
3180
+ this.height = height(output);
3181
+ }
3182
+ checkCursorPos() {
3183
+ const cursorPos = this.rl.getCursorPos();
3184
+ if (cursorPos.cols !== this.cursorPos.cols) {
3185
+ this.write(cursorTo(cursorPos.cols));
3186
+ this.cursorPos = cursorPos;
3187
+ }
3188
+ }
3189
+ done({ clearContent }) {
3190
+ this.rl.setPrompt("");
3191
+ let output = cursorDown(this.extraLinesUnderPrompt);
3192
+ output += clearContent ? eraseLines(this.height) : `
3193
+ `;
3194
+ output += cursorLeft;
3195
+ output += cursorShow;
3196
+ this.write(output);
3197
+ this.rl.close();
3198
+ }
3199
+ }
3200
+
3201
+ // ../../node_modules/.bun/@inquirer+core@11.2.1+e154a6929a67600d/node_modules/@inquirer/core/dist/lib/promise-polyfill.js
3202
+ class PromisePolyfill extends Promise {
3203
+ static withResolver() {
3204
+ let resolve4;
3205
+ let reject;
3206
+ const promise = new Promise((res, rej) => {
3207
+ resolve4 = res;
3208
+ reject = rej;
3209
+ });
3210
+ return { promise, resolve: resolve4, reject };
3211
+ }
3212
+ }
3213
+
3214
+ // ../../node_modules/.bun/@inquirer+core@11.2.1+e154a6929a67600d/node_modules/@inquirer/core/dist/lib/create-prompt.js
3215
+ import path from "node:path";
3216
+ var nativeSetImmediate = globalThis.setImmediate;
3217
+ function getCallSites() {
3218
+ const savedPrepareStackTrace = Error.prepareStackTrace;
3219
+ let result = [];
3220
+ try {
3221
+ Error.prepareStackTrace = (_, callSites) => {
3222
+ const callSitesWithoutCurrent = callSites.slice(1);
3223
+ result = callSitesWithoutCurrent;
3224
+ return callSitesWithoutCurrent;
3225
+ };
3226
+ new Error().stack;
3227
+ } catch {
3228
+ return result;
3229
+ }
3230
+ Error.prepareStackTrace = savedPrepareStackTrace;
3231
+ return result;
3232
+ }
3233
+ function createPrompt(view) {
3234
+ const callSites = getCallSites();
3235
+ const prompt = (config, context = {}) => {
3236
+ const { input = process.stdin, signal } = context;
3237
+ const cleanups = new Set;
3238
+ const output = new import_mute_stream.default;
3239
+ output.pipe(context.output ?? process.stdout);
3240
+ const rl = readline2.createInterface({
3241
+ terminal: true,
3242
+ input,
3243
+ output
3244
+ });
3245
+ output.mute();
3246
+ const screen = new ScreenManager(rl);
3247
+ const { promise, resolve: resolve4, reject } = PromisePolyfill.withResolver();
3248
+ const cancel = () => reject(new CancelPromptError);
3249
+ if (signal) {
3250
+ const abort = () => reject(new AbortPromptError({ cause: signal.reason }));
3251
+ if (signal.aborted) {
3252
+ abort();
3253
+ return Object.assign(promise, { cancel });
3254
+ }
3255
+ signal.addEventListener("abort", abort);
3256
+ cleanups.add(() => signal.removeEventListener("abort", abort));
3257
+ }
3258
+ cleanups.add(onExit((code, signal2) => {
3259
+ reject(new ExitPromptError(`User force closed the prompt with ${code} ${signal2}`));
3260
+ }));
3261
+ const sigint = () => reject(new ExitPromptError(`User force closed the prompt with SIGINT`));
3262
+ rl.on("SIGINT", sigint);
3263
+ cleanups.add(() => rl.removeListener("SIGINT", sigint));
3264
+ return withHooks(rl, (cycle) => {
3265
+ const hooksCleanup = AsyncResource3.bind(() => effectScheduler.clearAll());
3266
+ rl.on("close", hooksCleanup);
3267
+ cleanups.add(() => rl.removeListener("close", hooksCleanup));
3268
+ const startCycle = () => {
3269
+ const checkCursorPos = () => screen.checkCursorPos();
3270
+ rl.input.on("keypress", checkCursorPos);
3271
+ cleanups.add(() => rl.input.removeListener("keypress", checkCursorPos));
3272
+ let pendingDone = null;
3273
+ cycle(() => {
3274
+ let effectsSettled = false;
3275
+ try {
3276
+ const nextView = view(config, (value) => {
3277
+ if (effectsSettled) {
3278
+ resolve4(value);
3279
+ } else {
3280
+ pendingDone = { value };
3281
+ }
3282
+ });
3283
+ if (nextView === undefined) {
3284
+ let callerFilename = callSites[1]?.getFileName();
3285
+ if (callerFilename && !callerFilename.startsWith("file://")) {
3286
+ callerFilename = path.resolve(callerFilename);
3287
+ }
3288
+ throw new Error(`Prompt functions must return a string.
3289
+ at ${callerFilename}`);
3290
+ }
3291
+ const [content, bottomContent] = typeof nextView === "string" ? [nextView] : nextView;
3292
+ screen.render(content, bottomContent);
3293
+ effectScheduler.run();
3294
+ } catch (error) {
3295
+ reject(error);
3296
+ }
3297
+ effectsSettled = true;
3298
+ if (pendingDone !== null) {
3299
+ const { value } = pendingDone;
3300
+ pendingDone = null;
3301
+ resolve4(value);
3302
+ }
3303
+ });
3304
+ };
3305
+ if ("readableFlowing" in input) {
3306
+ nativeSetImmediate(startCycle);
3307
+ } else {
3308
+ startCycle();
3309
+ }
3310
+ return Object.assign(promise.then((answer) => {
3311
+ effectScheduler.clearAll();
3312
+ return answer;
3313
+ }, (error) => {
3314
+ effectScheduler.clearAll();
3315
+ throw error;
3316
+ }).finally(() => {
3317
+ cleanups.forEach((cleanup) => cleanup());
3318
+ screen.done({ clearContent: Boolean(context.clearPromptOnDone) });
3319
+ output.end();
3320
+ }).then(() => promise), { cancel });
3321
+ });
3322
+ };
3323
+ return prompt;
3324
+ }
3325
+ // ../../node_modules/.bun/@inquirer+core@11.2.1+e154a6929a67600d/node_modules/@inquirer/core/dist/lib/Separator.js
3326
+ import { styleText as styleText2 } from "node:util";
3327
+ class Separator {
3328
+ separator = styleText2("dim", Array.from({ length: 15 }).join(dist_default.line));
3329
+ type = "separator";
3330
+ constructor(separator) {
3331
+ if (separator) {
3332
+ this.separator = separator;
3333
+ }
3334
+ }
3335
+ static isSeparator(choice) {
3336
+ return Boolean(choice && typeof choice === "object" && "type" in choice && choice.type === "separator");
3337
+ }
3338
+ }
3339
+ // ../../node_modules/.bun/@inquirer+checkbox@5.2.1+e154a6929a67600d/node_modules/@inquirer/checkbox/dist/index.js
3340
+ import { styleText as styleText3 } from "node:util";
3341
+ var checkboxTheme = {
3342
+ icon: {
3343
+ checked: styleText3("green", dist_default.circleFilled),
3344
+ unchecked: dist_default.circle,
3345
+ cursor: dist_default.pointer,
3346
+ disabledChecked: styleText3("green", dist_default.circleDouble),
3347
+ disabledUnchecked: "-"
3348
+ },
3349
+ style: {
3350
+ disabled: (text) => styleText3("dim", text),
3351
+ renderSelectedChoices: (selectedChoices) => selectedChoices.map((choice) => choice.short).join(", "),
3352
+ description: (text) => styleText3("cyan", text),
3353
+ keysHelpTip: (keys) => keys.map(([key, action]) => `${styleText3("bold", key)} ${styleText3("dim", action)}`).join(styleText3("dim", " • "))
3354
+ },
3355
+ i18n: { disabledError: "This option is disabled and cannot be toggled." }
3356
+ };
3357
+ function isSelectable(item) {
3358
+ return !Separator.isSeparator(item) && !item.disabled;
3359
+ }
3360
+ function isNavigable(item) {
3361
+ return !Separator.isSeparator(item);
3362
+ }
3363
+ function isChecked(item) {
3364
+ return !Separator.isSeparator(item) && item.checked;
3365
+ }
3366
+ function toggle(item) {
3367
+ return isSelectable(item) ? { ...item, checked: !item.checked } : item;
3368
+ }
3369
+ function check(checked) {
3370
+ return function(item) {
3371
+ return isSelectable(item) ? { ...item, checked } : item;
3372
+ };
3373
+ }
3374
+ function normalizeChoices(choices) {
3375
+ return choices.map((choice) => {
3376
+ if (Separator.isSeparator(choice))
3377
+ return choice;
3378
+ if (typeof choice !== "object" || choice === null || !("value" in choice)) {
3379
+ const name2 = String(choice);
3380
+ return {
3381
+ value: choice,
3382
+ name: name2,
3383
+ short: name2,
3384
+ checkedName: name2,
3385
+ disabled: false,
3386
+ checked: false
3387
+ };
3388
+ }
3389
+ const name = choice.name ?? String(choice.value);
3390
+ const normalizedChoice = {
3391
+ value: choice.value,
3392
+ name,
3393
+ short: choice.short ?? name,
3394
+ checkedName: choice.checkedName ?? name,
3395
+ disabled: choice.disabled ?? false,
3396
+ checked: choice.checked ?? false
3397
+ };
3398
+ if (choice.description) {
3399
+ normalizedChoice.description = choice.description;
3400
+ }
3401
+ return normalizedChoice;
3402
+ });
3403
+ }
3404
+ var dist_default4 = createPrompt((config, done) => {
3405
+ const { pageSize = 7, loop = true, required, validate = () => true } = config;
3406
+ const shortcuts = { all: "a", invert: "i", ...config.shortcuts };
3407
+ const theme = makeTheme(checkboxTheme, config.theme);
3408
+ const { keybindings: keybindings2 } = theme;
3409
+ const [status, setStatus] = useState("idle");
3410
+ const prefix = usePrefix({ status, theme });
3411
+ const [items, setItems] = useState(normalizeChoices(config.choices));
3412
+ const bounds = useMemo(() => {
3413
+ const first = items.findIndex(isNavigable);
3414
+ const last = items.findLastIndex(isNavigable);
3415
+ if (first === -1) {
3416
+ throw new ValidationError("[checkbox prompt] No selectable choices. All choices are disabled.");
3417
+ }
3418
+ return { first, last };
3419
+ }, [items]);
3420
+ const [active, setActive] = useState(bounds.first);
3421
+ const [errorMsg, setError] = useState();
3422
+ useKeypress(async (key) => {
3423
+ if (isEnterKey(key)) {
3424
+ const selection = items.filter(isChecked);
3425
+ const isValid = await validate([...selection]);
3426
+ if (required && !selection.length) {
3427
+ setError("At least one choice must be selected");
3428
+ } else if (isValid === true) {
3429
+ setStatus("done");
3430
+ done(selection.map((choice) => choice.value));
3431
+ } else {
3432
+ setError(isValid || "You must select a valid value");
3433
+ }
3434
+ } else if (isUpKey(key, keybindings2) || isDownKey(key, keybindings2)) {
3435
+ if (errorMsg) {
3436
+ setError(undefined);
3437
+ }
3438
+ if (loop || isUpKey(key, keybindings2) && active !== bounds.first || isDownKey(key, keybindings2) && active !== bounds.last) {
3439
+ const offset = isUpKey(key, keybindings2) ? -1 : 1;
3440
+ let next = active;
3441
+ do {
3442
+ next = (next + offset + items.length) % items.length;
3443
+ } while (!isNavigable(items[next]));
3444
+ setActive(next);
3445
+ }
3446
+ } else if (isSpaceKey(key)) {
3447
+ const activeItem = items[active];
3448
+ if (activeItem && !Separator.isSeparator(activeItem)) {
3449
+ if (activeItem.disabled) {
3450
+ setError(theme.i18n.disabledError);
3451
+ } else {
3452
+ setError(undefined);
3453
+ setItems(items.map((choice, i) => i === active ? toggle(choice) : choice));
3454
+ }
3455
+ }
3456
+ } else if (key.name === shortcuts.all) {
3457
+ const selectAll = items.some((choice) => isSelectable(choice) && !choice.checked);
3458
+ setItems(items.map(check(selectAll)));
3459
+ } else if (key.name === shortcuts.invert) {
3460
+ setItems(items.map(toggle));
3461
+ } else if (isNumberKey(key)) {
3462
+ const selectedIndex = Number(key.name) - 1;
3463
+ let selectableIndex = -1;
3464
+ const position = items.findIndex((item) => {
3465
+ if (Separator.isSeparator(item))
3466
+ return false;
3467
+ selectableIndex++;
3468
+ return selectableIndex === selectedIndex;
3469
+ });
3470
+ const selectedItem = items[position];
3471
+ if (selectedItem && isSelectable(selectedItem)) {
3472
+ setActive(position);
3473
+ setItems(items.map((choice, i) => i === position ? toggle(choice) : choice));
3474
+ }
3475
+ }
3476
+ });
3477
+ const message = theme.style.message(config.message, status);
3478
+ let description;
3479
+ const page = usePagination({
3480
+ items,
3481
+ active,
3482
+ renderItem({ item, isActive }) {
3483
+ if (Separator.isSeparator(item)) {
3484
+ return ` ${item.separator}`;
3485
+ }
3486
+ const cursor = isActive ? theme.icon.cursor : " ";
3487
+ if (item.disabled) {
3488
+ const disabledLabel = typeof item.disabled === "string" ? item.disabled : "(disabled)";
3489
+ const checkbox2 = item.checked ? theme.icon.disabledChecked : theme.icon.disabledUnchecked;
3490
+ return theme.style.disabled(`${cursor}${checkbox2} ${item.name} ${disabledLabel}`);
3491
+ }
3492
+ if (isActive) {
3493
+ description = item.description;
3494
+ }
3495
+ const checkbox = item.checked ? theme.icon.checked : theme.icon.unchecked;
3496
+ const name = item.checked ? item.checkedName : item.name;
3497
+ const color = isActive ? theme.style.highlight : (x) => x;
3498
+ return color(`${cursor}${checkbox} ${name}`);
3499
+ },
3500
+ pageSize,
3501
+ loop
3502
+ });
3503
+ if (status === "done") {
3504
+ const selection = items.filter(isChecked);
3505
+ const answer = theme.style.answer(theme.style.renderSelectedChoices(selection, items));
3506
+ return [prefix, message, answer].filter(Boolean).join(" ");
3507
+ }
3508
+ const keys = [
3509
+ ["↑↓", "navigate"],
3510
+ ["space", "select"]
3511
+ ];
3512
+ if (shortcuts.all)
3513
+ keys.push([shortcuts.all, "all"]);
3514
+ if (shortcuts.invert)
3515
+ keys.push([shortcuts.invert, "invert"]);
3516
+ keys.push(["⏎", "submit"]);
3517
+ const helpLine = theme.style.keysHelpTip(keys);
3518
+ const lines = [
3519
+ [prefix, message].filter(Boolean).join(" "),
3520
+ page,
3521
+ " ",
3522
+ description ? theme.style.description(description) : "",
3523
+ errorMsg ? theme.style.error(errorMsg) : "",
3524
+ helpLine
3525
+ ].filter(Boolean).join(`
3526
+ `).trimEnd();
3527
+ return `${lines}${cursorHide}`;
3528
+ });
3529
+
3530
+ // src/interactive-selection.ts
3531
+ var oxcChoiceKey = "toolchain.oxc";
3532
+ async function applyInteractiveSelection(options, prompter = terminalPrompter()) {
3533
+ if (!options.interactive)
3534
+ return options;
3535
+ const optional = moduleDistributionCatalog.filter(({ name }) => !requiredModuleNames.includes(name));
3536
+ const requested = await prompter.selectGenerationChoices({
3537
+ choices: [
3538
+ ...optional.map(({ name, label, description, selection }) => ({
3539
+ value: name,
3540
+ label: `${label}(${sentenceWithoutStop(description)})`,
3541
+ hint: selection === "recommended" ? "推荐,默认选中" : "可选模块"
3542
+ })),
3543
+ {
3544
+ value: oxcChoiceKey,
3545
+ label: "Oxc 代码质量(Oxlint、Oxfmt 与提交格式化)",
3546
+ hint: "可选基础设施,默认选中"
3547
+ }
3548
+ ],
3549
+ defaults: [...recommendedModuleNames, oxcChoiceKey]
3550
+ });
3551
+ const includeOxc = requested.includes(oxcChoiceKey);
3552
+ const projectLicense = await prompter.selectLicense();
3553
+ const licenseHolder = projectLicense === "MIT" ? (await prompter.text("MIT 许可证权利人名称:")).trim() : undefined;
3554
+ if (projectLicense === "MIT" && !licenseHolder) {
3555
+ throw new Error("选择 MIT 时必须填写许可证权利人名称");
3556
+ }
3557
+ const selectedModules = resolveModuleSelection({
3558
+ includeRecommended: false,
3559
+ requested: requested.filter((value) => value !== oxcChoiceKey)
3560
+ });
3561
+ return {
3562
+ ...options,
3563
+ selectedModules,
3564
+ includeExample: selectedModules.includes("work-order"),
3565
+ includeOxc,
3566
+ projectLicense,
3567
+ licenseHolder,
3568
+ interactive: false
3569
+ };
3570
+ }
3571
+ function terminalPrompter() {
3572
+ const question = async (message) => {
3573
+ const readline3 = createInterface2({ input: stdin, output: stdout });
3574
+ try {
3575
+ return await readline3.question(message);
3576
+ } finally {
3577
+ readline3.close();
3578
+ }
3579
+ };
3580
+ return {
3581
+ async selectGenerationChoices({ choices, defaults }) {
3582
+ return dist_default4({
3583
+ message: "请选择要生成的平台模块和基础设施",
3584
+ choices: choices.map((choice) => ({
3585
+ value: choice.value,
3586
+ name: choice.label,
3587
+ description: choice.hint,
3588
+ checked: defaults.includes(choice.value)
3589
+ })),
3590
+ pageSize: choices.length,
3591
+ loop: false,
3592
+ shortcuts: { all: null, invert: null },
3593
+ theme: {
3594
+ style: {
3595
+ keysHelpTip: () => "↑/↓ 切换 · 空格 选中或取消 · 回车 提交"
3596
+ }
3597
+ }
3598
+ });
3599
+ },
3600
+ async selectLicense() {
3601
+ const answer = (await question(`项目法律许可证:1. UNLICENSED(默认) 2. MIT 3. Apache-2.0
3602
+ > `)).trim();
3603
+ if (!answer || answer === "1")
3604
+ return "UNLICENSED";
3605
+ if (answer === "2")
3606
+ return "MIT";
3607
+ if (answer === "3")
3608
+ return "Apache-2.0";
3609
+ throw new Error("许可证选择包含无效编号");
3610
+ },
3611
+ text(message) {
3612
+ return question(message);
3613
+ }
3614
+ };
3615
+ }
3616
+ function sentenceWithoutStop(value) {
3617
+ return value.replace(/[。.]$/, "");
3618
+ }
3619
+
3620
+ // src/update/cli.ts
3621
+ import { rm as rm8 } from "node:fs/promises";
3622
+ import { resolve as resolve4 } from "node:path";
3623
+
3624
+ // src/update/doctor.ts
3625
+ import { readFile as readFile9 } from "node:fs/promises";
3626
+ import { join as join9 } from "node:path";
3627
+
3628
+ // src/update/process.ts
3629
+ import { spawn as spawn3 } from "node:child_process";
3630
+ async function captureProcess(command, args, cwd, inherit = false) {
3631
+ return await new Promise((resolve4, reject) => {
3632
+ const child = spawn3(command, args, {
3633
+ cwd,
3634
+ stdio: inherit ? "inherit" : ["ignore", "pipe", "pipe"]
3635
+ });
3636
+ let stdout2 = "";
3637
+ let stderr = "";
3638
+ child.stdout?.on("data", (chunk) => stdout2 += chunk.toString());
3639
+ child.stderr?.on("data", (chunk) => stderr += chunk.toString());
3640
+ child.once("error", reject);
3641
+ child.once("exit", (code) => resolve4({ code: code ?? 1, stdout: stdout2, stderr }));
3642
+ });
3643
+ }
3644
+ async function assertProcess(command, args, cwd, inherit = false) {
3645
+ const result = await captureProcess(command, args, cwd, inherit);
3646
+ if (result.code !== 0) {
3647
+ const detail = result.stderr.trim() || result.stdout.trim();
3648
+ throw new Error(`${command} ${args.join(" ")} 执行失败${detail ? `:${detail}` : ""}`);
3649
+ }
3650
+ return result;
3651
+ }
3652
+
3653
+ // src/update/transaction.ts
3654
+ import {
3655
+ access as access2,
3656
+ copyFile as copyFile2,
3657
+ mkdir as mkdir5,
3658
+ readFile as readFile8,
3659
+ rm as rm5,
3660
+ writeFile as writeFile8
3661
+ } from "node:fs/promises";
3662
+ import { dirname as dirname3, join as join8 } from "node:path";
3663
+ var updateStatePath = ".windy/update-state.json";
3664
+ async function applyTransaction(plan) {
3665
+ if (plan.conflicts.length) {
3666
+ throw new Error(`更新存在 ${plan.conflicts.length} 个冲突,未写入任何项目文件`);
3667
+ }
3668
+ const changed = plan.files.filter(({ action }) => action === "create" || action === "update" || action === "delete");
3669
+ for (const file of changed)
3670
+ assertSafePath(file.path);
3671
+ const backupDirectory = join8(plan.projectDirectory, ".windy/backups", plan.id);
3672
+ const protectedPaths = new Set([
3673
+ ...changed.map(({ path: path2 }) => path2),
3674
+ ".windy/generation.json",
3675
+ ".windy/files.json",
3676
+ "bun.lock"
3677
+ ]);
3678
+ const backupEntries = [];
3679
+ for (const path2 of protectedPaths) {
3680
+ const source = join8(plan.projectDirectory, path2);
3681
+ const existed = await exists(source);
3682
+ backupEntries.push({ path: path2, existed });
3683
+ if (!existed)
3684
+ continue;
3685
+ const target = join8(backupDirectory, "files", path2);
3686
+ await mkdir5(dirname3(target), { recursive: true });
3687
+ await copyFile2(source, target);
3688
+ }
3689
+ const state = {
3690
+ schemaVersion: 1,
3691
+ updateId: plan.id,
3692
+ backupDirectory,
3693
+ entries: backupEntries
3694
+ };
3695
+ await writeState(plan.projectDirectory, state);
3696
+ try {
3697
+ for (const file of changed) {
3698
+ const target = join8(plan.projectDirectory, file.path);
3699
+ if (file.action === "delete") {
3700
+ await rm5(target, { force: true });
3701
+ continue;
3702
+ }
3703
+ if (!file.content)
3704
+ throw new Error(`更新计划缺少文件内容:${file.path}`);
3705
+ await mkdir5(dirname3(target), { recursive: true });
3706
+ await writeFile8(target, file.content);
3707
+ }
3708
+ } catch (error) {
3709
+ await restoreUpdateState(plan.projectDirectory, state);
3710
+ throw error;
3711
+ }
3712
+ return {
3713
+ plan,
3714
+ backupDirectory,
3715
+ backupEntries,
3716
+ changedFiles: changed.map(({ path: path2 }) => path2)
3717
+ };
3718
+ }
3719
+ async function readUpdateState(projectDirectory) {
3720
+ try {
3721
+ const parsed = JSON.parse(await readFile8(join8(projectDirectory, updateStatePath), "utf8"));
3722
+ if (!isUpdateState(parsed))
3723
+ throw new Error("更新恢复状态无效,请人工检查 .windy 目录");
3724
+ return parsed;
3725
+ } catch (error) {
3726
+ if (error instanceof Error && "code" in error && error.code === "ENOENT")
3727
+ return;
3728
+ throw error;
3729
+ }
3730
+ }
3731
+ async function restoreUpdateState(projectDirectory, state) {
3732
+ for (const entry of state.entries) {
3733
+ assertSafePath(entry.path);
3734
+ const target = join8(projectDirectory, entry.path);
3735
+ if (!entry.existed) {
3736
+ await rm5(target, { force: true });
3737
+ continue;
3738
+ }
3739
+ const backup = join8(state.backupDirectory, "files", entry.path);
3740
+ await mkdir5(dirname3(target), { recursive: true });
3741
+ await copyFile2(backup, target);
3742
+ }
3743
+ await rm5(join8(projectDirectory, updateStatePath), { force: true });
3744
+ }
3745
+ async function clearUpdateState(projectDirectory) {
3746
+ await rm5(join8(projectDirectory, updateStatePath), { force: true });
3747
+ }
3748
+ async function writeState(projectDirectory, state) {
3749
+ const path2 = join8(projectDirectory, updateStatePath);
3750
+ await mkdir5(dirname3(path2), { recursive: true });
3751
+ await writeFile8(path2, `${JSON.stringify(state, null, 2)}
3752
+ `);
3753
+ }
3754
+ async function exists(path2) {
3755
+ try {
3756
+ await access2(path2);
3757
+ return true;
3758
+ } catch {
3759
+ return false;
3760
+ }
3761
+ }
3762
+ function assertSafePath(path2) {
3763
+ if (!path2 || path2.startsWith("/") || path2.split("/").includes("..")) {
3764
+ throw new Error(`更新计划包含不安全路径:${path2}`);
3765
+ }
3766
+ }
3767
+ function isUpdateState(value) {
3768
+ if (!value || typeof value !== "object")
3769
+ return false;
3770
+ const state = value;
3771
+ return state.schemaVersion === 1 && typeof state.updateId === "string" && typeof state.backupDirectory === "string" && Array.isArray(state.entries);
3772
+ }
3773
+
3774
+ // src/update/doctor.ts
3775
+ var oxcPaths = new Set([
3776
+ ".oxfmtrc.json",
3777
+ ".oxlintrc.json",
3778
+ ".husky/pre-commit"
3779
+ ]);
3780
+ async function diagnoseProject(projectDirectory, repair = false) {
3781
+ const pending = await readUpdateState(projectDirectory);
3782
+ let repaired = false;
3783
+ if (pending && repair) {
3784
+ await restoreUpdateState(projectDirectory, pending);
3785
+ repaired = true;
3786
+ }
3787
+ const [provenance, manifest, git] = await Promise.all([
3788
+ readGenerationProvenance(projectDirectory),
3789
+ readManagedFilesManifest(projectDirectory),
3790
+ captureProcess("git", ["status", "--porcelain"], projectDirectory)
3791
+ ]);
3792
+ const modifiedManagedFiles = [];
3793
+ const missingManagedFiles = [];
3794
+ let detachedToolchain = false;
3795
+ for (const file of manifest.files) {
3796
+ if (file.ownership === "project-owned")
3797
+ continue;
3798
+ try {
3799
+ const changed = hashContent(await readFile9(join9(projectDirectory, file.path))) !== file.hash;
3800
+ if (!changed)
3801
+ continue;
3802
+ modifiedManagedFiles.push(file.path);
3803
+ if (oxcPaths.has(file.path))
3804
+ detachedToolchain = true;
3805
+ } catch (error) {
3806
+ if (error instanceof Error && "code" in error && error.code === "ENOENT") {
3807
+ missingManagedFiles.push(file.path);
3808
+ if (oxcPaths.has(file.path))
3809
+ detachedToolchain = true;
3810
+ continue;
3811
+ }
3812
+ throw error;
3813
+ }
3814
+ }
3815
+ return {
3816
+ version: provenance.windyVersion,
3817
+ gitClean: git.code === 0 && !git.stdout.trim(),
3818
+ modifiedManagedFiles,
3819
+ missingManagedFiles,
3820
+ detachedToolchain,
3821
+ recoveryRequired: Boolean(pending) && !repaired,
3822
+ repaired
3823
+ };
3824
+ }
3825
+
3826
+ // src/update/recipes.ts
3827
+ var recipes = [
3828
+ { id: "starter-0.1.1-to-0.1.2", from: "0.1.1", to: "0.1.2" },
3829
+ { id: "starter-0.1.2-to-0.2.0", from: "0.1.2", to: "0.2.0" }
3830
+ ];
3831
+ function resolveRecipeChain(sourceVersion, targetVersion) {
3832
+ if (sourceVersion === targetVersion)
3833
+ return [];
3834
+ const chain = [];
3835
+ let current = sourceVersion;
3836
+ const visited = new Set;
3837
+ while (current !== targetVersion) {
3838
+ if (visited.has(current))
3839
+ break;
3840
+ visited.add(current);
3841
+ const recipe = recipes.find(({ from }) => from === current);
3842
+ if (!recipe)
3843
+ break;
3844
+ chain.push(recipe);
3845
+ current = recipe.to;
3846
+ }
3847
+ if (current !== targetVersion) {
3848
+ throw new Error(`没有从 ${sourceVersion} 到 ${targetVersion} 的连续更新 recipe,禁止跳级`);
3849
+ }
3850
+ return chain;
3851
+ }
3852
+
3853
+ // src/update/updater.ts
3854
+ import { mkdir as mkdir7, readFile as readFile12, rm as rm7, writeFile as writeFile10 } from "node:fs/promises";
3855
+ import { dirname as dirname4, join as join13 } from "node:path";
3856
+
3857
+ // src/update/artifacts.ts
3858
+ import { mkdir as mkdir6, mkdtemp, readFile as readFile10 } from "node:fs/promises";
3859
+ import { tmpdir } from "node:os";
3860
+ import { basename as basename3, join as join10 } from "node:path";
3861
+ class PublishedArtifactProvider {
3862
+ async prepare(projectDirectory, provenance) {
3863
+ const temporaryRoot = await mkdtemp(join10(tmpdir(), "windy-update-"));
3864
+ const projectName = await readProjectName2(projectDirectory);
3865
+ const baseDirectory = join10(temporaryRoot, "base", projectName);
3866
+ const targetDirectory = join10(temporaryRoot, "target", projectName);
3867
+ await generatePublishedBase(temporaryRoot, projectName, provenance, baseDirectory);
3868
+ await generateProject({
3869
+ sourceRoot: await resolveTemplateRoot(),
3870
+ targetDirectory,
3871
+ projectName,
3872
+ selectedModules: provenance.modules.map(({ name }) => name),
3873
+ includeOxc: provenance.choices.includeOxc,
3874
+ projectLicense: provenance.legalLicense,
3875
+ licenseHolder: provenance.legalLicense === "MIT" ? "Windy project owner" : undefined,
3876
+ profile: provenance.profile
3877
+ });
3878
+ return { temporaryRoot, baseDirectory, targetDirectory };
3879
+ }
3880
+ }
3881
+ async function generatePublishedBase(temporaryRoot, projectName, provenance, expectedDirectory) {
3882
+ const parent = join10(temporaryRoot, "base");
3883
+ await mkdir6(parent, { recursive: true });
3884
+ const args = [
3885
+ "--bun",
3886
+ `create-windy@${provenance.generatorVersion}`,
3887
+ projectName,
3888
+ "--yes",
3889
+ "--skip-install",
3890
+ "--no-git",
3891
+ "--no-optional-modules",
3892
+ "--license",
3893
+ provenance.legalLicense
3894
+ ];
3895
+ if (!provenance.choices.includeOxc)
3896
+ args.push("--no-oxc");
3897
+ if (provenance.legalLicense === "MIT") {
3898
+ args.push("--license-holder", "Windy project owner");
3899
+ }
3900
+ for (const { name } of provenance.modules) {
3901
+ if (!requiredModuleNames.includes(name)) {
3902
+ args.push("--module", name);
3903
+ }
3904
+ }
3905
+ await assertProcess("bunx", args, parent);
3906
+ if (join10(parent, projectName) !== expectedDirectory) {
3907
+ throw new Error("历史 artifact 生成目录异常");
3908
+ }
3909
+ }
3910
+ async function readProjectName2(projectDirectory) {
3911
+ const source = JSON.parse(await readFile10(join10(projectDirectory, "package.json"), "utf8"));
3912
+ return source.name || basename3(projectDirectory);
3913
+ }
3914
+
3915
+ // src/update/planner.ts
3916
+ import { access as access3, readFile as readFile11 } from "node:fs/promises";
3917
+ import { join as join12 } from "node:path";
3918
+
3919
+ // src/update/merge.ts
3920
+ import { mkdtemp as mkdtemp2, rm as rm6, writeFile as writeFile9 } from "node:fs/promises";
3921
+ import { tmpdir as tmpdir2 } from "node:os";
3922
+ import { join as join11 } from "node:path";
3923
+ async function mergeTextFile(base, ours, theirs) {
3924
+ const root = await mkdtemp2(join11(tmpdir2(), "windy-merge-"));
3925
+ try {
3926
+ const oursPath = join11(root, "ours");
3927
+ const basePath = join11(root, "base");
3928
+ const theirsPath = join11(root, "theirs");
3929
+ await Promise.all([
3930
+ writeFile9(oursPath, ours),
3931
+ writeFile9(basePath, base),
3932
+ writeFile9(theirsPath, theirs)
3933
+ ]);
3934
+ const result = await captureProcess("git", ["merge-file", "-p", "--diff3", oursPath, basePath, theirsPath], root);
3935
+ if (result.code === 0) {
3936
+ return { content: new TextEncoder().encode(result.stdout) };
3937
+ }
3938
+ if (result.code === 1)
3939
+ return { conflict: "三方合并存在重叠修改" };
3940
+ return { conflict: result.stderr.trim() || "git merge-file 执行失败" };
3941
+ } finally {
3942
+ await rm6(root, { recursive: true, force: true });
3943
+ }
3944
+ }
3945
+
3946
+ // src/update/package-merge.ts
3947
+ function mergePackageJson(base, ours, theirs) {
3948
+ const conflicts = [];
3949
+ const merged = mergeValue(JSON.parse(new TextDecoder().decode(base)), JSON.parse(new TextDecoder().decode(ours)), JSON.parse(new TextDecoder().decode(theirs)), "package.json", conflicts);
3950
+ return conflicts.length ? { conflicts } : {
3951
+ conflicts,
3952
+ content: new TextEncoder().encode(`${JSON.stringify(merged, null, 2)}
3953
+ `)
3954
+ };
3955
+ }
3956
+ function mergeValue(base, ours, theirs, path2, conflicts) {
3957
+ if (equal(ours, theirs))
3958
+ return ours;
3959
+ if (equal(ours, base))
3960
+ return theirs;
3961
+ if (equal(theirs, base))
3962
+ return ours;
3963
+ if (isObject(base) && isObject(ours) && isObject(theirs)) {
3964
+ const output = {};
3965
+ const keys = new Set([
3966
+ ...Object.keys(base),
3967
+ ...Object.keys(ours),
3968
+ ...Object.keys(theirs)
3969
+ ]);
3970
+ for (const key of keys) {
3971
+ const value = mergeValue(base[key], ours[key], theirs[key], `${path2}.${key}`, conflicts);
3972
+ if (value !== undefined)
3973
+ output[key] = value;
3974
+ }
3975
+ return output;
3976
+ }
3977
+ conflicts.push(path2);
3978
+ return ours;
3979
+ }
3980
+ function equal(left, right) {
3981
+ return JSON.stringify(left) === JSON.stringify(right);
3982
+ }
3983
+ function isObject(value) {
3984
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value);
3985
+ }
3986
+
3987
+ // src/update/planner.ts
3988
+ var metadataPaths = new Set([
3989
+ ".windy/generation.json",
3990
+ ".windy/files.json",
3991
+ ".windy-template.json"
3992
+ ]);
3993
+ var oxcManagedPaths = new Set([
3994
+ ".oxfmtrc.json",
3995
+ ".oxlintrc.json",
3996
+ ".husky/pre-commit"
3997
+ ]);
3998
+ async function createUpdatePlan(request, artifacts) {
3999
+ await assertGitClean(request.projectDirectory);
4000
+ await assertNoPendingUpdate(request.projectDirectory);
4001
+ const provenance = await readGenerationProvenance(request.projectDirectory);
4002
+ const artifactSet = await artifacts.prepare(request.projectDirectory, provenance);
4003
+ const targetProvenance = await readGenerationProvenance(artifactSet.targetDirectory);
4004
+ const targetVersion = request.targetVersion || targetProvenance.generatorVersion;
4005
+ if (targetVersion !== targetProvenance.generatorVersion) {
4006
+ throw new Error(`当前 CLI 只能更新到 ${targetProvenance.generatorVersion},请运行 create-windy@${targetVersion}`);
4007
+ }
4008
+ const recipes2 = resolveRecipeChain(provenance.windyVersion, targetVersion);
4009
+ const [sourceManifest, targetManifest] = await Promise.all([
4010
+ readManagedFilesManifest(request.projectDirectory),
4011
+ readManagedFilesManifest(artifactSet.targetDirectory)
4012
+ ]);
4013
+ targetProvenance.appliedRecipes = [
4014
+ ...provenance.appliedRecipes,
4015
+ ...recipes2.map(({ id }) => id)
4016
+ ];
4017
+ const sourceEntries = new Map(sourceManifest.files.map((item) => [item.path, item]));
4018
+ const targetEntries = new Map(targetManifest.files.map((item) => [item.path, item]));
4019
+ const paths = new Set([...sourceEntries.keys(), ...targetEntries.keys()]);
4020
+ const files = [];
4021
+ let detachedToolchain = false;
4022
+ for (const path2 of [...paths].sort()) {
4023
+ if (metadataPaths.has(path2))
4024
+ continue;
4025
+ const file = await planFile(path2, request.projectDirectory, artifactSet.baseDirectory, artifactSet.targetDirectory, sourceEntries.get(path2), targetEntries.get(path2));
4026
+ if (oxcManagedPaths.has(path2) && file.reason === "客户已修改") {
4027
+ file.action = "preserve";
4028
+ delete file.conflict;
4029
+ detachedToolchain = true;
4030
+ }
4031
+ files.push(file);
4032
+ }
4033
+ const conflicts = files.flatMap((file) => file.conflict ? [`${file.path}:${file.conflict}`] : []);
4034
+ return {
4035
+ id: createUpdateId(provenance.windyVersion, targetVersion),
4036
+ projectDirectory: request.projectDirectory,
4037
+ sourceVersion: provenance.windyVersion,
4038
+ targetVersion,
4039
+ recipes: recipes2.map(({ id }) => id),
4040
+ files,
4041
+ conflicts,
4042
+ detachedToolchain,
4043
+ targetProvenance,
4044
+ targetManifest,
4045
+ temporaryRoot: artifactSet.temporaryRoot
4046
+ };
4047
+ }
4048
+ async function planFile(path2, project, baseRoot, targetRoot, source, target) {
4049
+ const [ours, base, theirs] = await Promise.all([
4050
+ readOptional(join12(project, path2)),
4051
+ readOptional(join12(baseRoot, path2)),
4052
+ readOptional(join12(targetRoot, path2))
4053
+ ]);
4054
+ const ownership = target?.ownership || source?.ownership || classifyOwnership(path2);
4055
+ if (path2.startsWith("packages/database/drizzle/") && path2.endsWith(".sql")) {
4056
+ if (source && !target)
4057
+ return conflict(path2, ownership, "已发布 migration 不可删除");
4058
+ if (source && target && source.hash !== target.hash) {
4059
+ return conflict(path2, ownership, "已发布 migration 不可改写,只能追加新文件");
4060
+ }
4061
+ }
4062
+ if (ownership === "project-owned") {
4063
+ if (!ours && theirs)
4064
+ return ready(path2, ownership, "create", "新增项目扩展点", theirs);
4065
+ return ready(path2, ownership, "preserve", "项目拥有,Windy 不覆盖");
4066
+ }
4067
+ if (!source && target) {
4068
+ if (!ours)
4069
+ return ready(path2, ownership, "create", "目标版本新增", theirs);
4070
+ if (theirs && hashContent(ours) === target.hash) {
4071
+ return ready(path2, ownership, "preserve", "已包含目标内容");
4072
+ }
4073
+ return conflict(path2, ownership, "目标版本新增路径已被项目占用");
4074
+ }
4075
+ if (source && !target) {
4076
+ if (!ours)
4077
+ return ready(path2, ownership, "preserve", "项目已删除");
4078
+ if (hashContent(ours) === source.hash) {
4079
+ return ready(path2, ownership, "delete", "目标版本删除");
4080
+ }
4081
+ return conflict(path2, ownership, "客户修改后 Windy 又删除");
4082
+ }
4083
+ if (!source || !target || !ours || !theirs) {
4084
+ return conflict(path2, ownership, "文件状态不完整,不能安全推断");
4085
+ }
4086
+ const oursChanged = hashContent(ours) !== source.hash;
4087
+ const targetChanged = target.hash !== source.hash;
4088
+ if (!oursChanged && !targetChanged)
4089
+ return ready(path2, ownership, "preserve", "双方未修改");
4090
+ if (!oursChanged)
4091
+ return ready(path2, ownership, "update", "仅 Windy 修改", theirs);
4092
+ if (!targetChanged)
4093
+ return ready(path2, ownership, "preserve", "客户已修改");
4094
+ if (hashContent(ours) === target.hash)
4095
+ return ready(path2, ownership, "preserve", "已包含目标内容");
4096
+ if (path2 === "package.json" && base) {
4097
+ const merged = mergePackageJson(base, ours, theirs);
4098
+ return merged.content ? ready(path2, ownership, "update", "package.json 字段级合并", merged.content) : conflict(path2, ownership, `字段冲突:${merged.conflicts.join("、")}`);
4099
+ }
4100
+ if (ownership === "shared-scaffold" && base) {
4101
+ const merged = await mergeTextFile(base, ours, theirs);
4102
+ return merged.content ? ready(path2, ownership, "update", "三方合并", merged.content) : conflict(path2, ownership, merged.conflict || "三方合并失败");
4103
+ }
4104
+ return conflict(path2, ownership, "客户和 Windy 均已修改");
4105
+ }
4106
+ function ready(path2, ownership, action, reason, content) {
4107
+ return { path: path2, ownership, action, reason, content };
4108
+ }
4109
+ function conflict(path2, ownership, reason) {
4110
+ return {
4111
+ path: path2,
4112
+ ownership,
4113
+ action: "preserve",
4114
+ reason: "客户已修改",
4115
+ conflict: reason
4116
+ };
4117
+ }
4118
+ async function readOptional(path2) {
4119
+ try {
4120
+ return await readFile11(path2);
4121
+ } catch (error) {
4122
+ if (error instanceof Error && "code" in error && error.code === "ENOENT")
4123
+ return;
4124
+ throw error;
4125
+ }
4126
+ }
4127
+ async function assertGitClean(projectDirectory) {
4128
+ const result = await captureProcess("git", ["status", "--porcelain"], projectDirectory);
4129
+ if (result.code !== 0)
4130
+ throw new Error("更新要求当前目录是有效的 Git 仓库");
4131
+ if (result.stdout.trim())
4132
+ throw new Error("更新前请先提交或暂存之外妥善处理 Git 工作区改动");
4133
+ }
4134
+ async function assertNoPendingUpdate(projectDirectory) {
4135
+ try {
4136
+ await access3(join12(projectDirectory, ".windy/update-state.json"));
4137
+ throw new Error("检测到未完成更新,请先运行 bun run windy doctor --repair");
4138
+ } catch (error) {
4139
+ if (error instanceof Error && "code" in error && error.code === "ENOENT")
4140
+ return;
4141
+ throw error;
4142
+ }
4143
+ }
4144
+ function createUpdateId(from, to) {
4145
+ return `${new Date().toISOString().replaceAll(/[:.]/g, "-")}-${from}-to-${to}`;
4146
+ }
4147
+
4148
+ // src/update/updater.ts
4149
+ class DefaultStarterUpdater {
4150
+ #artifacts;
4151
+ #execute;
4152
+ constructor(dependencies = {}) {
4153
+ this.#artifacts = dependencies.artifacts ?? new PublishedArtifactProvider;
4154
+ this.#execute = dependencies.execute ?? runCommand;
4155
+ }
4156
+ async plan(input) {
4157
+ return await createUpdatePlan(input, this.#artifacts);
4158
+ }
4159
+ async apply(plan) {
4160
+ try {
4161
+ return await applyTransaction(plan);
4162
+ } catch (error) {
4163
+ await rm7(plan.temporaryRoot, { recursive: true, force: true });
4164
+ throw error;
4165
+ }
4166
+ }
4167
+ async verify(result) {
4168
+ const steps = [];
4169
+ try {
4170
+ await this.#execute("bun", ["install"], result.plan.projectDirectory);
4171
+ steps.push({ name: "bun install", status: "passed" });
4172
+ const packageJson = JSON.parse(await readFile12(join13(result.plan.projectDirectory, "package.json"), "utf8"));
4173
+ for (const name of ["lint", "typecheck", "test", "build"]) {
4174
+ if (!packageJson.scripts?.[name]) {
4175
+ steps.push({ name: `bun run ${name}`, status: "skipped" });
4176
+ continue;
4177
+ }
4178
+ await this.#execute("bun", ["run", name], result.plan.projectDirectory);
4179
+ steps.push({ name: `bun run ${name}`, status: "passed" });
4180
+ }
4181
+ await finalize(result);
4182
+ const reportPath = `.windy/reports/${result.plan.id}.md`;
4183
+ await writeReport(result, steps, reportPath);
4184
+ await clearUpdateState(result.plan.projectDirectory);
4185
+ await rm7(result.plan.temporaryRoot, { recursive: true, force: true });
4186
+ return { updateId: result.plan.id, status: "passed", steps, reportPath };
4187
+ } catch (error) {
4188
+ await restoreUpdateState(result.plan.projectDirectory, {
4189
+ schemaVersion: 1,
4190
+ updateId: result.plan.id,
4191
+ backupDirectory: result.backupDirectory,
4192
+ entries: result.backupEntries
4193
+ });
4194
+ await rm7(result.plan.temporaryRoot, { recursive: true, force: true });
4195
+ throw new Error(`更新验证失败,项目已回滚到 ${result.plan.sourceVersion}:${error instanceof Error ? error.message : String(error)}`, { cause: error });
4196
+ }
4197
+ }
4198
+ }
4199
+ async function finalize(result) {
4200
+ const root = result.plan.projectDirectory;
4201
+ await writeFile10(join13(root, ".windy/generation.json"), `${JSON.stringify(result.plan.targetProvenance, null, 2)}
4202
+ `);
4203
+ await writeFile10(join13(root, ".windy/files.json"), `${JSON.stringify(result.plan.targetManifest, null, 2)}
4204
+ `);
4205
+ }
4206
+ async function writeReport(result, steps, relativePath2) {
4207
+ const path2 = join13(result.plan.projectDirectory, relativePath2);
4208
+ await mkdir7(dirname4(path2), { recursive: true });
4209
+ const lines = [
4210
+ `# Windy 更新报告 ${result.plan.id}`,
4211
+ "",
4212
+ `- 来源版本:${result.plan.sourceVersion}`,
4213
+ `- 目标版本:${result.plan.targetVersion}`,
4214
+ `- Recipe:${result.plan.recipes.join("、") || "无"}`,
4215
+ `- 修改文件:${result.changedFiles.length}`,
4216
+ `- Oxc 代管:${result.plan.detachedToolchain ? "已检测到客户接管并保留" : "保持"}`,
4217
+ "",
4218
+ "## 验证",
4219
+ "",
4220
+ ...steps.map(({ name, status }) => `- ${name}:${status}`),
4221
+ "",
4222
+ `备份保留在 \`.windy/backups/${result.plan.id}\`,确认稳定后可人工删除。`,
4223
+ ""
4224
+ ];
4225
+ await writeFile10(path2, lines.join(`
4226
+ `));
4227
+ }
4228
+
4229
+ // src/update/cli.ts
4230
+ async function runLifecycleCommand(args) {
4231
+ const command = args[0];
4232
+ if (command !== "doctor" && command !== "update")
4233
+ return false;
4234
+ const projectDirectory = resolve4(readValue2(args, "--cwd") || process.cwd());
4235
+ if (command === "doctor") {
4236
+ const report = await diagnoseProject(projectDirectory, args.includes("--repair"));
4237
+ printDoctor(report);
4238
+ if (report.recoveryRequired)
4239
+ process.exitCode = 1;
4240
+ return true;
4241
+ }
4242
+ await runUpdate(args, projectDirectory);
4243
+ return true;
4244
+ }
4245
+ async function runUpdate(args, projectDirectory) {
4246
+ const template = await readTemplateMetadata(await resolveTemplateRoot());
4247
+ const requested = readValue2(args, "--to");
4248
+ const registryVersion = requested ? undefined : await readRegistryLatest();
4249
+ if (registryVersion && compareVersions2(registryVersion, template.generatorVersion) > 0 && !args.includes("--no-delegate")) {
4250
+ if (args.includes("--check")) {
4251
+ const current2 = await readGenerationProvenance(projectDirectory);
4252
+ console.log(`可更新:${current2.windyVersion} → ${registryVersion}(请使用新版 CLI 生成完整计划)`);
4253
+ return;
4254
+ }
4255
+ await delegateUpdate(args, registryVersion, projectDirectory);
4256
+ return;
4257
+ }
4258
+ if (requested && requested !== template.generatorVersion && !args.includes("--no-delegate")) {
4259
+ await delegateUpdate(args, requested, projectDirectory);
4260
+ return;
4261
+ }
4262
+ const current = await readGenerationProvenance(projectDirectory);
4263
+ const target = requested || template.generatorVersion;
4264
+ const recipes2 = resolveRecipeChain(current.windyVersion, target);
4265
+ if (args.includes("--check")) {
4266
+ console.log(recipes2.length ? `可更新:${current.windyVersion} → ${target}(${recipes2.length} 个连续 recipe)` : `已是当前 CLI 支持的最新版本 ${current.windyVersion}`);
4267
+ return;
4268
+ }
4269
+ if (!recipes2.length) {
4270
+ console.log(`项目已经是 ${target},无需更新`);
4271
+ return;
4272
+ }
4273
+ const updater = new DefaultStarterUpdater;
4274
+ const plan = await updater.plan({ projectDirectory, targetVersion: target });
4275
+ printPlan(plan);
4276
+ if (args.includes("--dry-run")) {
4277
+ await rm8(plan.temporaryRoot, { recursive: true, force: true });
4278
+ console.log(`
4279
+ 演练完成:未写入项目文件`);
4280
+ return;
4281
+ }
4282
+ if (plan.conflicts.length) {
4283
+ await rm8(plan.temporaryRoot, { recursive: true, force: true });
4284
+ throw new Error("存在更新冲突;请按上方清单处理后重新运行,项目未被修改");
4285
+ }
4286
+ const result = await updater.apply(plan);
4287
+ const report = await updater.verify(result);
4288
+ console.log(`
4289
+ 更新完成:${plan.sourceVersion} → ${plan.targetVersion}`);
4290
+ console.log(`报告:${report.reportPath}`);
4291
+ }
4292
+ async function delegateUpdate(args, target, projectDirectory) {
4293
+ const forwarded = args.slice(1).filter((item, index, all) => {
4294
+ if (item === "--cwd" || item === "--to")
4295
+ return false;
4296
+ return all[index - 1] !== "--cwd" && all[index - 1] !== "--to";
4297
+ });
4298
+ await assertProcess("bunx", [
4299
+ "--bun",
4300
+ `create-windy@${target}`,
4301
+ "update",
4302
+ "--cwd",
4303
+ projectDirectory,
4304
+ "--to",
4305
+ target,
4306
+ "--no-delegate",
4307
+ ...forwarded
4308
+ ], projectDirectory, true);
4309
+ }
4310
+ function printPlan(plan) {
4311
+ const changed = plan.files.filter(({ action }) => action !== "preserve");
4312
+ console.log(`Windy 更新计划:${plan.sourceVersion} → ${plan.targetVersion}`);
4313
+ console.log(`Recipe:${plan.recipes.join("、")}`);
4314
+ console.log(`计划改动:${changed.length} 个文件;冲突:${plan.conflicts.length}`);
4315
+ for (const file of changed)
4316
+ console.log(` ${file.action.padEnd(6)} ${file.path}(${file.reason})`);
4317
+ for (const conflict2 of plan.conflicts)
4318
+ console.log(` conflict ${conflict2}`);
4319
+ if (plan.detachedToolchain)
4320
+ console.log("Oxc:检测到客户接管,相关配置保持不变");
4321
+ }
4322
+ function printDoctor(report) {
4323
+ console.log(`Windy Project Lock:${report.version}`);
4324
+ console.log(`Git 工作区:${report.gitClean ? "干净" : "有改动"}`);
4325
+ console.log(`客户修改的受管文件:${report.modifiedManagedFiles.length}`);
4326
+ console.log(`缺失的受管文件:${report.missingManagedFiles.length}`);
4327
+ console.log(`Oxc:${report.detachedToolchain ? "客户已接管" : "仍由 Windy 代管或未启用"}`);
4328
+ if (report.recoveryRequired)
4329
+ console.log("恢复:检测到中断更新,请运行 doctor --repair");
4330
+ if (report.repaired)
4331
+ console.log("恢复:已从事务备份回滚");
4332
+ }
4333
+ function readValue2(args, flag) {
4334
+ const index = args.indexOf(flag);
4335
+ return index >= 0 ? args[index + 1] : undefined;
4336
+ }
4337
+ async function readRegistryLatest() {
4338
+ try {
4339
+ const response = await fetch("https://registry.npmjs.org/create-windy/latest");
4340
+ if (!response.ok)
4341
+ return;
4342
+ const payload = await response.json();
4343
+ return payload.version;
4344
+ } catch {
4345
+ return;
4346
+ }
4347
+ }
4348
+ function compareVersions2(left, right) {
4349
+ const leftParts = left.split(".").map(Number);
4350
+ const rightParts = right.split(".").map(Number);
4351
+ for (let index = 0;index < 3; index += 1) {
4352
+ const difference = (leftParts[index] || 0) - (rightParts[index] || 0);
4353
+ if (difference)
4354
+ return difference;
4355
+ }
4356
+ return 0;
4357
+ }
4358
+
4359
+ // src/cli.ts
4360
+ async function main() {
4361
+ const args = process.argv.slice(2);
4362
+ if (await runLifecycleCommand(args))
4363
+ return;
4364
+ const options = parseArguments(args);
1671
4365
  if (options === "help") {
1672
4366
  console.log(helpText);
1673
4367
  return;