specflow-dev-service 0.0.0-beta.2
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.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +95 -0
- package/dist/cli.js.map +1 -0
- package/dist/config/defaults.d.ts +10 -0
- package/dist/config/defaults.d.ts.map +1 -0
- package/dist/config/defaults.js +26 -0
- package/dist/config/defaults.js.map +1 -0
- package/dist/config/loader.d.ts +12 -0
- package/dist/config/loader.d.ts.map +1 -0
- package/dist/config/loader.js +69 -0
- package/dist/config/loader.js.map +1 -0
- package/dist/config/schema.d.ts +68 -0
- package/dist/config/schema.d.ts.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +28 -0
- package/dist/index.js.map +1 -0
- package/dist/logger.d.ts +49 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +274 -0
- package/dist/logger.js.map +1 -0
- package/dist/orchestrator.d.ts +57 -0
- package/dist/orchestrator.d.ts.map +1 -0
- package/dist/orchestrator.js +650 -0
- package/dist/orchestrator.js.map +1 -0
- package/dist/runner/client.d.ts +13 -0
- package/dist/runner/client.d.ts.map +1 -0
- package/dist/runner/client.js +25 -0
- package/dist/runner/client.js.map +1 -0
- package/package.json +47 -0
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sources":[],"mappings":"","names":[]}
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var node_path = require('node:path');
|
|
4
|
+
var commander = require('commander');
|
|
5
|
+
require('node:fs');
|
|
6
|
+
var orchestrator = require('./orchestrator.js');
|
|
7
|
+
require('cross-spawn');
|
|
8
|
+
require('./logger.js');
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* specflow-dev-service CLI
|
|
12
|
+
*
|
|
13
|
+
* 命令:
|
|
14
|
+
* specflow dev — 启动开发环境(前端 + Go 后端热更新)
|
|
15
|
+
* specflow dev --client — 仅启动前端
|
|
16
|
+
* specflow dev --go — 仅启动 Go 后端
|
|
17
|
+
* specflow status — 查看服务状态
|
|
18
|
+
*
|
|
19
|
+
* 日志原则:无错误不输出,静默处理正常流程
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
// ============================================================
|
|
23
|
+
// CLI
|
|
24
|
+
// ============================================================
|
|
25
|
+
|
|
26
|
+
const program = new commander.Command();
|
|
27
|
+
program.name('specflow').description('Specflow 开发服务启动器 — 前端 + Go 后端热更新').version('0.0.0-beta.1');
|
|
28
|
+
|
|
29
|
+
// ==================== dev 命令 ====================
|
|
30
|
+
|
|
31
|
+
program.command('dev').description('启动开发环境(前端 + Go 后端)').option('-c, --config <path>', '配置文件路径').option('--client', '仅启动前端服务').option('--go', '仅启动 Go 后端服务').action(async opts => runDevCommand(opts));
|
|
32
|
+
async function runDevCommand(opts) {
|
|
33
|
+
const cwd = process.cwd();
|
|
34
|
+
const configPath = opts.config ? node_path.resolve(cwd, opts.config) : undefined;
|
|
35
|
+
let svc;
|
|
36
|
+
try {
|
|
37
|
+
svc = await orchestrator.createForgeService(cwd, configPath);
|
|
38
|
+
} catch (err) {
|
|
39
|
+
console.error('[specflow] 配置加载失败:', err instanceof Error ? err.message : err);
|
|
40
|
+
process.exit(1);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// 启动模式
|
|
44
|
+
try {
|
|
45
|
+
if (opts.go) {
|
|
46
|
+
await svc.start({
|
|
47
|
+
client: false,
|
|
48
|
+
service: true
|
|
49
|
+
});
|
|
50
|
+
} else if (opts.client) {
|
|
51
|
+
await svc.start({
|
|
52
|
+
client: true,
|
|
53
|
+
service: false
|
|
54
|
+
});
|
|
55
|
+
} else {
|
|
56
|
+
await svc.start();
|
|
57
|
+
}
|
|
58
|
+
} catch (err) {
|
|
59
|
+
console.error('[specflow] 启动失败:', err instanceof Error ? err.message : err);
|
|
60
|
+
process.exit(1);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// 优雅退出
|
|
64
|
+
const shutdown = async signal => {
|
|
65
|
+
process.stdout.write(`\n[${signal}] 正在停止...`);
|
|
66
|
+
try {
|
|
67
|
+
await svc.stop();
|
|
68
|
+
} catch {
|
|
69
|
+
/* ignore */
|
|
70
|
+
}
|
|
71
|
+
process.exit(0);
|
|
72
|
+
};
|
|
73
|
+
process.on('SIGINT', () => void shutdown('SIGINT'));
|
|
74
|
+
process.on('SIGTERM', () => void shutdown('SIGTERM'));
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// ==================== status 命令 ====================
|
|
78
|
+
|
|
79
|
+
program.command('status').description('查看服务状态').option('-c, --config <path>', '配置文件路径').action(async opts => {
|
|
80
|
+
try {
|
|
81
|
+
const cwd = process.cwd();
|
|
82
|
+
const configPath = opts.config ? node_path.resolve(cwd, opts.config) : undefined;
|
|
83
|
+
const svc = await orchestrator.createForgeService(cwd, configPath);
|
|
84
|
+
const status = svc.getStatus();
|
|
85
|
+
console.log(JSON.stringify(status, null, 2));
|
|
86
|
+
} catch (err) {
|
|
87
|
+
console.error('[specflow] 获取状态失败:', err instanceof Error ? err.message : err);
|
|
88
|
+
process.exit(1);
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
// ==================== 执行 ====================
|
|
93
|
+
|
|
94
|
+
program.parse();
|
|
95
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +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":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"defaults.d.ts","sources":["../../src/config/defaults.ts"],"mappings":";;AAAA;AACA;AACA;;AAEA,cAAc,aAAa,EAAE,IAAI,CAAC,cAAc;;;;","names":[]}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* 默认配置值
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const defaultConfig = {
|
|
8
|
+
client: {
|
|
9
|
+
dir: 'client',
|
|
10
|
+
dev: 'npm run dev',
|
|
11
|
+
build: 'npm run build',
|
|
12
|
+
port: 3000,
|
|
13
|
+
distDir: 'dist'
|
|
14
|
+
},
|
|
15
|
+
service: {
|
|
16
|
+
dir: 'service',
|
|
17
|
+
port: 8080,
|
|
18
|
+
pbDir: 'pb',
|
|
19
|
+
handlerDir: 'handler',
|
|
20
|
+
module: '',
|
|
21
|
+
dev: ''
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
exports.defaultConfig = defaultConfig;
|
|
26
|
+
//# sourceMappingURL=defaults.js.map
|
|
@@ -0,0 +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;AACF;;;;"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { SpecflowConfig, ResolvedConfig } from './schema.js';
|
|
2
|
+
export { ClientConfig, ServiceConfig } from './schema.js';
|
|
3
|
+
|
|
4
|
+
/** 定义配置的辅助函数(提供类型提示) */
|
|
5
|
+
declare function defineConfig(config: SpecflowConfig): SpecflowConfig;
|
|
6
|
+
/**
|
|
7
|
+
* 使用 confmix 加载配置文件
|
|
8
|
+
*/
|
|
9
|
+
declare function loadConfig(cwd: string): Promise<ResolvedConfig>;
|
|
10
|
+
|
|
11
|
+
export { ResolvedConfig, SpecflowConfig, defineConfig, loadConfig };
|
|
12
|
+
//# sourceMappingURL=loader.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loader.d.ts","sources":["../../src/config/loader.ts"],"mappings":";;;AACA;AACA,iBAAiB,YAAY,SAAS,cAAc,GAAG,cAAc;AACrE;AACA;AACA;AACA,iBAAiB,UAAU,eAAe,OAAO,CAAC,cAAc;;;;","names":[]}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var node_fs = require('node:fs');
|
|
4
|
+
var node_path = require('node:path');
|
|
5
|
+
var defaults = require('./defaults.js');
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* 配置文件加载器
|
|
9
|
+
*
|
|
10
|
+
* 支持 specflow.config.ts / .js / .mjs / .cjs / .json
|
|
11
|
+
* 使用 confmix 解析 TypeScript 配置
|
|
12
|
+
*/
|
|
13
|
+
/** 定义配置的辅助函数(提供类型提示) */
|
|
14
|
+
function defineConfig(config) {
|
|
15
|
+
return config;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* 使用 confmix 加载配置文件
|
|
20
|
+
*/
|
|
21
|
+
async function loadConfig(cwd) {
|
|
22
|
+
const configFiles = ['specflow.config.ts', 'specflow.config.js', 'specflow.config.mjs', 'specflow.config.cjs', 'specflow.config.json'];
|
|
23
|
+
let configPath = null;
|
|
24
|
+
for (const file of configFiles) {
|
|
25
|
+
const fullPath = node_path.resolve(cwd, file);
|
|
26
|
+
if (node_fs.existsSync(fullPath)) {
|
|
27
|
+
configPath = fullPath;
|
|
28
|
+
break;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
if (!configPath) {
|
|
32
|
+
return mergeConfig({}, cwd);
|
|
33
|
+
}
|
|
34
|
+
try {
|
|
35
|
+
// 动态导入 confmix(避免 Rollup 打包)
|
|
36
|
+
const {
|
|
37
|
+
parseConfig
|
|
38
|
+
} = await import('confmix');
|
|
39
|
+
// 默认使用 ts-node 解析 TypeScript(与 rollify 一致)
|
|
40
|
+
const {
|
|
41
|
+
config
|
|
42
|
+
} = await parseConfig(configPath);
|
|
43
|
+
return mergeConfig(config, cwd);
|
|
44
|
+
} catch (err) {
|
|
45
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
46
|
+
throw new Error(`加载配置文件失败: ${message}`);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/** 合并用户配置和默认配置 */
|
|
51
|
+
function mergeConfig(userConfig, cwd) {
|
|
52
|
+
return {
|
|
53
|
+
client: {
|
|
54
|
+
...defaults.defaultConfig.client,
|
|
55
|
+
...userConfig.client
|
|
56
|
+
},
|
|
57
|
+
service: {
|
|
58
|
+
...defaults.defaultConfig.service,
|
|
59
|
+
...userConfig.service
|
|
60
|
+
},
|
|
61
|
+
configDir: cwd
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// 重新导出类型
|
|
66
|
+
|
|
67
|
+
exports.defineConfig = defineConfig;
|
|
68
|
+
exports.loadConfig = loadConfig;
|
|
69
|
+
//# sourceMappingURL=loader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loader.js","sources":["../../src/config/loader.ts"],"sourcesContent":["/**\n * 配置文件加载器\n *\n * 支持 specflow.config.ts / .js / .mjs / .cjs / .json\n * 使用 confmix 解析 TypeScript 配置\n */\nimport { existsSync } from 'node:fs';\nimport { resolve } from 'node:path';\n\nimport { defaultConfig } from './defaults';\n\nimport type { SpecflowConfig, ResolvedConfig, ClientConfig, ServiceConfig } from './schema';\n\n/** 定义配置的辅助函数(提供类型提示) */\nexport function defineConfig(config: SpecflowConfig): SpecflowConfig {\n return config;\n}\n\n/**\n * 使用 confmix 加载配置文件\n */\nexport async function loadConfig(cwd: string): Promise<ResolvedConfig> {\n const configFiles = [\n 'specflow.config.ts',\n 'specflow.config.js',\n 'specflow.config.mjs',\n 'specflow.config.cjs',\n 'specflow.config.json',\n ];\n\n let configPath: string | null = null;\n\n for (const file of configFiles) {\n const fullPath = resolve(cwd, file);\n if (existsSync(fullPath)) {\n configPath = fullPath;\n break;\n }\n }\n\n if (!configPath) {\n return mergeConfig({}, cwd);\n }\n\n try {\n // 动态导入 confmix(避免 Rollup 打包)\n const { parseConfig } = await import('confmix');\n // 默认使用 ts-node 解析 TypeScript(与 rollify 一致)\n const { config } = await parseConfig<SpecflowConfig>(configPath);\n return mergeConfig(config, cwd);\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n throw new Error(`加载配置文件失败: ${message}`);\n }\n}\n\n/** 合并用户配置和默认配置 */\nfunction mergeConfig(userConfig: Partial<SpecflowConfig>, cwd: string): ResolvedConfig {\n return {\n client: { ...defaultConfig.client, ...userConfig.client },\n service: { ...defaultConfig.service, ...userConfig.service },\n configDir: cwd,\n };\n}\n\n// 重新导出类型\nexport type { SpecflowConfig, ResolvedConfig, ClientConfig, ServiceConfig };\n"],"names":["defineConfig","config","loadConfig","cwd","configFiles","configPath","file","fullPath","resolve","existsSync","mergeConfig","parseConfig","err","message","Error","String","userConfig","client","defaultConfig","service","configDir"],"mappings":";;;;;;AAAA;AACA;AACA;AACA;AACA;AACA;AAQA;AACO,SAASA,YAAYA,CAACC,MAAsB,EAAkB;AACnE,EAAA,OAAOA,MAAM;AACf;;AAEA;AACA;AACA;AACO,eAAeC,UAAUA,CAACC,GAAW,EAA2B;AACrE,EAAA,MAAMC,WAAW,GAAG,CAClB,oBAAoB,EACpB,oBAAoB,EACpB,qBAAqB,EACrB,qBAAqB,EACrB,sBAAsB,CACvB;EAED,IAAIC,UAAyB,GAAG,IAAI;AAEpC,EAAA,KAAK,MAAMC,IAAI,IAAIF,WAAW,EAAE;AAC9B,IAAA,MAAMG,QAAQ,GAAGC,iBAAO,CAACL,GAAG,EAAEG,IAAI,CAAC;AACnC,IAAA,IAAIG,kBAAU,CAACF,QAAQ,CAAC,EAAE;AACxBF,MAAAA,UAAU,GAAGE,QAAQ;AACrB,MAAA;AACF,IAAA;AACF,EAAA;EAEA,IAAI,CAACF,UAAU,EAAE;AACf,IAAA,OAAOK,WAAW,CAAC,EAAE,EAAEP,GAAG,CAAC;AAC7B,EAAA;EAEA,IAAI;AACF;IACA,MAAM;AAAEQ,MAAAA;AAAY,KAAC,GAAG,MAAM,OAAO,SAAS,CAAC;AAC/C;IACA,MAAM;AAAEV,MAAAA;AAAO,KAAC,GAAG,MAAMU,WAAW,CAAiBN,UAAU,CAAC;AAChE,IAAA,OAAOK,WAAW,CAACT,MAAM,EAAEE,GAAG,CAAC;EACjC,CAAC,CAAC,OAAOS,GAAG,EAAE;AACZ,IAAA,MAAMC,OAAO,GAAGD,GAAG,YAAYE,KAAK,GAAGF,GAAG,CAACC,OAAO,GAAGE,MAAM,CAACH,GAAG,CAAC;AAChE,IAAA,MAAM,IAAIE,KAAK,CAAC,CAAA,UAAA,EAAaD,OAAO,EAAE,CAAC;AACzC,EAAA;AACF;;AAEA;AACA,SAASH,WAAWA,CAACM,UAAmC,EAAEb,GAAW,EAAkB;EACrF,OAAO;AACLc,IAAAA,MAAM,EAAE;MAAE,GAAGC,sBAAa,CAACD,MAAM;AAAE,MAAA,GAAGD,UAAU,CAACC;KAAQ;AACzDE,IAAAA,OAAO,EAAE;MAAE,GAAGD,sBAAa,CAACC,OAAO;AAAE,MAAA,GAAGH,UAAU,CAACG;KAAS;AAC5DC,IAAAA,SAAS,EAAEjB;GACZ;AACH;;AAEA;;;;;"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* specflow 配置类型定义
|
|
3
|
+
*
|
|
4
|
+
* forge-service 只保留核心功能:
|
|
5
|
+
* - 配置文件加载与合并
|
|
6
|
+
* - 前端 dev server 启动
|
|
7
|
+
* - 后端 Go 服务热更新
|
|
8
|
+
*/
|
|
9
|
+
/** 前端客户端配置 */
|
|
10
|
+
interface ClientConfig {
|
|
11
|
+
/** 前端项目目录(相对于项目根目录),默认 'client' */
|
|
12
|
+
dir?: string;
|
|
13
|
+
/** 开发模式启动命令,如 'npm run dev' */
|
|
14
|
+
dev?: string;
|
|
15
|
+
/** 构建命令,如 'npm run build' */
|
|
16
|
+
build?: string;
|
|
17
|
+
/** 前端 dev server 端口,默认 3000 */
|
|
18
|
+
port?: number;
|
|
19
|
+
/** 构建输出目录(相对于 client dir),默认 'dist' */
|
|
20
|
+
distDir?: string;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Go 服务开发模式配置
|
|
24
|
+
*
|
|
25
|
+
* - 不配置或 undefined → 使用 air(自动检测,推荐)
|
|
26
|
+
* - 字符串 → 自定义启动命令,如 'make dev' 或 './scripts/dev.sh'
|
|
27
|
+
* - 对象 → 自定义命令 + 参数
|
|
28
|
+
*/
|
|
29
|
+
type ServiceDevConfig = string | {
|
|
30
|
+
command: string;
|
|
31
|
+
args?: string[];
|
|
32
|
+
};
|
|
33
|
+
/** Go 真实后端服务配置 */
|
|
34
|
+
interface ServiceConfig {
|
|
35
|
+
/** Go 服务目录(相对于项目根目录),默认 'service' */
|
|
36
|
+
dir?: string;
|
|
37
|
+
/** Go 服务端口,默认 8080 */
|
|
38
|
+
port?: number;
|
|
39
|
+
/** pb 类型输出目录(相对于 service dir),默认 'pb' */
|
|
40
|
+
pbDir?: string;
|
|
41
|
+
/** handler 目录(相对于 service dir),默认 'handler' */
|
|
42
|
+
handlerDir?: string;
|
|
43
|
+
/** Go module 名称,默认从 go.mod 读取 */
|
|
44
|
+
module?: string;
|
|
45
|
+
/**
|
|
46
|
+
* 开发模式热更新命令
|
|
47
|
+
* - 默认使用 air(需先安装: go install github.com/air-verse/air@latest)
|
|
48
|
+
* - 可自定义命令覆盖: dev: 'make dev' | { command: './scripts/dev.sh', args: ['--watch'] }
|
|
49
|
+
*/
|
|
50
|
+
dev?: ServiceDevConfig;
|
|
51
|
+
}
|
|
52
|
+
/** specflow 用户配置(forge-service 精简版) */
|
|
53
|
+
interface SpecflowConfig {
|
|
54
|
+
/** 前端客户端配置 */
|
|
55
|
+
client?: ClientConfig;
|
|
56
|
+
/** Go 真实后端服务配置 */
|
|
57
|
+
service?: ServiceConfig;
|
|
58
|
+
}
|
|
59
|
+
/** 解析后的配置(所有字段都有值) */
|
|
60
|
+
interface ResolvedConfig {
|
|
61
|
+
client: Required<ClientConfig>;
|
|
62
|
+
service: Required<ServiceConfig>;
|
|
63
|
+
/** 配置文件所在目录 */
|
|
64
|
+
configDir: string;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export type { ClientConfig, ResolvedConfig, ServiceConfig, ServiceDevConfig, SpecflowConfig };
|
|
68
|
+
//# sourceMappingURL=schema.d.ts.map
|
|
@@ -0,0 +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":[]}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { defineConfig, loadConfig } from './config/loader.js';
|
|
2
|
+
export { defaultConfig } from './config/defaults.js';
|
|
3
|
+
export { ForgeService, ForgeServiceStatus, createForgeService } from './orchestrator.js';
|
|
4
|
+
export { ClientHandle, startClient, stopClient } from './runner/client.js';
|
|
5
|
+
export { ClientConfig, ResolvedConfig, ServiceConfig, SpecflowConfig } from './config/schema.js';
|
|
6
|
+
export { logBanner, logError, logProgress, logReady, logServiceReady, logWarn, logWatch, setLogLevel, setVerbose } from './logger.js';
|
|
7
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sources":[],"mappings":";;;;;","names":[]}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var loader = require('./config/loader.js');
|
|
4
|
+
var defaults = require('./config/defaults.js');
|
|
5
|
+
var orchestrator = require('./orchestrator.js');
|
|
6
|
+
require('cross-spawn');
|
|
7
|
+
var client = require('./runner/client.js');
|
|
8
|
+
var logger = require('./logger.js');
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
exports.defineConfig = loader.defineConfig;
|
|
13
|
+
exports.loadConfig = loader.loadConfig;
|
|
14
|
+
exports.defaultConfig = defaults.defaultConfig;
|
|
15
|
+
exports.ForgeService = orchestrator.ForgeService;
|
|
16
|
+
exports.createForgeService = orchestrator.createForgeService;
|
|
17
|
+
exports.startClient = client.startClient;
|
|
18
|
+
exports.stopClient = client.stopClient;
|
|
19
|
+
exports.logBanner = logger.logBanner;
|
|
20
|
+
exports.logError = logger.logError;
|
|
21
|
+
exports.logProgress = logger.logProgress;
|
|
22
|
+
exports.logReady = logger.logReady;
|
|
23
|
+
exports.logServiceReady = logger.logServiceReady;
|
|
24
|
+
exports.logWarn = logger.logWarn;
|
|
25
|
+
exports.logWatch = logger.logWatch;
|
|
26
|
+
exports.setLogLevel = logger.setLogLevel;
|
|
27
|
+
exports.setVerbose = logger.setVerbose;
|
|
28
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;"}
|
package/dist/logger.d.ts
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 精简日志系统
|
|
3
|
+
*
|
|
4
|
+
* 设计原则:
|
|
5
|
+
* - 默认模式:只显示进度条 + URL,不刷屏
|
|
6
|
+
* - verbose 模式:展示全部详细信息
|
|
7
|
+
* - 错误始终展示
|
|
8
|
+
*/
|
|
9
|
+
type LogLevel = 'silent' | 'error' | 'warn' | 'info' | 'debug';
|
|
10
|
+
/** 设置日志级别 */
|
|
11
|
+
declare function setLogLevel(level: LogLevel): void;
|
|
12
|
+
/** 设置 verbose 模式(展示全部详细信息) */
|
|
13
|
+
declare function setVerbose(v: boolean): void;
|
|
14
|
+
/**
|
|
15
|
+
* 服务启动消息(始终展示——这是用户最需要看到的)
|
|
16
|
+
*
|
|
17
|
+
* 输出示例:
|
|
18
|
+
* ✓ Dev Service http://localhost:3001
|
|
19
|
+
* ✓ Client http://localhost:2029
|
|
20
|
+
*/
|
|
21
|
+
declare function logServiceReady(name: string, url: string, extra?: string): void;
|
|
22
|
+
/**
|
|
23
|
+
* 进度消息(仅 verbose 模式展示)
|
|
24
|
+
*/
|
|
25
|
+
declare function logProgress(module: string, action: string, detail?: string): void;
|
|
26
|
+
/**
|
|
27
|
+
* 文件变化通知(始终展示)
|
|
28
|
+
*/
|
|
29
|
+
declare function logWatch(file: string, action: string): void;
|
|
30
|
+
/**
|
|
31
|
+
* 警告(始终展示)
|
|
32
|
+
*/
|
|
33
|
+
declare function logWarn(msg: string): void;
|
|
34
|
+
/**
|
|
35
|
+
* 错误(展示详情)
|
|
36
|
+
*/
|
|
37
|
+
declare function logError(msg: string, err?: Error | string): void;
|
|
38
|
+
/**
|
|
39
|
+
* 启动 banner(极简版)
|
|
40
|
+
*/
|
|
41
|
+
declare function logBanner(command: string): void;
|
|
42
|
+
/**
|
|
43
|
+
* 完成消息
|
|
44
|
+
*/
|
|
45
|
+
declare function logReady(startTime: number): void;
|
|
46
|
+
|
|
47
|
+
export { logBanner, logError, logProgress, logReady, logServiceReady, logWarn, logWatch, setLogLevel, setVerbose };
|
|
48
|
+
export type { LogLevel };
|
|
49
|
+
//# sourceMappingURL=logger.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.d.ts","sources":["../src/logger.ts"],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK,QAAQ;AACb;AACA,iBAAiB,WAAW,QAAQ,QAAQ;AAC5C;AACA,iBAAiB,UAAU;AAuD3B;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iBAAiB,eAAe;AAChC;AACA;AACA;AACA,iBAAiB,WAAW;AAC5B;AACA;AACA;AACA,iBAAiB,QAAQ;AACzB;AACA;AACA;AACA,iBAAiB,OAAO;AACxB;AACA;AACA;AACA,iBAAiB,QAAQ,oBAAoB,KAAK;AAKlD;AACA;AACA;AACA,iBAAiB,SAAS;AAC1B;AACA;AACA;AACA,iBAAiB,QAAQ;;;;","names":[]}
|