gz-cli-front 1.0.0 → 1.0.1-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,173 +1,188 @@
1
- # gz-cli-front
2
-
3
- 一个轻量级的现代前端脚手架工具,通过远程模板创建项目。
4
-
5
- ## 安装
6
-
7
- ```bash
8
- npm install -g gz-cli-front
9
- ```
10
-
11
- ## 使用
12
-
13
- ```bash
14
- gz-cli-front init [project-name]
15
- ```
16
-
17
- 也可以不全局安装,直接运行:
18
-
19
- ```bash
20
- npx gz-cli-front init demo-app
21
- ```
22
-
23
- `create` 命令仍可使用,例如 `gz-cli-front create demo-app`。
24
- 新包只注册 `gz-cli-front` 命令,不注册旧的 `gg-cli` 命令。
25
-
26
- 可通过 `--pm` 指定本次初始化使用的包管理器:
27
-
28
- ```bash
29
- gz-cli-front init demo-app --pm npm
30
- gz-cli-front init demo-app --pm pnpm
31
- gz-cli-front init demo-app --pm yarn
32
- ```
33
-
34
- 未指定时,CLI 会按 `pnpm`、`yarn`、`npm` 的顺序检测当前环境;都未检测到时默认使用 `npm`。模板注册表不包含包管理器配置。
35
-
36
- ### 网络代理
37
-
38
- CLI 会自动读取当前系统代理,不绑定具体代理工具、地址或端口。代理优先级如下:
39
-
40
- ```text
41
- --no-proxy 强制直连
42
- --proxy 参数
43
- HTTP_PROXY / HTTPS_PROXY / NO_PROXY
44
- 操作系统代理
45
- 无代理直连
46
- ```
47
-
48
- 临时指定代理或强制直连:
49
-
50
- ```bash
51
- gz-cli-front init demo-app --proxy http://proxy-host:port
52
- gz-cli-front init demo-app --no-proxy
53
- ```
54
-
55
- 系统代理检测支持 Windows、macOS 和 Linux。代理相关日志只显示网络路径,不输出代理地址、账号或密码。
56
-
57
- ### 模板缓存
58
-
59
- 模板注册仓库和模板仓库会浅克隆并缓存到 `~/.gz-cli-front/cache`,减少重复创建项目时的网络等待。需要忽略缓存并获取最新内容时执行:
60
-
61
- ```bash
62
- gz-cli-front init demo-app --refresh
63
- ```
64
-
65
- 注册表缓存有效期为 5 分钟,`latest` 模板缓存有效期为 10 分钟;指定版本的模板缓存可以长期复用。远程暂时不可用时,未指定 `--refresh` 会回退到已有缓存。
66
-
67
- 模板注册仓库和模板仓库均为公共仓库,默认通过配置中的 HTTPS 地址直接下载,无需配置 GitHub Token 或 SSH Key。Git 操作设有超时并支持网络代理;如显式配置 SSH clone URL,仍会使用本机 SSH Agent。
68
-
69
- 可通过 `GZ_CLI_FRONT_CACHE_DIR` 指定缓存目录,通过 `GZ_CLI_FRONT_DEBUG=1` 开启网络和模板调试日志。新包不读取旧的 `GG_CLI_*` 环境变量,也不复用旧包的默认缓存目录。
70
-
71
- 模板注册仓库由 `config/gz-cli-front.config.json` 管理,现有远程仓库地址保持不变:
72
-
73
- ```json
74
- {
75
- "templateRegistry": {
76
- "source": "git",
77
- "url": "https://github.com/gz-fronted/gg-cli-template-register.git",
78
- "file": "templates.json"
79
- }
80
- }
81
- ```
82
-
83
- 注册表中的每个模板使用独立仓库,例如:
84
-
85
- ```json
86
- [
87
- {
88
- "name": "main-app",
89
- "label": "主应用模板",
90
- "description": "Garfish 主应用模板",
91
- "type": "main",
92
- "source": "git",
93
- "url": "https://github.com/your-org/gg-cli-template-main-app.git",
94
- "version": "latest"
95
- },
96
- {
97
- "name": "micro-app",
98
- "label": "微应用模板",
99
- "description": "Garfish 微应用模板",
100
- "type": "micro",
101
- "source": "git",
102
- "url": "https://github.com/your-org/gg-cli-template-micro-app.git",
103
- "version": "latest"
104
- }
105
- ]
106
- ```
107
-
108
- 公共仓库建议使用 `source: "git"` 和 HTTPS clone URL,避免要求使用者配置 SSH Key。CLI 会按配置的协议执行浅克隆;`source` 仍兼容 `github`、`gitlab` 和 `git`,旧的 GitHub `repo` 配置也可继续使用。
109
-
110
- ### Git 仓库访问测试
111
-
112
- 发版前可以在本机验证 Git 仓库访问失败时的错误提示,不会修改全局 Git 配置:
113
-
114
- ```bash
115
- npm run test:auth-error
116
- ```
117
-
118
- 该脚本使用独立缓存和模拟失败的 Git 命令运行构建后的 CLI,要求在超时前返回明确错误。正常访问链路仍使用以下命令验证:
119
-
120
- ```bash
121
- npm run build
122
- node dist/index.js init --refresh
123
- ```
124
-
125
- 发版前统一执行:
126
-
127
- ```bash
128
- npm run test:release
129
- ```
130
-
131
- 该命令会依次验证构建、HTTPS Git 兼容性、公共注册仓库访问、失败错误提示和 npm 发布包内容。
132
-
133
- 如果已经手动执行过 `npm run build`,可以只验证构建产物和 Git 场景:
134
-
135
- ```bash
136
- npm run test:smoke
137
- ```
138
-
139
- ## 发布到 npm
140
-
141
- 本包以 `gz-cli-front` 为独立包名,初始版本为 `1.0.0`,不会覆盖或更新旧的 `@chenhui996/gg-cli` 包。
142
-
143
- 首次发布前,确认包名尚未被占用,并登录有发布权限的 npm 账号:
144
-
145
- ```bash
146
- npm view gz-cli-front --registry=https://registry.npmjs.org/
147
- npm login --registry=https://registry.npmjs.org/
148
- npm whoami --registry=https://registry.npmjs.org/
149
- ```
150
-
151
- 查询返回 E404 表示未找到该包;网络或认证错误不能作为包名可用的判断依据。最终能否发布以 npm 的校验结果为准。
152
-
153
- 安装依赖并验证:
154
-
155
- ```bash
156
- npm ci
157
- npm run test:release
158
- ```
159
-
160
- 确认通过后发布:
161
-
162
- ```bash
163
- npm publish --registry=https://registry.npmjs.org/
164
- ```
165
-
166
- 发布时会自动通过 `prepublishOnly` 再运行一次发布验证。发布内容包括 `bin`、构建后的 `dist`、包信息和 README,不包含 `src/template` 中的本地模板。
167
-
168
- 发布后可验证:
169
-
170
- ```bash
171
- npm view gz-cli-front version --registry=https://registry.npmjs.org/
172
- npx --registry=https://registry.npmjs.org/ gz-cli-front@1.0.0 --version
173
- ```
1
+ # gz-cli-front
2
+
3
+ 一个轻量级的现代前端脚手架工具,通过远程模板创建项目。
4
+
5
+ npm 包名为 `gz-cli-front`,安装后使用 `gz-cli` 命令。
6
+
7
+ 版本变化见 [更新日志](CHANGELOG.md)。
8
+
9
+ ## 安装
10
+
11
+ ```bash
12
+ npm install -g gz-cli-front
13
+ ```
14
+
15
+ ## 使用
16
+
17
+ ```bash
18
+ gz-cli init [project-name]
19
+ ```
20
+
21
+ 也可以不全局安装,直接运行:
22
+
23
+ ```bash
24
+ npx gz-cli-front init demo-app
25
+ ```
26
+
27
+ `create` 命令仍可使用,例如 `gz-cli create demo-app`。
28
+ 同时保留 `gz-cli-front` 作为兼容命令,两者执行相同逻辑;新包不注册旧的 `gg-cli` 命令。
29
+
30
+ 从旧包迁移时可执行:
31
+
32
+ ```bash
33
+ npm uninstall -g @chenhui996/gg-cli
34
+ npm install -g gz-cli-front
35
+ gz-cli --version
36
+ gz-cli init demo-app
37
+ ```
38
+
39
+ 切换 CLI 后,新建项目会使用当前远程模板;已有业务项目不会自动迁移。
40
+
41
+ 可通过 `--pm` 指定本次初始化使用的包管理器:
42
+
43
+ ```bash
44
+ gz-cli init demo-app --pm npm
45
+ gz-cli init demo-app --pm pnpm
46
+ gz-cli init demo-app --pm yarn
47
+ ```
48
+
49
+ 未指定时,CLI 会按 `pnpm`、`yarn`、`npm` 的顺序检测当前环境;都未检测到时默认使用 `npm`。模板注册表不包含包管理器配置。
50
+
51
+ ### 网络代理
52
+
53
+ CLI 会自动读取当前系统代理,不绑定具体代理工具、地址或端口。代理优先级如下:
54
+
55
+ ```text
56
+ --no-proxy 强制直连
57
+ --proxy 参数
58
+ HTTP_PROXY / HTTPS_PROXY / NO_PROXY
59
+ 操作系统代理
60
+ 无代理直连
61
+ ```
62
+
63
+ 临时指定代理或强制直连:
64
+
65
+ ```bash
66
+ gz-cli init demo-app --proxy http://proxy-host:port
67
+ gz-cli init demo-app --no-proxy
68
+ ```
69
+
70
+ 系统代理检测支持 Windows、macOS 和 Linux。代理相关日志只显示网络路径,不输出代理地址、账号或密码。
71
+
72
+ ### 模板缓存
73
+
74
+ 模板注册仓库和模板仓库会浅克隆并缓存到 `~/.gz-cli-front/cache`,减少重复创建项目时的网络等待。需要忽略缓存并获取最新内容时执行:
75
+
76
+ ```bash
77
+ gz-cli init demo-app --refresh
78
+ ```
79
+
80
+ 注册表缓存有效期为 5 分钟,`latest` 模板缓存有效期为 10 分钟;指定版本的模板缓存可以长期复用。远程暂时不可用时,未指定 `--refresh` 会回退到已有缓存。
81
+
82
+ 模板注册仓库和模板仓库均为公共仓库,默认通过配置中的 HTTPS 地址直接下载,无需配置 GitHub Token 或 SSH Key。Git 操作设有超时并支持网络代理;如显式配置 SSH clone URL,仍会使用本机 SSH Agent。
83
+
84
+ 可通过 `GZ_CLI_FRONT_CACHE_DIR` 指定缓存目录,通过 `GZ_CLI_FRONT_DEBUG=1` 开启网络和模板调试日志。新包不读取旧的 `GG_CLI_*` 环境变量,也不复用旧包的默认缓存目录。
85
+
86
+ 模板注册仓库由 `config/gz-cli-front.config.json` 管理,现有远程仓库地址保持不变:
87
+
88
+ ```json
89
+ {
90
+ "templateRegistry": {
91
+ "source": "git",
92
+ "url": "https://github.com/gz-fronted/gg-cli-template-register.git",
93
+ "file": "templates.json"
94
+ }
95
+ }
96
+ ```
97
+
98
+ 注册表中的每个模板使用独立仓库,例如:
99
+
100
+ ```json
101
+ [
102
+ {
103
+ "name": "main-app",
104
+ "label": "主应用模板",
105
+ "description": "Garfish 主应用模板",
106
+ "type": "main",
107
+ "source": "git",
108
+ "url": "https://github.com/your-org/gg-cli-template-main-app.git",
109
+ "version": "latest"
110
+ },
111
+ {
112
+ "name": "micro-app",
113
+ "label": "微应用模板",
114
+ "description": "Garfish 微应用模板",
115
+ "type": "micro",
116
+ "source": "git",
117
+ "url": "https://github.com/your-org/gg-cli-template-micro-app.git",
118
+ "version": "latest"
119
+ }
120
+ ]
121
+ ```
122
+
123
+ 公共仓库建议使用 `source: "git"` 和 HTTPS clone URL,避免要求使用者配置 SSH Key。CLI 会按配置的协议执行浅克隆;`source` 仍兼容 `github`、`gitlab` 和 `git`,旧的 GitHub `repo` 配置也可继续使用。
124
+
125
+ ### Git 仓库访问测试
126
+
127
+ 发版前可以在本机验证 Git 仓库访问失败时的错误提示,不会修改全局 Git 配置:
128
+
129
+ ```bash
130
+ npm run test:auth-error
131
+ ```
132
+
133
+ 该脚本使用独立缓存和模拟失败的 Git 命令运行构建后的 CLI,要求在超时前返回明确错误。正常访问链路仍使用以下命令验证:
134
+
135
+ ```bash
136
+ npm run build
137
+ node dist/index.js init --refresh
138
+ ```
139
+
140
+ 发版前统一执行:
141
+
142
+ ```bash
143
+ npm run test:release
144
+ ```
145
+
146
+ 该命令会依次验证构建、命令入口及参数、HTTPS Git 兼容性、公共注册仓库访问、失败错误提示和 npm 发布包内容。
147
+
148
+ 如果已经手动执行过 `npm run build`,可以只验证构建产物和 Git 场景:
149
+
150
+ ```bash
151
+ npm run test:smoke
152
+ ```
153
+
154
+ ## 发布到 npm
155
+
156
+ 本包以 `gz-cli-front` 为独立包名,初始版本为 `1.0.0`,不会覆盖或更新旧的 `@chenhui996/gg-cli` 包。
157
+
158
+ 首次发布前,确认包名尚未被占用,并登录有发布权限的 npm 账号:
159
+
160
+ ```bash
161
+ npm view gz-cli-front --registry=https://registry.npmjs.org/
162
+ npm login --registry=https://registry.npmjs.org/
163
+ npm whoami --registry=https://registry.npmjs.org/
164
+ ```
165
+
166
+ 查询返回 E404 表示未找到该包;网络或认证错误不能作为包名可用的判断依据。最终能否发布以 npm 的校验结果为准。
167
+
168
+ 安装依赖并验证:
169
+
170
+ ```bash
171
+ npm ci
172
+ npm run test:release
173
+ ```
174
+
175
+ 确认通过后发布:
176
+
177
+ ```bash
178
+ npm publish --registry=https://registry.npmjs.org/
179
+ ```
180
+
181
+ 发布时会自动通过 `prepublishOnly` 再运行一次发布验证。发布内容包括 `bin`、构建后的 `dist`、包信息和 README,不包含 `src/template` 中的本地模板。
182
+
183
+ 发布后可验证:
184
+
185
+ ```bash
186
+ npm view gz-cli-front version --registry=https://registry.npmjs.org/
187
+ npx --registry=https://registry.npmjs.org/ gz-cli-front@1.0.0 --version
188
+ ```
@@ -1,2 +1,2 @@
1
- #!/usr/bin/env node
2
- import '../dist/index.js';
1
+ #!/usr/bin/env node
2
+ import '../dist/index.js';
@@ -1,7 +1,7 @@
1
- {
2
- "templateRegistry": {
3
- "source": "git",
4
- "url": "https://github.com/gz-fronted/gg-cli-template-register.git",
5
- "file": "templates.json"
6
- }
7
- }
1
+ {
2
+ "templateRegistry": {
3
+ "source": "git",
4
+ "url": "https://github.com/gz-fronted/gg-cli-template-register.git",
5
+ "file": "templates.json"
6
+ }
7
+ }
package/dist/index.js CHANGED
@@ -1451,7 +1451,7 @@ var program = new Command();
1451
1451
  var require2 = createRequire(import.meta.url);
1452
1452
  var packageMetadata = require2("../package.json");
1453
1453
  var packageVersion = getPackageVersion(packageMetadata);
1454
- program.name("gz-cli-front").description("\u524D\u7AEF\u811A\u624B\u67B6\u5DE5\u5177").version(packageVersion);
1454
+ program.name("gz-cli").description("\u524D\u7AEF\u811A\u624B\u67B6\u5DE5\u5177").version(packageVersion);
1455
1455
  program.command("init [project-name]", { isDefault: true }).description("\u521B\u5EFA\u4E00\u4E2A\u65B0\u9879\u76EE").option("--pm <package-manager>", "\u6307\u5B9A\u5305\u7BA1\u7406\u5668\uFF1Anpm\u3001pnpm \u6216 yarn").option("--proxy <url>", "\u6307\u5B9A\u672C\u6B21\u521D\u59CB\u5316\u4F7F\u7528\u7684 HTTP(S) \u4EE3\u7406").option("--no-proxy", "\u5F3A\u5236\u76F4\u8FDE\uFF0C\u4E0D\u8BFB\u53D6\u73AF\u5883\u53D8\u91CF\u6216\u7CFB\u7EDF\u4EE3\u7406").option("--refresh", "\u5FFD\u7565\u6A21\u677F\u914D\u7F6E\u548C\u6A21\u677F\u7F13\u5B58\uFF0C\u5F3A\u5236\u4ECE\u8FDC\u7A0B\u4ED3\u5E93\u5237\u65B0").action((projectName, options) => {
1456
1456
  void create(projectName, options);
1457
1457
  });
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/commands/create.ts","../src/services/config.ts","../src/utils/pkg-manager.ts","../src/utils/template.ts","../src/utils/cache.ts","../src/utils/http.ts","../src/utils/system-proxy.ts","../src/utils/git-repository.ts","../src/utils/template-downloader.ts","../src/utils/stable-spinner.ts","../src/pre/index.ts"],"sourcesContent":["import { Command } from 'commander';\nimport { createRequire } from 'node:module';\nimport { create } from './commands/create.js';\nimport { checkNodeVersion } from './pre/index.js';\n\n// 1. 前置检查:Node.js 版本\ncheckNodeVersion();\n\nconst program = new Command();\nconst require = createRequire(import.meta.url);\nconst packageMetadata: unknown = require('../package.json');\nconst packageVersion = getPackageVersion(packageMetadata);\n\nprogram\n .name('gz-cli-front')\n .description('前端脚手架工具')\n .version(packageVersion);\n\n// 将 init 设为默认命令,参数改为可选 [project-name]\nprogram\n .command('init [project-name]', { isDefault: true })\n .description('创建一个新项目')\n .option('--pm <package-manager>', '指定包管理器:npm、pnpm 或 yarn')\n .option('--proxy <url>', '指定本次初始化使用的 HTTP(S) 代理')\n .option('--no-proxy', '强制直连,不读取环境变量或系统代理')\n .option('--refresh', '忽略模板配置和模板缓存,强制从远程仓库刷新')\n .action((projectName, options) => {\n void create(projectName, options);\n });\n\nprogram\n .command('create [project-name]')\n .description('创建一个新项目(兼容旧命令)')\n .option('--pm <package-manager>', '指定包管理器:npm、pnpm 或 yarn')\n .option('--proxy <url>', '指定本次初始化使用的 HTTP(S) 代理')\n .option('--no-proxy', '强制直连,不读取环境变量或系统代理')\n .option('--refresh', '忽略模板配置和模板缓存,强制从远程仓库刷新')\n .action((projectName, options) => {\n void create(projectName, options);\n });\n\nprogram.parse(process.argv);\n\nfunction getPackageVersion(value: unknown): string {\n if (typeof value !== 'object' || value === null) {\n throw new Error('无法读取 gz-cli-front 版本号。');\n }\n\n const version = (value as Record<string, unknown>).version;\n if (typeof version !== 'string' || !version.trim()) {\n throw new Error('gz-cli-front package.json 中缺少有效版本号。');\n }\n return version;\n}\n","import { confirm, input, select } from '@inquirer/prompts';\nimport chalk from 'chalk';\nimport { execa } from 'execa';\nimport fs from 'fs-extra';\nimport ora from 'ora';\nimport path from 'path';\nimport { performance } from 'node:perf_hooks';\nimport { loadCliConfig } from '../services/config.js';\nimport {\n detectPackageManager,\n isPackageManager,\n updateProjectPackageJson,\n type PackageManager,\n} from '../utils/pkg-manager.js';\nimport {\n fetchTemplates,\n replaceTemplateVariables,\n type FetchTemplatesResult,\n type TemplateMeta,\n} from '../utils/template.js';\nimport { downloadTemplate, type TemplateDownloadTiming } from '../utils/template-downloader.js';\nimport { configureNetwork, type NetworkRoute } from '../utils/http.js';\nimport { createStableSpinner } from '../utils/stable-spinner.js';\n\nexport interface InitOptions {\n pm?: string;\n proxy?: string | false;\n refresh?: boolean;\n}\n\ninterface InitContext {\n projectName: string;\n template: TemplateMeta;\n packageManager: PackageManager;\n}\n\ninterface TemplateTiming {\n configRoute: NetworkRoute | 'ssh' | 'cache' | 'stale-cache';\n copyMs: number;\n fetchConfigMs: number;\n parseConfigMs: number;\n templateRoute: NetworkRoute | 'ssh' | 'cache' | 'stale-cache' | 'git';\n downloadMs: number;\n extractMs: number;\n renderMs: number;\n}\n\nexport async function create(projectName?: string, options: InitOptions = {}): Promise<void> {\n try {\n configureNetwork({\n forceDirect: options.proxy === false,\n proxy: typeof options.proxy === 'string' ? options.proxy : undefined,\n });\n const templateTiming = createTemplateTiming();\n const context = await createInitContext(projectName, options, templateTiming);\n const targetPath = path.resolve(process.cwd(), context.projectName);\n\n if (!(await prepareTargetDirectory(targetPath, context.projectName))) {\n return;\n }\n\n const install = await confirm({\n message: '是否自动安装依赖?',\n default: true,\n });\n\n await downloadAndGenerate(context, targetPath, templateTiming, options);\n await installDependencies(install, targetPath, context.packageManager);\n await initializeGit(targetPath);\n printNextSteps(context, install);\n } catch (error: unknown) {\n if (isUserCancellation(error)) {\n console.log(chalk.yellow('\\n已取消操作。'));\n return;\n }\n\n console.error(chalk.red(`创建项目失败:${getErrorMessage(error)}`));\n }\n}\n\nasync function createInitContext(\n projectName: string | undefined,\n options: InitOptions,\n templateTiming: TemplateTiming,\n): Promise<InitContext> {\n const finalProjectName = await getProjectName(projectName);\n const templates = await loadTemplates(templateTiming, options);\n const template = await chooseTemplate(templates);\n\n return {\n projectName: finalProjectName,\n template,\n packageManager: resolvePackageManager(options.pm),\n };\n}\n\nasync function getProjectName(projectName?: string): Promise<string> {\n if (projectName?.trim()) {\n return projectName.trim();\n }\n\n return input({\n message: '请输入项目名称:',\n validate: (value) => value.trim() ? true : '项目名称不能为空',\n });\n}\n\nasync function loadTemplates(\n templateTiming: TemplateTiming,\n options: InitOptions,\n): Promise<TemplateMeta[]> {\n const spinner = createStableSpinner();\n try {\n const config = await loadCliConfig();\n spinner.start('正在获取远程模板配置...');\n const result = await fetchTemplates(config.templateRegistry, {\n forceRefresh: options.refresh === true,\n });\n assignFetchTiming(templateTiming, result);\n spinner.succeed('远程模板配置获取成功');\n if (result.staleCache) {\n console.log(chalk.yellow('远程模板配置暂时不可用,已使用本地缓存。'));\n }\n return result.templates;\n } catch (error: unknown) {\n if (spinner.isSpinning) {\n spinner.fail('获取远程模板配置失败');\n } else {\n console.error(chalk.red('获取远程模板配置失败'));\n }\n const message = error instanceof Error && error.message\n ? error.message\n : '未知错误';\n throw new Error(`获取远程模板配置失败,请检查网络或模板配置地址。\\n${message}`);\n }\n}\n\nasync function chooseTemplate(templates: TemplateMeta[]): Promise<TemplateMeta> {\n return select({\n message: '请选择项目模板:',\n choices: templates.map((template) => ({\n name: `${template.label} (${template.name}) - ${template.description}`,\n value: template,\n })),\n default: templates.find((template) => template.type === 'micro') ?? templates[0],\n });\n}\n\nfunction resolvePackageManager(requestedPackageManager?: string): PackageManager {\n if (requestedPackageManager !== undefined) {\n if (!isPackageManager(requestedPackageManager)) {\n throw new Error(\n `不支持的 packageManager: ${requestedPackageManager}\\n支持: npm、pnpm、yarn`,\n );\n }\n return requestedPackageManager;\n }\n\n const packageManager = detectPackageManager();\n if (packageManager === 'npm') {\n console.log(chalk.yellow('未检测到 pnpm 或 yarn,自动使用 npm。'));\n }\n return packageManager;\n}\n\nasync function prepareTargetDirectory(targetPath: string, projectName: string): Promise<boolean> {\n if (!(await fs.pathExists(targetPath))) {\n return true;\n }\n\n const overwrite = await confirm({\n message: `目录 ${projectName} 已存在,是否覆盖?`,\n default: false,\n });\n\n if (!overwrite) {\n console.log(chalk.yellow('已取消创建。'));\n return false;\n }\n\n await fs.remove(targetPath);\n return true;\n}\n\nasync function downloadAndGenerate(\n context: InitContext,\n targetPath: string,\n templateTiming: TemplateTiming,\n options: InitOptions,\n): Promise<void> {\n const { template, projectName, packageManager } = context;\n const spinner = createStableSpinner();\n const downloadStartedAt = performance.now();\n try {\n spinner.start(`正在下载模板 ${template.label}...`);\n const downloadTiming = await downloadTemplate(template, targetPath, {\n forceRefresh: options.refresh === true,\n });\n assignDownloadTiming(templateTiming, downloadTiming);\n } catch (error: unknown) {\n templateTiming.downloadMs = Math.round(performance.now() - downloadStartedAt);\n await fs.remove(targetPath);\n if (spinner.isSpinning) {\n spinner.fail('模板下载失败');\n } else {\n console.error(chalk.red('模板下载失败'));\n }\n printTemplateTiming(templateTiming);\n const message = error instanceof Error && error.message\n ? error.message\n : '未知错误';\n throw new Error(`模板下载失败,请检查仓库地址或网络连接。\\n${message}`);\n }\n\n try {\n spinner.text = '正在替换模板变量...';\n const startedAt = performance.now();\n await replaceTemplateVariables(targetPath, { projectName });\n await updateProjectPackageJson(targetPath, projectName, packageManager);\n templateTiming.renderMs = Math.round(performance.now() - startedAt);\n spinner.succeed('模板下载并生成完成');\n printTemplateTiming(templateTiming);\n } catch {\n await fs.remove(targetPath);\n spinner.fail('模板下载或变量替换失败');\n throw new Error('模板变量替换失败,请检查模板文件内容。');\n }\n}\n\nfunction createTemplateTiming(): TemplateTiming {\n return {\n configRoute: 'direct',\n copyMs: 0,\n fetchConfigMs: 0,\n parseConfigMs: 0,\n templateRoute: 'direct',\n downloadMs: 0,\n extractMs: 0,\n renderMs: 0,\n };\n}\n\nfunction assignFetchTiming(\n templateTiming: TemplateTiming,\n result: FetchTemplatesResult,\n): void {\n templateTiming.fetchConfigMs = result.fetchMs;\n templateTiming.parseConfigMs = result.parseMs;\n templateTiming.configRoute = result.route;\n}\n\nfunction assignDownloadTiming(\n templateTiming: TemplateTiming,\n downloadTiming: TemplateDownloadTiming,\n): void {\n templateTiming.copyMs = downloadTiming.copyMs;\n templateTiming.downloadMs = downloadTiming.downloadMs;\n templateTiming.extractMs = downloadTiming.extractMs;\n templateTiming.templateRoute = downloadTiming.route;\n}\n\nfunction printTemplateTiming(templateTiming: TemplateTiming): void {\n console.log('\\n[template]');\n console.log(`fetch config: ${templateTiming.fetchConfigMs} ms (${formatRoute(templateTiming.configRoute)})`);\n console.log(`parse config: ${templateTiming.parseConfigMs} ms`);\n console.log(`download: ${templateTiming.downloadMs} ms (${formatRoute(templateTiming.templateRoute)})`);\n console.log(`extract: ${templateTiming.extractMs} ms`);\n console.log(`copy: ${templateTiming.copyMs} ms`);\n console.log(`render: ${templateTiming.renderMs} ms`);\n}\n\nfunction formatRoute(route: TemplateTiming['configRoute'] | TemplateTiming['templateRoute']): string {\n if (route === 'proxy-environment') {\n return 'remote, 环境变量代理';\n }\n if (route === 'proxy-system') {\n return 'remote, 系统代理';\n }\n if (route === 'direct') {\n return 'remote, 直连';\n }\n if (route === 'ssh') {\n return 'remote, Git/SSH';\n }\n return route.replace('-', ' ');\n}\n\nasync function installDependencies(\n install: boolean,\n targetPath: string,\n packageManager: PackageManager,\n): Promise<void> {\n if (!install) {\n return;\n }\n\n const installCommand = packageManager === 'yarn' ? [] : ['install'];\n const spinner = ora(`正在安装依赖 (${packageManager} ${installCommand.join(' ')})...`).start();\n try {\n await execa(packageManager, installCommand, { cwd: targetPath });\n spinner.succeed('依赖安装成功');\n } catch {\n spinner.warn('依赖安装失败,请进入项目目录后手动安装');\n }\n}\n\nasync function initializeGit(targetPath: string): Promise<void> {\n const spinner = ora('正在初始化 Git 仓库...').start();\n try {\n await execa('git', ['init'], { cwd: targetPath });\n spinner.succeed('Git 仓库初始化成功');\n } catch {\n spinner.warn('Git 仓库初始化失败,请确认 Git 已安装');\n }\n}\n\nfunction printNextSteps(context: InitContext, installed: boolean): void {\n const { projectName, packageManager } = context;\n const installCommand = packageManager === 'yarn' ? 'yarn' : `${packageManager} install`;\n const devCommand = packageManager === 'npm' ? 'npm run dev' : `${packageManager} dev`;\n\n console.log(chalk.green(`\\n项目 ${projectName} 创建成功!`));\n console.log('\\n接下来你可以:\\n');\n console.log(chalk.cyan(` cd ${projectName}`));\n if (!installed) {\n console.log(chalk.cyan(` ${installCommand}`));\n }\n console.log(chalk.cyan(` ${devCommand}`));\n}\n\nfunction isUserCancellation(error: unknown): boolean {\n return error instanceof Error && /User force closed|User cancelled/i.test(error.message);\n}\n\nfunction getErrorMessage(error: unknown): string {\n return error instanceof Error && error.message ? ` ${error.message}` : '';\n}\n","import fs from 'fs-extra';\nimport path from 'path';\nimport { fileURLToPath } from 'url';\nimport type { CliConfig } from '../types/config.js';\n\nconst CONFIG_FILE_NAME = 'gz-cli-front.config.json';\n\nexport async function loadCliConfig(): Promise<CliConfig> {\n const configPath = await findConfigPath();\n const config: unknown = await fs.readJson(configPath);\n\n if (!isCliConfig(config)) {\n throw new Error(`CLI 配置文件无效:${configPath}`);\n }\n\n return config;\n}\n\nasync function findConfigPath(): Promise<string> {\n const moduleDirectory = path.dirname(fileURLToPath(import.meta.url));\n const configPaths = [\n path.resolve(moduleDirectory, 'config', CONFIG_FILE_NAME),\n path.resolve(moduleDirectory, '..', 'config', CONFIG_FILE_NAME),\n path.resolve(moduleDirectory, '..', '..', 'config', CONFIG_FILE_NAME),\n ];\n\n for (const configPath of configPaths) {\n if (await fs.pathExists(configPath)) {\n return configPath;\n }\n }\n\n throw new Error('未找到 gz-cli-front 配置文件。');\n}\n\nfunction isCliConfig(value: unknown): value is CliConfig {\n if (typeof value !== 'object' || value === null) {\n return false;\n }\n\n const templateRegistry = (value as Record<string, unknown>).templateRegistry;\n if (typeof templateRegistry !== 'object' || templateRegistry === null) {\n return false;\n }\n\n return isTemplateRegistryConfig(templateRegistry as Record<string, unknown>);\n}\n\nfunction isTemplateRegistryConfig(value: Record<string, unknown>): boolean {\n if (!isNonEmptyString(value.url)) {\n return false;\n }\n\n if (value.source === undefined || value.source === 'http') {\n return true;\n }\n\n return value.source === 'git'\n && isNonEmptyString(value.file)\n && (value.version === undefined || isNonEmptyString(value.version));\n}\n\nfunction isNonEmptyString(value: unknown): value is string {\n return typeof value === 'string' && value.trim().length > 0;\n}\n","import fs from 'fs-extra';\nimport path from 'path';\nimport { spawnSync } from 'node:child_process';\n\nexport type PackageManager = 'npm' | 'pnpm' | 'yarn';\n\nconst PACKAGE_MANAGERS: readonly PackageManager[] = ['pnpm', 'yarn', 'npm'];\n\nexport function detectPackageManager(): PackageManager {\n return PACKAGE_MANAGERS.find(isPackageManagerAvailable) ?? 'npm';\n}\n\nexport function isPackageManager(value: string): value is PackageManager {\n return PACKAGE_MANAGERS.includes(value as PackageManager);\n}\n\nexport async function updateProjectPackageJson(\n targetDir: string,\n projectName: string,\n packageManager: PackageManager,\n): Promise<void> {\n const packageJsonPath = path.join(targetDir, 'package.json');\n if (!(await fs.pathExists(packageJsonPath))) {\n return;\n }\n\n const packageJson: Record<string, unknown> = await fs.readJson(packageJsonPath);\n packageJson.name = projectName;\n\n if (Object.prototype.hasOwnProperty.call(packageJson, 'packageManager')) {\n packageJson.packageManager = packageManager;\n }\n\n await fs.writeJson(packageJsonPath, packageJson, { spaces: 2 });\n}\n\nfunction isPackageManagerAvailable(packageManager: PackageManager): boolean {\n const result = spawnSync(packageManager, ['--version'], {\n shell: process.platform === 'win32',\n stdio: 'ignore',\n });\n\n return result.status === 0;\n}\n","import fs from 'fs-extra';\nimport path from 'path';\nimport { performance } from 'node:perf_hooks';\nimport type { TemplateRegistryConfig } from '../types/config.js';\nimport type { TemplateMeta, TemplateSource, TemplateType } from '../types/template.js';\nimport {\n getTemplateRegistryCachePath,\n isCacheFresh,\n TEMPLATE_REGISTRY_CACHE_TTL_MS,\n} from './cache.js';\nimport { requestBuffer, type NetworkRoute } from './http.js';\nimport { ensureGitRepository } from './git-repository.js';\n\nconst TEXT_FILE_EXTENSIONS = new Set([\n '.json', '.ts', '.tsx', '.js', '.jsx', '.md', '.html', '.css', '.less', '.scss', '.env',\n]);\nconst IGNORED_DIRECTORIES = new Set(['node_modules', 'dist', '.git']);\nconst TEMPLATE_DEBUG_ENV = 'GZ_CLI_FRONT_DEBUG';\nconst TEMPLATE_REGISTRY_TIMEOUT_MS = 5_000;\n\ninterface TemplateRegistryCache {\n body: string;\n fetchedAt: number;\n url: string;\n}\n\nexport interface FetchTemplatesOptions {\n forceRefresh?: boolean;\n}\n\nexport interface FetchTemplatesResult {\n cacheHit: boolean;\n fetchMs: number;\n parseMs: number;\n route: NetworkRoute | 'ssh' | 'cache' | 'stale-cache';\n staleCache: boolean;\n templates: TemplateMeta[];\n}\n\nexport type { TemplateMeta, TemplateSource, TemplateType } from '../types/template.js';\n\nexport async function fetchTemplates(\n templateRegistry: TemplateRegistryConfig | string,\n options: FetchTemplatesOptions = {},\n): Promise<FetchTemplatesResult> {\n const registry = typeof templateRegistry === 'string'\n ? { url: templateRegistry } satisfies TemplateRegistryConfig\n : templateRegistry;\n\n if (registry.source === 'git') {\n return fetchTemplatesFromGit(registry, options);\n }\n\n return fetchTemplatesFromHttp(registry.url, options);\n}\n\nasync function fetchTemplatesFromHttp(\n templateRegistryUrl: string,\n options: FetchTemplatesOptions,\n): Promise<FetchTemplatesResult> {\n const cachePath = getTemplateRegistryCachePath(templateRegistryUrl);\n const cacheStartedAt = performance.now();\n let cached = await readRegistryCache(cachePath, templateRegistryUrl);\n const cacheReadMs = Math.round(performance.now() - cacheStartedAt);\n debugTemplateRequest(templateRegistryUrl, cachePath, options.forceRefresh === true);\n\n if (!options.forceRefresh && cached\n && isCacheFresh(cached.fetchedAt, TEMPLATE_REGISTRY_CACHE_TTL_MS)) {\n try {\n return parseTemplates(cached.body, true, false, cacheReadMs, 'cache');\n } catch {\n await fs.remove(cachePath);\n cached = undefined;\n }\n }\n\n const fetchStartedAt = performance.now();\n try {\n const response = await requestBuffer(templateRegistryUrl, {\n retries: 1,\n timeoutMs: TEMPLATE_REGISTRY_TIMEOUT_MS,\n });\n const body = response.body.toString('utf8');\n const result = parseTemplates(body, false, false, response.elapsedMs, response.route);\n try {\n await writeRegistryCache(cachePath, {\n body,\n fetchedAt: Date.now(),\n url: templateRegistryUrl,\n });\n } catch (error: unknown) {\n if (process.env[TEMPLATE_DEBUG_ENV] === '1') {\n console.log(`template config cache write failed: ${getErrorMessage(error)}`);\n }\n }\n return result;\n } catch (error: unknown) {\n if (!options.forceRefresh && cached) {\n return parseTemplates(\n cached.body,\n true,\n true,\n Math.round(performance.now() - fetchStartedAt),\n 'stale-cache',\n );\n }\n throw createTemplateRequestError(templateRegistryUrl, error);\n }\n}\n\nasync function fetchTemplatesFromGit(\n registry: Extract<TemplateRegistryConfig, { source: 'git' }>,\n options: FetchTemplatesOptions,\n): Promise<FetchTemplatesResult> {\n const cacheKey = `git:${registry.url}#${registry.version ?? 'latest'}:${registry.file}`;\n const fallbackCachePath = getTemplateRegistryCachePath(cacheKey);\n const fallbackCache = await readRegistryCache(fallbackCachePath, cacheKey);\n const startedAt = performance.now();\n\n try {\n const result = await ensureGitRepository(registry.url, {\n forceRefresh: options.forceRefresh,\n namespace: 'registry',\n ttlMs: TEMPLATE_REGISTRY_CACHE_TTL_MS,\n version: registry.version,\n });\n const registryFile = resolveRegistryFile(result.path, registry.file);\n const body = await fs.readFile(registryFile, 'utf8');\n const parsed = parseTemplates(\n body,\n result.cacheHit,\n result.staleCache,\n result.elapsedMs,\n result.route,\n );\n if (!result.cacheHit || !fallbackCache) {\n await writeRegistryCache(fallbackCachePath, {\n body,\n fetchedAt: Date.now(),\n url: cacheKey,\n }).catch(() => undefined);\n }\n return parsed;\n } catch (error: unknown) {\n if (!options.forceRefresh && fallbackCache) {\n return parseTemplates(\n fallbackCache.body,\n true,\n true,\n Math.round(performance.now() - startedAt),\n 'stale-cache',\n );\n }\n throw new Error(`模板注册仓库读取失败\\nerror: ${getErrorMessage(error)}`);\n }\n}\n\nfunction resolveRegistryFile(repositoryPath: string, registryFile: string): string {\n const resolvedRepository = path.resolve(repositoryPath);\n const resolvedFile = path.resolve(repositoryPath, registryFile);\n if (resolvedFile !== resolvedRepository\n && !resolvedFile.startsWith(`${resolvedRepository}${path.sep}`)) {\n throw new Error(`模板注册文件必须位于注册仓库内:${registryFile}`);\n }\n return resolvedFile;\n}\n\nfunction parseTemplates(\n body: string,\n cacheHit: boolean,\n staleCache: boolean,\n fetchMs: number,\n route: FetchTemplatesResult['route'],\n): FetchTemplatesResult {\n const parseStartedAt = performance.now();\n let data: unknown;\n\n try {\n data = JSON.parse(body);\n } catch (error: unknown) {\n throw new Error(`模板配置 JSON 解析失败:${getErrorMessage(error)}`);\n }\n if (!Array.isArray(data) || data.length === 0) {\n throw new Error('模板注册表为空');\n }\n\n const templates = data.filter(isTemplateMeta);\n if (templates.length === 0) {\n throw new Error('模板注册表中没有有效模板');\n }\n\n return {\n cacheHit,\n fetchMs,\n parseMs: Math.round(performance.now() - parseStartedAt),\n route,\n staleCache,\n templates,\n };\n}\n\nfunction debugTemplateRequest(\n templateRegistryUrl: string,\n cachePath: string,\n forceRefresh: boolean,\n): void {\n if (process.env[TEMPLATE_DEBUG_ENV] !== '1') {\n return;\n }\n\n console.log('template config url:', templateRegistryUrl);\n console.log('template config client: undici fetch');\n console.log(`template config timeout: ${TEMPLATE_REGISTRY_TIMEOUT_MS} ms`);\n console.log('template config cache:', cachePath);\n console.log('template config force refresh:', forceRefresh);\n}\n\nfunction createTemplateRequestError(templateRegistryUrl: string, error: unknown): Error {\n return new Error(\n `模板配置请求失败\\nurl: ${templateRegistryUrl}\\nerror: ${getErrorMessage(error)}`,\n );\n}\n\nfunction getErrorMessage(error: unknown): string {\n if (!(error instanceof Error)) {\n return '未知错误';\n }\n\n const cause = 'cause' in error ? error.cause : undefined;\n const causeMessage = cause instanceof Error ? cause.message : String(cause ?? '');\n return causeMessage ? `${error.message} (${causeMessage})` : error.message;\n}\n\nasync function readRegistryCache(\n cachePath: string,\n templateRegistryUrl: string,\n): Promise<TemplateRegistryCache | undefined> {\n try {\n const cache: unknown = await fs.readJson(cachePath);\n if (!isRecord(cache)\n || cache.url !== templateRegistryUrl\n || typeof cache.body !== 'string'\n || typeof cache.fetchedAt !== 'number') {\n return undefined;\n }\n return {\n body: cache.body,\n fetchedAt: cache.fetchedAt,\n url: cache.url,\n };\n } catch {\n return undefined;\n }\n}\n\nasync function writeRegistryCache(\n cachePath: string,\n cache: TemplateRegistryCache,\n): Promise<void> {\n await fs.ensureDir(path.dirname(cachePath));\n await fs.writeJson(cachePath, cache);\n}\n\nexport async function replaceTemplateVariables(\n targetDir: string,\n variables: Readonly<Record<string, string>>,\n): Promise<void> {\n await visitDirectory(targetDir, async (filePath) => {\n if (!shouldProcessFile(filePath)) {\n return;\n }\n\n const content = await fs.readFile(filePath, 'utf8');\n const replaced = Object.entries(variables).reduce(\n (result, [key, value]) => result.split(`{{ ${key} }}`).join(value),\n content,\n );\n\n if (replaced !== content) {\n await fs.writeFile(filePath, replaced, 'utf8');\n }\n });\n}\n\nasync function visitDirectory(\n directory: string,\n onFile: (filePath: string) => Promise<void>,\n): Promise<void> {\n const entries = await fs.readdir(directory, { withFileTypes: true });\n for (const entry of entries) {\n const entryPath = path.join(directory, entry.name);\n if (entry.isDirectory()) {\n if (!IGNORED_DIRECTORIES.has(entry.name)) {\n await visitDirectory(entryPath, onFile);\n }\n } else if (entry.isFile()) {\n await onFile(entryPath);\n }\n }\n}\n\nfunction shouldProcessFile(filePath: string): boolean {\n const filename = path.basename(filePath);\n return TEXT_FILE_EXTENSIONS.has(path.extname(filename)) || filename.startsWith('.env');\n}\n\nfunction isTemplateMeta(value: unknown): value is TemplateMeta {\n if (!isRecord(value)) {\n return false;\n }\n\n return isString(value.name)\n && isString(value.label)\n && isString(value.description)\n && isTemplateType(value.type)\n && isTemplateLocation(value)\n && (value.version === undefined || isString(value.version));\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null;\n}\n\nfunction isString(value: unknown): value is string {\n return typeof value === 'string' && value.trim().length > 0;\n}\n\nfunction isTemplateType(value: unknown): value is TemplateType {\n return value === 'main' || value === 'micro';\n}\n\nfunction isTemplateLocation(value: Record<string, unknown>): boolean {\n if (value.source !== undefined && !isTemplateSource(value.source)) {\n return false;\n }\n\n if (isString(value.url)) {\n return true;\n }\n\n return value.source === undefined && isString(value.repo);\n}\n\nfunction isTemplateSource(value: unknown): value is TemplateSource {\n return value === 'github' || value === 'gitlab' || value === 'git';\n}\n","import { createHash } from 'node:crypto';\nimport os from 'node:os';\nimport path from 'node:path';\n\nexport const TEMPLATE_REGISTRY_CACHE_TTL_MS = 5 * 60 * 1000;\nexport const TEMPLATE_ARCHIVE_CACHE_TTL_MS = 10 * 60 * 1000;\n\nexport function getTemplateRegistryCachePath(url: string): string {\n return path.join(getCacheDirectory(), 'registry', `${createCacheKey(url)}.json`);\n}\n\nexport function getTemplateArchiveCachePath(source: string): string {\n return path.join(getCacheDirectory(), 'templates', `${createCacheKey(source)}.tar.gz`);\n}\n\nexport function getGitRepositoryCachePath(\n namespace: 'registry' | 'templates',\n source: string,\n): string {\n return path.join(getCacheDirectory(), namespace, `git-${createCacheKey(source)}`);\n}\n\nexport function isCacheFresh(updatedAt: number, ttlMs: number): boolean {\n return Date.now() - updatedAt < ttlMs;\n}\n\nfunction getCacheDirectory(): string {\n const configuredDirectory = process.env.GZ_CLI_FRONT_CACHE_DIR?.trim();\n return configuredDirectory || path.join(os.homedir(), '.gz-cli-front', 'cache');\n}\n\nfunction createCacheKey(value: string): string {\n return createHash('sha256').update(value).digest('hex').slice(0, 24);\n}\n","import { setTimeout as delay } from 'node:timers/promises';\nimport {\n EnvHttpProxyAgent,\n ProxyAgent,\n fetch as undiciFetch,\n type Dispatcher,\n} from 'undici';\nimport { getSystemProxy } from './system-proxy.js';\n\nexport interface NetworkOptions {\n forceDirect?: boolean;\n proxy?: string;\n}\n\nexport interface HttpRequestOptions {\n headers?: Readonly<Record<string, string>>;\n retries: number;\n timeoutMs: number;\n}\n\nexport interface HttpResponseData {\n body: Buffer;\n elapsedMs: number;\n route: NetworkRoute;\n status: number;\n}\n\nexport type NetworkRoute = 'direct' | 'proxy-environment' | 'proxy-system';\n\nlet networkOptions: NetworkOptions = {};\n\nexport function configureNetwork(options: NetworkOptions): void {\n if (options.proxy) {\n validateProxyUrl(options.proxy);\n }\n networkOptions = { ...options };\n}\n\nexport async function requestBuffer(\n url: string,\n options: HttpRequestOptions,\n): Promise<HttpResponseData> {\n const startedAt = performance.now();\n let lastError: unknown;\n const proxyConfig = await resolveProxyConfig(url);\n\n for (let attempt = 0; attempt <= options.retries; attempt += 1) {\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), options.timeoutMs);\n const dispatcher = proxyConfig.createDispatcher?.();\n\n debugNetworkRoute(url, proxyConfig.route, attempt + 1, options.retries + 1);\n\n try {\n const response = await undiciFetch(url, {\n ...(dispatcher ? { dispatcher } : {}),\n headers: options.headers,\n redirect: 'follow',\n signal: controller.signal,\n });\n\n if (!response.ok) {\n throw new Error(`HTTP ${response.status} ${response.statusText}`);\n }\n\n return {\n body: Buffer.from(await response.arrayBuffer()),\n elapsedMs: Math.round(performance.now() - startedAt),\n route: proxyConfig.route,\n status: response.status,\n };\n } catch (error: unknown) {\n lastError = error;\n if (attempt < options.retries) {\n await delay(250 * (attempt + 1));\n }\n } finally {\n clearTimeout(timeout);\n await dispatcher?.destroy();\n }\n }\n\n throw createRequestError(url, options, proxyConfig.route, lastError);\n}\n\ninterface ResolvedProxyConfig {\n createDispatcher?: () => Dispatcher;\n proxyUrl?: string;\n route: NetworkRoute;\n}\n\nasync function resolveProxyConfig(url: string): Promise<ResolvedProxyConfig> {\n const target = new URL(url);\n\n if (networkOptions.forceDirect) {\n return { route: 'direct' };\n }\n\n if (networkOptions.proxy) {\n const proxyUrl = networkOptions.proxy;\n return {\n createDispatcher: () => new ProxyAgent({ uri: proxyUrl }),\n proxyUrl,\n route: 'proxy-environment',\n };\n }\n\n const httpProxy = readEnvironmentVariable('http_proxy', 'HTTP_PROXY');\n const httpsProxy = readEnvironmentVariable('https_proxy', 'HTTPS_PROXY');\n const noProxy = readEnvironmentVariable('no_proxy', 'NO_PROXY');\n const environmentProxy = target.protocol === 'https:'\n ? httpsProxy ?? httpProxy\n : httpProxy;\n\n if (noProxy && shouldBypassProxy(target, noProxy)) {\n return { route: 'direct' };\n }\n\n if (environmentProxy) {\n return {\n createDispatcher: () => new EnvHttpProxyAgent({\n httpProxy,\n httpsProxy,\n noProxy,\n }),\n proxyUrl: environmentProxy,\n route: 'proxy-environment',\n };\n }\n\n const systemProxy = await getSystemProxy(target);\n if (systemProxy.noProxy && shouldBypassProxy(target, systemProxy.noProxy)) {\n return { route: 'direct' };\n }\n if (systemProxy.proxyUrl) {\n return {\n createDispatcher: () => new ProxyAgent({ uri: systemProxy.proxyUrl! }),\n proxyUrl: systemProxy.proxyUrl,\n route: 'proxy-system',\n };\n }\n\n return { route: 'direct' };\n}\n\nexport interface GitNetworkConfig {\n args: string[];\n route: NetworkRoute | 'ssh';\n}\n\nexport async function resolveGitNetworkConfig(repositoryUrl: string): Promise<GitNetworkConfig> {\n if (!/^https?:\\/\\//i.test(repositoryUrl)) {\n return { args: [], route: 'ssh' };\n }\n\n const proxyConfig = await resolveProxyConfig(repositoryUrl);\n if (proxyConfig.proxyUrl) {\n return {\n args: ['-c', `http.proxy=${proxyConfig.proxyUrl}`],\n route: proxyConfig.route,\n };\n }\n\n return {\n args: networkOptions.forceDirect ? ['-c', 'http.proxy='] : [],\n route: 'direct',\n };\n}\n\nfunction readEnvironmentVariable(primaryName: string, fallbackName: string): string | undefined {\n const value = process.env[primaryName] ?? process.env[fallbackName];\n return value?.trim() || undefined;\n}\n\nfunction shouldBypassProxy(target: URL, noProxy: string): boolean {\n const hostname = target.hostname.toLowerCase();\n const port = Number.parseInt(target.port, 10)\n || (target.protocol === 'https:' ? 443 : 80);\n\n return noProxy.split(/[,\\s]/).some((rawEntry) => {\n const entry = rawEntry.trim().toLowerCase();\n if (!entry) {\n return false;\n }\n if (entry === '*') {\n return true;\n }\n\n const parsed = entry.match(/^(.+):(\\d+)$/);\n const entryHostname = parsed ? parsed[1] : entry;\n const entryPort = parsed ? Number.parseInt(parsed[2], 10) : 0;\n if (entryPort && entryPort !== port) {\n return false;\n }\n\n if (!/^[.*]/.test(entryHostname)) {\n return hostname === entryHostname;\n }\n return hostname.endsWith(entryHostname.replace(/^\\*/, ''));\n });\n}\n\nexport function formatNetworkRoute(route: NetworkRoute): string {\n if (route === 'proxy-environment') {\n return '环境变量代理';\n }\n if (route === 'proxy-system') {\n return '系统代理';\n }\n return '直连';\n}\n\nfunction createRequestError(\n url: string,\n options: HttpRequestOptions,\n route: NetworkRoute,\n error: unknown,\n): Error {\n const cause = getErrorMessage(error);\n return new Error(\n `请求失败\\nurl: ${url}\\nerror: ${cause}\\nnetwork: ${formatNetworkRoute(route)}\\ntimeout: ${options.timeoutMs} ms\\nattempts: ${options.retries + 1}`,\n );\n}\n\nfunction validateProxyUrl(proxyUrl: string): void {\n try {\n const parsed = new URL(proxyUrl);\n if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') {\n throw new Error();\n }\n } catch {\n throw new Error('无效的代理地址,请使用 http://host:port 或 https://host:port 格式。');\n }\n}\n\nfunction debugNetworkRoute(\n url: string,\n route: NetworkRoute,\n attempt: number,\n attempts: number,\n): void {\n if (process.env.GZ_CLI_FRONT_DEBUG !== '1') {\n return;\n }\n\n console.log(`[network] host: ${new URL(url).host}`);\n console.log(`[network] route: ${formatNetworkRoute(route)}`);\n console.log(`[network] attempt: ${attempt}/${attempts}`);\n}\n\nfunction getErrorMessage(error: unknown): string {\n if (!(error instanceof Error)) {\n return '未知错误';\n }\n const cause = 'cause' in error ? error.cause : undefined;\n const causeMessage = cause instanceof Error ? cause.message : String(cause ?? '');\n return causeMessage ? `${error.message} (${causeMessage})` : error.message;\n}\n","import { execFile } from 'node:child_process';\nimport { promisify } from 'node:util';\n\nconst execFileAsync = promisify(execFile);\nconst WINDOWS_INTERNET_SETTINGS = String.raw`HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings`;\nconst SYSTEM_PROXY_TIMEOUT_MS = 1_500;\n\nexport interface SystemProxyConfig {\n noProxy?: string;\n proxyUrl?: string;\n}\n\nconst systemProxyCache = new Map<string, Promise<SystemProxyConfig>>();\n\nexport function getSystemProxy(target: URL): Promise<SystemProxyConfig> {\n const cacheKey = `${process.platform}:${target.protocol}`;\n const cached = systemProxyCache.get(cacheKey);\n if (cached) {\n return cached;\n }\n\n const request = detectSystemProxy(target).catch(() => ({}));\n systemProxyCache.set(cacheKey, request);\n return request;\n}\n\nasync function detectSystemProxy(target: URL): Promise<SystemProxyConfig> {\n if (process.platform === 'win32') {\n return detectWindowsProxy(target);\n }\n if (process.platform === 'darwin') {\n return detectMacOsProxy(target);\n }\n if (process.platform === 'linux') {\n return detectLinuxProxy(target);\n }\n return {};\n}\n\nasync function detectWindowsProxy(target: URL): Promise<SystemProxyConfig> {\n const [enabledOutput, serverOutput, overrideOutput] = await Promise.all([\n queryWindowsRegistry('ProxyEnable'),\n queryWindowsRegistry('ProxyServer'),\n queryWindowsRegistry('ProxyOverride'),\n ]);\n const enabled = readRegistryValue(enabledOutput, 'ProxyEnable');\n if (enabled !== '0x1' && enabled !== '1') {\n return {};\n }\n\n const proxyServer = readRegistryValue(serverOutput, 'ProxyServer');\n if (!proxyServer) {\n return {};\n }\n\n const proxyAddress = selectWindowsProxy(proxyServer, target.protocol);\n if (!proxyAddress) {\n return {};\n }\n\n const proxyOverride = readRegistryValue(overrideOutput, 'ProxyOverride');\n return {\n noProxy: proxyOverride?.split(';').filter((entry) => entry !== '<local>').join(','),\n proxyUrl: normalizeProxyUrl(proxyAddress),\n };\n}\n\nasync function queryWindowsRegistry(valueName: string): Promise<string> {\n try {\n const result = await execFileAsync(\n 'reg.exe',\n ['query', WINDOWS_INTERNET_SETTINGS, '/v', valueName],\n { timeout: SYSTEM_PROXY_TIMEOUT_MS, windowsHide: true },\n );\n return result.stdout;\n } catch {\n return '';\n }\n}\n\nfunction readRegistryValue(output: string, valueName: string): string | undefined {\n const line = output.split(/\\r?\\n/).find((entry) => entry.includes(valueName));\n return line?.match(/REG_\\w+\\s+(.+)$/)?.[1]?.trim();\n}\n\nfunction selectWindowsProxy(proxyServer: string, protocol: string): string | undefined {\n if (!proxyServer.includes('=')) {\n return proxyServer;\n }\n\n const proxies = new Map(\n proxyServer.split(';').flatMap((entry) => {\n const [key, value] = entry.split('=', 2).map((part) => part.trim());\n return key && value ? [[key.toLowerCase(), value] as const] : [];\n }),\n );\n const protocolName = protocol.replace(':', '');\n return proxies.get(protocolName) ?? proxies.get('http');\n}\n\nasync function detectMacOsProxy(target: URL): Promise<SystemProxyConfig> {\n try {\n const result = await execFileAsync('scutil', ['--proxy'], {\n timeout: SYSTEM_PROXY_TIMEOUT_MS,\n });\n const prefix = target.protocol === 'https:' ? 'HTTPS' : 'HTTP';\n if (readScutilValue(result.stdout, `${prefix}Enable`) !== '1') {\n return {};\n }\n const host = readScutilValue(result.stdout, `${prefix}Proxy`);\n const port = readScutilValue(result.stdout, `${prefix}Port`);\n return host && port ? { proxyUrl: `http://${host}:${port}` } : {};\n } catch {\n return {};\n }\n}\n\nfunction readScutilValue(output: string, key: string): string | undefined {\n return output.match(new RegExp(`^\\\\s*${key}\\\\s*:\\\\s*(.+)$`, 'm'))?.[1]?.trim();\n}\n\nasync function detectLinuxProxy(target: URL): Promise<SystemProxyConfig> {\n try {\n const mode = stripQuotes(await queryGSettings('org.gnome.system.proxy', 'mode'));\n if (mode !== 'manual') {\n return {};\n }\n\n const protocol = target.protocol === 'https:' ? 'https' : 'http';\n const [hostValue, portValue, ignoredHostsValue] = await Promise.all([\n queryGSettings(`org.gnome.system.proxy.${protocol}`, 'host'),\n queryGSettings(`org.gnome.system.proxy.${protocol}`, 'port'),\n queryGSettings('org.gnome.system.proxy', 'ignore-hosts'),\n ]);\n const host = stripQuotes(hostValue);\n const port = Number.parseInt(portValue.trim(), 10);\n if (!host || !Number.isInteger(port) || port <= 0) {\n return {};\n }\n\n return {\n noProxy: Array.from(\n ignoredHostsValue.matchAll(/'([^']+)'/g),\n (match) => match[1],\n ).join(','),\n proxyUrl: `http://${host}:${port}`,\n };\n } catch {\n return {};\n }\n}\n\nasync function queryGSettings(schema: string, key: string): Promise<string> {\n const result = await execFileAsync('gsettings', ['get', schema, key], {\n timeout: SYSTEM_PROXY_TIMEOUT_MS,\n });\n return result.stdout;\n}\n\nfunction stripQuotes(value: string): string {\n return value.trim().replace(/^['\"]|['\"]$/g, '');\n}\n\nfunction normalizeProxyUrl(proxyAddress: string): string {\n return /^[a-z][a-z\\d+.-]*:\\/\\//i.test(proxyAddress)\n ? proxyAddress\n : `http://${proxyAddress}`;\n}\n","import { execa } from 'execa';\nimport fs from 'fs-extra';\nimport { randomUUID } from 'node:crypto';\nimport path from 'node:path';\nimport { performance } from 'node:perf_hooks';\nimport { setTimeout as delay } from 'node:timers/promises';\nimport { getGitRepositoryCachePath, isCacheFresh } from './cache.js';\nimport {\n formatNetworkRoute,\n resolveGitNetworkConfig,\n type NetworkRoute,\n} from './http.js';\n\nconst GIT_OPERATION_ATTEMPTS = 2;\nconst GIT_AUTH_TIMEOUT_MS = 60_000;\nconst GIT_SSH_CLONE_TIMEOUT_MS = 20_000;\ntype GitOperationStage = 'clone';\n\nexport interface GitRepositoryOptions {\n forceRefresh?: boolean;\n namespace: 'registry' | 'templates';\n ttlMs: number;\n version?: string;\n}\n\nexport interface GitRepositoryResult {\n cacheHit: boolean;\n elapsedMs: number;\n path: string;\n route: NetworkRoute | 'ssh' | 'cache' | 'stale-cache';\n staleCache: boolean;\n}\n\nexport async function ensureGitRepository(\n repositoryUrl: string,\n options: GitRepositoryOptions,\n): Promise<GitRepositoryResult> {\n const version = normalizeVersion(options.version);\n const repositoryPath = getRepositoryCachePath(repositoryUrl, options.namespace, version);\n const startedAt = performance.now();\n const cacheExists = await isValidGitCache(repositoryPath);\n\n if (await canUseGitCache(repositoryPath, cacheExists, version, options)) {\n return createCacheResult(repositoryPath, startedAt, false);\n }\n\n const temporaryPath = `${repositoryPath}.${randomUUID()}.tmp`;\n const candidates = getRepositoryCandidates(repositoryUrl);\n let lastError: unknown;\n await fs.ensureDir(path.dirname(repositoryPath));\n\n for (const [index, candidate] of candidates.entries()) {\n try {\n const network = await resolveGitNetworkConfig(candidate);\n const isSshCandidate = network.route === 'ssh';\n const timeoutMs = isSshCandidate ? GIT_SSH_CLONE_TIMEOUT_MS : GIT_AUTH_TIMEOUT_MS;\n debugGitRepository(candidate, network.route, timeoutMs);\n await cloneRepository(\n candidate,\n temporaryPath,\n version,\n network.args,\n timeoutMs,\n isSshCandidate ? 1 : GIT_OPERATION_ATTEMPTS,\n );\n await replaceCacheDirectory(temporaryPath, repositoryPath);\n return {\n cacheHit: false,\n elapsedMs: Math.round(performance.now() - startedAt),\n path: repositoryPath,\n route: network.route,\n staleCache: false,\n };\n } catch (error: unknown) {\n lastError = error;\n await fs.remove(temporaryPath);\n if (index < candidates.length - 1) {\n if (process.env.GZ_CLI_FRONT_DEBUG === '1') {\n console.log('[git] SSH 不可用,正在尝试 HTTPS...');\n }\n continue;\n }\n }\n }\n\n if (cacheExists && !options.forceRefresh) {\n return createCacheResult(repositoryPath, startedAt, true);\n }\n throw createGitError(repositoryUrl, lastError, 'clone');\n}\n\nfunction getRepositoryCachePath(\n repositoryUrl: string,\n namespace: GitRepositoryOptions['namespace'],\n version: string | undefined,\n): string {\n return getGitRepositoryCachePath(\n namespace,\n `${getRepositoryIdentity(repositoryUrl)}#${version ?? 'latest'}`,\n );\n}\n\nfunction getRepositoryCandidates(repositoryUrl: string): string[] {\n return [repositoryUrl];\n}\n\nfunction getRepositoryIdentity(repositoryUrl: string): string {\n try {\n const parsed = new URL(repositoryUrl);\n const repositoryPath = parsed.pathname.replace(/^\\/|\\/$/g, '').replace(/\\.git$/i, '');\n return `${parsed.hostname.toLowerCase()}/${repositoryPath}`;\n } catch {\n const sshMatch = repositoryUrl.match(/^[^@]+@([^:]+):(.+)$/);\n if (!sshMatch) {\n return repositoryUrl;\n }\n return `${sshMatch[1].toLowerCase()}/${sshMatch[2].replace(/\\.git$/i, '')}`;\n }\n}\n\nasync function canUseGitCache(\n repositoryPath: string,\n cacheExists: boolean,\n version: string | undefined,\n options: GitRepositoryOptions,\n): Promise<boolean> {\n if (options.forceRefresh || !cacheExists) {\n return false;\n }\n const stats = await fs.stat(repositoryPath);\n return Boolean(version) || isCacheFresh(stats.mtimeMs, options.ttlMs);\n}\n\nfunction debugGitRepository(\n repositoryUrl: string,\n route: NetworkRoute | 'ssh',\n timeoutMs: number,\n): void {\n if (process.env.GZ_CLI_FRONT_DEBUG !== '1') {\n return;\n }\n\n const routeLabel = route === 'ssh' ? 'Git/SSH' : formatNetworkRoute(route);\n console.log(`[git] host: ${getRepositoryHost(repositoryUrl)}`);\n console.log(`[git] route: ${routeLabel}`);\n console.log(`[git] timeout: ${timeoutMs} ms`);\n}\n\nfunction getRepositoryHost(repositoryUrl: string): string {\n try {\n return new URL(repositoryUrl).host;\n } catch {\n return repositoryUrl.match(/^[^@]+@([^:]+):/)?.[1] ?? 'unknown';\n }\n}\n\nasync function cloneRepository(\n repositoryUrl: string,\n targetPath: string,\n version: string | undefined,\n networkArgs: string[],\n timeoutMs: number,\n attempts: number,\n): Promise<void> {\n const args = [\n ...networkArgs,\n 'clone',\n '--quiet',\n '--depth',\n '1',\n '--single-branch',\n ];\n if (version) {\n args.push('--branch', version);\n }\n args.push(repositoryUrl, targetPath);\n\n for (let attempt = 1; attempt <= attempts; attempt += 1) {\n try {\n await execa('git', args, {\n forceKillAfterDelay: 1_000,\n stdin: 'inherit',\n stdout: 'pipe',\n stderr: ['pipe', 'inherit'],\n timeout: timeoutMs,\n windowsHide: true,\n });\n return;\n } catch (error: unknown) {\n if (attempt === attempts || !isTransientGitError(error)) {\n throw error;\n }\n if (process.env.GZ_CLI_FRONT_DEBUG === '1') {\n console.log(`[git] transient failure, retry: ${attempt + 1}/${attempts}`);\n }\n await fs.remove(targetPath);\n await delay(300);\n }\n }\n}\n\nfunction isTransientGitError(error: unknown): boolean {\n if (typeof error === 'object' && error !== null\n && (error as Record<string, unknown>).timedOut === true) {\n return true;\n }\n\n const message = error instanceof Error ? error.message : String(error);\n return [\n /SSL\\/TLS connection failed/i,\n /failed to receive handshake/i,\n /connection (?:was )?reset/i,\n /remote end hung up unexpectedly/i,\n /early EOF/i,\n /failed to connect/i,\n /could not resolve host/i,\n /timed out|timeout/i,\n ].some((pattern) => pattern.test(message));\n}\n\nasync function replaceCacheDirectory(sourcePath: string, targetPath: string): Promise<void> {\n const backupPath = `${targetPath}.${randomUUID()}.bak`;\n const targetExists = await fs.pathExists(targetPath);\n if (targetExists) {\n await fs.move(targetPath, backupPath);\n }\n\n try {\n await fs.move(sourcePath, targetPath);\n await fs.remove(backupPath);\n } catch (error: unknown) {\n await fs.remove(targetPath);\n if (await fs.pathExists(backupPath)) {\n await fs.move(backupPath, targetPath);\n }\n throw error;\n }\n}\n\nasync function isValidGitCache(repositoryPath: string): Promise<boolean> {\n return fs.pathExists(path.join(repositoryPath, '.git'));\n}\n\nfunction createCacheResult(\n repositoryPath: string,\n startedAt: number,\n staleCache: boolean,\n): GitRepositoryResult {\n return {\n cacheHit: true,\n elapsedMs: Math.round(performance.now() - startedAt),\n path: repositoryPath,\n route: staleCache ? 'stale-cache' : 'cache',\n staleCache,\n };\n}\n\nfunction normalizeVersion(version: string | undefined): string | undefined {\n return version && version !== 'latest' ? version : undefined;\n}\n\nfunction createGitError(\n repositoryUrl: string,\n error: unknown,\n stage: GitOperationStage,\n): Error {\n const message = getGitErrorMessage(error);\n const safeRepository = sanitizeRepositoryUrl(repositoryUrl);\n debugGitFailure(stage, message);\n if (isGitTimeoutError(error, message)) {\n return new Error(\n `Git 仓库连接超时(阶段:${stage},${GIT_AUTH_TIMEOUT_MS} ms):${safeRepository}\\n请检查当前网络或代理设置后重试。`,\n );\n }\n\n if (isGitPermissionError(message)) {\n return new Error(\n `无法访问 Git 仓库(阶段:${stage}):${safeRepository}\\n请检查仓库地址、网络连接及当前 Git 凭据后重试。`,\n );\n }\n\n return new Error(\n `Git 仓库访问失败(阶段:${stage}):${safeRepository}\\n请确认已安装 Git,且当前 Git/SSH 账号拥有仓库 Read 权限。\\n${message}`,\n );\n}\n\nfunction getGitErrorMessage(error: unknown): string {\n return redactCredentials(error instanceof Error ? error.message : '未知错误');\n}\n\nfunction debugGitFailure(stage: GitOperationStage, message: string): void {\n if (process.env.GZ_CLI_FRONT_DEBUG !== '1') {\n return;\n }\n\n console.error(`[git] failed stage: ${stage}`);\n console.error(`[git] error: ${message}`);\n}\n\nfunction isGitTimeoutError(error: unknown, message: string): boolean {\n if (typeof error === 'object' && error !== null\n && (error as Record<string, unknown>).timedOut === true) {\n return true;\n }\n return /timed out|timeout/i.test(message);\n}\n\nfunction isGitPermissionError(message: string): boolean {\n return [\n /authentication failed/i,\n /permission denied/i,\n /repository not found/i,\n /could not read username/i,\n /unable to get (?:password|username) from user/i,\n /terminal prompts disabled/i,\n /user interaction is disabled/i,\n /interactive prompts are disabled/i,\n /credential.*(?:failed|unavailable)/i,\n /access denied/i,\n /http (?:error )?40[13]/i,\n /status code: 40[13]/i,\n ].some((pattern) => pattern.test(message));\n}\n\nfunction redactCredentials(message: string): string {\n return message\n .replace(/http\\.proxy=\\S+/gi, 'http.proxy=***')\n .replace(/(https?:\\/\\/)[^@\\s/]+@/gi, '$1***@');\n}\n\nfunction sanitizeRepositoryUrl(repositoryUrl: string): string {\n try {\n const parsed = new URL(repositoryUrl);\n parsed.username = '';\n parsed.password = '';\n return parsed.toString();\n } catch {\n return repositoryUrl;\n }\n}\n","import fs from 'fs-extra';\nimport { randomUUID } from 'node:crypto';\nimport path from 'path';\nimport { performance } from 'node:perf_hooks';\nimport { x as extractTar } from 'tar';\nimport type { TemplateMeta, TemplateSource } from '../types/template.js';\nimport {\n getTemplateArchiveCachePath,\n isCacheFresh,\n TEMPLATE_ARCHIVE_CACHE_TTL_MS,\n} from './cache.js';\nimport { requestBuffer, type NetworkRoute } from './http.js';\nimport { ensureGitRepository } from './git-repository.js';\n\nconst TEMPLATE_DOWNLOAD_TIMEOUT_MS = 12_000;\n\nexport interface TemplateDownloadTiming {\n cacheHit: boolean;\n copyMs: number;\n downloadMs: number;\n extractMs: number;\n route: NetworkRoute | 'ssh' | 'cache' | 'stale-cache' | 'git';\n}\n\nexport interface DownloadTemplateOptions {\n forceRefresh?: boolean;\n}\n\ntype TemplateDownloader = (\n template: TemplateMeta,\n targetDir: string,\n options: DownloadTemplateOptions,\n) => Promise<TemplateDownloadTiming>;\n\nconst DOWNLOADERS: Readonly<Record<TemplateSource, TemplateDownloader>> = {\n github: downloadFromGitHub,\n gitlab: downloadFromGit,\n git: downloadFromGit,\n};\n\nexport async function downloadTemplate(\n template: TemplateMeta,\n targetDir: string,\n options: DownloadTemplateOptions = {},\n): Promise<TemplateDownloadTiming> {\n const source = template.source ?? 'github';\n return DOWNLOADERS[source](template, targetDir, options);\n}\n\nasync function downloadFromGitHub(\n template: TemplateMeta,\n targetDir: string,\n options: DownloadTemplateOptions,\n): Promise<TemplateDownloadTiming> {\n const repository = normalizeGitHubRepository(getTemplateUrl(template));\n const version = template.version && template.version !== 'latest'\n ? template.version\n : undefined;\n const sourceKey = `${repository}${version ? `#${version}` : '#latest'}`;\n const archivePath = getTemplateArchiveCachePath(sourceKey);\n const archive = await ensureGitHubArchive(\n repository,\n version,\n archivePath,\n options.forceRefresh === true,\n );\n\n const extractStartedAt = performance.now();\n await fs.ensureDir(targetDir);\n try {\n await extractTar({\n cwd: targetDir,\n file: archivePath,\n preservePaths: false,\n strict: true,\n strip: 1,\n });\n } catch (error: unknown) {\n if (!archive.cacheHit) {\n throw error;\n }\n\n await fs.remove(archivePath);\n await fs.emptyDir(targetDir);\n return downloadFromGitHub(template, targetDir, { forceRefresh: true });\n }\n\n return {\n cacheHit: archive.cacheHit,\n copyMs: 0,\n downloadMs: archive.downloadMs,\n extractMs: Math.round(performance.now() - extractStartedAt),\n route: archive.route,\n };\n}\n\nasync function downloadFromGit(\n template: TemplateMeta,\n targetDir: string,\n options: DownloadTemplateOptions,\n): Promise<TemplateDownloadTiming> {\n if (!template.url) {\n throw new Error(`${template.source} 模板必须提供 Git clone URL。`);\n }\n\n const repository = await ensureGitRepository(template.url, {\n forceRefresh: options.forceRefresh,\n namespace: 'templates',\n ttlMs: TEMPLATE_ARCHIVE_CACHE_TTL_MS,\n version: template.version,\n });\n const copyStartedAt = performance.now();\n await fs.copy(repository.path, targetDir, {\n filter: (sourcePath) => path.basename(sourcePath) !== '.git',\n });\n\n return {\n cacheHit: repository.cacheHit,\n copyMs: Math.round(performance.now() - copyStartedAt),\n downloadMs: repository.elapsedMs,\n extractMs: 0,\n route: repository.route,\n };\n}\n\ninterface GitHubArchiveResult {\n cacheHit: boolean;\n downloadMs: number;\n route: NetworkRoute | 'cache';\n}\n\nasync function ensureGitHubArchive(\n repository: string,\n version: string | undefined,\n archivePath: string,\n forceRefresh: boolean,\n): Promise<GitHubArchiveResult> {\n const startedAt = performance.now();\n if (!forceRefresh && await canUseArchiveCache(archivePath, Boolean(version))) {\n return {\n cacheHit: true,\n downloadMs: Math.round(performance.now() - startedAt),\n route: 'cache',\n };\n }\n\n const archiveRequest = createGitHubArchiveRequest(repository, version);\n const response = await requestBuffer(archiveRequest.url, {\n headers: archiveRequest.headers,\n retries: 1,\n timeoutMs: TEMPLATE_DOWNLOAD_TIMEOUT_MS,\n });\n const temporaryPath = `${archivePath}.${randomUUID()}.tmp`;\n\n await fs.ensureDir(path.dirname(archivePath));\n try {\n await fs.writeFile(temporaryPath, response.body);\n await fs.move(temporaryPath, archivePath, { overwrite: true });\n } finally {\n await fs.remove(temporaryPath);\n }\n\n return {\n cacheHit: false,\n downloadMs: Math.round(performance.now() - startedAt),\n route: response.route,\n };\n}\n\ninterface GitHubArchiveRequest {\n headers: Readonly<Record<string, string>>;\n url: string;\n}\n\nfunction createGitHubArchiveRequest(\n repository: string,\n version: string | undefined,\n): GitHubArchiveRequest {\n const token = process.env.GITHUB_TOKEN?.trim();\n if (token) {\n return {\n headers: createGitHubApiHeaders(token),\n url: `https://api.github.com/repos/${repository}/tarball${version ? `/${encodeURIComponent(version)}` : ''}`,\n };\n }\n\n return {\n headers: { 'user-agent': 'gz-cli-front' },\n url: `https://codeload.github.com/${repository}/tar.gz/${encodeURIComponent(version ?? 'HEAD')}`,\n };\n}\n\nasync function canUseArchiveCache(archivePath: string, immutableVersion: boolean): Promise<boolean> {\n try {\n const stats = await fs.stat(archivePath);\n return stats.isFile()\n && (immutableVersion || isCacheFresh(stats.mtimeMs, TEMPLATE_ARCHIVE_CACHE_TTL_MS));\n } catch {\n return false;\n }\n}\n\nfunction normalizeGitHubRepository(repository: string): string {\n const normalized = repository\n .replace(/^https:\\/\\/github\\.com\\//i, '')\n .replace(/\\.git$/i, '')\n .replace(/^\\/+|\\/+$/g, '');\n\n if (!/^[^/\\s]+\\/[^/\\s]+$/.test(normalized)) {\n throw new Error(`无效的 GitHub 模板地址:${repository}`);\n }\n\n return normalized;\n}\n\nfunction createGitHubApiHeaders(token: string): Readonly<Record<string, string>> {\n return {\n accept: 'application/vnd.github+json',\n authorization: `Bearer ${token}`,\n 'user-agent': 'gz-cli-front',\n 'x-github-api-version': '2022-11-28',\n };\n}\n\nfunction getTemplateUrl(template: TemplateMeta): string {\n if (template.url) {\n return template.url;\n }\n if (template.repo) {\n return template.repo;\n }\n throw new Error('模板配置缺少 url。');\n}\n","import chalk from 'chalk';\nimport { clearLine, cursorTo } from 'node:readline';\n\nconst SPINNER_FRAMES = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];\nconst SPINNER_INTERVAL_MS = 80;\nconst RESTORE_CURSOR = '\\u001B[u';\nconst SAVE_CURSOR = '\\u001B[s';\n\nexport interface StableSpinner {\n readonly isSpinning: boolean;\n text: string;\n fail(text?: string): void;\n start(text?: string): void;\n succeed(text?: string): void;\n}\n\nexport function createStableSpinner(): StableSpinner {\n return new StableTextSpinner(process.stderr);\n}\n\nclass StableTextSpinner implements StableSpinner {\n private frameIndex = 0;\n private interval: NodeJS.Timeout | undefined;\n private readonly stream: NodeJS.WriteStream;\n private value = '';\n\n constructor(stream: NodeJS.WriteStream) {\n this.stream = stream;\n }\n\n get isSpinning(): boolean {\n return this.interval !== undefined;\n }\n\n get text(): string {\n return this.value;\n }\n\n set text(value: string) {\n this.value = value;\n if (this.isSpinning) {\n this.renderLine();\n }\n }\n\n start(text?: string): void {\n if (text !== undefined) {\n this.value = text;\n }\n if (!this.stream.isTTY || this.isSpinning) {\n if (!this.stream.isTTY && this.value) {\n this.stream.write(`- ${this.value}\\n`);\n }\n return;\n }\n\n this.stream.write(\n `${chalk.cyan(SPINNER_FRAMES[this.frameIndex])} ${this.value}${SAVE_CURSOR}`,\n );\n this.interval = setInterval(() => this.renderFrame(), SPINNER_INTERVAL_MS);\n }\n\n succeed(text?: string): void {\n this.persist(chalk.green('✔'), text);\n }\n\n fail(text?: string): void {\n this.persist(chalk.red('✖'), text);\n }\n\n private renderLine(): void {\n this.restoreAndClearLine();\n this.stream.write(`${chalk.cyan(SPINNER_FRAMES[this.frameIndex])} ${this.value}${SAVE_CURSOR}`);\n }\n\n private renderFrame(): void {\n this.frameIndex = (this.frameIndex + 1) % SPINNER_FRAMES.length;\n this.stream.write(\n `${RESTORE_CURSOR}\\r${chalk.cyan(SPINNER_FRAMES[this.frameIndex])}${RESTORE_CURSOR}`,\n );\n }\n\n private persist(symbol: string, text?: string): void {\n const finalText = text ?? this.value;\n this.stop();\n this.stream.write(`${symbol}${finalText ? ` ${finalText}` : ''}\\n`);\n }\n\n private stop(): boolean {\n if (!this.interval) {\n return false;\n }\n\n clearInterval(this.interval);\n this.interval = undefined;\n this.restoreAndClearLine();\n return true;\n }\n\n private restoreAndClearLine(): void {\n this.stream.write(RESTORE_CURSOR);\n cursorTo(this.stream, 0);\n clearLine(this.stream, 0);\n }\n}\n","import chalk from 'chalk';\n\n/**\n * 检查当前 Node.js 版本是否符合要求\n * 要求 Node.js 版本 >= 22.19.0\n */\nexport function checkNodeVersion() {\n const currentVersion = process.version;\n // 去掉版本号前的 'v',例如 'v22.5.1' -> '22.5.1'\n const version = currentVersion.replace(/^v/, '');\n const [major] = version.split('.').map(Number);\n\n if (major < 22) {\n console.error(chalk.red(`\\n❌ 错误:当前 Node.js 版本 (${currentVersion}) 过低!`));\n console.error(chalk.yellow('⚠️ 请升级 Node.js 版本,不低于 v22.19.0'));\n process.exit(1);\n }\n}\n"],"mappings":"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","names":["chalk","execa","fs","path","performance","fs","path","fs","path","performance","path","fs","path","performance","delay","performance","fs","path","delay","performance","fs","getErrorMessage","path","fs","randomUUID","path","performance","performance","fs","path","randomUUID","path","chalk","getErrorMessage","fs","performance","execa","chalk","require"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/commands/create.ts","../src/services/config.ts","../src/utils/pkg-manager.ts","../src/utils/template.ts","../src/utils/cache.ts","../src/utils/http.ts","../src/utils/system-proxy.ts","../src/utils/git-repository.ts","../src/utils/template-downloader.ts","../src/utils/stable-spinner.ts","../src/pre/index.ts"],"sourcesContent":["import { Command } from 'commander';\r\nimport { createRequire } from 'node:module';\r\nimport { create } from './commands/create.js';\r\nimport { checkNodeVersion } from './pre/index.js';\r\n\r\n// 1. 前置检查:Node.js 版本\r\ncheckNodeVersion();\r\n\r\nconst program = new Command();\r\nconst require = createRequire(import.meta.url);\r\nconst packageMetadata: unknown = require('../package.json');\r\nconst packageVersion = getPackageVersion(packageMetadata);\r\n\r\nprogram\r\n .name('gz-cli')\r\n .description('前端脚手架工具')\r\n .version(packageVersion);\r\n\r\n// 将 init 设为默认命令,参数改为可选 [project-name]\r\nprogram\r\n .command('init [project-name]', { isDefault: true })\r\n .description('创建一个新项目')\r\n .option('--pm <package-manager>', '指定包管理器:npm、pnpm 或 yarn')\r\n .option('--proxy <url>', '指定本次初始化使用的 HTTP(S) 代理')\r\n .option('--no-proxy', '强制直连,不读取环境变量或系统代理')\r\n .option('--refresh', '忽略模板配置和模板缓存,强制从远程仓库刷新')\r\n .action((projectName, options) => {\r\n void create(projectName, options);\r\n });\r\n\r\nprogram\r\n .command('create [project-name]')\r\n .description('创建一个新项目(兼容旧命令)')\r\n .option('--pm <package-manager>', '指定包管理器:npm、pnpm 或 yarn')\r\n .option('--proxy <url>', '指定本次初始化使用的 HTTP(S) 代理')\r\n .option('--no-proxy', '强制直连,不读取环境变量或系统代理')\r\n .option('--refresh', '忽略模板配置和模板缓存,强制从远程仓库刷新')\r\n .action((projectName, options) => {\r\n void create(projectName, options);\r\n });\r\n\r\nprogram.parse(process.argv);\r\n\r\nfunction getPackageVersion(value: unknown): string {\r\n if (typeof value !== 'object' || value === null) {\r\n throw new Error('无法读取 gz-cli-front 版本号。');\r\n }\r\n\r\n const version = (value as Record<string, unknown>).version;\r\n if (typeof version !== 'string' || !version.trim()) {\r\n throw new Error('gz-cli-front package.json 中缺少有效版本号。');\r\n }\r\n return version;\r\n}\r\n","import { confirm, input, select } from '@inquirer/prompts';\r\nimport chalk from 'chalk';\r\nimport { execa } from 'execa';\r\nimport fs from 'fs-extra';\r\nimport ora from 'ora';\r\nimport path from 'path';\r\nimport { performance } from 'node:perf_hooks';\r\nimport { loadCliConfig } from '../services/config.js';\r\nimport {\r\n detectPackageManager,\r\n isPackageManager,\r\n updateProjectPackageJson,\r\n type PackageManager,\r\n} from '../utils/pkg-manager.js';\r\nimport {\r\n fetchTemplates,\r\n replaceTemplateVariables,\r\n type FetchTemplatesResult,\r\n type TemplateMeta,\r\n} from '../utils/template.js';\r\nimport { downloadTemplate, type TemplateDownloadTiming } from '../utils/template-downloader.js';\r\nimport { configureNetwork, type NetworkRoute } from '../utils/http.js';\r\nimport { createStableSpinner } from '../utils/stable-spinner.js';\r\n\r\nexport interface InitOptions {\r\n pm?: string;\r\n proxy?: string | false;\r\n refresh?: boolean;\r\n}\r\n\r\ninterface InitContext {\r\n projectName: string;\r\n template: TemplateMeta;\r\n packageManager: PackageManager;\r\n}\r\n\r\ninterface TemplateTiming {\r\n configRoute: NetworkRoute | 'ssh' | 'cache' | 'stale-cache';\r\n copyMs: number;\r\n fetchConfigMs: number;\r\n parseConfigMs: number;\r\n templateRoute: NetworkRoute | 'ssh' | 'cache' | 'stale-cache' | 'git';\r\n downloadMs: number;\r\n extractMs: number;\r\n renderMs: number;\r\n}\r\n\r\nexport async function create(projectName?: string, options: InitOptions = {}): Promise<void> {\r\n try {\r\n configureNetwork({\r\n forceDirect: options.proxy === false,\r\n proxy: typeof options.proxy === 'string' ? options.proxy : undefined,\r\n });\r\n const templateTiming = createTemplateTiming();\r\n const context = await createInitContext(projectName, options, templateTiming);\r\n const targetPath = path.resolve(process.cwd(), context.projectName);\r\n\r\n if (!(await prepareTargetDirectory(targetPath, context.projectName))) {\r\n return;\r\n }\r\n\r\n const install = await confirm({\r\n message: '是否自动安装依赖?',\r\n default: true,\r\n });\r\n\r\n await downloadAndGenerate(context, targetPath, templateTiming, options);\r\n await installDependencies(install, targetPath, context.packageManager);\r\n await initializeGit(targetPath);\r\n printNextSteps(context, install);\r\n } catch (error: unknown) {\r\n if (isUserCancellation(error)) {\r\n console.log(chalk.yellow('\\n已取消操作。'));\r\n return;\r\n }\r\n\r\n console.error(chalk.red(`创建项目失败:${getErrorMessage(error)}`));\r\n }\r\n}\r\n\r\nasync function createInitContext(\r\n projectName: string | undefined,\r\n options: InitOptions,\r\n templateTiming: TemplateTiming,\r\n): Promise<InitContext> {\r\n const finalProjectName = await getProjectName(projectName);\r\n const templates = await loadTemplates(templateTiming, options);\r\n const template = await chooseTemplate(templates);\r\n\r\n return {\r\n projectName: finalProjectName,\r\n template,\r\n packageManager: resolvePackageManager(options.pm),\r\n };\r\n}\r\n\r\nasync function getProjectName(projectName?: string): Promise<string> {\r\n if (projectName?.trim()) {\r\n return projectName.trim();\r\n }\r\n\r\n return input({\r\n message: '请输入项目名称:',\r\n validate: (value) => value.trim() ? true : '项目名称不能为空',\r\n });\r\n}\r\n\r\nasync function loadTemplates(\r\n templateTiming: TemplateTiming,\r\n options: InitOptions,\r\n): Promise<TemplateMeta[]> {\r\n const spinner = createStableSpinner();\r\n try {\r\n const config = await loadCliConfig();\r\n spinner.start('正在获取远程模板配置...');\r\n const result = await fetchTemplates(config.templateRegistry, {\r\n forceRefresh: options.refresh === true,\r\n });\r\n assignFetchTiming(templateTiming, result);\r\n spinner.succeed('远程模板配置获取成功');\r\n if (result.staleCache) {\r\n console.log(chalk.yellow('远程模板配置暂时不可用,已使用本地缓存。'));\r\n }\r\n return result.templates;\r\n } catch (error: unknown) {\r\n if (spinner.isSpinning) {\r\n spinner.fail('获取远程模板配置失败');\r\n } else {\r\n console.error(chalk.red('获取远程模板配置失败'));\r\n }\r\n const message = error instanceof Error && error.message\r\n ? error.message\r\n : '未知错误';\r\n throw new Error(`获取远程模板配置失败,请检查网络或模板配置地址。\\n${message}`);\r\n }\r\n}\r\n\r\nasync function chooseTemplate(templates: TemplateMeta[]): Promise<TemplateMeta> {\r\n return select({\r\n message: '请选择项目模板:',\r\n choices: templates.map((template) => ({\r\n name: `${template.label} (${template.name}) - ${template.description}`,\r\n value: template,\r\n })),\r\n default: templates.find((template) => template.type === 'micro') ?? templates[0],\r\n });\r\n}\r\n\r\nfunction resolvePackageManager(requestedPackageManager?: string): PackageManager {\r\n if (requestedPackageManager !== undefined) {\r\n if (!isPackageManager(requestedPackageManager)) {\r\n throw new Error(\r\n `不支持的 packageManager: ${requestedPackageManager}\\n支持: npm、pnpm、yarn`,\r\n );\r\n }\r\n return requestedPackageManager;\r\n }\r\n\r\n const packageManager = detectPackageManager();\r\n if (packageManager === 'npm') {\r\n console.log(chalk.yellow('未检测到 pnpm 或 yarn,自动使用 npm。'));\r\n }\r\n return packageManager;\r\n}\r\n\r\nasync function prepareTargetDirectory(targetPath: string, projectName: string): Promise<boolean> {\r\n if (!(await fs.pathExists(targetPath))) {\r\n return true;\r\n }\r\n\r\n const overwrite = await confirm({\r\n message: `目录 ${projectName} 已存在,是否覆盖?`,\r\n default: false,\r\n });\r\n\r\n if (!overwrite) {\r\n console.log(chalk.yellow('已取消创建。'));\r\n return false;\r\n }\r\n\r\n await fs.remove(targetPath);\r\n return true;\r\n}\r\n\r\nasync function downloadAndGenerate(\r\n context: InitContext,\r\n targetPath: string,\r\n templateTiming: TemplateTiming,\r\n options: InitOptions,\r\n): Promise<void> {\r\n const { template, projectName, packageManager } = context;\r\n const spinner = createStableSpinner();\r\n const downloadStartedAt = performance.now();\r\n try {\r\n spinner.start(`正在下载模板 ${template.label}...`);\r\n const downloadTiming = await downloadTemplate(template, targetPath, {\r\n forceRefresh: options.refresh === true,\r\n });\r\n assignDownloadTiming(templateTiming, downloadTiming);\r\n } catch (error: unknown) {\r\n templateTiming.downloadMs = Math.round(performance.now() - downloadStartedAt);\r\n await fs.remove(targetPath);\r\n if (spinner.isSpinning) {\r\n spinner.fail('模板下载失败');\r\n } else {\r\n console.error(chalk.red('模板下载失败'));\r\n }\r\n printTemplateTiming(templateTiming);\r\n const message = error instanceof Error && error.message\r\n ? error.message\r\n : '未知错误';\r\n throw new Error(`模板下载失败,请检查仓库地址或网络连接。\\n${message}`);\r\n }\r\n\r\n try {\r\n spinner.text = '正在替换模板变量...';\r\n const startedAt = performance.now();\r\n await replaceTemplateVariables(targetPath, { projectName });\r\n await updateProjectPackageJson(targetPath, projectName, packageManager);\r\n templateTiming.renderMs = Math.round(performance.now() - startedAt);\r\n spinner.succeed('模板下载并生成完成');\r\n printTemplateTiming(templateTiming);\r\n } catch {\r\n await fs.remove(targetPath);\r\n spinner.fail('模板下载或变量替换失败');\r\n throw new Error('模板变量替换失败,请检查模板文件内容。');\r\n }\r\n}\r\n\r\nfunction createTemplateTiming(): TemplateTiming {\r\n return {\r\n configRoute: 'direct',\r\n copyMs: 0,\r\n fetchConfigMs: 0,\r\n parseConfigMs: 0,\r\n templateRoute: 'direct',\r\n downloadMs: 0,\r\n extractMs: 0,\r\n renderMs: 0,\r\n };\r\n}\r\n\r\nfunction assignFetchTiming(\r\n templateTiming: TemplateTiming,\r\n result: FetchTemplatesResult,\r\n): void {\r\n templateTiming.fetchConfigMs = result.fetchMs;\r\n templateTiming.parseConfigMs = result.parseMs;\r\n templateTiming.configRoute = result.route;\r\n}\r\n\r\nfunction assignDownloadTiming(\r\n templateTiming: TemplateTiming,\r\n downloadTiming: TemplateDownloadTiming,\r\n): void {\r\n templateTiming.copyMs = downloadTiming.copyMs;\r\n templateTiming.downloadMs = downloadTiming.downloadMs;\r\n templateTiming.extractMs = downloadTiming.extractMs;\r\n templateTiming.templateRoute = downloadTiming.route;\r\n}\r\n\r\nfunction printTemplateTiming(templateTiming: TemplateTiming): void {\r\n console.log('\\n[template]');\r\n console.log(`fetch config: ${templateTiming.fetchConfigMs} ms (${formatRoute(templateTiming.configRoute)})`);\r\n console.log(`parse config: ${templateTiming.parseConfigMs} ms`);\r\n console.log(`download: ${templateTiming.downloadMs} ms (${formatRoute(templateTiming.templateRoute)})`);\r\n console.log(`extract: ${templateTiming.extractMs} ms`);\r\n console.log(`copy: ${templateTiming.copyMs} ms`);\r\n console.log(`render: ${templateTiming.renderMs} ms`);\r\n}\r\n\r\nfunction formatRoute(route: TemplateTiming['configRoute'] | TemplateTiming['templateRoute']): string {\r\n if (route === 'proxy-environment') {\r\n return 'remote, 环境变量代理';\r\n }\r\n if (route === 'proxy-system') {\r\n return 'remote, 系统代理';\r\n }\r\n if (route === 'direct') {\r\n return 'remote, 直连';\r\n }\r\n if (route === 'ssh') {\r\n return 'remote, Git/SSH';\r\n }\r\n return route.replace('-', ' ');\r\n}\r\n\r\nasync function installDependencies(\r\n install: boolean,\r\n targetPath: string,\r\n packageManager: PackageManager,\r\n): Promise<void> {\r\n if (!install) {\r\n return;\r\n }\r\n\r\n const installCommand = packageManager === 'yarn' ? [] : ['install'];\r\n const spinner = ora(`正在安装依赖 (${packageManager} ${installCommand.join(' ')})...`).start();\r\n try {\r\n await execa(packageManager, installCommand, { cwd: targetPath });\r\n spinner.succeed('依赖安装成功');\r\n } catch {\r\n spinner.warn('依赖安装失败,请进入项目目录后手动安装');\r\n }\r\n}\r\n\r\nasync function initializeGit(targetPath: string): Promise<void> {\r\n const spinner = ora('正在初始化 Git 仓库...').start();\r\n try {\r\n await execa('git', ['init'], { cwd: targetPath });\r\n spinner.succeed('Git 仓库初始化成功');\r\n } catch {\r\n spinner.warn('Git 仓库初始化失败,请确认 Git 已安装');\r\n }\r\n}\r\n\r\nfunction printNextSteps(context: InitContext, installed: boolean): void {\r\n const { projectName, packageManager } = context;\r\n const installCommand = packageManager === 'yarn' ? 'yarn' : `${packageManager} install`;\r\n const devCommand = packageManager === 'npm' ? 'npm run dev' : `${packageManager} dev`;\r\n\r\n console.log(chalk.green(`\\n项目 ${projectName} 创建成功!`));\r\n console.log('\\n接下来你可以:\\n');\r\n console.log(chalk.cyan(` cd ${projectName}`));\r\n if (!installed) {\r\n console.log(chalk.cyan(` ${installCommand}`));\r\n }\r\n console.log(chalk.cyan(` ${devCommand}`));\r\n}\r\n\r\nfunction isUserCancellation(error: unknown): boolean {\r\n return error instanceof Error && /User force closed|User cancelled/i.test(error.message);\r\n}\r\n\r\nfunction getErrorMessage(error: unknown): string {\r\n return error instanceof Error && error.message ? ` ${error.message}` : '';\r\n}\r\n","import fs from 'fs-extra';\r\nimport path from 'path';\r\nimport { fileURLToPath } from 'url';\r\nimport type { CliConfig } from '../types/config.js';\r\n\r\nconst CONFIG_FILE_NAME = 'gz-cli-front.config.json';\r\n\r\nexport async function loadCliConfig(): Promise<CliConfig> {\r\n const configPath = await findConfigPath();\r\n const config: unknown = await fs.readJson(configPath);\r\n\r\n if (!isCliConfig(config)) {\r\n throw new Error(`CLI 配置文件无效:${configPath}`);\r\n }\r\n\r\n return config;\r\n}\r\n\r\nasync function findConfigPath(): Promise<string> {\r\n const moduleDirectory = path.dirname(fileURLToPath(import.meta.url));\r\n const configPaths = [\r\n path.resolve(moduleDirectory, 'config', CONFIG_FILE_NAME),\r\n path.resolve(moduleDirectory, '..', 'config', CONFIG_FILE_NAME),\r\n path.resolve(moduleDirectory, '..', '..', 'config', CONFIG_FILE_NAME),\r\n ];\r\n\r\n for (const configPath of configPaths) {\r\n if (await fs.pathExists(configPath)) {\r\n return configPath;\r\n }\r\n }\r\n\r\n throw new Error('未找到 gz-cli-front 配置文件。');\r\n}\r\n\r\nfunction isCliConfig(value: unknown): value is CliConfig {\r\n if (typeof value !== 'object' || value === null) {\r\n return false;\r\n }\r\n\r\n const templateRegistry = (value as Record<string, unknown>).templateRegistry;\r\n if (typeof templateRegistry !== 'object' || templateRegistry === null) {\r\n return false;\r\n }\r\n\r\n return isTemplateRegistryConfig(templateRegistry as Record<string, unknown>);\r\n}\r\n\r\nfunction isTemplateRegistryConfig(value: Record<string, unknown>): boolean {\r\n if (!isNonEmptyString(value.url)) {\r\n return false;\r\n }\r\n\r\n if (value.source === undefined || value.source === 'http') {\r\n return true;\r\n }\r\n\r\n return value.source === 'git'\r\n && isNonEmptyString(value.file)\r\n && (value.version === undefined || isNonEmptyString(value.version));\r\n}\r\n\r\nfunction isNonEmptyString(value: unknown): value is string {\r\n return typeof value === 'string' && value.trim().length > 0;\r\n}\r\n","import fs from 'fs-extra';\r\nimport path from 'path';\r\nimport { spawnSync } from 'node:child_process';\r\n\r\nexport type PackageManager = 'npm' | 'pnpm' | 'yarn';\r\n\r\nconst PACKAGE_MANAGERS: readonly PackageManager[] = ['pnpm', 'yarn', 'npm'];\r\n\r\nexport function detectPackageManager(): PackageManager {\r\n return PACKAGE_MANAGERS.find(isPackageManagerAvailable) ?? 'npm';\r\n}\r\n\r\nexport function isPackageManager(value: string): value is PackageManager {\r\n return PACKAGE_MANAGERS.includes(value as PackageManager);\r\n}\r\n\r\nexport async function updateProjectPackageJson(\r\n targetDir: string,\r\n projectName: string,\r\n packageManager: PackageManager,\r\n): Promise<void> {\r\n const packageJsonPath = path.join(targetDir, 'package.json');\r\n if (!(await fs.pathExists(packageJsonPath))) {\r\n return;\r\n }\r\n\r\n const packageJson: Record<string, unknown> = await fs.readJson(packageJsonPath);\r\n packageJson.name = projectName;\r\n\r\n if (Object.prototype.hasOwnProperty.call(packageJson, 'packageManager')) {\r\n packageJson.packageManager = packageManager;\r\n }\r\n\r\n await fs.writeJson(packageJsonPath, packageJson, { spaces: 2 });\r\n}\r\n\r\nfunction isPackageManagerAvailable(packageManager: PackageManager): boolean {\r\n const result = spawnSync(packageManager, ['--version'], {\r\n shell: process.platform === 'win32',\r\n stdio: 'ignore',\r\n });\r\n\r\n return result.status === 0;\r\n}\r\n","import fs from 'fs-extra';\r\nimport path from 'path';\r\nimport { performance } from 'node:perf_hooks';\r\nimport type { TemplateRegistryConfig } from '../types/config.js';\r\nimport type { TemplateMeta, TemplateSource, TemplateType } from '../types/template.js';\r\nimport {\r\n getTemplateRegistryCachePath,\r\n isCacheFresh,\r\n TEMPLATE_REGISTRY_CACHE_TTL_MS,\r\n} from './cache.js';\r\nimport { requestBuffer, type NetworkRoute } from './http.js';\r\nimport { ensureGitRepository } from './git-repository.js';\r\n\r\nconst TEXT_FILE_EXTENSIONS = new Set([\r\n '.json', '.ts', '.tsx', '.js', '.jsx', '.md', '.html', '.css', '.less', '.scss', '.env',\r\n]);\r\nconst IGNORED_DIRECTORIES = new Set(['node_modules', 'dist', '.git']);\r\nconst TEMPLATE_DEBUG_ENV = 'GZ_CLI_FRONT_DEBUG';\r\nconst TEMPLATE_REGISTRY_TIMEOUT_MS = 5_000;\r\n\r\ninterface TemplateRegistryCache {\r\n body: string;\r\n fetchedAt: number;\r\n url: string;\r\n}\r\n\r\nexport interface FetchTemplatesOptions {\r\n forceRefresh?: boolean;\r\n}\r\n\r\nexport interface FetchTemplatesResult {\r\n cacheHit: boolean;\r\n fetchMs: number;\r\n parseMs: number;\r\n route: NetworkRoute | 'ssh' | 'cache' | 'stale-cache';\r\n staleCache: boolean;\r\n templates: TemplateMeta[];\r\n}\r\n\r\nexport type { TemplateMeta, TemplateSource, TemplateType } from '../types/template.js';\r\n\r\nexport async function fetchTemplates(\r\n templateRegistry: TemplateRegistryConfig | string,\r\n options: FetchTemplatesOptions = {},\r\n): Promise<FetchTemplatesResult> {\r\n const registry = typeof templateRegistry === 'string'\r\n ? { url: templateRegistry } satisfies TemplateRegistryConfig\r\n : templateRegistry;\r\n\r\n if (registry.source === 'git') {\r\n return fetchTemplatesFromGit(registry, options);\r\n }\r\n\r\n return fetchTemplatesFromHttp(registry.url, options);\r\n}\r\n\r\nasync function fetchTemplatesFromHttp(\r\n templateRegistryUrl: string,\r\n options: FetchTemplatesOptions,\r\n): Promise<FetchTemplatesResult> {\r\n const cachePath = getTemplateRegistryCachePath(templateRegistryUrl);\r\n const cacheStartedAt = performance.now();\r\n let cached = await readRegistryCache(cachePath, templateRegistryUrl);\r\n const cacheReadMs = Math.round(performance.now() - cacheStartedAt);\r\n debugTemplateRequest(templateRegistryUrl, cachePath, options.forceRefresh === true);\r\n\r\n if (!options.forceRefresh && cached\r\n && isCacheFresh(cached.fetchedAt, TEMPLATE_REGISTRY_CACHE_TTL_MS)) {\r\n try {\r\n return parseTemplates(cached.body, true, false, cacheReadMs, 'cache');\r\n } catch {\r\n await fs.remove(cachePath);\r\n cached = undefined;\r\n }\r\n }\r\n\r\n const fetchStartedAt = performance.now();\r\n try {\r\n const response = await requestBuffer(templateRegistryUrl, {\r\n retries: 1,\r\n timeoutMs: TEMPLATE_REGISTRY_TIMEOUT_MS,\r\n });\r\n const body = response.body.toString('utf8');\r\n const result = parseTemplates(body, false, false, response.elapsedMs, response.route);\r\n try {\r\n await writeRegistryCache(cachePath, {\r\n body,\r\n fetchedAt: Date.now(),\r\n url: templateRegistryUrl,\r\n });\r\n } catch (error: unknown) {\r\n if (process.env[TEMPLATE_DEBUG_ENV] === '1') {\r\n console.log(`template config cache write failed: ${getErrorMessage(error)}`);\r\n }\r\n }\r\n return result;\r\n } catch (error: unknown) {\r\n if (!options.forceRefresh && cached) {\r\n return parseTemplates(\r\n cached.body,\r\n true,\r\n true,\r\n Math.round(performance.now() - fetchStartedAt),\r\n 'stale-cache',\r\n );\r\n }\r\n throw createTemplateRequestError(templateRegistryUrl, error);\r\n }\r\n}\r\n\r\nasync function fetchTemplatesFromGit(\r\n registry: Extract<TemplateRegistryConfig, { source: 'git' }>,\r\n options: FetchTemplatesOptions,\r\n): Promise<FetchTemplatesResult> {\r\n const cacheKey = `git:${registry.url}#${registry.version ?? 'latest'}:${registry.file}`;\r\n const fallbackCachePath = getTemplateRegistryCachePath(cacheKey);\r\n const fallbackCache = await readRegistryCache(fallbackCachePath, cacheKey);\r\n const startedAt = performance.now();\r\n\r\n try {\r\n const result = await ensureGitRepository(registry.url, {\r\n forceRefresh: options.forceRefresh,\r\n namespace: 'registry',\r\n ttlMs: TEMPLATE_REGISTRY_CACHE_TTL_MS,\r\n version: registry.version,\r\n });\r\n const registryFile = resolveRegistryFile(result.path, registry.file);\r\n const body = await fs.readFile(registryFile, 'utf8');\r\n const parsed = parseTemplates(\r\n body,\r\n result.cacheHit,\r\n result.staleCache,\r\n result.elapsedMs,\r\n result.route,\r\n );\r\n if (!result.cacheHit || !fallbackCache) {\r\n await writeRegistryCache(fallbackCachePath, {\r\n body,\r\n fetchedAt: Date.now(),\r\n url: cacheKey,\r\n }).catch(() => undefined);\r\n }\r\n return parsed;\r\n } catch (error: unknown) {\r\n if (!options.forceRefresh && fallbackCache) {\r\n return parseTemplates(\r\n fallbackCache.body,\r\n true,\r\n true,\r\n Math.round(performance.now() - startedAt),\r\n 'stale-cache',\r\n );\r\n }\r\n throw new Error(`模板注册仓库读取失败\\nerror: ${getErrorMessage(error)}`);\r\n }\r\n}\r\n\r\nfunction resolveRegistryFile(repositoryPath: string, registryFile: string): string {\r\n const resolvedRepository = path.resolve(repositoryPath);\r\n const resolvedFile = path.resolve(repositoryPath, registryFile);\r\n if (resolvedFile !== resolvedRepository\r\n && !resolvedFile.startsWith(`${resolvedRepository}${path.sep}`)) {\r\n throw new Error(`模板注册文件必须位于注册仓库内:${registryFile}`);\r\n }\r\n return resolvedFile;\r\n}\r\n\r\nfunction parseTemplates(\r\n body: string,\r\n cacheHit: boolean,\r\n staleCache: boolean,\r\n fetchMs: number,\r\n route: FetchTemplatesResult['route'],\r\n): FetchTemplatesResult {\r\n const parseStartedAt = performance.now();\r\n let data: unknown;\r\n\r\n try {\r\n data = JSON.parse(body);\r\n } catch (error: unknown) {\r\n throw new Error(`模板配置 JSON 解析失败:${getErrorMessage(error)}`);\r\n }\r\n if (!Array.isArray(data) || data.length === 0) {\r\n throw new Error('模板注册表为空');\r\n }\r\n\r\n const templates = data.filter(isTemplateMeta);\r\n if (templates.length === 0) {\r\n throw new Error('模板注册表中没有有效模板');\r\n }\r\n\r\n return {\r\n cacheHit,\r\n fetchMs,\r\n parseMs: Math.round(performance.now() - parseStartedAt),\r\n route,\r\n staleCache,\r\n templates,\r\n };\r\n}\r\n\r\nfunction debugTemplateRequest(\r\n templateRegistryUrl: string,\r\n cachePath: string,\r\n forceRefresh: boolean,\r\n): void {\r\n if (process.env[TEMPLATE_DEBUG_ENV] !== '1') {\r\n return;\r\n }\r\n\r\n console.log('template config url:', templateRegistryUrl);\r\n console.log('template config client: undici fetch');\r\n console.log(`template config timeout: ${TEMPLATE_REGISTRY_TIMEOUT_MS} ms`);\r\n console.log('template config cache:', cachePath);\r\n console.log('template config force refresh:', forceRefresh);\r\n}\r\n\r\nfunction createTemplateRequestError(templateRegistryUrl: string, error: unknown): Error {\r\n return new Error(\r\n `模板配置请求失败\\nurl: ${templateRegistryUrl}\\nerror: ${getErrorMessage(error)}`,\r\n );\r\n}\r\n\r\nfunction getErrorMessage(error: unknown): string {\r\n if (!(error instanceof Error)) {\r\n return '未知错误';\r\n }\r\n\r\n const cause = 'cause' in error ? error.cause : undefined;\r\n const causeMessage = cause instanceof Error ? cause.message : String(cause ?? '');\r\n return causeMessage ? `${error.message} (${causeMessage})` : error.message;\r\n}\r\n\r\nasync function readRegistryCache(\r\n cachePath: string,\r\n templateRegistryUrl: string,\r\n): Promise<TemplateRegistryCache | undefined> {\r\n try {\r\n const cache: unknown = await fs.readJson(cachePath);\r\n if (!isRecord(cache)\r\n || cache.url !== templateRegistryUrl\r\n || typeof cache.body !== 'string'\r\n || typeof cache.fetchedAt !== 'number') {\r\n return undefined;\r\n }\r\n return {\r\n body: cache.body,\r\n fetchedAt: cache.fetchedAt,\r\n url: cache.url,\r\n };\r\n } catch {\r\n return undefined;\r\n }\r\n}\r\n\r\nasync function writeRegistryCache(\r\n cachePath: string,\r\n cache: TemplateRegistryCache,\r\n): Promise<void> {\r\n await fs.ensureDir(path.dirname(cachePath));\r\n await fs.writeJson(cachePath, cache);\r\n}\r\n\r\nexport async function replaceTemplateVariables(\r\n targetDir: string,\r\n variables: Readonly<Record<string, string>>,\r\n): Promise<void> {\r\n await visitDirectory(targetDir, async (filePath) => {\r\n if (!shouldProcessFile(filePath)) {\r\n return;\r\n }\r\n\r\n const content = await fs.readFile(filePath, 'utf8');\r\n const replaced = Object.entries(variables).reduce(\r\n (result, [key, value]) => result.split(`{{ ${key} }}`).join(value),\r\n content,\r\n );\r\n\r\n if (replaced !== content) {\r\n await fs.writeFile(filePath, replaced, 'utf8');\r\n }\r\n });\r\n}\r\n\r\nasync function visitDirectory(\r\n directory: string,\r\n onFile: (filePath: string) => Promise<void>,\r\n): Promise<void> {\r\n const entries = await fs.readdir(directory, { withFileTypes: true });\r\n for (const entry of entries) {\r\n const entryPath = path.join(directory, entry.name);\r\n if (entry.isDirectory()) {\r\n if (!IGNORED_DIRECTORIES.has(entry.name)) {\r\n await visitDirectory(entryPath, onFile);\r\n }\r\n } else if (entry.isFile()) {\r\n await onFile(entryPath);\r\n }\r\n }\r\n}\r\n\r\nfunction shouldProcessFile(filePath: string): boolean {\r\n const filename = path.basename(filePath);\r\n return TEXT_FILE_EXTENSIONS.has(path.extname(filename)) || filename.startsWith('.env');\r\n}\r\n\r\nfunction isTemplateMeta(value: unknown): value is TemplateMeta {\r\n if (!isRecord(value)) {\r\n return false;\r\n }\r\n\r\n return isString(value.name)\r\n && isString(value.label)\r\n && isString(value.description)\r\n && isTemplateType(value.type)\r\n && isTemplateLocation(value)\r\n && (value.version === undefined || isString(value.version));\r\n}\r\n\r\nfunction isRecord(value: unknown): value is Record<string, unknown> {\r\n return typeof value === 'object' && value !== null;\r\n}\r\n\r\nfunction isString(value: unknown): value is string {\r\n return typeof value === 'string' && value.trim().length > 0;\r\n}\r\n\r\nfunction isTemplateType(value: unknown): value is TemplateType {\r\n return value === 'main' || value === 'micro';\r\n}\r\n\r\nfunction isTemplateLocation(value: Record<string, unknown>): boolean {\r\n if (value.source !== undefined && !isTemplateSource(value.source)) {\r\n return false;\r\n }\r\n\r\n if (isString(value.url)) {\r\n return true;\r\n }\r\n\r\n return value.source === undefined && isString(value.repo);\r\n}\r\n\r\nfunction isTemplateSource(value: unknown): value is TemplateSource {\r\n return value === 'github' || value === 'gitlab' || value === 'git';\r\n}\r\n","import { createHash } from 'node:crypto';\r\nimport os from 'node:os';\r\nimport path from 'node:path';\r\n\r\nexport const TEMPLATE_REGISTRY_CACHE_TTL_MS = 5 * 60 * 1000;\r\nexport const TEMPLATE_ARCHIVE_CACHE_TTL_MS = 10 * 60 * 1000;\r\n\r\nexport function getTemplateRegistryCachePath(url: string): string {\r\n return path.join(getCacheDirectory(), 'registry', `${createCacheKey(url)}.json`);\r\n}\r\n\r\nexport function getTemplateArchiveCachePath(source: string): string {\r\n return path.join(getCacheDirectory(), 'templates', `${createCacheKey(source)}.tar.gz`);\r\n}\r\n\r\nexport function getGitRepositoryCachePath(\r\n namespace: 'registry' | 'templates',\r\n source: string,\r\n): string {\r\n return path.join(getCacheDirectory(), namespace, `git-${createCacheKey(source)}`);\r\n}\r\n\r\nexport function isCacheFresh(updatedAt: number, ttlMs: number): boolean {\r\n return Date.now() - updatedAt < ttlMs;\r\n}\r\n\r\nfunction getCacheDirectory(): string {\r\n const configuredDirectory = process.env.GZ_CLI_FRONT_CACHE_DIR?.trim();\r\n return configuredDirectory || path.join(os.homedir(), '.gz-cli-front', 'cache');\r\n}\r\n\r\nfunction createCacheKey(value: string): string {\r\n return createHash('sha256').update(value).digest('hex').slice(0, 24);\r\n}\r\n","import { setTimeout as delay } from 'node:timers/promises';\r\nimport {\r\n EnvHttpProxyAgent,\r\n ProxyAgent,\r\n fetch as undiciFetch,\r\n type Dispatcher,\r\n} from 'undici';\r\nimport { getSystemProxy } from './system-proxy.js';\r\n\r\nexport interface NetworkOptions {\r\n forceDirect?: boolean;\r\n proxy?: string;\r\n}\r\n\r\nexport interface HttpRequestOptions {\r\n headers?: Readonly<Record<string, string>>;\r\n retries: number;\r\n timeoutMs: number;\r\n}\r\n\r\nexport interface HttpResponseData {\r\n body: Buffer;\r\n elapsedMs: number;\r\n route: NetworkRoute;\r\n status: number;\r\n}\r\n\r\nexport type NetworkRoute = 'direct' | 'proxy-environment' | 'proxy-system';\r\n\r\nlet networkOptions: NetworkOptions = {};\r\n\r\nexport function configureNetwork(options: NetworkOptions): void {\r\n if (options.proxy) {\r\n validateProxyUrl(options.proxy);\r\n }\r\n networkOptions = { ...options };\r\n}\r\n\r\nexport async function requestBuffer(\r\n url: string,\r\n options: HttpRequestOptions,\r\n): Promise<HttpResponseData> {\r\n const startedAt = performance.now();\r\n let lastError: unknown;\r\n const proxyConfig = await resolveProxyConfig(url);\r\n\r\n for (let attempt = 0; attempt <= options.retries; attempt += 1) {\r\n const controller = new AbortController();\r\n const timeout = setTimeout(() => controller.abort(), options.timeoutMs);\r\n const dispatcher = proxyConfig.createDispatcher?.();\r\n\r\n debugNetworkRoute(url, proxyConfig.route, attempt + 1, options.retries + 1);\r\n\r\n try {\r\n const response = await undiciFetch(url, {\r\n ...(dispatcher ? { dispatcher } : {}),\r\n headers: options.headers,\r\n redirect: 'follow',\r\n signal: controller.signal,\r\n });\r\n\r\n if (!response.ok) {\r\n throw new Error(`HTTP ${response.status} ${response.statusText}`);\r\n }\r\n\r\n return {\r\n body: Buffer.from(await response.arrayBuffer()),\r\n elapsedMs: Math.round(performance.now() - startedAt),\r\n route: proxyConfig.route,\r\n status: response.status,\r\n };\r\n } catch (error: unknown) {\r\n lastError = error;\r\n if (attempt < options.retries) {\r\n await delay(250 * (attempt + 1));\r\n }\r\n } finally {\r\n clearTimeout(timeout);\r\n await dispatcher?.destroy();\r\n }\r\n }\r\n\r\n throw createRequestError(url, options, proxyConfig.route, lastError);\r\n}\r\n\r\ninterface ResolvedProxyConfig {\r\n createDispatcher?: () => Dispatcher;\r\n proxyUrl?: string;\r\n route: NetworkRoute;\r\n}\r\n\r\nasync function resolveProxyConfig(url: string): Promise<ResolvedProxyConfig> {\r\n const target = new URL(url);\r\n\r\n if (networkOptions.forceDirect) {\r\n return { route: 'direct' };\r\n }\r\n\r\n if (networkOptions.proxy) {\r\n const proxyUrl = networkOptions.proxy;\r\n return {\r\n createDispatcher: () => new ProxyAgent({ uri: proxyUrl }),\r\n proxyUrl,\r\n route: 'proxy-environment',\r\n };\r\n }\r\n\r\n const httpProxy = readEnvironmentVariable('http_proxy', 'HTTP_PROXY');\r\n const httpsProxy = readEnvironmentVariable('https_proxy', 'HTTPS_PROXY');\r\n const noProxy = readEnvironmentVariable('no_proxy', 'NO_PROXY');\r\n const environmentProxy = target.protocol === 'https:'\r\n ? httpsProxy ?? httpProxy\r\n : httpProxy;\r\n\r\n if (noProxy && shouldBypassProxy(target, noProxy)) {\r\n return { route: 'direct' };\r\n }\r\n\r\n if (environmentProxy) {\r\n return {\r\n createDispatcher: () => new EnvHttpProxyAgent({\r\n httpProxy,\r\n httpsProxy,\r\n noProxy,\r\n }),\r\n proxyUrl: environmentProxy,\r\n route: 'proxy-environment',\r\n };\r\n }\r\n\r\n const systemProxy = await getSystemProxy(target);\r\n if (systemProxy.noProxy && shouldBypassProxy(target, systemProxy.noProxy)) {\r\n return { route: 'direct' };\r\n }\r\n if (systemProxy.proxyUrl) {\r\n return {\r\n createDispatcher: () => new ProxyAgent({ uri: systemProxy.proxyUrl! }),\r\n proxyUrl: systemProxy.proxyUrl,\r\n route: 'proxy-system',\r\n };\r\n }\r\n\r\n return { route: 'direct' };\r\n}\r\n\r\nexport interface GitNetworkConfig {\r\n args: string[];\r\n route: NetworkRoute | 'ssh';\r\n}\r\n\r\nexport async function resolveGitNetworkConfig(repositoryUrl: string): Promise<GitNetworkConfig> {\r\n if (!/^https?:\\/\\//i.test(repositoryUrl)) {\r\n return { args: [], route: 'ssh' };\r\n }\r\n\r\n const proxyConfig = await resolveProxyConfig(repositoryUrl);\r\n if (proxyConfig.proxyUrl) {\r\n return {\r\n args: ['-c', `http.proxy=${proxyConfig.proxyUrl}`],\r\n route: proxyConfig.route,\r\n };\r\n }\r\n\r\n return {\r\n args: networkOptions.forceDirect ? ['-c', 'http.proxy='] : [],\r\n route: 'direct',\r\n };\r\n}\r\n\r\nfunction readEnvironmentVariable(primaryName: string, fallbackName: string): string | undefined {\r\n const value = process.env[primaryName] ?? process.env[fallbackName];\r\n return value?.trim() || undefined;\r\n}\r\n\r\nfunction shouldBypassProxy(target: URL, noProxy: string): boolean {\r\n const hostname = target.hostname.toLowerCase();\r\n const port = Number.parseInt(target.port, 10)\r\n || (target.protocol === 'https:' ? 443 : 80);\r\n\r\n return noProxy.split(/[,\\s]/).some((rawEntry) => {\r\n const entry = rawEntry.trim().toLowerCase();\r\n if (!entry) {\r\n return false;\r\n }\r\n if (entry === '*') {\r\n return true;\r\n }\r\n\r\n const parsed = entry.match(/^(.+):(\\d+)$/);\r\n const entryHostname = parsed ? parsed[1] : entry;\r\n const entryPort = parsed ? Number.parseInt(parsed[2], 10) : 0;\r\n if (entryPort && entryPort !== port) {\r\n return false;\r\n }\r\n\r\n if (!/^[.*]/.test(entryHostname)) {\r\n return hostname === entryHostname;\r\n }\r\n return hostname.endsWith(entryHostname.replace(/^\\*/, ''));\r\n });\r\n}\r\n\r\nexport function formatNetworkRoute(route: NetworkRoute): string {\r\n if (route === 'proxy-environment') {\r\n return '环境变量代理';\r\n }\r\n if (route === 'proxy-system') {\r\n return '系统代理';\r\n }\r\n return '直连';\r\n}\r\n\r\nfunction createRequestError(\r\n url: string,\r\n options: HttpRequestOptions,\r\n route: NetworkRoute,\r\n error: unknown,\r\n): Error {\r\n const cause = getErrorMessage(error);\r\n return new Error(\r\n `请求失败\\nurl: ${url}\\nerror: ${cause}\\nnetwork: ${formatNetworkRoute(route)}\\ntimeout: ${options.timeoutMs} ms\\nattempts: ${options.retries + 1}`,\r\n );\r\n}\r\n\r\nfunction validateProxyUrl(proxyUrl: string): void {\r\n try {\r\n const parsed = new URL(proxyUrl);\r\n if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') {\r\n throw new Error();\r\n }\r\n } catch {\r\n throw new Error('无效的代理地址,请使用 http://host:port 或 https://host:port 格式。');\r\n }\r\n}\r\n\r\nfunction debugNetworkRoute(\r\n url: string,\r\n route: NetworkRoute,\r\n attempt: number,\r\n attempts: number,\r\n): void {\r\n if (process.env.GZ_CLI_FRONT_DEBUG !== '1') {\r\n return;\r\n }\r\n\r\n console.log(`[network] host: ${new URL(url).host}`);\r\n console.log(`[network] route: ${formatNetworkRoute(route)}`);\r\n console.log(`[network] attempt: ${attempt}/${attempts}`);\r\n}\r\n\r\nfunction getErrorMessage(error: unknown): string {\r\n if (!(error instanceof Error)) {\r\n return '未知错误';\r\n }\r\n const cause = 'cause' in error ? error.cause : undefined;\r\n const causeMessage = cause instanceof Error ? cause.message : String(cause ?? '');\r\n return causeMessage ? `${error.message} (${causeMessage})` : error.message;\r\n}\r\n","import { execFile } from 'node:child_process';\r\nimport { promisify } from 'node:util';\r\n\r\nconst execFileAsync = promisify(execFile);\r\nconst WINDOWS_INTERNET_SETTINGS = String.raw`HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings`;\r\nconst SYSTEM_PROXY_TIMEOUT_MS = 1_500;\r\n\r\nexport interface SystemProxyConfig {\r\n noProxy?: string;\r\n proxyUrl?: string;\r\n}\r\n\r\nconst systemProxyCache = new Map<string, Promise<SystemProxyConfig>>();\r\n\r\nexport function getSystemProxy(target: URL): Promise<SystemProxyConfig> {\r\n const cacheKey = `${process.platform}:${target.protocol}`;\r\n const cached = systemProxyCache.get(cacheKey);\r\n if (cached) {\r\n return cached;\r\n }\r\n\r\n const request = detectSystemProxy(target).catch(() => ({}));\r\n systemProxyCache.set(cacheKey, request);\r\n return request;\r\n}\r\n\r\nasync function detectSystemProxy(target: URL): Promise<SystemProxyConfig> {\r\n if (process.platform === 'win32') {\r\n return detectWindowsProxy(target);\r\n }\r\n if (process.platform === 'darwin') {\r\n return detectMacOsProxy(target);\r\n }\r\n if (process.platform === 'linux') {\r\n return detectLinuxProxy(target);\r\n }\r\n return {};\r\n}\r\n\r\nasync function detectWindowsProxy(target: URL): Promise<SystemProxyConfig> {\r\n const [enabledOutput, serverOutput, overrideOutput] = await Promise.all([\r\n queryWindowsRegistry('ProxyEnable'),\r\n queryWindowsRegistry('ProxyServer'),\r\n queryWindowsRegistry('ProxyOverride'),\r\n ]);\r\n const enabled = readRegistryValue(enabledOutput, 'ProxyEnable');\r\n if (enabled !== '0x1' && enabled !== '1') {\r\n return {};\r\n }\r\n\r\n const proxyServer = readRegistryValue(serverOutput, 'ProxyServer');\r\n if (!proxyServer) {\r\n return {};\r\n }\r\n\r\n const proxyAddress = selectWindowsProxy(proxyServer, target.protocol);\r\n if (!proxyAddress) {\r\n return {};\r\n }\r\n\r\n const proxyOverride = readRegistryValue(overrideOutput, 'ProxyOverride');\r\n return {\r\n noProxy: proxyOverride?.split(';').filter((entry) => entry !== '<local>').join(','),\r\n proxyUrl: normalizeProxyUrl(proxyAddress),\r\n };\r\n}\r\n\r\nasync function queryWindowsRegistry(valueName: string): Promise<string> {\r\n try {\r\n const result = await execFileAsync(\r\n 'reg.exe',\r\n ['query', WINDOWS_INTERNET_SETTINGS, '/v', valueName],\r\n { timeout: SYSTEM_PROXY_TIMEOUT_MS, windowsHide: true },\r\n );\r\n return result.stdout;\r\n } catch {\r\n return '';\r\n }\r\n}\r\n\r\nfunction readRegistryValue(output: string, valueName: string): string | undefined {\r\n const line = output.split(/\\r?\\n/).find((entry) => entry.includes(valueName));\r\n return line?.match(/REG_\\w+\\s+(.+)$/)?.[1]?.trim();\r\n}\r\n\r\nfunction selectWindowsProxy(proxyServer: string, protocol: string): string | undefined {\r\n if (!proxyServer.includes('=')) {\r\n return proxyServer;\r\n }\r\n\r\n const proxies = new Map(\r\n proxyServer.split(';').flatMap((entry) => {\r\n const [key, value] = entry.split('=', 2).map((part) => part.trim());\r\n return key && value ? [[key.toLowerCase(), value] as const] : [];\r\n }),\r\n );\r\n const protocolName = protocol.replace(':', '');\r\n return proxies.get(protocolName) ?? proxies.get('http');\r\n}\r\n\r\nasync function detectMacOsProxy(target: URL): Promise<SystemProxyConfig> {\r\n try {\r\n const result = await execFileAsync('scutil', ['--proxy'], {\r\n timeout: SYSTEM_PROXY_TIMEOUT_MS,\r\n });\r\n const prefix = target.protocol === 'https:' ? 'HTTPS' : 'HTTP';\r\n if (readScutilValue(result.stdout, `${prefix}Enable`) !== '1') {\r\n return {};\r\n }\r\n const host = readScutilValue(result.stdout, `${prefix}Proxy`);\r\n const port = readScutilValue(result.stdout, `${prefix}Port`);\r\n return host && port ? { proxyUrl: `http://${host}:${port}` } : {};\r\n } catch {\r\n return {};\r\n }\r\n}\r\n\r\nfunction readScutilValue(output: string, key: string): string | undefined {\r\n return output.match(new RegExp(`^\\\\s*${key}\\\\s*:\\\\s*(.+)$`, 'm'))?.[1]?.trim();\r\n}\r\n\r\nasync function detectLinuxProxy(target: URL): Promise<SystemProxyConfig> {\r\n try {\r\n const mode = stripQuotes(await queryGSettings('org.gnome.system.proxy', 'mode'));\r\n if (mode !== 'manual') {\r\n return {};\r\n }\r\n\r\n const protocol = target.protocol === 'https:' ? 'https' : 'http';\r\n const [hostValue, portValue, ignoredHostsValue] = await Promise.all([\r\n queryGSettings(`org.gnome.system.proxy.${protocol}`, 'host'),\r\n queryGSettings(`org.gnome.system.proxy.${protocol}`, 'port'),\r\n queryGSettings('org.gnome.system.proxy', 'ignore-hosts'),\r\n ]);\r\n const host = stripQuotes(hostValue);\r\n const port = Number.parseInt(portValue.trim(), 10);\r\n if (!host || !Number.isInteger(port) || port <= 0) {\r\n return {};\r\n }\r\n\r\n return {\r\n noProxy: Array.from(\r\n ignoredHostsValue.matchAll(/'([^']+)'/g),\r\n (match) => match[1],\r\n ).join(','),\r\n proxyUrl: `http://${host}:${port}`,\r\n };\r\n } catch {\r\n return {};\r\n }\r\n}\r\n\r\nasync function queryGSettings(schema: string, key: string): Promise<string> {\r\n const result = await execFileAsync('gsettings', ['get', schema, key], {\r\n timeout: SYSTEM_PROXY_TIMEOUT_MS,\r\n });\r\n return result.stdout;\r\n}\r\n\r\nfunction stripQuotes(value: string): string {\r\n return value.trim().replace(/^['\"]|['\"]$/g, '');\r\n}\r\n\r\nfunction normalizeProxyUrl(proxyAddress: string): string {\r\n return /^[a-z][a-z\\d+.-]*:\\/\\//i.test(proxyAddress)\r\n ? proxyAddress\r\n : `http://${proxyAddress}`;\r\n}\r\n","import { execa } from 'execa';\r\nimport fs from 'fs-extra';\r\nimport { randomUUID } from 'node:crypto';\r\nimport path from 'node:path';\r\nimport { performance } from 'node:perf_hooks';\r\nimport { setTimeout as delay } from 'node:timers/promises';\r\nimport { getGitRepositoryCachePath, isCacheFresh } from './cache.js';\r\nimport {\r\n formatNetworkRoute,\r\n resolveGitNetworkConfig,\r\n type NetworkRoute,\r\n} from './http.js';\r\n\r\nconst GIT_OPERATION_ATTEMPTS = 2;\r\nconst GIT_AUTH_TIMEOUT_MS = 60_000;\r\nconst GIT_SSH_CLONE_TIMEOUT_MS = 20_000;\r\ntype GitOperationStage = 'clone';\r\n\r\nexport interface GitRepositoryOptions {\r\n forceRefresh?: boolean;\r\n namespace: 'registry' | 'templates';\r\n ttlMs: number;\r\n version?: string;\r\n}\r\n\r\nexport interface GitRepositoryResult {\r\n cacheHit: boolean;\r\n elapsedMs: number;\r\n path: string;\r\n route: NetworkRoute | 'ssh' | 'cache' | 'stale-cache';\r\n staleCache: boolean;\r\n}\r\n\r\nexport async function ensureGitRepository(\r\n repositoryUrl: string,\r\n options: GitRepositoryOptions,\r\n): Promise<GitRepositoryResult> {\r\n const version = normalizeVersion(options.version);\r\n const repositoryPath = getRepositoryCachePath(repositoryUrl, options.namespace, version);\r\n const startedAt = performance.now();\r\n const cacheExists = await isValidGitCache(repositoryPath);\r\n\r\n if (await canUseGitCache(repositoryPath, cacheExists, version, options)) {\r\n return createCacheResult(repositoryPath, startedAt, false);\r\n }\r\n\r\n const temporaryPath = `${repositoryPath}.${randomUUID()}.tmp`;\r\n const candidates = getRepositoryCandidates(repositoryUrl);\r\n let lastError: unknown;\r\n await fs.ensureDir(path.dirname(repositoryPath));\r\n\r\n for (const [index, candidate] of candidates.entries()) {\r\n try {\r\n const network = await resolveGitNetworkConfig(candidate);\r\n const isSshCandidate = network.route === 'ssh';\r\n const timeoutMs = isSshCandidate ? GIT_SSH_CLONE_TIMEOUT_MS : GIT_AUTH_TIMEOUT_MS;\r\n debugGitRepository(candidate, network.route, timeoutMs);\r\n await cloneRepository(\r\n candidate,\r\n temporaryPath,\r\n version,\r\n network.args,\r\n timeoutMs,\r\n isSshCandidate ? 1 : GIT_OPERATION_ATTEMPTS,\r\n );\r\n await replaceCacheDirectory(temporaryPath, repositoryPath);\r\n return {\r\n cacheHit: false,\r\n elapsedMs: Math.round(performance.now() - startedAt),\r\n path: repositoryPath,\r\n route: network.route,\r\n staleCache: false,\r\n };\r\n } catch (error: unknown) {\r\n lastError = error;\r\n await fs.remove(temporaryPath);\r\n if (index < candidates.length - 1) {\r\n if (process.env.GZ_CLI_FRONT_DEBUG === '1') {\r\n console.log('[git] SSH 不可用,正在尝试 HTTPS...');\r\n }\r\n continue;\r\n }\r\n }\r\n }\r\n\r\n if (cacheExists && !options.forceRefresh) {\r\n return createCacheResult(repositoryPath, startedAt, true);\r\n }\r\n throw createGitError(repositoryUrl, lastError, 'clone');\r\n}\r\n\r\nfunction getRepositoryCachePath(\r\n repositoryUrl: string,\r\n namespace: GitRepositoryOptions['namespace'],\r\n version: string | undefined,\r\n): string {\r\n return getGitRepositoryCachePath(\r\n namespace,\r\n `${getRepositoryIdentity(repositoryUrl)}#${version ?? 'latest'}`,\r\n );\r\n}\r\n\r\nfunction getRepositoryCandidates(repositoryUrl: string): string[] {\r\n return [repositoryUrl];\r\n}\r\n\r\nfunction getRepositoryIdentity(repositoryUrl: string): string {\r\n try {\r\n const parsed = new URL(repositoryUrl);\r\n const repositoryPath = parsed.pathname.replace(/^\\/|\\/$/g, '').replace(/\\.git$/i, '');\r\n return `${parsed.hostname.toLowerCase()}/${repositoryPath}`;\r\n } catch {\r\n const sshMatch = repositoryUrl.match(/^[^@]+@([^:]+):(.+)$/);\r\n if (!sshMatch) {\r\n return repositoryUrl;\r\n }\r\n return `${sshMatch[1].toLowerCase()}/${sshMatch[2].replace(/\\.git$/i, '')}`;\r\n }\r\n}\r\n\r\nasync function canUseGitCache(\r\n repositoryPath: string,\r\n cacheExists: boolean,\r\n version: string | undefined,\r\n options: GitRepositoryOptions,\r\n): Promise<boolean> {\r\n if (options.forceRefresh || !cacheExists) {\r\n return false;\r\n }\r\n const stats = await fs.stat(repositoryPath);\r\n return Boolean(version) || isCacheFresh(stats.mtimeMs, options.ttlMs);\r\n}\r\n\r\nfunction debugGitRepository(\r\n repositoryUrl: string,\r\n route: NetworkRoute | 'ssh',\r\n timeoutMs: number,\r\n): void {\r\n if (process.env.GZ_CLI_FRONT_DEBUG !== '1') {\r\n return;\r\n }\r\n\r\n const routeLabel = route === 'ssh' ? 'Git/SSH' : formatNetworkRoute(route);\r\n console.log(`[git] host: ${getRepositoryHost(repositoryUrl)}`);\r\n console.log(`[git] route: ${routeLabel}`);\r\n console.log(`[git] timeout: ${timeoutMs} ms`);\r\n}\r\n\r\nfunction getRepositoryHost(repositoryUrl: string): string {\r\n try {\r\n return new URL(repositoryUrl).host;\r\n } catch {\r\n return repositoryUrl.match(/^[^@]+@([^:]+):/)?.[1] ?? 'unknown';\r\n }\r\n}\r\n\r\nasync function cloneRepository(\r\n repositoryUrl: string,\r\n targetPath: string,\r\n version: string | undefined,\r\n networkArgs: string[],\r\n timeoutMs: number,\r\n attempts: number,\r\n): Promise<void> {\r\n const args = [\r\n ...networkArgs,\r\n 'clone',\r\n '--quiet',\r\n '--depth',\r\n '1',\r\n '--single-branch',\r\n ];\r\n if (version) {\r\n args.push('--branch', version);\r\n }\r\n args.push(repositoryUrl, targetPath);\r\n\r\n for (let attempt = 1; attempt <= attempts; attempt += 1) {\r\n try {\r\n await execa('git', args, {\r\n forceKillAfterDelay: 1_000,\r\n stdin: 'inherit',\r\n stdout: 'pipe',\r\n stderr: ['pipe', 'inherit'],\r\n timeout: timeoutMs,\r\n windowsHide: true,\r\n });\r\n return;\r\n } catch (error: unknown) {\r\n if (attempt === attempts || !isTransientGitError(error)) {\r\n throw error;\r\n }\r\n if (process.env.GZ_CLI_FRONT_DEBUG === '1') {\r\n console.log(`[git] transient failure, retry: ${attempt + 1}/${attempts}`);\r\n }\r\n await fs.remove(targetPath);\r\n await delay(300);\r\n }\r\n }\r\n}\r\n\r\nfunction isTransientGitError(error: unknown): boolean {\r\n if (typeof error === 'object' && error !== null\r\n && (error as Record<string, unknown>).timedOut === true) {\r\n return true;\r\n }\r\n\r\n const message = error instanceof Error ? error.message : String(error);\r\n return [\r\n /SSL\\/TLS connection failed/i,\r\n /failed to receive handshake/i,\r\n /connection (?:was )?reset/i,\r\n /remote end hung up unexpectedly/i,\r\n /early EOF/i,\r\n /failed to connect/i,\r\n /could not resolve host/i,\r\n /timed out|timeout/i,\r\n ].some((pattern) => pattern.test(message));\r\n}\r\n\r\nasync function replaceCacheDirectory(sourcePath: string, targetPath: string): Promise<void> {\r\n const backupPath = `${targetPath}.${randomUUID()}.bak`;\r\n const targetExists = await fs.pathExists(targetPath);\r\n if (targetExists) {\r\n await fs.move(targetPath, backupPath);\r\n }\r\n\r\n try {\r\n await fs.move(sourcePath, targetPath);\r\n await fs.remove(backupPath);\r\n } catch (error: unknown) {\r\n await fs.remove(targetPath);\r\n if (await fs.pathExists(backupPath)) {\r\n await fs.move(backupPath, targetPath);\r\n }\r\n throw error;\r\n }\r\n}\r\n\r\nasync function isValidGitCache(repositoryPath: string): Promise<boolean> {\r\n return fs.pathExists(path.join(repositoryPath, '.git'));\r\n}\r\n\r\nfunction createCacheResult(\r\n repositoryPath: string,\r\n startedAt: number,\r\n staleCache: boolean,\r\n): GitRepositoryResult {\r\n return {\r\n cacheHit: true,\r\n elapsedMs: Math.round(performance.now() - startedAt),\r\n path: repositoryPath,\r\n route: staleCache ? 'stale-cache' : 'cache',\r\n staleCache,\r\n };\r\n}\r\n\r\nfunction normalizeVersion(version: string | undefined): string | undefined {\r\n return version && version !== 'latest' ? version : undefined;\r\n}\r\n\r\nfunction createGitError(\r\n repositoryUrl: string,\r\n error: unknown,\r\n stage: GitOperationStage,\r\n): Error {\r\n const message = getGitErrorMessage(error);\r\n const safeRepository = sanitizeRepositoryUrl(repositoryUrl);\r\n debugGitFailure(stage, message);\r\n if (isGitTimeoutError(error, message)) {\r\n return new Error(\r\n `Git 仓库连接超时(阶段:${stage},${GIT_AUTH_TIMEOUT_MS} ms):${safeRepository}\\n请检查当前网络或代理设置后重试。`,\r\n );\r\n }\r\n\r\n if (isGitPermissionError(message)) {\r\n return new Error(\r\n `无法访问 Git 仓库(阶段:${stage}):${safeRepository}\\n请检查仓库地址、网络连接及当前 Git 凭据后重试。`,\r\n );\r\n }\r\n\r\n return new Error(\r\n `Git 仓库访问失败(阶段:${stage}):${safeRepository}\\n请确认已安装 Git,且当前 Git/SSH 账号拥有仓库 Read 权限。\\n${message}`,\r\n );\r\n}\r\n\r\nfunction getGitErrorMessage(error: unknown): string {\r\n return redactCredentials(error instanceof Error ? error.message : '未知错误');\r\n}\r\n\r\nfunction debugGitFailure(stage: GitOperationStage, message: string): void {\r\n if (process.env.GZ_CLI_FRONT_DEBUG !== '1') {\r\n return;\r\n }\r\n\r\n console.error(`[git] failed stage: ${stage}`);\r\n console.error(`[git] error: ${message}`);\r\n}\r\n\r\nfunction isGitTimeoutError(error: unknown, message: string): boolean {\r\n if (typeof error === 'object' && error !== null\r\n && (error as Record<string, unknown>).timedOut === true) {\r\n return true;\r\n }\r\n return /timed out|timeout/i.test(message);\r\n}\r\n\r\nfunction isGitPermissionError(message: string): boolean {\r\n return [\r\n /authentication failed/i,\r\n /permission denied/i,\r\n /repository not found/i,\r\n /could not read username/i,\r\n /unable to get (?:password|username) from user/i,\r\n /terminal prompts disabled/i,\r\n /user interaction is disabled/i,\r\n /interactive prompts are disabled/i,\r\n /credential.*(?:failed|unavailable)/i,\r\n /access denied/i,\r\n /http (?:error )?40[13]/i,\r\n /status code: 40[13]/i,\r\n ].some((pattern) => pattern.test(message));\r\n}\r\n\r\nfunction redactCredentials(message: string): string {\r\n return message\r\n .replace(/http\\.proxy=\\S+/gi, 'http.proxy=***')\r\n .replace(/(https?:\\/\\/)[^@\\s/]+@/gi, '$1***@');\r\n}\r\n\r\nfunction sanitizeRepositoryUrl(repositoryUrl: string): string {\r\n try {\r\n const parsed = new URL(repositoryUrl);\r\n parsed.username = '';\r\n parsed.password = '';\r\n return parsed.toString();\r\n } catch {\r\n return repositoryUrl;\r\n }\r\n}\r\n","import fs from 'fs-extra';\r\nimport { randomUUID } from 'node:crypto';\r\nimport path from 'path';\r\nimport { performance } from 'node:perf_hooks';\r\nimport { x as extractTar } from 'tar';\r\nimport type { TemplateMeta, TemplateSource } from '../types/template.js';\r\nimport {\r\n getTemplateArchiveCachePath,\r\n isCacheFresh,\r\n TEMPLATE_ARCHIVE_CACHE_TTL_MS,\r\n} from './cache.js';\r\nimport { requestBuffer, type NetworkRoute } from './http.js';\r\nimport { ensureGitRepository } from './git-repository.js';\r\n\r\nconst TEMPLATE_DOWNLOAD_TIMEOUT_MS = 12_000;\r\n\r\nexport interface TemplateDownloadTiming {\r\n cacheHit: boolean;\r\n copyMs: number;\r\n downloadMs: number;\r\n extractMs: number;\r\n route: NetworkRoute | 'ssh' | 'cache' | 'stale-cache' | 'git';\r\n}\r\n\r\nexport interface DownloadTemplateOptions {\r\n forceRefresh?: boolean;\r\n}\r\n\r\ntype TemplateDownloader = (\r\n template: TemplateMeta,\r\n targetDir: string,\r\n options: DownloadTemplateOptions,\r\n) => Promise<TemplateDownloadTiming>;\r\n\r\nconst DOWNLOADERS: Readonly<Record<TemplateSource, TemplateDownloader>> = {\r\n github: downloadFromGitHub,\r\n gitlab: downloadFromGit,\r\n git: downloadFromGit,\r\n};\r\n\r\nexport async function downloadTemplate(\r\n template: TemplateMeta,\r\n targetDir: string,\r\n options: DownloadTemplateOptions = {},\r\n): Promise<TemplateDownloadTiming> {\r\n const source = template.source ?? 'github';\r\n return DOWNLOADERS[source](template, targetDir, options);\r\n}\r\n\r\nasync function downloadFromGitHub(\r\n template: TemplateMeta,\r\n targetDir: string,\r\n options: DownloadTemplateOptions,\r\n): Promise<TemplateDownloadTiming> {\r\n const repository = normalizeGitHubRepository(getTemplateUrl(template));\r\n const version = template.version && template.version !== 'latest'\r\n ? template.version\r\n : undefined;\r\n const sourceKey = `${repository}${version ? `#${version}` : '#latest'}`;\r\n const archivePath = getTemplateArchiveCachePath(sourceKey);\r\n const archive = await ensureGitHubArchive(\r\n repository,\r\n version,\r\n archivePath,\r\n options.forceRefresh === true,\r\n );\r\n\r\n const extractStartedAt = performance.now();\r\n await fs.ensureDir(targetDir);\r\n try {\r\n await extractTar({\r\n cwd: targetDir,\r\n file: archivePath,\r\n preservePaths: false,\r\n strict: true,\r\n strip: 1,\r\n });\r\n } catch (error: unknown) {\r\n if (!archive.cacheHit) {\r\n throw error;\r\n }\r\n\r\n await fs.remove(archivePath);\r\n await fs.emptyDir(targetDir);\r\n return downloadFromGitHub(template, targetDir, { forceRefresh: true });\r\n }\r\n\r\n return {\r\n cacheHit: archive.cacheHit,\r\n copyMs: 0,\r\n downloadMs: archive.downloadMs,\r\n extractMs: Math.round(performance.now() - extractStartedAt),\r\n route: archive.route,\r\n };\r\n}\r\n\r\nasync function downloadFromGit(\r\n template: TemplateMeta,\r\n targetDir: string,\r\n options: DownloadTemplateOptions,\r\n): Promise<TemplateDownloadTiming> {\r\n if (!template.url) {\r\n throw new Error(`${template.source} 模板必须提供 Git clone URL。`);\r\n }\r\n\r\n const repository = await ensureGitRepository(template.url, {\r\n forceRefresh: options.forceRefresh,\r\n namespace: 'templates',\r\n ttlMs: TEMPLATE_ARCHIVE_CACHE_TTL_MS,\r\n version: template.version,\r\n });\r\n const copyStartedAt = performance.now();\r\n await fs.copy(repository.path, targetDir, {\r\n filter: (sourcePath) => path.basename(sourcePath) !== '.git',\r\n });\r\n\r\n return {\r\n cacheHit: repository.cacheHit,\r\n copyMs: Math.round(performance.now() - copyStartedAt),\r\n downloadMs: repository.elapsedMs,\r\n extractMs: 0,\r\n route: repository.route,\r\n };\r\n}\r\n\r\ninterface GitHubArchiveResult {\r\n cacheHit: boolean;\r\n downloadMs: number;\r\n route: NetworkRoute | 'cache';\r\n}\r\n\r\nasync function ensureGitHubArchive(\r\n repository: string,\r\n version: string | undefined,\r\n archivePath: string,\r\n forceRefresh: boolean,\r\n): Promise<GitHubArchiveResult> {\r\n const startedAt = performance.now();\r\n if (!forceRefresh && await canUseArchiveCache(archivePath, Boolean(version))) {\r\n return {\r\n cacheHit: true,\r\n downloadMs: Math.round(performance.now() - startedAt),\r\n route: 'cache',\r\n };\r\n }\r\n\r\n const archiveRequest = createGitHubArchiveRequest(repository, version);\r\n const response = await requestBuffer(archiveRequest.url, {\r\n headers: archiveRequest.headers,\r\n retries: 1,\r\n timeoutMs: TEMPLATE_DOWNLOAD_TIMEOUT_MS,\r\n });\r\n const temporaryPath = `${archivePath}.${randomUUID()}.tmp`;\r\n\r\n await fs.ensureDir(path.dirname(archivePath));\r\n try {\r\n await fs.writeFile(temporaryPath, response.body);\r\n await fs.move(temporaryPath, archivePath, { overwrite: true });\r\n } finally {\r\n await fs.remove(temporaryPath);\r\n }\r\n\r\n return {\r\n cacheHit: false,\r\n downloadMs: Math.round(performance.now() - startedAt),\r\n route: response.route,\r\n };\r\n}\r\n\r\ninterface GitHubArchiveRequest {\r\n headers: Readonly<Record<string, string>>;\r\n url: string;\r\n}\r\n\r\nfunction createGitHubArchiveRequest(\r\n repository: string,\r\n version: string | undefined,\r\n): GitHubArchiveRequest {\r\n const token = process.env.GITHUB_TOKEN?.trim();\r\n if (token) {\r\n return {\r\n headers: createGitHubApiHeaders(token),\r\n url: `https://api.github.com/repos/${repository}/tarball${version ? `/${encodeURIComponent(version)}` : ''}`,\r\n };\r\n }\r\n\r\n return {\r\n headers: { 'user-agent': 'gz-cli-front' },\r\n url: `https://codeload.github.com/${repository}/tar.gz/${encodeURIComponent(version ?? 'HEAD')}`,\r\n };\r\n}\r\n\r\nasync function canUseArchiveCache(archivePath: string, immutableVersion: boolean): Promise<boolean> {\r\n try {\r\n const stats = await fs.stat(archivePath);\r\n return stats.isFile()\r\n && (immutableVersion || isCacheFresh(stats.mtimeMs, TEMPLATE_ARCHIVE_CACHE_TTL_MS));\r\n } catch {\r\n return false;\r\n }\r\n}\r\n\r\nfunction normalizeGitHubRepository(repository: string): string {\r\n const normalized = repository\r\n .replace(/^https:\\/\\/github\\.com\\//i, '')\r\n .replace(/\\.git$/i, '')\r\n .replace(/^\\/+|\\/+$/g, '');\r\n\r\n if (!/^[^/\\s]+\\/[^/\\s]+$/.test(normalized)) {\r\n throw new Error(`无效的 GitHub 模板地址:${repository}`);\r\n }\r\n\r\n return normalized;\r\n}\r\n\r\nfunction createGitHubApiHeaders(token: string): Readonly<Record<string, string>> {\r\n return {\r\n accept: 'application/vnd.github+json',\r\n authorization: `Bearer ${token}`,\r\n 'user-agent': 'gz-cli-front',\r\n 'x-github-api-version': '2022-11-28',\r\n };\r\n}\r\n\r\nfunction getTemplateUrl(template: TemplateMeta): string {\r\n if (template.url) {\r\n return template.url;\r\n }\r\n if (template.repo) {\r\n return template.repo;\r\n }\r\n throw new Error('模板配置缺少 url。');\r\n}\r\n","import chalk from 'chalk';\r\nimport { clearLine, cursorTo } from 'node:readline';\r\n\r\nconst SPINNER_FRAMES = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];\r\nconst SPINNER_INTERVAL_MS = 80;\r\nconst RESTORE_CURSOR = '\\u001B[u';\r\nconst SAVE_CURSOR = '\\u001B[s';\r\n\r\nexport interface StableSpinner {\r\n readonly isSpinning: boolean;\r\n text: string;\r\n fail(text?: string): void;\r\n start(text?: string): void;\r\n succeed(text?: string): void;\r\n}\r\n\r\nexport function createStableSpinner(): StableSpinner {\r\n return new StableTextSpinner(process.stderr);\r\n}\r\n\r\nclass StableTextSpinner implements StableSpinner {\r\n private frameIndex = 0;\r\n private interval: NodeJS.Timeout | undefined;\r\n private readonly stream: NodeJS.WriteStream;\r\n private value = '';\r\n\r\n constructor(stream: NodeJS.WriteStream) {\r\n this.stream = stream;\r\n }\r\n\r\n get isSpinning(): boolean {\r\n return this.interval !== undefined;\r\n }\r\n\r\n get text(): string {\r\n return this.value;\r\n }\r\n\r\n set text(value: string) {\r\n this.value = value;\r\n if (this.isSpinning) {\r\n this.renderLine();\r\n }\r\n }\r\n\r\n start(text?: string): void {\r\n if (text !== undefined) {\r\n this.value = text;\r\n }\r\n if (!this.stream.isTTY || this.isSpinning) {\r\n if (!this.stream.isTTY && this.value) {\r\n this.stream.write(`- ${this.value}\\n`);\r\n }\r\n return;\r\n }\r\n\r\n this.stream.write(\r\n `${chalk.cyan(SPINNER_FRAMES[this.frameIndex])} ${this.value}${SAVE_CURSOR}`,\r\n );\r\n this.interval = setInterval(() => this.renderFrame(), SPINNER_INTERVAL_MS);\r\n }\r\n\r\n succeed(text?: string): void {\r\n this.persist(chalk.green('✔'), text);\r\n }\r\n\r\n fail(text?: string): void {\r\n this.persist(chalk.red('✖'), text);\r\n }\r\n\r\n private renderLine(): void {\r\n this.restoreAndClearLine();\r\n this.stream.write(`${chalk.cyan(SPINNER_FRAMES[this.frameIndex])} ${this.value}${SAVE_CURSOR}`);\r\n }\r\n\r\n private renderFrame(): void {\r\n this.frameIndex = (this.frameIndex + 1) % SPINNER_FRAMES.length;\r\n this.stream.write(\r\n `${RESTORE_CURSOR}\\r${chalk.cyan(SPINNER_FRAMES[this.frameIndex])}${RESTORE_CURSOR}`,\r\n );\r\n }\r\n\r\n private persist(symbol: string, text?: string): void {\r\n const finalText = text ?? this.value;\r\n this.stop();\r\n this.stream.write(`${symbol}${finalText ? ` ${finalText}` : ''}\\n`);\r\n }\r\n\r\n private stop(): boolean {\r\n if (!this.interval) {\r\n return false;\r\n }\r\n\r\n clearInterval(this.interval);\r\n this.interval = undefined;\r\n this.restoreAndClearLine();\r\n return true;\r\n }\r\n\r\n private restoreAndClearLine(): void {\r\n this.stream.write(RESTORE_CURSOR);\r\n cursorTo(this.stream, 0);\r\n clearLine(this.stream, 0);\r\n }\r\n}\r\n","import chalk from 'chalk';\r\n\r\n/**\r\n * 检查当前 Node.js 版本是否符合要求\r\n * 要求 Node.js 版本 >= 22.19.0\r\n */\r\nexport function checkNodeVersion() {\r\n const currentVersion = process.version;\r\n // 去掉版本号前的 'v',例如 'v22.5.1' -> '22.5.1'\r\n const version = currentVersion.replace(/^v/, '');\r\n const [major] = version.split('.').map(Number);\r\n\r\n if (major < 22) {\r\n console.error(chalk.red(`\\n❌ 错误:当前 Node.js 版本 (${currentVersion}) 过低!`));\r\n console.error(chalk.yellow('⚠️ 请升级 Node.js 版本,不低于 v22.19.0'));\r\n process.exit(1);\r\n }\r\n}\r\n"],"mappings":"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","names":["chalk","execa","fs","path","performance","fs","path","fs","path","performance","path","fs","path","performance","delay","performance","fs","path","delay","performance","fs","getErrorMessage","path","fs","randomUUID","path","performance","performance","fs","path","randomUUID","path","chalk","getErrorMessage","fs","performance","execa","chalk","require"]}
package/package.json CHANGED
@@ -1,46 +1,48 @@
1
- {
2
- "name": "gz-cli-front",
3
- "version": "1.0.0",
4
- "description": "一个轻量级的现代前端脚手架工具",
5
- "type": "module",
6
- "main": "dist/index.js",
7
- "bin": {
8
- "gz-cli-front": "bin/gz-cli-front.js"
9
- },
10
- "files": [
11
- "dist",
12
- "bin"
13
- ],
14
- "scripts": {
15
- "dev": "tsup --watch",
16
- "build": "tsup && node scripts/copy-assets.js",
17
- "prepublishOnly": "npm run test:release",
18
- "test": "echo \"Error: no test specified\" && exit 1",
19
- "test:auth-error": "npm run build && node scripts/test-private-auth.js",
20
- "test:git-compat": "node --no-warnings --loader ts-node/esm scripts/test-git-credential-compat.ts",
21
- "test:private-access": "node --no-warnings --loader ts-node/esm scripts/test-private-access.ts",
22
- "test:smoke": "npm run test:git-compat && npm run test:private-access && node scripts/test-private-auth.js && npm pack --dry-run",
23
- "test:release": "npm run build && npm run test:smoke"
24
- },
25
- "keywords": [],
26
- "author": "chenhui996",
27
- "license": "ISC",
28
- "devDependencies": {
29
- "@types/node": "^25.5.0",
30
- "cpy-cli": "^7.0.0",
31
- "ts-node": "^10.9.2",
32
- "tsup": "^8.5.1",
33
- "typescript": "^5.9.3"
34
- },
35
- "dependencies": {
36
- "@inquirer/prompts": "^8.3.2",
37
- "@types/fs-extra": "^11.0.4",
38
- "chalk": "^4.1.2",
39
- "commander": "^14.0.3",
40
- "execa": "^9.6.1",
41
- "fs-extra": "^11.3.4",
42
- "ora": "^5.4.1",
43
- "tar": "^7.5.20",
44
- "undici": "^7.28.0"
45
- }
46
- }
1
+ {
2
+ "name": "gz-cli-front",
3
+ "version": "1.0.1-beta.0",
4
+ "description": "一个轻量级的现代前端脚手架工具",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "bin": {
8
+ "gz-cli": "bin/gz-cli-front.js",
9
+ "gz-cli-front": "bin/gz-cli-front.js"
10
+ },
11
+ "files": [
12
+ "dist",
13
+ "bin"
14
+ ],
15
+ "scripts": {
16
+ "dev": "tsup --watch",
17
+ "build": "tsup && node scripts/copy-assets.js",
18
+ "prepublishOnly": "npm run test:release",
19
+ "test": "echo \"Error: no test specified\" && exit 1",
20
+ "test:cli": "node scripts/test-cli.js",
21
+ "test:auth-error": "npm run build && node scripts/test-private-auth.js",
22
+ "test:git-compat": "node --no-warnings --loader ts-node/esm scripts/test-git-credential-compat.ts",
23
+ "test:private-access": "node --no-warnings --loader ts-node/esm scripts/test-private-access.ts",
24
+ "test:smoke": "npm run test:cli && npm run test:git-compat && npm run test:private-access && node scripts/test-private-auth.js && npm pack --dry-run",
25
+ "test:release": "npm run build && npm run test:smoke"
26
+ },
27
+ "keywords": [],
28
+ "author": "chenhui996",
29
+ "license": "ISC",
30
+ "devDependencies": {
31
+ "@types/node": "^25.5.0",
32
+ "cpy-cli": "^7.0.0",
33
+ "ts-node": "^10.9.2",
34
+ "tsup": "^8.5.1",
35
+ "typescript": "^5.9.3"
36
+ },
37
+ "dependencies": {
38
+ "@inquirer/prompts": "^8.3.2",
39
+ "@types/fs-extra": "^11.0.4",
40
+ "chalk": "^4.1.2",
41
+ "commander": "^14.0.3",
42
+ "execa": "^9.6.1",
43
+ "fs-extra": "^11.3.4",
44
+ "ora": "^5.4.1",
45
+ "tar": "^7.5.20",
46
+ "undici": "^7.28.0"
47
+ }
48
+ }