electron-ohos-hotreload 1.0.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/package.json ADDED
@@ -0,0 +1,40 @@
1
+ {
2
+ "name": "electron-ohos-hotreload",
3
+ "version": "1.0.0",
4
+ "description": "Hot-reload CLI for Electron on HarmonyOS — push JS/TS changes to device without rebuilding HAP",
5
+ "bin": {
6
+ "eohr": "./bin/eohr.js"
7
+ },
8
+ "main": "bin/eohr.js",
9
+ "scripts": {
10
+ "start": "node bin/eohr.js"
11
+ },
12
+ "engines": {
13
+ "node": ">=16"
14
+ },
15
+ "dependencies": {
16
+ "esbuild": "^0.21.0"
17
+ },
18
+ "keywords": [
19
+ "electron",
20
+ "harmonyos",
21
+ "ohos",
22
+ "hot-reload",
23
+ "hot",
24
+ "reload",
25
+ "hvigor"
26
+ ],
27
+ "author": "zhangqingnan",
28
+ "license": "BSD-2-Clause",
29
+ "repository": {
30
+ "type": "git",
31
+ "url": ""
32
+ },
33
+ "homepage": "",
34
+ "files": [
35
+ "bin/",
36
+ "src/",
37
+ "templates/",
38
+ "docs/"
39
+ ]
40
+ }
@@ -0,0 +1,97 @@
1
+ "use strict";
2
+ /**
3
+ * eohr clean — 恢复工程 + 清空设备
4
+ *
5
+ * 1. 删除 hot-reload-agent.js(工程文件)
6
+ * 2. 把 package.json 的 main 改回原始入口(从 .eohr.config.json 的 entry 读取)
7
+ * 3. 删除 .eohr.config.json
8
+ * 4. 清空设备 override 目录和状态文件
9
+ *
10
+ * 跑完后工程恢复到 eohr init 之前的状态,开发者重建 HAP 即可。
11
+ */
12
+ var fs = require("fs");
13
+ var path = require("path");
14
+ var Config = require("../core/Config");
15
+ var HdcBridge = require("../core/HdcBridge");
16
+ var utils = require("../utils");
17
+ var c = utils.c;
18
+
19
+ function run(opts) {
20
+ opts = opts || {};
21
+ var config = Config.load(opts);
22
+ var dash = new (require("../core/Dashboard"))();
23
+
24
+ dash.info("开始恢复工程");
25
+
26
+ var appDir = config.appDir;
27
+ var agentJs = path.join(appDir, "hot-reload-agent.js");
28
+ var packageJsonPath = path.join(appDir, "package.json");
29
+ var configPath = path.join(config.hapRoot, Config.CONFIG_FILE);
30
+
31
+ var restored = [];
32
+
33
+ // 1. 删除 hot-reload-agent.js
34
+ if (fs.existsSync(agentJs)) {
35
+ fs.unlinkSync(agentJs);
36
+ restored.push("hot-reload-agent.js 已删除");
37
+ }
38
+
39
+ // 2. 把 package.json 的 main 改回原始入口
40
+ if (fs.existsSync(packageJsonPath)) {
41
+ var pkg = JSON.parse(fs.readFileSync(packageJsonPath, "utf8"));
42
+ if (pkg.main === "hot-reload-agent.js") {
43
+ // 从 config.entry 推导原始文件名
44
+ var origMain = "main.js";
45
+ if (config.entry) {
46
+ origMain = path.basename(config.entry);
47
+ }
48
+ pkg.main = origMain;
49
+ fs.writeFileSync(packageJsonPath, JSON.stringify(pkg, null, 2));
50
+ restored.push('package.json main → "' + origMain + '"');
51
+ }
52
+ }
53
+
54
+ // 3. 删除 .eohr.config.json
55
+ if (fs.existsSync(configPath)) {
56
+ fs.unlinkSync(configPath);
57
+ restored.push(".eohr.config.json 已删除");
58
+ }
59
+
60
+ // 输出恢复结果
61
+ if (restored.length > 0) {
62
+ restored.forEach(function (msg) {
63
+ console.log(c.green + " [ok]" + c.reset + " " + msg);
64
+ });
65
+ } else {
66
+ dash.info("工程已是原始状态,无需恢复");
67
+ }
68
+
69
+ // 4. 清空设备 override 目录和状态文件
70
+ var hdc = new HdcBridge(config.bundleName);
71
+ console.log(c.dim + " 清空设备..." + c.reset);
72
+
73
+ hdc.shell("rm -rf " + config.physicalOverrideDir + "/*").then(function () {
74
+ return hdc.shell("rm -f " + config.physicalResultDir + "/hot-status.json " +
75
+ config.physicalResultDir + "/hot-harness.log");
76
+ }).then(function () {
77
+ console.log(c.green + " [ok]" + c.reset + " 设备已清空");
78
+ console.log();
79
+ console.log(c.bold + c.green + " ✓ clean 完成" + c.reset);
80
+ console.log();
81
+ console.log(c.dim + " 工程已恢复到 eohr init 之前的状态。" + c.reset);
82
+ console.log(c.dim + " 请重建 HAP 让恢复生效:" + c.reset);
83
+ console.log(c.gray + " hvigorw assembleHap --mode module -p product=default -p buildMode=debug --no-daemon" + c.reset);
84
+ console.log(c.gray + ' hdc install <hap>' + c.reset);
85
+ }).catch(function (err) {
86
+ // 设备可能未连接,工程恢复已完成
87
+ console.log(c.yellow + " [warn]" + c.reset + " 设备清理失败 (" + err.message + ")");
88
+ console.log();
89
+ console.log(c.bold + c.green + " ✓ 工程已恢复" + c.reset);
90
+ console.log();
91
+ console.log(c.dim + " 请重建 HAP 让恢复生效:" + c.reset);
92
+ console.log(c.gray + " hvigorw assembleHap --mode module -p product=default -p buildMode=debug --no-daemon" + c.reset);
93
+ console.log(c.gray + ' hdc install <hap>' + c.reset);
94
+ });
95
+ }
96
+
97
+ module.exports = run;
@@ -0,0 +1,92 @@
1
+ "use strict";
2
+ /**
3
+ * eohr init — 一次性初始化
4
+ *
5
+ * 只做两件事:
6
+ * 1. 在 app 目录新增 hot-reload-agent.js(不修改任何已有文件)
7
+ * 2. 修改 package.json 的 main 字段为 "hot-reload-agent.js"
8
+ *
9
+ * 开发者的 main.js 和其他文件完全不动。
10
+ */
11
+ var fs = require("fs");
12
+ var path = require("path");
13
+ var Config = require("../core/Config");
14
+ var utils = require("../utils");
15
+ var c = utils.c;
16
+
17
+ function run(opts) {
18
+ opts = opts || {};
19
+ var config = Config.load(opts);
20
+ var dash = new (require("../core/Dashboard"))();
21
+
22
+ dash.banner(config);
23
+
24
+ if (!config.bundleName) {
25
+ dash.error("无法探测 bundleName,请确保在 ohos_hap 工程根目录运行,或通过 --bundle-name 指定");
26
+ process.exit(1);
27
+ }
28
+
29
+ if (!config.appDir || !fs.existsSync(config.appDir)) {
30
+ dash.error("无法探测 app 目录 (resfile/resources/app/),请通过 --app-dir 指定");
31
+ process.exit(1);
32
+ }
33
+
34
+ var agentJs = path.join(config.appDir, "hot-reload-agent.js");
35
+ var packageJsonPath = path.join(config.appDir, "package.json");
36
+
37
+ var tplDir = path.join(__dirname, "..", "..", "templates");
38
+ var tplAgent = path.join(tplDir, "hot-reload-agent.js");
39
+
40
+ // 1. 新增 hot-reload-agent.js(如果已存在则覆盖)
41
+ var agentContent = fs.readFileSync(tplAgent, "utf8");
42
+ fs.writeFileSync(agentJs, utils.stripBOM(agentContent));
43
+ dash.info("已新增 hot-reload-agent.js");
44
+
45
+ // 2. 修改 package.json 的 main 字段
46
+ if (!fs.existsSync(packageJsonPath)) {
47
+ dash.error("package.json 不存在: " + packageJsonPath);
48
+ process.exit(1);
49
+ }
50
+
51
+ var pkg = JSON.parse(fs.readFileSync(packageJsonPath, "utf8"));
52
+ var origMain = pkg.main;
53
+
54
+ if (origMain === "hot-reload-agent.js") {
55
+ dash.info("package.json 已配置,跳过");
56
+ } else {
57
+ // 备份原始 main 值到 .eohr.config.json 的 entry 字段(转为相对 hapRoot 的路径)
58
+ if (origMain) {
59
+ var origMainAbs = path.isAbsolute(origMain) ? origMain : path.join(config.appDir, origMain);
60
+ config.entry = path.relative(config.hapRoot, origMainAbs).replace(/\\/g, "/");
61
+ }
62
+ pkg.main = "hot-reload-agent.js";
63
+ fs.writeFileSync(packageJsonPath, JSON.stringify(pkg, null, 2));
64
+ dash.info("package.json main: \"" + origMain + "\" → \"hot-reload-agent.js\"");
65
+ }
66
+
67
+ // 3. 保存配置
68
+ var configPath = Config.save(config);
69
+ dash.info("已生成 " + path.basename(configPath));
70
+
71
+ // 4. 提示
72
+ console.log();
73
+ console.log(c.bold + c.green + " ✓ init 完成" + c.reset);
74
+ console.log();
75
+ console.log(c.dim + " 改动清单:" + c.reset);
76
+ console.log(" " + c.green + "+" + c.reset + " hot-reload-agent.js (新增)");
77
+ console.log(" " + c.yellow + "~" + c.reset + " package.json (main → hot-reload-agent.js)");
78
+ console.log(" " + c.gray + "main.js (未改动)" + c.reset);
79
+ console.log();
80
+ console.log(c.dim + " 下一步:" + c.reset);
81
+ console.log(" 1. 重建 HAP 并安装 (仅此一次):");
82
+ console.log(c.gray + " hvigorw assembleHap --mode module -p product=default -p buildMode=debug --no-daemon" + c.reset);
83
+ console.log(c.gray + ' hdc install <hap-path>' + c.reset);
84
+ console.log();
85
+ console.log(" 2. 启动热加载:");
86
+ console.log(c.gray + " eohr watch" + c.reset);
87
+ console.log();
88
+
89
+ return config;
90
+ }
91
+
92
+ module.exports = run;
@@ -0,0 +1,35 @@
1
+ "use strict";
2
+ /**
3
+ * eohr log — 查看设备运行日志
4
+ */
5
+ var Config = require("../core/Config");
6
+ var HdcBridge = require("../core/HdcBridge");
7
+ var utils = require("../utils");
8
+ var c = utils.c;
9
+
10
+ function run(opts) {
11
+ opts = opts || {};
12
+ var config = Config.load(opts);
13
+ var hdc = new HdcBridge(config.bundleName);
14
+
15
+ var lines = opts._args && opts._args[0] ? parseInt(opts._args[0]) : 50;
16
+
17
+ console.log(c.cyan + " [log]" + c.reset + " 最近 " + lines + " 行");
18
+ console.log(c.dim + " ──────────────────────────────────────" + c.reset);
19
+
20
+ hdc.shell("tail -n " + lines + " " + config.physicalResultDir + "/hot-harness.log 2>/dev/null").then(function (content) {
21
+ if (!content || content.trim() === "") {
22
+ console.log(c.gray + " (无日志文件)" + c.reset);
23
+ } else {
24
+ content.split("\n").forEach(function (line) {
25
+ console.log(" " + line);
26
+ });
27
+ }
28
+ console.log();
29
+ }).catch(function (err) {
30
+ console.error(c.red + " [error]" + c.reset + " " + err.message);
31
+ process.exit(1);
32
+ });
33
+ }
34
+
35
+ module.exports = run;
@@ -0,0 +1,104 @@
1
+ "use strict";
2
+ /**
3
+ * eohr push — 单次打包并推送 entry.js 到设备
4
+ *
5
+ * 用法:
6
+ * eohr push # 打包入口文件 + 推送 entry.js + 触发重载
7
+ * eohr push --file <f> # 推送单个文件到 override 目录
8
+ * eohr push --no-trigger # 推送但不触发重载
9
+ */
10
+ var fs = require("fs");
11
+ var path = require("path");
12
+ var os = require("os");
13
+ var Config = require("../core/Config");
14
+ var HdcBridge = require("../core/HdcBridge");
15
+ var Bundler = require("../core/Bundler");
16
+ var utils = require("../utils");
17
+ var c = utils.c;
18
+
19
+ function run(opts) {
20
+ opts = opts || {};
21
+ var config = Config.load(opts);
22
+ var hdc = new HdcBridge(config.bundleName);
23
+
24
+ console.log(c.cyan + " [push]" + c.reset + " bundleName=" + config.bundleName);
25
+
26
+ // 单文件推送模式
27
+ if (opts.file) {
28
+ var localFile = path.resolve(opts.file);
29
+ var remoteName = opts.remoteName || path.basename(localFile);
30
+
31
+ if (!fs.existsSync(localFile)) {
32
+ console.error(c.red + " [error]" + c.reset + " 文件不存在: " + localFile);
33
+ process.exit(1);
34
+ }
35
+
36
+ var content = fs.readFileSync(localFile);
37
+ var debommed = utils.stripBOM(content);
38
+ var tmpFile = path.join(os.tmpdir(), "eohr-" + remoteName);
39
+ fs.writeFileSync(tmpFile, debommed);
40
+
41
+ return hdc.mkdir(config.physicalOverrideDir).then(function () {
42
+ return hdc.pushOverride(tmpFile, remoteName, config);
43
+ }).then(function () {
44
+ console.log(c.green + " [ok]" + c.reset + " " + remoteName + " pushed");
45
+ if (!opts.noTrigger) {
46
+ return hdc.touch(config.physicalOverrideDir + "/.reload-trigger").then(function () {
47
+ console.log(c.yellow + " [reload]" + c.reset + " triggered");
48
+ });
49
+ }
50
+ }).catch(function (err) {
51
+ console.error(c.red + " [error]" + c.reset + " " + err.message);
52
+ process.exit(1);
53
+ });
54
+ }
55
+
56
+ // 默认: 打包入口文件并推送
57
+ var bundler = new Bundler(config);
58
+
59
+ console.log(c.blue + " [bundle]" + c.reset + " esbuild...");
60
+ console.log(c.dim + " entry: " + config.entry + c.reset);
61
+ var start = Date.now();
62
+
63
+ return bundler.bundle().then(function (result) {
64
+ console.log(c.green + " [ok]" + c.reset + " bundled (" + utils.fmtMs(Date.now() - start) + ")");
65
+
66
+ var tmpFile = path.join(os.tmpdir(), "eohr-entry.js");
67
+ fs.writeFileSync(tmpFile, result.code);
68
+
69
+ console.log(c.blue + " [send]" + c.reset + " hdc file send...");
70
+ return hdc.mkdir(config.physicalOverrideDir).then(function () {
71
+ return hdc.pushOverride(tmpFile, "entry.js", config);
72
+ }).then(function () {
73
+ console.log(c.green + " [ok]" + c.reset + " entry.js pushed");
74
+
75
+ var cfgJson = JSON.stringify({
76
+ strategy: config.strategy,
77
+ softTimeout: config.softTimeout,
78
+ });
79
+ var cfgTmp = path.join(os.tmpdir(), "eohr-hot-config.json");
80
+ fs.writeFileSync(cfgTmp, cfgJson);
81
+ return hdc.pushOverride(cfgTmp, "hot-config.json", config);
82
+ }).then(function () {
83
+ if (!opts.noTrigger) {
84
+ if (config.strategy === "hard") {
85
+ console.log(c.dim + " 重启应用..." + c.reset);
86
+ return hdc.forceStop().then(function () {
87
+ return hdc.startAbility();
88
+ }).then(function () {
89
+ console.log(c.yellow + " [reload]" + c.reset + " app restarted");
90
+ });
91
+ } else {
92
+ return hdc.touch(config.physicalOverrideDir + "/.reload-trigger").then(function () {
93
+ console.log(c.yellow + " [reload]" + c.reset + " triggered");
94
+ });
95
+ }
96
+ }
97
+ });
98
+ }).catch(function (err) {
99
+ console.error(c.red + " [error]" + c.reset + " " + err.message);
100
+ process.exit(1);
101
+ });
102
+ }
103
+
104
+ module.exports = run;
@@ -0,0 +1,197 @@
1
+ "use strict";
2
+ /**
3
+ * eohr setup — 自动配置快捷命令
4
+ *
5
+ * 自动检测当前终端类型(PowerShell / cmd / bash / zsh),
6
+ * 在对应配置文件中写入快捷命令,重启终端后 `eohr` 即可直接使用。
7
+ */
8
+ var fs = require("fs");
9
+ var path = require("path");
10
+ var os = require("os");
11
+ var utils = require("../utils");
12
+ var c = utils.c;
13
+
14
+ function run(opts) {
15
+ opts = opts || {};
16
+ var binPath = path.resolve(__dirname, "..", "..", "bin", "eohr.js");
17
+ var platform = os.platform();
18
+ var isWin = platform === "win32";
19
+ var isMac = platform === "darwin";
20
+
21
+ var dash = new (require("../core/Dashboard"))();
22
+
23
+ // 检测当前 shell 类型
24
+ var shell = detectShell();
25
+ dash.info("当前终端: " + shell);
26
+ dash.info("平台: " + (isWin ? "Windows" : isMac ? "macOS" : "Linux"));
27
+ dash.info("eohr 路径: " + binPath);
28
+
29
+ var success = false;
30
+ var instructions = [];
31
+
32
+ if (isWin) {
33
+ // Windows: 同时配置 PowerShell 和 cmd
34
+ success = setupPowerShell(binPath, dash) | setupCmd(binPath, dash);
35
+ } else {
36
+ // macOS / Linux: 配置 bash/zsh
37
+ success = setupUnix(binPath, dash, isMac);
38
+ }
39
+
40
+ if (success) {
41
+ console.log();
42
+ console.log(c.bold + c.green + " ✓ setup 完成" + c.reset);
43
+ console.log();
44
+ console.log(c.dim + " 请重新打开终端,然后运行:" + c.reset);
45
+ console.log(c.gray + " eohr --version" + c.reset);
46
+ console.log();
47
+ }
48
+ }
49
+
50
+ /** 检测当前 shell */
51
+ function detectShell() {
52
+ var term = process.env.TERM || "";
53
+ var shell = process.env.SHELL || "";
54
+ var comspec = process.env.COMSPEC || "";
55
+
56
+ // PowerShell
57
+ if (process.env.PSModulePath !== undefined) {
58
+ return "PowerShell";
59
+ }
60
+ // cmd
61
+ if (comspec.toLowerCase().indexOf("cmd.exe") >= 0) {
62
+ return "cmd";
63
+ }
64
+ // zsh
65
+ if (shell.indexOf("zsh") >= 0) {
66
+ return "zsh";
67
+ }
68
+ // bash
69
+ if (shell.indexOf("bash") >= 0) {
70
+ return "bash";
71
+ }
72
+ return shell || "unknown";
73
+ }
74
+
75
+ /** 配置 PowerShell */
76
+ function setupPowerShell(binPath, dash) {
77
+ var profileDir = path.join(os.homedir(), "Documents", "WindowsPowerShell");
78
+ var profilePath = path.join(profileDir, "Microsoft.PowerShell_profile.ps1");
79
+
80
+ try {
81
+ if (!fs.existsSync(profileDir)) {
82
+ fs.mkdirSync(profileDir, { recursive: true });
83
+ }
84
+ if (!fs.existsSync(profilePath)) {
85
+ fs.writeFileSync(profilePath, "");
86
+ }
87
+
88
+ var content = fs.readFileSync(profilePath, "utf8");
89
+ var line = 'function eohr { node "' + binPath + '" @args }';
90
+
91
+ if (content.indexOf("function eohr") >= 0) {
92
+ dash.info("PowerShell: 已配置,跳过");
93
+ } else {
94
+ var newContent = content.trimEnd() + "\n" + line + "\n";
95
+ fs.writeFileSync(profilePath, newContent);
96
+ dash.info("PowerShell: 已写入 " + profilePath);
97
+ }
98
+
99
+ // 设置执行策略,允许当前用户运行本地脚本
100
+ try {
101
+ require("child_process").execSync(
102
+ 'powershell -Command "Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser -Force"',
103
+ { windowsHide: true, timeout: 10000 }
104
+ );
105
+ dash.info("PowerShell: 执行策略已设置为 RemoteSigned");
106
+ } catch (e) {
107
+ console.log(c.yellow + " [warn]" + c.reset + " 无法自动设置执行策略,请手动运行:");
108
+ console.log(c.gray + " Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser" + c.reset);
109
+ }
110
+
111
+ return true;
112
+ } catch (e) {
113
+ dash.error("PowerShell 配置失败: " + e.message);
114
+ console.log(c.gray + " 手动添加: 在 $PROFILE 中加入:" + c.reset);
115
+ console.log(c.gray + ' function eohr { node "' + binPath + '" @args }' + c.reset);
116
+ return false;
117
+ }
118
+ }
119
+
120
+ /** 配置 cmd (创建 eohr.bat) */
121
+ function setupCmd(binPath, dash) {
122
+ var batPath = path.join(os.homedir(), "eohr.bat");
123
+ var content = '@node "' + binPath + '" %*\r\n';
124
+
125
+ try {
126
+ fs.writeFileSync(batPath, content);
127
+ dash.info("cmd: 已创建 " + batPath);
128
+
129
+ // 自动把用户目录加入用户 PATH
130
+ var pathEnv = process.env.PATH || "";
131
+ var homeInPath = pathEnv.split(path.delimiter).some(function (p) {
132
+ return p.toLowerCase() === os.homedir().toLowerCase();
133
+ });
134
+
135
+ if (!homeInPath) {
136
+ try {
137
+ var userPath = require("child_process").execSync(
138
+ 'powershell -Command "[System.Environment]::GetEnvironmentVariable(\'PATH\', \'User\')"',
139
+ { encoding: "utf8" }
140
+ ).trim();
141
+ if (userPath.toLowerCase().indexOf(os.homedir().toLowerCase()) < 0) {
142
+ require("child_process").execSync(
143
+ 'powershell -Command "[System.Environment]::SetEnvironmentVariable(\'PATH\', \'' +
144
+ os.homedir() + ";\" + [System.Environment]::GetEnvironmentVariable('PATH', 'User'), 'User\")",
145
+ { windowsHide: true }
146
+ );
147
+ dash.info("cmd: 已将用户目录加入 PATH");
148
+ }
149
+ } catch (e) {
150
+ console.log(c.yellow + " [warn]" + c.reset + " 无法自动加入 PATH,请手动将 " + os.homedir() + " 加入系统 PATH");
151
+ }
152
+ }
153
+
154
+ return true;
155
+ } catch (e) {
156
+ dash.error("cmd 配置失败: " + e.message);
157
+ return false;
158
+ }
159
+ }
160
+
161
+ /** 配置 macOS / Linux */
162
+ function setupUnix(binPath, dash, isMac) {
163
+ var home = os.homedir();
164
+ var candidates = isMac
165
+ ? [path.join(home, ".zshrc"), path.join(home, ".bash_profile")]
166
+ : [path.join(home, ".bashrc"), path.join(home, ".bash_profile")];
167
+
168
+ var line = 'alias eohr="node ' + binPath + '"';
169
+
170
+ for (var i = 0; i < candidates.length; i++) {
171
+ var rcPath = candidates[i];
172
+ try {
173
+ if (!fs.existsSync(rcPath)) {
174
+ fs.writeFileSync(rcPath, "");
175
+ }
176
+ var content = fs.readFileSync(rcPath, "utf8");
177
+
178
+ if (content.indexOf("alias eohr=") >= 0) {
179
+ dash.info(path.basename(rcPath) + ": 已配置,跳过");
180
+ return true;
181
+ }
182
+
183
+ var newContent = content.trimEnd() + "\n" + line + "\n";
184
+ fs.writeFileSync(rcPath, newContent);
185
+ dash.info("已写入 " + rcPath);
186
+ return true;
187
+ } catch (e) {
188
+ // 尝试下一个
189
+ }
190
+ }
191
+
192
+ console.log(c.gray + " 手动添加: 在你的 shell 配置文件中加入:" + c.reset);
193
+ console.log(c.gray + " " + line + c.reset);
194
+ return false;
195
+ }
196
+
197
+ module.exports = run;
@@ -0,0 +1,57 @@
1
+ "use strict";
2
+ /**
3
+ * eohr status — 查询设备侧 agent 状态
4
+ */
5
+ var Config = require("../core/Config");
6
+ var HdcBridge = require("../core/HdcBridge");
7
+ var utils = require("../utils");
8
+ var c = utils.c;
9
+
10
+ function run(opts) {
11
+ opts = opts || {};
12
+ var config = Config.load(opts);
13
+ var hdc = new HdcBridge(config.bundleName);
14
+
15
+ console.log(c.cyan + " [status]" + c.reset + " bundleName=" + config.bundleName);
16
+ console.log(c.dim + " ──────────────────────────────────────" + c.reset);
17
+
18
+ hdc.isDeviceConnected().then(function (connected) {
19
+ console.log(" Device: " + (connected ? c.green + "connected" + c.reset : c.red + "disconnected" + c.reset));
20
+ if (!connected) {
21
+ console.log(c.red + " 设备未连接" + c.reset);
22
+ process.exit(1);
23
+ }
24
+
25
+ return hdc.readResult("hot-status.json", config);
26
+ }).then(function (statusContent) {
27
+ if (statusContent) {
28
+ try {
29
+ var status = JSON.parse(statusContent.trim());
30
+ console.log(" Status: " + status.status);
31
+ console.log(" PID: " + (status.pid || "?"));
32
+ console.log(" Strategy: " + (status.strategy || "?"));
33
+ if (status.error) {
34
+ console.log(c.red + " Error: " + status.error + c.reset);
35
+ }
36
+ } catch (e) {
37
+ console.log(c.gray + " Status: (无法解析)" + c.reset);
38
+ }
39
+ } else {
40
+ console.log(c.gray + " Status: (无状态文件,agent 可能未启动)" + c.reset);
41
+ }
42
+
43
+ return hdc.shell("ls -la " + config.physicalOverrideDir + "/entry.js 2>/dev/null");
44
+ }).then(function (lsResult) {
45
+ if (lsResult) {
46
+ console.log(" Entry.js: " + c.green + "exists" + c.reset);
47
+ } else {
48
+ console.log(" Entry.js: " + c.gray + "not found" + c.reset);
49
+ }
50
+ console.log();
51
+ }).catch(function (err) {
52
+ console.error(c.red + " [error]" + c.reset + " " + err.message);
53
+ process.exit(1);
54
+ });
55
+ }
56
+
57
+ module.exports = run;
@@ -0,0 +1,63 @@
1
+ "use strict";
2
+ /**
3
+ * eohr strategy — 切换重载策略
4
+ *
5
+ * 用法:
6
+ * eohr strategy soft # 仅软重载 (require.cache 失效)
7
+ * eohr strategy hard # 仅硬重载 (app.quit + restart, 默认)
8
+ * eohr strategy hard-first # 软重载优先, 失败回退硬重载
9
+ */
10
+ var fs = require("fs");
11
+ var path = require("path");
12
+ var os = require("os");
13
+ var Config = require("../core/Config");
14
+ var HdcBridge = require("../core/HdcBridge");
15
+ var utils = require("../utils");
16
+ var c = utils.c;
17
+
18
+ function run(opts) {
19
+ opts = opts || {};
20
+ var config = Config.load(opts);
21
+ var strategy = opts._args && opts._args[0];
22
+
23
+ if (!strategy) {
24
+ console.log(c.cyan + " [strategy]" + c.reset + " 当前: " + config.strategy);
25
+ console.log();
26
+ console.log(" 可选值:");
27
+ console.log(" soft 仅软重载 (require.cache 失效, ~1-3s)");
28
+ console.log(" hard 仅硬重载 (app.quit + restart, ~15s, 默认)");
29
+ console.log(" hard-first 软重载优先, 失败回退硬重载");
30
+ return;
31
+ }
32
+
33
+ var valid = ["soft", "hard", "hard-first"];
34
+ if (valid.indexOf(strategy) < 0) {
35
+ console.error(c.red + " [error]" + c.reset + " 无效策略: " + strategy);
36
+ console.error(" 可选: " + valid.join(", "));
37
+ process.exit(1);
38
+ }
39
+
40
+ config.strategy = strategy;
41
+ Config.save(config);
42
+
43
+ var hdc = new HdcBridge(config.bundleName);
44
+ var cfgJson = JSON.stringify({
45
+ strategy: config.strategy,
46
+ softTimeout: config.softTimeout,
47
+ });
48
+
49
+ var tmpFile = path.join(os.tmpdir(), "eohr-hot-config.json");
50
+ fs.writeFileSync(tmpFile, cfgJson);
51
+
52
+ hdc.mkdir(config.physicalOverrideDir).then(function () {
53
+ return hdc.pushOverride(tmpFile, "hot-config.json", config);
54
+ }).then(function () {
55
+ console.log(c.green + " [ok]" + c.reset + " 策略已切换: " + c.bold + strategy + c.reset);
56
+ console.log(c.dim + " 配置已推送到设备,下次重载生效" + c.reset);
57
+ }).catch(function (err) {
58
+ console.log(c.yellow + " [warn]" + c.reset + " 设备推送失败 (" + err.message + ")");
59
+ console.log(c.dim + " 本地配置已更新,下次 eohr watch 时生效" + c.reset);
60
+ });
61
+ }
62
+
63
+ module.exports = run;