specflow-dev-service 0.0.0-beta.5 → 0.0.0-beta.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +2 -2
- package/dist/cli.js.map +1 -1
- package/dist/config/defaults.js +2 -1
- package/dist/config/defaults.js.map +1 -1
- package/dist/config/schema.d.ts +18 -0
- package/dist/config/schema.d.ts.map +1 -1
- package/dist/orchestrator.d.ts +5 -2
- package/dist/orchestrator.d.ts.map +1 -1
- package/dist/orchestrator.js +30 -3
- package/dist/orchestrator.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -28,13 +28,13 @@ program.name('specflow').description('Specflow 开发服务启动器 — 前端
|
|
|
28
28
|
|
|
29
29
|
// ==================== dev 命令 ====================
|
|
30
30
|
|
|
31
|
-
program.command('dev').description('启动开发环境(前端 + Go 后端)').option('-c, --config <path>', '配置文件路径').option('--client', '仅启动前端服务').option('--go', '仅启动 Go 后端服务').action(async opts => runDevCommand(opts));
|
|
31
|
+
program.command('dev').description('启动开发环境(前端 + Go 后端)').option('-c, --config <path>', '配置文件路径').option('-e, --env <name>', '环境变量分组名(如 local / remote),默认取第一个').option('--client', '仅启动前端服务').option('--go', '仅启动 Go 后端服务').action(async opts => runDevCommand(opts));
|
|
32
32
|
async function runDevCommand(opts) {
|
|
33
33
|
const cwd = process.cwd();
|
|
34
34
|
const configPath = opts.config ? node_path.resolve(cwd, opts.config) : undefined;
|
|
35
35
|
let svc;
|
|
36
36
|
try {
|
|
37
|
-
svc = await orchestrator.createForgeService(cwd, configPath);
|
|
37
|
+
svc = await orchestrator.createForgeService(cwd, configPath, opts.env);
|
|
38
38
|
} catch (err) {
|
|
39
39
|
console.error('[specflow] 配置加载失败:', err instanceof Error ? err.message : err);
|
|
40
40
|
process.exit(1);
|
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.js","sources":["../src/cli.ts"],"sourcesContent":["/**\n * specflow-dev-service CLI\n *\n * 命令:\n * specflow dev — 启动开发环境(前端 + Go 后端热更新)\n * specflow dev --client — 仅启动前端\n * specflow dev --go — 仅启动 Go 后端\n * specflow status — 查看服务状态\n *\n * 日志原则:无错误不输出,静默处理正常流程\n */\n\nimport { resolve } from 'node:path';\n\nimport { Command } from 'commander';\n\nimport { createForgeService } from './index';\n\nimport type { ForgeService } from './orchestrator';\n\n// ============================================================\n// CLI\n// ============================================================\n\nconst program = new Command();\n\nprogram.name('specflow').description('Specflow 开发服务启动器 — 前端 + Go 后端热更新').version('0.0.0-beta.1');\n\n// ==================== dev 命令 ====================\n\nprogram\n .command('dev')\n .description('启动开发环境(前端 + Go 后端)')\n .option('-c, --config <path>', '配置文件路径')\n .option('--client', '仅启动前端服务')\n .option('--go', '仅启动 Go 后端服务')\n .action(async (opts: { config?: string; client?: boolean; go?: boolean }) => runDevCommand(opts));\n\nasync function runDevCommand(opts: { config?: string; client?: boolean; go?: boolean }): Promise<void> {\n const cwd = process.cwd();\n const configPath = opts.config ? resolve(cwd, opts.config) : undefined;\n\n let svc: ForgeService;\n try {\n svc = await createForgeService(cwd, configPath);\n } catch (err) {\n console.error('[specflow] 配置加载失败:', err instanceof Error ? err.message : err);\n process.exit(1);\n }\n\n // 启动模式\n try {\n if (opts.go) {\n await svc.start({ client: false, service: true });\n } else if (opts.client) {\n await svc.start({ client: true, service: false });\n } else {\n await svc.start();\n }\n } catch (err) {\n console.error('[specflow] 启动失败:', err instanceof Error ? err.message : err);\n process.exit(1);\n }\n\n // 优雅退出\n const shutdown = async (signal: string): Promise<void> => {\n process.stdout.write(`\\n[${signal}] 正在停止...`);\n try {\n await svc.stop();\n } catch {\n /* ignore */\n }\n process.exit(0);\n };\n\n process.on('SIGINT', () => void shutdown('SIGINT'));\n process.on('SIGTERM', () => void shutdown('SIGTERM'));\n}\n\n// ==================== status 命令 ====================\n\nprogram\n .command('status')\n .description('查看服务状态')\n .option('-c, --config <path>', '配置文件路径')\n .action(async (opts: { config?: string }) => {\n try {\n const cwd = process.cwd();\n const configPath = opts.config ? resolve(cwd, opts.config) : undefined;\n const svc = await createForgeService(cwd, configPath);\n const status = svc.getStatus();\n console.log(JSON.stringify(status, null, 2));\n } catch (err) {\n console.error('[specflow] 获取状态失败:', err instanceof Error ? err.message : err);\n process.exit(1);\n }\n });\n\n// ==================== 执行 ====================\n\nprogram.parse();\n"],"names":["program","Command","name","description","version","command","option","action","opts","runDevCommand","cwd","process","configPath","config","resolve","undefined","svc","createForgeService","err","console","error","Error","message","exit","go","start","client","service","shutdown","signal","stdout","write","stop","on","status","getStatus","log","JSON","stringify","parse"],"mappings":";;;;;;;;;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAUA;AACA;AACA;;AAEA,MAAMA,OAAO,GAAG,IAAIC,iBAAO,EAAE;AAE7BD,OAAO,CAACE,IAAI,CAAC,UAAU,CAAC,CAACC,WAAW,CAAC,kCAAkC,CAAC,CAACC,OAAO,CAAC,cAAc,CAAC;;AAEhG;;AAEAJ,OAAO,CACJK,OAAO,CAAC,KAAK,CAAC,CACdF,WAAW,CAAC,oBAAoB,CAAC,CACjCG,MAAM,CAAC,qBAAqB,EAAE,QAAQ,CAAC,CACvCA,MAAM,CAAC,UAAU,EAAE,SAAS,CAAC,CAC7BA,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAC7BC,MAAM,
|
|
1
|
+
{"version":3,"file":"cli.js","sources":["../src/cli.ts"],"sourcesContent":["/**\n * specflow-dev-service CLI\n *\n * 命令:\n * specflow dev — 启动开发环境(前端 + Go 后端热更新)\n * specflow dev --client — 仅启动前端\n * specflow dev --go — 仅启动 Go 后端\n * specflow status — 查看服务状态\n *\n * 日志原则:无错误不输出,静默处理正常流程\n */\n\nimport { resolve } from 'node:path';\n\nimport { Command } from 'commander';\n\nimport { createForgeService } from './index';\n\nimport type { ForgeService } from './orchestrator';\n\n// ============================================================\n// CLI\n// ============================================================\n\nconst program = new Command();\n\nprogram.name('specflow').description('Specflow 开发服务启动器 — 前端 + Go 后端热更新').version('0.0.0-beta.1');\n\n// ==================== dev 命令 ====================\n\nprogram\n .command('dev')\n .description('启动开发环境(前端 + Go 后端)')\n .option('-c, --config <path>', '配置文件路径')\n .option('-e, --env <name>', '环境变量分组名(如 local / remote),默认取第一个')\n .option('--client', '仅启动前端服务')\n .option('--go', '仅启动 Go 后端服务')\n .action(\n async (opts: { config?: string; env?: string; client?: boolean; go?: boolean }) => runDevCommand(opts),\n );\n\nasync function runDevCommand(opts: { config?: string; env?: string; client?: boolean; go?: boolean }): Promise<void> {\n const cwd = process.cwd();\n const configPath = opts.config ? resolve(cwd, opts.config) : undefined;\n\n let svc: ForgeService;\n try {\n svc = await createForgeService(cwd, configPath, opts.env);\n } catch (err) {\n console.error('[specflow] 配置加载失败:', err instanceof Error ? err.message : err);\n process.exit(1);\n }\n\n // 启动模式\n try {\n if (opts.go) {\n await svc.start({ client: false, service: true });\n } else if (opts.client) {\n await svc.start({ client: true, service: false });\n } else {\n await svc.start();\n }\n } catch (err) {\n console.error('[specflow] 启动失败:', err instanceof Error ? err.message : err);\n process.exit(1);\n }\n\n // 优雅退出\n const shutdown = async (signal: string): Promise<void> => {\n process.stdout.write(`\\n[${signal}] 正在停止...`);\n try {\n await svc.stop();\n } catch {\n /* ignore */\n }\n process.exit(0);\n };\n\n process.on('SIGINT', () => void shutdown('SIGINT'));\n process.on('SIGTERM', () => void shutdown('SIGTERM'));\n}\n\n// ==================== status 命令 ====================\n\nprogram\n .command('status')\n .description('查看服务状态')\n .option('-c, --config <path>', '配置文件路径')\n .action(async (opts: { config?: string }) => {\n try {\n const cwd = process.cwd();\n const configPath = opts.config ? resolve(cwd, opts.config) : undefined;\n const svc = await createForgeService(cwd, configPath);\n const status = svc.getStatus();\n console.log(JSON.stringify(status, null, 2));\n } catch (err) {\n console.error('[specflow] 获取状态失败:', err instanceof Error ? err.message : err);\n process.exit(1);\n }\n });\n\n// ==================== 执行 ====================\n\nprogram.parse();\n"],"names":["program","Command","name","description","version","command","option","action","opts","runDevCommand","cwd","process","configPath","config","resolve","undefined","svc","createForgeService","env","err","console","error","Error","message","exit","go","start","client","service","shutdown","signal","stdout","write","stop","on","status","getStatus","log","JSON","stringify","parse"],"mappings":"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"}
|
package/dist/config/defaults.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"defaults.js","sources":["../../src/config/defaults.ts"],"sourcesContent":["/**\n * 默认配置值\n */\n\nimport type { ResolvedConfig } from './schema';\n\nexport const defaultConfig: Omit<ResolvedConfig, 'configDir'> = {\n client: {\n dir: 'client',\n dev: 'npm run dev',\n build: 'npm run build',\n port: 3000,\n distDir: 'dist',\n },\n service: {\n dir: 'service',\n port: 8080,\n pbDir: 'pb',\n handlerDir: 'handler',\n module: '',\n dev: '',\n },\n};\n"],"names":["defaultConfig","client","dir","dev","build","port","distDir","service","pbDir","handlerDir","module"],"mappings":";;AAAA;AACA;AACA;;AAIO,MAAMA,aAAgD,GAAG;AAC9DC,EAAAA,MAAM,EAAE;AACNC,IAAAA,GAAG,EAAE,QAAQ;AACbC,IAAAA,GAAG,EAAE,aAAa;AAClBC,IAAAA,KAAK,EAAE,eAAe;AACtBC,IAAAA,IAAI,EAAE,IAAI;AACVC,IAAAA,OAAO,EAAE;GACV;AACDC,EAAAA,OAAO,EAAE;AACPL,IAAAA,GAAG,EAAE,SAAS;AACdG,IAAAA,IAAI,EAAE,IAAI;AACVG,IAAAA,KAAK,EAAE,IAAI;AACXC,IAAAA,UAAU,EAAE,SAAS;AACrBC,IAAAA,MAAM,EAAE,EAAE;AACVP,IAAAA,GAAG,EAAE;AACP
|
|
1
|
+
{"version":3,"file":"defaults.js","sources":["../../src/config/defaults.ts"],"sourcesContent":["/**\n * 默认配置值\n */\n\nimport type { ResolvedConfig } from './schema';\n\nexport const defaultConfig: Omit<ResolvedConfig, 'configDir'> = {\n client: {\n dir: 'client',\n dev: 'npm run dev',\n build: 'npm run build',\n port: 3000,\n distDir: 'dist',\n },\n service: {\n dir: 'service',\n port: 8080,\n pbDir: 'pb',\n handlerDir: 'handler',\n module: '',\n dev: '',\n },\n env: {},\n};\n"],"names":["defaultConfig","client","dir","dev","build","port","distDir","service","pbDir","handlerDir","module","env"],"mappings":";;AAAA;AACA;AACA;;AAIO,MAAMA,aAAgD,GAAG;AAC9DC,EAAAA,MAAM,EAAE;AACNC,IAAAA,GAAG,EAAE,QAAQ;AACbC,IAAAA,GAAG,EAAE,aAAa;AAClBC,IAAAA,KAAK,EAAE,eAAe;AACtBC,IAAAA,IAAI,EAAE,IAAI;AACVC,IAAAA,OAAO,EAAE;GACV;AACDC,EAAAA,OAAO,EAAE;AACPL,IAAAA,GAAG,EAAE,SAAS;AACdG,IAAAA,IAAI,EAAE,IAAI;AACVG,IAAAA,KAAK,EAAE,IAAI;AACXC,IAAAA,UAAU,EAAE,SAAS;AACrBC,IAAAA,MAAM,EAAE,EAAE;AACVP,IAAAA,GAAG,EAAE;GACN;AACDQ,EAAAA,GAAG,EAAE;AACP;;;;"}
|
package/dist/config/schema.d.ts
CHANGED
|
@@ -55,6 +55,22 @@ interface SpecflowConfig {
|
|
|
55
55
|
client?: ClientConfig;
|
|
56
56
|
/** Go 真实后端服务配置 */
|
|
57
57
|
service?: ServiceConfig;
|
|
58
|
+
/**
|
|
59
|
+
* 环境变量分组(按 preset 名区分,通过 `specflow dev --env <name>` 选择注入)
|
|
60
|
+
*
|
|
61
|
+
* 示例:
|
|
62
|
+
* env: {
|
|
63
|
+
* local: {
|
|
64
|
+
* MYSQL_DSN: 'root:123456@tcp(127.0.0.1:3306)/db?charset=utf8mb4',
|
|
65
|
+
* API_PROXY_TARGET: 'http://localhost:8080',
|
|
66
|
+
* },
|
|
67
|
+
* remote: {
|
|
68
|
+
* MYSQL_DSN: 'admin:xxx@tcp(10.0.0.1:3306)/db',
|
|
69
|
+
* API_PROXY_TARGET: 'http://10.0.0.2:8080',
|
|
70
|
+
* },
|
|
71
|
+
* }
|
|
72
|
+
*/
|
|
73
|
+
env?: Record<string, Record<string, string>>;
|
|
58
74
|
}
|
|
59
75
|
/** 解析后的配置(所有字段都有值) */
|
|
60
76
|
interface ResolvedConfig {
|
|
@@ -62,6 +78,8 @@ interface ResolvedConfig {
|
|
|
62
78
|
service: Required<ServiceConfig>;
|
|
63
79
|
/** 配置文件所在目录 */
|
|
64
80
|
configDir: string;
|
|
81
|
+
/** 环境变量分组注册表 */
|
|
82
|
+
env: Record<string, Record<string, string>>;
|
|
65
83
|
}
|
|
66
84
|
|
|
67
85
|
export type { ClientConfig, ResolvedConfig, ServiceConfig, ServiceDevConfig, SpecflowConfig };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schema.d.ts","sources":["../../src/config/schema.ts"],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,UAAU,YAAY;AACtB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK,gBAAgB;AACrB;AACA;AACA;AACA;AACA,UAAU,aAAa;AACvB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,UAAU,gBAAgB;AAC1B;AACA;AACA,UAAU,cAAc;AACxB;AACA,aAAa,YAAY;AACzB;AACA,cAAc,aAAa;AAC3B;AACA;AACA,UAAU,cAAc;AACxB,YAAY,QAAQ,CAAC,YAAY;AACjC,aAAa,QAAQ,CAAC,aAAa;AACnC;AACA;AACA;;;;","names":[]}
|
|
1
|
+
{"version":3,"file":"schema.d.ts","sources":["../../src/config/schema.ts"],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,UAAU,YAAY;AACtB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK,gBAAgB;AACrB;AACA;AACA;AACA;AACA,UAAU,aAAa;AACvB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,UAAU,gBAAgB;AAC1B;AACA;AACA,UAAU,cAAc;AACxB;AACA,aAAa,YAAY;AACzB;AACA,cAAc,aAAa;AAC3B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,UAAU,MAAM,SAAS,MAAM;AAC/B;AACA;AACA,UAAU,cAAc;AACxB,YAAY,QAAQ,CAAC,YAAY;AACjC,aAAa,QAAQ,CAAC,aAAa;AACnC;AACA;AACA;AACA,SAAS,MAAM,SAAS,MAAM;AAC9B;;;;","names":[]}
|
package/dist/orchestrator.d.ts
CHANGED
|
@@ -33,9 +33,10 @@ declare class ForgeService {
|
|
|
33
33
|
private config;
|
|
34
34
|
private cwd;
|
|
35
35
|
private running;
|
|
36
|
+
private envName?;
|
|
36
37
|
private clientHandle;
|
|
37
38
|
private goManager;
|
|
38
|
-
constructor(config: ResolvedConfig, cwd: string);
|
|
39
|
+
constructor(config: ResolvedConfig, cwd: string, envName?: string);
|
|
39
40
|
/** 停止所有服务 */
|
|
40
41
|
stop(): Promise<void>;
|
|
41
42
|
/** 获取状态 */
|
|
@@ -45,12 +46,14 @@ declare class ForgeService {
|
|
|
45
46
|
client?: boolean;
|
|
46
47
|
service?: boolean;
|
|
47
48
|
}): Promise<void>;
|
|
49
|
+
/** 按 preset 名称注入环境变量到 process.env */
|
|
50
|
+
private injectEnvPreset;
|
|
48
51
|
private getClientStatus;
|
|
49
52
|
private getServiceStatus;
|
|
50
53
|
private waitForPort;
|
|
51
54
|
private startGoService;
|
|
52
55
|
}
|
|
53
|
-
declare function createForgeService(cwd?: string, configPath?: string): Promise<ForgeService>;
|
|
56
|
+
declare function createForgeService(cwd?: string, configPath?: string, envName?: string): Promise<ForgeService>;
|
|
54
57
|
|
|
55
58
|
export { ForgeService, createForgeService };
|
|
56
59
|
export type { ForgeServiceStatus };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"orchestrator.d.ts","sources":["../src/orchestrator.ts"],"mappings":";;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA,UAAU,kBAAkB;AAC5B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,cAAc,YAAY;AAC1B;AACA;AACA;AACA;AACA;AACA;AACA,wBAAwB,cAAc;AACtC;AACA,YAAY,OAAO;AACnB;AACA,iBAAiB,kBAAkB;AACnC;AACA;AACA;AACA;AACA,QAAQ,OAAO;AACf;AACA;AACA;AACA;AACA;AACA,iBAAiB,kBAAkB,
|
|
1
|
+
{"version":3,"file":"orchestrator.d.ts","sources":["../src/orchestrator.ts"],"mappings":";;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA,UAAU,kBAAkB;AAC5B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,cAAc,YAAY;AAC1B;AACA;AACA;AACA;AACA;AACA;AACA;AACA,wBAAwB,cAAc;AACtC;AACA,YAAY,OAAO;AACnB;AACA,iBAAiB,kBAAkB;AACnC;AACA;AACA;AACA;AACA,QAAQ,OAAO;AACf;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iBAAiB,kBAAkB,uDAAuD,OAAO,CAAC,YAAY;;;;","names":[]}
|
package/dist/orchestrator.js
CHANGED
|
@@ -468,9 +468,10 @@ class ForgeService {
|
|
|
468
468
|
running = false;
|
|
469
469
|
clientHandle = null;
|
|
470
470
|
goManager = null;
|
|
471
|
-
constructor(config, cwd) {
|
|
471
|
+
constructor(config, cwd, envName) {
|
|
472
472
|
this.config = config;
|
|
473
473
|
this.cwd = cwd;
|
|
474
|
+
this.envName = envName;
|
|
474
475
|
}
|
|
475
476
|
|
|
476
477
|
/** 停止所有服务 */
|
|
@@ -507,6 +508,9 @@ class ForgeService {
|
|
|
507
508
|
...options
|
|
508
509
|
};
|
|
509
510
|
|
|
511
|
+
// === 第零步:按 preset 注入自定义环境变量(前端/Go 进程均可读取) ===
|
|
512
|
+
this.injectEnvPreset();
|
|
513
|
+
|
|
510
514
|
// === 第一步:启动 Go 后端(必须先就绪) ===
|
|
511
515
|
if (opt.service) {
|
|
512
516
|
await this.startGoService();
|
|
@@ -528,6 +532,25 @@ class ForgeService {
|
|
|
528
532
|
}
|
|
529
533
|
this.running = true;
|
|
530
534
|
}
|
|
535
|
+
|
|
536
|
+
/** 按 preset 名称注入环境变量到 process.env */
|
|
537
|
+
injectEnvPreset() {
|
|
538
|
+
const presets = this.config.env;
|
|
539
|
+
const presetKeys = Object.keys(presets);
|
|
540
|
+
if (presetKeys.length === 0) return;
|
|
541
|
+
|
|
542
|
+
// 确定使用哪个 preset
|
|
543
|
+
const name = this.envName || presetKeys[0];
|
|
544
|
+
const vars = presets[name];
|
|
545
|
+
if (!vars) {
|
|
546
|
+
logger.logError(`[specflow] 环境变量分组 "${name}" 不存在,可选: ${presetKeys.join(', ')}`);
|
|
547
|
+
return;
|
|
548
|
+
}
|
|
549
|
+
for (const [key, value] of Object.entries(vars)) {
|
|
550
|
+
process.env[key] = value;
|
|
551
|
+
}
|
|
552
|
+
logger.logProgress('specflow', 'env', `"${name}" (${Object.keys(vars).length} 个变量)`);
|
|
553
|
+
}
|
|
531
554
|
getClientStatus() {
|
|
532
555
|
const {
|
|
533
556
|
port
|
|
@@ -620,10 +643,10 @@ class ForgeService {
|
|
|
620
643
|
// 工厂函数
|
|
621
644
|
// ============================================================
|
|
622
645
|
|
|
623
|
-
async function createForgeService(cwd, configPath) {
|
|
646
|
+
async function createForgeService(cwd, configPath, envName) {
|
|
624
647
|
const root = cwd || process.cwd();
|
|
625
648
|
const config = configPath ? await loadConfigFromPath(configPath, root) : await loader.loadConfig(root);
|
|
626
|
-
return new ForgeService(config, root);
|
|
649
|
+
return new ForgeService(config, root, envName);
|
|
627
650
|
}
|
|
628
651
|
async function loadConfigFromPath(configPath, cwd) {
|
|
629
652
|
const {
|
|
@@ -641,6 +664,10 @@ async function loadConfigFromPath(configPath, cwd) {
|
|
|
641
664
|
...defaults.defaultConfig.service,
|
|
642
665
|
...(userConfig.service || {})
|
|
643
666
|
},
|
|
667
|
+
env: {
|
|
668
|
+
...defaults.defaultConfig.env,
|
|
669
|
+
...(userConfig.env || {})
|
|
670
|
+
},
|
|
644
671
|
configDir: cwd
|
|
645
672
|
};
|
|
646
673
|
}
|
package/dist/orchestrator.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"orchestrator.js","sources":["../src/orchestrator.ts"],"sourcesContent":["/**\n * ForgeService — 核心协调器\n *\n * 职责:\n * 1. 解析 specflow.config.ts 配置文件\n * 2. 前端启动逻辑(端口管理 + Vite 进程管理)\n * 3. 后端热更新逻辑(air)\n *\n * 日志原则:只输出关键信息,静默处理正常流程\n */\n\nimport { spawn, type ChildProcess, execSync } from 'node:child_process';\nimport { existsSync, writeFileSync, mkdirSync } from 'node:fs';\nimport { resolve } from 'node:path';\n\nimport { defaultConfig } from './config/defaults';\nimport { loadConfig } from './config/loader';\nimport { logProgress, logError } from './logger';\nimport { startClient, stopClient, type ClientHandle } from './runner';\n\nimport type { ResolvedConfig } from './config/schema';\n\n// ============================================================\n// 类型定义\n// ============================================================\n\nexport interface ForgeServiceStatus {\n running: boolean;\n config: { clientPort: number; servicePort: number };\n client: { port: number; running: boolean; pid?: number };\n service: { port: number; running: boolean; pid?: number };\n}\n\n// ============================================================\n// Go 进程管理器(基于 air,极致精简)\n// ============================================================\n\nclass GoProcessManager {\n private process: ChildProcess | null = null;\n private state: 'idle' | 'starting' | 'running' | 'stopped' = 'idle';\n private restartCount = 0;\n /** 端口真正就绪的 Promise(running 信号后开始等待) */\n private portReadyResolver: (() => void) | null = null;\n private portReadyPromise: Promise<void> | null = null;\n\n constructor(\n private serviceDir: string,\n private port: number,\n private env: Record<string, string | undefined>,\n private options?: { command?: string; args?: string[] },\n ) {}\n\n get isRunning(): boolean {\n return this.state === 'running' && this.process !== null && !this.process.killed;\n }\n\n get pid(): number | undefined {\n return this.process?.pid ?? undefined;\n }\n\n async start(): Promise<void> {\n if (this.state === 'starting' || this.state === 'running') return;\n this.state = 'starting';\n\n // 用户自定义命令优先\n if (this.options?.command) {\n await this.startCustom();\n return;\n }\n\n // 默认使用 air\n await this.startWithAir();\n }\n\n async stop(): Promise<void> {\n if (this.state === 'stopped' || this.state === 'idle') return;\n this.state = 'stopped';\n\n if (this.process) {\n this.killProcess();\n this.process = null;\n }\n\n this.state = 'idle';\n }\n\n /** 使用 air 启动 */\n private async startWithAir(): Promise<void> {\n // 检查并自动安装 air\n if (!(await this.ensureAirInstalled())) return;\n\n // 自动生成 .air.toml(不存在时)\n this.ensureAirToml();\n\n const args = this.buildAirArgs();\n\n this.process = spawn('air', args, {\n cwd: this.serviceDir,\n stdio: ['ignore', 'pipe', 'pipe'],\n env: this.env, // 不额外注入 PORT,由 Go 程序自身配置决定端口\n windowsHide: true,\n shell: process.platform === 'win32',\n });\n\n this.setupAirOutputHandler();\n\n // 创建端口就绪 Promise(output handler 的 running... 信号会触发 resolve)\n this.portReadyPromise = new Promise<void>((resolve) => {\n this.portReadyResolver = resolve;\n });\n\n // 等待 air 启动完成\n await new Promise<void>((res) => setTimeout(res, 1200));\n\n if (this.process && !this.process.killed) {\n this.state = 'running';\n this.restartCount++;\n // 等待端口真正就绪(覆盖 MySQL/Redis/tRPC 初始化窗口)\n await this.portReadyPromise;\n }\n }\n\n /**\n * 自动生成 .air.toml 配置文件(仅当不存在时)\n *\n * 设计原则:\n * - 生成的配置与用户手动编写的完全等价,无任何降级\n * - 平台自适应:Windows 生成 .exe,Linux/Mac 无后缀\n * - 输出同时写 stdout+stderr(forge-service 通过 pipe 捕获)\n */\n private ensureAirToml(): void {\n const tomlPath = resolve(this.serviceDir, '.air.toml');\n const binExt = process.platform === 'win32' ? '.exe' : '';\n const tmpDir = 'tmp';\n const binName = `./tmp/main${binExt}`;\n\n // 检测损坏的旧版本:如果文件存在但包含未替换的模板变量,则重新生成\n if (existsSync(tomlPath)) {\n try {\n const existing = require('node:fs').readFileSync(tomlPath, 'utf-8');\n if (existing.includes('${binExt}') || existing.includes('${tmpDir}')) {\n // 损坏的旧版 → 删除并重新生成\n require('node:fs').unlinkSync(tomlPath);\n } else {\n return; // 已有有效配置,不覆盖\n }\n } catch {\n /* 读取失败,重新生成 */\n }\n }\n\n // 确保 tmp 目录存在\n const tmpFullPath = resolve(this.serviceDir, tmpDir);\n if (!existsSync(tmpFullPath)) {\n mkdirSync(tmpFullPath, { recursive: true });\n }\n\n const tomlContent = [\n '# Air 配置文件 - Go 热更新(自动生成,可手动修改)',\n '',\n 'root = \".\"',\n `tmp_dir = \"${tmpDir}\"`,\n 'working_dir = \".\"',\n '',\n '[build]',\n ` entrypoint = \"${binName}\"`,\n ` cmd = \"go build -o ./tmp/main${binExt} .\"`,\n ' delay = 1000',\n ` exclude_dir = [\"${tmpDir}\", \"vendor\", \"client\", \"bin\", \"log\", \"node_modules\", \".git\"]`,\n ' include_ext = [\"go\", \"yaml\", \"yml\", \"json\", \"toml\", \"mod\", \"sum\"]',\n ' kill_delay = \"3s\"',\n ' build_delay = \"6s\"',\n ' log = \"\"',\n ' send_interrupt = true',\n ' stop_on_error = false',\n '',\n '[log]',\n ' time = false',\n ' outputs = [\"stdout\", \"stderr\"]',\n '',\n '[color]',\n ' main = \"magenta\"',\n ' watcher = \"cyan\"',\n ' build = \"yellow\"',\n ' runner = \"green\"',\n '',\n '[misc]',\n ' clean_on_exit = true',\n ].join('\\n');\n\n writeFileSync(tomlPath, tomlContent, 'utf-8');\n logProgress('go', 'config', `.air.toml 已生成 (${binName})`);\n }\n\n /** 构建 air 参数(始终使用 .air.toml) */\n private buildAirArgs(): string[] {\n // 始终使用项目中的 .air.toml(ensureAirToml 保证其存在)\n const args = ['-c', '.air.toml'];\n if (this.options?.args) args.push(...this.options.args);\n return args;\n }\n\n /** 检查并自动安装 air */\n private async ensureAirInstalled(): Promise<boolean> {\n // 兼容旧版 air(v1.65.x 用 -v,新版用 --version)\n const versionFlags = ['-v', '--version'];\n for (const flag of versionFlags) {\n try {\n execSync(`air ${flag}`, { stdio: 'pipe', timeout: 2000 });\n return true; // 已安装\n } catch {\n // 这个 flag 不支持,试下一个\n }\n }\n\n // 都没成功 → 尝试自动安装\n logProgress('go', 'installing air', 'go install github.com/air-verse/air@latest');\n\n try {\n await new Promise<void>((resolvePromise, reject) => {\n const installProc = spawn('go', ['install', 'github.com/air-verse/air@latest'], {\n stdio: 'pipe',\n env: this.env,\n windowsHide: true,\n });\n installProc.on('close', (code) => {\n if (code === 0) resolvePromise();\n else reject(new Error(`air 安装失败 (exit ${code})`));\n });\n installProc.on('error', reject);\n });\n\n // 验证安装\n for (const flag of versionFlags) {\n try {\n execSync(`air ${flag}`, { stdio: 'pipe', timeout: 2000 });\n return true;\n } catch {\n /* continue */\n }\n }\n throw new Error('安装后验证失败');\n } catch (err) {\n logError(`[go] air 安装失败: ${err instanceof Error ? err.message : String(err)}`);\n logError('[go] 请手动执行: go install github.com/air-verse/air@latest');\n this.state = 'idle';\n return false;\n }\n }\n\n /**\n * 处理 air 输出 — 用户友好模式\n *\n * 正常情况只显示:\n * [go] compiling... (编译进度)\n * [go] ✓ ready http://localhost:11080 (启动成功+端口)\n * [go] ✓ reloaded (热更新成功)\n *\n * 出错才显示:\n * [go] ✗ compile error: (编译失败,显示具体错误)\n * [go] ✗ crashed (运行时崩溃,显示panic)\n */\n private setupAirOutputHandler(): void {\n if (!this.process) return;\n const prefix = '\\x1b[36m[go]\\x1b[0m';\n const isTTY = process.stdout.isTTY === true;\n\n let phase: 'idle' | 'building' | 'running' | 'failed' = 'idle';\n let errorLines: string[] = []; // 编译错误(只在 building 收集)\n let buildDots = 0;\n let buildTimer: ReturnType<typeof setInterval> | null = null;\n\n const clearLine = () => {\n if (isTTY) process.stdout.write('\\r\\x1b[K');\n };\n\n const startBuildProgress = () => {\n if (buildTimer) return;\n buildDots = 0;\n if (isTTY) {\n buildTimer = setInterval(() => {\n buildDots = (buildDots + 1) % 4;\n process.stdout.write(`\\r\\x1b[K${prefix} compiling${'.'.repeat(buildDots)}${' '.repeat(3 - buildDots)}`);\n }, 300);\n } else {\n process.stdout.write(`${prefix} compiling...\\n`);\n }\n };\n\n const stopBuildProgress = () => {\n if (buildTimer) {\n clearInterval(buildTimer);\n buildTimer = null;\n }\n clearLine();\n };\n\n /** 等待端口真正就绪后输出 ready 并 resolve portReadyPromise */\n const waitForPortReady = () => {\n const { port } = this;\n const maxWait = 15000; // 最多等 15s(覆盖慢速 DB/Redis 初始化)\n const start = Date.now();\n const check = (): void => {\n // 先检查进程是否还活着(避免死循环)\n if (!this.process || this.process.killed) return;\n\n try {\n const socket = require('net').createConnection(port, '127.0.0.1');\n socket.on('connect', () => {\n socket.destroy();\n // 端口就绪 → 输出 + 通知 startWithAir 继续\n if ((this as unknown as { restartCount: number }).restartCount > 1) {\n console.log(`${prefix} \\x1b[32m✓ reloaded\\x1b[0m`);\n } else {\n console.log(`${prefix} \\x1b[32m✓ ready\\x1b[0m \\x1b[4mhttp://localhost:${port}\\x1b[0m`);\n }\n this.portReadyResolver?.();\n });\n socket.on('error', () => {\n socket.destroy();\n if (Date.now() - start < maxWait) setTimeout(check, 300);\n else {\n // 超时:仍然放行(可能是服务没监听此端口),打印警告\n console.log(\n `${prefix} \\x1b[33m⚠ port :${port} not responding in ${maxWait / 1000}s, proceeding anyway\\x1b[0m`,\n );\n this.portReadyResolver?.();\n }\n });\n setTimeout(() => {\n try {\n socket.destroy();\n } catch {\n /* noop */\n }\n }, 2000);\n } catch {\n // net 模块异常,直接放行\n this.portReadyResolver?.();\n }\n };\n check();\n };\n\n // ---- 核心行处理 ----\n const stripAnsi = (s: string) => s.replace(/\\x1b\\[[0-9;]*[a-zA-Z]/g, '').replace(/\\r/g, '');\n const stripAirPrefix = (s: string) => s.replace(/^[\\s]*[✗✓]?\\s*\\[air\\]\\s*/i, '');\n\n const isAirNoise = (t: string): boolean =>\n /^[_/\\\\ |]+$/.test(t) ||\n /^(watching|!exclude|cleaning|see you)/i.test(t) ||\n t.startsWith('air') ||\n /^v\\d+\\.\\d+/.test(t) ||\n (/^[|/_\\\\-]+/.test(t) && t.length < 40) ||\n /built with Go/i.test(t);\n\n const handlePhaseSignal = (t: string): boolean => {\n if (/^building\\.\\.\\./.test(t)) {\n phase = 'building';\n errorLines = [];\n startBuildProgress();\n return true;\n }\n if (/^running\\.\\.\\./.test(t)) {\n stopBuildProgress();\n phase = 'running';\n waitForPortReady();\n return true;\n }\n const exitMatch = t.match(/Process Exit with Code:\\s*(\\d+)/);\n if (exitMatch) {\n stopBuildProgress();\n const code = exitMatch[1];\n phase = code === '0' ? 'idle' : 'failed';\n if (code !== '0' && errorLines.length > 0) {\n console.log(`\\n${prefix} \\x1b[31m✗ compile error:\\x1b[0m`);\n for (const line of errorLines.slice(0, 10)) {\n console.log(` \\x1b[31m${line}\\x1b[0m`);\n }\n errorLines = [];\n }\n return true;\n }\n return false;\n };\n\n const handleBuildingPhase = (t: string): void => {\n if (/^\\d{4}-\\d{2}-\\d{2}/.test(t)) return;\n if (/\\.go:\\d+:\\d+:/.test(t) || /^#\\s/.test(t)) {\n errorLines.push(t);\n return;\n }\n if (\n /cannot\\s+(find|import)\\s+package|:\\s*undefined:|declared\\s+and\\s+not\\s+used|imported\\s+and\\s+not\\s+used/.test(\n t,\n )\n ) {\n errorLines.push(t);\n }\n };\n\n const handleLine = (raw: string) => {\n const t = stripAirPrefix(stripAnsi(raw)).trim();\n if (!t || isAirNoise(t)) return;\n if (handlePhaseSignal(t)) return;\n if (phase === 'building') handleBuildingPhase(t);\n };\n\n // ---- 绑定流 ----\n let buf = '';\n const drain = (chunk: Buffer) => {\n buf += chunk.toString();\n const lines = buf.split('\\n');\n buf = lines.pop() || '';\n for (const line of lines) handleLine(line);\n };\n this.process.stdout?.on('data', drain);\n this.process.stderr?.on('data', drain);\n\n this.process.on('error', () => {\n stopBuildProgress();\n this.state = 'idle';\n });\n this.process.on('exit', (_code, signal) => {\n stopBuildProgress();\n if (signal !== 'SIGTERM' && signal !== 'SIGINT') {\n logError(`[go] air stopped`);\n }\n this.process = null;\n this.state = 'idle';\n });\n }\n\n /** 自定义命令启动 */\n private async startCustom(): Promise<void> {\n const cmd = this.options.command;\n const args = this.options.args || [];\n\n this.process = spawn(cmd, args, {\n cwd: this.serviceDir,\n stdio: ['ignore', 'pipe', 'pipe'],\n env: this.env,\n windowsHide: true,\n shell: process.platform === 'win32',\n });\n\n this.setupCustomOutputHandler(cmd);\n\n await new Promise<void>((res) => setTimeout(res, 1500));\n\n if (this.process && !this.process.killed) {\n this.state = 'running';\n this.restartCount++;\n logProgress('go', 'ready', `http://localhost:${this.port} (${cmd})`);\n }\n }\n\n private setupCustomOutputHandler(cmd: string): void {\n if (!this.process) return;\n\n const prefix = `\\x1b[36m[go]\\x1b[0m`;\n\n // ---- 绑定 stdout + stderr,复用 handleLine 过滤 ----\n let buf = '';\n const flush = () => {\n if (!buf.trim()) {\n buf = '';\n return;\n }\n for (const line of buf.split('\\n')) {\n const t = line.trim();\n if (!t) continue;\n // 自定义命令:透传关键信息,过滤噪音\n if (/launch\\s+success|listening|serving|started|ready|error|panic|fatal/i.test(t)) {\n console.log(`${prefix} ${t}`);\n }\n }\n buf = '';\n };\n\n this.process.stdout?.on('data', (d: Buffer) => {\n buf += d.toString();\n const nl = buf.lastIndexOf('\\n');\n if (nl !== -1) {\n const chunk = buf.slice(0, nl);\n buf = buf.slice(nl + 1);\n for (const line of chunk.split('\\n')) {\n const t = line.trim();\n if (!t) continue;\n if (/launch\\s+success|listening|serving|started|ready|error|panic|fatal/i.test(t)) {\n console.log(`${prefix} ${t}`);\n }\n }\n }\n });\n\n this.process.stderr?.on('data', (d: Buffer) => {\n const text = d.toString().trim();\n if (text) logError(`[${cmd}] ${text}`);\n });\n\n this.process.on('error', (err) => {\n logError(`[go] ${err.message}`);\n this.state = 'idle';\n });\n\n this.process.on('exit', () => {\n flush();\n this.process = null;\n this.state = 'idle';\n });\n }\n\n private killProcess(): void {\n if (!this.process || this.process.killed) return;\n\n try {\n if (process.platform === 'win32') {\n execSync(`taskkill /PID ${this.process.pid} /T /F`, {\n stdio: 'pipe',\n timeout: 5000,\n windowsHide: true,\n });\n } else {\n this.process.kill('SIGTERM');\n // 给进程 1 秒优雅退出\n setTimeout(() => {\n if (this.process && !this.process.killed) {\n this.process.kill('SIGKILL');\n }\n }, 1000);\n }\n } catch {\n // 进程可能已退出,忽略错误\n }\n }\n}\n\n// ============================================================\n// ForgeService 主类\n// ============================================================\n\nexport class ForgeService {\n public onLog?: (level: 'info' | 'warn' | 'error' | 'success', msg: string) => void;\n\n private config: ResolvedConfig;\n private cwd: string;\n private running = false;\n\n private clientHandle: ClientHandle | null = null;\n private goManager: GoProcessManager | null = null;\n\n constructor(config: ResolvedConfig, cwd: string) {\n this.config = config;\n this.cwd = cwd;\n }\n\n /** 停止所有服务 */\n async stop(): Promise<void> {\n if (this.goManager) {\n await this.goManager.stop();\n this.goManager = null;\n }\n if (this.clientHandle) {\n stopClient(this.clientHandle);\n this.clientHandle = null;\n }\n this.running = false;\n }\n\n /** 获取状态 */\n getStatus(): ForgeServiceStatus {\n return {\n running: this.running,\n config: { clientPort: this.config.client.port, servicePort: this.config.service.port },\n client: this.getClientStatus(),\n service: this.getServiceStatus(),\n };\n }\n\n /** 启动所有服务(Go 后端先启动,前端后启动) */\n async start(options?: { client?: boolean; service?: boolean }): Promise<void> {\n const opt = { client: true, service: true, ...options };\n\n // === 第一步:启动 Go 后端(必须先就绪) ===\n if (opt.service) {\n await this.startGoService();\n }\n\n // === 第二步:等待 Go 后端 ready(最多 10 秒) ===\n if (opt.service && this.goManager) {\n const goPort = this.config.service.port;\n await this.waitForPort(goPort, 10000);\n }\n\n // === 第三步:启动前端 ===\n if (opt.client) {\n const clientConfig = {\n port: this.config.client.port,\n dir: resolve(this.cwd, this.config.client.dir),\n };\n this.clientHandle = startClient(clientConfig);\n }\n\n this.running = true;\n }\n\n private getClientStatus(): ForgeServiceStatus['client'] {\n const { port } = this.config.client;\n const pid = this.clientHandle?.child?.pid;\n return { port, running: pid !== null && pid !== undefined, pid };\n }\n\n private getServiceStatus(): ForgeServiceStatus['service'] {\n const { port } = this.config.service;\n const pid = this.goManager?.pid;\n return { port, running: this.goManager?.isRunning ?? false, pid };\n }\n\n private async waitForPort(port: number, timeoutMs: number): Promise<void> {\n const start = Date.now();\n while (Date.now() - start < timeoutMs) {\n try {\n const socket = require('net').createConnection(port, '127.0.0.1');\n await new Promise<void>((resolve, reject) => {\n socket.on('connect', () => {\n socket.destroy();\n resolve();\n });\n socket.on('error', reject);\n setTimeout(() => {\n socket.destroy();\n reject(new Error('timeout'));\n }, 2000);\n });\n return; // 端口可达\n } catch {\n // 端口未就绪,等 500ms 再试\n await new Promise((r) => setTimeout(r, 500));\n }\n }\n }\n\n // ---- Go 服务启动 ----\n\n private async startGoService(): Promise<void> {\n const serviceDir = resolve(this.cwd, this.config.service.dir);\n\n if (!existsSync(serviceDir)) return;\n\n // 检查 main.go 或 go.mod 是否存在\n const hasMainGo = existsSync(resolve(serviceDir, 'main.go'));\n const hasGoMod = existsSync(resolve(serviceDir, 'go.mod'));\n if (!hasMainGo && !hasGoMod) return;\n\n const goEnv = {\n ...process.env,\n // 不注入 PORT 环境变量 — 让 Go 程序使用自身配置文件(yaml/toml)中的端口设置\n // 强制注入 PORT 会导致 tRPC 等框架的行为与直接运行 air 时不一致\n };\n\n // 解析 dev 配置\n const { dev } = this.config.service;\n\n let devOpts: { command?: string; args?: string[] } | undefined;\n\n if (typeof dev === 'string' && dev !== 'air') {\n // \"make dev\" 或 \"./scripts/dev.sh\"(显式自定义命令)\n // 注意:'air' 是保留字,表示使用内置 air 管理(走 startWithAir 路径)\n devOpts = { command: dev };\n } else if (dev && typeof dev === 'object') {\n // { command: 'make', args: ['dev'] }\n devOpts = dev;\n }\n // dev === 'air' 或 dev 未配置 → 默认使用内置 startWithAir()\n\n this.goManager = new GoProcessManager(serviceDir, this.config.service.port, goEnv, devOpts);\n\n try {\n await this.goManager.start();\n } catch (err) {\n logError(`[go] ${err instanceof Error ? err.message : String(err)}`);\n }\n }\n}\n\n// ============================================================\n// 工厂函数\n// ============================================================\n\nexport async function createForgeService(cwd?: string, configPath?: string): Promise<ForgeService> {\n const root = cwd || process.cwd();\n const config = configPath ? await loadConfigFromPath(configPath, root) : await loadConfig(root);\n return new ForgeService(config, root);\n}\n\nasync function loadConfigFromPath(configPath: string, cwd: string): Promise<ResolvedConfig> {\n const { parseConfig } = await import('confmix');\n const { config: userConfig } = await parseConfig<Partial<ResolvedConfig>>(configPath);\n return {\n client: { ...defaultConfig.client, ...(userConfig.client || {}) },\n service: { ...defaultConfig.service, ...(userConfig.service || {}) },\n configDir: cwd,\n };\n}\n"],"names":["GoProcessManager","process","state","restartCount","portReadyResolver","portReadyPromise","constructor","serviceDir","port","env","options","isRunning","killed","pid","undefined","start","command","startCustom","startWithAir","stop","killProcess","ensureAirInstalled","ensureAirToml","args","buildAirArgs","spawn","cwd","stdio","windowsHide","shell","platform","setupAirOutputHandler","Promise","resolve","res","setTimeout","tomlPath","binExt","tmpDir","binName","existsSync","existing","require","readFileSync","includes","unlinkSync","tmpFullPath","mkdirSync","recursive","tomlContent","join","writeFileSync","logProgress","push","versionFlags","flag","execSync","timeout","resolvePromise","reject","installProc","on","code","Error","err","logError","message","String","prefix","isTTY","stdout","phase","errorLines","buildDots","buildTimer","clearLine","write","startBuildProgress","setInterval","repeat","stopBuildProgress","clearInterval","waitForPortReady","maxWait","Date","now","check","socket","createConnection","destroy","console","log","stripAnsi","s","replace","stripAirPrefix","isAirNoise","t","test","startsWith","length","handlePhaseSignal","exitMatch","match","line","slice","handleBuildingPhase","handleLine","raw","trim","buf","drain","chunk","toString","lines","split","pop","stderr","_code","signal","cmd","setupCustomOutputHandler","flush","d","nl","lastIndexOf","text","kill","ForgeService","running","clientHandle","goManager","config","stopClient","getStatus","clientPort","client","servicePort","service","getClientStatus","getServiceStatus","opt","startGoService","goPort","waitForPort","clientConfig","dir","startClient","child","timeoutMs","r","hasMainGo","hasGoMod","goEnv","dev","devOpts","createForgeService","configPath","root","loadConfigFromPath","loadConfig","parseConfig","userConfig","defaultConfig","configDir"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"orchestrator.js","sources":["../src/orchestrator.ts"],"sourcesContent":["/**\n * ForgeService — 核心协调器\n *\n * 职责:\n * 1. 解析 specflow.config.ts 配置文件\n * 2. 前端启动逻辑(端口管理 + Vite 进程管理)\n * 3. 后端热更新逻辑(air)\n *\n * 日志原则:只输出关键信息,静默处理正常流程\n */\n\nimport { spawn, type ChildProcess, execSync } from 'node:child_process';\nimport { existsSync, writeFileSync, mkdirSync } from 'node:fs';\nimport { resolve } from 'node:path';\n\nimport { defaultConfig } from './config/defaults';\nimport { loadConfig } from './config/loader';\nimport { logProgress, logError } from './logger';\nimport { startClient, stopClient, type ClientHandle } from './runner';\n\nimport type { ResolvedConfig } from './config/schema';\n\n// ============================================================\n// 类型定义\n// ============================================================\n\nexport interface ForgeServiceStatus {\n running: boolean;\n config: { clientPort: number; servicePort: number };\n client: { port: number; running: boolean; pid?: number };\n service: { port: number; running: boolean; pid?: number };\n}\n\n// ============================================================\n// Go 进程管理器(基于 air,极致精简)\n// ============================================================\n\nclass GoProcessManager {\n private process: ChildProcess | null = null;\n private state: 'idle' | 'starting' | 'running' | 'stopped' = 'idle';\n private restartCount = 0;\n /** 端口真正就绪的 Promise(running 信号后开始等待) */\n private portReadyResolver: (() => void) | null = null;\n private portReadyPromise: Promise<void> | null = null;\n\n constructor(\n private serviceDir: string,\n private port: number,\n private env: Record<string, string | undefined>,\n private options?: { command?: string; args?: string[] },\n ) {}\n\n get isRunning(): boolean {\n return this.state === 'running' && this.process !== null && !this.process.killed;\n }\n\n get pid(): number | undefined {\n return this.process?.pid ?? undefined;\n }\n\n async start(): Promise<void> {\n if (this.state === 'starting' || this.state === 'running') return;\n this.state = 'starting';\n\n // 用户自定义命令优先\n if (this.options?.command) {\n await this.startCustom();\n return;\n }\n\n // 默认使用 air\n await this.startWithAir();\n }\n\n async stop(): Promise<void> {\n if (this.state === 'stopped' || this.state === 'idle') return;\n this.state = 'stopped';\n\n if (this.process) {\n this.killProcess();\n this.process = null;\n }\n\n this.state = 'idle';\n }\n\n /** 使用 air 启动 */\n private async startWithAir(): Promise<void> {\n // 检查并自动安装 air\n if (!(await this.ensureAirInstalled())) return;\n\n // 自动生成 .air.toml(不存在时)\n this.ensureAirToml();\n\n const args = this.buildAirArgs();\n\n this.process = spawn('air', args, {\n cwd: this.serviceDir,\n stdio: ['ignore', 'pipe', 'pipe'],\n env: this.env, // 不额外注入 PORT,由 Go 程序自身配置决定端口\n windowsHide: true,\n shell: process.platform === 'win32',\n });\n\n this.setupAirOutputHandler();\n\n // 创建端口就绪 Promise(output handler 的 running... 信号会触发 resolve)\n this.portReadyPromise = new Promise<void>((resolve) => {\n this.portReadyResolver = resolve;\n });\n\n // 等待 air 启动完成\n await new Promise<void>((res) => setTimeout(res, 1200));\n\n if (this.process && !this.process.killed) {\n this.state = 'running';\n this.restartCount++;\n // 等待端口真正就绪(覆盖 MySQL/Redis/tRPC 初始化窗口)\n await this.portReadyPromise;\n }\n }\n\n /**\n * 自动生成 .air.toml 配置文件(仅当不存在时)\n *\n * 设计原则:\n * - 生成的配置与用户手动编写的完全等价,无任何降级\n * - 平台自适应:Windows 生成 .exe,Linux/Mac 无后缀\n * - 输出同时写 stdout+stderr(forge-service 通过 pipe 捕获)\n */\n private ensureAirToml(): void {\n const tomlPath = resolve(this.serviceDir, '.air.toml');\n const binExt = process.platform === 'win32' ? '.exe' : '';\n const tmpDir = 'tmp';\n const binName = `./tmp/main${binExt}`;\n\n // 检测损坏的旧版本:如果文件存在但包含未替换的模板变量,则重新生成\n if (existsSync(tomlPath)) {\n try {\n const existing = require('node:fs').readFileSync(tomlPath, 'utf-8');\n if (existing.includes('${binExt}') || existing.includes('${tmpDir}')) {\n // 损坏的旧版 → 删除并重新生成\n require('node:fs').unlinkSync(tomlPath);\n } else {\n return; // 已有有效配置,不覆盖\n }\n } catch {\n /* 读取失败,重新生成 */\n }\n }\n\n // 确保 tmp 目录存在\n const tmpFullPath = resolve(this.serviceDir, tmpDir);\n if (!existsSync(tmpFullPath)) {\n mkdirSync(tmpFullPath, { recursive: true });\n }\n\n const tomlContent = [\n '# Air 配置文件 - Go 热更新(自动生成,可手动修改)',\n '',\n 'root = \".\"',\n `tmp_dir = \"${tmpDir}\"`,\n 'working_dir = \".\"',\n '',\n '[build]',\n ` entrypoint = \"${binName}\"`,\n ` cmd = \"go build -o ./tmp/main${binExt} .\"`,\n ' delay = 1000',\n ` exclude_dir = [\"${tmpDir}\", \"vendor\", \"client\", \"bin\", \"log\", \"node_modules\", \".git\"]`,\n ' include_ext = [\"go\", \"yaml\", \"yml\", \"json\", \"toml\", \"mod\", \"sum\"]',\n ' kill_delay = \"3s\"',\n ' build_delay = \"6s\"',\n ' log = \"\"',\n ' send_interrupt = true',\n ' stop_on_error = false',\n '',\n '[log]',\n ' time = false',\n ' outputs = [\"stdout\", \"stderr\"]',\n '',\n '[color]',\n ' main = \"magenta\"',\n ' watcher = \"cyan\"',\n ' build = \"yellow\"',\n ' runner = \"green\"',\n '',\n '[misc]',\n ' clean_on_exit = true',\n ].join('\\n');\n\n writeFileSync(tomlPath, tomlContent, 'utf-8');\n logProgress('go', 'config', `.air.toml 已生成 (${binName})`);\n }\n\n /** 构建 air 参数(始终使用 .air.toml) */\n private buildAirArgs(): string[] {\n // 始终使用项目中的 .air.toml(ensureAirToml 保证其存在)\n const args = ['-c', '.air.toml'];\n if (this.options?.args) args.push(...this.options.args);\n return args;\n }\n\n /** 检查并自动安装 air */\n private async ensureAirInstalled(): Promise<boolean> {\n // 兼容旧版 air(v1.65.x 用 -v,新版用 --version)\n const versionFlags = ['-v', '--version'];\n for (const flag of versionFlags) {\n try {\n execSync(`air ${flag}`, { stdio: 'pipe', timeout: 2000 });\n return true; // 已安装\n } catch {\n // 这个 flag 不支持,试下一个\n }\n }\n\n // 都没成功 → 尝试自动安装\n logProgress('go', 'installing air', 'go install github.com/air-verse/air@latest');\n\n try {\n await new Promise<void>((resolvePromise, reject) => {\n const installProc = spawn('go', ['install', 'github.com/air-verse/air@latest'], {\n stdio: 'pipe',\n env: this.env,\n windowsHide: true,\n });\n installProc.on('close', (code) => {\n if (code === 0) resolvePromise();\n else reject(new Error(`air 安装失败 (exit ${code})`));\n });\n installProc.on('error', reject);\n });\n\n // 验证安装\n for (const flag of versionFlags) {\n try {\n execSync(`air ${flag}`, { stdio: 'pipe', timeout: 2000 });\n return true;\n } catch {\n /* continue */\n }\n }\n throw new Error('安装后验证失败');\n } catch (err) {\n logError(`[go] air 安装失败: ${err instanceof Error ? err.message : String(err)}`);\n logError('[go] 请手动执行: go install github.com/air-verse/air@latest');\n this.state = 'idle';\n return false;\n }\n }\n\n /**\n * 处理 air 输出 — 用户友好模式\n *\n * 正常情况只显示:\n * [go] compiling... (编译进度)\n * [go] ✓ ready http://localhost:11080 (启动成功+端口)\n * [go] ✓ reloaded (热更新成功)\n *\n * 出错才显示:\n * [go] ✗ compile error: (编译失败,显示具体错误)\n * [go] ✗ crashed (运行时崩溃,显示panic)\n */\n private setupAirOutputHandler(): void {\n if (!this.process) return;\n const prefix = '\\x1b[36m[go]\\x1b[0m';\n const isTTY = process.stdout.isTTY === true;\n\n let phase: 'idle' | 'building' | 'running' | 'failed' = 'idle';\n let errorLines: string[] = []; // 编译错误(只在 building 收集)\n let buildDots = 0;\n let buildTimer: ReturnType<typeof setInterval> | null = null;\n\n const clearLine = () => {\n if (isTTY) process.stdout.write('\\r\\x1b[K');\n };\n\n const startBuildProgress = () => {\n if (buildTimer) return;\n buildDots = 0;\n if (isTTY) {\n buildTimer = setInterval(() => {\n buildDots = (buildDots + 1) % 4;\n process.stdout.write(`\\r\\x1b[K${prefix} compiling${'.'.repeat(buildDots)}${' '.repeat(3 - buildDots)}`);\n }, 300);\n } else {\n process.stdout.write(`${prefix} compiling...\\n`);\n }\n };\n\n const stopBuildProgress = () => {\n if (buildTimer) {\n clearInterval(buildTimer);\n buildTimer = null;\n }\n clearLine();\n };\n\n /** 等待端口真正就绪后输出 ready 并 resolve portReadyPromise */\n const waitForPortReady = () => {\n const { port } = this;\n const maxWait = 15000; // 最多等 15s(覆盖慢速 DB/Redis 初始化)\n const start = Date.now();\n const check = (): void => {\n // 先检查进程是否还活着(避免死循环)\n if (!this.process || this.process.killed) return;\n\n try {\n const socket = require('net').createConnection(port, '127.0.0.1');\n socket.on('connect', () => {\n socket.destroy();\n // 端口就绪 → 输出 + 通知 startWithAir 继续\n if ((this as unknown as { restartCount: number }).restartCount > 1) {\n console.log(`${prefix} \\x1b[32m✓ reloaded\\x1b[0m`);\n } else {\n console.log(`${prefix} \\x1b[32m✓ ready\\x1b[0m \\x1b[4mhttp://localhost:${port}\\x1b[0m`);\n }\n this.portReadyResolver?.();\n });\n socket.on('error', () => {\n socket.destroy();\n if (Date.now() - start < maxWait) setTimeout(check, 300);\n else {\n // 超时:仍然放行(可能是服务没监听此端口),打印警告\n console.log(\n `${prefix} \\x1b[33m⚠ port :${port} not responding in ${maxWait / 1000}s, proceeding anyway\\x1b[0m`,\n );\n this.portReadyResolver?.();\n }\n });\n setTimeout(() => {\n try {\n socket.destroy();\n } catch {\n /* noop */\n }\n }, 2000);\n } catch {\n // net 模块异常,直接放行\n this.portReadyResolver?.();\n }\n };\n check();\n };\n\n // ---- 核心行处理 ----\n const stripAnsi = (s: string) => s.replace(/\\x1b\\[[0-9;]*[a-zA-Z]/g, '').replace(/\\r/g, '');\n const stripAirPrefix = (s: string) => s.replace(/^[\\s]*[✗✓]?\\s*\\[air\\]\\s*/i, '');\n\n const isAirNoise = (t: string): boolean =>\n /^[_/\\\\ |]+$/.test(t) ||\n /^(watching|!exclude|cleaning|see you)/i.test(t) ||\n t.startsWith('air') ||\n /^v\\d+\\.\\d+/.test(t) ||\n (/^[|/_\\\\-]+/.test(t) && t.length < 40) ||\n /built with Go/i.test(t);\n\n const handlePhaseSignal = (t: string): boolean => {\n if (/^building\\.\\.\\./.test(t)) {\n phase = 'building';\n errorLines = [];\n startBuildProgress();\n return true;\n }\n if (/^running\\.\\.\\./.test(t)) {\n stopBuildProgress();\n phase = 'running';\n waitForPortReady();\n return true;\n }\n const exitMatch = t.match(/Process Exit with Code:\\s*(\\d+)/);\n if (exitMatch) {\n stopBuildProgress();\n const code = exitMatch[1];\n phase = code === '0' ? 'idle' : 'failed';\n if (code !== '0' && errorLines.length > 0) {\n console.log(`\\n${prefix} \\x1b[31m✗ compile error:\\x1b[0m`);\n for (const line of errorLines.slice(0, 10)) {\n console.log(` \\x1b[31m${line}\\x1b[0m`);\n }\n errorLines = [];\n }\n return true;\n }\n return false;\n };\n\n const handleBuildingPhase = (t: string): void => {\n if (/^\\d{4}-\\d{2}-\\d{2}/.test(t)) return;\n if (/\\.go:\\d+:\\d+:/.test(t) || /^#\\s/.test(t)) {\n errorLines.push(t);\n return;\n }\n if (\n /cannot\\s+(find|import)\\s+package|:\\s*undefined:|declared\\s+and\\s+not\\s+used|imported\\s+and\\s+not\\s+used/.test(\n t,\n )\n ) {\n errorLines.push(t);\n }\n };\n\n const handleLine = (raw: string) => {\n const t = stripAirPrefix(stripAnsi(raw)).trim();\n if (!t || isAirNoise(t)) return;\n if (handlePhaseSignal(t)) return;\n if (phase === 'building') handleBuildingPhase(t);\n };\n\n // ---- 绑定流 ----\n let buf = '';\n const drain = (chunk: Buffer) => {\n buf += chunk.toString();\n const lines = buf.split('\\n');\n buf = lines.pop() || '';\n for (const line of lines) handleLine(line);\n };\n this.process.stdout?.on('data', drain);\n this.process.stderr?.on('data', drain);\n\n this.process.on('error', () => {\n stopBuildProgress();\n this.state = 'idle';\n });\n this.process.on('exit', (_code, signal) => {\n stopBuildProgress();\n if (signal !== 'SIGTERM' && signal !== 'SIGINT') {\n logError(`[go] air stopped`);\n }\n this.process = null;\n this.state = 'idle';\n });\n }\n\n /** 自定义命令启动 */\n private async startCustom(): Promise<void> {\n const cmd = this.options.command;\n const args = this.options.args || [];\n\n this.process = spawn(cmd, args, {\n cwd: this.serviceDir,\n stdio: ['ignore', 'pipe', 'pipe'],\n env: this.env,\n windowsHide: true,\n shell: process.platform === 'win32',\n });\n\n this.setupCustomOutputHandler(cmd);\n\n await new Promise<void>((res) => setTimeout(res, 1500));\n\n if (this.process && !this.process.killed) {\n this.state = 'running';\n this.restartCount++;\n logProgress('go', 'ready', `http://localhost:${this.port} (${cmd})`);\n }\n }\n\n private setupCustomOutputHandler(cmd: string): void {\n if (!this.process) return;\n\n const prefix = `\\x1b[36m[go]\\x1b[0m`;\n\n // ---- 绑定 stdout + stderr,复用 handleLine 过滤 ----\n let buf = '';\n const flush = () => {\n if (!buf.trim()) {\n buf = '';\n return;\n }\n for (const line of buf.split('\\n')) {\n const t = line.trim();\n if (!t) continue;\n // 自定义命令:透传关键信息,过滤噪音\n if (/launch\\s+success|listening|serving|started|ready|error|panic|fatal/i.test(t)) {\n console.log(`${prefix} ${t}`);\n }\n }\n buf = '';\n };\n\n this.process.stdout?.on('data', (d: Buffer) => {\n buf += d.toString();\n const nl = buf.lastIndexOf('\\n');\n if (nl !== -1) {\n const chunk = buf.slice(0, nl);\n buf = buf.slice(nl + 1);\n for (const line of chunk.split('\\n')) {\n const t = line.trim();\n if (!t) continue;\n if (/launch\\s+success|listening|serving|started|ready|error|panic|fatal/i.test(t)) {\n console.log(`${prefix} ${t}`);\n }\n }\n }\n });\n\n this.process.stderr?.on('data', (d: Buffer) => {\n const text = d.toString().trim();\n if (text) logError(`[${cmd}] ${text}`);\n });\n\n this.process.on('error', (err) => {\n logError(`[go] ${err.message}`);\n this.state = 'idle';\n });\n\n this.process.on('exit', () => {\n flush();\n this.process = null;\n this.state = 'idle';\n });\n }\n\n private killProcess(): void {\n if (!this.process || this.process.killed) return;\n\n try {\n if (process.platform === 'win32') {\n execSync(`taskkill /PID ${this.process.pid} /T /F`, {\n stdio: 'pipe',\n timeout: 5000,\n windowsHide: true,\n });\n } else {\n this.process.kill('SIGTERM');\n // 给进程 1 秒优雅退出\n setTimeout(() => {\n if (this.process && !this.process.killed) {\n this.process.kill('SIGKILL');\n }\n }, 1000);\n }\n } catch {\n // 进程可能已退出,忽略错误\n }\n }\n}\n\n// ============================================================\n// ForgeService 主类\n// ============================================================\n\nexport class ForgeService {\n public onLog?: (level: 'info' | 'warn' | 'error' | 'success', msg: string) => void;\n\n private config: ResolvedConfig;\n private cwd: string;\n private running = false;\n private envName?: string;\n\n private clientHandle: ClientHandle | null = null;\n private goManager: GoProcessManager | null = null;\n\n constructor(config: ResolvedConfig, cwd: string, envName?: string) {\n this.config = config;\n this.cwd = cwd;\n this.envName = envName;\n }\n\n /** 停止所有服务 */\n async stop(): Promise<void> {\n if (this.goManager) {\n await this.goManager.stop();\n this.goManager = null;\n }\n if (this.clientHandle) {\n stopClient(this.clientHandle);\n this.clientHandle = null;\n }\n this.running = false;\n }\n\n /** 获取状态 */\n getStatus(): ForgeServiceStatus {\n return {\n running: this.running,\n config: { clientPort: this.config.client.port, servicePort: this.config.service.port },\n client: this.getClientStatus(),\n service: this.getServiceStatus(),\n };\n }\n\n /** 启动所有服务(Go 后端先启动,前端后启动) */\n async start(options?: { client?: boolean; service?: boolean }): Promise<void> {\n const opt = { client: true, service: true, ...options };\n\n // === 第零步:按 preset 注入自定义环境变量(前端/Go 进程均可读取) ===\n this.injectEnvPreset();\n\n // === 第一步:启动 Go 后端(必须先就绪) ===\n if (opt.service) {\n await this.startGoService();\n }\n\n // === 第二步:等待 Go 后端 ready(最多 10 秒) ===\n if (opt.service && this.goManager) {\n const goPort = this.config.service.port;\n await this.waitForPort(goPort, 10000);\n }\n\n // === 第三步:启动前端 ===\n if (opt.client) {\n const clientConfig = {\n port: this.config.client.port,\n dir: resolve(this.cwd, this.config.client.dir),\n };\n this.clientHandle = startClient(clientConfig);\n }\n\n this.running = true;\n }\n\n /** 按 preset 名称注入环境变量到 process.env */\n private injectEnvPreset(): void {\n const presets = this.config.env;\n const presetKeys = Object.keys(presets);\n if (presetKeys.length === 0) return;\n\n // 确定使用哪个 preset\n const name = this.envName || presetKeys[0];\n const vars = presets[name];\n if (!vars) {\n logError(`[specflow] 环境变量分组 \"${name}\" 不存在,可选: ${presetKeys.join(', ')}`);\n return;\n }\n\n for (const [key, value] of Object.entries(vars)) {\n process.env[key] = value;\n }\n logProgress('specflow', 'env', `\"${name}\" (${Object.keys(vars).length} 个变量)`);\n }\n\n private getClientStatus(): ForgeServiceStatus['client'] {\n const { port } = this.config.client;\n const pid = this.clientHandle?.child?.pid;\n return { port, running: pid !== null && pid !== undefined, pid };\n }\n\n private getServiceStatus(): ForgeServiceStatus['service'] {\n const { port } = this.config.service;\n const pid = this.goManager?.pid;\n return { port, running: this.goManager?.isRunning ?? false, pid };\n }\n\n private async waitForPort(port: number, timeoutMs: number): Promise<void> {\n const start = Date.now();\n while (Date.now() - start < timeoutMs) {\n try {\n const socket = require('net').createConnection(port, '127.0.0.1');\n await new Promise<void>((resolve, reject) => {\n socket.on('connect', () => {\n socket.destroy();\n resolve();\n });\n socket.on('error', reject);\n setTimeout(() => {\n socket.destroy();\n reject(new Error('timeout'));\n }, 2000);\n });\n return; // 端口可达\n } catch {\n // 端口未就绪,等 500ms 再试\n await new Promise((r) => setTimeout(r, 500));\n }\n }\n }\n\n // ---- Go 服务启动 ----\n\n private async startGoService(): Promise<void> {\n const serviceDir = resolve(this.cwd, this.config.service.dir);\n\n if (!existsSync(serviceDir)) return;\n\n // 检查 main.go 或 go.mod 是否存在\n const hasMainGo = existsSync(resolve(serviceDir, 'main.go'));\n const hasGoMod = existsSync(resolve(serviceDir, 'go.mod'));\n if (!hasMainGo && !hasGoMod) return;\n\n const goEnv = {\n ...process.env,\n // 不注入 PORT 环境变量 — 让 Go 程序使用自身配置文件(yaml/toml)中的端口设置\n // 强制注入 PORT 会导致 tRPC 等框架的行为与直接运行 air 时不一致\n };\n\n // 解析 dev 配置\n const { dev } = this.config.service;\n\n let devOpts: { command?: string; args?: string[] } | undefined;\n\n if (typeof dev === 'string' && dev !== 'air') {\n // \"make dev\" 或 \"./scripts/dev.sh\"(显式自定义命令)\n // 注意:'air' 是保留字,表示使用内置 air 管理(走 startWithAir 路径)\n devOpts = { command: dev };\n } else if (dev && typeof dev === 'object') {\n // { command: 'make', args: ['dev'] }\n devOpts = dev;\n }\n // dev === 'air' 或 dev 未配置 → 默认使用内置 startWithAir()\n\n this.goManager = new GoProcessManager(serviceDir, this.config.service.port, goEnv, devOpts);\n\n try {\n await this.goManager.start();\n } catch (err) {\n logError(`[go] ${err instanceof Error ? err.message : String(err)}`);\n }\n }\n}\n\n// ============================================================\n// 工厂函数\n// ============================================================\n\nexport async function createForgeService(cwd?: string, configPath?: string, envName?: string): Promise<ForgeService> {\n const root = cwd || process.cwd();\n const config = configPath ? await loadConfigFromPath(configPath, root) : await loadConfig(root);\n return new ForgeService(config, root, envName);\n}\n\nasync function loadConfigFromPath(configPath: string, cwd: string): Promise<ResolvedConfig> {\n const { parseConfig } = await import('confmix');\n const { config: userConfig } = await parseConfig<Partial<ResolvedConfig>>(configPath);\n return {\n client: { ...defaultConfig.client, ...(userConfig.client || {}) },\n service: { ...defaultConfig.service, ...(userConfig.service || {}) },\n env: { ...defaultConfig.env, ...(userConfig.env || {}) },\n configDir: cwd,\n };\n}\n"],"names":["GoProcessManager","process","state","restartCount","portReadyResolver","portReadyPromise","constructor","serviceDir","port","env","options","isRunning","killed","pid","undefined","start","command","startCustom","startWithAir","stop","killProcess","ensureAirInstalled","ensureAirToml","args","buildAirArgs","spawn","cwd","stdio","windowsHide","shell","platform","setupAirOutputHandler","Promise","resolve","res","setTimeout","tomlPath","binExt","tmpDir","binName","existsSync","existing","require","readFileSync","includes","unlinkSync","tmpFullPath","mkdirSync","recursive","tomlContent","join","writeFileSync","logProgress","push","versionFlags","flag","execSync","timeout","resolvePromise","reject","installProc","on","code","Error","err","logError","message","String","prefix","isTTY","stdout","phase","errorLines","buildDots","buildTimer","clearLine","write","startBuildProgress","setInterval","repeat","stopBuildProgress","clearInterval","waitForPortReady","maxWait","Date","now","check","socket","createConnection","destroy","console","log","stripAnsi","s","replace","stripAirPrefix","isAirNoise","t","test","startsWith","length","handlePhaseSignal","exitMatch","match","line","slice","handleBuildingPhase","handleLine","raw","trim","buf","drain","chunk","toString","lines","split","pop","stderr","_code","signal","cmd","setupCustomOutputHandler","flush","d","nl","lastIndexOf","text","kill","ForgeService","running","clientHandle","goManager","config","envName","stopClient","getStatus","clientPort","client","servicePort","service","getClientStatus","getServiceStatus","opt","injectEnvPreset","startGoService","goPort","waitForPort","clientConfig","dir","startClient","presets","presetKeys","Object","keys","name","vars","key","value","entries","child","timeoutMs","r","hasMainGo","hasGoMod","goEnv","dev","devOpts","createForgeService","configPath","root","loadConfigFromPath","loadConfig","parseConfig","userConfig","defaultConfig","configDir"],"mappings":"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"}
|